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