1--Minetest
2--Copyright (C) 2013 sapier
3--
4--This program is free software; you can redistribute it and/or modify
5--it under the terms of the GNU Lesser General Public License as published by
6--the Free Software Foundation; either version 2.1 of the License, or
7--(at your option) any later version.
8--
9--This program is distributed in the hope that it will be useful,
10--but WITHOUT ANY WARRANTY; without even the implied warranty of
11--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12--GNU Lesser General Public License for more details.
13--
14--You should have received a copy of the GNU Lesser General Public License along
15--with this program; if not, write to the Free Software Foundation, Inc.,
16--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18--------------------------------------------------------------------------------
19function get_mods(path,retval,modpack)
20
21	local mods = core.get_dirlist(path,true)
22	for i=1,#mods,1 do
23		local toadd = {}
24		local modpackfile = nil
25
26		toadd.name		= mods[i]
27		toadd.path		= path .. DIR_DELIM .. mods[i] .. DIR_DELIM
28		if modpack ~= nil and
29			modpack ~= "" then
30			toadd.modpack	= modpack
31		else
32			local filename = path .. DIR_DELIM .. mods[i] .. DIR_DELIM .. "modpack.txt"
33			local error = nil
34			modpackfile,error = io.open(filename,"r")
35		end
36
37		if modpackfile ~= nil then
38			modpackfile:close()
39			toadd.is_modpack = true
40			table.insert(retval,toadd)
41			get_mods(path .. DIR_DELIM .. mods[i],retval,mods[i])
42		else
43			table.insert(retval,toadd)
44		end
45	end
46end
47
48--modmanager implementation
49modmgr = {}
50
51--------------------------------------------------------------------------------
52function modmgr.extract(modfile)
53	if modfile.type == "zip" then
54		local tempfolder = os.tempfolder()
55
56		if tempfolder ~= nil and
57			tempfolder ~= "" then
58			core.create_dir(tempfolder)
59			if core.extract_zip(modfile.name,tempfolder) then
60				return tempfolder
61			end
62		end
63	end
64	return nil
65end
66
67-------------------------------------------------------------------------------
68function modmgr.getbasefolder(temppath)
69
70	if temppath == nil then
71		return {
72		type = "invalid",
73		path = ""
74		}
75	end
76
77	local testfile = io.open(temppath .. DIR_DELIM .. "init.lua","r")
78	if testfile ~= nil then
79		testfile:close()
80		return {
81				type="mod",
82				path=temppath
83				}
84	end
85
86	testfile = io.open(temppath .. DIR_DELIM .. "modpack.txt","r")
87	if testfile ~= nil then
88		testfile:close()
89		return {
90				type="modpack",
91				path=temppath
92				}
93	end
94
95	local subdirs = core.get_dirlist(temppath,true)
96
97	--only single mod or modpack allowed
98	if #subdirs ~= 1 then
99		return {
100			type = "invalid",
101			path = ""
102			}
103	end
104
105	testfile =
106	io.open(temppath .. DIR_DELIM .. subdirs[1] ..DIR_DELIM .."init.lua","r")
107	if testfile ~= nil then
108		testfile:close()
109		return {
110			type="mod",
111			path= temppath .. DIR_DELIM .. subdirs[1]
112			}
113	end
114
115	testfile =
116	io.open(temppath .. DIR_DELIM .. subdirs[1] ..DIR_DELIM .."modpack.txt","r")
117	if testfile ~= nil then
118		testfile:close()
119		return {
120			type="modpack",
121			path=temppath ..  DIR_DELIM .. subdirs[1]
122			}
123	end
124
125	return {
126		type = "invalid",
127		path = ""
128		}
129end
130
131--------------------------------------------------------------------------------
132function modmgr.isValidModname(modpath)
133	if modpath:find("-") ~= nil then
134		return false
135	end
136
137	return true
138end
139
140--------------------------------------------------------------------------------
141function modmgr.parse_register_line(line)
142	local pos1 = line:find("\"")
143	local pos2 = nil
144	if pos1 ~= nil then
145		pos2 = line:find("\"",pos1+1)
146	end
147
148	if pos1 ~= nil and pos2 ~= nil then
149		local item = line:sub(pos1+1,pos2-1)
150
151		if item ~= nil and
152			item ~= "" then
153			local pos3 = item:find(":")
154
155			if pos3 ~= nil then
156				local retval = item:sub(1,pos3-1)
157				if retval ~= nil and
158					retval ~= "" then
159					return retval
160				end
161			end
162		end
163	end
164	return nil
165end
166
167--------------------------------------------------------------------------------
168function modmgr.parse_dofile_line(modpath,line)
169	local pos1 = line:find("\"")
170	local pos2 = nil
171	if pos1 ~= nil then
172		pos2 = line:find("\"",pos1+1)
173	end
174
175	if pos1 ~= nil and pos2 ~= nil then
176		local filename = line:sub(pos1+1,pos2-1)
177
178		if filename ~= nil and
179			filename ~= "" and
180			filename:find(".lua") then
181			return modmgr.identify_modname(modpath,filename)
182		end
183	end
184	return nil
185end
186
187--------------------------------------------------------------------------------
188function modmgr.identify_modname(modpath,filename)
189	local testfile = io.open(modpath .. DIR_DELIM .. filename,"r")
190	if testfile ~= nil then
191		local line = testfile:read()
192
193		while line~= nil do
194			local modname = nil
195
196			if line:find("register_tool") or
197			   line:find("register_craftitem") or
198			   line:find("register_node") then
199				modname = modmgr.parse_register_line(line)
200			end
201
202			if line:find("dofile") then
203				modname = modmgr.parse_dofile_line(modpath,line)
204			end
205
206			if modname ~= nil then
207				testfile:close()
208				return modname
209			end
210
211			line = testfile:read()
212		end
213		testfile:close()
214	end
215
216	return nil
217end
218
219--------------------------------------------------------------------------------
220function modmgr.tab()
221	if modmgr.global_mods == nil then
222		modmgr.refresh_globals()
223	end
224
225	if modmgr.selected_mod == nil then
226		modmgr.selected_mod = 1
227	end
228
229	local retval =
230		"label[6.5,-0.25;".. fgettext("Installed Mods:") .. "]" ..
231		"textlist[6.5,0.25;8,4;modlist;" ..
232		modmgr.render_modlist(modmgr.global_mods) ..
233		";" .. modmgr.selected_mod .. "]"
234
235	retval = retval ..
236--		TODO Disabled due to upcoming release 0.4.8 and irrlicht messing up localization
237--		"button[0.75,4.85;1.8,0.5;btn_mod_mgr_install_local;".. fgettext("Local install") .. "]" ..
238		"button[6.5,4.5;3.05,0.5;btn_mod_mgr_download;".. fgettext("Online mod repository") .. "]"
239
240	local selected_mod = nil
241
242	if filterlist.size(modmgr.global_mods) >= modmgr.selected_mod then
243		selected_mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
244	end
245
246	if selected_mod ~= nil then
247		local modscreenshot = nil
248
249		--check for screenshot beeing available
250		local screenshotfilename = selected_mod.path .. DIR_DELIM .. "screenshot.png"
251		local error = nil
252		screenshotfile,error = io.open(screenshotfilename,"r")
253		if error == nil then
254			screenshotfile:close()
255			modscreenshot = screenshotfilename
256		end
257
258		if modscreenshot == nil then
259				modscreenshot = modstore.basetexturedir .. "no_screenshot.png"
260		end
261
262		retval = retval
263				.. "image[6.5,5;3,2;" .. core.formspec_escape(modscreenshot) .. "]"
264				.. "label[9.5,5.6;" .. selected_mod.name .. "]"
265
266		local descriptionlines = nil
267		error = nil
268		local descriptionfilename = selected_mod.path .. "description.txt"
269		descriptionfile,error = io.open(descriptionfilename,"r")
270		if error == nil then
271			descriptiontext = descriptionfile:read("*all")
272
273			descriptionlines = core.splittext(descriptiontext,42)
274			descriptionfile:close()
275		else
276			descriptionlines = {}
277			table.insert(descriptionlines,fgettext("No mod description available"))
278		end
279
280		retval = retval ..
281			"label[6.5,6.7;".. fgettext("Mod information:") .. "]" ..
282			"textlist[6.5,7.2;8,2.4;description;"
283
284		for i=1,#descriptionlines,1 do
285			retval = retval .. core.formspec_escape(descriptionlines[i]) .. ","
286		end
287
288
289		if selected_mod.is_modpack then
290			retval = retval .. ";0]" ..
291				"button[10,4.85;2,0.5;btn_mod_mgr_rename_modpack;" ..
292				fgettext("Rename") .. "]"
293			retval = retval .. "button[6.5,4.85;4.5,0.5;btn_mod_mgr_delete_mod;"
294				.. fgettext("Uninstall selected modpack") .. "]"
295		else
296			--show dependencies
297
298			retval = retval .. ",Depends:,"
299
300			toadd = modmgr.get_dependencies(selected_mod.path)
301
302			retval = retval .. toadd .. ";0]"
303
304			retval = retval .. "button[6.5,9.85;4.5,0.5;btn_mod_mgr_delete_mod;"
305				.. fgettext("Uninstall selected mod") .. "]"
306		end
307	end
308	return retval
309end
310
311--------------------------------------------------------------------------------
312function modmgr.dialog_rename_modpack()
313
314	local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
315
316	local retval =
317		"label[1.75,1;".. fgettext("Rename Modpack:") .. "]"..
318		"field[4.5,1.4;6,0.5;te_modpack_name;;" ..
319		mod.name ..
320		"]" ..
321		"button[5,4.2;2.6,0.5;dlg_rename_modpack_confirm;"..
322				fgettext("Accept") .. "]" ..
323		"button[7.5,4.2;2.8,0.5;dlg_rename_modpack_cancel;"..
324				fgettext("Cancel") .. "]"
325
326	return retval
327end
328
329--------------------------------------------------------------------------------
330function modmgr.precheck()
331
332	if modmgr.world_config_selected_world == nil then
333		modmgr.world_config_selected_world = 1
334	end
335
336	if modmgr.world_config_selected_mod == nil then
337		modmgr.world_config_selected_mod = 1
338	end
339
340	if modmgr.hide_gamemods == nil then
341		modmgr.hide_gamemods = true
342	end
343
344	if modmgr.hide_modpackcontents == nil then
345		modmgr.hide_modpackcontents = true
346	end
347end
348
349--------------------------------------------------------------------------------
350function modmgr.render_modlist(render_list)
351	local retval = ""
352
353	if render_list == nil then
354		if modmgr.global_mods == nil then
355			modmgr.refresh_globals()
356		end
357		render_list = modmgr.global_mods
358	end
359
360	local list = filterlist.get_list(render_list)
361	local last_modpack = nil
362
363	for i,v in ipairs(list) do
364		if retval ~= "" then
365			retval = retval ..","
366		end
367
368		local color = ""
369
370		if v.is_modpack then
371			local rawlist = filterlist.get_raw_list(render_list)
372
373			local all_enabled = true
374			for j=1,#rawlist,1 do
375				if rawlist[j].modpack == list[i].name and
376					rawlist[j].enabled ~= true then
377						all_enabled = false
378						break
379				end
380			end
381
382			if all_enabled == false then
383				color = mt_color_grey
384			else
385				color = mt_color_dark_green
386			end
387		end
388
389		if v.typ == "game_mod" then
390			color = mt_color_blue
391		else
392			if v.enabled then
393				color = mt_color_green
394			end
395		end
396
397		retval = retval .. color
398		if v.modpack  ~= nil then
399			retval = retval .. "    "
400		end
401		retval = retval .. v.name
402	end
403
404	return retval
405end
406
407--------------------------------------------------------------------------------
408function modmgr.dialog_configure_world()
409	modmgr.precheck()
410
411	local worldspec = core.get_worlds()[modmgr.world_config_selected_world]
412	local mod = filterlist.get_list(modmgr.modlist)[modmgr.world_config_selected_mod]
413
414	local retval =
415		"size[11,6.5,true]" ..
416		"label[0.5,-0.25;" .. fgettext("World:") .. "]" ..
417		"label[1.75,-0.25;" .. worldspec.name .. "]"
418
419	if modmgr.hide_gamemods then
420		retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";true]"
421	else
422		retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";false]"
423	end
424
425	if modmgr.hide_modpackcontents then
426		retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";true]"
427	else
428		retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";false]"
429	end
430
431	if mod == nil then
432		mod = {name=""}
433	end
434	retval = retval ..
435		"label[0,0.45;" .. fgettext("Mod:") .. "]" ..
436		"label[0.75,0.45;" .. mod.name .. "]" ..
437		"label[0,1;" .. fgettext("Depends:") .. "]" ..
438		"textlist[0,1.5;5,4.25;world_config_depends;" ..
439		modmgr.get_dependencies(mod.path) .. ";0]" ..
440		"button[9.25,6.35;2,0.5;btn_config_world_save;" .. fgettext("Save") .. "]" ..
441		"button[7.4,6.35;2,0.5;btn_config_world_cancel;" .. fgettext("Cancel") .. "]"
442
443	if mod ~= nil and mod.name ~= "" and mod.typ ~= "game_mod" then
444		if mod.is_modpack then
445			local rawlist = filterlist.get_raw_list(modmgr.modlist)
446
447			local all_enabled = true
448			for j=1,#rawlist,1 do
449				if rawlist[j].modpack == mod.name and
450					rawlist[j].enabled ~= true then
451						all_enabled = false
452						break
453				end
454			end
455
456			if all_enabled == false then
457				retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_enable;" .. fgettext("Enable MP") .. "]"
458			else
459				retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_disable;" .. fgettext("Disable MP") .. "]"
460			end
461		else
462			if mod.enabled then
463				retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";true]"
464			else
465				retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";false]"
466			end
467		end
468	end
469
470	retval = retval ..
471		"button[8.5,-0.125;2.5,0.5;btn_all_mods;" .. fgettext("Enable all") .. "]" ..
472		"textlist[5.5,0.5;5.5,5.75;world_config_modlist;"
473
474	retval = retval .. modmgr.render_modlist(modmgr.modlist)
475
476	retval = retval .. ";" .. modmgr.world_config_selected_mod .."]"
477
478	return retval
479end
480
481--------------------------------------------------------------------------------
482function modmgr.handle_buttons(tab,fields)
483
484	local retval = nil
485
486	if tab == "mod_mgr" then
487		retval = modmgr.handle_modmgr_buttons(fields)
488	end
489
490	if tab == "dialog_rename_modpack" then
491		retval = modmgr.handle_rename_modpack_buttons(fields)
492	end
493
494	if tab == "dialog_delete_mod" then
495		retval = modmgr.handle_delete_mod_buttons(fields)
496	end
497
498	if tab == "dialog_configure_world" then
499		retval = modmgr.handle_configure_world_buttons(fields)
500	end
501
502	return retval
503end
504
505--------------------------------------------------------------------------------
506function modmgr.get_dependencies(modfolder)
507	local toadd = ""
508	if modfolder ~= nil then
509		local filename = modfolder ..
510					DIR_DELIM .. "depends.txt"
511
512		local dependencyfile = io.open(filename,"r")
513
514		if dependencyfile then
515			local dependency = dependencyfile:read("*l")
516			while dependency do
517				if toadd ~= "" then
518					toadd = toadd .. ","
519				end
520				toadd = toadd .. dependency
521				dependency = dependencyfile:read()
522			end
523			dependencyfile:close()
524		end
525	end
526
527	return toadd
528end
529
530
531--------------------------------------------------------------------------------
532function modmgr.get_worldconfig(worldpath)
533	local filename = worldpath ..
534				DIR_DELIM .. "world.mt"
535
536	local worldfile = Settings(filename)
537
538	local worldconfig = {}
539	worldconfig.global_mods = {}
540	worldconfig.game_mods = {}
541
542	for key,value in pairs(worldfile:to_table()) do
543		if key == "gameid" then
544			worldconfig.id = value
545		else
546			worldconfig.global_mods[key] = core.is_yes(value)
547		end
548	end
549
550	--read gamemods
551	local gamespec = gamemgr.find_by_gameid(worldconfig.id)
552	gamemgr.get_game_mods(gamespec, worldconfig.game_mods)
553
554	return worldconfig
555end
556--------------------------------------------------------------------------------
557function modmgr.handle_modmgr_buttons(fields)
558	local retval = {
559			tab = nil,
560			is_dialog = nil,
561			show_buttons = nil,
562		}
563
564	if fields["modlist"] ~= nil then
565		local event = core.explode_textlist_event(fields["modlist"])
566		modmgr.selected_mod = event.index
567	end
568
569	if fields["btn_mod_mgr_install_local"] ~= nil then
570		core.show_file_open_dialog("mod_mgt_open_dlg",fgettext("Select Mod File:"))
571	end
572
573	if fields["btn_mod_mgr_download"] ~= nil then
574		modstore.update_modlist()
575		retval.current_tab = "dialog_modstore_unsorted"
576		retval.is_dialog = true
577		retval.show_buttons = false
578		return retval
579	end
580
581	if fields["btn_mod_mgr_rename_modpack"] ~= nil then
582		retval.current_tab = "dialog_rename_modpack"
583		retval.is_dialog = true
584		retval.show_buttons = false
585		return retval
586	end
587
588	if fields["btn_mod_mgr_delete_mod"] ~= nil then
589		retval.current_tab = "dialog_delete_mod"
590		retval.is_dialog = true
591		retval.show_buttons = false
592		return retval
593	end
594
595	if fields["mod_mgt_open_dlg_accepted"] ~= nil and
596		fields["mod_mgt_open_dlg_accepted"] ~= "" then
597		modmgr.installmod(fields["mod_mgt_open_dlg_accepted"],nil)
598	end
599
600	return nil;
601end
602
603--------------------------------------------------------------------------------
604function modmgr.installmod(modfilename,basename)
605	local modfile = modmgr.identify_filetype(modfilename)
606	local modpath = modmgr.extract(modfile)
607
608	if modpath == nil then
609		gamedata.errormessage = fgettext("Install Mod: file: \"$1\"", modfile.name) ..
610			fgettext("\nInstall Mod: unsupported filetype \"$1\" or broken archive", modfile.type)
611		return
612	end
613
614
615	local basefolder = modmgr.getbasefolder(modpath)
616
617	if basefolder.type == "modpack" then
618		local clean_path = nil
619
620		if basename ~= nil then
621			clean_path = "mp_" .. basename
622		end
623
624		if clean_path == nil then
625			clean_path = get_last_folder(cleanup_path(basefolder.path))
626		end
627
628		if clean_path ~= nil then
629			local targetpath = core.get_modpath() .. DIR_DELIM .. clean_path
630			if not core.copy_dir(basefolder.path,targetpath) then
631				gamedata.errormessage = fgettext("Failed to install $1 to $2", basename, targetpath)
632			end
633		else
634			gamedata.errormessage = fgettext("Install Mod: unable to find suitable foldername for modpack $1", modfilename)
635		end
636	end
637
638	if basefolder.type == "mod" then
639		local targetfolder = basename
640
641		if targetfolder == nil then
642			targetfolder = modmgr.identify_modname(basefolder.path,"init.lua")
643		end
644
645		--if heuristic failed try to use current foldername
646		if targetfolder == nil then
647			targetfolder = get_last_folder(basefolder.path)
648		end
649
650		if targetfolder ~= nil and modmgr.isValidModname(targetfolder) then
651			local targetpath = core.get_modpath() .. DIR_DELIM .. targetfolder
652			core.copy_dir(basefolder.path,targetpath)
653		else
654			gamedata.errormessage = fgettext("Install Mod: unable to find real modname for: $1", modfilename)
655		end
656	end
657
658	core.delete_dir(modpath)
659
660	modmgr.refresh_globals()
661
662end
663
664--------------------------------------------------------------------------------
665function modmgr.handle_rename_modpack_buttons(fields)
666
667	if fields["dlg_rename_modpack_confirm"] ~= nil then
668		local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
669		local oldpath = core.get_modpath() .. DIR_DELIM .. mod.name
670		local targetpath = core.get_modpath() .. DIR_DELIM .. fields["te_modpack_name"]
671		core.copy_dir(oldpath,targetpath,false)
672		modmgr.refresh_globals()
673		modmgr.selected_mod = filterlist.get_current_index(modmgr.global_mods,
674			filterlist.raw_index_by_uid(modmgr.global_mods, fields["te_modpack_name"]))
675	end
676
677	return {
678		is_dialog = false,
679		show_buttons = true,
680		current_tab = core.setting_get("main_menu_tab")
681		}
682end
683--------------------------------------------------------------------------------
684function modmgr.handle_configure_world_buttons(fields)
685	if fields["world_config_modlist"] ~= nil then
686		local event = core.explode_textlist_event(fields["world_config_modlist"])
687		modmgr.world_config_selected_mod = event.index
688
689		if event.type == "DCL" then
690			modmgr.world_config_enable_mod(nil)
691		end
692	end
693
694	if fields["key_enter"] ~= nil then
695		modmgr.world_config_enable_mod(nil)
696	end
697
698	if fields["cb_mod_enable"] ~= nil then
699		local toset = core.is_yes(fields["cb_mod_enable"])
700		modmgr.world_config_enable_mod(toset)
701	end
702
703	if fields["btn_mp_enable"] ~= nil or
704		fields["btn_mp_disable"] then
705		local toset = (fields["btn_mp_enable"] ~= nil)
706		modmgr.world_config_enable_mod(toset)
707	end
708
709	if fields["cb_hide_gamemods"] ~= nil then
710		local current = filterlist.get_filtercriteria(modmgr.modlist)
711
712		if current == nil then
713			current = {}
714		end
715
716		if core.is_yes(fields["cb_hide_gamemods"]) then
717			current.hide_game = true
718			modmgr.hide_gamemods = true
719		else
720			current.hide_game = false
721			modmgr.hide_gamemods = false
722		end
723
724		filterlist.set_filtercriteria(modmgr.modlist,current)
725	end
726
727		if fields["cb_hide_mpcontent"] ~= nil then
728		local current = filterlist.get_filtercriteria(modmgr.modlist)
729
730		if current == nil then
731			current = {}
732		end
733
734		if core.is_yes(fields["cb_hide_mpcontent"]) then
735			current.hide_modpackcontents = true
736			modmgr.hide_modpackcontents = true
737		else
738			current.hide_modpackcontents = false
739			modmgr.hide_modpackcontents = false
740		end
741
742		filterlist.set_filtercriteria(modmgr.modlist,current)
743	end
744
745	if fields["btn_config_world_save"] then
746		local worldspec = core.get_worlds()[modmgr.world_config_selected_world]
747
748		local filename = worldspec.path ..
749				DIR_DELIM .. "world.mt"
750
751		local worldfile = Settings(filename)
752		local mods = worldfile:to_table()
753
754		local rawlist = filterlist.get_raw_list(modmgr.modlist)
755
756		local i,mod
757		for i,mod in ipairs(rawlist) do
758			if not mod.is_modpack and
759					mod.typ ~= "game_mod" then
760				if mod.enabled then
761					worldfile:set("load_mod_"..mod.name, "true")
762				else
763					worldfile:set("load_mod_"..mod.name, "false")
764				end
765				mods["load_mod_"..mod.name] = nil
766			end
767		end
768
769		-- Remove mods that are not present anymore
770		for key,value in pairs(mods) do
771			if key:sub(1,9) == "load_mod_" then
772				worldfile:remove(key)
773			end
774		end
775
776		if not worldfile:write() then
777			core.log("error", "Failed to write world config file")
778		end
779
780		modmgr.modlist = nil
781		modmgr.worldconfig = nil
782
783		return {
784			is_dialog = false,
785			show_buttons = true,
786			current_tab = core.setting_get("main_menu_tab")
787		}
788	end
789
790	if fields["btn_config_world_cancel"] then
791
792		modmgr.worldconfig = nil
793
794		return {
795			is_dialog = false,
796			show_buttons = true,
797			current_tab = core.setting_get("main_menu_tab")
798		}
799	end
800
801	if fields["btn_all_mods"] then
802		local list = filterlist.get_raw_list(modmgr.modlist)
803
804		for i=1,#list,1 do
805			if list[i].typ ~= "game_mod" and
806				not list[i].is_modpack then
807				list[i].enabled = true
808			end
809		end
810	end
811
812	return nil
813end
814--------------------------------------------------------------------------------
815function modmgr.world_config_enable_mod(toset)
816	local mod = filterlist.get_list(modmgr.modlist)
817		[core.get_textlist_index("world_config_modlist")]
818
819	if mod.typ == "game_mod" then
820		-- game mods can't be enabled or disabled
821	elseif not mod.is_modpack then
822		if toset == nil then
823			mod.enabled = not mod.enabled
824		else
825			mod.enabled = toset
826		end
827	else
828		local list = filterlist.get_raw_list(modmgr.modlist)
829		for i=1,#list,1 do
830			if list[i].modpack == mod.name then
831				if toset == nil then
832					toset = not list[i].enabled
833				end
834				list[i].enabled = toset
835			end
836		end
837	end
838end
839--------------------------------------------------------------------------------
840function modmgr.handle_delete_mod_buttons(fields)
841	local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
842
843	if fields["dlg_delete_mod_confirm"] ~= nil then
844
845		if mod.path ~= nil and
846			mod.path ~= "" and
847			mod.path ~= core.get_modpath() then
848			if not core.delete_dir(mod.path) then
849				gamedata.errormessage = fgettext("Modmgr: failed to delete \"$1\"", mod.path)
850			end
851			modmgr.refresh_globals()
852		else
853			gamedata.errormessage = fgettext("Modmgr: invalid modpath \"$1\"", mod.path)
854		end
855	end
856
857	return {
858		is_dialog = false,
859		show_buttons = true,
860		current_tab = core.setting_get("main_menu_tab")
861		}
862end
863
864--------------------------------------------------------------------------------
865function modmgr.dialog_delete_mod()
866
867	local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
868
869	local retval =
870		"field[1.75,1;10,3;;" .. fgettext("Are you sure you want to delete \"$1\"?", mod.name) ..  ";]"..
871		"button[4,4.2;1,0.5;dlg_delete_mod_confirm;" .. fgettext("Yes") .. "]" ..
872		"button[6.5,4.2;3,0.5;dlg_delete_mod_cancel;" .. fgettext("No of course not!") .. "]"
873
874	return retval
875end
876
877--------------------------------------------------------------------------------
878function modmgr.preparemodlist(data)
879	local retval = {}
880
881	local global_mods = {}
882	local game_mods = {}
883
884	--read global mods
885	local modpath = core.get_modpath()
886
887	if modpath ~= nil and
888		modpath ~= "" then
889		get_mods(modpath,global_mods)
890	end
891
892	for i=1,#global_mods,1 do
893		global_mods[i].typ = "global_mod"
894		table.insert(retval,global_mods[i])
895	end
896
897	--read game mods
898	local gamespec = gamemgr.find_by_gameid(data.gameid)
899	gamemgr.get_game_mods(gamespec, game_mods)
900
901	for i=1,#game_mods,1 do
902		game_mods[i].typ = "game_mod"
903		table.insert(retval,game_mods[i])
904	end
905
906	if data.worldpath == nil then
907		return retval
908	end
909
910	--read world mod configuration
911	local filename = data.worldpath ..
912				DIR_DELIM .. "world.mt"
913
914	local worldfile = Settings(filename)
915
916	for key,value in pairs(worldfile:to_table()) do
917		if key:sub(1, 9) == "load_mod_" then
918			key = key:sub(10)
919			local element = nil
920			for i=1,#retval,1 do
921				if retval[i].name == key then
922					element = retval[i]
923					break
924				end
925			end
926			if element ~= nil then
927				element.enabled = core.is_yes(value)
928			else
929				core.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found")
930			end
931		end
932	end
933
934	return retval
935end
936
937--------------------------------------------------------------------------------
938function modmgr.init_worldconfig()
939	modmgr.precheck()
940	local worldspec = core.get_worlds()[modmgr.world_config_selected_world]
941
942	if worldspec ~= nil then
943		--read worldconfig
944		modmgr.worldconfig = modmgr.get_worldconfig(worldspec.path)
945
946		if modmgr.worldconfig.id == nil or
947			modmgr.worldconfig.id == "" then
948			modmgr.worldconfig = nil
949			return false
950		end
951
952		modmgr.modlist = filterlist.create(
953						modmgr.preparemodlist, --refresh
954						modmgr.comparemod, --compare
955						function(element,uid) --uid match
956							if element.name == uid then
957								return true
958							end
959						end,
960						function(element,criteria)
961							if criteria.hide_game and
962								element.typ == "game_mod" then
963									return false
964							end
965
966							if criteria.hide_modpackcontents and
967								element.modpack ~= nil then
968									return false
969								end
970							return true
971						end, --filter
972						{ worldpath= worldspec.path,
973						  gameid = worldspec.gameid }
974					)
975
976		filterlist.set_filtercriteria(modmgr.modlist, {
977									hide_game=modmgr.hide_gamemods,
978									hide_modpackcontents= modmgr.hide_modpackcontents
979									})
980		filterlist.add_sort_mechanism(modmgr.modlist, "alphabetic", sort_mod_list)
981		filterlist.set_sortmode(modmgr.modlist, "alphabetic")
982
983		return true
984	end
985
986	return false
987end
988
989--------------------------------------------------------------------------------
990function modmgr.comparemod(elem1,elem2)
991	if elem1 == nil or elem2 == nil then
992		return false
993	end
994	if elem1.name ~= elem2.name then
995		return false
996	end
997	if elem1.is_modpack ~= elem2.is_modpack then
998		return false
999	end
1000	if elem1.typ ~= elem2.typ then
1001		return false
1002	end
1003	if elem1.modpack ~= elem2.modpack then
1004		return false
1005	end
1006
1007	if elem1.path ~= elem2.path then
1008		return false
1009	end
1010
1011	return true
1012end
1013
1014--------------------------------------------------------------------------------
1015function modmgr.gettab(name)
1016	local retval = ""
1017
1018	if name == "mod_mgr" then
1019		retval = retval .. modmgr.tab()
1020	end
1021
1022	if name == "dialog_rename_modpack" then
1023		retval = retval .. modmgr.dialog_rename_modpack()
1024	end
1025
1026	if name == "dialog_delete_mod" then
1027		retval = retval .. modmgr.dialog_delete_mod()
1028	end
1029
1030	if name == "dialog_configure_world" then
1031		retval = retval .. modmgr.dialog_configure_world()
1032	end
1033
1034	return retval
1035end
1036
1037--------------------------------------------------------------------------------
1038function modmgr.mod_exists(basename)
1039
1040	if modmgr.global_mods == nil then
1041		modmgr.refresh_globals()
1042	end
1043
1044	if filterlist.raw_index_by_uid(modmgr.global_mods,basename) > 0 then
1045		return true
1046	end
1047
1048	return false
1049end
1050
1051--------------------------------------------------------------------------------
1052function modmgr.get_global_mod(idx)
1053
1054	if modmgr.global_mods == nil then
1055		return nil
1056	end
1057
1058	if idx == nil or idx < 1 or idx > filterlist.size(modmgr.global_mods) then
1059		return nil
1060	end
1061
1062	return filterlist.get_list(modmgr.global_mods)[idx]
1063end
1064
1065--------------------------------------------------------------------------------
1066function modmgr.refresh_globals()
1067	modmgr.global_mods = filterlist.create(
1068					modmgr.preparemodlist, --refresh
1069					modmgr.comparemod, --compare
1070					function(element,uid) --uid match
1071						if element.name == uid then
1072							return true
1073						end
1074					end,
1075					nil, --filter
1076					{}
1077					)
1078	filterlist.add_sort_mechanism(modmgr.global_mods, "alphabetic", sort_mod_list)
1079	filterlist.set_sortmode(modmgr.global_mods, "alphabetic")
1080end
1081
1082--------------------------------------------------------------------------------
1083function modmgr.identify_filetype(name)
1084
1085	if name:sub(-3):lower() == "zip" then
1086		return {
1087				name = name,
1088				type = "zip"
1089				}
1090	end
1091
1092	if name:sub(-6):lower() == "tar.gz" or
1093		name:sub(-3):lower() == "tgz"then
1094		return {
1095				name = name,
1096				type = "tgz"
1097				}
1098	end
1099
1100	if name:sub(-6):lower() == "tar.bz2" then
1101		return {
1102				name = name,
1103				type = "tbz"
1104				}
1105	end
1106
1107	if name:sub(-2):lower() == "7z" then
1108		return {
1109				name = name,
1110				type = "7z"
1111				}
1112	end
1113
1114	return {
1115		name = name,
1116		type = "ukn"
1117	}
1118end
1119