Fix nearly all warnings
[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_settings.setBool("load_mod_"+modname, false);
120         }
121         // find missing mods (mentioned in world.mt, but not installed)
122         for(std::set<std::string>::iterator it = mod_names.begin();
123                 it != mod_names.end(); ++it)
124         {
125                 std::string modname = *it;
126                 if(m_addonmods.count(modname) == 0)
127                         m_settings.remove("load_mod_"+modname);
128         }
129         std::string worldmtfile = m_wspec.path+DIR_DELIM+"world.mt";
130         m_settings.updateConfigFile(worldmtfile.c_str());
131 }
132
133 void GUIConfigureWorld::drawMenu()
134 {
135         gui::IGUISkin* skin = Environment->getSkin();
136         if (!skin)
137                 return;
138         video::IVideoDriver* driver = Environment->getVideoDriver();
139         
140         video::SColor bgcolor(140,0,0,0);
141         driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
142
143         gui::IGUIElement::draw();
144 }
145
146
147 void GUIConfigureWorld::regenerateGui(v2u32 screensize)
148 {
149
150         /*
151                 Remove stuff
152         */
153         removeChildren();
154         
155         /*
156                 Calculate new sizes and positions
157         */
158         core::rect<s32> rect(
159                         screensize.X/2 - 580/2,
160                         screensize.Y/2 - 300/2,
161                         screensize.X/2 + 580/2,
162                         screensize.Y/2 + 300/2
163         );
164         
165         DesiredRect = rect;
166         recalculateAbsolutePosition(false);
167
168         v2s32 topleft = v2s32(10, 10);
169
170         /*
171                 Add stuff
172         */
173         changeCtype("");
174         {
175                 core::rect<s32> rect(0, 0, 200, 20);
176                 rect += topleft;
177                 //proper text is set below, when a mod is selected
178                 m_modname_text = Environment->addStaticText(L"Mod: N/A", rect, false, 
179                                                                                                         false, this, -1);
180         }
181         {
182                 core::rect<s32> rect(0, 0, 200, 20);
183                 rect += v2s32(0, 25) + topleft;
184                 wchar_t* text = wgettext("enabled");
185                 m_enabled_checkbox = 
186                         Environment->addCheckBox(false, rect, this, GUI_ID_ENABLED_CHECKBOX, 
187                                                                          text);
188                 delete[] text;
189                 m_enabled_checkbox->setVisible(false);
190         }
191         {
192                 core::rect<s32> rect(0, 0, 85, 30);
193                 rect = rect + v2s32(0, 25) + topleft;
194                 wchar_t* text = wgettext("Enable All");
195                 m_enableall = Environment->addButton(rect, this, GUI_ID_ENABLEALL,
196                                                                                          text);
197                 delete[] text;
198                 m_enableall->setVisible(false);
199         }
200         {
201                 core::rect<s32> rect(0, 0, 85, 30);
202                 rect = rect + v2s32(115, 25) + topleft;
203                 wchar_t* text = wgettext("Disable All");
204                 m_disableall = Environment->addButton(rect, this, GUI_ID_DISABLEALL, text );
205                 delete[] text;
206                 m_disableall->setVisible(false);
207         }
208         {
209                 core::rect<s32> rect(0, 0, 200, 20);
210                 rect += v2s32(0, 60) + topleft;
211                 wchar_t* text = wgettext("depends on:");
212                 Environment->addStaticText(text, rect, false, false, this, -1);
213                 delete[] text;
214         }
215         {
216                 core::rect<s32> rect(0, 0, 200, 85);
217                 rect += v2s32(0, 80) + topleft;
218                 m_dependencies_listbox = 
219                         Environment->addListBox(rect, this, GUI_ID_DEPENDS_LISTBOX, true);
220         }
221         {
222                 core::rect<s32> rect(0, 0, 200, 20);
223                 rect += v2s32(0, 175) + topleft;
224                 wchar_t* text = wgettext("is required by:");
225                 Environment->addStaticText( text, rect, false, false, this, -1);
226                 delete[] text;
227         }
228         {
229                 core::rect<s32> rect(0, 0, 200, 85);
230                 rect += v2s32(0, 195) + topleft;
231                 m_rdependencies_listbox = 
232                         Environment->addListBox(rect,this, GUI_ID_RDEPENDS_LISTBOX,true);
233         }
234         {
235                 core::rect<s32> rect(0, 0, 340, 250);
236                 rect += v2s32(220, 0) + topleft;
237                 m_treeview = Environment->addTreeView(rect, this,
238                                                                                           GUI_ID_MOD_TREEVIEW,true);
239                 gui::IGUITreeViewNode* node 
240                         = m_treeview->getRoot()->addChildBack(L"Add-Ons");
241                 buildTreeView(m_addontree, node);
242         }
243         {
244                 core::rect<s32> rect(0, 0, 120, 30);
245                 rect = rect + v2s32(330, 270) - topleft;
246                 wchar_t* text = wgettext("Cancel");
247                 Environment->addButton(rect, this, GUI_ID_CANCEL, text);
248                 delete[] text;
249         }
250         {
251                 core::rect<s32> rect(0, 0, 120, 30);
252                 rect = rect + v2s32(460, 270) - topleft;
253                 wchar_t* text = wgettext("Save");
254                 Environment->addButton(rect, this, GUI_ID_SAVE, text);
255                 delete[] text;
256         }
257         changeCtype("C");
258
259         // at start, none of the treeview nodes is selected, so we select
260         // the first element in the treeview of mods manually here.
261         if(m_treeview->getRoot()->hasChilds())
262         {
263                 m_treeview->getRoot()->getFirstChild()->setExpanded(true);
264                 m_treeview->getRoot()->getFirstChild()->setSelected(true);
265                 // Because a manual ->setSelected() doesn't cause an event, we
266                 // have to do this here:
267                 adjustSidebar();
268         }
269 }
270
271 bool GUIConfigureWorld::OnEvent(const SEvent& event)
272 {
273
274         gui::IGUITreeViewNode* selected_node = NULL;
275         if(m_treeview != NULL)
276                 selected_node = m_treeview->getSelected();
277
278         if(event.EventType==EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
279         {
280                 switch (event.KeyInput.Key) {
281                 case KEY_ESCAPE: {
282                         quitMenu();
283                         return true;
284                 }
285                 //      irrlicht's built-in TreeView gui has no keyboard control,
286                 //      so we do it here: up/down to select prev/next node,
287                 //      left/right to collapse/expand nodes, space to toggle
288                 //      enabled/disabled.
289                 case KEY_DOWN: {
290                         if(selected_node != NULL)
291                         {
292                                 gui::IGUITreeViewNode* node = selected_node->getNextVisible();
293                                 if(node != NULL)
294                                 {
295                                         node->setSelected(true);
296                                         adjustSidebar();
297                                 }
298                         }
299                         return true;
300                 }
301                 case KEY_UP: {
302                         if(selected_node != NULL)
303                         {
304                                 gui::IGUITreeViewNode* node = selected_node->getPrevSibling();
305                                 if(node!=NULL)
306                                 {
307                                         node->setSelected(true);
308                                         adjustSidebar();
309                                 }
310                                 else 
311                                 {
312                                         gui::IGUITreeViewNode* parent = selected_node->getParent();
313                                         if(selected_node == parent->getFirstChild() &&
314                                            parent != m_treeview->getRoot()) 
315                                         {
316                                                 parent->setSelected(true);
317                                                 adjustSidebar();
318                                         }
319                                 }
320                         }
321                         return true;
322                 }
323                 case KEY_RIGHT: {
324                         if(selected_node != NULL && selected_node->hasChilds())
325                                 selected_node->setExpanded(true);
326                         return true;
327                 }
328                 case KEY_LEFT: {
329                         if(selected_node != NULL && selected_node->hasChilds())
330                                 selected_node->setExpanded(false);
331                         return true;
332                 }
333                 case KEY_SPACE: {
334                         if(selected_node != NULL && !selected_node->hasChilds() && 
335                            selected_node->getText() != NULL)
336                         {
337                                 std::string modname = wide_to_narrow(selected_node->getText());
338                                 bool checked = m_enabled_checkbox->isChecked();
339                                 m_enabled_checkbox->setChecked(!checked);
340                                 setEnabled(modname,!checked);
341                         }
342                         return true;
343                 }
344                 default: {}
345                 }
346         }
347         if(event.EventType==EET_GUI_EVENT)
348         {
349                 if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
350                                 && isVisible())
351                 {
352                         if(!canTakeFocus(event.GUIEvent.Element))
353                         {
354                                 dstream<<"GUIConfigureWorld: Not allowing focus change."
355                                                 <<std::endl;
356                                 // Returning true disables focus change
357                                 return true;
358                         }
359                 }
360                 if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED){
361                         switch(event.GUIEvent.Caller->getID()){
362                         case GUI_ID_CANCEL: {
363                                 quitMenu();
364                                 return true;
365                         }
366                         case GUI_ID_SAVE: {
367                                 std::string worldmtfile = m_wspec.path+DIR_DELIM+"world.mt";
368                                 m_settings.updateConfigFile(worldmtfile.c_str());
369
370                                 // The trailing spaces are because there seems to be a
371                                 // bug in the text-size calculation. if the trailing
372                                 // spaces are removed from the message text, the
373                                 // message gets wrapped and parts of it are cut off:
374                                 wchar_t* text = wgettext("Configuration saved.  ");
375                                 GUIMessageMenu *menu = 
376                                         new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
377                                                                          text );
378                                 delete[] text;
379                                 menu->drop();
380
381                                 try
382                                 {
383                                         ModConfiguration modconf(m_wspec.path);
384                                         if(!modconf.isConsistent())
385                                         {
386                                                 wchar_t* text = wgettext("Warning: Configuration not consistent.  ");
387                                                 GUIMessageMenu *menu =
388                                                         new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
389                                                                                  text );
390                                                 delete[] text;
391                                                 menu->drop();
392                                         }
393                                 }
394                                 catch(ModError &err)
395                                 {
396                                         errorstream<<err.what()<<std::endl;
397                                         std::wstring text = narrow_to_wide(err.what()) + wgettext("\nCheck debug.txt for details.");
398                                         GUIMessageMenu *menu =
399                                                 new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
400                                                                          text );
401                                         menu->drop();
402                                 }
403
404                                 quitMenu();     
405                                 return true;
406                         }
407                         case GUI_ID_ENABLEALL: {
408                                 if(selected_node != NULL && selected_node->getParent() == m_treeview->getRoot())
409                                 {  
410                                         enableAllMods(m_addonmods,true);
411                                 } 
412                                 else if(selected_node != NULL && selected_node->getText() != NULL)
413                                 {  
414                                         std::string modname = wide_to_narrow(selected_node->getText());
415                                         std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
416                                         if(mod_it != m_addonmods.end())
417                                                 enableAllMods(mod_it->second.modpack_content,true);
418                                 }
419                                 return true;
420                         }
421                         case GUI_ID_DISABLEALL: {
422                                 if(selected_node != NULL && selected_node->getParent() == m_treeview->getRoot())
423                                 {
424                                         enableAllMods(m_addonmods,false);
425                                 } 
426                                 if(selected_node != NULL && selected_node->getText() != NULL)
427                                 {
428                                         std::string modname = wide_to_narrow(selected_node->getText());
429                                         std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
430                                         if(mod_it != m_addonmods.end())
431                                                 enableAllMods(mod_it->second.modpack_content,false);
432                                 }
433                                 return true;
434                         }
435                         }
436                 }       
437                 if(event.GUIEvent.EventType==gui::EGET_CHECKBOX_CHANGED &&
438                         event.GUIEvent.Caller->getID() == GUI_ID_ENABLED_CHECKBOX)
439                 {
440                         if(selected_node != NULL && !selected_node->hasChilds() && 
441                            selected_node->getText() != NULL)
442                         {
443                                 std::string modname = wide_to_narrow(selected_node->getText());
444                                 setEnabled(modname, m_enabled_checkbox->isChecked());
445                         }
446                         return true;
447                 }
448                 if(event.GUIEvent.EventType==gui::EGET_TREEVIEW_NODE_SELECT &&
449                    event.GUIEvent.Caller->getID() == GUI_ID_MOD_TREEVIEW)
450                 {
451                         selecting_dep = -1;
452                         selecting_rdep = -1;
453                         adjustSidebar();
454                         return true;
455                 }
456                 if(event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED &&
457                    event.GUIEvent.Caller->getID() == GUI_ID_DEPENDS_LISTBOX)
458                 {
459                         selecting_dep = m_dependencies_listbox->getSelected();
460                         selecting_rdep = -1;
461                         return true;
462                 }
463                 if(event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED &&
464                    event.GUIEvent.Caller->getID() == GUI_ID_RDEPENDS_LISTBOX)
465                 {
466                         selecting_dep = -1;
467                         selecting_rdep = m_rdependencies_listbox->getSelected();
468                         return true;
469                 }
470
471                 //double click in a dependency listbox: find corresponding
472                 //treeviewnode and select it:
473                 if(event.GUIEvent.EventType==gui::EGET_LISTBOX_SELECTED_AGAIN)
474                 {
475                         gui::IGUIListBox* box = NULL;
476                         if(event.GUIEvent.Caller->getID() == GUI_ID_DEPENDS_LISTBOX)
477                         {
478                                 box = m_dependencies_listbox;
479                                 if(box->getSelected() != selecting_dep)
480                                         return true;
481                         }
482                         if(event.GUIEvent.Caller->getID() == GUI_ID_RDEPENDS_LISTBOX)
483                         {
484                                 box = m_rdependencies_listbox;
485                                 if(box->getSelected() != selecting_rdep)
486                                         return true;
487                         }
488                         if(box != NULL && box->getSelected() != -1 &&
489                            box->getListItem(box->getSelected()) != NULL)
490                         {
491                                 std::string modname = 
492                                         wide_to_narrow(box->getListItem(box->getSelected()));
493                                 std::map<std::string, gui::IGUITreeViewNode*>::iterator it =
494                                         m_nodes.find(modname);
495                                 if(it != m_nodes.end())
496                                 {
497                                         // select node and make sure node is visible by
498                                         // expanding all parents
499                                         gui::IGUITreeViewNode* node = (*it).second;
500                                         node->setSelected(true);
501                                         while(!node->isVisible() && 
502                                                   node->getParent() != m_treeview->getRoot())
503                                         {
504                                                 node = node->getParent();
505                                                 node->setExpanded(true);
506                                         }
507                                         adjustSidebar();
508                                 }
509                         }
510                         return true;
511                 }
512         }
513
514         return Parent ? Parent->OnEvent(event) : false;
515 }
516
517 void GUIConfigureWorld::buildTreeView(std::map<std::string, ModSpec> mods, 
518                                                                           gui::IGUITreeViewNode* node)
519 {
520         for(std::map<std::string,ModSpec>::iterator it = mods.begin();
521                 it != mods.end(); ++it)    
522         {
523                 std::string modname = (*it).first;
524                 ModSpec mod = (*it).second;
525                 gui::IGUITreeViewNode* new_node = 
526                         node->addChildBack(narrow_to_wide(modname).c_str());
527                 m_nodes.insert(std::make_pair(modname, new_node));
528                 if(mod.is_modpack)
529                         buildTreeView(mod.modpack_content, new_node);
530                 else
531                 {
532                         // set icon for node: x for disabled mods, checkmark for enabled mods
533                         bool mod_enabled = false;
534                         if(m_settings.exists("load_mod_"+modname))
535                                 mod_enabled = m_settings.getBool("load_mod_"+modname);
536                         if(mod_enabled)
537                                 new_node->setIcon(CHECKMARK_STR);
538                         else
539                                 new_node->setIcon(CROSS_STR);
540                 }
541         }
542 }
543
544
545 void GUIConfigureWorld::adjustSidebar()
546 {
547         gui::IGUITreeViewNode* node = m_treeview->getSelected();
548         std::wstring modname_w;
549         if(node->getText() != NULL)
550                 modname_w = node->getText();
551         else 
552                 modname_w = L"N/A";
553         std::string modname = wide_to_narrow(modname_w);
554
555         ModSpec mspec;
556         std::map<std::string, ModSpec>::iterator it = m_addonmods.find(modname);
557         if(it != m_addonmods.end())
558                 mspec = it->second;
559
560         m_dependencies_listbox->clear();
561         m_rdependencies_listbox->clear();
562
563         // if no mods installed, there is nothing to enable/disable, so we
564         // don't show buttons or checkbox on the sidebar
565         if(node->getParent() == m_treeview->getRoot() && !node->hasChilds())
566         {
567                 m_disableall->setVisible(false);
568                 m_enableall->setVisible(false);
569                 m_enabled_checkbox->setVisible(false);
570                 return;
571         } 
572         
573     // a modpack is not enabled/disabled by itself, only its cotnents
574     // are. so we show show enable/disable all buttons, but hide the
575     // checkbox
576         if(node->getParent() == m_treeview->getRoot() ||
577            mspec.is_modpack)
578         {
579                 m_enabled_checkbox->setVisible(false);
580                 m_disableall->setVisible(true);
581                 m_enableall->setVisible(true);
582                 m_modname_text->setText((L"Modpack: "+modname_w).c_str());
583                 return;
584         }       
585
586         // for a normal mod, we hide the enable/disable all buttons, but show the checkbox.
587         m_disableall->setVisible(false);
588         m_enableall->setVisible(false);
589         m_enabled_checkbox->setVisible(true);
590         m_modname_text->setText((L"Mod: "+modname_w).c_str());
591
592         // the mod is enabled unless it is disabled in the world.mt settings. 
593         bool mod_enabled = true;
594         if(m_settings.exists("load_mod_"+modname))
595                 mod_enabled = m_settings.getBool("load_mod_"+modname);
596         m_enabled_checkbox->setChecked(mod_enabled);
597
598         for(std::set<std::string>::iterator it=mspec.depends.begin();
599                 it != mspec.depends.end(); ++it)
600         {
601                 // check if it is an add-on mod or a game/world mod. We only
602                 // want to show add-ons
603                 std::string dependency = (*it);
604                 if(m_gamemods.count(dependency) > 0)
605                         dependency += " (" + m_gspec.id + ")";
606                 else if(m_worldmods.count(dependency) > 0)
607                         dependency += " (" + m_wspec.name + ")";
608                 else if(m_addonmods.count(dependency) == 0)
609                         dependency += " (missing)";
610                 m_dependencies_listbox->addItem(narrow_to_wide(dependency).c_str());
611         }
612
613         // reverse dependencies of this mod:
614         std::pair< std::multimap<std::string, std::string>::iterator, 
615                         std::multimap<std::string, std::string>::iterator > rdep = 
616                 m_reverse_depends.equal_range(modname);
617         for(std::multimap<std::string,std::string>::iterator it = rdep.first;
618                 it != rdep.second; ++it)
619         {
620                 // check if it is an add-on mod or a game/world mod. We only
621                 // want to show add-ons
622                 std::string rdependency = (*it).second;
623                 if(m_addonmods.count(rdependency) > 0)
624                         m_rdependencies_listbox->addItem(narrow_to_wide(rdependency).c_str());
625         }
626 }
627
628 void GUIConfigureWorld::enableAllMods(std::map<std::string, ModSpec> mods,bool enable)
629 {
630         for(std::map<std::string, ModSpec>::iterator it = mods.begin();
631                 it != mods.end(); ++it)
632         {
633                 ModSpec mod = (*it).second;
634                 if(mod.is_modpack) 
635                         // a modpack, recursively enable all mods in it
636                         enableAllMods(mod.modpack_content,enable);
637                 else // not a modpack
638                         setEnabled(mod.name, enable);
639
640         }
641 }
642
643 void GUIConfigureWorld::enableMod(std::string modname)
644 {
645         std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
646         if(mod_it == m_addonmods.end()){
647                 errorstream << "enableMod() called with invalid mod name \"" << modname << "\"" << std::endl;
648                 return;
649         }
650         ModSpec mspec = mod_it->second;
651         m_settings.setBool("load_mod_"+modname,true);
652         std::map<std::string,gui::IGUITreeViewNode*>::iterator it = 
653                 m_nodes.find(modname);
654         if(it != m_nodes.end())
655                 (*it).second->setIcon(CHECKMARK_STR);
656         //also enable all dependencies
657         for(std::set<std::string>::iterator it=mspec.depends.begin();
658                 it != mspec.depends.end(); ++it)
659         {
660                 std::string dependency = *it;
661                 // only enable it if it is an add-on mod
662                 if(m_addonmods.count(dependency) > 0)
663                         enableMod(dependency);
664         }
665 }
666
667 void GUIConfigureWorld::disableMod(std::string modname)
668 {
669         std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
670         if(mod_it == m_addonmods.end()){
671                 errorstream << "disableMod() called with invalid mod name \"" << modname << "\"" << std::endl;
672                 return;
673         }
674
675         m_settings.setBool("load_mod_"+modname,false);
676         std::map<std::string,gui::IGUITreeViewNode*>::iterator it = 
677                 m_nodes.find(modname);
678         if(it != m_nodes.end())
679                 (*it).second->setIcon(CROSS_STR);
680         //also disable all mods that depend on this one
681         std::pair<std::multimap<std::string, std::string>::iterator, 
682                           std::multimap<std::string, std::string>::iterator > rdep = 
683                 m_reverse_depends.equal_range(modname);
684         for(std::multimap<std::string,std::string>::iterator it = rdep.first;
685                 it != rdep.second; ++it)
686         {
687                 std::string rdependency = (*it).second;
688                 // only disable it if it is an add-on mod
689                 if(m_addonmods.count(rdependency) > 0)
690                         disableMod(rdependency);
691         }       
692 }
693