Re-add jungles, apple trees
[oweals/minetest.git] / src / guiConfigureWorld.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20
21 #include <iostream> 
22 #include <string>
23 #include <map>
24
25 #include "guiConfigureWorld.h"
26 #include "guiMessageMenu.h"
27 #include <IGUIButton.h>
28 #include <IGUICheckBox.h>
29 #include <IGUIListBox.h>
30 #include <IGUIStaticText.h>
31 #include <IGUITreeView.h>
32 #include "gettext.h"
33 #include "util/string.h"
34 #include "settings.h"
35 #include "filesys.h"
36
37 enum
38 {
39         GUI_ID_MOD_TREEVIEW = 101,
40         GUI_ID_ENABLED_CHECKBOX,
41         GUI_ID_ENABLEALL,
42         GUI_ID_DISABLEALL,
43         GUI_ID_DEPENDS_LISTBOX,
44         GUI_ID_RDEPENDS_LISTBOX,
45         GUI_ID_CANCEL,
46         GUI_ID_SAVE
47 };
48
49 #define QUESTIONMARK_STR L"?"
50 #define CHECKMARK_STR    L"\411"
51 #define CROSS_STR        L"\403"
52
53 GUIConfigureWorld::GUIConfigureWorld(gui::IGUIEnvironment* env,
54                 gui::IGUIElement* parent, s32 id,
55                 IMenuManager *menumgr, WorldSpec wspec):
56         GUIModalMenu(env, parent, id, menumgr),
57         m_wspec(wspec),
58         m_gspec(findWorldSubgame(m_wspec.path)),
59         m_menumgr(menumgr)
60 {
61         //will be initialized in regenerateGUI()
62         m_treeview=NULL;
63
64         // game mods
65         m_gamemods = flattenModTree(getModsInPath(m_gspec.gamemods_path));
66
67         // world mods
68         std::string worldmods_path = wspec.path + DIR_DELIM + "worldmods";
69         m_worldmods = flattenModTree(getModsInPath(worldmods_path));
70
71         // fill m_addontree with add-on mods
72         std::set<std::string> paths = m_gspec.addon_mods_paths;
73         for(std::set<std::string>::iterator it=paths.begin();
74                 it != paths.end(); ++it)
75         {
76                 std::map<std::string,ModSpec> mods = getModsInPath(*it);
77                 m_addontree.insert(mods.begin(), mods.end());
78         }
79
80         // expand modpacks
81         m_addonmods = flattenModTree(m_addontree);
82
83         // collect reverse dependencies
84         for(std::map<std::string, ModSpec>::iterator it = m_addonmods.begin();
85                 it != m_addonmods.end(); ++it)
86         {
87                 std::string modname = (*it).first;
88                 ModSpec mod = (*it).second;
89                 for(std::set<std::string>::iterator dep_it = mod.depends.begin();
90                         dep_it != mod.depends.end(); ++dep_it)
91                 {
92                         m_reverse_depends.insert(std::make_pair((*dep_it),modname));
93                 }
94         }
95
96         m_settings.readConfigFile((m_wspec.path + DIR_DELIM + "world.mt").c_str());
97         std::vector<std::string> names = m_settings.getNames();
98
99         // mod_names contains the names of mods mentioned in the world.mt file
100         std::set<std::string> mod_names;
101         for(std::vector<std::string>::iterator it = names.begin(); 
102                 it != names.end(); ++it)
103         {       
104                 std::string name = *it;  
105                 if (name.compare(0,9,"load_mod_")==0)
106                         mod_names.insert(name.substr(9));
107         }
108
109         // find new mods (installed but not mentioned in world.mt)
110         for(std::map<std::string, ModSpec>::iterator it = m_addonmods.begin();
111                 it != m_addonmods.end(); ++it)
112         {
113                 std::string modname = (*it).first;
114                 ModSpec mod = (*it).second;
115                 // a mod is new if it is not a modpack, and does not occur in
116                 // mod_names
117                 if(!mod.is_modpack &&
118                    mod_names.count(modname) == 0)
119                         m_new_mod_names.insert(modname);
120         }
121         if(!m_new_mod_names.empty())
122         {
123                 GUIMessageMenu *menu = 
124                         new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
125                                                            wgettext("Warning: Some mods are not configured yet.\n" 
126                                                                                 "They will be enabled by default when you save the configuration.  ")); 
127                 menu->drop();
128         }
129         
130
131         // find missing mods (mentioned in world.mt, but not installed)
132         std::set<std::string> missing_mods;
133         for(std::set<std::string>::iterator it = mod_names.begin();
134                 it != mod_names.end(); ++it)
135         {
136                 std::string modname = *it;
137                 if(m_addonmods.count(modname) == 0)
138                         missing_mods.insert(modname);
139         }
140         if(!missing_mods.empty())
141         {
142                 GUIMessageMenu *menu = 
143                         new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
144                                                            wgettext("Warning: Some configured mods are missing.\n"
145                                                                                 "Their setting will be removed when you save the configuration.  ")); 
146                 for(std::set<std::string>::iterator it = missing_mods.begin();
147                         it != missing_mods.end(); ++it)
148                         m_settings.remove("load_mod_"+(*it));
149                 menu->drop();
150         }       
151 }
152
153 void GUIConfigureWorld::drawMenu()
154 {
155         gui::IGUISkin* skin = Environment->getSkin();
156         if (!skin)
157                 return;
158         video::IVideoDriver* driver = Environment->getVideoDriver();
159         
160         video::SColor bgcolor(140,0,0,0);
161         driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
162
163         gui::IGUIElement::draw();
164 }
165
166
167 void GUIConfigureWorld::regenerateGui(v2u32 screensize)
168 {
169
170         /*
171                 Remove stuff
172         */
173         removeChildren();
174         
175         /*
176                 Calculate new sizes and positions
177         */
178         core::rect<s32> rect(
179                         screensize.X/2 - 580/2,
180                         screensize.Y/2 - 300/2,
181                         screensize.X/2 + 580/2,
182                         screensize.Y/2 + 300/2
183         );
184         
185         DesiredRect = rect;
186         recalculateAbsolutePosition(false);
187
188         v2s32 size = rect.getSize();
189
190         v2s32 topleft = v2s32(10, 10);
191
192         /*
193                 Add stuff
194         */
195         changeCtype("");
196         {
197                 core::rect<s32> rect(0, 0, 200, 20);
198                 rect += topleft;
199                 //proper text is set below, when a mod is selected
200                 m_modname_text = Environment->addStaticText(L"Mod: N/A", rect, false, 
201                                                                                                         false, this, -1);
202         }
203         {
204                 core::rect<s32> rect(0, 0, 200, 20);
205                 rect += v2s32(0, 25) + topleft;
206                 m_enabled_checkbox = 
207                         Environment->addCheckBox(false, rect, this, GUI_ID_ENABLED_CHECKBOX, 
208                                                                          wgettext("enabled"));
209                 m_enabled_checkbox->setVisible(false);
210         }
211         {
212                 core::rect<s32> rect(0, 0, 85, 30);
213                 rect = rect + v2s32(0, 25) + topleft;
214                 m_enableall = Environment->addButton(rect, this, GUI_ID_ENABLEALL,
215                                                                                          wgettext("Enable All"));
216                 m_enableall->setVisible(false);
217         }
218         {
219                 core::rect<s32> rect(0, 0, 85, 30);
220                 rect = rect + v2s32(115, 25) + topleft;
221                 m_disableall = Environment->addButton(rect, this, GUI_ID_DISABLEALL,
222                                                                                           wgettext("Disable All"));
223                 m_disableall->setVisible(false);
224         }
225         {
226                 core::rect<s32> rect(0, 0, 200, 20);
227                 rect += v2s32(0, 60) + topleft;
228                 Environment->addStaticText(wgettext("depends on:"),
229                         rect, false, false, this, -1);
230         }
231         {
232                 core::rect<s32> rect(0, 0, 200, 85);
233                 rect += v2s32(0, 80) + topleft;
234                 m_dependencies_listbox = 
235                         Environment->addListBox(rect, this, GUI_ID_DEPENDS_LISTBOX, true);
236         }
237         {
238                 core::rect<s32> rect(0, 0, 200, 20);
239                 rect += v2s32(0, 175) + topleft;
240                 Environment->addStaticText(wgettext("is required by:"),
241                                         rect, false, false, this, -1);
242         }
243         {
244                 core::rect<s32> rect(0, 0, 200, 85);
245                 rect += v2s32(0, 195) + topleft;
246                 m_rdependencies_listbox = 
247                         Environment->addListBox(rect,this, GUI_ID_RDEPENDS_LISTBOX,true);
248         }
249         {
250                 core::rect<s32> rect(0, 0, 340, 250);
251                 rect += v2s32(220, 0) + topleft;
252                 m_treeview = Environment->addTreeView(rect, this,
253                                                                                           GUI_ID_MOD_TREEVIEW,true);
254                 gui::IGUITreeViewNode* node 
255                         = m_treeview->getRoot()->addChildBack(L"Add-Ons");
256                 buildTreeView(m_addontree, node);
257         }
258         {
259                 core::rect<s32> rect(0, 0, 120, 30);
260                 rect = rect + v2s32(330, 270) - topleft;
261                 Environment->addButton(rect, this, GUI_ID_CANCEL,
262                         wgettext("Cancel"));
263         }
264         {
265                 core::rect<s32> rect(0, 0, 120, 30);
266                 rect = rect + v2s32(460, 270) - topleft;
267                 Environment->addButton(rect, this, GUI_ID_SAVE,
268                         wgettext("Save"));
269         }
270         changeCtype("C");
271
272         // at start, none of the treeview nodes is selected, so we select
273         // the first element in the treeview of mods manually here.
274         if(m_treeview->getRoot()->hasChilds())
275         {
276                 m_treeview->getRoot()->getFirstChild()->setExpanded(true);
277                 m_treeview->getRoot()->getFirstChild()->setSelected(true);
278                 // Because a manual ->setSelected() doesn't cause an event, we
279                 // have to do this here:
280                 adjustSidebar();
281         }
282 }
283
284 bool GUIConfigureWorld::OnEvent(const SEvent& event)
285 {
286
287         gui::IGUITreeViewNode* selected_node = NULL;
288         if(m_treeview != NULL)
289                 selected_node = m_treeview->getSelected();
290
291         if(event.EventType==EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
292         {
293                 switch (event.KeyInput.Key) {
294                 case KEY_ESCAPE: {
295                         quitMenu();
296                         return true;
297                 }
298                 //      irrlicht's built-in TreeView gui has no keyboard control,
299                 //      so we do it here: up/down to select prev/next node,
300                 //      left/right to collapse/expand nodes, space to toggle
301                 //      enabled/disabled.
302                 case KEY_DOWN: {
303                         if(selected_node != NULL)
304                         {
305                                 gui::IGUITreeViewNode* node = selected_node->getNextVisible();
306                                 if(node != NULL)
307                                 {
308                                         node->setSelected(true);
309                                         adjustSidebar();
310                                 }
311                         }
312                         return true;
313                 }
314                 case KEY_UP: {
315                         if(selected_node != NULL)
316                         {
317                                 gui::IGUITreeViewNode* node = selected_node->getPrevSibling();
318                                 if(node!=NULL)
319                                 {
320                                         node->setSelected(true);
321                                         adjustSidebar();
322                                 }
323                                 else 
324                                 {
325                                         gui::IGUITreeViewNode* parent = selected_node->getParent();
326                                         if(selected_node == parent->getFirstChild() &&
327                                            parent != m_treeview->getRoot()) 
328                                         {
329                                                 parent->setSelected(true);
330                                                 adjustSidebar();
331                                         }
332                                 }
333                         }
334                         return true;
335                 }
336                 case KEY_RIGHT: {
337                         if(selected_node != NULL && selected_node->hasChilds())
338                                 selected_node->setExpanded(true);
339                         return true;
340                 }
341                 case KEY_LEFT: {
342                         if(selected_node != NULL && selected_node->hasChilds())
343                                 selected_node->setExpanded(false);
344                         return true;
345                 }
346                 case KEY_SPACE: {
347                         if(selected_node != NULL && !selected_node->hasChilds() && 
348                            selected_node->getText() != NULL)
349                         {
350                                 std::string modname = wide_to_narrow(selected_node->getText());
351                                 bool checked = m_enabled_checkbox->isChecked();
352                                 m_enabled_checkbox->setChecked(!checked);
353                                 setEnabled(modname,!checked);
354                         }
355                         return true;
356                 }
357                 default: {}
358                 }
359         }
360         if(event.EventType==EET_GUI_EVENT)
361         {
362                 if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
363                                 && isVisible())
364                 {
365                         if(!canTakeFocus(event.GUIEvent.Element))
366                         {
367                                 dstream<<"GUIConfigureWorld: Not allowing focus change."
368                                                 <<std::endl;
369                                 // Returning true disables focus change
370                                 return true;
371                         }
372                 }
373                 if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED){
374                         switch(event.GUIEvent.Caller->getID()){
375                         case GUI_ID_CANCEL: {
376                                 quitMenu();
377                                 return true;
378                         }
379                         case GUI_ID_SAVE: {
380                                 for(std::set<std::string>::iterator it = m_new_mod_names.begin();
381                                         it!= m_new_mod_names.end(); ++it)
382                                 {
383                                         m_settings.setBool("load_mod_"+(*it),true);
384                                 }
385                                 std::string worldmtfile = m_wspec.path+DIR_DELIM+"world.mt";
386                                 m_settings.updateConfigFile(worldmtfile.c_str());
387
388                                 // The trailing spaces are because there seems to be a
389                                 // bug in the text-size calculation. if the trailing
390                                 // spaces are removed from the message text, the
391                                 // message gets wrapped and parts of it are cut off:
392                                 GUIMessageMenu *menu = 
393                                         new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
394                                                                            wgettext("Configuration saved.  "));
395                                 menu->drop();
396
397                                 ModConfiguration modconf(m_wspec.path);
398                                 if(!modconf.isConsistent())
399                                 {
400                                         GUIMessageMenu *menu = 
401                                                 new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
402                                                                                    wgettext("Warning: Configuration not consistent.  "));
403                                         menu->drop();
404                                 }
405
406                                 quitMenu();     
407                                 return true;
408                         }
409                         case GUI_ID_ENABLEALL: {
410                                 if(selected_node != NULL && selected_node->getParent() == m_treeview->getRoot())
411                                 {  
412                                         enableAllMods(m_addonmods,true);
413                                 } 
414                                 else if(selected_node != NULL && selected_node->getText() != NULL)
415                                 {  
416                                         std::string modname = wide_to_narrow(selected_node->getText());
417                                         std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
418                                         if(mod_it != m_addonmods.end())
419                                                 enableAllMods(mod_it->second.modpack_content,true);
420                                 }
421                                 return true;
422                         }
423                         case GUI_ID_DISABLEALL: {
424                                 if(selected_node != NULL && selected_node->getParent() == m_treeview->getRoot())
425                                 {
426                                         enableAllMods(m_addonmods,false);
427                                 } 
428                                 if(selected_node != NULL && selected_node->getText() != NULL)
429                                 {
430                                         std::string modname = wide_to_narrow(selected_node->getText());
431                                         std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
432                                         if(mod_it != m_addonmods.end())
433                                                 enableAllMods(mod_it->second.modpack_content,false);
434                                 }
435                                 return true;
436                         }
437                         }
438                 }       
439                 if(event.GUIEvent.EventType==gui::EGET_CHECKBOX_CHANGED &&
440                         event.GUIEvent.Caller->getID() == GUI_ID_ENABLED_CHECKBOX)
441                 {
442                         if(selected_node != NULL && !selected_node->hasChilds() && 
443                            selected_node->getText() != NULL)
444                         {
445                                 std::string modname = wide_to_narrow(selected_node->getText());
446                                 setEnabled(modname, m_enabled_checkbox->isChecked());
447                         }
448                         return true;
449                 }
450                 if(event.GUIEvent.EventType==gui::EGET_TREEVIEW_NODE_SELECT &&
451                    event.GUIEvent.Caller->getID() == GUI_ID_MOD_TREEVIEW)
452                 {
453                         selecting_dep = -1;
454                         selecting_rdep = -1;
455                         adjustSidebar();
456                         return true;
457                 }
458                 if(event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED &&
459                    event.GUIEvent.Caller->getID() == GUI_ID_DEPENDS_LISTBOX)
460                 {
461                         selecting_dep = m_dependencies_listbox->getSelected();
462                         selecting_rdep = -1;
463                         return true;
464                 }
465                 if(event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED &&
466                    event.GUIEvent.Caller->getID() == GUI_ID_RDEPENDS_LISTBOX)
467                 {
468                         selecting_dep = -1;
469                         selecting_rdep = m_rdependencies_listbox->getSelected();
470                         return true;
471                 }
472
473                 //double click in a dependency listbox: find corresponding
474                 //treeviewnode and select it:
475                 if(event.GUIEvent.EventType==gui::EGET_LISTBOX_SELECTED_AGAIN)
476                 {
477                         gui::IGUIListBox* box = NULL;
478                         if(event.GUIEvent.Caller->getID() == GUI_ID_DEPENDS_LISTBOX)
479                         {
480                                 box = m_dependencies_listbox;
481                                 if(box->getSelected() != selecting_dep)
482                                         return true;
483                         }
484                         if(event.GUIEvent.Caller->getID() == GUI_ID_RDEPENDS_LISTBOX)
485                         {
486                                 box = m_rdependencies_listbox;
487                                 if(box->getSelected() != selecting_rdep)
488                                         return true;
489                         }
490                         if(box != NULL && box->getSelected() != -1 &&
491                            box->getListItem(box->getSelected()) != NULL)
492                         {
493                                 std::string modname = 
494                                         wide_to_narrow(box->getListItem(box->getSelected()));
495                                 std::map<std::string, gui::IGUITreeViewNode*>::iterator it =
496                                         m_nodes.find(modname);
497                                 if(it != m_nodes.end())
498                                 {
499                                         // select node and make sure node is visible by
500                                         // expanding all parents
501                                         gui::IGUITreeViewNode* node = (*it).second;
502                                         node->setSelected(true);
503                                         while(!node->isVisible() && 
504                                                   node->getParent() != m_treeview->getRoot())
505                                         {
506                                                 node = node->getParent();
507                                                 node->setExpanded(true);
508                                         }
509                                         adjustSidebar();
510                                 }
511                         }
512                         return true;
513                 }
514         }
515
516         return Parent ? Parent->OnEvent(event) : false;
517 }
518
519 void GUIConfigureWorld::buildTreeView(std::map<std::string, ModSpec> mods, 
520                                                                           gui::IGUITreeViewNode* node)
521 {
522         for(std::map<std::string,ModSpec>::iterator it = mods.begin();
523                 it != mods.end(); ++it)    
524         {
525                 std::string modname = (*it).first;
526                 ModSpec mod = (*it).second;
527                 gui::IGUITreeViewNode* new_node = 
528                         node->addChildBack(narrow_to_wide(modname).c_str());
529                 m_nodes.insert(std::make_pair(modname, new_node));
530                 if(mod.is_modpack)
531                         buildTreeView(mod.modpack_content, new_node);
532                 else
533                 {
534                         // set icon for node: ? for new mods, x for disabled mods,
535                         // checkmark for enabled mods
536                         if(m_new_mod_names.count(modname) > 0)
537                         {
538                                 new_node->setIcon(QUESTIONMARK_STR);
539                         }
540                         else
541                         {
542                                 bool mod_enabled = true;
543                                 if(m_settings.exists("load_mod_"+modname))
544                                         mod_enabled = m_settings.getBool("load_mod_"+modname);
545                                 if(mod_enabled)
546                                         new_node->setIcon(CHECKMARK_STR);
547                                 else 
548                                         new_node->setIcon(CROSS_STR);
549                         }
550                 }
551         }
552 }
553
554
555 void GUIConfigureWorld::adjustSidebar()
556 {
557         gui::IGUITreeViewNode* node = m_treeview->getSelected();
558         std::wstring modname_w;
559         if(node->getText() != NULL)
560                 modname_w = node->getText();
561         else 
562                 modname_w = L"N/A";
563         std::string modname = wide_to_narrow(modname_w);
564
565         ModSpec mspec;
566         std::map<std::string, ModSpec>::iterator it = m_addonmods.find(modname);
567         if(it != m_addonmods.end())
568                 mspec = it->second;
569
570         m_dependencies_listbox->clear();
571         m_rdependencies_listbox->clear();
572
573         // if no mods installed, there is nothing to enable/disable, so we
574         // don't show buttons or checkbox on the sidebar
575         if(node->getParent() == m_treeview->getRoot() && !node->hasChilds())
576         {
577                 m_disableall->setVisible(false);
578                 m_enableall->setVisible(false);
579                 m_enabled_checkbox->setVisible(false);
580                 return;
581         } 
582         
583     // a modpack is not enabled/disabled by itself, only its cotnents
584     // are. so we show show enable/disable all buttons, but hide the
585     // checkbox
586         if(node->getParent() == m_treeview->getRoot() ||
587            mspec.is_modpack)
588         {
589                 m_enabled_checkbox->setVisible(false);
590                 m_disableall->setVisible(true);
591                 m_enableall->setVisible(true);
592                 m_modname_text->setText((L"Modpack: "+modname_w).c_str());
593                 return;
594         }       
595
596         // for a normal mod, we hide the enable/disable all buttons, but show the checkbox.
597         m_disableall->setVisible(false);
598         m_enableall->setVisible(false);
599         m_enabled_checkbox->setVisible(true);
600         m_modname_text->setText((L"Mod: "+modname_w).c_str());
601
602         // the mod is enabled unless it is disabled in the world.mt settings. 
603         bool mod_enabled = true;
604         if(m_settings.exists("load_mod_"+modname))
605                 mod_enabled = m_settings.getBool("load_mod_"+modname);
606         m_enabled_checkbox->setChecked(mod_enabled);
607
608         for(std::set<std::string>::iterator it=mspec.depends.begin();
609                 it != mspec.depends.end(); ++it)
610         {
611                 // check if it is an add-on mod or a game/world mod. We only
612                 // want to show add-ons
613                 std::string dependency = (*it);
614                 if(m_gamemods.count(dependency) > 0)
615                         dependency += " (" + m_gspec.id + ")";
616                 else if(m_worldmods.count(dependency) > 0)
617                         dependency += " (" + m_wspec.name + ")";
618                 else if(m_addonmods.count(dependency) == 0)
619                         dependency += " (missing)";
620                 m_dependencies_listbox->addItem(narrow_to_wide(dependency).c_str());
621         }
622
623         // reverse dependencies of this mod:
624         std::pair< std::multimap<std::string, std::string>::iterator, 
625                         std::multimap<std::string, std::string>::iterator > rdep = 
626                 m_reverse_depends.equal_range(modname);
627         for(std::multimap<std::string,std::string>::iterator it = rdep.first;
628                 it != rdep.second; ++it)
629         {
630                 // check if it is an add-on mod or a game/world mod. We only
631                 // want to show add-ons
632                 std::string rdependency = (*it).second;
633                 if(m_addonmods.count(rdependency) > 0)
634                         m_rdependencies_listbox->addItem(narrow_to_wide(rdependency).c_str());
635         }
636 }
637
638 void GUIConfigureWorld::enableAllMods(std::map<std::string, ModSpec> mods,bool enable)
639 {
640         for(std::map<std::string, ModSpec>::iterator it = mods.begin();
641                 it != mods.end(); ++it)
642         {
643                 ModSpec mod = (*it).second;
644                 if(mod.is_modpack) 
645                         // a modpack, recursively enable all mods in it
646                         enableAllMods(mod.modpack_content,enable);
647                 else // not a modpack
648                         setEnabled(mod.name, enable);
649
650         }
651 }
652
653 void GUIConfigureWorld::enableMod(std::string modname)
654 {
655         std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
656         if(mod_it == m_addonmods.end()){
657                 errorstream << "enableMod() called with invalid mod name \"" << modname << "\"" << std::endl;
658                 return;
659         }
660         ModSpec mspec = mod_it->second;
661         m_settings.setBool("load_mod_"+modname,true);
662         std::map<std::string,gui::IGUITreeViewNode*>::iterator it = 
663                 m_nodes.find(modname);
664         if(it != m_nodes.end())
665                 (*it).second->setIcon(CHECKMARK_STR);
666         m_new_mod_names.erase(modname);
667         //also enable all dependencies
668         for(std::set<std::string>::iterator it=mspec.depends.begin();
669                 it != mspec.depends.end(); ++it)
670         {
671                 std::string dependency = *it;
672                 // only enable it if it is an add-on mod
673                 if(m_addonmods.count(dependency) > 0)
674                         enableMod(dependency);
675         }
676 }
677
678 void GUIConfigureWorld::disableMod(std::string modname)
679 {
680         std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
681         if(mod_it == m_addonmods.end()){
682                 errorstream << "disableMod() called with invalid mod name \"" << modname << "\"" << std::endl;
683                 return;
684         }
685
686         m_settings.setBool("load_mod_"+modname,false);
687         std::map<std::string,gui::IGUITreeViewNode*>::iterator it = 
688                 m_nodes.find(modname);
689         if(it != m_nodes.end())
690                 (*it).second->setIcon(CROSS_STR);
691         m_new_mod_names.erase(modname);
692         //also disable all mods that depend on this one
693         std::pair<std::multimap<std::string, std::string>::iterator, 
694                           std::multimap<std::string, std::string>::iterator > rdep = 
695                 m_reverse_depends.equal_range(modname);
696         for(std::multimap<std::string,std::string>::iterator it = rdep.first;
697                 it != rdep.second; ++it)
698         {
699                 std::string rdependency = (*it).second;
700                 // only disable it if it is an add-on mod
701                 if(m_addonmods.count(rdependency) > 0)
702                         disableMod(rdependency);
703         }       
704 }
705