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