Просмотр исходного кода

Merge pull request #4787 from IvanSavenko/mod_presets

Support for mod presets (part 1)
Ivan Savenko 10 месяцев назад
Родитель
Сommit
c6806cedfb
70 измененных файлов с 5841 добавлено и 4111 удалено
  1. 0 3
      Mods/vcmi/Content/config/chinese.json
  2. 0 3
      Mods/vcmi/Content/config/czech.json
  3. 0 3
      Mods/vcmi/Content/config/english.json
  4. 0 2
      Mods/vcmi/Content/config/german.json
  5. 0 2
      Mods/vcmi/Content/config/polish.json
  6. 0 2
      Mods/vcmi/Content/config/portuguese.json
  7. 0 2
      Mods/vcmi/Content/config/spanish.json
  8. 0 2
      Mods/vcmi/Content/config/swedish.json
  9. 0 2
      Mods/vcmi/Content/config/ukrainian.json
  10. 3 3
      client/globalLobby/GlobalLobbyRoomWindow.cpp
  11. 0 11
      client/mainmenu/CMainMenu.cpp
  12. 0 5
      config/schemas/settings.json
  13. 8 6
      launcher/CMakeLists.txt
  14. BIN
      launcher/icons/submod-disabled.png
  15. BIN
      launcher/icons/submod-enabled.png
  16. 0 5
      launcher/mainwindow_moc.cpp
  17. 0 1
      launcher/mainwindow_moc.h
  18. 0 434
      launcher/modManager/cmodlist.cpp
  19. 0 112
      launcher/modManager/cmodlist.h
  20. 269 303
      launcher/modManager/cmodlistview_moc.cpp
  21. 16 19
      launcher/modManager/cmodlistview_moc.h
  22. 231 0
      launcher/modManager/modstate.cpp
  23. 69 0
      launcher/modManager/modstate.h
  24. 45 147
      launcher/modManager/modstatecontroller.cpp
  25. 14 14
      launcher/modManager/modstatecontroller.h
  26. 98 64
      launcher/modManager/modstateitemmodel_moc.cpp
  27. 33 25
      launcher/modManager/modstateitemmodel_moc.h
  28. 130 0
      launcher/modManager/modstatemodel.cpp
  29. 52 0
      launcher/modManager/modstatemodel.h
  30. 2 0
      launcher/resources.qrc
  31. 304 145
      launcher/translation/chinese.ts
  32. 304 145
      launcher/translation/czech.ts
  33. 248 281
      launcher/translation/english.ts
  34. 304 145
      launcher/translation/french.ts
  35. 304 145
      launcher/translation/german.ts
  36. 304 145
      launcher/translation/polish.ts
  37. 304 145
      launcher/translation/portuguese.ts
  38. 280 218
      launcher/translation/russian.ts
  39. 281 215
      launcher/translation/spanish.ts
  40. 304 145
      launcher/translation/swedish.ts
  41. 304 145
      launcher/translation/ukrainian.ts
  42. 280 218
      launcher/translation/vietnamese.ts
  43. 4 2
      lib/CMakeLists.txt
  44. 0 1
      lib/IGameCallback.cpp
  45. 22 34
      lib/VCMI_Lib.cpp
  46. 1 0
      lib/filesystem/Filesystem.cpp
  47. 1 1
      lib/json/JsonNode.h
  48. 1 1
      lib/mapObjectConstructors/CObjectClassesHandler.cpp
  49. 2 2
      lib/mapObjects/ObstacleSetHandler.cpp
  50. 2 2
      lib/mapping/CMapService.cpp
  51. 5 5
      lib/modding/ActiveModsInSaveList.cpp
  52. 5 2
      lib/modding/ActiveModsInSaveList.h
  53. 120 384
      lib/modding/CModHandler.cpp
  54. 12 36
      lib/modding/CModHandler.h
  55. 0 206
      lib/modding/CModInfo.cpp
  56. 0 85
      lib/modding/CModInfo.h
  57. 12 56
      lib/modding/ContentTypeHandler.cpp
  58. 3 10
      lib/modding/ContentTypeHandler.h
  59. 219 0
      lib/modding/ModDescription.cpp
  60. 69 0
      lib/modding/ModDescription.h
  61. 706 0
      lib/modding/ModManager.cpp
  62. 144 0
      lib/modding/ModManager.h
  63. 5 5
      lib/modding/ModVerificationInfo.cpp
  64. 1 1
      mapeditor/mapcontroller.cpp
  65. 1 2
      mapeditor/mapcontroller.h
  66. 5 5
      mapeditor/mapsettings/modsettings.cpp
  67. 1 1
      mapeditor/validator.cpp
  68. 3 2
      server/GlobalLobbyProcessor.cpp
  69. 4 4
      vcmiqt/jsonutils.cpp
  70. 2 2
      vcmiqt/jsonutils.h

+ 0 - 3
Mods/vcmi/Content/config/chinese.json

@@ -188,9 +188,6 @@
 	"vcmi.server.errors.existingProcess"     : "一个VCMI进程已经在运行,启动新进程前请结束它。",
 	"vcmi.server.errors.modsToEnable"    : "{需要启用的mod列表}",
 	"vcmi.server.errors.modsToDisable"   : "{需要禁用的mod列表}",
-	"vcmi.server.errors.modNoDependency" : "读取mod包 {'%s'}失败!\n 需要的mod {'%s'} 没有安装或无效!\n",
-	"vcmi.server.errors.modDependencyLoop" : "读取mod包 {'%s'}失败!\n 这个mod可能存在循环(软)依赖!",
-	"vcmi.server.errors.modConflict" : "读取的mod包 {'%s'}无法运行!\n 与另一个mod {'%s'}冲突!\n",
 	"vcmi.server.errors.unknownEntity" : "加载保存失败! 在保存的游戏中发现未知实体'%s'! 保存可能与当前安装的mod版本不兼容!",
 
 	"vcmi.dimensionDoor.seaToLandError" : "无法在陆地与海洋之间使用异次元之门传送。",

+ 0 - 3
Mods/vcmi/Content/config/czech.json

@@ -187,9 +187,6 @@
 	"vcmi.server.errors.existingProcess" : "Již běží jiný server VCMI. Prosím, ukončete ho před startem nové hry.",
 	"vcmi.server.errors.modsToEnable"    : "{Následující modifikace jsou nutné pro načtení hry}",
 	"vcmi.server.errors.modsToDisable"   : "{Následující modifikace musí být zakázány}",
-	"vcmi.server.errors.modNoDependency" : "Nelze načíst modifikaci {'%s'}!\n Závisí na modifikaci {'%s'}, která není aktivní!\n",
-	"vcmi.server.errors.modDependencyLoop" : "Nelze načíst modifikaci {'%s'}!\n Modifikace může být součástí (nepřímé) závislostní smyčky.",
-	"vcmi.server.errors.modConflict" : "Nelze načíst modifikaci {'%s'}!\n Je v kolizi s aktivní modifikací {'%s'}!\n",
 	"vcmi.server.errors.unknownEntity" : "Nelze načíst uloženou pozici! Neznámá entita '%s' nalezena v uložené pozici! Uložná pozice nemusí být kompatibilní s aktuálními verzemi modifikací!",
 
 	"vcmi.dimensionDoor.seaToLandError" : "Pomocí dimenzní brány není možné se teleportovat z moře na pevninu nebo naopak.",

+ 0 - 3
Mods/vcmi/Content/config/english.json

@@ -188,9 +188,6 @@
 	"vcmi.server.errors.existingProcess" : "Another VCMI server process is running. Please terminate it before starting a new game.",
 	"vcmi.server.errors.modsToEnable"    : "{Following mods are required}",
 	"vcmi.server.errors.modsToDisable"   : "{Following mods must be disabled}",
-	"vcmi.server.errors.modNoDependency" : "Failed to load mod {'%s'}!\n It depends on mod {'%s'} which is not active!\n",
-	"vcmi.server.errors.modDependencyLoop" : "Failed to load mod {'%s'}!\n It maybe in a (soft) dependency loop.",
-	"vcmi.server.errors.modConflict" : "Failed to load mod {'%s'}!\n Conflicts with active mod {'%s'}!\n",
 	"vcmi.server.errors.unknownEntity" : "Failed to load save! Unknown entity '%s' found in saved game! Save may not be compatible with currently installed version of mods!",
 	
 	"vcmi.dimensionDoor.seaToLandError" : "It's not possible to teleport from sea to land or vice versa with a Dimension Door.",

+ 0 - 2
Mods/vcmi/Content/config/german.json

@@ -188,9 +188,7 @@
 	"vcmi.server.errors.existingProcess" : "Es läuft ein weiterer vcmiserver-Prozess, bitte beendet diesen zuerst",
 	"vcmi.server.errors.modsToEnable"    : "{Erforderliche Mods um das Spiel zu laden}",
 	"vcmi.server.errors.modsToDisable"   : "{Folgende Mods müssen deaktiviert werden}",
-	"vcmi.server.errors.modNoDependency" : "Mod {'%s'} konnte nicht geladen werden!\n Sie hängt von Mod {'%s'} ab, die nicht aktiv ist!\n",
 	"vcmi.server.errors.modDependencyLoop" : "Mod {'%s'} konnte nicht geladen werden.!\n Möglicherweise befindet sie sich in einer (weichen) Abhängigkeitsschleife.",
-	"vcmi.server.errors.modConflict" : "Mod {'%s'} konnte nicht geladen werden!\n Konflikte mit aktiver Mod {'%s'}!\n",
 	"vcmi.server.errors.unknownEntity" : "Spielstand konnte nicht geladen werden! Unbekannte Entität '%s' im gespeicherten Spiel gefunden! Der Spielstand ist möglicherweise nicht mit der aktuell installierten Version der Mods kompatibel!",
 	
 	"vcmi.dimensionDoor.seaToLandError" : "Es ist nicht möglich, mit einer Dimensionstür vom Meer zum Land oder umgekehrt zu teleportieren.",

+ 0 - 2
Mods/vcmi/Content/config/polish.json

@@ -182,9 +182,7 @@
 	"vcmi.server.errors.existingProcess" : "Inny proces 'vcmiserver' został już uruchomiony, zakończ go nim przejdziesz dalej",
 	"vcmi.server.errors.modsToEnable"    : "{Następujące mody są wymagane do wczytania gry}",
 	"vcmi.server.errors.modsToDisable"   : "{Następujące mody muszą zostać wyłączone}",
-	"vcmi.server.errors.modNoDependency" : "Nie udało się wczytać moda {'%s'}!\n Jest on zależny od moda {'%s'} który nie jest aktywny!\n",
 	"vcmi.server.errors.modDependencyLoop" : "Nie udało się wczytać moda {'%s'}!\n Być może znajduje się w pętli zależności",
-	"vcmi.server.errors.modConflict" : "Nie udało się wczytać moda {'%s'}!\n Konflikty z aktywnym modem {'%s'}!\n",
 	"vcmi.server.errors.unknownEntity" : "Nie udało się wczytać zapisu! Nieznany element '%s' znaleziony w pliku zapisu! Zapis może nie być zgodny z aktualnie zainstalowaną wersją modów!",
 
 	"vcmi.dimensionDoor.seaToLandError" : "Nie jest możliwa teleportacja przez drzwi wymiarów z wód na ląd i na odwrót.",

+ 0 - 2
Mods/vcmi/Content/config/portuguese.json

@@ -174,8 +174,6 @@
 	"vcmi.server.errors.existingProcess" : "Outro processo do servidor VCMI está em execução. Por favor, termine-o antes de iniciar um novo jogo.",
 	"vcmi.server.errors.modsToEnable"    : "{Os seguintes mods são necessários}",
 	"vcmi.server.errors.modsToDisable"   : "{Os seguintes mods devem ser desativados}",
-	"vcmi.server.errors.modNoDependency" : "Falha ao carregar o mod {'%s'}!\n Ele depende do mod {'%s'}, que não está ativo!\n",
-	"vcmi.server.errors.modConflict" : "Falha ao carregar o mod {'%s'}!\n Conflito com o mod ativo {'%s'}!\n",
 	"vcmi.server.errors.unknownEntity" : "Falha ao carregar o jogo salvo! Entidade desconhecida '%s' encontrada no jogo salvo! O jogo salvo pode não ser compatível com a versão atualmente instalada dos mods!",
 	
 	"vcmi.dimensionDoor.seaToLandError" : "Não é possível teleportar do mar para a terra ou vice-versa com uma Porta Dimensional.",

+ 0 - 2
Mods/vcmi/Content/config/spanish.json

@@ -79,8 +79,6 @@
 	"vcmi.server.errors.modsToEnable"    : "{Se requieren los siguientes mods}",
 	"vcmi.server.errors.modsToDisable"   : "{Deben desactivarse los siguientes mods}",
 	"vcmi.server.confirmReconnect"       : "¿Quieres reconectar a la última sesión?",
-	"vcmi.server.errors.modNoDependency" : "Error al cargar el mod {'%s'}.\n Depende del mod {'%s'}, que no está activo.\n",
-	"vcmi.server.errors.modConflict" : "Error al cargar el mod {'%s'}.\n Conflicto con el mod activo {'%s'}.\n",
 	"vcmi.server.errors.unknownEntity" : "Error al cargar la partida guardada. ¡Se encontró una entidad desconocida '%s' en la partida guardada! Es posible que la partida no sea compatible con la versión actualmente instalada de los mods.",
 
 	"vcmi.settingsMainWindow.generalTab.hover" : "General",

+ 0 - 2
Mods/vcmi/Content/config/swedish.json

@@ -188,9 +188,7 @@
 	"vcmi.server.errors.existingProcess"  : "En annan VCMI-serverprocess är igång. Vänligen avsluta den innan du startar ett nytt spel.",
 	"vcmi.server.errors.modsToEnable"     : "{Följande modd(ar) krävs}",
 	"vcmi.server.errors.modsToDisable"    : "{Följande modd(ar) måste inaktiveras}",
-	"vcmi.server.errors.modNoDependency"  : "Misslyckades med att ladda modd {'%s'}!\n Den är beroende av modd {'%s'} som inte är aktiverad!\n",
 	"vcmi.server.errors.modDependencyLoop": "Misslyckades med att ladda modd {'%s'}!\n Den kanske är i en (mjuk) beroendeloop.",
-	"vcmi.server.errors.modConflict"      : "Misslyckades med att ladda modd {'%s'}!\n Konflikter med aktiverad modd {'%s'}!\n",
 	"vcmi.server.errors.unknownEntity"    : "Misslyckades med att ladda sparat spel! Okänd enhet '%s' hittades i sparat spel! Sparningen kanske inte är kompatibel med den aktuella versionen av moddarna!",
 
 	"vcmi.dimensionDoor.seaToLandError" : "Det går inte att teleportera sig från hav till land eller tvärtom med trollformeln 'Dimensionsdörr'.",

+ 0 - 2
Mods/vcmi/Content/config/ukrainian.json

@@ -139,8 +139,6 @@
 	"vcmi.server.errors.modsToEnable"    : "{Потрібні модифікації для завантаження гри}",
 	"vcmi.server.errors.modsToDisable"   : "{Модифікації що мають бути вимкнені}",
 	"vcmi.server.confirmReconnect"       : "Підключитися до минулої сесії?",
-	"vcmi.server.errors.modNoDependency" : "Не вдалося увімкнути мод {'%s'}!\n Модифікація потребує мод {'%s'} який зараз не активний!\n",
-	"vcmi.server.errors.modConflict" : "Не вдалося увімкнути мод {'%s'}!\n Конфліктує з активним модом {'%s'}!\n",
 	"vcmi.server.errors.unknownEntity" : "Не вдалося завантажити гру! У збереженій грі знайдено невідомий об'єкт '%s'! Це збереження може бути несумісним зі встановленою версією модифікацій!",
 	
 	"vcmi.dimensionDoor.seaToLandError" : "Неможливо телепортуватися з моря на сушу або навпаки за допомогою просторової брами",

+ 3 - 3
client/globalLobby/GlobalLobbyRoomWindow.cpp

@@ -27,7 +27,7 @@
 #include "../widgets/ObjectLists.h"
 
 #include "../../lib/modding/CModHandler.h"
-#include "../../lib/modding/CModInfo.h"
+#include "../../lib/modding/ModDescription.h"
 #include "../../lib/texts/CGeneralTextHandler.h"
 #include "../../lib/texts/MetaString.h"
 
@@ -128,14 +128,14 @@ GlobalLobbyRoomWindow::GlobalLobbyRoomWindow(GlobalLobbyWindow * window, const s
 		GlobalLobbyRoomModInfo modInfo;
 		modInfo.status = modEntry.second;
 		if (modEntry.second == ModVerificationStatus::EXCESSIVE)
-			modInfo.version = CGI->modh->getModInfo(modEntry.first).getVerificationInfo().version.toString();
+			modInfo.version = CGI->modh->getModInfo(modEntry.first).getVersion().toString();
 		else
 			modInfo.version = roomDescription.modList.at(modEntry.first).version.toString();
 
 		if (modEntry.second == ModVerificationStatus::NOT_INSTALLED)
 			modInfo.modName = roomDescription.modList.at(modEntry.first).name;
 		else
-			modInfo.modName = CGI->modh->getModInfo(modEntry.first).getVerificationInfo().name;
+			modInfo.modName = CGI->modh->getModInfo(modEntry.first).getName();
 
 		modVerificationList.push_back(modInfo);
 	}

+ 0 - 11
client/mainmenu/CMainMenu.cpp

@@ -362,17 +362,6 @@ void CMainMenu::update()
 		menu->switchToTab(menu->getActiveTab());
 	}
 
-	static bool warnedAboutModDependencies = false;
-
-	if (!warnedAboutModDependencies)
-	{
-		warnedAboutModDependencies = true;
-		auto errorMessages = CGI->modh->getModLoadErrors();
-
-		if (!errorMessages.empty())
-			CInfoWindow::showInfoDialog(errorMessages, std::vector<std::shared_ptr<CComponent>>(), PlayerColor(1));
-	}
-
 	// Handles mouse and key input
 	GH.handleEvents();
 	GH.windows().simpleRedraw();

+ 0 - 5
config/schemas/settings.json

@@ -620,7 +620,6 @@
 				"defaultRepositoryURL", 
 				"extraRepositoryURL", 
 				"extraRepositoryEnabled", 
-				"enableInstalledMods", 
 				"autoCheckRepositories", 
 				"ignoreSslErrors",
 				"updateOnStartup", 
@@ -647,10 +646,6 @@
 					"type" : "boolean",
 					"default" : false
 				},
-				"enableInstalledMods" : {
-					"type" : "boolean",
-					"default" : true
-				},
 				"ignoreSslErrors" : {
 					"type" : "boolean",
 					"default" : false

+ 8 - 6
launcher/CMakeLists.txt

@@ -7,10 +7,11 @@ set(launcher_SRCS
 		StdInc.cpp
 		aboutProject/aboutproject_moc.cpp
 		modManager/cdownloadmanager_moc.cpp
-		modManager/cmodlist.cpp
-		modManager/cmodlistmodel_moc.cpp
+		modManager/modstateitemmodel_moc.cpp
 		modManager/cmodlistview_moc.cpp
-		modManager/cmodmanager.cpp
+		modManager/modstatecontroller.cpp
+		modManager/modstatemodel.cpp
+		modManager/modstate.cpp
 		modManager/imageviewer_moc.cpp
 		modManager/chroniclesextractor.cpp
 		settingsView/csettingsview_moc.cpp
@@ -37,10 +38,11 @@ set(launcher_HEADERS
 		StdInc.h
 		aboutProject/aboutproject_moc.h
 		modManager/cdownloadmanager_moc.h
-		modManager/cmodlist.h
-		modManager/cmodlistmodel_moc.h
+		modManager/modstateitemmodel_moc.h
 		modManager/cmodlistview_moc.h
-		modManager/cmodmanager.h
+		modManager/modstatecontroller.h
+		modManager/modstatemodel.h
+		modManager/modstate.h
 		modManager/imageviewer_moc.h
 		modManager/chroniclesextractor.h
 		settingsView/csettingsview_moc.h

BIN
launcher/icons/submod-disabled.png


BIN
launcher/icons/submod-enabled.png


+ 0 - 5
launcher/mainwindow_moc.cpp

@@ -206,11 +206,6 @@ void MainWindow::on_startEditorButton_clicked()
 	startEditor({});
 }
 
-const CModList & MainWindow::getModList() const
-{
-	return ui->modlistView->getModList();
-}
-
 CModListView * MainWindow::getModView()
 {
 	return ui->modlistView;

+ 0 - 1
launcher/mainwindow_moc.h

@@ -46,7 +46,6 @@ public:
 	explicit MainWindow(QWidget * parent = nullptr);
 	~MainWindow() override;
 
-	const CModList & getModList() const;
 	CModListView * getModView();
 
 	void updateTranslation();

+ 0 - 434
launcher/modManager/cmodlist.cpp

@@ -1,434 +0,0 @@
-/*
- * cmodlist.cpp, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-#include "StdInc.h"
-#include "cmodlist.h"
-
-#include "../lib/CConfigHandler.h"
-#include "../../lib/filesystem/CFileInputStream.h"
-#include "../../lib/GameConstants.h"
-#include "../../lib/modding/CModVersion.h"
-
-QString CModEntry::sizeToString(double size)
-{
-	static const std::array sizes {
-		QT_TRANSLATE_NOOP("File size", "%1 B"),
-		QT_TRANSLATE_NOOP("File size", "%1 KiB"),
-		QT_TRANSLATE_NOOP("File size", "%1 MiB"),
-		QT_TRANSLATE_NOOP("File size", "%1 GiB"),
-		QT_TRANSLATE_NOOP("File size", "%1 TiB")
-	};
-	size_t index = 0;
-	while(size > 1024 && index < sizes.size())
-	{
-		size /= 1024;
-		index++;
-	}
-	return QCoreApplication::translate("File size", sizes[index]).arg(QString::number(size, 'f', 1));
-}
-
-CModEntry::CModEntry(QVariantMap repository, QVariantMap localData, QVariantMap modSettings, QString modname)
-	: repository(repository), localData(localData), modSettings(modSettings), modname(modname)
-{
-}
-
-bool CModEntry::isEnabled() const
-{
-	if(!isInstalled())
-		return false;
-
-	if (!isVisible())
-		return false;
-
-	return modSettings["active"].toBool();
-}
-
-bool CModEntry::isDisabled() const
-{
-	if(!isInstalled())
-		return false;
-	return !isEnabled();
-}
-
-bool CModEntry::isAvailable() const
-{
-	if(isInstalled())
-		return false;
-	return !repository.isEmpty();
-}
-
-bool CModEntry::isUpdateable() const
-{
-	if(!isInstalled())
-		return false;
-
-	auto installedVer = localData["installedVersion"].toString().toStdString();
-	auto availableVer = repository["latestVersion"].toString().toStdString();
-
-	return (CModVersion::fromString(installedVer) < CModVersion::fromString(availableVer));
-}
-
-bool isCompatible(const QVariantMap & compatibility)
-{
-	auto compatibleMin = CModVersion::fromString(compatibility["min"].toString().toStdString());
-	auto compatibleMax = CModVersion::fromString(compatibility["max"].toString().toStdString());
-
-	return (compatibleMin.isNull() || CModVersion::GameVersion().compatible(compatibleMin, true, true))
-			&& (compatibleMax.isNull() || compatibleMax.compatible(CModVersion::GameVersion(), true, true));
-}
-
-bool CModEntry::isCompatible() const
-{
-	return ::isCompatible(localData["compatibility"].toMap());
-}
-
-bool CModEntry::isEssential() const
-{
-	return getName() == "vcmi";
-}
-
-bool CModEntry::isInstalled() const
-{
-	return !localData.isEmpty();
-}
-
-bool CModEntry::isVisible() const
-{
-	if (isCompatibilityPatch())
-	{
-		if (isSubmod())
-			return false;
-	}
-
-	if (isTranslation())
-	{
-		// Do not show not installed translation mods to languages other than player language
-		if (localData.empty() && getBaseValue("language") != QString::fromStdString(settings["general"]["language"].String()) )
-			return false;
-	}
-
-	return !localData.isEmpty() || (!repository.isEmpty() && !repository.contains("mod"));
-}
-
-bool CModEntry::isTranslation() const
-{
-	return getBaseValue("modType").toString() == "Translation";
-}
-
-bool CModEntry::isCompatibilityPatch() const
-{
-	return getBaseValue("modType").toString() == "Compatibility";
-}
-
-bool CModEntry::isSubmod() const
-{
-	return getName().contains('.');
-}
-
-int CModEntry::getModStatus() const
-{
-	int status = 0;
-	if(isEnabled())
-		status |= ModStatus::ENABLED;
-	if(isInstalled())
-		status |= ModStatus::INSTALLED;
-	if(isUpdateable())
-		status |= ModStatus::UPDATEABLE;
-
-	return status;
-}
-
-QString CModEntry::getName() const
-{
-	return modname;
-}
-
-QVariant CModEntry::getValue(QString value) const
-{
-	return getValueImpl(value, true);
-}
-
-QStringList CModEntry::getDependencies() const
-{
-	QStringList result;
-	for (auto const & entry : getValue("depends").toStringList())
-		result.push_back(entry.toLower());
-	return result;
-}
-
-QStringList CModEntry::getConflicts() const
-{
-	QStringList result;
-	for (auto const & entry : getValue("conflicts").toStringList())
-		result.push_back(entry.toLower());
-	return result;
-}
-
-QVariant CModEntry::getBaseValue(QString value) const
-{
-	return getValueImpl(value, false);
-}
-
-QVariant CModEntry::getValueImpl(QString value, bool localized) const
-
-{
-	QString langValue = QString::fromStdString(settings["general"]["language"].String());
-
-	// Priorities
-	// 1) data from newest version
-	// 2) data from preferred language
-
-	bool useRepositoryData = repository.contains(value);
-
-	if(repository.contains(value) && localData.contains(value))
-	{
-		// value is present in both repo and locally installed. Select one from latest version
-		auto installedVer = localData["installedVersion"].toString().toStdString();
-		auto availableVer = repository["latestVersion"].toString().toStdString();
-
-		useRepositoryData = CModVersion::fromString(installedVer) < CModVersion::fromString(availableVer);
-	}
-
-	auto & storage = useRepositoryData ? repository : localData;
-
-	if(localized && storage.contains(langValue))
-	{
-		auto langStorage = storage[langValue].toMap();
-		if (langStorage.contains(value))
-			return langStorage[value];
-	}
-
-	if(storage.contains(value))
-		return storage[value];
-
-	return QVariant();
-}
-
-QVariantMap CModList::copyField(QVariantMap data, QString from, QString to) const
-{
-	QVariantMap renamed;
-
-	for(auto it = data.begin(); it != data.end(); it++)
-	{
-		QVariantMap modConf = it.value().toMap();
-
-		modConf.insert(to, modConf.value(from));
-		renamed.insert(it.key(), modConf);
-	}
-	return renamed;
-}
-
-void CModList::reloadRepositories()
-{
-	cachedMods.clear();
-}
-
-void CModList::resetRepositories()
-{
-	repositories.clear();
-	cachedMods.clear();
-}
-
-void CModList::addRepository(QVariantMap data)
-{
-	for(auto & key : data.keys())
-		data[key.toLower()] = data.take(key);
-	repositories.push_back(copyField(data, "version", "latestVersion"));
-
-	cachedMods.clear();
-}
-
-void CModList::setLocalModList(QVariantMap data)
-{
-	localModList = copyField(data, "version", "installedVersion");
-	cachedMods.clear();
-}
-
-void CModList::setModSettings(QVariant data)
-{
-	modSettings = data.toMap();
-	cachedMods.clear();
-}
-
-void CModList::modChanged(QString modID)
-{
-	cachedMods.clear();
-}
-
-static QVariant getValue(QVariant input, QString path)
-{
-	if(path.size() > 1)
-	{
-		QString entryName = path.section('/', 0, 1);
-		QString remainder = "/" + path.section('/', 2, -1);
-
-		entryName.remove(0, 1);
-		return getValue(input.toMap().value(entryName), remainder);
-	}
-	else
-	{
-		return input;
-	}
-}
-
-const CModEntry & CModList::getMod(QString modName) const
-{
-	modName = modName.toLower();
-
-	auto it = cachedMods.find(modName);
-
-	if (it != cachedMods.end())
-		return it.value();
-
-	auto itNew = cachedMods.insert(modName, getModUncached(modName));
-	return *itNew;
-}
-
-CModEntry CModList::getModUncached(QString modname) const
-{
-	QVariantMap repo;
-	QVariantMap local = localModList[modname].toMap();
-	QVariantMap settings;
-
-	QString path = modname;
-	path = "/" + path.replace(".", "/mods/");
-	QVariant conf = getValue(modSettings, path);
-
-	if(conf.isNull())
-	{
-		settings["active"] = !local.value("keepDisabled").toBool();
-	}
-	else
-	{
-		if(!conf.toMap().isEmpty())
-		{
-			settings = conf.toMap();
-			if(settings.value("active").isNull())
-				settings["active"] = !local.value("keepDisabled").toBool();
-		}
-		else
-			settings.insert("active", conf);
-	}
-	
-	if(settings["active"].toBool())
-	{
-		QString rootPath = path.section('/', 0, 1);
-		if(path != rootPath)
-		{
-			conf = getValue(modSettings, rootPath);
-			const auto confMap = conf.toMap();
-			if(!conf.isNull() && !confMap["active"].isNull() && !confMap["active"].toBool())
-			{
-				settings = confMap;
-			}
-		}
-	}
-
-	if(settings.value("active").toBool())
-	{
-		if(!::isCompatible(local.value("compatibility").toMap()))
-			settings["active"] = false;
-	}
-
-	for(auto entry : repositories)
-	{
-		QVariant repoVal = getValue(entry, path);
-		if(repoVal.isValid())
-		{
-			auto repoValMap = repoVal.toMap();
-			if(::isCompatible(repoValMap["compatibility"].toMap()))
-			{
-				if(repo.empty()
-					|| CModVersion::fromString(repo["version"].toString().toStdString())
-					 < CModVersion::fromString(repoValMap["version"].toString().toStdString()))
-				{
-					//take valid download link, screenshots and mod size before assignment
-					auto download = repo.value("download");
-					auto screenshots = repo.value("screenshots");
-					auto size = repo.value("downloadSize");
-					repo = repoValMap;
-					if(repo.value("download").isNull())
-					{
-						repo["download"] = download;
-						if(repo.value("screenshots").isNull()) //taking screenshot from the downloadable version
-							repo["screenshots"] = screenshots;
-					}
-					if(repo.value("downloadSize").isNull())
-						repo["downloadSize"] = size;
-				}
-			}
-		}
-	}
-
-	return CModEntry(repo, local, settings, modname);
-}
-
-bool CModList::hasMod(QString modname) const
-{
-	if(localModList.contains(modname))
-		return true;
-
-	for(auto entry : repositories)
-		if(entry.contains(modname))
-			return true;
-
-	return false;
-}
-
-QStringList CModList::getRequirements(QString modname)
-{
-	QStringList ret;
-
-	if(hasMod(modname))
-	{
-		auto mod = getMod(modname);
-
-		for(auto entry : mod.getDependencies())
-			ret += getRequirements(entry.toLower());
-	}
-	ret += modname;
-
-	return ret;
-}
-
-QVector<QString> CModList::getModList() const
-{
-	QSet<QString> knownMods;
-	QVector<QString> modList;
-	for(auto repo : repositories)
-	{
-		for(auto it = repo.begin(); it != repo.end(); it++)
-		{
-			knownMods.insert(it.key().toLower());
-		}
-	}
-	for(auto it = localModList.begin(); it != localModList.end(); it++)
-	{
-		knownMods.insert(it.key().toLower());
-	}
-
-	for(auto entry : knownMods)
-	{
-		modList.push_back(entry);
-	}
-	return modList;
-}
-
-QVector<QString> CModList::getChildren(QString parent) const
-{
-	QVector<QString> children;
-
-	int depth = parent.count('.') + 1;
-	for(const QString & mod : getModList())
-	{
-		if(mod.count('.') == depth && mod.startsWith(parent))
-			children.push_back(mod);
-	}
-	return children;
-}

+ 0 - 112
launcher/modManager/cmodlist.h

@@ -1,112 +0,0 @@
-/*
- * cmodlist.h, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-#pragma once
-
-#include <QVariantMap>
-#include <QVariant>
-#include <QVector>
-
-namespace ModStatus
-{
-enum EModStatus
-{
-	MASK_NONE = 0,
-	ENABLED = 1,
-	INSTALLED = 2,
-	UPDATEABLE = 4,
-	MASK_ALL = 255
-};
-}
-
-class CModEntry
-{
-	// repository contains newest version only (if multiple are available)
-	QVariantMap repository;
-	QVariantMap localData;
-	QVariantMap modSettings;
-
-	QString modname;
-
-	QVariant getValueImpl(QString value, bool localized) const;
-public:
-	CModEntry(QVariantMap repository, QVariantMap localData, QVariantMap modSettings, QString modname);
-
-	// installed and enabled
-	bool isEnabled() const;
-	// installed but disabled
-	bool isDisabled() const;
-	// available in any of repositories but not installed
-	bool isAvailable() const;
-	// installed and greater version exists in repository
-	bool isUpdateable() const;
-	// installed
-	bool isInstalled() const;
-	// vcmi essential files
-	bool isEssential() const;
-	// checks if version is compatible with vcmi
-	bool isCompatible() const;
-	// returns true if mod should be visible in Launcher
-	bool isVisible() const;
-	// returns true if mod type is Translation
-	bool isTranslation() const;
-	// returns true if mod type is Compatibility
-	bool isCompatibilityPatch() const;
-	// returns true if this is a submod
-	bool isSubmod() const;
-
-	// see ModStatus enum
-	int getModStatus() const;
-
-	QString getName() const;
-
-	// get value of some field in mod structure. Returns empty optional if value is not present
-	QVariant getValue(QString value) const;
-	QVariant getBaseValue(QString value) const;
-
-	QStringList getDependencies() const;
-	QStringList getConflicts() const;
-
-	static QString sizeToString(double size);
-};
-
-class CModList
-{
-	QVector<QVariantMap> repositories;
-	QVariantMap localModList;
-	QVariantMap modSettings;
-
-	mutable QMap<QString, CModEntry> cachedMods;
-
-	QVariantMap copyField(QVariantMap data, QString from, QString to) const;
-
-	CModEntry getModUncached(QString modname) const;
-public:
-	virtual void resetRepositories();
-	virtual void reloadRepositories();
-	virtual void addRepository(QVariantMap data);
-	virtual void setLocalModList(QVariantMap data);
-	virtual void setModSettings(QVariant data);
-	virtual void modChanged(QString modID);
-
-	// returns mod by name. Note: mod MUST exist
-	const CModEntry & getMod(QString modname) const;
-
-	// returns list of all mods necessary to run selected one, including mod itself
-	// order is: first mods in list don't have any dependencies, last mod is modname
-	// note: may include mods not present in list
-	QStringList getRequirements(QString modname);
-
-	bool hasMod(QString modname) const;
-
-	// returns list of all available mods
-	QVector<QString> getModList() const;
-
-	QVector<QString> getChildren(QString parent) const;
-};

+ 269 - 303
launcher/modManager/cmodlistview_moc.cpp

@@ -17,8 +17,9 @@
 #include <QCryptographicHash>
 #include <QRegularExpression>
 
-#include "cmodlistmodel_moc.h"
-#include "cmodmanager.h"
+#include "modstatemodel.h"
+#include "modstateitemmodel_moc.h"
+#include "modstatecontroller.h"
 #include "cdownloadmanager_moc.h"
 #include "chroniclesextractor.h"
 #include "../settingsView/csettingsview_moc.h"
@@ -31,18 +32,21 @@
 #include "../../lib/texts/Languages.h"
 #include "../../lib/modding/CModVersion.h"
 #include "../../lib/filesystem/Filesystem.h"
+#include "../../lib/texts/CGeneralTextHandler.h"
 
 #include <future>
 
-static double mbToBytes(double mb)
-{
-	return mb * 1024 * 1024;
-}
-
 void CModListView::setupModModel()
 {
-	modModel = new CModListModel(this);
-	manager = std::make_unique<CModManager>(modModel);
+	static const QString repositoryCachePath = CLauncherDirs::downloadsPath() + "/repositoryCache.json";
+	const auto &cachedRepositoryData = JsonUtils::jsonFromFile(repositoryCachePath);
+
+	modStateModel = std::make_shared<ModStateModel>();
+	if (!cachedRepositoryData.isNull())
+		modStateModel->appendRepositories(cachedRepositoryData);
+
+	modModel = new ModStateItemModel(modStateModel, this);
+	manager = std::make_unique<ModStateController>(modStateModel);
 }
 
 void CModListView::changeEvent(QEvent *event)
@@ -148,13 +152,7 @@ CModListView::CModListView(QWidget * parent)
 	dlManager = nullptr;
 
 	if(settings["launcher"]["autoCheckRepositories"].Bool())
-	{
 		loadRepositories();
-	}
-	else
-	{
-		manager->resetRepositories();
-	}
 
 #ifdef VCMI_MOBILE
 	for(auto * scrollWidget : {
@@ -171,8 +169,6 @@ CModListView::CModListView(QWidget * parent)
 
 void CModListView::loadRepositories()
 {
-	manager->resetRepositories();
-
 	QStringList repositories;
 
 	if (settings["launcher"]["defaultRepositoryEnabled"].Bool())
@@ -181,7 +177,7 @@ void CModListView::loadRepositories()
 	if (settings["launcher"]["extraRepositoryEnabled"].Bool())
 		repositories.push_back(QString::fromStdString(settings["launcher"]["extraRepositoryURL"].String()));
 
-	for(auto entry : repositories)
+	for(const auto & entry : repositories)
 	{
 		if (entry.isEmpty())
 			continue;
@@ -204,11 +200,21 @@ CModListView::~CModListView()
 
 static QString replaceIfNotEmpty(QVariant value, QString pattern)
 {
-	if(value.canConvert<QStringList>())
-		return pattern.arg(value.toStringList().join(", "));
-
 	if(value.canConvert<QString>())
-		return pattern.arg(value.toString());
+	{
+		if (value.toString().isEmpty())
+			return "";
+		else
+			return pattern.arg(value.toString());
+	}
+
+	if(value.canConvert<QStringList>())
+	{
+		if (value.toStringList().isEmpty())
+			return "";
+		else
+			return pattern.arg(value.toStringList().join(", "));
+	}
 
 	// all valid types of data should have been filtered by code above
 	assert(!value.isValid());
@@ -223,7 +229,7 @@ static QString replaceIfNotEmpty(QStringList value, QString pattern)
 	return "";
 }
 
-QString CModListView::genChangelogText(CModEntry & mod)
+QString CModListView::genChangelogText(const ModState & mod)
 {
 	QString headerTemplate = "<p><span style=\" font-weight:600;\">%1: </span></p>";
 	QString entryBegin = "<p align=\"justify\"><ul>";
@@ -233,7 +239,7 @@ QString CModListView::genChangelogText(CModEntry & mod)
 
 	QString result;
 
-	QVariantMap changelog = mod.getValue("changelog").toMap();
+	QMap<QString, QStringList> changelog = mod.getChangelog();
 	QList<QString> versions = changelog.keys();
 
 	std::sort(versions.begin(), versions.end(), [](QString lesser, QString greater)
@@ -242,37 +248,59 @@ QString CModListView::genChangelogText(CModEntry & mod)
 	});
 	std::reverse(versions.begin(), versions.end());
 
-	for(auto & version : versions)
+	for(const auto & version : versions)
 	{
 		result += headerTemplate.arg(version);
 		result += entryBegin;
-		for(auto & line : changelog.value(version).toStringList())
+		for(const auto & line : changelog.value(version))
 			result += entryLine.arg(line);
 		result += entryEnd;
 	}
 	return result;
 }
 
-QStringList CModListView::getModNames(QStringList input)
+QStringList CModListView::getModNames(QString queryingModID, QStringList input)
 {
 	QStringList result;
 
+	auto queryingMod = modStateModel->getMod(queryingModID);
+
 	for(const auto & modID : input)
 	{
-		auto mod = modModel->getMod(modID.toLower());
+		if (modStateModel->isModExists(modID) && modStateModel->getMod(modID).isHidden())
+			continue;
+
+		QString parentModID = modStateModel->getTopParent(modID);
+		QString displayName;
+
+		if (modStateModel->isSubmod(modID) && queryingMod.getParentID() != parentModID )
+		{
+			// show in form "parent mod (submod)"
+
+			QString parentDisplayName = parentModID;
+			QString submodDisplayName = modID;
+
+			if (modStateModel->isModExists(parentModID))
+				parentDisplayName = modStateModel->getMod(parentModID).getName();
 
-		QString modName = mod.getValue("name").toString();
+			if (modStateModel->isModExists(modID))
+				submodDisplayName = modStateModel->getMod(modID).getName();
 
-		if (modName.isEmpty())
-			result += modID.toLower();
+			displayName = QString("%1 (%2)").arg(submodDisplayName, parentDisplayName);
+		}
 		else
-			result += modName;
+		{
+			// show simply as mod name
+			displayName = modID;
+			if (modStateModel->isModExists(modID))
+				displayName = modStateModel->getMod(modID).getName();
+		}
+		result += displayName;
 	}
-
 	return result;
 }
 
-QString CModListView::genModInfoText(CModEntry & mod)
+QString CModListView::genModInfoText(const ModState & mod)
 {
 	QString prefix = "<p><span style=\" font-weight:600;\">%1: </span>"; // shared prefix
 	QString redPrefix = "<p><span style=\" font-weight:600; color:red\">%1: </span>"; // shared prefix
@@ -286,29 +314,40 @@ QString CModListView::genModInfoText(CModEntry & mod)
 
 	QString result;
 
-	result += replaceIfNotEmpty(mod.getValue("name"), lineTemplate.arg(tr("Mod name")));
-	result += replaceIfNotEmpty(mod.getValue("installedVersion"), lineTemplate.arg(tr("Installed version")));
-	result += replaceIfNotEmpty(mod.getValue("latestVersion"), lineTemplate.arg(tr("Latest version")));
+	result += replaceIfNotEmpty(mod.getName(), lineTemplate.arg(tr("Mod name")));
+	if (mod.isUpdateAvailable())
+	{
+		result += replaceIfNotEmpty(mod.getInstalledVersion(), lineTemplate.arg(tr("Installed version")));
+		result += replaceIfNotEmpty(mod.getRepositoryVersion(), lineTemplate.arg(tr("Latest version")));
+	}
+	else
+	{
+		if (mod.isInstalled())
+			result += replaceIfNotEmpty(mod.getInstalledVersion(), lineTemplate.arg(tr("Installed version")));
+		else
+			result += replaceIfNotEmpty(mod.getRepositoryVersion(), lineTemplate.arg(tr("Latest version")));
+	}
+
+	if (mod.isInstalled())
+		result += replaceIfNotEmpty(modStateModel->getInstalledModSizeFormatted(mod.getID()), lineTemplate.arg(tr("Size")));
 
-	if(mod.getValue("localSizeBytes").isValid())
-		result += replaceIfNotEmpty(CModEntry::sizeToString(mod.getValue("localSizeBytes").toDouble()), lineTemplate.arg(tr("Size")));
-	if((mod.isAvailable() || mod.isUpdateable()) && mod.getValue("downloadSize").isValid())
-		result += replaceIfNotEmpty(CModEntry::sizeToString(mbToBytes(mod.getValue("downloadSize").toDouble())), lineTemplate.arg(tr("Download size")));
+	if((!mod.isInstalled() || mod.isUpdateAvailable()) && !mod.getDownloadSizeFormatted().isEmpty())
+		result += replaceIfNotEmpty(mod.getDownloadSizeFormatted(), lineTemplate.arg(tr("Download size")));
 	
-	result += replaceIfNotEmpty(mod.getValue("author"), lineTemplate.arg(tr("Authors")));
+	result += replaceIfNotEmpty(mod.getAuthors(), lineTemplate.arg(tr("Authors")));
 
-	if(mod.getValue("licenseURL").isValid())
-		result += urlTemplate.arg(tr("License")).arg(mod.getValue("licenseURL").toString()).arg(mod.getValue("licenseName").toString());
+	if(!mod.getLicenseName().isEmpty())
+		result += urlTemplate.arg(tr("License")).arg(mod.getLicenseUrl()).arg(mod.getLicenseName());
 
-	if(mod.getValue("contact").isValid())
-		result += urlTemplate.arg(tr("Contact")).arg(mod.getValue("contact").toString()).arg(mod.getValue("contact").toString());
+	if(!mod.getContact().isEmpty())
+		result += urlTemplate.arg(tr("Contact")).arg(mod.getContact()).arg(mod.getContact());
 
 	//compatibility info
 	if(!mod.isCompatible())
 	{
-		auto compatibilityInfo = mod.getValue("compatibility").toMap();
-		auto minStr = compatibilityInfo.value("min").toString();
-		auto maxStr = compatibilityInfo.value("max").toString();
+		auto compatibilityInfo = mod.getCompatibleVersionRange();
+		auto minStr = compatibilityInfo.first;
+		auto maxStr = compatibilityInfo.second;
 
 		result += incompatibleString.arg(tr("Compatibility"));
 		if(minStr == maxStr)
@@ -327,52 +366,57 @@ QString CModListView::genModInfoText(CModEntry & mod)
 		}
 	}
 
-	QStringList supportedLanguages;
-	QVariant baseLanguageVariant = mod.getBaseValue("language");
+	QVariant baseLanguageVariant = mod.getBaseLanguage();
 	QString baseLanguageID = baseLanguageVariant.isValid() ? baseLanguageVariant.toString() : "english";
 
-	bool needToShowSupportedLanguages = false;
+	QStringList supportedLanguages = mod.getSupportedLanguages();
 
-	for(const auto & language : Languages::getLanguageList())
+	if(supportedLanguages.size() > 1)
 	{
-		QString languageID = QString::fromStdString(language.identifier);
+		QStringList supportedLanguagesTranslated;
 
-		if (languageID != baseLanguageID && !mod.getValue(languageID).isValid())
-			continue;
+		for (const auto & languageID : supportedLanguages)
+			supportedLanguagesTranslated += QApplication::translate("Language", Languages::getLanguageOptions(languageID.toStdString()).nameEnglish.c_str());
 
-		if (languageID != baseLanguageID)
-			needToShowSupportedLanguages = true;
-
-		supportedLanguages += QApplication::translate("Language", language.nameEnglish.c_str());
+		result += replaceIfNotEmpty(supportedLanguagesTranslated, lineTemplate.arg(tr("Languages")));
 	}
 
-	if(needToShowSupportedLanguages)
-		result += replaceIfNotEmpty(supportedLanguages, lineTemplate.arg(tr("Languages")));
+	QStringList conflicts = mod.getConflicts();
+	for (const auto & otherMod : modStateModel->getAllMods())
+	{
+		QStringList otherConflicts = modStateModel->getMod(otherMod).getConflicts();
+
+		if (otherConflicts.contains(mod.getID()) && !conflicts.contains(otherMod))
+			conflicts.push_back(otherMod);
+	}
 
-	result += replaceIfNotEmpty(getModNames(mod.getDependencies()), lineTemplate.arg(tr("Required mods")));
-	result += replaceIfNotEmpty(getModNames(mod.getConflicts()), lineTemplate.arg(tr("Conflicting mods")));
-	result += replaceIfNotEmpty(mod.getValue("description"), textTemplate.arg(tr("Description")));
+	result += replaceIfNotEmpty(getModNames(mod.getID(), mod.getDependencies()), lineTemplate.arg(tr("Required mods")));
+	result += replaceIfNotEmpty(getModNames(mod.getID(), conflicts), lineTemplate.arg(tr("Conflicting mods")));
+	result += replaceIfNotEmpty(mod.getDescription(), textTemplate.arg(tr("Description")));
 
 	result += "<p></p>"; // to get some empty space
 
-	QString unknownDeps = tr("This mod can not be installed or enabled because the following dependencies are not present");
-	QString blockingMods = tr("This mod can not be enabled because the following mods are incompatible with it");
-	QString hasActiveDependentMods = tr("This mod cannot be disabled because it is required by the following mods");
-	QString hasDependentMods = tr("This mod cannot be uninstalled or updated because it is required by the following mods");
+	QString translationMismatch = tr("This mod cannot be enabled because it translates into a different language.");
+	QString notInstalledDeps = tr("This mod can not be enabled because the following dependencies are not present");
+	QString unavailableDeps = tr("This mod can not be installed because the following dependencies are not present");
 	QString thisIsSubmod = tr("This is a submod and it cannot be installed or uninstalled separately from its parent mod");
 
 	QString notes;
 
-	notes += replaceIfNotEmpty(getModNames(findInvalidDependencies(mod.getName())), listTemplate.arg(unknownDeps));
-	notes += replaceIfNotEmpty(getModNames(findBlockingMods(mod.getName())), listTemplate.arg(blockingMods));
-	if(mod.isEnabled())
-		notes += replaceIfNotEmpty(getModNames(findDependentMods(mod.getName(), true)), listTemplate.arg(hasActiveDependentMods));
-	if(mod.isInstalled())
-		notes += replaceIfNotEmpty(getModNames(findDependentMods(mod.getName(), false)), listTemplate.arg(hasDependentMods));
+	QStringList notInstalledDependencies = this->getModsToInstall(mod.getID());
+	QStringList unavailableDependencies = this->findUnavailableMods(notInstalledDependencies);
+
+	if (mod.isInstalled())
+		notes += replaceIfNotEmpty(getModNames(mod.getID(), notInstalledDependencies), listTemplate.arg(notInstalledDeps));
+	else
+		notes += replaceIfNotEmpty(getModNames(mod.getID(), unavailableDependencies), listTemplate.arg(unavailableDeps));
 
 	if(mod.isSubmod())
 		notes += noteTemplate.arg(thisIsSubmod);
 
+	if (mod.isTranslation() && CGeneralTextHandler::getPreferredLanguage() != mod.getBaseLanguage().toStdString())
+		notes += noteTemplate.arg(translationMismatch);
+
 	if(notes.size())
 		result += textTemplate.arg(tr("Notes")).arg(notes);
 
@@ -395,6 +439,8 @@ void CModListView::dataChanged(const QModelIndex & topleft, const QModelIndex &
 
 void CModListView::selectMod(const QModelIndex & index)
 {
+	ui->tabWidget->setCurrentIndex(0);
+
 	if(!index.isValid())
 	{
 		disableModInfo();
@@ -402,7 +448,10 @@ void CModListView::selectMod(const QModelIndex & index)
 	else
 	{
 		const auto modName = index.data(ModRoles::ModNameRole).toString();
-		auto mod = modModel->getMod(modName);
+		auto mod = modStateModel->getMod(modName);
+
+		ui->tabWidget->setTabEnabled(1, !mod.getChangelog().isEmpty());
+		ui->tabWidget->setTabEnabled(2, !mod.getScreenshots().isEmpty());
 
 		ui->modInfoBrowser->setHtml(genModInfoText(mod));
 		ui->changelogBrowser->setHtml(genChangelogText(mod));
@@ -410,24 +459,22 @@ void CModListView::selectMod(const QModelIndex & index)
 		Helper::enableScrollBySwiping(ui->modInfoBrowser);
 		Helper::enableScrollBySwiping(ui->changelogBrowser);
 
-		bool hasInvalidDeps = !findInvalidDependencies(modName).empty();
-		bool hasBlockingMods = !findBlockingMods(modName).empty();
-		bool hasDependentMods = !findDependentMods(modName, true).empty();
+		QStringList notInstalledDependencies = this->getModsToInstall(modName);
+		QStringList unavailableDependencies = this->findUnavailableMods(notInstalledDependencies);
+		bool translationMismatch = 	mod.isTranslation() && CGeneralTextHandler::getPreferredLanguage() != mod.getBaseLanguage().toStdString();
 
-		ui->disableButton->setVisible(mod.isEnabled());
-		ui->enableButton->setVisible(mod.isDisabled());
+		ui->disableButton->setVisible(modStateModel->isModInstalled(mod.getID()) && modStateModel->isModEnabled(mod.getID()));
+		ui->enableButton->setVisible(modStateModel->isModInstalled(mod.getID()) && !modStateModel->isModEnabled(mod.getID()));
 		ui->installButton->setVisible(mod.isAvailable() && !mod.isSubmod());
 		ui->uninstallButton->setVisible(mod.isInstalled() && !mod.isSubmod());
-		ui->updateButton->setVisible(mod.isUpdateable());
+		ui->updateButton->setVisible(mod.isUpdateAvailable());
 
 		// Block buttons if action is not allowed at this time
-		// TODO: automate handling of some of these cases instead of forcing player
-		// to resolve all conflicts manually.
-		ui->disableButton->setEnabled(!hasDependentMods && !mod.isEssential());
-		ui->enableButton->setEnabled(!hasBlockingMods && !hasInvalidDeps);
-		ui->installButton->setEnabled(!hasInvalidDeps);
-		ui->uninstallButton->setEnabled(!hasDependentMods && !mod.isEssential());
-		ui->updateButton->setEnabled(!hasInvalidDeps && !hasDependentMods);
+		ui->disableButton->setEnabled(true);
+		ui->enableButton->setEnabled(notInstalledDependencies.empty() && !translationMismatch);
+		ui->installButton->setEnabled(unavailableDependencies.empty());
+		ui->uninstallButton->setEnabled(true);
+		ui->updateButton->setEnabled(unavailableDependencies.empty());
 
 		loadScreenshots();
 	}
@@ -460,149 +507,118 @@ void CModListView::on_lineEdit_textChanged(const QString & arg1)
 
 void CModListView::on_comboBox_currentIndexChanged(int index)
 {
-	switch(index)
-	{
-	case 0:
-		filterModel->setTypeFilter(ModStatus::MASK_NONE, ModStatus::MASK_NONE);
-		break;
-	case 1:
-		filterModel->setTypeFilter(ModStatus::MASK_NONE, ModStatus::INSTALLED);
-		break;
-	case 2:
-		filterModel->setTypeFilter(ModStatus::INSTALLED, ModStatus::INSTALLED);
-		break;
-	case 3:
-		filterModel->setTypeFilter(ModStatus::UPDATEABLE, ModStatus::UPDATEABLE);
-		break;
-	case 4:
-		filterModel->setTypeFilter(ModStatus::ENABLED | ModStatus::INSTALLED, ModStatus::ENABLED | ModStatus::INSTALLED);
-		break;
-	case 5:
-		filterModel->setTypeFilter(ModStatus::INSTALLED, ModStatus::ENABLED | ModStatus::INSTALLED);
-		break;
-	}
-}
-
-QStringList CModListView::findInvalidDependencies(QString mod)
-{
-	QStringList ret;
-	for(QString requirement : modModel->getRequirements(mod))
-	{
-		if(!modModel->hasMod(requirement) && !modModel->hasMod(requirement.split(QChar('.'))[0]))
-			ret += requirement;
-	}
-	return ret;
+	auto enumIndex = static_cast<ModFilterMask>(index);
+	filterModel->setTypeFilter(enumIndex);
 }
 
-QStringList CModListView::findBlockingMods(QString modUnderTest)
+QStringList CModListView::findUnavailableMods(QStringList candidates)
 {
-	QStringList ret;
-	auto required = modModel->getRequirements(modUnderTest);
+	QStringList invalidMods;
 
-	for(QString name : modModel->getModList())
+	for(QString modName : candidates)
 	{
-		auto mod = modModel->getMod(name);
-
-		if(mod.isEnabled())
-		{
-			// one of enabled mods have requirement (or this mod) marked as conflict
-			for(auto conflict : mod.getConflicts())
-			{
-				if(required.contains(conflict))
-					ret.push_back(name);
-			}
-		}
-	}
-
-	return ret;
-}
-
-QStringList CModListView::findDependentMods(QString mod, bool excludeDisabled)
-{
-	QStringList ret;
-	for(QString modName : modModel->getModList())
-	{
-		auto current = modModel->getMod(modName);
-
-		if(!current.isInstalled() || !current.isVisible())
-			continue;
-
-		if(current.getDependencies().contains(mod, Qt::CaseInsensitive))
-		{
-			if(!(current.isDisabled() && excludeDisabled))
-				ret += modName;
-		}
+		if(!modStateModel->isModExists(modName))
+			invalidMods.push_back(modName);
 	}
-	return ret;
+	return invalidMods;
 }
 
 void CModListView::on_enableButton_clicked()
 {
 	QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
-	
 	enableModByName(modName);
-	
 	checkManagerErrors();
 }
 
 void CModListView::enableModByName(QString modName)
 {
-	assert(findBlockingMods(modName).empty());
-	assert(findInvalidDependencies(modName).empty());
-
-	for(auto & name : modModel->getRequirements(modName))
-	{
-		if(modModel->getMod(name).isDisabled())
-			manager->enableMod(name);
-	}
-	emit modsChanged();
+	manager->enableMods({modName});
+	modModel->modChanged(modName);
 }
 
 void CModListView::on_disableButton_clicked()
 {
 	QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
-
 	disableModByName(modName);
-	
 	checkManagerErrors();
 }
 
 void CModListView::disableModByName(QString modName)
 {
-	if(modModel->hasMod(modName) && modModel->getMod(modName).isEnabled())
-		manager->disableMod(modName);
+	manager->disableMod(modName);
+	modModel->modChanged(modName);
+}
+
+QStringList CModListView::getModsToInstall(QString mod)
+{
+	QStringList result;
+	QStringList candidates;
+	QStringList processed;
+
+	candidates.push_back(mod);
+	while (!candidates.empty())
+	{
+		QString potentialToInstall = candidates.back();
+		candidates.pop_back();
+		processed.push_back(potentialToInstall);
+
+		if (modStateModel->isModExists(potentialToInstall) && modStateModel->isModInstalled(potentialToInstall))
+			continue;
+
+		if (modStateModel->isSubmod(potentialToInstall))
+		{
+			QString topParent = modStateModel->getTopParent(potentialToInstall);
+			if (modStateModel->isModInstalled(topParent))
+			{
+				if (modStateModel->isModUpdateAvailable(topParent))
+					potentialToInstall = modStateModel->getTopParent(potentialToInstall);
+				// else - potentially broken mod that depends on non-existing submod
+			}
+			else
+				potentialToInstall = modStateModel->getTopParent(potentialToInstall);
+		}
 
-	emit modsChanged();
+		result.push_back(potentialToInstall);
+
+		if (modStateModel->isModExists(potentialToInstall))
+		{
+			QStringList dependencies = modStateModel->getMod(potentialToInstall).getDependencies();
+			for (const auto & dependency : dependencies)
+			{
+				if (!processed.contains(dependency) && !candidates.contains(dependency))
+					candidates.push_back(dependency);
+			}
+		}
+	}
+	result.removeDuplicates();
+	return result;
 }
 
 void CModListView::on_updateButton_clicked()
 {
 	QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
 
-	assert(findInvalidDependencies(modName).empty());
-
-	for(auto & name : modModel->getRequirements(modName))
+	for(const auto & name : getModsToInstall(modName))
 	{
-		auto mod = modModel->getMod(name);
+		auto mod = modStateModel->getMod(name);
 		// update required mod, install missing (can be new dependency)
-		if(mod.isUpdateable() || !mod.isInstalled())
-			downloadFile(name + ".zip", mod.getValue("download").toString(), name, mbToBytes(mod.getValue("downloadSize").toDouble()));
+		if(mod.isUpdateAvailable() || !mod.isInstalled())
+			downloadFile(name + ".zip", mod.getDownloadUrl(), name, mod.getDownloadSizeBytes());
 	}
 }
 
 void CModListView::on_uninstallButton_clicked()
 {
 	QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
-	// NOTE: perhaps add "manually installed" flag and uninstall those dependencies that don't have it?
 
-	if(modModel->hasMod(modName) && modModel->getMod(modName).isInstalled())
+	if(modStateModel->isModExists(modName) && modStateModel->getMod(modName).isInstalled())
 	{
-		if(modModel->getMod(modName).isEnabled())
+		if(modStateModel->isModEnabled(modName))
 			manager->disableMod(modName);
 		manager->uninstallMod(modName);
+		modModel->reloadRepositories();
 	}
 	
-	emit modsChanged();
 	checkManagerErrors();
 }
 
@@ -610,28 +626,14 @@ void CModListView::on_installButton_clicked()
 {
 	QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
 
-	assert(findInvalidDependencies(modName).empty());
-
-	for(auto & name : modModel->getRequirements(modName))
+	for(const auto & name : getModsToInstall(modName))
 	{
-		auto mod = modModel->getMod(name);
+		auto mod = modStateModel->getMod(name);
 		if(mod.isAvailable())
-			downloadFile(name + ".zip", mod.getValue("download").toString(), name, mbToBytes(mod.getValue("downloadSize").toDouble()));
-		else if(!mod.isEnabled())
+			downloadFile(name + ".zip", mod.getDownloadUrl(), name, mod.getDownloadSizeBytes());
+		else if(!modStateModel->isModEnabled(name))
 			enableModByName(name);
 	}
-
-	for(auto & name : modModel->getMod(modName).getConflicts())
-	{
-		auto mod = modModel->getMod(name);
-		if(mod.isEnabled())
-		{
-			//TODO: consider reverse dependencies disabling
-			//TODO: consider if it may be possible for subdependencies to block disabling conflicting mod?
-			//TODO: consider if it may be possible to get subconflicts that will block disabling conflicting mod?
-			disableModByName(name);
-		}
-	}
 }
 
 void CModListView::on_installFromFileButton_clicked()
@@ -683,11 +685,12 @@ void CModListView::manualInstallFile(QString filePath)
 
 				// reload settings
 				Helper::loadSettings();
-				for(auto widget : qApp->allWidgets())
+				for(const auto widget : qApp->allWidgets())
 					if(auto settingsView = qobject_cast<CSettingsView *>(widget))
 						settingsView->loadSettings();
-				manager->loadMods();
-				manager->loadModSettings();
+
+				modStateModel->reloadLocalState();
+				modModel->reloadRepositories();
 			}
 		}
 	}
@@ -695,12 +698,12 @@ void CModListView::manualInstallFile(QString filePath)
 		downloadFile(fileName, QUrl::fromLocalFile(filePath), fileName);
 }
 
-void CModListView::downloadFile(QString file, QString url, QString description, qint64 size)
+void CModListView::downloadFile(QString file, QString url, QString description, qint64 sizeBytes)
 {
-	downloadFile(file, QUrl{url}, description, size);
+	downloadFile(file, QUrl{url}, description, sizeBytes);
 }
 
-void CModListView::downloadFile(QString file, QUrl url, QString description, qint64 size)
+void CModListView::downloadFile(QString file, QUrl url, QString description, qint64 sizeBytes)
 {
 	if(!dlManager)
 	{
@@ -715,13 +718,13 @@ void CModListView::downloadFile(QString file, QUrl url, QString description, qin
 		connect(manager.get(), SIGNAL(extractionProgress(qint64,qint64)),
 			this, SLOT(extractionProgress(qint64,qint64)));
 
-		connect(modModel, &CModListModel::dataChanged, filterModel, &QAbstractItemModel::dataChanged);
+		connect(modModel, &ModStateItemModel::dataChanged, filterModel, &QAbstractItemModel::dataChanged);
 
 		const auto progressBarFormat = tr("Downloading %1. %p% (%v MB out of %m MB) finished").arg(description);
 		ui->progressBar->setFormat(progressBarFormat);
 	}
 
-	dlManager->downloadFile(url, file, size);
+	dlManager->downloadFile(url, file, sizeBytes);
 }
 
 void CModListView::downloadProgress(qint64 current, qint64 max)
@@ -780,7 +783,6 @@ void CModListView::downloadFinished(QStringList savedFiles, QStringList failedFi
 		installFiles(savedFiles);
 	
 	hideProgressBar();
-	emit modsChanged();
 }
 
 void CModListView::hideProgressBar()
@@ -799,7 +801,7 @@ void CModListView::installFiles(QStringList files)
 	QStringList maps;
 	QStringList images;
 	QStringList exe;
-	QVector<QVariantMap> repositories;
+	JsonNode repository;
 
 	// TODO: some better way to separate zip's with mods and downloaded repository files
 	for(QString filename : files)
@@ -813,36 +815,47 @@ void CModListView::installFiles(QStringList files)
 		else if(filename.endsWith(".json", Qt::CaseInsensitive))
 		{
 			//download and merge additional files
-			auto repoData = JsonUtils::JsonFromFile(filename).toMap();
-			if(repoData.value("name").isNull())
+			const auto &repoData = JsonUtils::jsonFromFile(filename);
+			if(repoData["name"].isNull())
 			{
-				for(const auto & key : repoData.keys())
+				// This is main repository index. Download all referenced mods
+				for(const auto & [modName, modJson] : repoData.Struct())
 				{
-					auto modjson = repoData[key].toMap().value("mod");
-					if(!modjson.isNull())
-					{
-						downloadFile(key + ".json", modjson.toString(), tr("mods repository index"));
-					}
+					auto modNameLower = boost::algorithm::to_lower_copy(modName);
+					auto modJsonUrl = modJson["mod"];
+					if(!modJsonUrl.isNull())
+						downloadFile(QString::fromStdString(modName + ".json"), QString::fromStdString(modJsonUrl.String()), tr("mods repository index"));
+
+					repository[modNameLower] = modJson;
 				}
 			}
 			else
 			{
-				auto modn = QFileInfo(filename).baseName();
-				QVariantMap temp;
-				temp[modn] = repoData;
-				repoData = temp;
+				// This is json of a single mod. Extract name of mod and add it to repo
+				auto modName = QFileInfo(filename).baseName().toStdString();
+				auto modNameLower = boost::algorithm::to_lower_copy(modName);
+				repository[modNameLower] = repoData;
 			}
-			repositories.push_back(repoData);
 		}
 		else if(filename.endsWith(".png", Qt::CaseInsensitive))
 			images.push_back(filename);
 	}
 
-	if (!repositories.empty())
-		manager->loadRepositories(repositories);
+	if (!repository.isNull())
+	{
+		manager->appendRepositories(repository);
+		modModel->reloadRepositories();
+
+		static const QString repositoryCachePath = CLauncherDirs::downloadsPath() + "/repositoryCache.json";
+		JsonUtils::jsonToFile(repositoryCachePath, modStateModel->getRepositoryData());
+	}
 
 	if(!mods.empty())
+	{
 		installMods(mods);
+		modStateModel->reloadLocalState();
+		modModel->reloadRepositories();
+	}
 
 	if(!maps.empty())
 		installMaps(maps);
@@ -869,10 +882,8 @@ void CModListView::installFiles(QStringList files)
 		if(futureExtract.get())
 		{
 			//update
-			CResourceHandler::get("initial")->updateFilteredFiles([](const std::string &){ return true; });
-			manager->loadMods();
+			modStateModel->reloadLocalState();
 			modModel->reloadRepositories();
-			emit modsChanged();
 		}
 	}
 
@@ -883,6 +894,7 @@ void CModListView::installFiles(QStringList files)
 void CModListView::installMods(QStringList archives)
 {
 	QStringList modNames;
+	QStringList modsToEnable;
 
 	for(QString archive : archives)
 	{
@@ -893,65 +905,30 @@ void CModListView::installMods(QStringList archives)
 		modNames.push_back(modName);
 	}
 
-	QStringList modsToEnable;
-
-	// disable mod(s), to properly recalculate dependencies, if changed
-	for(QString mod : boost::adaptors::reverse(modNames))
+	// uninstall old version of mod, if installed
+	for(QString mod : modNames)
 	{
-		CModEntry entry = modModel->getMod(mod);
-		if(entry.isInstalled())
+		if(modStateModel->getMod(mod).isInstalled())
 		{
-			// enable mod if installed and enabled
-			if(entry.isEnabled())
+			if (modStateModel->isModEnabled(mod))
 				modsToEnable.push_back(mod);
+
+			manager->uninstallMod(mod);
 		}
 		else
 		{
-			// enable mod if m
-			if(settings["launcher"]["enableInstalledMods"].Bool())
-				modsToEnable.push_back(mod);
+			// installation of previously not present mod -> enable it
+			modsToEnable.push_back(mod);
 		}
 	}
 
-	// uninstall old version of mod, if installed
-	for(QString mod : boost::adaptors::reverse(modNames))
-	{
-		if(modModel->getMod(mod).isInstalled())
-			manager->uninstallMod(mod);
-	}
-
 	for(int i = 0; i < modNames.size(); i++)
 	{
 		ui->progressBar->setFormat(tr("Installing mod %1").arg(modNames[i]));
 		manager->installMod(modNames[i], archives[i]);
 	}
 
-	std::function<void(QString)> enableMod;
-
-	enableMod = [&](QString modName)
-	{
-		auto mod = modModel->getMod(modName);
-		if(mod.isInstalled() && !mod.getValue("keepDisabled").toBool())
-		{
-			for (auto const & dependencyName : mod.getDependencies())
-			{
-				auto dependency = modModel->getMod(dependencyName);
-				if(dependency.isDisabled())
-					manager->enableMod(dependencyName);
-			}
-
-			if(mod.isDisabled() && manager->enableMod(modName))
-			{
-				for(QString child : modModel->getChildren(modName))
-					enableMod(child);
-			}
-		}
-	};
-
-	for(QString mod : modsToEnable)
-	{
-		enableMod(mod);
-	}
+	manager->enableMods(modsToEnable);
 
 	checkManagerErrors();
 
@@ -1014,9 +991,9 @@ void CModListView::loadScreenshots()
 		
 		ui->screenshotsList->clear();
 		QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
-		assert(modModel->hasMod(modName)); //should be filtered out by check above
+		assert(modStateModel->isModExists(modName)); //should be filtered out by check above
 
-		for(QString url : modModel->getMod(modName).getValue("screenshots").toStringList())
+		for(QString url : modStateModel->getMod(modName).getScreenshots())
 		{
 			// URL must be encoded to something else to get rid of symbols illegal in file names
 			const auto hashed = QCryptographicHash::hash(url.toUtf8(), QCryptographicHash::Md5);
@@ -1050,52 +1027,42 @@ void CModListView::on_screenshotsList_clicked(const QModelIndex & index)
 	}
 }
 
-const CModList & CModListView::getModList() const
-{
-	assert(modModel);
-	return *modModel;
-}
-
 void CModListView::doInstallMod(const QString & modName)
 {
-	assert(findInvalidDependencies(modName).empty());
-
-	for(auto & name : modModel->getRequirements(modName))
+	for(const auto & name : modStateModel->getMod(modName).getDependencies())
 	{
-		auto mod = modModel->getMod(name);
+		auto mod = modStateModel->getMod(name);
 		if(!mod.isInstalled())
-			downloadFile(name + ".zip", mod.getValue("download").toString(), name, mbToBytes(mod.getValue("downloadSize").toDouble()));
+			downloadFile(name + ".zip", mod.getDownloadUrl(), name, mod.getDownloadSizeBytes());
 	}
 }
 
 bool CModListView::isModAvailable(const QString & modName)
 {
-	auto mod = modModel->getMod(modName);
-	return mod.isAvailable();
+	return !modStateModel->isModInstalled(modName);
 }
 
 bool CModListView::isModEnabled(const QString & modName)
 {
-	auto mod = modModel->getMod(modName);
-	return mod.isEnabled();
+	return modStateModel->isModEnabled(modName);
 }
 
 bool CModListView::isModInstalled(const QString & modName)
 {
-	auto mod = modModel->getMod(modName);
+	auto mod = modStateModel->getMod(modName);
 	return mod.isInstalled();
 }
 
 QString CModListView::getTranslationModName(const QString & language)
 {
-	for(const auto & modName : modModel->getModList())
+	for(const auto & modName : modStateModel->getAllMods())
 	{
-		auto mod = modModel->getMod(modName);
+		auto mod = modStateModel->getMod(modName);
 
 		if (!mod.isTranslation())
 			continue;
 
-		if (mod.getBaseValue("language").toString() != language)
+		if (mod.getBaseLanguage() != language)
 			continue;
 
 		return modName;
@@ -1110,19 +1077,18 @@ void CModListView::on_allModsView_doubleClicked(const QModelIndex &index)
 		return;
 	
 	auto modName = index.data(ModRoles::ModNameRole).toString();
-	auto mod = modModel->getMod(modName);
+	auto mod = modStateModel->getMod(modName);
 	
-	bool hasInvalidDeps = !findInvalidDependencies(modName).empty();
-	bool hasBlockingMods = !findBlockingMods(modName).empty();
-	bool hasDependentMods = !findDependentMods(modName, true).empty();
-	
-	if(!hasInvalidDeps && mod.isAvailable() && !mod.isSubmod())
+	QStringList notInstalledDependencies = this->getModsToInstall(mod.getID());
+	QStringList unavailableDependencies = this->findUnavailableMods(notInstalledDependencies);
+
+	if(unavailableDependencies.empty() && mod.isAvailable() && !mod.isSubmod())
 	{
 		on_installButton_clicked();
 		return;
 	}
 
-	if(!hasInvalidDeps && !hasDependentMods && mod.isUpdateable() && index.column() == ModFields::STATUS_UPDATE)
+	if(unavailableDependencies.empty() && mod.isUpdateAvailable() && index.column() == ModFields::STATUS_UPDATE)
 	{
 		on_updateButton_clicked();
 		return;
@@ -1138,13 +1104,13 @@ void CModListView::on_allModsView_doubleClicked(const QModelIndex &index)
 		return;
 	}
 
-	if(!hasBlockingMods && !hasInvalidDeps && mod.isDisabled())
+	if(notInstalledDependencies.empty() && !modStateModel->isModEnabled(modName))
 	{
 		on_enableButton_clicked();
 		return;
 	}
 
-	if(!hasDependentMods && !mod.isEssential() && mod.isEnabled())
+	if(modStateModel->isModEnabled(modName))
 	{
 		on_disableButton_clicked();
 		return;

+ 16 - 19
launcher/modManager/cmodlistview_moc.h

@@ -17,21 +17,23 @@ namespace Ui
 class CModListView;
 }
 
-class CModManager;
+class ModStateController;
 class CModList;
-class CModListModel;
+class ModStateItemModel;
+class ModStateModel;
 class CModFilterModel;
 class CDownloadManager;
 class QTableWidgetItem;
 
-class CModEntry;
+class ModState;
 
 class CModListView : public QWidget
 {
 	Q_OBJECT
 
-	std::unique_ptr<CModManager> manager;
-	CModListModel * modModel;
+	std::shared_ptr<ModStateModel> modStateModel;
+	std::unique_ptr<ModStateController> manager;
+	ModStateItemModel * modModel;
 	CModFilterModel * filterModel;
 	CDownloadManager * dlManager;
 
@@ -42,31 +44,28 @@ class CModListView : public QWidget
 	void checkManagerErrors();
 
 	/// replace mod ID's with proper human-readable mod names
-	QStringList getModNames(QStringList input);
+	QStringList getModNames(QString queryingMod, QStringList input);
+
+	/// returns list of mods that are needed for install of this mod (potentially including this mod itself)
+	QStringList getModsToInstall(QString mod);
 
 	// find mods unknown to mod list (not present in repo and not installed)
-	QStringList findInvalidDependencies(QString mod);
-	// find mods that block enabling of this mod: conflicting with this mod or one of required mods
-	QStringList findBlockingMods(QString modUnderTest);
-	// find mods that depend on this one
-	QStringList findDependentMods(QString mod, bool excludeDisabled);
+	QStringList findUnavailableMods(QStringList candidates);
 
 	void manualInstallFile(QString filePath);
-	void downloadFile(QString file, QString url, QString description, qint64 size = 0);
-	void downloadFile(QString file, QUrl url, QString description, qint64 size = 0);
+	void downloadFile(QString file, QString url, QString description, qint64 sizeBytes = 0);
+	void downloadFile(QString file, QUrl url, QString description, qint64 sizeBytes = 0);
 
 	void installMods(QStringList archives);
 	void installMaps(QStringList maps);
 	void installFiles(QStringList mods);
 
-	QString genChangelogText(CModEntry & mod);
-	QString genModInfoText(CModEntry & mod);
+	QString genChangelogText(const ModState & mod);
+	QString genModInfoText(const ModState & mod);
 
 	void changeEvent(QEvent *event) override;
 	void dragEnterEvent(QDragEnterEvent* event) override;
 	void dropEvent(QDropEvent *event) override;
-signals:
-	void modsChanged();
 
 public:
 	explicit CModListView(QWidget * parent = nullptr);
@@ -79,8 +78,6 @@ public:
 
 	void selectMod(const QModelIndex & index);
 
-	const CModList & getModList() const;
-	
 	// First Launch View interface
 
 	/// install mod by name

+ 231 - 0
launcher/modManager/modstate.cpp

@@ -0,0 +1,231 @@
+/*
+ * modstate.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+#include "modstate.h"
+
+#include "../../lib/modding/ModDescription.h"
+#include "../../lib/json/JsonNode.h"
+#include "../../lib/texts/CGeneralTextHandler.h"
+#include "../../lib/texts/Languages.h"
+
+ModState::ModState(const ModDescription & impl)
+	: impl(impl)
+{
+}
+
+QString ModState::getName() const
+{
+	return QString::fromStdString(impl.getName());
+}
+
+QString ModState::getType() const
+{
+	return QString::fromStdString(impl.getValue("modType").String());
+}
+
+QString ModState::getDescription() const
+{
+	return QString::fromStdString(impl.getLocalizedValue("description").String());
+}
+
+QString ModState::getID() const
+{
+	return QString::fromStdString(impl.getID());
+}
+
+QString ModState::getParentID() const
+{
+	return QString::fromStdString(impl.getParentID());
+}
+
+QString ModState::getTopParentID() const
+{
+	return QString::fromStdString(impl.getTopParentID());
+}
+
+template<typename Container>
+QStringList stringListStdToQt(const Container & container)
+{
+	QStringList result;
+	for (const auto & str : container)
+		result.push_back(QString::fromStdString(str));
+	return result;
+}
+
+QStringList ModState::getDependencies() const
+{
+	return stringListStdToQt(impl.getDependencies());
+}
+
+QStringList ModState::getConflicts() const
+{
+	return stringListStdToQt(impl.getConflicts());
+}
+
+QStringList ModState::getScreenshots() const
+{
+	return stringListStdToQt(impl.getLocalizedValue("screenshots").convertTo<std::vector<std::string>>());
+}
+
+QString ModState::getBaseLanguage() const
+{
+	return QString::fromStdString(impl.getBaseLanguage());
+}
+
+QStringList ModState::getSupportedLanguages() const
+{
+	QStringList result;
+	result.push_back(getBaseLanguage());
+
+	for (const auto & language : Languages::getLanguageList())
+	{
+		QString languageID = QString::fromStdString(language.identifier);
+
+		if (languageID != getBaseLanguage() && !impl.getValue(language.identifier).isNull())
+			result.push_back(languageID);
+	}
+	return result;
+}
+
+QMap<QString, QStringList> ModState::getChangelog() const
+{
+	QMap<QString, QStringList> result;
+	const JsonNode & changelog = impl.getLocalizedValue("changelog");
+
+	for (const auto & entry : changelog.Struct())
+	{
+		QString version = QString::fromStdString(entry.first);
+		QStringList changes = stringListStdToQt(entry.second.convertTo<std::vector<std::string>>());
+
+		result[version]	= changes;
+	}
+
+	return result;
+}
+
+QString ModState::getInstalledVersion() const
+{
+	return QString::fromStdString(impl.getLocalValue("version").String());
+}
+
+QString ModState::getRepositoryVersion() const
+{
+	return QString::fromStdString(impl.getRepositoryValue("version").String());
+}
+
+QString ModState::getVersion() const
+{
+	return QString::fromStdString(impl.getValue("version").String());
+}
+
+double ModState::getDownloadSizeMegabytes() const
+{
+	return impl.getRepositoryValue("downloadSize").Float();
+}
+
+size_t ModState::getDownloadSizeBytes() const
+{
+	return getDownloadSizeMegabytes() * 1024 * 1024;
+}
+
+QString ModState::getDownloadSizeFormatted() const
+{
+	return QCoreApplication::translate("File size", "%1 MiB").arg(QString::number(getDownloadSizeMegabytes(), 'f', 1));
+}
+
+QString ModState::getAuthors() const
+{
+	return QString::fromStdString(impl.getLocalizedValue("author").String());
+}
+
+QString ModState::getContact() const
+{
+	return QString::fromStdString(impl.getValue("contact").String());
+}
+
+QString ModState::getLicenseUrl() const
+{
+	return QString::fromStdString(impl.getValue("licenseURL").String());
+}
+
+QString ModState::getLicenseName() const
+{
+	return QString::fromStdString(impl.getValue("licenseName").String());
+}
+
+QString ModState::getDownloadUrl() const
+{
+	return QString::fromStdString(impl.getRepositoryValue("download").String());
+}
+
+QPair<QString, QString> ModState::getCompatibleVersionRange() const
+{
+	const JsonNode & compatibility = impl.getValue("compatibility");
+
+	if (compatibility.isNull())
+		return {};
+
+	auto min = QString::fromStdString(compatibility["min"].String());
+	auto max = QString::fromStdString(compatibility["max"].String());
+	return { min, max};
+}
+
+bool ModState::isSubmod() const
+{
+	return !getParentID().isEmpty();
+}
+
+bool ModState::isCompatibility() const
+{
+	return impl.isCompatibility();
+}
+
+bool ModState::isTranslation() const
+{
+	return impl.isTranslation();
+}
+
+bool ModState::isVisible() const
+{
+	return !isHidden();
+}
+
+bool ModState::isHidden() const
+{
+	if (isTranslation() && !isInstalled())
+		return impl.getBaseLanguage() != CGeneralTextHandler::getPreferredLanguage();
+
+	return isCompatibility() || getID() == "vcmi" || getID() == "core";
+}
+
+bool ModState::isAvailable() const
+{
+	return !isInstalled();
+}
+
+bool ModState::isInstalled() const
+{
+	return impl.isInstalled();
+}
+
+bool ModState::isUpdateAvailable() const
+{
+	return getInstalledVersion() != getRepositoryVersion() && !getRepositoryVersion().isEmpty() && !getInstalledVersion().isEmpty();
+}
+
+bool ModState::isCompatible() const
+{
+	return impl.isCompatible();
+}
+
+bool ModState::isKeptDisabled() const
+{
+	return impl.keepDisabled();
+}

+ 69 - 0
launcher/modManager/modstate.h

@@ -0,0 +1,69 @@
+/*
+ * modstate.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+VCMI_LIB_NAMESPACE_BEGIN
+class ModDescription;
+VCMI_LIB_NAMESPACE_END
+
+/// Class that represent current state of mod in Launcher
+/// Provides Qt-based interface to library class ModDescription
+class ModState
+{
+	const ModDescription & impl;
+
+public:
+	explicit ModState(const ModDescription & impl);
+
+	QString getName() const;
+	QString getType() const;
+	QString getDescription() const;
+
+	QString getID() const;
+	QString getParentID() const;
+	QString getTopParentID() const;
+
+	QStringList getDependencies() const;
+	QStringList getConflicts() const;
+	QStringList getScreenshots() const;
+
+	QString getBaseLanguage() const;
+	QStringList getSupportedLanguages() const;
+
+	QMap<QString, QStringList> getChangelog() const;
+
+	QString getInstalledVersion() const;
+	QString getRepositoryVersion() const;
+	QString getVersion() const;
+
+	double getDownloadSizeMegabytes() const;
+	size_t getDownloadSizeBytes() const;
+	QString getDownloadSizeFormatted() const;
+	QString getAuthors() const;
+	QString getContact() const;
+	QString getLicenseUrl() const;
+	QString getLicenseName() const;
+
+	QString getDownloadUrl() const;
+
+	QPair<QString, QString> getCompatibleVersionRange() const;
+
+	bool isSubmod() const;
+	bool isCompatibility() const;
+	bool isTranslation() const;
+
+	bool isVisible() const;
+	bool isHidden() const;
+	bool isAvailable() const;
+	bool isInstalled() const;
+	bool isUpdateAvailable() const;
+	bool isCompatible() const;
+	bool isKeptDisabled() const;
+};

+ 45 - 147
launcher/modManager/cmodmanager.cpp → launcher/modManager/modstatecontroller.cpp

@@ -1,5 +1,5 @@
 /*
- * cmodmanager.cpp, part of VCMI engine
+ * modstatecontroller.cpp, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *
@@ -8,14 +8,17 @@
  *
  */
 #include "StdInc.h"
-#include "cmodmanager.h"
+#include "modstatecontroller.h"
+
+#include "modstatemodel.h"
 
 #include "../../lib/VCMIDirs.h"
 #include "../../lib/filesystem/Filesystem.h"
 #include "../../lib/filesystem/CZipLoader.h"
 #include "../../lib/modding/CModHandler.h"
-#include "../../lib/modding/CModInfo.h"
 #include "../../lib/modding/IdentifierStorage.h"
+#include "../../lib/json/JsonNode.h"
+#include "../../lib/texts/CGeneralTextHandler.h"
 
 #include "../vcmiqt/jsonutils.h"
 #include "../vcmiqt/launcherdirs.h"
@@ -40,7 +43,7 @@ QString detectModArchive(QString path, QString modName, std::vector<std::string>
 
 	for(int folderLevel : {0, 1}) //search in subfolder if there is no mod.json in the root
 	{
-		for(auto file : filesToExtract)
+		for(const auto & file : filesToExtract)
 		{
 			QString filename = QString::fromUtf8(file.c_str());
 			modDirName = filename.section('/', 0, folderLevel);
@@ -54,7 +57,7 @@ QString detectModArchive(QString path, QString modName, std::vector<std::string>
 
 	logGlobal->error("Failed to detect mod path in archive!");
 	logGlobal->debug("List of file in archive:");
-	for(auto file : filesToExtract)
+	for(const auto & file : filesToExtract)
 		logGlobal->debug("%s", file.c_str());
 	
 	return "";
@@ -62,105 +65,60 @@ QString detectModArchive(QString path, QString modName, std::vector<std::string>
 }
 
 
-CModManager::CModManager(CModList * modList)
+ModStateController::ModStateController(std::shared_ptr<ModStateModel> modList)
 	: modList(modList)
 {
-	loadMods();
-	loadModSettings();
 }
 
-QString CModManager::settingsPath()
-{
-	return pathToQString(VCMIDirs::get().userConfigPath() / "modSettings.json");
-}
+ModStateController::~ModStateController() = default;
 
-void CModManager::loadModSettings()
+void ModStateController::appendRepositories(const JsonNode & repomap)
 {
-	modSettings = JsonUtils::JsonFromFile(settingsPath()).toMap();
-	modList->setModSettings(modSettings["activeMods"]);
-}
-
-void CModManager::resetRepositories()
-{
-	modList->resetRepositories();
-}
-
-void CModManager::loadRepositories(QVector<QVariantMap> repomap)
-{
-	for (auto const & entry : repomap)
-		modList->addRepository(entry);
-	modList->reloadRepositories();
-}
-
-void CModManager::loadMods()
-{
-	CModHandler handler;
-	handler.loadMods();
-	auto installedMods = handler.getAllMods();
-	localMods.clear();
-
-	for(auto modname : installedMods)
-	{
-		auto resID = CModInfo::getModFile(modname);
-		if(CResourceHandler::get()->existsResource(resID))
-		{
-			//calculate mod size
-			qint64 total = 0;
-			ResourcePath resDir(CModInfo::getModDir(modname), EResType::DIRECTORY);
-			if(CResourceHandler::get()->existsResource(resDir))
-			{
-				for(QDirIterator iter(QString::fromStdString(CResourceHandler::get()->getResourceName(resDir)->string()), QDirIterator::Subdirectories); iter.hasNext(); iter.next())
-					total += iter.fileInfo().size();
-			}
-			
-			boost::filesystem::path name = *CResourceHandler::get()->getResourceName(resID);
-			auto mod = JsonUtils::JsonFromFile(pathToQString(name));
-			auto json = JsonUtils::toJson(mod);
-			json["localSizeBytes"].Float() = total;
-			if(!name.is_absolute())
-				json["storedLocally"].Bool() = true;
-
-			mod = JsonUtils::toVariant(json);
-			localMods.insert(QString::fromUtf8(modname.c_str()).toLower(), mod);
-		}
-	}
-	modList->setLocalModList(localMods);
+	modList->appendRepositories(repomap);
 }
 
-bool CModManager::addError(QString modname, QString message)
+bool ModStateController::addError(QString modname, QString message)
 {
 	recentErrors.push_back(QString("%1: %2").arg(modname).arg(message));
 	return false;
 }
 
-QStringList CModManager::getErrors()
+QStringList ModStateController::getErrors()
 {
 	QStringList ret = recentErrors;
 	recentErrors.clear();
 	return ret;
 }
 
-bool CModManager::installMod(QString modname, QString archivePath)
+bool ModStateController::installMod(QString modname, QString archivePath)
 {
 	return canInstallMod(modname) && doInstallMod(modname, archivePath);
 }
 
-bool CModManager::uninstallMod(QString modname)
+bool ModStateController::uninstallMod(QString modname)
 {
 	return canUninstallMod(modname) && doUninstallMod(modname);
 }
 
-bool CModManager::enableMod(QString modname)
+bool ModStateController::enableMods(QStringList modlist)
 {
-	return canEnableMod(modname) && doEnableMod(modname, true);
+	for (const auto & modname : modlist)
+		if (!canEnableMod(modname))
+			return false;
+
+	modList->doEnableMods(modlist);
+	return true;
 }
 
-bool CModManager::disableMod(QString modname)
+bool ModStateController::disableMod(QString modname)
 {
-	return canDisableMod(modname) && doEnableMod(modname, false);
+	if (!canDisableMod(modname))
+		return false;
+	modList->doDisableMod(modname);
+	return true;
 }
 
-bool CModManager::canInstallMod(QString modname)
+bool ModStateController::canInstallMod(QString modname)
 {
 	auto mod = modList->getMod(modname);
 
@@ -172,7 +130,7 @@ bool CModManager::canInstallMod(QString modname)
 	return true;
 }
 
-bool CModManager::canUninstallMod(QString modname)
+bool ModStateController::canUninstallMod(QString modname)
 {
 	auto mod = modList->getMod(modname);
 
@@ -185,11 +143,11 @@ bool CModManager::canUninstallMod(QString modname)
 	return true;
 }
 
-bool CModManager::canEnableMod(QString modname)
+bool ModStateController::canEnableMod(QString modname)
 {
 	auto mod = modList->getMod(modname);
 
-	if(mod.isEnabled())
+	if(modList->isModEnabled(modname))
 		return addError(modname, tr("Mod is already enabled"));
 
 	if(!mod.isInstalled())
@@ -199,88 +157,32 @@ bool CModManager::canEnableMod(QString modname)
 	if(!mod.isCompatible())
 		return addError(modname, tr("Mod is not compatible, please update VCMI and checkout latest mod revisions"));
 
-	for(auto modEntry : mod.getDependencies())
-	{
-		if(!modList->hasMod(modEntry)) // required mod is not available
-			return addError(modname, tr("Required mod %1 is missing").arg(modEntry));
-
-		CModEntry modData = modList->getMod(modEntry);
-
-		if(!modData.isCompatibilityPatch() && !modData.isEnabled())
-			return addError(modname, tr("Required mod %1 is not enabled").arg(modEntry));
-	}
+	if (mod.isTranslation() && CGeneralTextHandler::getPreferredLanguage() != mod.getBaseLanguage().toStdString())
+		return addError(modname, tr("Can not enable translation mod for a different language!"));
 
-	for(QString modEntry : modList->getModList())
+	for(const auto & modEntry : mod.getDependencies())
 	{
-		auto mod = modList->getMod(modEntry);
-
-		// "reverse conflict" - enabled mod has this one as conflict
-		if(mod.isEnabled() && mod.getConflicts().contains(modname))
-			return addError(modname, tr("This mod conflicts with %1").arg(modEntry));
+		if(!modList->isModExists(modEntry)) // required mod is not available
+			return addError(modname, tr("Required mod %1 is missing").arg(modEntry));
 	}
 
-	for(auto modEntry : mod.getConflicts())
-	{
-		// check if conflicting mod installed and enabled
-		if(modList->hasMod(modEntry) && modList->getMod(modEntry).isEnabled())
-			return addError(modname, tr("This mod conflicts with %1").arg(modEntry));
-	}
 	return true;
 }
 
-bool CModManager::canDisableMod(QString modname)
+bool ModStateController::canDisableMod(QString modname)
 {
 	auto mod = modList->getMod(modname);
 
-	if(mod.isDisabled())
+	if(!modList->isModEnabled(modname))
 		return addError(modname, tr("Mod is already disabled"));
 
 	if(!mod.isInstalled())
 		return addError(modname, tr("Mod must be installed first"));
 
-	for(QString modEntry : modList->getModList())
-	{
-		auto current = modList->getMod(modEntry);
-
-		if(current.getDependencies().contains(modname) && current.isEnabled())
-			return addError(modname, tr("This mod is needed to run %1").arg(modEntry));
-	}
-	return true;
-}
-
-static QVariant writeValue(QString path, QVariantMap input, QVariant value)
-{
-	if(path.size() > 1)
-	{
-
-		QString entryName = path.section('/', 0, 1);
-		QString remainder = "/" + path.section('/', 2, -1);
-
-		entryName.remove(0, 1);
-		input.insert(entryName, writeValue(remainder, input.value(entryName).toMap(), value));
-		return input;
-	}
-	else
-	{
-		return value;
-	}
-}
-
-bool CModManager::doEnableMod(QString mod, bool on)
-{
-	QString path = mod;
-	path = "/activeMods/" + path.replace(".", "/mods/") + "/active";
-
-	modSettings = writeValue(path, modSettings, QVariant(on)).toMap();
-	modList->setModSettings(modSettings["activeMods"]);
-	modList->modChanged(mod);
-
-	JsonUtils::JsonToFile(settingsPath(), modSettings);
-
 	return true;
 }
 
-bool CModManager::doInstallMod(QString modname, QString archivePath)
+bool ModStateController::doInstallMod(QString modname, QString archivePath)
 {
 	const auto destDir = CLauncherDirs::modsPath() + QChar{'/'};
 
@@ -301,7 +203,7 @@ bool CModManager::doInstallMod(QString modname, QString archivePath)
 	{
 		const auto destDirFsPath = qstringToPath(destDir);
 		ZipArchive archive(qstringToPath(archivePath));
-		for (auto const & file : filesToExtract)
+		for(const auto & file : filesToExtract)
 		{
 			if (!archive.extract(destDirFsPath, file))
 				return false;
@@ -333,14 +235,12 @@ bool CModManager::doInstallMod(QString modname, QString archivePath)
 	if(upperLevel != modDirName)
 		removeModDir(destDir + upperLevel);
 	
-	CResourceHandler::get("initial")->updateFilteredFiles([](const std::string &) { return true; });
-	loadMods();
-	modList->reloadRepositories();
+	modList->reloadLocalState();
 
 	return true;
 }
 
-bool CModManager::doUninstallMod(QString modname)
+bool ModStateController::doUninstallMod(QString modname)
 {
 	ResourcePath resID(std::string("Mods/") + modname.toStdString(), EResType::DIRECTORY);
 	// Get location of the mod, in case-insensitive way
@@ -353,14 +253,12 @@ bool CModManager::doUninstallMod(QString modname)
 	if(!removeModDir(modDir))
 		return addError(modname, tr("Mod is located in protected directory, please remove it manually:\n") + modFullDir.absolutePath());
 
-	CResourceHandler::get("initial")->updateFilteredFiles([](const std::string &){ return true; });
-	loadMods();
-	modList->reloadRepositories();
+	modList->reloadLocalState();
 
 	return true;
 }
 
-bool CModManager::removeModDir(QString path)
+bool ModStateController::removeModDir(QString path)
 {
 	// issues 2673 and 2680 its why you do not recursively remove without sanity check
 	QDir checkDir(path);

+ 14 - 14
launcher/modManager/cmodmanager.h → launcher/modManager/modstatecontroller.h

@@ -1,5 +1,5 @@
 /*
- * cmodmanager.h, part of VCMI engine
+ * modstatecontroller.h, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *
@@ -9,22 +9,24 @@
  */
 #pragma once
 
-#include "cmodlist.h"
+#include <QVector>
 
-class CModManager : public QObject
+VCMI_LIB_NAMESPACE_BEGIN
+class JsonNode;
+VCMI_LIB_NAMESPACE_END
+
+class ModStateModel;
+
+class ModStateController : public QObject, public boost::noncopyable
 {
 	Q_OBJECT
 
-	CModList * modList;
-
-	QString settingsPath();
+	std::shared_ptr<ModStateModel> modList;
 
 	// check-free version of public method
-	bool doEnableMod(QString mod, bool on);
 	bool doInstallMod(QString mod, QString archivePath);
 	bool doUninstallMod(QString mod);
 
-	QVariantMap modSettings;
 	QVariantMap localMods;
 
 	QStringList recentErrors;
@@ -32,12 +34,10 @@ class CModManager : public QObject
 	bool removeModDir(QString mod);
 
 public:
-	CModManager(CModList * modList);
+	ModStateController(std::shared_ptr<ModStateModel> modList);
+	~ModStateController();
 
-	void resetRepositories();
-	void loadRepositories(QVector<QVariantMap> repomap);
-	void loadModSettings();
-	void loadMods();
+	void appendRepositories(const JsonNode & repositoriesList);
 
 	QStringList getErrors();
 
@@ -46,7 +46,7 @@ public:
 	/// installs mod from zip archive located at archivePath
 	bool installMod(QString mod, QString archivePath);
 	bool uninstallMod(QString mod);
-	bool enableMod(QString mod);
+	bool enableMods(QStringList mod);
 	bool disableMod(QString mod);
 
 	bool canInstallMod(QString mod);

+ 98 - 64
launcher/modManager/cmodlistmodel_moc.cpp → launcher/modManager/modstateitemmodel_moc.cpp

@@ -1,5 +1,5 @@
 /*
- * cmodlistmodel_moc.cpp, part of VCMI engine
+ * modstateview_moc.cpp, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *
@@ -8,25 +8,19 @@
  *
  */
 #include "StdInc.h"
-#include "cmodlistmodel_moc.h"
+#include "modstateitemmodel_moc.h"
 
-#include <QIcon>
+#include "modstatemodel.h"
 
-namespace ModStatus
-{
-static const QString iconDelete = ":/icons/mod-delete.png";
-static const QString iconDisabled = ":/icons/mod-disabled.png";
-static const QString iconDownload = ":/icons/mod-download.png";
-static const QString iconEnabled = ":/icons/mod-enabled.png";
-static const QString iconUpdate = ":/icons/mod-update.png";
-}
+#include <QIcon>
 
-CModListModel::CModListModel(QObject * parent)
+ModStateItemModel::ModStateItemModel(std::shared_ptr<ModStateModel> model, QObject * parent)
 	: QAbstractItemModel(parent)
+	, model(model)
 {
 }
 
-QString CModListModel::modIndexToName(const QModelIndex & index) const
+QString ModStateItemModel::modIndexToName(const QModelIndex & index) const
 {
 	if(index.isValid())
 	{
@@ -36,7 +30,7 @@ QString CModListModel::modIndexToName(const QModelIndex & index) const
 }
 
 
-QString CModListModel::modTypeName(QString modTypeID) const
+QString ModStateItemModel::modTypeName(QString modTypeID) const
 {
 	static const QMap<QString, QString> modTypes = {
 		{"Translation", tr("Translation")},
@@ -69,28 +63,28 @@ QString CModListModel::modTypeName(QString modTypeID) const
 	return tr("Other");
 }
 
-QVariant CModListModel::getValue(const CModEntry & mod, int field) const
+QVariant ModStateItemModel::getValue(const ModState & mod, int field) const
 {
 	switch(field)
 	{
 		case ModFields::STATUS_ENABLED:
-			return mod.getModStatus() & (ModStatus::ENABLED | ModStatus::INSTALLED);
+			return model->isModEnabled(mod.getID());
 
 		case ModFields::STATUS_UPDATE:
-			return mod.getModStatus() & (ModStatus::UPDATEABLE | ModStatus::INSTALLED);
+			return model->isModUpdateAvailable(mod.getID());
 
 		case ModFields::NAME:
-			return mod.getValue("name");
+			return mod.getName();
 
 		case ModFields::TYPE:
-			return modTypeName(mod.getValue("modType").toString());
+			return modTypeName(mod.getType());
 
 		default:
 			return QVariant();
 	}
 }
 
-QVariant CModListModel::getText(const CModEntry & mod, int field) const
+QVariant ModStateItemModel::getText(const ModState & mod, int field) const
 {
 	switch(field)
 	{
@@ -102,31 +96,58 @@ QVariant CModListModel::getText(const CModEntry & mod, int field) const
 	}
 }
 
-QVariant CModListModel::getIcon(const CModEntry & mod, int field) const
+QVariant ModStateItemModel::getIcon(const ModState & mod, int field) const
 {
-	if(field == ModFields::STATUS_ENABLED && mod.isEnabled())
-		return QIcon(ModStatus::iconEnabled);
-	if(field == ModFields::STATUS_ENABLED && mod.isDisabled())
-		return QIcon(ModStatus::iconDisabled);
+	static const QString iconDisabled = ":/icons/mod-disabled.png";
+	static const QString iconDisabledSubmod = ":/icons/submod-disabled.png";
+	static const QString iconDownload = ":/icons/mod-download.png";
+	static const QString iconEnabled = ":/icons/mod-enabled.png";
+	static const QString iconEnabledSubmod = ":/icons/submod-enabled.png";
+	static const QString iconUpdate = ":/icons/mod-update.png";
+
+	if (field == ModFields::STATUS_ENABLED)
+	{
+		if (!model->isModInstalled(mod.getID()))
+			return QVariant();
+
+		if(mod.isSubmod() && !model->isModEnabled(mod.getTopParentID()))
+		{
+			QString topParentID = mod.getTopParentID();
+			QString settingID = mod.getID().section('.', 1);
+
+			if (model->isModSettingEnabled(topParentID, settingID))
+				return QIcon(iconEnabledSubmod);
+			else
+				return QIcon(iconDisabledSubmod);
+		}
+
+		if (model->isModEnabled(mod.getID()))
+			return QIcon(iconEnabled);
+		else
+			return QIcon(iconDisabled);
+	}
 
-	if(field == ModFields::STATUS_UPDATE && mod.isUpdateable())
-		return QIcon(ModStatus::iconUpdate);
-	if(field == ModFields::STATUS_UPDATE && !mod.isInstalled())
-		return QIcon(ModStatus::iconDownload);
+	if(field == ModFields::STATUS_UPDATE)
+	{
+		if (model->isModUpdateAvailable(mod.getID()))
+			return QIcon(iconUpdate);
+		if (!model->isModInstalled(mod.getID()))
+			return QIcon(iconDownload);
+	}
 
 	return QVariant();
 }
 
-QVariant CModListModel::getTextAlign(int field) const
+QVariant ModStateItemModel::getTextAlign(int field) const
 {
 	return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
 }
 
-QVariant CModListModel::data(const QModelIndex & index, int role) const
+QVariant ModStateItemModel::data(const QModelIndex & index, int role) const
 {
 	if(index.isValid())
 	{
-		auto mod = getMod(modIndexToName(index));
+		auto mod = model->getMod(modIndexToName(index));
 
 		switch(role)
 		{
@@ -139,32 +160,32 @@ QVariant CModListModel::data(const QModelIndex & index, int role) const
 		case ModRoles::ValueRole:
 			return getValue(mod, index.column());
 		case ModRoles::ModNameRole:
-			return mod.getName();
+			return mod.getID();
 		}
 	}
 	return QVariant();
 }
 
-int CModListModel::rowCount(const QModelIndex & index) const
+int ModStateItemModel::rowCount(const QModelIndex & index) const
 {
 	if(index.isValid())
 		return modIndex[modIndexToName(index)].size();
 	return modIndex[""].size();
 }
 
-int CModListModel::columnCount(const QModelIndex &) const
+int ModStateItemModel::columnCount(const QModelIndex &) const
 {
 	return ModFields::COUNT;
 }
 
-Qt::ItemFlags CModListModel::flags(const QModelIndex &) const
+Qt::ItemFlags ModStateItemModel::flags(const QModelIndex &) const
 {
 	return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
 }
 
-QVariant CModListModel::headerData(int section, Qt::Orientation orientation, int role) const
+QVariant ModStateItemModel::headerData(int section, Qt::Orientation orientation, int role) const
 {
-	static const QString header[ModFields::COUNT] =
+	static const std::array header =
 	{
 		QT_TRANSLATE_NOOP("ModFields", "Name"),
 		QT_TRANSLATE_NOOP("ModFields", ""), // status icon
@@ -173,24 +194,17 @@ QVariant CModListModel::headerData(int section, Qt::Orientation orientation, int
 	};
 
 	if(role == Qt::DisplayRole && orientation == Qt::Horizontal)
-		return QCoreApplication::translate("ModFields", header[section].toStdString().c_str());
+		return QCoreApplication::translate("ModFields", header[section]);
 	return QVariant();
 }
 
-void CModListModel::reloadRepositories()
-{
-	beginResetModel();
-	endResetModel();
-}
-
-void CModListModel::resetRepositories()
+void ModStateItemModel::reloadRepositories()
 {
 	beginResetModel();
-	CModList::resetRepositories();
 	endResetModel();
 }
 
-void CModListModel::modChanged(QString modID)
+void ModStateItemModel::modChanged(QString modID)
 {
 	int index = modNameToID.indexOf(modID);
 	QModelIndex parent = this->parent(createIndex(0, 0, index));
@@ -198,9 +212,9 @@ void CModListModel::modChanged(QString modID)
 	emit dataChanged(createIndex(row, 0, index), createIndex(row, 4, index));
 }
 
-void CModListModel::endResetModel()
+void ModStateItemModel::endResetModel()
 {
-	modNameToID = getModList();
+	modNameToID = model->getAllMods();
 	modIndex.clear();
 	for(const QString & str : modNameToID)
 	{
@@ -216,7 +230,7 @@ void CModListModel::endResetModel()
 	QAbstractItemModel::endResetModel();
 }
 
-QModelIndex CModListModel::index(int row, int column, const QModelIndex & parent) const
+QModelIndex ModStateItemModel::index(int row, int column, const QModelIndex & parent) const
 {
 	if(parent.isValid())
 	{
@@ -231,7 +245,7 @@ QModelIndex CModListModel::index(int row, int column, const QModelIndex & parent
 	return QModelIndex();
 }
 
-QModelIndex CModListModel::parent(const QModelIndex & child) const
+QModelIndex ModStateItemModel::parent(const QModelIndex & child) const
 {
 	QString modID = modNameToID[child.internalId()];
 	for(auto entry = modIndex.begin(); entry != modIndex.end(); entry++) // because using range-for entry type is QMap::value_type oO
@@ -244,26 +258,46 @@ QModelIndex CModListModel::parent(const QModelIndex & child) const
 	return QModelIndex();
 }
 
-void CModFilterModel::setTypeFilter(int filteredType, int filterMask)
+void CModFilterModel::setTypeFilter(ModFilterMask newFilterMask)
 {
-	this->filterMask = filterMask;
-	this->filteredType = filteredType;
+	filterMask = newFilterMask;
 	invalidateFilter();
 }
 
+bool CModFilterModel::filterMatchesCategory(const QModelIndex & source) const
+{
+	QString modID =source.data(ModRoles::ModNameRole).toString();
+	ModState mod = base->model->getMod(modID);
+
+	switch (filterMask)
+	{
+		case ModFilterMask::ALL:
+			return true;
+		case ModFilterMask::AVAILABLE:
+			return !mod.isInstalled();
+		case ModFilterMask::INSTALLED:
+			return mod.isInstalled();
+		case ModFilterMask::UPDATEABLE:
+			return mod.isUpdateAvailable();
+		case ModFilterMask::ENABLED:
+			return mod.isInstalled() && base->model->isModEnabled(modID);
+		case ModFilterMask::DISABLED:
+			return mod.isInstalled() && !base->model->isModEnabled(modID);
+	}
+	assert(0);
+	return false;
+}
+
 bool CModFilterModel::filterMatchesThis(const QModelIndex & source) const
 {
-	CModEntry mod = base->getMod(source.data(ModRoles::ModNameRole).toString());
-	return (mod.getModStatus() & filterMask) == filteredType &&
-	       QSortFilterProxyModel::filterAcceptsRow(source.row(), source.parent());
+	return filterMatchesCategory(source) && QSortFilterProxyModel::filterAcceptsRow(source.row(), source.parent());
 }
 
 bool CModFilterModel::filterAcceptsRow(int source_row, const QModelIndex & source_parent) const
 {
 	QModelIndex index = base->index(source_row, 0, source_parent);
-
-	CModEntry mod = base->getMod(index.data(ModRoles::ModNameRole).toString());
-	if (!mod.isVisible())
+	QString modID = index.data(ModRoles::ModNameRole).toString();
+	if (base->model->getMod(modID).isHidden())
 		return false;
 
 	if(filterMatchesThis(index))
@@ -273,7 +307,7 @@ bool CModFilterModel::filterAcceptsRow(int source_row, const QModelIndex & sourc
 
 	for(size_t i = 0; i < base->rowCount(index); i++)
 	{
-		if(filterMatchesThis(base->index((int)i, 0, index)))
+		if(filterMatchesThis(base->index(i, 0, index)))
 			return true;
 	}
 
@@ -287,8 +321,8 @@ bool CModFilterModel::filterAcceptsRow(int source_row, const QModelIndex & sourc
 	return false;
 }
 
-CModFilterModel::CModFilterModel(CModListModel * model, QObject * parent)
-	: QSortFilterProxyModel(parent), base(model), filteredType(ModStatus::MASK_NONE), filterMask(ModStatus::MASK_NONE)
+CModFilterModel::CModFilterModel(ModStateItemModel * model, QObject * parent)
+	: QSortFilterProxyModel(parent), base(model), filterMask(ModFilterMask::ALL)
 {
 	setSourceModel(model);
 	setSortRole(ModRoles::ValueRole);

+ 33 - 25
launcher/modManager/cmodlistmodel_moc.h → launcher/modManager/modstateitemmodel_moc.h

@@ -1,5 +1,5 @@
 /*
- * cmodlistmodel_moc.h, part of VCMI engine
+ * modstateview_moc.h, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *
@@ -9,11 +9,12 @@
  */
 #pragma once
 
-#include "cmodlist.h"
-
 #include <QAbstractTableModel>
 #include <QSortFilterProxyModel>
 
+class ModStateModel;
+class ModState;
+
 namespace ModFields
 {
 enum EModFields
@@ -26,6 +27,16 @@ enum EModFields
 };
 }
 
+enum class ModFilterMask : uint8_t
+{
+	ALL,
+	AVAILABLE,
+	INSTALLED,
+	UPDATEABLE,
+	ENABLED,
+	DISABLED
+};
+
 namespace ModRoles
 {
 enum EModRoles
@@ -35,14 +46,17 @@ enum EModRoles
 };
 }
 
-class CModListModel : public QAbstractItemModel, public CModList
+class ModStateItemModel final : public QAbstractItemModel
 {
+	friend class CModFilterModel;
 	Q_OBJECT
 
-	QVector<QString> modNameToID;
+	std::shared_ptr<ModStateModel> model;
+
+	QStringList modNameToID;
 	// contains mapping mod -> numbered list of submods
 	// mods that have no parent located under "" key (empty string)
-	QMap<QString, QVector<QString>> modIndex;
+	QMap<QString, QStringList> modIndex;
 
 	void endResetModel();
 
@@ -50,17 +64,16 @@ class CModListModel : public QAbstractItemModel, public CModList
 	QString modTypeName(QString modTypeID) const;
 
 	QVariant getTextAlign(int field) const;
-	QVariant getValue(const CModEntry & mod, int field) const;
-	QVariant getText(const CModEntry & mod, int field) const;
-	QVariant getIcon(const CModEntry & mod, int field) const;
+	QVariant getValue(const ModState & mod, int field) const;
+	QVariant getText(const ModState & mod, int field) const;
+	QVariant getIcon(const ModState & mod, int field) const;
 
 public:
-	explicit CModListModel(QObject * parent = nullptr);
+	explicit ModStateItemModel(std::shared_ptr<ModStateModel> model, QObject * parent);
 
 	/// CModListContainer overrides
-	void resetRepositories() override;
-	void reloadRepositories() override;
-	void modChanged(QString modID) override;
+	void reloadRepositories();
+	void modChanged(QString modID);
 
 	QVariant data(const QModelIndex & index, int role) const override;
 	QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
@@ -68,29 +81,24 @@ public:
 	int rowCount(const QModelIndex & parent) const override;
 	int columnCount(const QModelIndex & parent) const override;
 
-	QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override;
+	QModelIndex index(int row, int column, const QModelIndex & parent) const override;
 	QModelIndex parent(const QModelIndex & child) const override;
 
 	Qt::ItemFlags flags(const QModelIndex & index) const override;
-
-signals:
-
-public slots:
-
 };
 
-class CModFilterModel : public QSortFilterProxyModel
+class CModFilterModel final : public QSortFilterProxyModel
 {
-	CModListModel * base;
-	int filteredType;
-	int filterMask;
+	ModStateItemModel * base;
+	ModFilterMask filterMask;
 
 	bool filterMatchesThis(const QModelIndex & source) const;
+	bool filterMatchesCategory(const QModelIndex & source) const;
 
 	bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override;
 
 public:
-	void setTypeFilter(int filteredType, int filterMask);
+	void setTypeFilter(ModFilterMask filterMask);
 
-	CModFilterModel(CModListModel * model, QObject * parent = nullptr);
+	CModFilterModel(ModStateItemModel * model, QObject * parent = nullptr);
 };

+ 130 - 0
launcher/modManager/modstatemodel.cpp

@@ -0,0 +1,130 @@
+/*
+ * modstatemodel.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+#include "modstatemodel.h"
+
+#include "../../lib/filesystem/Filesystem.h"
+#include "../../lib/json/JsonUtils.h"
+#include "../../lib/modding/ModManager.h"
+
+ModStateModel::ModStateModel()
+	: repositoryData(std::make_unique<JsonNode>())
+	, modManager(std::make_unique<ModManager>())
+{
+}
+
+ModStateModel::~ModStateModel() = default;
+
+void ModStateModel::appendRepositories(const JsonNode & repositoriesList)
+{
+	JsonUtils::mergeCopy(*repositoryData, repositoriesList);
+
+	modManager = std::make_unique<ModManager>(*repositoryData);
+}
+
+void ModStateModel::reloadLocalState()
+{
+	CResourceHandler::get("initial")->updateFilteredFiles([](const std::string &){ return true; });
+	modManager = std::make_unique<ModManager>(*repositoryData);
+}
+
+const JsonNode & ModStateModel::getRepositoryData() const
+{
+	return *repositoryData;
+}
+
+ModState ModStateModel::getMod(QString modName) const
+{
+	assert(modName.toLower() == modName);
+	return ModState(modManager->getModDescription(modName.toStdString()));
+}
+
+template<typename Container>
+QStringList stringListStdToQt(const Container & container)
+{
+	QStringList result;
+	for (const auto & str : container)
+		result.push_back(QString::fromStdString(str));
+	return result;
+}
+
+QStringList ModStateModel::getAllMods() const
+{
+	return stringListStdToQt(modManager->getAllMods());
+}
+
+bool ModStateModel::isModExists(QString modName) const
+{
+	return vstd::contains(modManager->getAllMods(), modName.toStdString());
+}
+
+bool ModStateModel::isModInstalled(QString modName) const
+{
+	return getMod(modName).isInstalled();
+}
+
+bool ModStateModel::isModSettingEnabled(QString rootModName, QString modSettingName) const
+{
+	return modManager->isModSettingActive(rootModName.toStdString(), modSettingName.toStdString());
+}
+
+bool ModStateModel::isModEnabled(QString modName) const
+{
+	return modManager->isModActive(modName.toStdString());
+}
+
+bool ModStateModel::isModUpdateAvailable(QString modName) const
+{
+	return getMod(modName).isUpdateAvailable();
+}
+
+bool ModStateModel::isModVisible(QString modName) const
+{
+	return getMod(modName).isVisible();
+}
+
+QString ModStateModel::getInstalledModSizeFormatted(QString modName) const
+{
+	return QCoreApplication::translate("File size", "%1 MiB").arg(QString::number(getInstalledModSizeMegabytes(modName), 'f', 1));
+}
+
+double ModStateModel::getInstalledModSizeMegabytes(QString modName) const
+{
+	return modManager->getInstalledModSizeMegabytes(modName.toStdString());
+}
+
+void ModStateModel::doEnableMods(QStringList modList)
+{
+	std::vector<std::string> stdList;
+
+	for (const auto & entry : modList)
+		stdList.push_back(entry.toStdString());
+
+	modManager->tryEnableMods(stdList);
+}
+
+void ModStateModel::doDisableMod(QString modname)
+{
+	modManager->tryDisableMod(modname.toStdString());
+}
+
+bool ModStateModel::isSubmod(QString modname)
+{
+	return modname.contains('.');
+}
+
+QString ModStateModel::getTopParent(QString modname) const
+{
+	QStringList components = modname.split('.');
+	if (components.size() > 1)
+		return components.front();
+	else
+		return "";
+}

+ 52 - 0
launcher/modManager/modstatemodel.h

@@ -0,0 +1,52 @@
+/*
+ * modstatemodel.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "modstate.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+class JsonNode;
+class ModManager;
+VCMI_LIB_NAMESPACE_END
+
+/// Class that represent current state of available mods
+/// Provides Qt-based interface to library class ModManager
+class ModStateModel
+{
+	std::unique_ptr<JsonNode> repositoryData;
+	std::unique_ptr<ModManager> modManager;
+
+public:
+	ModStateModel();
+	~ModStateModel();
+
+	void appendRepositories(const JsonNode & repositoriesList);
+	void reloadLocalState();
+	const JsonNode & getRepositoryData() const;
+
+	ModState getMod(QString modName) const;
+	QStringList getAllMods() const;
+
+	QString getInstalledModSizeFormatted(QString modName) const;
+	double getInstalledModSizeMegabytes(QString modName) const;
+
+	bool isModExists(QString modName) const;
+	bool isModInstalled(QString modName) const;
+	bool isModEnabled(QString modName) const;
+	bool isModSettingEnabled(QString rootModName, QString modSettingName) const;
+	bool isModUpdateAvailable(QString modName) const;
+	bool isModVisible(QString modName) const;
+
+	void doEnableMods(QStringList modList);
+	void doDisableMod(QString modname);
+
+	bool isSubmod(QString modname);
+	QString getTopParent(QString modname) const;
+};

+ 2 - 0
launcher/resources.qrc

@@ -7,8 +7,10 @@
         <file>icons/menu-settings.png</file>
         <file>icons/mod-delete.png</file>
         <file>icons/mod-disabled.png</file>
+        <file>icons/submod-disabled.png</file>
         <file>icons/mod-download.png</file>
         <file>icons/mod-enabled.png</file>
+        <file>icons/submod-enabled.png</file>
         <file>icons/mod-update.png</file>
     </qresource>
 </RCC>

+ 304 - 145
launcher/translation/chinese.ts

@@ -90,109 +90,85 @@
 <context>
     <name>CModListModel</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="42"/>
         <source>Translation</source>
-        <translation>本地化</translation>
+        <translation type="vanished">本地化</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="43"/>
         <source>Town</source>
-        <translation>城镇</translation>
+        <translation type="vanished">城镇</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="44"/>
         <source>Test</source>
-        <translation>测试</translation>
+        <translation type="vanished">测试</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="45"/>
         <source>Templates</source>
-        <translation>地图模板</translation>
+        <translation type="vanished">地图模板</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="46"/>
         <source>Spells</source>
-        <translation>法术</translation>
+        <translation type="vanished">法术</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="47"/>
         <source>Music</source>
-        <translation>音乐</translation>
+        <translation type="vanished">音乐</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="48"/>
         <source>Maps</source>
-        <translation>地图</translation>
+        <translation type="vanished">地图</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="49"/>
         <source>Sounds</source>
-        <translation>音效</translation>
+        <translation type="vanished">音效</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="50"/>
         <source>Skills</source>
-        <translation>技能</translation>
+        <translation type="vanished">技能</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="51"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="69"/>
         <source>Other</source>
-        <translation>其他</translation>
+        <translation type="vanished">其他</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="52"/>
         <source>Objects</source>
-        <translation>物件</translation>
+        <translation type="vanished">物件</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="53"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="54"/>
         <source>Mechanics</source>
         <translatorcomment>无法确定是否分类是游戏机制或者是游戏中的战争器械</translatorcomment>
-        <translation>机制</translation>
+        <translation type="vanished">机制</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="55"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="56"/>
         <source>Interface</source>
-        <translation>界面</translation>
+        <translation type="vanished">界面</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="57"/>
         <source>Heroes</source>
-        <translation>英雄</translation>
+        <translation type="vanished">英雄</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="58"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="59"/>
         <source>Graphical</source>
-        <translation>图像</translation>
+        <translation type="vanished">图像</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="60"/>
         <source>Expansion</source>
-        <translation>扩展包</translation>
+        <translation type="vanished">扩展包</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="61"/>
         <source>Creatures</source>
-        <translation>生物</translation>
+        <translation type="vanished">生物</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="62"/>
         <source>Compatibility</source>
-        <translation>兼容性</translation>
+        <translation type="vanished">兼容性</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="63"/>
         <source>Artifacts</source>
-        <translation>宝物</translation>
+        <translation type="vanished">宝物</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="64"/>
         <source>AI</source>
-        <translation>AI</translation>
+        <translation type="vanished">AI</translation>
     </message>
 </context>
 <context>
@@ -235,7 +211,7 @@
     </message>
     <message>
         <location filename="../modManager/cmodlistview_moc.ui" line="163"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="395"/>
         <source>Description</source>
         <translation>详细介绍</translation>
     </message>
@@ -295,191 +271,204 @@
         <translation>终止</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="289"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="317"/>
         <source>Mod name</source>
         <translation>模组名称</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="290"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="320"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
         <source>Installed version</source>
         <translation>已安装的版本</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="291"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="328"/>
         <source>Latest version</source>
         <translation>最新版本</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="294"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="332"/>
         <source>Size</source>
         <translation>大小</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="296"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="335"/>
         <source>Download size</source>
         <translation>下载大小</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="337"/>
         <source>Authors</source>
         <translation>作者</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="301"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="340"/>
         <source>License</source>
         <translation>授权许可</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="304"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="343"/>
         <source>Contact</source>
         <translation>联系方式</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="313"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
         <source>Compatibility</source>
         <translation>兼容性</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="315"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>Required VCMI version</source>
         <translation>需要VCMI版本</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>Supported VCMI version</source>
         <translation>支持的VCMI版本</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>please upgrade mod</source>
         <translation>请更新模组</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="193"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="824"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="189"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="827"/>
         <source>mods repository index</source>
         <translation>模组源索引号</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>or newer</source>
         <translation>或更新的版本</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="365"/>
         <source>Supported VCMI versions</source>
         <translation>支持的VCMI版本</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="350"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="381"/>
         <source>Languages</source>
         <translation>语言</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="393"/>
         <source>Required mods</source>
         <translatorcomment>Mod统一翻译为模组</translatorcomment>
         <translation>前置模组</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="353"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="394"/>
         <source>Conflicting mods</source>
         <translatorcomment>Mod统一翻译为模组</translatorcomment>
         <translation>冲突的模组</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="358"/>
         <source>This mod can not be installed or enabled because the following dependencies are not present</source>
-        <translation>这个模组无法被安装或者激活,因为下列依赖项未满足</translation>
+        <translation type="vanished">这个模组无法被安装或者激活,因为下列依赖项未满足</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="359"/>
         <source>This mod can not be enabled because the following mods are incompatible with it</source>
-        <translation>这个模组无法被激活,因为下列模组与其不兼容</translation>
+        <translation type="vanished">这个模组无法被激活,因为下列模组与其不兼容</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>This mod cannot be disabled because it is required by the following mods</source>
-        <translation>这个模组无法被禁用,因为它被下列模组所依赖</translation>
+        <translation type="vanished">这个模组无法被禁用,因为它被下列模组所依赖</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="361"/>
         <source>This mod cannot be uninstalled or updated because it is required by the following mods</source>
-        <translation>这个模组无法被卸载或者更新,因为它被下列模组所依赖</translation>
+        <translation type="vanished">这个模组无法被卸载或者更新,因为它被下列模组所依赖</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="399"/>
+        <source>This mod cannot be enabled because it translates into a different language.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="400"/>
+        <source>This mod can not be enabled because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="401"/>
+        <source>This mod can not be installed because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="402"/>
         <source>This is a submod and it cannot be installed or uninstalled separately from its parent mod</source>
         <translation>这是一个附属模组它无法在所属模组外被直接被安装或者卸载</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="377"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="421"/>
         <source>Notes</source>
         <translation>笔记注释</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="643"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
         <source>All supported files</source>
         <translation>所有支持的文件格式</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="644"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
         <source>Maps</source>
         <translation>地图</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
         <source>Campaigns</source>
         <translation>战役</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
         <source>Configs</source>
         <translation>配置</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="649"/>
         <source>Mods</source>
         <translation>模组</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
         <source>Gog files</source>
         <translation>Gog文件</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
         <source>All files (*.*)</source>
         <translation>所有文件 (*.*)</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
         <source>Select files (configs, mods, maps, campaigns, gog files) to install...</source>
         <translation>选择需要安装的文件(配置,模组,地图,战役,gog文件)...</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Replace config file?</source>
         <translation>替换配置文件?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Do you want to replace %1?</source>
         <translation>你想要替换%1吗?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="720"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="723"/>
         <source>Downloading %1. %p% (%v MB out of %m MB) finished</source>
         <translation>正在下载 %1. %p% (%v MB 共 %m MB) 已完成</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="745"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="748"/>
         <source>Download failed</source>
         <translation>下载失败</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="746"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="749"/>
         <source>Unable to download all files.
 
 Encountered errors:
@@ -492,7 +481,7 @@ Encountered errors:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="747"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="750"/>
         <source>
 
 Install successfully downloaded?</source>
@@ -501,39 +490,39 @@ Install successfully downloaded?</source>
 安装下载成功的部分?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="852"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="865"/>
         <source>Installing chronicles</source>
         <translation>安装历代记</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="925"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="927"/>
         <source>Installing mod %1</source>
         <translation>正在安装模组 %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="994"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="971"/>
         <source>Operation failed</source>
         <translation>操作失败</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="995"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="972"/>
         <source>Encountered errors:
 </source>
         <translation>遇到问题:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1030"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1007"/>
         <source>screenshots</source>
         <translation>截图</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1036"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1013"/>
         <source>Screenshot %1</source>
         <translation>截图 %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="284"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="312"/>
         <source>Mod is incompatible</source>
         <translatorcomment>Mod统一翻译为模组</translatorcomment>
         <translation>模组不兼容</translation>
@@ -542,97 +531,77 @@ Install successfully downloaded?</source>
 <context>
     <name>CModManager</name>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="168"/>
         <source>Can not install submod</source>
-        <translation>无法安装子模组</translation>
+        <translation type="vanished">无法安装子模组</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="171"/>
         <source>Mod is already installed</source>
-        <translation>模组已安装</translation>
+        <translation type="vanished">模组已安装</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="180"/>
         <source>Can not uninstall submod</source>
-        <translation>无法卸载子模组</translation>
+        <translation type="vanished">无法卸载子模组</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="183"/>
         <source>Mod is not installed</source>
-        <translation>模组未安装</translation>
+        <translation type="vanished">模组未安装</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="193"/>
         <source>Mod is already enabled</source>
-        <translation>模组已启用</translation>
+        <translation type="vanished">模组已启用</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="196"/>
-        <location filename="../modManager/cmodmanager.cpp" line="239"/>
         <source>Mod must be installed first</source>
-        <translation>需要先安装模组</translation>
+        <translation type="vanished">需要先安装模组</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="200"/>
         <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
-        <translation>模组不兼容,请更新VCMI并获取模组最新版本</translation>
+        <translation type="vanished">模组不兼容,请更新VCMI并获取模组最新版本</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="205"/>
         <source>Required mod %1 is missing</source>
-        <translation>需要的模组%1未找到</translation>
+        <translation type="vanished">需要的模组%1未找到</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="210"/>
         <source>Required mod %1 is not enabled</source>
-        <translation>需要的模组%1未启用</translation>
+        <translation type="vanished">需要的模组%1未启用</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="219"/>
-        <location filename="../modManager/cmodmanager.cpp" line="226"/>
         <source>This mod conflicts with %1</source>
-        <translation>此模组和%1冲突</translation>
+        <translation type="vanished">此模组和%1冲突</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="236"/>
         <source>Mod is already disabled</source>
-        <translation>模组已禁用</translation>
+        <translation type="vanished">模组已禁用</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="246"/>
         <source>This mod is needed to run %1</source>
-        <translation>此模组需要运行%1</translation>
+        <translation type="vanished">此模组需要运行%1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="288"/>
         <source>Mod archive is missing</source>
-        <translation>模组归档文件未找到</translation>
+        <translation type="vanished">模组归档文件未找到</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="291"/>
         <source>Mod with such name is already installed</source>
-        <translation>同名模组已安装</translation>
+        <translation type="vanished">同名模组已安装</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="296"/>
         <source>Mod archive is invalid or corrupted</source>
-        <translation>模组归档文件无效或损坏</translation>
+        <translation type="vanished">模组归档文件无效或损坏</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="322"/>
         <source>Failed to extract mod data</source>
-        <translation>提取模组数据失败</translation>
+        <translation type="vanished">提取模组数据失败</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="350"/>
         <source>Data with this mod was not found</source>
-        <translation>此模组的数据未找到</translation>
+        <translation type="vanished">此模组的数据未找到</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="354"/>
         <source>Mod is located in protected directory, please remove it manually:
 </source>
-        <translation>模组位于受保护的目录,请手动删除它:
+        <translation type="vanished">模组位于受保护的目录,请手动删除它:
 </translation>
     </message>
 </context>
@@ -1099,29 +1068,26 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
 <context>
     <name>File size</name>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="21"/>
         <source>%1 B</source>
-        <translation>%1 B</translation>
+        <translation type="vanished">%1 B</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="22"/>
         <source>%1 KiB</source>
-        <translation>%1 KiB</translation>
+        <translation type="vanished">%1 KiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="23"/>
+        <location filename="../modManager/modstate.cpp" line="140"/>
+        <location filename="../modManager/modstatemodel.cpp" line="95"/>
         <source>%1 MiB</source>
         <translation>%1 MiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="24"/>
         <source>%1 GiB</source>
-        <translation>%1 GiB</translation>
+        <translation type="vanished">%1 GiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="25"/>
         <source>%1 TiB</source>
-        <translation>%1 TiB</translation>
+        <translation type="vanished">%1 TiB</translation>
     </message>
 </context>
 <context>
@@ -1572,16 +1538,209 @@ error reason: </source>
 <context>
     <name>ModFields</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="169"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="190"/>
         <source>Name</source>
         <translation>名称</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="172"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="193"/>
         <source>Type</source>
         <translation>类型</translation>
     </message>
 </context>
+<context>
+    <name>ModStateController</name>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="126"/>
+        <source>Can not install submod</source>
+        <translation type="unfinished">无法安装子模组</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="129"/>
+        <source>Mod is already installed</source>
+        <translation type="unfinished">模组已安装</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="138"/>
+        <source>Can not uninstall submod</source>
+        <translation type="unfinished">无法卸载子模组</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="141"/>
+        <source>Mod is not installed</source>
+        <translation type="unfinished">模组未安装</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="151"/>
+        <source>Mod is already enabled</source>
+        <translation type="unfinished">模组已启用</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="154"/>
+        <location filename="../modManager/modstatecontroller.cpp" line="180"/>
+        <source>Mod must be installed first</source>
+        <translation type="unfinished">需要先安装模组</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="158"/>
+        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
+        <translation type="unfinished">模组不兼容,请更新VCMI并获取模组最新版本</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="161"/>
+        <source>Can not enable translation mod for a different language!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="166"/>
+        <source>Required mod %1 is missing</source>
+        <translation type="unfinished">需要的模组%1未找到</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="177"/>
+        <source>Mod is already disabled</source>
+        <translation type="unfinished">模组已禁用</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="190"/>
+        <source>Mod archive is missing</source>
+        <translation type="unfinished">模组归档文件未找到</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="193"/>
+        <source>Mod with such name is already installed</source>
+        <translation type="unfinished">同名模组已安装</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="198"/>
+        <source>Mod archive is invalid or corrupted</source>
+        <translation type="unfinished">模组归档文件无效或损坏</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="224"/>
+        <source>Failed to extract mod data</source>
+        <translation type="unfinished">提取模组数据失败</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="250"/>
+        <source>Data with this mod was not found</source>
+        <translation type="unfinished">此模组的数据未找到</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="254"/>
+        <source>Mod is located in protected directory, please remove it manually:
+</source>
+        <translation type="unfinished">模组位于受保护的目录,请手动删除它:
+</translation>
+    </message>
+</context>
+<context>
+    <name>ModStateItemModel</name>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="36"/>
+        <source>Translation</source>
+        <translation type="unfinished">本地化</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="37"/>
+        <source>Town</source>
+        <translation type="unfinished">城镇</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="38"/>
+        <source>Test</source>
+        <translation type="unfinished">测试</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="39"/>
+        <source>Templates</source>
+        <translation type="unfinished">地图模板</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="40"/>
+        <source>Spells</source>
+        <translation type="unfinished">法术</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="41"/>
+        <source>Music</source>
+        <translation type="unfinished">音乐</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="42"/>
+        <source>Maps</source>
+        <translation type="unfinished">地图</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="43"/>
+        <source>Sounds</source>
+        <translation type="unfinished">音效</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="44"/>
+        <source>Skills</source>
+        <translation type="unfinished">技能</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="45"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="63"/>
+        <source>Other</source>
+        <translation type="unfinished">其他</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="46"/>
+        <source>Objects</source>
+        <translation type="unfinished">物件</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="47"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="48"/>
+        <source>Mechanics</source>
+        <translation type="unfinished">机制</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="49"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="50"/>
+        <source>Interface</source>
+        <translation type="unfinished">界面</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="51"/>
+        <source>Heroes</source>
+        <translation type="unfinished">英雄</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="52"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="53"/>
+        <source>Graphical</source>
+        <translation type="unfinished">图像</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
+        <source>Expansion</source>
+        <translation type="unfinished">扩展包</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
+        <source>Creatures</source>
+        <translation type="unfinished">生物</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="56"/>
+        <source>Compatibility</source>
+        <translation type="unfinished">兼容性</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
+        <source>Artifacts</source>
+        <translation type="unfinished">宝物</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="58"/>
+        <source>AI</source>
+        <translation type="unfinished">AI</translation>
+    </message>
+</context>
 <context>
     <name>QObject</name>
     <message>

+ 304 - 145
launcher/translation/czech.ts

@@ -90,108 +90,84 @@
 <context>
     <name>CModListModel</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="42"/>
         <source>Translation</source>
-        <translation>Překlad</translation>
+        <translation type="vanished">Překlad</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="43"/>
         <source>Town</source>
-        <translation>Město</translation>
+        <translation type="vanished">Město</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="44"/>
         <source>Test</source>
-        <translation>Zkouška</translation>
+        <translation type="vanished">Zkouška</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="45"/>
         <source>Templates</source>
-        <translation>Šablony</translation>
+        <translation type="vanished">Šablony</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="46"/>
         <source>Spells</source>
-        <translation>Kouzla</translation>
+        <translation type="vanished">Kouzla</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="47"/>
         <source>Music</source>
-        <translation>Hudba</translation>
+        <translation type="vanished">Hudba</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="48"/>
         <source>Maps</source>
-        <translation>Mapy</translation>
+        <translation type="vanished">Mapy</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="49"/>
         <source>Sounds</source>
-        <translation>Zvuky</translation>
+        <translation type="vanished">Zvuky</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="50"/>
         <source>Skills</source>
-        <translation>Schopnosti</translation>
+        <translation type="vanished">Schopnosti</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="51"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="69"/>
         <source>Other</source>
-        <translation>Ostatní</translation>
+        <translation type="vanished">Ostatní</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="52"/>
         <source>Objects</source>
-        <translation>Objekty</translation>
+        <translation type="vanished">Objekty</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="53"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="54"/>
         <source>Mechanics</source>
-        <translation>Mechaniky</translation>
+        <translation type="vanished">Mechaniky</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="55"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="56"/>
         <source>Interface</source>
-        <translation>Rozhraní</translation>
+        <translation type="vanished">Rozhraní</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="57"/>
         <source>Heroes</source>
-        <translation>Hrdinové</translation>
+        <translation type="vanished">Hrdinové</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="58"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="59"/>
         <source>Graphical</source>
-        <translation>Grafika</translation>
+        <translation type="vanished">Grafika</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="60"/>
         <source>Expansion</source>
-        <translation>Rozšíření</translation>
+        <translation type="vanished">Rozšíření</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="61"/>
         <source>Creatures</source>
-        <translation>Jednotky</translation>
+        <translation type="vanished">Jednotky</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="62"/>
         <source>Compatibility</source>
-        <translation>Kompabilita</translation>
+        <translation type="vanished">Kompabilita</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="63"/>
         <source>Artifacts</source>
-        <translation>Artefakty</translation>
+        <translation type="vanished">Artefakty</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="64"/>
         <source>AI</source>
-        <translation>AI</translation>
+        <translation type="vanished">AI</translation>
     </message>
 </context>
 <context>
@@ -233,7 +209,7 @@
     </message>
     <message>
         <location filename="../modManager/cmodlistview_moc.ui" line="163"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="395"/>
         <source>Description</source>
         <translation>Popis</translation>
     </message>
@@ -293,189 +269,202 @@
         <translation>Zrušit</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="289"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="317"/>
         <source>Mod name</source>
         <translation>Název modifikace</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="290"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="320"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
         <source>Installed version</source>
         <translation>Nainstalovaná verze</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="291"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="328"/>
         <source>Latest version</source>
         <translation>Nejnovější verze</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="294"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="332"/>
         <source>Size</source>
         <translation>Velikost</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="296"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="335"/>
         <source>Download size</source>
         <translation>Velikost ke stažení</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="337"/>
         <source>Authors</source>
         <translation>Autoři</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="301"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="340"/>
         <source>License</source>
         <translation>Licence</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="304"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="343"/>
         <source>Contact</source>
         <translation>Kontakt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="313"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
         <source>Compatibility</source>
         <translation>Kompabilita</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="315"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>Required VCMI version</source>
         <translation>Vyžadovaná verze VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>Supported VCMI version</source>
         <translation>Podporovaná verze VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>please upgrade mod</source>
         <translation>prosíme aktualizujte modifikaci</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="193"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="824"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="189"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="827"/>
         <source>mods repository index</source>
         <translation>index repozitáře modifikací</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>or newer</source>
         <translation>nebo novější</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="365"/>
         <source>Supported VCMI versions</source>
         <translation>Podporované verze VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="350"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="381"/>
         <source>Languages</source>
         <translation>Jazyky</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="393"/>
         <source>Required mods</source>
         <translation>Vyžadované modifikace VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="353"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="394"/>
         <source>Conflicting mods</source>
         <translation>Modifikace v kolizi</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="358"/>
         <source>This mod can not be installed or enabled because the following dependencies are not present</source>
-        <translation>Tato modifikace nelze nainstalovat ani povolit, protože nejsou přítomny následující závislosti</translation>
+        <translation type="vanished">Tato modifikace nelze nainstalovat ani povolit, protože nejsou přítomny následující závislosti</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="359"/>
         <source>This mod can not be enabled because the following mods are incompatible with it</source>
-        <translation>Tato modifikace nemůže být povolena, protože není kompatibilní s následujícími modifikacemi</translation>
+        <translation type="vanished">Tato modifikace nemůže být povolena, protože není kompatibilní s následujícími modifikacemi</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>This mod cannot be disabled because it is required by the following mods</source>
-        <translation>Tato modifikace nemůže být zakázána, protože je vyžadována následujícími modifikacemi</translation>
+        <translation type="vanished">Tato modifikace nemůže být zakázána, protože je vyžadována následujícími modifikacemi</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="361"/>
         <source>This mod cannot be uninstalled or updated because it is required by the following mods</source>
-        <translation>Tato modifikace nemůže být odinstalována nebo aktualizována, protože je vyžadována následujícími modifikacemi</translation>
+        <translation type="vanished">Tato modifikace nemůže být odinstalována nebo aktualizována, protože je vyžadována následujícími modifikacemi</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="399"/>
+        <source>This mod cannot be enabled because it translates into a different language.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="400"/>
+        <source>This mod can not be enabled because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="401"/>
+        <source>This mod can not be installed because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="402"/>
         <source>This is a submod and it cannot be installed or uninstalled separately from its parent mod</source>
         <translation>Toto je podmodifikace a nelze ji nainstalovat ani odinstalovat samostatně bez hlavní modifikace</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="377"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="421"/>
         <source>Notes</source>
         <translation>Poznámky</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="643"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
         <source>All supported files</source>
         <translation>Všechny podporované soubory</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="644"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
         <source>Maps</source>
         <translation>Mapy</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
         <source>Campaigns</source>
         <translation>Kampaně</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
         <source>Configs</source>
         <translation>Nastavení</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="649"/>
         <source>Mods</source>
         <translation>Modifikace</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
         <source>Gog files</source>
         <translation>Soubory GOG</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
         <source>All files (*.*)</source>
         <translation>Všechny soubory (*.*)</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
         <source>Select files (configs, mods, maps, campaigns, gog files) to install...</source>
         <translation>Vyberte soubory (konfigurace, modifikace, mapy, kampaně, soubory GOG) k instalaci...</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Replace config file?</source>
         <translation>Nahradit soubor nastavení?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Do you want to replace %1?</source>
         <translation>Chcete nahradit %1?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="720"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="723"/>
         <source>Downloading %1. %p% (%v MB out of %m MB) finished</source>
         <translation>Stahování %1. %p% (%v MB z %m MB) dokončeno</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="745"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="748"/>
         <source>Download failed</source>
         <translation>Stahování selhalo</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="746"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="749"/>
         <source>Unable to download all files.
 
 Encountered errors:
@@ -488,7 +477,7 @@ Vyskytly se chyby:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="747"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="750"/>
         <source>
 
 Install successfully downloaded?</source>
@@ -497,39 +486,39 @@ Install successfully downloaded?</source>
 Nainstalovat úspěšně stažené?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="852"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="865"/>
         <source>Installing chronicles</source>
         <translation>Instalování kronik</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="925"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="927"/>
         <source>Installing mod %1</source>
         <translation>Instalování modifikace %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="994"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="971"/>
         <source>Operation failed</source>
         <translation>Operace selhala</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="995"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="972"/>
         <source>Encountered errors:
 </source>
         <translation>Vyskytly se chyby:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1030"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1007"/>
         <source>screenshots</source>
         <translation>snímky obrazovky</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1036"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1013"/>
         <source>Screenshot %1</source>
         <translation>Snímek obrazovky %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="284"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="312"/>
         <source>Mod is incompatible</source>
         <translation>Modifikace není kompatibilní</translation>
     </message>
@@ -537,97 +526,77 @@ Nainstalovat úspěšně stažené?</translation>
 <context>
     <name>CModManager</name>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="168"/>
         <source>Can not install submod</source>
-        <translation>Nelze nainstalovat podmodifikaci</translation>
+        <translation type="vanished">Nelze nainstalovat podmodifikaci</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="171"/>
         <source>Mod is already installed</source>
-        <translation>Modifikace je již nainstalována</translation>
+        <translation type="vanished">Modifikace je již nainstalována</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="180"/>
         <source>Can not uninstall submod</source>
-        <translation>Nelze odinstalovat podmodifikaci</translation>
+        <translation type="vanished">Nelze odinstalovat podmodifikaci</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="183"/>
         <source>Mod is not installed</source>
-        <translation>Modifikace není nainstalována</translation>
+        <translation type="vanished">Modifikace není nainstalována</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="193"/>
         <source>Mod is already enabled</source>
-        <translation>Modifikace je již povolena</translation>
+        <translation type="vanished">Modifikace je již povolena</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="196"/>
-        <location filename="../modManager/cmodmanager.cpp" line="239"/>
         <source>Mod must be installed first</source>
-        <translation>Nejprve musí být nainstalována modifikace</translation>
+        <translation type="vanished">Nejprve musí být nainstalována modifikace</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="200"/>
         <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
-        <translation>Modifikace není kompatibilní, prosíme aktualizujte VCMI a použijte nejnovější verzi modifikace</translation>
+        <translation type="vanished">Modifikace není kompatibilní, prosíme aktualizujte VCMI a použijte nejnovější verzi modifikace</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="205"/>
         <source>Required mod %1 is missing</source>
-        <translation>Vyžadovaná modifkace %1 chybí</translation>
+        <translation type="vanished">Vyžadovaná modifkace %1 chybí</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="210"/>
         <source>Required mod %1 is not enabled</source>
-        <translation>Vyžadovaná modifikace %1 není povolena</translation>
+        <translation type="vanished">Vyžadovaná modifikace %1 není povolena</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="219"/>
-        <location filename="../modManager/cmodmanager.cpp" line="226"/>
         <source>This mod conflicts with %1</source>
-        <translation>Tato modifikace koliduje s %1</translation>
+        <translation type="vanished">Tato modifikace koliduje s %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="236"/>
         <source>Mod is already disabled</source>
-        <translation>Modifikace je již povolena</translation>
+        <translation type="vanished">Modifikace je již povolena</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="246"/>
         <source>This mod is needed to run %1</source>
-        <translation>Modifikace %1 je vyžadována pro běh</translation>
+        <translation type="vanished">Modifikace %1 je vyžadována pro běh</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="288"/>
         <source>Mod archive is missing</source>
-        <translation>Archiv modifikace chybí</translation>
+        <translation type="vanished">Archiv modifikace chybí</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="291"/>
         <source>Mod with such name is already installed</source>
-        <translation>Modifikace s tímto názvem je již nainstalována</translation>
+        <translation type="vanished">Modifikace s tímto názvem je již nainstalována</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="296"/>
         <source>Mod archive is invalid or corrupted</source>
-        <translation>Archiv modifikace je neplatný nebo poškozený</translation>
+        <translation type="vanished">Archiv modifikace je neplatný nebo poškozený</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="322"/>
         <source>Failed to extract mod data</source>
-        <translation>Extrakce dat modifikace selhala</translation>
+        <translation type="vanished">Extrakce dat modifikace selhala</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="350"/>
         <source>Data with this mod was not found</source>
-        <translation>Data s touto modifikací nebyla nalezena</translation>
+        <translation type="vanished">Data s touto modifikací nebyla nalezena</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="354"/>
         <source>Mod is located in protected directory, please remove it manually:
 </source>
-        <translation>Modifikace se nachází v zabezpečené složce, prosíme odstraňte ji ručně:
+        <translation type="vanished">Modifikace se nachází v zabezpečené složce, prosíme odstraňte ji ručně:
 </translation>
     </message>
 </context>
@@ -1093,29 +1062,26 @@ Exkluzivní celá obrazovka - hra zakryje vaši celou obrazovku a použije vybra
 <context>
     <name>File size</name>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="21"/>
         <source>%1 B</source>
-        <translation>%1 B</translation>
+        <translation type="vanished">%1 B</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="22"/>
         <source>%1 KiB</source>
-        <translation>%1 KiB</translation>
+        <translation type="vanished">%1 KiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="23"/>
+        <location filename="../modManager/modstate.cpp" line="140"/>
+        <location filename="../modManager/modstatemodel.cpp" line="95"/>
         <source>%1 MiB</source>
         <translation>%1 MiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="24"/>
         <source>%1 GiB</source>
-        <translation>%1 GiB</translation>
+        <translation type="vanished">%1 GiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="25"/>
         <source>%1 TiB</source>
-        <translation>%1 TiB</translation>
+        <translation type="vanished">%1 TiB</translation>
     </message>
 </context>
 <context>
@@ -1565,16 +1531,209 @@ Důvod chyby: </translation>
 <context>
     <name>ModFields</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="169"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="190"/>
         <source>Name</source>
         <translation>Název</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="172"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="193"/>
         <source>Type</source>
         <translation>Druh</translation>
     </message>
 </context>
+<context>
+    <name>ModStateController</name>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="126"/>
+        <source>Can not install submod</source>
+        <translation type="unfinished">Nelze nainstalovat podmodifikaci</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="129"/>
+        <source>Mod is already installed</source>
+        <translation type="unfinished">Modifikace je již nainstalována</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="138"/>
+        <source>Can not uninstall submod</source>
+        <translation type="unfinished">Nelze odinstalovat podmodifikaci</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="141"/>
+        <source>Mod is not installed</source>
+        <translation type="unfinished">Modifikace není nainstalována</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="151"/>
+        <source>Mod is already enabled</source>
+        <translation type="unfinished">Modifikace je již povolena</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="154"/>
+        <location filename="../modManager/modstatecontroller.cpp" line="180"/>
+        <source>Mod must be installed first</source>
+        <translation type="unfinished">Nejprve musí být nainstalována modifikace</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="158"/>
+        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
+        <translation type="unfinished">Modifikace není kompatibilní, prosíme aktualizujte VCMI a použijte nejnovější verzi modifikace</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="161"/>
+        <source>Can not enable translation mod for a different language!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="166"/>
+        <source>Required mod %1 is missing</source>
+        <translation type="unfinished">Vyžadovaná modifkace %1 chybí</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="177"/>
+        <source>Mod is already disabled</source>
+        <translation type="unfinished">Modifikace je již povolena</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="190"/>
+        <source>Mod archive is missing</source>
+        <translation type="unfinished">Archiv modifikace chybí</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="193"/>
+        <source>Mod with such name is already installed</source>
+        <translation type="unfinished">Modifikace s tímto názvem je již nainstalována</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="198"/>
+        <source>Mod archive is invalid or corrupted</source>
+        <translation type="unfinished">Archiv modifikace je neplatný nebo poškozený</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="224"/>
+        <source>Failed to extract mod data</source>
+        <translation type="unfinished">Extrakce dat modifikace selhala</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="250"/>
+        <source>Data with this mod was not found</source>
+        <translation type="unfinished">Data s touto modifikací nebyla nalezena</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="254"/>
+        <source>Mod is located in protected directory, please remove it manually:
+</source>
+        <translation type="unfinished">Modifikace se nachází v zabezpečené složce, prosíme odstraňte ji ručně:
+</translation>
+    </message>
+</context>
+<context>
+    <name>ModStateItemModel</name>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="36"/>
+        <source>Translation</source>
+        <translation type="unfinished">Překlad</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="37"/>
+        <source>Town</source>
+        <translation type="unfinished">Město</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="38"/>
+        <source>Test</source>
+        <translation type="unfinished">Zkouška</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="39"/>
+        <source>Templates</source>
+        <translation type="unfinished">Šablony</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="40"/>
+        <source>Spells</source>
+        <translation type="unfinished">Kouzla</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="41"/>
+        <source>Music</source>
+        <translation type="unfinished">Hudba</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="42"/>
+        <source>Maps</source>
+        <translation type="unfinished">Mapy</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="43"/>
+        <source>Sounds</source>
+        <translation type="unfinished">Zvuky</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="44"/>
+        <source>Skills</source>
+        <translation type="unfinished">Schopnosti</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="45"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="63"/>
+        <source>Other</source>
+        <translation type="unfinished">Ostatní</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="46"/>
+        <source>Objects</source>
+        <translation type="unfinished">Objekty</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="47"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="48"/>
+        <source>Mechanics</source>
+        <translation type="unfinished">Mechaniky</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="49"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="50"/>
+        <source>Interface</source>
+        <translation type="unfinished">Rozhraní</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="51"/>
+        <source>Heroes</source>
+        <translation type="unfinished">Hrdinové</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="52"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="53"/>
+        <source>Graphical</source>
+        <translation type="unfinished">Grafika</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
+        <source>Expansion</source>
+        <translation type="unfinished">Rozšíření</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Jednotky</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="56"/>
+        <source>Compatibility</source>
+        <translation type="unfinished">Kompabilita</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
+        <source>Artifacts</source>
+        <translation type="unfinished">Artefakty</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="58"/>
+        <source>AI</source>
+        <translation type="unfinished">AI</translation>
+    </message>
+</context>
 <context>
     <name>QObject</name>
     <message>

+ 248 - 281
launcher/translation/english.ts

@@ -87,113 +87,6 @@
         <translation type="unfinished"></translation>
     </message>
 </context>
-<context>
-    <name>CModListModel</name>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="42"/>
-        <source>Translation</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="43"/>
-        <source>Town</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="44"/>
-        <source>Test</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="45"/>
-        <source>Templates</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="46"/>
-        <source>Spells</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="47"/>
-        <source>Music</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="48"/>
-        <source>Maps</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="49"/>
-        <source>Sounds</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="50"/>
-        <source>Skills</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="51"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="69"/>
-        <source>Other</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="52"/>
-        <source>Objects</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="53"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="54"/>
-        <source>Mechanics</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="55"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="56"/>
-        <source>Interface</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="57"/>
-        <source>Heroes</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="58"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="59"/>
-        <source>Graphical</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="60"/>
-        <source>Expansion</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="61"/>
-        <source>Creatures</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="62"/>
-        <source>Compatibility</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="63"/>
-        <source>Artifacts</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="64"/>
-        <source>AI</source>
-        <translation type="unfinished"></translation>
-    </message>
-</context>
 <context>
     <name>CModListView</name>
     <message>
@@ -233,7 +126,7 @@
     </message>
     <message>
         <location filename="../modManager/cmodlistview_moc.ui" line="163"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="395"/>
         <source>Description</source>
         <translation type="unfinished"></translation>
     </message>
@@ -293,189 +186,186 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="289"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="317"/>
         <source>Mod name</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="290"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="320"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
         <source>Installed version</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="291"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="328"/>
         <source>Latest version</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="294"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="332"/>
         <source>Size</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="296"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="335"/>
         <source>Download size</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="337"/>
         <source>Authors</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="301"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="340"/>
         <source>License</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="304"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="343"/>
         <source>Contact</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="313"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
         <source>Compatibility</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="315"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>Required VCMI version</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>Supported VCMI version</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>please upgrade mod</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="193"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="824"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="189"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="827"/>
         <source>mods repository index</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>or newer</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="365"/>
         <source>Supported VCMI versions</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="350"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="381"/>
         <source>Languages</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="393"/>
         <source>Required mods</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="353"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="394"/>
         <source>Conflicting mods</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="358"/>
-        <source>This mod can not be installed or enabled because the following dependencies are not present</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="359"/>
-        <source>This mod can not be enabled because the following mods are incompatible with it</source>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="399"/>
+        <source>This mod cannot be enabled because it translates into a different language.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
-        <source>This mod cannot be disabled because it is required by the following mods</source>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="400"/>
+        <source>This mod can not be enabled because the following dependencies are not present</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="361"/>
-        <source>This mod cannot be uninstalled or updated because it is required by the following mods</source>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="401"/>
+        <source>This mod can not be installed because the following dependencies are not present</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="402"/>
         <source>This is a submod and it cannot be installed or uninstalled separately from its parent mod</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="377"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="421"/>
         <source>Notes</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="643"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
         <source>All supported files</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="644"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
         <source>Maps</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
         <source>Campaigns</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
         <source>Configs</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="649"/>
         <source>Mods</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
         <source>Gog files</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
         <source>All files (*.*)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
         <source>Select files (configs, mods, maps, campaigns, gog files) to install...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Replace config file?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Do you want to replace %1?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="720"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="723"/>
         <source>Downloading %1. %p% (%v MB out of %m MB) finished</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="745"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="748"/>
         <source>Download failed</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="746"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="749"/>
         <source>Unable to download all files.
 
 Encountered errors:
@@ -484,145 +374,49 @@ Encountered errors:
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="747"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="750"/>
         <source>
 
 Install successfully downloaded?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="852"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="865"/>
         <source>Installing chronicles</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="925"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="927"/>
         <source>Installing mod %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="994"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="971"/>
         <source>Operation failed</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="995"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="972"/>
         <source>Encountered errors:
 </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1030"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1007"/>
         <source>screenshots</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1036"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1013"/>
         <source>Screenshot %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="284"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="312"/>
         <source>Mod is incompatible</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
-<context>
-    <name>CModManager</name>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="168"/>
-        <source>Can not install submod</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="171"/>
-        <source>Mod is already installed</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="180"/>
-        <source>Can not uninstall submod</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="183"/>
-        <source>Mod is not installed</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="193"/>
-        <source>Mod is already enabled</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="196"/>
-        <location filename="../modManager/cmodmanager.cpp" line="239"/>
-        <source>Mod must be installed first</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="200"/>
-        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="205"/>
-        <source>Required mod %1 is missing</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="210"/>
-        <source>Required mod %1 is not enabled</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="219"/>
-        <location filename="../modManager/cmodmanager.cpp" line="226"/>
-        <source>This mod conflicts with %1</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="236"/>
-        <source>Mod is already disabled</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="246"/>
-        <source>This mod is needed to run %1</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="288"/>
-        <source>Mod archive is missing</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="291"/>
-        <source>Mod with such name is already installed</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="296"/>
-        <source>Mod archive is invalid or corrupted</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="322"/>
-        <source>Failed to extract mod data</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="350"/>
-        <source>Data with this mod was not found</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="354"/>
-        <source>Mod is located in protected directory, please remove it manually:
-</source>
-        <translation type="unfinished"></translation>
-    </message>
-</context>
 <context>
     <name>CSettingsView</name>
     <message>
@@ -1079,30 +873,11 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
 <context>
     <name>File size</name>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="21"/>
-        <source>%1 B</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="22"/>
-        <source>%1 KiB</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="23"/>
+        <location filename="../modManager/modstate.cpp" line="140"/>
+        <location filename="../modManager/modstatemodel.cpp" line="95"/>
         <source>%1 MiB</source>
         <translation type="unfinished"></translation>
     </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="24"/>
-        <source>%1 GiB</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="25"/>
-        <source>%1 TiB</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>FirstLaunchView</name>
@@ -1540,16 +1315,208 @@ error reason: </source>
 <context>
     <name>ModFields</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="169"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="190"/>
         <source>Name</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="172"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="193"/>
         <source>Type</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
+<context>
+    <name>ModStateController</name>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="126"/>
+        <source>Can not install submod</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="129"/>
+        <source>Mod is already installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="138"/>
+        <source>Can not uninstall submod</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="141"/>
+        <source>Mod is not installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="151"/>
+        <source>Mod is already enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="154"/>
+        <location filename="../modManager/modstatecontroller.cpp" line="180"/>
+        <source>Mod must be installed first</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="158"/>
+        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="161"/>
+        <source>Can not enable translation mod for a different language!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="166"/>
+        <source>Required mod %1 is missing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="177"/>
+        <source>Mod is already disabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="190"/>
+        <source>Mod archive is missing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="193"/>
+        <source>Mod with such name is already installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="198"/>
+        <source>Mod archive is invalid or corrupted</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="224"/>
+        <source>Failed to extract mod data</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="250"/>
+        <source>Data with this mod was not found</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="254"/>
+        <source>Mod is located in protected directory, please remove it manually:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>ModStateItemModel</name>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="36"/>
+        <source>Translation</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="37"/>
+        <source>Town</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="38"/>
+        <source>Test</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="39"/>
+        <source>Templates</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="40"/>
+        <source>Spells</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="41"/>
+        <source>Music</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="42"/>
+        <source>Maps</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="43"/>
+        <source>Sounds</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="44"/>
+        <source>Skills</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="45"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="63"/>
+        <source>Other</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="46"/>
+        <source>Objects</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="47"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="48"/>
+        <source>Mechanics</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="49"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="50"/>
+        <source>Interface</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="51"/>
+        <source>Heroes</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="52"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="53"/>
+        <source>Graphical</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
+        <source>Expansion</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
+        <source>Creatures</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="56"/>
+        <source>Compatibility</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
+        <source>Artifacts</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="58"/>
+        <source>AI</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
 <context>
     <name>QObject</name>
     <message>

+ 304 - 145
launcher/translation/french.ts

@@ -90,108 +90,84 @@
 <context>
     <name>CModListModel</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="42"/>
         <source>Translation</source>
-        <translation>Traduction</translation>
+        <translation type="vanished">Traduction</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="43"/>
         <source>Town</source>
-        <translation>Ville</translation>
+        <translation type="vanished">Ville</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="44"/>
         <source>Test</source>
-        <translation>Test</translation>
+        <translation type="vanished">Test</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="45"/>
         <source>Templates</source>
-        <translation>Modèles</translation>
+        <translation type="vanished">Modèles</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="46"/>
         <source>Spells</source>
-        <translation>Sorts</translation>
+        <translation type="vanished">Sorts</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="47"/>
         <source>Music</source>
-        <translation>Musique</translation>
+        <translation type="vanished">Musique</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="48"/>
         <source>Maps</source>
-        <translation>Cartes</translation>
+        <translation type="vanished">Cartes</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="49"/>
         <source>Sounds</source>
-        <translation>Sons</translation>
+        <translation type="vanished">Sons</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="50"/>
         <source>Skills</source>
-        <translation>Compétences</translation>
+        <translation type="vanished">Compétences</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="51"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="69"/>
         <source>Other</source>
-        <translation>Autre</translation>
+        <translation type="vanished">Autre</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="52"/>
         <source>Objects</source>
-        <translation>Objets</translation>
+        <translation type="vanished">Objets</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="53"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="54"/>
         <source>Mechanics</source>
-        <translation>Mécaniques</translation>
+        <translation type="vanished">Mécaniques</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="55"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="56"/>
         <source>Interface</source>
-        <translation>Interface</translation>
+        <translation type="vanished">Interface</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="57"/>
         <source>Heroes</source>
-        <translation>Héros</translation>
+        <translation type="vanished">Héros</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="58"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="59"/>
         <source>Graphical</source>
-        <translation>Graphisme</translation>
+        <translation type="vanished">Graphisme</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="60"/>
         <source>Expansion</source>
-        <translation>Extension</translation>
+        <translation type="vanished">Extension</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="61"/>
         <source>Creatures</source>
-        <translation>Créatures</translation>
+        <translation type="vanished">Créatures</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="62"/>
         <source>Compatibility</source>
-        <translation>Compatibilité</translation>
+        <translation type="vanished">Compatibilité</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="63"/>
         <source>Artifacts</source>
-        <translation>Artefacts</translation>
+        <translation type="vanished">Artefacts</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="64"/>
         <source>AI</source>
-        <translation>IA</translation>
+        <translation type="vanished">IA</translation>
     </message>
 </context>
 <context>
@@ -238,7 +214,7 @@
     </message>
     <message>
         <location filename="../modManager/cmodlistview_moc.ui" line="163"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="395"/>
         <source>Description</source>
         <translation>Description</translation>
     </message>
@@ -293,194 +269,207 @@
         <translation>Abandonner</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="289"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="317"/>
         <source>Mod name</source>
         <translation>Nom du mod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="290"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="320"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
         <source>Installed version</source>
         <translation>Version installée</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="291"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="328"/>
         <source>Latest version</source>
         <translation>Dernière version</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="294"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="332"/>
         <source>Size</source>
         <translation>Taille</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="296"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="335"/>
         <source>Download size</source>
         <translation>Taille de téléchargement</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="337"/>
         <source>Authors</source>
         <translation>Auteur(s)</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="301"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="340"/>
         <source>License</source>
         <translation>Licence</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="304"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="343"/>
         <source>Contact</source>
         <translation>Contact</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="313"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
         <source>Compatibility</source>
         <translation>Compatibilité</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="315"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>Required VCMI version</source>
         <translation>Version requise de VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>Supported VCMI version</source>
         <translation>Version supportée de VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>please upgrade mod</source>
         <translation>veuillez mettre à jour le mod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="193"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="824"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="189"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="827"/>
         <source>mods repository index</source>
         <translation>Index du dépôt de mods</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>or newer</source>
         <translation>ou plus récente</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="365"/>
         <source>Supported VCMI versions</source>
         <translation>Versions supportées de VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="350"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="381"/>
         <source>Languages</source>
         <translation>Langues</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="393"/>
         <source>Required mods</source>
         <translation>Mods requis</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="353"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="394"/>
         <source>Conflicting mods</source>
         <translation>Mods en conflit</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="358"/>
         <source>This mod can not be installed or enabled because the following dependencies are not present</source>
-        <translation>Ce mod ne peut pas être installé ou activé car les dépendances suivantes ne sont pas présents
+        <translation type="vanished">Ce mod ne peut pas être installé ou activé car les dépendances suivantes ne sont pas présents
             </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="359"/>
         <source>This mod can not be enabled because the following mods are incompatible with it</source>
-        <translation>Ce mod ne peut pas être installé ou activé, car les dépendances suivantes sont incompatibles avec lui
+        <translation type="vanished">Ce mod ne peut pas être installé ou activé, car les dépendances suivantes sont incompatibles avec lui
             </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>This mod cannot be disabled because it is required by the following mods</source>
-        <translation>Ce mod ne peut pas être désactivé car il est requis pour les dépendances suivantes
+        <translation type="vanished">Ce mod ne peut pas être désactivé car il est requis pour les dépendances suivantes
             </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="361"/>
         <source>This mod cannot be uninstalled or updated because it is required by the following mods</source>
-        <translation>Ce mod ne peut pas être désinstallé ou mis à jour car il est requis pour les dépendances suivantes
+        <translation type="vanished">Ce mod ne peut pas être désinstallé ou mis à jour car il est requis pour les dépendances suivantes
             </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="399"/>
+        <source>This mod cannot be enabled because it translates into a different language.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="400"/>
+        <source>This mod can not be enabled because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="401"/>
+        <source>This mod can not be installed because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="402"/>
         <source>This is a submod and it cannot be installed or uninstalled separately from its parent mod</source>
         <translation>Ce sous-mod ne peut pas être installé ou mis à jour séparément du mod parent
             </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="377"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="421"/>
         <source>Notes</source>
         <translation>Notes</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="643"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
         <source>All supported files</source>
         <translation>Tous les fichiers supportés</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="644"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
         <source>Maps</source>
         <translation>Cartes</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
         <source>Campaigns</source>
         <translation>Campagnes</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
         <source>Configs</source>
         <translation>Configurations</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="649"/>
         <source>Mods</source>
         <translation>Mods</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
         <source>Gog files</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
         <source>All files (*.*)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
         <source>Select files (configs, mods, maps, campaigns, gog files) to install...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Replace config file?</source>
         <translation>Remplacer le fichier de configuration ?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Do you want to replace %1?</source>
         <translation>Voulez vous remplacer %1 ?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="720"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="723"/>
         <source>Downloading %1. %p% (%v MB out of %m MB) finished</source>
         <translation>Téléchargement %1. %p% (%v Mo sur %m Mo) terminé</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="745"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="748"/>
         <source>Download failed</source>
         <translation>Téléchargement échoué</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="746"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="749"/>
         <source>Unable to download all files.
 
 Encountered errors:
@@ -493,7 +482,7 @@ Erreur rencontrées:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="747"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="750"/>
         <source>
 
 Install successfully downloaded?</source>
@@ -502,39 +491,39 @@ Install successfully downloaded?</source>
 Installer les téchargements réussis?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="852"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="865"/>
         <source>Installing chronicles</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="925"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="927"/>
         <source>Installing mod %1</source>
         <translation>Installer le mod %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="994"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="971"/>
         <source>Operation failed</source>
         <translation>Opération échouée</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="995"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="972"/>
         <source>Encountered errors:
 </source>
         <translation>Erreurs rencontrées:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1030"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1007"/>
         <source>screenshots</source>
         <translation>captures d&apos;écran</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1036"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1013"/>
         <source>Screenshot %1</source>
         <translation>Impression écran %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="284"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="312"/>
         <source>Mod is incompatible</source>
         <translation>Ce mod est incompatible</translation>
     </message>
@@ -542,97 +531,77 @@ Installer les téchargements réussis?</translation>
 <context>
     <name>CModManager</name>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="168"/>
         <source>Can not install submod</source>
-        <translation>Impossible d&apos;installer le sous-mod</translation>
+        <translation type="vanished">Impossible d&apos;installer le sous-mod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="171"/>
         <source>Mod is already installed</source>
-        <translation>Le mod est déjà installé</translation>
+        <translation type="vanished">Le mod est déjà installé</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="180"/>
         <source>Can not uninstall submod</source>
-        <translation>Impossible de désinstaller le sousmod</translation>
+        <translation type="vanished">Impossible de désinstaller le sousmod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="183"/>
         <source>Mod is not installed</source>
-        <translation>Le mod n&apos;est pas installé</translation>
+        <translation type="vanished">Le mod n&apos;est pas installé</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="193"/>
         <source>Mod is already enabled</source>
-        <translation>Mod déjà activé</translation>
+        <translation type="vanished">Mod déjà activé</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="196"/>
-        <location filename="../modManager/cmodmanager.cpp" line="239"/>
         <source>Mod must be installed first</source>
-        <translation>Le mode doit d&apos;abord être installé</translation>
+        <translation type="vanished">Le mode doit d&apos;abord être installé</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="200"/>
         <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
-        <translation>Mod non compatible, veuillez mettre à jour VCMI et vérifier la dernière revision du mod</translation>
+        <translation type="vanished">Mod non compatible, veuillez mettre à jour VCMI et vérifier la dernière revision du mod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="205"/>
         <source>Required mod %1 is missing</source>
-        <translation>Le mod requis %1 est manquant</translation>
+        <translation type="vanished">Le mod requis %1 est manquant</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="210"/>
         <source>Required mod %1 is not enabled</source>
-        <translation>Le mod requis %1 n&apos;est pas activé</translation>
+        <translation type="vanished">Le mod requis %1 n&apos;est pas activé</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="219"/>
-        <location filename="../modManager/cmodmanager.cpp" line="226"/>
         <source>This mod conflicts with %1</source>
-        <translation>Ce mod rentre en conflit avec %1</translation>
+        <translation type="vanished">Ce mod rentre en conflit avec %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="236"/>
         <source>Mod is already disabled</source>
-        <translation>Mod déjà désactivé</translation>
+        <translation type="vanished">Mod déjà désactivé</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="246"/>
         <source>This mod is needed to run %1</source>
-        <translation>Le mod est requis pour lancer %1</translation>
+        <translation type="vanished">Le mod est requis pour lancer %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="288"/>
         <source>Mod archive is missing</source>
-        <translation>Archive du mod manquante</translation>
+        <translation type="vanished">Archive du mod manquante</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="291"/>
         <source>Mod with such name is already installed</source>
-        <translation>Un mod avec le même nom est déjà installé</translation>
+        <translation type="vanished">Un mod avec le même nom est déjà installé</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="296"/>
         <source>Mod archive is invalid or corrupted</source>
-        <translation>L&apos;archive du mod est invalide ou corrompue</translation>
+        <translation type="vanished">L&apos;archive du mod est invalide ou corrompue</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="322"/>
         <source>Failed to extract mod data</source>
-        <translation>Echec de l&apos;extraction des données du mod</translation>
+        <translation type="vanished">Echec de l&apos;extraction des données du mod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="350"/>
         <source>Data with this mod was not found</source>
-        <translation>Les données de ce mod n&apos;ont pas étés trouvées</translation>
+        <translation type="vanished">Les données de ce mod n&apos;ont pas étés trouvées</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="354"/>
         <source>Mod is located in protected directory, please remove it manually:
 </source>
-        <translation>Le mod est placé dans un dossier protégé, veuillez le supprimer manuellement:
+        <translation type="vanished">Le mod est placé dans un dossier protégé, veuillez le supprimer manuellement:
 </translation>
     </message>
 </context>
@@ -1098,29 +1067,26 @@ Mode exclusif plein écran - le jeu couvrira l&quot;intégralité de votre écra
 <context>
     <name>File size</name>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="21"/>
         <source>%1 B</source>
-        <translation>%1 B</translation>
+        <translation type="vanished">%1 B</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="22"/>
         <source>%1 KiB</source>
-        <translation>%1 KiB</translation>
+        <translation type="vanished">%1 KiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="23"/>
+        <location filename="../modManager/modstate.cpp" line="140"/>
+        <location filename="../modManager/modstatemodel.cpp" line="95"/>
         <source>%1 MiB</source>
         <translation>%1 MiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="24"/>
         <source>%1 GiB</source>
-        <translation>%1 GiB</translation>
+        <translation type="vanished">%1 GiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="25"/>
         <source>%1 TiB</source>
-        <translation>%1 TiB</translation>
+        <translation type="vanished">%1 TiB</translation>
     </message>
 </context>
 <context>
@@ -1570,16 +1536,209 @@ Raison de l&apos;erreur&#xa0;: </translation>
 <context>
     <name>ModFields</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="169"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="190"/>
         <source>Name</source>
         <translation>Nom</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="172"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="193"/>
         <source>Type</source>
         <translation>Type</translation>
     </message>
 </context>
+<context>
+    <name>ModStateController</name>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="126"/>
+        <source>Can not install submod</source>
+        <translation type="unfinished">Impossible d&apos;installer le sous-mod</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="129"/>
+        <source>Mod is already installed</source>
+        <translation type="unfinished">Le mod est déjà installé</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="138"/>
+        <source>Can not uninstall submod</source>
+        <translation type="unfinished">Impossible de désinstaller le sousmod</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="141"/>
+        <source>Mod is not installed</source>
+        <translation type="unfinished">Le mod n&apos;est pas installé</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="151"/>
+        <source>Mod is already enabled</source>
+        <translation type="unfinished">Mod déjà activé</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="154"/>
+        <location filename="../modManager/modstatecontroller.cpp" line="180"/>
+        <source>Mod must be installed first</source>
+        <translation type="unfinished">Le mode doit d&apos;abord être installé</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="158"/>
+        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
+        <translation type="unfinished">Mod non compatible, veuillez mettre à jour VCMI et vérifier la dernière revision du mod</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="161"/>
+        <source>Can not enable translation mod for a different language!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="166"/>
+        <source>Required mod %1 is missing</source>
+        <translation type="unfinished">Le mod requis %1 est manquant</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="177"/>
+        <source>Mod is already disabled</source>
+        <translation type="unfinished">Mod déjà désactivé</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="190"/>
+        <source>Mod archive is missing</source>
+        <translation type="unfinished">Archive du mod manquante</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="193"/>
+        <source>Mod with such name is already installed</source>
+        <translation type="unfinished">Un mod avec le même nom est déjà installé</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="198"/>
+        <source>Mod archive is invalid or corrupted</source>
+        <translation type="unfinished">L&apos;archive du mod est invalide ou corrompue</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="224"/>
+        <source>Failed to extract mod data</source>
+        <translation type="unfinished">Echec de l&apos;extraction des données du mod</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="250"/>
+        <source>Data with this mod was not found</source>
+        <translation type="unfinished">Les données de ce mod n&apos;ont pas étés trouvées</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="254"/>
+        <source>Mod is located in protected directory, please remove it manually:
+</source>
+        <translation type="unfinished">Le mod est placé dans un dossier protégé, veuillez le supprimer manuellement:
+</translation>
+    </message>
+</context>
+<context>
+    <name>ModStateItemModel</name>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="36"/>
+        <source>Translation</source>
+        <translation type="unfinished">Traduction</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="37"/>
+        <source>Town</source>
+        <translation type="unfinished">Ville</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="38"/>
+        <source>Test</source>
+        <translation type="unfinished">Test</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="39"/>
+        <source>Templates</source>
+        <translation type="unfinished">Modèles</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="40"/>
+        <source>Spells</source>
+        <translation type="unfinished">Sorts</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="41"/>
+        <source>Music</source>
+        <translation type="unfinished">Musique</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="42"/>
+        <source>Maps</source>
+        <translation type="unfinished">Cartes</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="43"/>
+        <source>Sounds</source>
+        <translation type="unfinished">Sons</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="44"/>
+        <source>Skills</source>
+        <translation type="unfinished">Compétences</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="45"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="63"/>
+        <source>Other</source>
+        <translation type="unfinished">Autre</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="46"/>
+        <source>Objects</source>
+        <translation type="unfinished">Objets</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="47"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="48"/>
+        <source>Mechanics</source>
+        <translation type="unfinished">Mécaniques</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="49"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="50"/>
+        <source>Interface</source>
+        <translation type="unfinished">Interface</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="51"/>
+        <source>Heroes</source>
+        <translation type="unfinished">Héros</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="52"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="53"/>
+        <source>Graphical</source>
+        <translation type="unfinished">Graphisme</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
+        <source>Expansion</source>
+        <translation type="unfinished">Extension</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Créatures</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="56"/>
+        <source>Compatibility</source>
+        <translation type="unfinished">Compatibilité</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
+        <source>Artifacts</source>
+        <translation type="unfinished">Artefacts</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="58"/>
+        <source>AI</source>
+        <translation type="unfinished">IA</translation>
+    </message>
+</context>
 <context>
     <name>QObject</name>
     <message>

+ 304 - 145
launcher/translation/german.ts

@@ -90,108 +90,84 @@
 <context>
     <name>CModListModel</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="42"/>
         <source>Translation</source>
-        <translation>Übersetzung</translation>
+        <translation type="vanished">Übersetzung</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="43"/>
         <source>Town</source>
-        <translation>Stadt</translation>
+        <translation type="vanished">Stadt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="44"/>
         <source>Test</source>
-        <translation>Test</translation>
+        <translation type="vanished">Test</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="45"/>
         <source>Templates</source>
-        <translation>Templates</translation>
+        <translation type="vanished">Templates</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="46"/>
         <source>Spells</source>
-        <translation>Zaubersprüche</translation>
+        <translation type="vanished">Zaubersprüche</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="47"/>
         <source>Music</source>
-        <translation>Musik</translation>
+        <translation type="vanished">Musik</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="48"/>
         <source>Maps</source>
-        <translation>Karten</translation>
+        <translation type="vanished">Karten</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="49"/>
         <source>Sounds</source>
-        <translation>Sounds</translation>
+        <translation type="vanished">Sounds</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="50"/>
         <source>Skills</source>
-        <translation>Fertigkeiten</translation>
+        <translation type="vanished">Fertigkeiten</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="51"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="69"/>
         <source>Other</source>
-        <translation>Andere</translation>
+        <translation type="vanished">Andere</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="52"/>
         <source>Objects</source>
-        <translation>Objekte</translation>
+        <translation type="vanished">Objekte</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="53"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="54"/>
         <source>Mechanics</source>
-        <translation>Mechaniken</translation>
+        <translation type="vanished">Mechaniken</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="55"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="56"/>
         <source>Interface</source>
-        <translation>Schnittstelle</translation>
+        <translation type="vanished">Schnittstelle</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="57"/>
         <source>Heroes</source>
-        <translation>Helden</translation>
+        <translation type="vanished">Helden</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="58"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="59"/>
         <source>Graphical</source>
-        <translation>Grafisches</translation>
+        <translation type="vanished">Grafisches</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="60"/>
         <source>Expansion</source>
-        <translation>Erweiterung</translation>
+        <translation type="vanished">Erweiterung</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="61"/>
         <source>Creatures</source>
-        <translation>Kreaturen</translation>
+        <translation type="vanished">Kreaturen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="62"/>
         <source>Compatibility</source>
-        <translation>Kompatibilität</translation>
+        <translation type="vanished">Kompatibilität</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="63"/>
         <source>Artifacts</source>
-        <translation>Artefakte</translation>
+        <translation type="vanished">Artefakte</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="64"/>
         <source>AI</source>
-        <translation>KI</translation>
+        <translation type="vanished">KI</translation>
     </message>
 </context>
 <context>
@@ -233,7 +209,7 @@
     </message>
     <message>
         <location filename="../modManager/cmodlistview_moc.ui" line="163"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="395"/>
         <source>Description</source>
         <translation>Beschreibung</translation>
     </message>
@@ -293,189 +269,202 @@
         <translation>Abbrechen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="289"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="317"/>
         <source>Mod name</source>
         <translation>Mod-Name</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="290"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="320"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
         <source>Installed version</source>
         <translation>Installierte Version</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="291"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="328"/>
         <source>Latest version</source>
         <translation>Letzte Version</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="294"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="332"/>
         <source>Size</source>
         <translation>Größe</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="296"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="335"/>
         <source>Download size</source>
         <translation>Downloadgröße</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="337"/>
         <source>Authors</source>
         <translation>Autoren</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="301"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="340"/>
         <source>License</source>
         <translation>Lizenz</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="304"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="343"/>
         <source>Contact</source>
         <translation>Kontakt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="313"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
         <source>Compatibility</source>
         <translation>Kompatibilität</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="315"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>Required VCMI version</source>
         <translation>Benötigte VCMI Version</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>Supported VCMI version</source>
         <translation>Unterstützte VCMI Version</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>please upgrade mod</source>
         <translation>bitte Mod upgraden</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="193"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="824"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="189"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="827"/>
         <source>mods repository index</source>
         <translation>Mod Verzeichnis Index</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>or newer</source>
         <translation>oder neuer</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="365"/>
         <source>Supported VCMI versions</source>
         <translation>Unterstützte VCMI Versionen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="350"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="381"/>
         <source>Languages</source>
         <translation>Sprachen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="393"/>
         <source>Required mods</source>
         <translation>Benötigte Mods</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="353"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="394"/>
         <source>Conflicting mods</source>
         <translation>Mods mit Konflikt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="358"/>
         <source>This mod can not be installed or enabled because the following dependencies are not present</source>
-        <translation>Diese Mod kann nicht installiert oder aktiviert werden, da die folgenden Abhängigkeiten nicht vorhanden sind</translation>
+        <translation type="vanished">Diese Mod kann nicht installiert oder aktiviert werden, da die folgenden Abhängigkeiten nicht vorhanden sind</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="359"/>
         <source>This mod can not be enabled because the following mods are incompatible with it</source>
-        <translation>Diese Mod kann nicht aktiviert werden, da folgende Mods nicht mit dieser Mod kompatibel sind</translation>
+        <translation type="vanished">Diese Mod kann nicht aktiviert werden, da folgende Mods nicht mit dieser Mod kompatibel sind</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>This mod cannot be disabled because it is required by the following mods</source>
-        <translation>Diese Mod kann nicht deaktiviert werden, da sie zum Ausführen der folgenden Mods erforderlich ist</translation>
+        <translation type="vanished">Diese Mod kann nicht deaktiviert werden, da sie zum Ausführen der folgenden Mods erforderlich ist</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="361"/>
         <source>This mod cannot be uninstalled or updated because it is required by the following mods</source>
-        <translation>Diese Mod kann nicht deinstalliert oder aktualisiert werden, da sie für die folgenden Mods erforderlich ist</translation>
+        <translation type="vanished">Diese Mod kann nicht deinstalliert oder aktualisiert werden, da sie für die folgenden Mods erforderlich ist</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="399"/>
+        <source>This mod cannot be enabled because it translates into a different language.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="400"/>
+        <source>This mod can not be enabled because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="401"/>
+        <source>This mod can not be installed because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="402"/>
         <source>This is a submod and it cannot be installed or uninstalled separately from its parent mod</source>
         <translation>Dies ist eine Submod und kann nicht separat von der Hauptmod installiert oder deinstalliert werden</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="377"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="421"/>
         <source>Notes</source>
         <translation>Anmerkungen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="643"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
         <source>All supported files</source>
         <translation>Alle unterstützten Dateien</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="644"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
         <source>Maps</source>
         <translation>Karten</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
         <source>Campaigns</source>
         <translation>Kampagnen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
         <source>Configs</source>
         <translation>Konfigurationen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="649"/>
         <source>Mods</source>
         <translation>Mods</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
         <source>Gog files</source>
         <translation>Gog-Dateien</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
         <source>All files (*.*)</source>
         <translation>Alle Dateien (*.*)</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
         <source>Select files (configs, mods, maps, campaigns, gog files) to install...</source>
         <translation>Wähle zu installierenden Dateien aus (Konfigs, Mods, Karten, Kampagnen, Gog-Dateien)...</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Replace config file?</source>
         <translation>Konfigurationsdatei ersetzen?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Do you want to replace %1?</source>
         <translation>Soll %1 ersetzt werden?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="720"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="723"/>
         <source>Downloading %1. %p% (%v MB out of %m MB) finished</source>
         <translation>Downloade %1. %p% (%v MB von %m MB) abgeschlossen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="745"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="748"/>
         <source>Download failed</source>
         <translation>Download fehlgeschlagen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="746"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="749"/>
         <source>Unable to download all files.
 
 Encountered errors:
@@ -488,7 +477,7 @@ Es sind Fehler aufgetreten:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="747"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="750"/>
         <source>
 
 Install successfully downloaded?</source>
@@ -497,39 +486,39 @@ Install successfully downloaded?</source>
 Installation erfolgreich heruntergeladen?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="852"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="865"/>
         <source>Installing chronicles</source>
         <translation>Installation der Chronicles</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="925"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="927"/>
         <source>Installing mod %1</source>
         <translation>Installation von Mod %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="994"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="971"/>
         <source>Operation failed</source>
         <translation>Operation fehlgeschlagen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="995"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="972"/>
         <source>Encountered errors:
 </source>
         <translation>Aufgetretene Fehler:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1030"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1007"/>
         <source>screenshots</source>
         <translation>Screenshots</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1036"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1013"/>
         <source>Screenshot %1</source>
         <translation>Screenshot %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="284"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="312"/>
         <source>Mod is incompatible</source>
         <translation>Mod ist inkompatibel</translation>
     </message>
@@ -537,97 +526,77 @@ Installation erfolgreich heruntergeladen?</translation>
 <context>
     <name>CModManager</name>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="168"/>
         <source>Can not install submod</source>
-        <translation>Submod kann nicht installiert werden</translation>
+        <translation type="vanished">Submod kann nicht installiert werden</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="171"/>
         <source>Mod is already installed</source>
-        <translation>Mod ist bereits installiert</translation>
+        <translation type="vanished">Mod ist bereits installiert</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="180"/>
         <source>Can not uninstall submod</source>
-        <translation>Submod kann nicht deinstalliert werden</translation>
+        <translation type="vanished">Submod kann nicht deinstalliert werden</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="183"/>
         <source>Mod is not installed</source>
-        <translation>Mod ist nicht installiert</translation>
+        <translation type="vanished">Mod ist nicht installiert</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="193"/>
         <source>Mod is already enabled</source>
-        <translation>Mod ist bereits aktiviert</translation>
+        <translation type="vanished">Mod ist bereits aktiviert</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="196"/>
-        <location filename="../modManager/cmodmanager.cpp" line="239"/>
         <source>Mod must be installed first</source>
-        <translation>Mod muss zuerst installiert werden</translation>
+        <translation type="vanished">Mod muss zuerst installiert werden</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="200"/>
         <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
-        <translation>Mod ist nicht kompatibel, bitte aktualisieren Sie VCMI und überprüfen Sie die neuesten Mod-Versionen</translation>
+        <translation type="vanished">Mod ist nicht kompatibel, bitte aktualisieren Sie VCMI und überprüfen Sie die neuesten Mod-Versionen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="205"/>
         <source>Required mod %1 is missing</source>
-        <translation>Der erforderliche Mod %1 fehlt</translation>
+        <translation type="vanished">Der erforderliche Mod %1 fehlt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="210"/>
         <source>Required mod %1 is not enabled</source>
-        <translation>Erforderliche Mod %1 ist nicht aktiviert</translation>
+        <translation type="vanished">Erforderliche Mod %1 ist nicht aktiviert</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="219"/>
-        <location filename="../modManager/cmodmanager.cpp" line="226"/>
         <source>This mod conflicts with %1</source>
-        <translation>Diese Mod steht im Konflikt mit %1</translation>
+        <translation type="vanished">Diese Mod steht im Konflikt mit %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="236"/>
         <source>Mod is already disabled</source>
-        <translation>Mod ist bereits deaktiviert</translation>
+        <translation type="vanished">Mod ist bereits deaktiviert</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="246"/>
         <source>This mod is needed to run %1</source>
-        <translation>Diese Mod wird benötigt, um %1 auszuführen</translation>
+        <translation type="vanished">Diese Mod wird benötigt, um %1 auszuführen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="288"/>
         <source>Mod archive is missing</source>
-        <translation>Mod-Archiv fehlt</translation>
+        <translation type="vanished">Mod-Archiv fehlt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="291"/>
         <source>Mod with such name is already installed</source>
-        <translation>Mod mit diesem Namen ist bereits installiert</translation>
+        <translation type="vanished">Mod mit diesem Namen ist bereits installiert</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="296"/>
         <source>Mod archive is invalid or corrupted</source>
-        <translation>Mod-Archiv ist ungültig oder beschädigt</translation>
+        <translation type="vanished">Mod-Archiv ist ungültig oder beschädigt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="322"/>
         <source>Failed to extract mod data</source>
-        <translation>Mod-Daten konnten nicht extrahiert werden</translation>
+        <translation type="vanished">Mod-Daten konnten nicht extrahiert werden</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="350"/>
         <source>Data with this mod was not found</source>
-        <translation>Daten mit dieser Mod wurden nicht gefunden</translation>
+        <translation type="vanished">Daten mit dieser Mod wurden nicht gefunden</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="354"/>
         <source>Mod is located in protected directory, please remove it manually:
 </source>
-        <translation>Mod befindet sich im geschützten Verzeichnis, bitte entfernen Sie sie manuell:
+        <translation type="vanished">Mod befindet sich im geschützten Verzeichnis, bitte entfernen Sie sie manuell:
 </translation>
     </message>
 </context>
@@ -1093,29 +1062,26 @@ Exklusiver Vollbildmodus - das Spiel bedeckt den gesamten Bildschirm und verwend
 <context>
     <name>File size</name>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="21"/>
         <source>%1 B</source>
-        <translation>%1 B</translation>
+        <translation type="vanished">%1 B</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="22"/>
         <source>%1 KiB</source>
-        <translation>%1 KiB</translation>
+        <translation type="vanished">%1 KiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="23"/>
+        <location filename="../modManager/modstate.cpp" line="140"/>
+        <location filename="../modManager/modstatemodel.cpp" line="95"/>
         <source>%1 MiB</source>
         <translation>%1 MiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="24"/>
         <source>%1 GiB</source>
-        <translation>%1 GiB</translation>
+        <translation type="vanished">%1 GiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="25"/>
         <source>%1 TiB</source>
-        <translation>%1 TiB</translation>
+        <translation type="vanished">%1 TiB</translation>
     </message>
 </context>
 <context>
@@ -1565,16 +1531,209 @@ Fehlerursache: </translation>
 <context>
     <name>ModFields</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="169"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="190"/>
         <source>Name</source>
         <translation>Name</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="172"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="193"/>
         <source>Type</source>
         <translation>Typ</translation>
     </message>
 </context>
+<context>
+    <name>ModStateController</name>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="126"/>
+        <source>Can not install submod</source>
+        <translation type="unfinished">Submod kann nicht installiert werden</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="129"/>
+        <source>Mod is already installed</source>
+        <translation type="unfinished">Mod ist bereits installiert</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="138"/>
+        <source>Can not uninstall submod</source>
+        <translation type="unfinished">Submod kann nicht deinstalliert werden</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="141"/>
+        <source>Mod is not installed</source>
+        <translation type="unfinished">Mod ist nicht installiert</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="151"/>
+        <source>Mod is already enabled</source>
+        <translation type="unfinished">Mod ist bereits aktiviert</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="154"/>
+        <location filename="../modManager/modstatecontroller.cpp" line="180"/>
+        <source>Mod must be installed first</source>
+        <translation type="unfinished">Mod muss zuerst installiert werden</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="158"/>
+        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
+        <translation type="unfinished">Mod ist nicht kompatibel, bitte aktualisieren Sie VCMI und überprüfen Sie die neuesten Mod-Versionen</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="161"/>
+        <source>Can not enable translation mod for a different language!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="166"/>
+        <source>Required mod %1 is missing</source>
+        <translation type="unfinished">Der erforderliche Mod %1 fehlt</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="177"/>
+        <source>Mod is already disabled</source>
+        <translation type="unfinished">Mod ist bereits deaktiviert</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="190"/>
+        <source>Mod archive is missing</source>
+        <translation type="unfinished">Mod-Archiv fehlt</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="193"/>
+        <source>Mod with such name is already installed</source>
+        <translation type="unfinished">Mod mit diesem Namen ist bereits installiert</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="198"/>
+        <source>Mod archive is invalid or corrupted</source>
+        <translation type="unfinished">Mod-Archiv ist ungültig oder beschädigt</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="224"/>
+        <source>Failed to extract mod data</source>
+        <translation type="unfinished">Mod-Daten konnten nicht extrahiert werden</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="250"/>
+        <source>Data with this mod was not found</source>
+        <translation type="unfinished">Daten mit dieser Mod wurden nicht gefunden</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="254"/>
+        <source>Mod is located in protected directory, please remove it manually:
+</source>
+        <translation type="unfinished">Mod befindet sich im geschützten Verzeichnis, bitte entfernen Sie sie manuell:
+</translation>
+    </message>
+</context>
+<context>
+    <name>ModStateItemModel</name>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="36"/>
+        <source>Translation</source>
+        <translation type="unfinished">Übersetzung</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="37"/>
+        <source>Town</source>
+        <translation type="unfinished">Stadt</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="38"/>
+        <source>Test</source>
+        <translation type="unfinished">Test</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="39"/>
+        <source>Templates</source>
+        <translation type="unfinished">Templates</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="40"/>
+        <source>Spells</source>
+        <translation type="unfinished">Zaubersprüche</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="41"/>
+        <source>Music</source>
+        <translation type="unfinished">Musik</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="42"/>
+        <source>Maps</source>
+        <translation type="unfinished">Karten</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="43"/>
+        <source>Sounds</source>
+        <translation type="unfinished">Sounds</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="44"/>
+        <source>Skills</source>
+        <translation type="unfinished">Fertigkeiten</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="45"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="63"/>
+        <source>Other</source>
+        <translation type="unfinished">Andere</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="46"/>
+        <source>Objects</source>
+        <translation type="unfinished">Objekte</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="47"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="48"/>
+        <source>Mechanics</source>
+        <translation type="unfinished">Mechaniken</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="49"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="50"/>
+        <source>Interface</source>
+        <translation type="unfinished">Schnittstelle</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="51"/>
+        <source>Heroes</source>
+        <translation type="unfinished">Helden</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="52"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="53"/>
+        <source>Graphical</source>
+        <translation type="unfinished">Grafisches</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
+        <source>Expansion</source>
+        <translation type="unfinished">Erweiterung</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Kreaturen</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="56"/>
+        <source>Compatibility</source>
+        <translation type="unfinished">Kompatibilität</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
+        <source>Artifacts</source>
+        <translation type="unfinished">Artefakte</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="58"/>
+        <source>AI</source>
+        <translation type="unfinished">KI</translation>
+    </message>
+</context>
 <context>
     <name>QObject</name>
     <message>

+ 304 - 145
launcher/translation/polish.ts

@@ -90,108 +90,84 @@
 <context>
     <name>CModListModel</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="42"/>
         <source>Translation</source>
-        <translation>Tłumaczenie</translation>
+        <translation type="vanished">Tłumaczenie</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="43"/>
         <source>Town</source>
-        <translation>Miasto</translation>
+        <translation type="vanished">Miasto</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="44"/>
         <source>Test</source>
-        <translation>Test</translation>
+        <translation type="vanished">Test</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="45"/>
         <source>Templates</source>
-        <translation>Szablony</translation>
+        <translation type="vanished">Szablony</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="46"/>
         <source>Spells</source>
-        <translation>Zaklęcia</translation>
+        <translation type="vanished">Zaklęcia</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="47"/>
         <source>Music</source>
-        <translation>Muzyczny</translation>
+        <translation type="vanished">Muzyczny</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="48"/>
         <source>Maps</source>
-        <translation>Mapy</translation>
+        <translation type="vanished">Mapy</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="49"/>
         <source>Sounds</source>
-        <translation>Dźwięki</translation>
+        <translation type="vanished">Dźwięki</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="50"/>
         <source>Skills</source>
-        <translation>Umiejętności</translation>
+        <translation type="vanished">Umiejętności</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="51"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="69"/>
         <source>Other</source>
-        <translation>Inne</translation>
+        <translation type="vanished">Inne</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="52"/>
         <source>Objects</source>
-        <translation>Obiekty</translation>
+        <translation type="vanished">Obiekty</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="53"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="54"/>
         <source>Mechanics</source>
-        <translation>Mechaniki</translation>
+        <translation type="vanished">Mechaniki</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="55"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="56"/>
         <source>Interface</source>
-        <translation>Interfejs</translation>
+        <translation type="vanished">Interfejs</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="57"/>
         <source>Heroes</source>
-        <translation>Bohaterowie</translation>
+        <translation type="vanished">Bohaterowie</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="58"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="59"/>
         <source>Graphical</source>
-        <translation>Graficzny</translation>
+        <translation type="vanished">Graficzny</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="60"/>
         <source>Expansion</source>
-        <translation>Dodatek</translation>
+        <translation type="vanished">Dodatek</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="61"/>
         <source>Creatures</source>
-        <translation>Stworzenia</translation>
+        <translation type="vanished">Stworzenia</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="62"/>
         <source>Compatibility</source>
-        <translation>Kompatybilność</translation>
+        <translation type="vanished">Kompatybilność</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="63"/>
         <source>Artifacts</source>
-        <translation>Artefakty</translation>
+        <translation type="vanished">Artefakty</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="64"/>
         <source>AI</source>
-        <translation>AI</translation>
+        <translation type="vanished">AI</translation>
     </message>
 </context>
 <context>
@@ -233,7 +209,7 @@
     </message>
     <message>
         <location filename="../modManager/cmodlistview_moc.ui" line="163"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="395"/>
         <source>Description</source>
         <translation>Opis</translation>
     </message>
@@ -293,189 +269,202 @@
         <translation>Przerwij</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="289"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="317"/>
         <source>Mod name</source>
         <translation>Nazwa moda</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="290"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="320"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
         <source>Installed version</source>
         <translation>Zainstalowana wersja</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="291"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="328"/>
         <source>Latest version</source>
         <translation>Najnowsza wersja</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="294"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="332"/>
         <source>Size</source>
         <translation>Rozmiar</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="296"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="335"/>
         <source>Download size</source>
         <translation>Rozmiar pobierania</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="337"/>
         <source>Authors</source>
         <translation>Autorzy</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="301"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="340"/>
         <source>License</source>
         <translation>Licencja</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="304"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="343"/>
         <source>Contact</source>
         <translation>Kontakt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="313"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
         <source>Compatibility</source>
         <translation>Kompatybilność</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="315"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>Required VCMI version</source>
         <translation>Wymagana wersja VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>Supported VCMI version</source>
         <translation>Wspierana wersja VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>please upgrade mod</source>
         <translation>proszę zaktualizować moda</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="193"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="824"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="189"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="827"/>
         <source>mods repository index</source>
         <translation>indeks repozytorium modów</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>or newer</source>
         <translation>lub nowsze</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="365"/>
         <source>Supported VCMI versions</source>
         <translation>Wspierane wersje VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="350"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="381"/>
         <source>Languages</source>
         <translation>Języki</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="393"/>
         <source>Required mods</source>
         <translation>Wymagane mody</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="353"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="394"/>
         <source>Conflicting mods</source>
         <translation>Konfliktujące mody</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="358"/>
         <source>This mod can not be installed or enabled because the following dependencies are not present</source>
-        <translation>Ten mod nie może zostać zainstalowany lub włączony ponieważ następujące zależności nie zostały spełnione</translation>
+        <translation type="vanished">Ten mod nie może zostać zainstalowany lub włączony ponieważ następujące zależności nie zostały spełnione</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="359"/>
         <source>This mod can not be enabled because the following mods are incompatible with it</source>
-        <translation>Ten mod nie może zostać włączony ponieważ następujące mody są z nim niekompatybilne</translation>
+        <translation type="vanished">Ten mod nie może zostać włączony ponieważ następujące mody są z nim niekompatybilne</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>This mod cannot be disabled because it is required by the following mods</source>
-        <translation>Ten mod nie może zostać wyłączony ponieważ jest wymagany do uruchomienia następujących modów</translation>
+        <translation type="vanished">Ten mod nie może zostać wyłączony ponieważ jest wymagany do uruchomienia następujących modów</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="361"/>
         <source>This mod cannot be uninstalled or updated because it is required by the following mods</source>
-        <translation>Ten mod nie może zostać odinstalowany lub zaktualizowany ponieważ jest wymagany do uruchomienia następujących modów</translation>
+        <translation type="vanished">Ten mod nie może zostać odinstalowany lub zaktualizowany ponieważ jest wymagany do uruchomienia następujących modów</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="399"/>
+        <source>This mod cannot be enabled because it translates into a different language.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="400"/>
+        <source>This mod can not be enabled because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="401"/>
+        <source>This mod can not be installed because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="402"/>
         <source>This is a submod and it cannot be installed or uninstalled separately from its parent mod</source>
         <translation>To jest moduł składowy innego moda i nie może być zainstalowany lub odinstalowany oddzielnie od moda nadrzędnego</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="377"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="421"/>
         <source>Notes</source>
         <translation>Uwagi</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="643"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
         <source>All supported files</source>
         <translation>Wszystkie wspierane pliki</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="644"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
         <source>Maps</source>
         <translation>Mapy</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
         <source>Campaigns</source>
         <translation>Kampanie</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
         <source>Configs</source>
         <translation>Konfiguracje</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="649"/>
         <source>Mods</source>
         <translation>Mody</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
         <source>Gog files</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
         <source>All files (*.*)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
         <source>Select files (configs, mods, maps, campaigns, gog files) to install...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Replace config file?</source>
         <translation>Zastąpić plik konfiguracji?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Do you want to replace %1?</source>
         <translation>Czy chcesz zastąpić %1?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="720"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="723"/>
         <source>Downloading %1. %p% (%v MB out of %m MB) finished</source>
         <translation>Pobieranie %1. %p% (%v MB z %m MB) ukończono</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="745"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="748"/>
         <source>Download failed</source>
         <translation>Pobieranie nieudane</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="746"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="749"/>
         <source>Unable to download all files.
 
 Encountered errors:
@@ -488,7 +477,7 @@ Napotkane błędy:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="747"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="750"/>
         <source>
 
 Install successfully downloaded?</source>
@@ -497,39 +486,39 @@ Install successfully downloaded?</source>
 Zainstalować pomyślnie pobrane?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="852"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="865"/>
         <source>Installing chronicles</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="925"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="927"/>
         <source>Installing mod %1</source>
         <translation>Instalowanie modyfikacji %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="994"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="971"/>
         <source>Operation failed</source>
         <translation>Operacja nieudana</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="995"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="972"/>
         <source>Encountered errors:
 </source>
         <translation>Napotkane błędy:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1030"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1007"/>
         <source>screenshots</source>
         <translation>zrzuty ekranu</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1036"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1013"/>
         <source>Screenshot %1</source>
         <translation>Zrzut ekranu %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="284"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="312"/>
         <source>Mod is incompatible</source>
         <translation>Mod jest niekompatybilny</translation>
     </message>
@@ -537,97 +526,77 @@ Zainstalować pomyślnie pobrane?</translation>
 <context>
     <name>CModManager</name>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="168"/>
         <source>Can not install submod</source>
-        <translation>Nie można zainstalować submoda</translation>
+        <translation type="vanished">Nie można zainstalować submoda</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="171"/>
         <source>Mod is already installed</source>
-        <translation>Mod jest już zainstalowany</translation>
+        <translation type="vanished">Mod jest już zainstalowany</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="180"/>
         <source>Can not uninstall submod</source>
-        <translation>Nie można odinstalować submoda</translation>
+        <translation type="vanished">Nie można odinstalować submoda</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="183"/>
         <source>Mod is not installed</source>
-        <translation>Mod nie jest zainstalowany</translation>
+        <translation type="vanished">Mod nie jest zainstalowany</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="193"/>
         <source>Mod is already enabled</source>
-        <translation>Mod jest już włączony</translation>
+        <translation type="vanished">Mod jest już włączony</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="196"/>
-        <location filename="../modManager/cmodmanager.cpp" line="239"/>
         <source>Mod must be installed first</source>
-        <translation>Mod musi zostać najpierw zainstalowany</translation>
+        <translation type="vanished">Mod musi zostać najpierw zainstalowany</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="200"/>
         <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
-        <translation>Mod nie jest kompatybilny, proszę zaktualizować VCMI i odświeżyć listę modów</translation>
+        <translation type="vanished">Mod nie jest kompatybilny, proszę zaktualizować VCMI i odświeżyć listę modów</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="205"/>
         <source>Required mod %1 is missing</source>
-        <translation>Brakuje wymaganego moda %1</translation>
+        <translation type="vanished">Brakuje wymaganego moda %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="210"/>
         <source>Required mod %1 is not enabled</source>
-        <translation>Wymagany mod %1 jest wyłączony</translation>
+        <translation type="vanished">Wymagany mod %1 jest wyłączony</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="219"/>
-        <location filename="../modManager/cmodmanager.cpp" line="226"/>
         <source>This mod conflicts with %1</source>
-        <translation>Ten mod konfliktuje z %1</translation>
+        <translation type="vanished">Ten mod konfliktuje z %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="236"/>
         <source>Mod is already disabled</source>
-        <translation>Mod jest już wyłączony</translation>
+        <translation type="vanished">Mod jest już wyłączony</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="246"/>
         <source>This mod is needed to run %1</source>
-        <translation>Ten mod jest potrzebny do uruchomienia %1</translation>
+        <translation type="vanished">Ten mod jest potrzebny do uruchomienia %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="288"/>
         <source>Mod archive is missing</source>
-        <translation>Brakuje archiwum modyfikacji</translation>
+        <translation type="vanished">Brakuje archiwum modyfikacji</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="291"/>
         <source>Mod with such name is already installed</source>
-        <translation>Mod z taką nazwą jest już zainstalowany</translation>
+        <translation type="vanished">Mod z taką nazwą jest już zainstalowany</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="296"/>
         <source>Mod archive is invalid or corrupted</source>
-        <translation>Archiwum moda jest niepoprawne lub uszkodzone</translation>
+        <translation type="vanished">Archiwum moda jest niepoprawne lub uszkodzone</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="322"/>
         <source>Failed to extract mod data</source>
-        <translation>Nieudane wyodrębnienie danych moda</translation>
+        <translation type="vanished">Nieudane wyodrębnienie danych moda</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="350"/>
         <source>Data with this mod was not found</source>
-        <translation>Dane z tym modem nie zostały znalezione</translation>
+        <translation type="vanished">Dane z tym modem nie zostały znalezione</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="354"/>
         <source>Mod is located in protected directory, please remove it manually:
 </source>
-        <translation>Mod jest umiejscowiony w chronionym folderze, proszę go usunąć ręcznie:
+        <translation type="vanished">Mod jest umiejscowiony w chronionym folderze, proszę go usunąć ręcznie:
 </translation>
     </message>
 </context>
@@ -1093,29 +1062,26 @@ Pełny ekran klasyczny - gra przysłoni cały ekran uruchamiając się w wybrane
 <context>
     <name>File size</name>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="21"/>
         <source>%1 B</source>
-        <translation>%1 B</translation>
+        <translation type="vanished">%1 B</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="22"/>
         <source>%1 KiB</source>
-        <translation>%1 KiB</translation>
+        <translation type="vanished">%1 KiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="23"/>
+        <location filename="../modManager/modstate.cpp" line="140"/>
+        <location filename="../modManager/modstatemodel.cpp" line="95"/>
         <source>%1 MiB</source>
         <translation>%1 MiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="24"/>
         <source>%1 GiB</source>
-        <translation>%1 GiB</translation>
+        <translation type="vanished">%1 GiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="25"/>
         <source>%1 TiB</source>
-        <translation>%1 TiB</translation>
+        <translation type="vanished">%1 TiB</translation>
     </message>
 </context>
 <context>
@@ -1565,16 +1531,209 @@ powód błędu: </translation>
 <context>
     <name>ModFields</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="169"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="190"/>
         <source>Name</source>
         <translation>Nazwa</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="172"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="193"/>
         <source>Type</source>
         <translation>Typ</translation>
     </message>
 </context>
+<context>
+    <name>ModStateController</name>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="126"/>
+        <source>Can not install submod</source>
+        <translation type="unfinished">Nie można zainstalować submoda</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="129"/>
+        <source>Mod is already installed</source>
+        <translation type="unfinished">Mod jest już zainstalowany</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="138"/>
+        <source>Can not uninstall submod</source>
+        <translation type="unfinished">Nie można odinstalować submoda</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="141"/>
+        <source>Mod is not installed</source>
+        <translation type="unfinished">Mod nie jest zainstalowany</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="151"/>
+        <source>Mod is already enabled</source>
+        <translation type="unfinished">Mod jest już włączony</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="154"/>
+        <location filename="../modManager/modstatecontroller.cpp" line="180"/>
+        <source>Mod must be installed first</source>
+        <translation type="unfinished">Mod musi zostać najpierw zainstalowany</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="158"/>
+        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
+        <translation type="unfinished">Mod nie jest kompatybilny, proszę zaktualizować VCMI i odświeżyć listę modów</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="161"/>
+        <source>Can not enable translation mod for a different language!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="166"/>
+        <source>Required mod %1 is missing</source>
+        <translation type="unfinished">Brakuje wymaganego moda %1</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="177"/>
+        <source>Mod is already disabled</source>
+        <translation type="unfinished">Mod jest już wyłączony</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="190"/>
+        <source>Mod archive is missing</source>
+        <translation type="unfinished">Brakuje archiwum modyfikacji</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="193"/>
+        <source>Mod with such name is already installed</source>
+        <translation type="unfinished">Mod z taką nazwą jest już zainstalowany</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="198"/>
+        <source>Mod archive is invalid or corrupted</source>
+        <translation type="unfinished">Archiwum moda jest niepoprawne lub uszkodzone</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="224"/>
+        <source>Failed to extract mod data</source>
+        <translation type="unfinished">Nieudane wyodrębnienie danych moda</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="250"/>
+        <source>Data with this mod was not found</source>
+        <translation type="unfinished">Dane z tym modem nie zostały znalezione</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="254"/>
+        <source>Mod is located in protected directory, please remove it manually:
+</source>
+        <translation type="unfinished">Mod jest umiejscowiony w chronionym folderze, proszę go usunąć ręcznie:
+</translation>
+    </message>
+</context>
+<context>
+    <name>ModStateItemModel</name>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="36"/>
+        <source>Translation</source>
+        <translation type="unfinished">Tłumaczenie</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="37"/>
+        <source>Town</source>
+        <translation type="unfinished">Miasto</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="38"/>
+        <source>Test</source>
+        <translation type="unfinished">Test</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="39"/>
+        <source>Templates</source>
+        <translation type="unfinished">Szablony</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="40"/>
+        <source>Spells</source>
+        <translation type="unfinished">Zaklęcia</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="41"/>
+        <source>Music</source>
+        <translation type="unfinished">Muzyczny</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="42"/>
+        <source>Maps</source>
+        <translation type="unfinished">Mapy</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="43"/>
+        <source>Sounds</source>
+        <translation type="unfinished">Dźwięki</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="44"/>
+        <source>Skills</source>
+        <translation type="unfinished">Umiejętności</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="45"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="63"/>
+        <source>Other</source>
+        <translation type="unfinished">Inne</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="46"/>
+        <source>Objects</source>
+        <translation type="unfinished">Obiekty</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="47"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="48"/>
+        <source>Mechanics</source>
+        <translation type="unfinished">Mechaniki</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="49"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="50"/>
+        <source>Interface</source>
+        <translation type="unfinished">Interfejs</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="51"/>
+        <source>Heroes</source>
+        <translation type="unfinished">Bohaterowie</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="52"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="53"/>
+        <source>Graphical</source>
+        <translation type="unfinished">Graficzny</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
+        <source>Expansion</source>
+        <translation type="unfinished">Dodatek</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Stworzenia</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="56"/>
+        <source>Compatibility</source>
+        <translation type="unfinished">Kompatybilność</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
+        <source>Artifacts</source>
+        <translation type="unfinished">Artefakty</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="58"/>
+        <source>AI</source>
+        <translation type="unfinished">AI</translation>
+    </message>
+</context>
 <context>
     <name>QObject</name>
     <message>

+ 304 - 145
launcher/translation/portuguese.ts

@@ -90,108 +90,84 @@
 <context>
     <name>CModListModel</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="42"/>
         <source>Translation</source>
-        <translation>Tradução</translation>
+        <translation type="vanished">Tradução</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="43"/>
         <source>Town</source>
-        <translation>Cidade</translation>
+        <translation type="vanished">Cidade</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="44"/>
         <source>Test</source>
-        <translation>Teste</translation>
+        <translation type="vanished">Teste</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="45"/>
         <source>Templates</source>
-        <translation>Modelos</translation>
+        <translation type="vanished">Modelos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="46"/>
         <source>Spells</source>
-        <translation>Feitiços</translation>
+        <translation type="vanished">Feitiços</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="47"/>
         <source>Music</source>
-        <translation>Música</translation>
+        <translation type="vanished">Música</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="48"/>
         <source>Maps</source>
-        <translation>Mapas</translation>
+        <translation type="vanished">Mapas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="49"/>
         <source>Sounds</source>
-        <translation>Sons</translation>
+        <translation type="vanished">Sons</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="50"/>
         <source>Skills</source>
-        <translation>Habilidades</translation>
+        <translation type="vanished">Habilidades</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="51"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="69"/>
         <source>Other</source>
-        <translation>Outros</translation>
+        <translation type="vanished">Outros</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="52"/>
         <source>Objects</source>
-        <translation>Objetos</translation>
+        <translation type="vanished">Objetos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="53"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="54"/>
         <source>Mechanics</source>
-        <translation>Mecânicas</translation>
+        <translation type="vanished">Mecânicas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="55"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="56"/>
         <source>Interface</source>
-        <translation>Interface</translation>
+        <translation type="vanished">Interface</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="57"/>
         <source>Heroes</source>
-        <translation>Heróis</translation>
+        <translation type="vanished">Heróis</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="58"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="59"/>
         <source>Graphical</source>
-        <translation>Gráficos</translation>
+        <translation type="vanished">Gráficos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="60"/>
         <source>Expansion</source>
-        <translation>Expansão</translation>
+        <translation type="vanished">Expansão</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="61"/>
         <source>Creatures</source>
-        <translation>Criaturas</translation>
+        <translation type="vanished">Criaturas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="62"/>
         <source>Compatibility</source>
-        <translation>Compatibilidade</translation>
+        <translation type="vanished">Compatibilidade</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="63"/>
         <source>Artifacts</source>
-        <translation>Artefatos</translation>
+        <translation type="vanished">Artefatos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="64"/>
         <source>AI</source>
-        <translation>IA</translation>
+        <translation type="vanished">IA</translation>
     </message>
 </context>
 <context>
@@ -233,7 +209,7 @@
     </message>
     <message>
         <location filename="../modManager/cmodlistview_moc.ui" line="163"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="395"/>
         <source>Description</source>
         <translation>Descrição</translation>
     </message>
@@ -293,189 +269,202 @@
         <translation>Cancelar</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="289"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="317"/>
         <source>Mod name</source>
         <translation>Nome do mod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="290"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="320"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
         <source>Installed version</source>
         <translation>Versão instalada</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="291"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="328"/>
         <source>Latest version</source>
         <translation>Última versão</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="294"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="332"/>
         <source>Size</source>
         <translation>Tamanho</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="296"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="335"/>
         <source>Download size</source>
         <translation>Tamanho do download</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="337"/>
         <source>Authors</source>
         <translation>Autores</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="301"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="340"/>
         <source>License</source>
         <translation>Licença</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="304"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="343"/>
         <source>Contact</source>
         <translation>Contato</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="313"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
         <source>Compatibility</source>
         <translation>Compatibilidade</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="315"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>Required VCMI version</source>
         <translation>Versão do VCMI necessária</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>Supported VCMI version</source>
         <translation>Versão do VCMI suportada</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>please upgrade mod</source>
         <translation>por favor, atualize o mod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="193"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="824"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="189"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="827"/>
         <source>mods repository index</source>
         <translation>índice do repositório de mods</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>or newer</source>
         <translation>ou mais recente</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="365"/>
         <source>Supported VCMI versions</source>
         <translation>Versões do VCMI suportadas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="350"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="381"/>
         <source>Languages</source>
         <translation>Idiomas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="393"/>
         <source>Required mods</source>
         <translation>Mods requeridos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="353"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="394"/>
         <source>Conflicting mods</source>
         <translation>Mods conflitantes</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="358"/>
         <source>This mod can not be installed or enabled because the following dependencies are not present</source>
-        <translation>Este mod não pode ser instalado ou ativado porque as seguintes dependências não estão presentes</translation>
+        <translation type="vanished">Este mod não pode ser instalado ou ativado porque as seguintes dependências não estão presentes</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="359"/>
         <source>This mod can not be enabled because the following mods are incompatible with it</source>
-        <translation>Este mod não pode ser ativado porque os seguintes mods são incompatíveis com ele</translation>
+        <translation type="vanished">Este mod não pode ser ativado porque os seguintes mods são incompatíveis com ele</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>This mod cannot be disabled because it is required by the following mods</source>
-        <translation>Este mod não pode ser desativado porque é necessário pelos seguintes mods</translation>
+        <translation type="vanished">Este mod não pode ser desativado porque é necessário pelos seguintes mods</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="361"/>
         <source>This mod cannot be uninstalled or updated because it is required by the following mods</source>
-        <translation>Este mod não pode ser desinstalado ou atualizado porque é necessário pelos seguintes mods</translation>
+        <translation type="vanished">Este mod não pode ser desinstalado ou atualizado porque é necessário pelos seguintes mods</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="399"/>
+        <source>This mod cannot be enabled because it translates into a different language.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="400"/>
+        <source>This mod can not be enabled because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="401"/>
+        <source>This mod can not be installed because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="402"/>
         <source>This is a submod and it cannot be installed or uninstalled separately from its parent mod</source>
         <translation>Este é um submod e não pode ser instalado ou desinstalado separadamente do seu mod principal</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="377"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="421"/>
         <source>Notes</source>
         <translation>Notas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="643"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
         <source>All supported files</source>
         <translation>Todos os arquivos suportados</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="644"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
         <source>Maps</source>
         <translation>Mapas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
         <source>Campaigns</source>
         <translation>Campanhas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
         <source>Configs</source>
         <translation>Configurações</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="649"/>
         <source>Mods</source>
         <translation>Mods</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
         <source>Gog files</source>
         <translation>Arquivos GOG</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
         <source>All files (*.*)</source>
         <translation>Todos os arquivos (*.*)</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
         <source>Select files (configs, mods, maps, campaigns, gog files) to install...</source>
         <translation>Selecione arquivos (configurações, mods, mapas, campanhas, arquivos gog) para instalar...</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Replace config file?</source>
         <translation>Substituir arquivo de configuração?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Do you want to replace %1?</source>
         <translation>Você deseja substituir %1?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="720"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="723"/>
         <source>Downloading %1. %p% (%v MB out of %m MB) finished</source>
         <translation>Baixando %1. %p% (%v MB de %m MB) concluído</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="745"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="748"/>
         <source>Download failed</source>
         <translation>Falha no download</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="746"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="749"/>
         <source>Unable to download all files.
 
 Encountered errors:
@@ -488,7 +477,7 @@ Erros encontrados:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="747"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="750"/>
         <source>
 
 Install successfully downloaded?</source>
@@ -497,39 +486,39 @@ Install successfully downloaded?</source>
 O download da instalação foi bem-sucedido?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="852"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="865"/>
         <source>Installing chronicles</source>
         <translation>Instalando crônicas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="925"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="927"/>
         <source>Installing mod %1</source>
         <translation>Instalando mod %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="994"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="971"/>
         <source>Operation failed</source>
         <translation>Falha na operação</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="995"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="972"/>
         <source>Encountered errors:
 </source>
         <translation>Erros encontrados:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1030"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1007"/>
         <source>screenshots</source>
         <translation>capturas de tela</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1036"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1013"/>
         <source>Screenshot %1</source>
         <translation>Captura de tela %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="284"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="312"/>
         <source>Mod is incompatible</source>
         <translation>O mod é incompatível</translation>
     </message>
@@ -537,97 +526,77 @@ O download da instalação foi bem-sucedido?</translation>
 <context>
     <name>CModManager</name>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="168"/>
         <source>Can not install submod</source>
-        <translation>Não é possível instalar o submod</translation>
+        <translation type="vanished">Não é possível instalar o submod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="171"/>
         <source>Mod is already installed</source>
-        <translation>O mod já está instalado</translation>
+        <translation type="vanished">O mod já está instalado</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="180"/>
         <source>Can not uninstall submod</source>
-        <translation>Não é possível desinstalar o submod</translation>
+        <translation type="vanished">Não é possível desinstalar o submod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="183"/>
         <source>Mod is not installed</source>
-        <translation>O mod não está instalado</translation>
+        <translation type="vanished">O mod não está instalado</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="193"/>
         <source>Mod is already enabled</source>
-        <translation>O mod já está ativado</translation>
+        <translation type="vanished">O mod já está ativado</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="196"/>
-        <location filename="../modManager/cmodmanager.cpp" line="239"/>
         <source>Mod must be installed first</source>
-        <translation>O mod deve ser instalado primeiro</translation>
+        <translation type="vanished">O mod deve ser instalado primeiro</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="200"/>
         <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
-        <translation>O mod não é compatível, por favor, atualize o VCMI e verifique as últimas revisões do mod</translation>
+        <translation type="vanished">O mod não é compatível, por favor, atualize o VCMI e verifique as últimas revisões do mod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="205"/>
         <source>Required mod %1 is missing</source>
-        <translation>O mod necessário %1 está faltando</translation>
+        <translation type="vanished">O mod necessário %1 está faltando</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="210"/>
         <source>Required mod %1 is not enabled</source>
-        <translation>O mod necessário %1 não está ativado</translation>
+        <translation type="vanished">O mod necessário %1 não está ativado</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="219"/>
-        <location filename="../modManager/cmodmanager.cpp" line="226"/>
         <source>This mod conflicts with %1</source>
-        <translation>Este mod entra em conflito com %1</translation>
+        <translation type="vanished">Este mod entra em conflito com %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="236"/>
         <source>Mod is already disabled</source>
-        <translation>O mod já está desativado</translation>
+        <translation type="vanished">O mod já está desativado</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="246"/>
         <source>This mod is needed to run %1</source>
-        <translation>Este mod é necessário para executar %1</translation>
+        <translation type="vanished">Este mod é necessário para executar %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="288"/>
         <source>Mod archive is missing</source>
-        <translation>O arquivo do mod está faltando</translation>
+        <translation type="vanished">O arquivo do mod está faltando</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="291"/>
         <source>Mod with such name is already installed</source>
-        <translation>Um mod com esse nome já está instalado</translation>
+        <translation type="vanished">Um mod com esse nome já está instalado</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="296"/>
         <source>Mod archive is invalid or corrupted</source>
-        <translation>O arquivo do mod é inválido ou está corrompido</translation>
+        <translation type="vanished">O arquivo do mod é inválido ou está corrompido</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="322"/>
         <source>Failed to extract mod data</source>
-        <translation>Falha ao extrair os dados do mod</translation>
+        <translation type="vanished">Falha ao extrair os dados do mod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="350"/>
         <source>Data with this mod was not found</source>
-        <translation>Não foram encontrados dados com este mod</translation>
+        <translation type="vanished">Não foram encontrados dados com este mod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="354"/>
         <source>Mod is located in protected directory, please remove it manually:
 </source>
-        <translation>O mod está localizado em um diretório protegido, por favor, remova-o manualmente:
+        <translation type="vanished">O mod está localizado em um diretório protegido, por favor, remova-o manualmente:
 </translation>
     </message>
 </context>
@@ -1093,29 +1062,26 @@ Modo de tela cheia exclusivo - o jogo cobrirá toda a sua tela e usará a resolu
 <context>
     <name>File size</name>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="21"/>
         <source>%1 B</source>
-        <translation>%1 B</translation>
+        <translation type="vanished">%1 B</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="22"/>
         <source>%1 KiB</source>
-        <translation>%1 KiB</translation>
+        <translation type="vanished">%1 KiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="23"/>
+        <location filename="../modManager/modstate.cpp" line="140"/>
+        <location filename="../modManager/modstatemodel.cpp" line="95"/>
         <source>%1 MiB</source>
         <translation>%1 MiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="24"/>
         <source>%1 GiB</source>
-        <translation>%1 GiB</translation>
+        <translation type="vanished">%1 GiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="25"/>
         <source>%1 TiB</source>
-        <translation>%1 TiB</translation>
+        <translation type="vanished">%1 TiB</translation>
     </message>
 </context>
 <context>
@@ -1565,16 +1531,209 @@ Motivo do erro: </translation>
 <context>
     <name>ModFields</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="169"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="190"/>
         <source>Name</source>
         <translation>Nome</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="172"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="193"/>
         <source>Type</source>
         <translation>Tipo</translation>
     </message>
 </context>
+<context>
+    <name>ModStateController</name>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="126"/>
+        <source>Can not install submod</source>
+        <translation type="unfinished">Não é possível instalar o submod</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="129"/>
+        <source>Mod is already installed</source>
+        <translation type="unfinished">O mod já está instalado</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="138"/>
+        <source>Can not uninstall submod</source>
+        <translation type="unfinished">Não é possível desinstalar o submod</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="141"/>
+        <source>Mod is not installed</source>
+        <translation type="unfinished">O mod não está instalado</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="151"/>
+        <source>Mod is already enabled</source>
+        <translation type="unfinished">O mod já está ativado</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="154"/>
+        <location filename="../modManager/modstatecontroller.cpp" line="180"/>
+        <source>Mod must be installed first</source>
+        <translation type="unfinished">O mod deve ser instalado primeiro</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="158"/>
+        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
+        <translation type="unfinished">O mod não é compatível, por favor, atualize o VCMI e verifique as últimas revisões do mod</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="161"/>
+        <source>Can not enable translation mod for a different language!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="166"/>
+        <source>Required mod %1 is missing</source>
+        <translation type="unfinished">O mod necessário %1 está faltando</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="177"/>
+        <source>Mod is already disabled</source>
+        <translation type="unfinished">O mod já está desativado</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="190"/>
+        <source>Mod archive is missing</source>
+        <translation type="unfinished">O arquivo do mod está faltando</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="193"/>
+        <source>Mod with such name is already installed</source>
+        <translation type="unfinished">Um mod com esse nome já está instalado</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="198"/>
+        <source>Mod archive is invalid or corrupted</source>
+        <translation type="unfinished">O arquivo do mod é inválido ou está corrompido</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="224"/>
+        <source>Failed to extract mod data</source>
+        <translation type="unfinished">Falha ao extrair os dados do mod</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="250"/>
+        <source>Data with this mod was not found</source>
+        <translation type="unfinished">Não foram encontrados dados com este mod</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="254"/>
+        <source>Mod is located in protected directory, please remove it manually:
+</source>
+        <translation type="unfinished">O mod está localizado em um diretório protegido, por favor, remova-o manualmente:
+</translation>
+    </message>
+</context>
+<context>
+    <name>ModStateItemModel</name>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="36"/>
+        <source>Translation</source>
+        <translation type="unfinished">Tradução</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="37"/>
+        <source>Town</source>
+        <translation type="unfinished">Cidade</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="38"/>
+        <source>Test</source>
+        <translation type="unfinished">Teste</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="39"/>
+        <source>Templates</source>
+        <translation type="unfinished">Modelos</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="40"/>
+        <source>Spells</source>
+        <translation type="unfinished">Feitiços</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="41"/>
+        <source>Music</source>
+        <translation type="unfinished">Música</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="42"/>
+        <source>Maps</source>
+        <translation type="unfinished">Mapas</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="43"/>
+        <source>Sounds</source>
+        <translation type="unfinished">Sons</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="44"/>
+        <source>Skills</source>
+        <translation type="unfinished">Habilidades</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="45"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="63"/>
+        <source>Other</source>
+        <translation type="unfinished">Outros</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="46"/>
+        <source>Objects</source>
+        <translation type="unfinished">Objetos</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="47"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="48"/>
+        <source>Mechanics</source>
+        <translation type="unfinished">Mecânicas</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="49"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="50"/>
+        <source>Interface</source>
+        <translation type="unfinished">Interface</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="51"/>
+        <source>Heroes</source>
+        <translation type="unfinished">Heróis</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="52"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="53"/>
+        <source>Graphical</source>
+        <translation type="unfinished">Gráficos</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
+        <source>Expansion</source>
+        <translation type="unfinished">Expansão</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Criaturas</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="56"/>
+        <source>Compatibility</source>
+        <translation type="unfinished">Compatibilidade</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
+        <source>Artifacts</source>
+        <translation type="unfinished">Artefatos</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="58"/>
+        <source>AI</source>
+        <translation type="unfinished">IA</translation>
+    </message>
+</context>
 <context>
     <name>QObject</name>
     <message>

+ 280 - 218
launcher/translation/russian.ts

@@ -90,108 +90,80 @@
 <context>
     <name>CModListModel</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="42"/>
         <source>Translation</source>
-        <translation>Перевод</translation>
+        <translation type="vanished">Перевод</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="43"/>
         <source>Town</source>
-        <translation>Город</translation>
+        <translation type="vanished">Город</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="44"/>
         <source>Test</source>
-        <translation>Тест</translation>
+        <translation type="vanished">Тест</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="45"/>
         <source>Templates</source>
-        <translation>Шаблоны карт</translation>
+        <translation type="vanished">Шаблоны карт</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="46"/>
         <source>Spells</source>
-        <translation>Заклинания</translation>
+        <translation type="vanished">Заклинания</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="47"/>
         <source>Music</source>
-        <translation>Музыка</translation>
+        <translation type="vanished">Музыка</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="48"/>
-        <source>Maps</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="49"/>
         <source>Sounds</source>
-        <translation>Звуки</translation>
+        <translation type="vanished">Звуки</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="50"/>
         <source>Skills</source>
-        <translation>Навыки</translation>
+        <translation type="vanished">Навыки</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="51"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="69"/>
         <source>Other</source>
-        <translation>Иное</translation>
+        <translation type="vanished">Иное</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="52"/>
         <source>Objects</source>
-        <translation>Объекты</translation>
+        <translation type="vanished">Объекты</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="53"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="54"/>
         <source>Mechanics</source>
-        <translation>Механика</translation>
+        <translation type="vanished">Механика</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="55"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="56"/>
         <source>Interface</source>
-        <translation>Интерфейс</translation>
+        <translation type="vanished">Интерфейс</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="57"/>
         <source>Heroes</source>
-        <translation>Герои</translation>
+        <translation type="vanished">Герои</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="58"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="59"/>
         <source>Graphical</source>
-        <translation>Графика</translation>
+        <translation type="vanished">Графика</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="60"/>
         <source>Expansion</source>
-        <translation>Дополнение</translation>
+        <translation type="vanished">Дополнение</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="61"/>
         <source>Creatures</source>
-        <translation>Существа</translation>
+        <translation type="vanished">Существа</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="62"/>
         <source>Compatibility</source>
-        <translation type="unfinished">Совместимость</translation>
+        <translation type="obsolete">Совместимость</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="63"/>
         <source>Artifacts</source>
-        <translation>Артефакт</translation>
+        <translation type="vanished">Артефакт</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="64"/>
         <source>AI</source>
-        <translation>ИИ</translation>
+        <translation type="vanished">ИИ</translation>
     </message>
 </context>
 <context>
@@ -233,7 +205,7 @@
     </message>
     <message>
         <location filename="../modManager/cmodlistview_moc.ui" line="163"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="395"/>
         <source>Description</source>
         <translation>Описание</translation>
     </message>
@@ -293,189 +265,202 @@
         <translation>Отмена</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="289"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="317"/>
         <source>Mod name</source>
         <translation>Название мода</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="290"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="320"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
         <source>Installed version</source>
         <translation>Установленная версия</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="291"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="328"/>
         <source>Latest version</source>
         <translation>Последняя версия</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="294"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="332"/>
         <source>Size</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="296"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="335"/>
         <source>Download size</source>
         <translation>Размер загрузки</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="337"/>
         <source>Authors</source>
         <translation>Авторы</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="301"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="340"/>
         <source>License</source>
         <translation>Лицензия</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="304"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="343"/>
         <source>Contact</source>
         <translation>Контакты</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="313"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
         <source>Compatibility</source>
         <translation>Совместимость</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="315"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>Required VCMI version</source>
         <translation>Требуемая версия VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>Supported VCMI version</source>
         <translation>Поддерживаемая версия VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>please upgrade mod</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="193"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="824"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="189"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="827"/>
         <source>mods repository index</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>or newer</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="365"/>
         <source>Supported VCMI versions</source>
         <translation>Поддерживаемые версии VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="350"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="381"/>
         <source>Languages</source>
         <translation>Языки</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="393"/>
         <source>Required mods</source>
         <translation>Зависимости</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="353"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="394"/>
         <source>Conflicting mods</source>
         <translation>Конфликтующие моды</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="358"/>
         <source>This mod can not be installed or enabled because the following dependencies are not present</source>
-        <translation>Этот мод не может быть установлен или активирован, так как отсутствуют следующие зависимости</translation>
+        <translation type="vanished">Этот мод не может быть установлен или активирован, так как отсутствуют следующие зависимости</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="359"/>
         <source>This mod can not be enabled because the following mods are incompatible with it</source>
-        <translation>Этот мод не может быть установлен или активирован, так как следующие моды несовместимы с этим</translation>
+        <translation type="vanished">Этот мод не может быть установлен или активирован, так как следующие моды несовместимы с этим</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>This mod cannot be disabled because it is required by the following mods</source>
-        <translation>Этот мод не может быть выключен, так как он является зависимостью для следующих</translation>
+        <translation type="vanished">Этот мод не может быть выключен, так как он является зависимостью для следующих</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="361"/>
         <source>This mod cannot be uninstalled or updated because it is required by the following mods</source>
-        <translation>Этот мод не может быть удален или обновлен, так как является зависимостью для следующих модов</translation>
+        <translation type="vanished">Этот мод не может быть удален или обновлен, так как является зависимостью для следующих модов</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="399"/>
+        <source>This mod cannot be enabled because it translates into a different language.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="400"/>
+        <source>This mod can not be enabled because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="401"/>
+        <source>This mod can not be installed because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="402"/>
         <source>This is a submod and it cannot be installed or uninstalled separately from its parent mod</source>
         <translation>Это вложенный мод, он не может быть установлен или удален отдельно от родительского</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="377"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="421"/>
         <source>Notes</source>
         <translation>Замечания</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="643"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
         <source>All supported files</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="644"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
         <source>Maps</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
         <source>Campaigns</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
         <source>Configs</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="649"/>
         <source>Mods</source>
         <translation type="unfinished">Моды</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
         <source>Gog files</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
         <source>All files (*.*)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
         <source>Select files (configs, mods, maps, campaigns, gog files) to install...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Replace config file?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Do you want to replace %1?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="720"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="723"/>
         <source>Downloading %1. %p% (%v MB out of %m MB) finished</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="745"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="748"/>
         <source>Download failed</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="746"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="749"/>
         <source>Unable to download all files.
 
 Encountered errors:
@@ -484,145 +469,49 @@ Encountered errors:
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="747"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="750"/>
         <source>
 
 Install successfully downloaded?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="852"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="865"/>
         <source>Installing chronicles</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="925"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="927"/>
         <source>Installing mod %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="994"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="971"/>
         <source>Operation failed</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="995"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="972"/>
         <source>Encountered errors:
 </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1030"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1007"/>
         <source>screenshots</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1036"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1013"/>
         <source>Screenshot %1</source>
         <translation>Скриншот %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="284"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="312"/>
         <source>Mod is incompatible</source>
         <translation>Мод несовместим</translation>
     </message>
 </context>
-<context>
-    <name>CModManager</name>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="168"/>
-        <source>Can not install submod</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="171"/>
-        <source>Mod is already installed</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="180"/>
-        <source>Can not uninstall submod</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="183"/>
-        <source>Mod is not installed</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="193"/>
-        <source>Mod is already enabled</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="196"/>
-        <location filename="../modManager/cmodmanager.cpp" line="239"/>
-        <source>Mod must be installed first</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="200"/>
-        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="205"/>
-        <source>Required mod %1 is missing</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="210"/>
-        <source>Required mod %1 is not enabled</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="219"/>
-        <location filename="../modManager/cmodmanager.cpp" line="226"/>
-        <source>This mod conflicts with %1</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="236"/>
-        <source>Mod is already disabled</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="246"/>
-        <source>This mod is needed to run %1</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="288"/>
-        <source>Mod archive is missing</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="291"/>
-        <source>Mod with such name is already installed</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="296"/>
-        <source>Mod archive is invalid or corrupted</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="322"/>
-        <source>Failed to extract mod data</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="350"/>
-        <source>Data with this mod was not found</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="354"/>
-        <source>Mod is located in protected directory, please remove it manually:
-</source>
-        <translation type="unfinished"></translation>
-    </message>
-</context>
 <context>
     <name>CSettingsView</name>
     <message>
@@ -1079,30 +968,11 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
 <context>
     <name>File size</name>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="21"/>
-        <source>%1 B</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="22"/>
-        <source>%1 KiB</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="23"/>
+        <location filename="../modManager/modstate.cpp" line="140"/>
+        <location filename="../modManager/modstatemodel.cpp" line="95"/>
         <source>%1 MiB</source>
         <translation type="unfinished"></translation>
     </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="24"/>
-        <source>%1 GiB</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="25"/>
-        <source>%1 TiB</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>FirstLaunchView</name>
@@ -1546,16 +1416,208 @@ error reason: </source>
 <context>
     <name>ModFields</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="169"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="190"/>
         <source>Name</source>
         <translation type="unfinished">Название</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="172"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="193"/>
         <source>Type</source>
         <translation type="unfinished">Тип</translation>
     </message>
 </context>
+<context>
+    <name>ModStateController</name>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="126"/>
+        <source>Can not install submod</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="129"/>
+        <source>Mod is already installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="138"/>
+        <source>Can not uninstall submod</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="141"/>
+        <source>Mod is not installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="151"/>
+        <source>Mod is already enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="154"/>
+        <location filename="../modManager/modstatecontroller.cpp" line="180"/>
+        <source>Mod must be installed first</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="158"/>
+        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="161"/>
+        <source>Can not enable translation mod for a different language!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="166"/>
+        <source>Required mod %1 is missing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="177"/>
+        <source>Mod is already disabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="190"/>
+        <source>Mod archive is missing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="193"/>
+        <source>Mod with such name is already installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="198"/>
+        <source>Mod archive is invalid or corrupted</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="224"/>
+        <source>Failed to extract mod data</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="250"/>
+        <source>Data with this mod was not found</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="254"/>
+        <source>Mod is located in protected directory, please remove it manually:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>ModStateItemModel</name>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="36"/>
+        <source>Translation</source>
+        <translation type="unfinished">Перевод</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="37"/>
+        <source>Town</source>
+        <translation type="unfinished">Город</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="38"/>
+        <source>Test</source>
+        <translation type="unfinished">Тест</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="39"/>
+        <source>Templates</source>
+        <translation type="unfinished">Шаблоны карт</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="40"/>
+        <source>Spells</source>
+        <translation type="unfinished">Заклинания</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="41"/>
+        <source>Music</source>
+        <translation type="unfinished">Музыка</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="42"/>
+        <source>Maps</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="43"/>
+        <source>Sounds</source>
+        <translation type="unfinished">Звуки</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="44"/>
+        <source>Skills</source>
+        <translation type="unfinished">Навыки</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="45"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="63"/>
+        <source>Other</source>
+        <translation type="unfinished">Иное</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="46"/>
+        <source>Objects</source>
+        <translation type="unfinished">Объекты</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="47"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="48"/>
+        <source>Mechanics</source>
+        <translation type="unfinished">Механика</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="49"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="50"/>
+        <source>Interface</source>
+        <translation type="unfinished">Интерфейс</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="51"/>
+        <source>Heroes</source>
+        <translation type="unfinished">Герои</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="52"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="53"/>
+        <source>Graphical</source>
+        <translation type="unfinished">Графика</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
+        <source>Expansion</source>
+        <translation type="unfinished">Дополнение</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Существа</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="56"/>
+        <source>Compatibility</source>
+        <translation type="unfinished">Совместимость</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
+        <source>Artifacts</source>
+        <translation type="unfinished">Артефакт</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="58"/>
+        <source>AI</source>
+        <translation type="unfinished">ИИ</translation>
+    </message>
+</context>
 <context>
     <name>QObject</name>
     <message>

+ 281 - 215
launcher/translation/spanish.ts

@@ -90,108 +90,84 @@
 <context>
     <name>CModListModel</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="42"/>
         <source>Translation</source>
-        <translation>Traducción</translation>
+        <translation type="vanished">Traducción</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="43"/>
         <source>Town</source>
-        <translation>Ciudad</translation>
+        <translation type="vanished">Ciudad</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="44"/>
         <source>Test</source>
-        <translation>Test</translation>
+        <translation type="vanished">Test</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="45"/>
         <source>Templates</source>
-        <translation>Plantillas</translation>
+        <translation type="vanished">Plantillas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="46"/>
         <source>Spells</source>
-        <translation>Hechizos</translation>
+        <translation type="vanished">Hechizos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="47"/>
         <source>Music</source>
-        <translation>Música</translation>
+        <translation type="vanished">Música</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="48"/>
         <source>Maps</source>
-        <translation>Mapas</translation>
+        <translation type="vanished">Mapas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="49"/>
         <source>Sounds</source>
-        <translation>Sonidos</translation>
+        <translation type="vanished">Sonidos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="50"/>
         <source>Skills</source>
-        <translation>Habilidades</translation>
+        <translation type="vanished">Habilidades</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="51"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="69"/>
         <source>Other</source>
-        <translation>Otro</translation>
+        <translation type="vanished">Otro</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="52"/>
         <source>Objects</source>
-        <translation>Objetos</translation>
+        <translation type="vanished">Objetos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="53"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="54"/>
         <source>Mechanics</source>
-        <translation>Mecánicas</translation>
+        <translation type="vanished">Mecánicas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="55"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="56"/>
         <source>Interface</source>
-        <translation>Interfaz</translation>
+        <translation type="vanished">Interfaz</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="57"/>
         <source>Heroes</source>
-        <translation>Heroes</translation>
+        <translation type="vanished">Heroes</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="58"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="59"/>
         <source>Graphical</source>
-        <translation>Gráficos</translation>
+        <translation type="vanished">Gráficos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="60"/>
         <source>Expansion</source>
-        <translation>Expansión</translation>
+        <translation type="vanished">Expansión</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="61"/>
         <source>Creatures</source>
-        <translation>Criaturas</translation>
+        <translation type="vanished">Criaturas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="62"/>
         <source>Compatibility</source>
-        <translation>Compatibilidad</translation>
+        <translation type="vanished">Compatibilidad</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="63"/>
         <source>Artifacts</source>
-        <translation>Artefactos</translation>
+        <translation type="vanished">Artefactos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="64"/>
         <source>AI</source>
-        <translation>IA</translation>
+        <translation type="vanished">IA</translation>
     </message>
 </context>
 <context>
@@ -233,7 +209,7 @@
     </message>
     <message>
         <location filename="../modManager/cmodlistview_moc.ui" line="163"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="395"/>
         <source>Description</source>
         <translation>Descripción</translation>
     </message>
@@ -293,189 +269,202 @@
         <translation>Cancelar</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="289"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="317"/>
         <source>Mod name</source>
         <translation>Nombre del mod</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="290"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="320"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
         <source>Installed version</source>
         <translation>Versión instalada</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="291"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="328"/>
         <source>Latest version</source>
         <translation>Última versión</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="294"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="332"/>
         <source>Size</source>
         <translation>Tamaño</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="296"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="335"/>
         <source>Download size</source>
         <translation>Tamaño de descarga</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="337"/>
         <source>Authors</source>
         <translation>Autores</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="301"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="340"/>
         <source>License</source>
         <translation>Licencia</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="304"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="343"/>
         <source>Contact</source>
         <translation>Contacto</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="313"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
         <source>Compatibility</source>
         <translation>Compatibilidad</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="315"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>Required VCMI version</source>
         <translation>Versión de VCMI requerida</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>Supported VCMI version</source>
         <translation>Versión de VCMI compatible</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>please upgrade mod</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="193"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="824"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="189"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="827"/>
         <source>mods repository index</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>or newer</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="365"/>
         <source>Supported VCMI versions</source>
         <translation>Versiones de VCMI compatibles</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="350"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="381"/>
         <source>Languages</source>
         <translation>Idiomas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="393"/>
         <source>Required mods</source>
         <translation>Mods requeridos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="353"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="394"/>
         <source>Conflicting mods</source>
         <translation>Mods conflictivos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="358"/>
         <source>This mod can not be installed or enabled because the following dependencies are not present</source>
-        <translation>Este mod no se puede instalar o habilitar porque no están presentes las siguientes dependencias</translation>
+        <translation type="vanished">Este mod no se puede instalar o habilitar porque no están presentes las siguientes dependencias</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="359"/>
         <source>This mod can not be enabled because the following mods are incompatible with it</source>
-        <translation>Este mod no se puede habilitar porque los siguientes mods son incompatibles con él</translation>
+        <translation type="vanished">Este mod no se puede habilitar porque los siguientes mods son incompatibles con él</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>This mod cannot be disabled because it is required by the following mods</source>
-        <translation>No se puede desactivar este mod porque es necesario para ejecutar los siguientes mods</translation>
+        <translation type="vanished">No se puede desactivar este mod porque es necesario para ejecutar los siguientes mods</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="361"/>
         <source>This mod cannot be uninstalled or updated because it is required by the following mods</source>
-        <translation>No se puede desinstalar o actualizar este mod porque es necesario para ejecutar los siguientes mods</translation>
+        <translation type="vanished">No se puede desinstalar o actualizar este mod porque es necesario para ejecutar los siguientes mods</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="399"/>
+        <source>This mod cannot be enabled because it translates into a different language.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="400"/>
+        <source>This mod can not be enabled because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="401"/>
+        <source>This mod can not be installed because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="402"/>
         <source>This is a submod and it cannot be installed or uninstalled separately from its parent mod</source>
         <translation>Este es un submod y no se puede instalar o desinstalar por separado del mod principal</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="377"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="421"/>
         <source>Notes</source>
         <translation>Notas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="643"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
         <source>All supported files</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="644"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
         <source>Maps</source>
         <translation type="unfinished">Mapas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
         <source>Campaigns</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
         <source>Configs</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="649"/>
         <source>Mods</source>
         <translation type="unfinished">Mods</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
         <source>Gog files</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
         <source>All files (*.*)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
         <source>Select files (configs, mods, maps, campaigns, gog files) to install...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Replace config file?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Do you want to replace %1?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="720"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="723"/>
         <source>Downloading %1. %p% (%v MB out of %m MB) finished</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="745"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="748"/>
         <source>Download failed</source>
         <translation>Descarga fallida</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="746"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="749"/>
         <source>Unable to download all files.
 
 Encountered errors:
@@ -488,7 +477,7 @@ Errores encontrados:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="747"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="750"/>
         <source>
 
 Install successfully downloaded?</source>
@@ -497,139 +486,43 @@ Install successfully downloaded?</source>
 Instalar lo correctamente descargado?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="852"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="865"/>
         <source>Installing chronicles</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="925"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="927"/>
         <source>Installing mod %1</source>
         <translation>Instalando mod %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="994"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="971"/>
         <source>Operation failed</source>
         <translation>Operación fallida</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="995"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="972"/>
         <source>Encountered errors:
 </source>
         <translation>Errores encontrados:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1030"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1007"/>
         <source>screenshots</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1036"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1013"/>
         <source>Screenshot %1</source>
         <translation>Captura de pantalla %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="284"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="312"/>
         <source>Mod is incompatible</source>
         <translation>El mod es incompatible</translation>
     </message>
 </context>
-<context>
-    <name>CModManager</name>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="168"/>
-        <source>Can not install submod</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="171"/>
-        <source>Mod is already installed</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="180"/>
-        <source>Can not uninstall submod</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="183"/>
-        <source>Mod is not installed</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="193"/>
-        <source>Mod is already enabled</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="196"/>
-        <location filename="../modManager/cmodmanager.cpp" line="239"/>
-        <source>Mod must be installed first</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="200"/>
-        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="205"/>
-        <source>Required mod %1 is missing</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="210"/>
-        <source>Required mod %1 is not enabled</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="219"/>
-        <location filename="../modManager/cmodmanager.cpp" line="226"/>
-        <source>This mod conflicts with %1</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="236"/>
-        <source>Mod is already disabled</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="246"/>
-        <source>This mod is needed to run %1</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="288"/>
-        <source>Mod archive is missing</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="291"/>
-        <source>Mod with such name is already installed</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="296"/>
-        <source>Mod archive is invalid or corrupted</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="322"/>
-        <source>Failed to extract mod data</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="350"/>
-        <source>Data with this mod was not found</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="354"/>
-        <source>Mod is located in protected directory, please remove it manually:
-</source>
-        <translation type="unfinished"></translation>
-    </message>
-</context>
 <context>
     <name>CSettingsView</name>
     <message>
@@ -1092,30 +985,11 @@ Pantalla completa - el juego cubrirá la totalidad de la pantalla y utilizará l
 <context>
     <name>File size</name>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="21"/>
-        <source>%1 B</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="22"/>
-        <source>%1 KiB</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="23"/>
+        <location filename="../modManager/modstate.cpp" line="140"/>
+        <location filename="../modManager/modstatemodel.cpp" line="95"/>
         <source>%1 MiB</source>
         <translation type="unfinished"></translation>
     </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="24"/>
-        <source>%1 GiB</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="25"/>
-        <source>%1 TiB</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>FirstLaunchView</name>
@@ -1559,16 +1433,208 @@ error reason: </source>
 <context>
     <name>ModFields</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="169"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="190"/>
         <source>Name</source>
         <translation type="unfinished">Nombre</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="172"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="193"/>
         <source>Type</source>
         <translation type="unfinished">Tipo</translation>
     </message>
 </context>
+<context>
+    <name>ModStateController</name>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="126"/>
+        <source>Can not install submod</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="129"/>
+        <source>Mod is already installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="138"/>
+        <source>Can not uninstall submod</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="141"/>
+        <source>Mod is not installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="151"/>
+        <source>Mod is already enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="154"/>
+        <location filename="../modManager/modstatecontroller.cpp" line="180"/>
+        <source>Mod must be installed first</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="158"/>
+        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="161"/>
+        <source>Can not enable translation mod for a different language!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="166"/>
+        <source>Required mod %1 is missing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="177"/>
+        <source>Mod is already disabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="190"/>
+        <source>Mod archive is missing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="193"/>
+        <source>Mod with such name is already installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="198"/>
+        <source>Mod archive is invalid or corrupted</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="224"/>
+        <source>Failed to extract mod data</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="250"/>
+        <source>Data with this mod was not found</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="254"/>
+        <source>Mod is located in protected directory, please remove it manually:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>ModStateItemModel</name>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="36"/>
+        <source>Translation</source>
+        <translation type="unfinished">Traducción</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="37"/>
+        <source>Town</source>
+        <translation type="unfinished">Ciudad</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="38"/>
+        <source>Test</source>
+        <translation type="unfinished">Test</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="39"/>
+        <source>Templates</source>
+        <translation type="unfinished">Plantillas</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="40"/>
+        <source>Spells</source>
+        <translation type="unfinished">Hechizos</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="41"/>
+        <source>Music</source>
+        <translation type="unfinished">Música</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="42"/>
+        <source>Maps</source>
+        <translation type="unfinished">Mapas</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="43"/>
+        <source>Sounds</source>
+        <translation type="unfinished">Sonidos</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="44"/>
+        <source>Skills</source>
+        <translation type="unfinished">Habilidades</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="45"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="63"/>
+        <source>Other</source>
+        <translation type="unfinished">Otro</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="46"/>
+        <source>Objects</source>
+        <translation type="unfinished">Objetos</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="47"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="48"/>
+        <source>Mechanics</source>
+        <translation type="unfinished">Mecánicas</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="49"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="50"/>
+        <source>Interface</source>
+        <translation type="unfinished">Interfaz</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="51"/>
+        <source>Heroes</source>
+        <translation type="unfinished">Heroes</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="52"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="53"/>
+        <source>Graphical</source>
+        <translation type="unfinished">Gráficos</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
+        <source>Expansion</source>
+        <translation type="unfinished">Expansión</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Criaturas</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="56"/>
+        <source>Compatibility</source>
+        <translation type="unfinished">Compatibilidad</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
+        <source>Artifacts</source>
+        <translation type="unfinished">Artefactos</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="58"/>
+        <source>AI</source>
+        <translation type="unfinished">IA</translation>
+    </message>
+</context>
 <context>
     <name>QObject</name>
     <message>

+ 304 - 145
launcher/translation/swedish.ts

@@ -90,108 +90,84 @@
 <context>
     <name>CModListModel</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="42"/>
         <source>Translation</source>
-        <translation>Översättning</translation>
+        <translation type="vanished">Översättning</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="43"/>
         <source>Town</source>
-        <translation>Stad</translation>
+        <translation type="vanished">Stad</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="44"/>
         <source>Test</source>
-        <translation>Test</translation>
+        <translation type="vanished">Test</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="45"/>
         <source>Templates</source>
-        <translation>Modeller</translation>
+        <translation type="vanished">Modeller</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="46"/>
         <source>Spells</source>
-        <translation>Trollformler</translation>
+        <translation type="vanished">Trollformler</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="47"/>
         <source>Music</source>
-        <translation>Musik</translation>
+        <translation type="vanished">Musik</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="48"/>
         <source>Maps</source>
-        <translation>Kartor</translation>
+        <translation type="vanished">Kartor</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="49"/>
         <source>Sounds</source>
-        <translation>Ljud</translation>
+        <translation type="vanished">Ljud</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="50"/>
         <source>Skills</source>
-        <translation>Färdigheter</translation>
+        <translation type="vanished">Färdigheter</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="51"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="69"/>
         <source>Other</source>
-        <translation>Annan</translation>
+        <translation type="vanished">Annan</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="52"/>
         <source>Objects</source>
-        <translation>Objekt</translation>
+        <translation type="vanished">Objekt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="53"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="54"/>
         <source>Mechanics</source>
-        <translation>Mekanik</translation>
+        <translation type="vanished">Mekanik</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="55"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="56"/>
         <source>Interface</source>
-        <translation>Gränssnitt</translation>
+        <translation type="vanished">Gränssnitt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="57"/>
         <source>Heroes</source>
-        <translation>Hjälte</translation>
+        <translation type="vanished">Hjälte</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="58"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="59"/>
         <source>Graphical</source>
-        <translation>Grafik</translation>
+        <translation type="vanished">Grafik</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="60"/>
         <source>Expansion</source>
-        <translation>Expansion/Tillägg</translation>
+        <translation type="vanished">Expansion/Tillägg</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="61"/>
         <source>Creatures</source>
-        <translation>Varelser</translation>
+        <translation type="vanished">Varelser</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="62"/>
         <source>Compatibility</source>
-        <translation>Kompatibilitet</translation>
+        <translation type="vanished">Kompatibilitet</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="63"/>
         <source>Artifacts</source>
-        <translation>Artefakter</translation>
+        <translation type="vanished">Artefakter</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="64"/>
         <source>AI</source>
-        <translation>AI</translation>
+        <translation type="vanished">AI</translation>
     </message>
 </context>
 <context>
@@ -238,7 +214,7 @@
     </message>
     <message>
         <location filename="../modManager/cmodlistview_moc.ui" line="163"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="395"/>
         <source>Description</source>
         <translation>Beskrivning</translation>
     </message>
@@ -293,189 +269,202 @@
         <translation>Avbryt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="289"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="317"/>
         <source>Mod name</source>
         <translation>Modd-namn</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="290"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="320"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
         <source>Installed version</source>
         <translation>Installerad version</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="291"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="328"/>
         <source>Latest version</source>
         <translation>Senaste version</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="294"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="332"/>
         <source>Size</source>
         <translation>Storlek</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="296"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="335"/>
         <source>Download size</source>
         <translation>Nedladdnings-storlek</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="337"/>
         <source>Authors</source>
         <translation>Författare</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="301"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="340"/>
         <source>License</source>
         <translation>Licens</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="304"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="343"/>
         <source>Contact</source>
         <translation>Kontakt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="313"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
         <source>Compatibility</source>
         <translation>Kompatibilitet</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="315"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>Required VCMI version</source>
         <translation>VCMI-version som krävs</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>Supported VCMI version</source>
         <translation>VCMI-version som stöds</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>please upgrade mod</source>
         <translation>vänligen uppdatera modd</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="193"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="824"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="189"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="827"/>
         <source>mods repository index</source>
         <translation>Modd-repositorie-index</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>or newer</source>
         <translation>eller nyare</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="365"/>
         <source>Supported VCMI versions</source>
         <translation>VCMI-versioner som stöds</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="350"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="381"/>
         <source>Languages</source>
         <translation>Språk</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="393"/>
         <source>Required mods</source>
         <translation>Moddar som krävs</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="353"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="394"/>
         <source>Conflicting mods</source>
         <translation>Modd-konflikter</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="358"/>
         <source>This mod can not be installed or enabled because the following dependencies are not present</source>
-        <translation>Denna modd kan inte installeras eller aktiveras eftersom följande beroenden inte finns</translation>
+        <translation type="vanished">Denna modd kan inte installeras eller aktiveras eftersom följande beroenden inte finns</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="359"/>
         <source>This mod can not be enabled because the following mods are incompatible with it</source>
-        <translation>Denna modd kan inte aktiveras eftersom följande moddar är inkompatibla med den</translation>
+        <translation type="vanished">Denna modd kan inte aktiveras eftersom följande moddar är inkompatibla med den</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>This mod cannot be disabled because it is required by the following mods</source>
-        <translation>Denna modd kan inte inaktiveras eftersom den krävs för följande modd</translation>
+        <translation type="vanished">Denna modd kan inte inaktiveras eftersom den krävs för följande modd</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="361"/>
         <source>This mod cannot be uninstalled or updated because it is required by the following mods</source>
-        <translation>Denna modd kan inte avinstalleras eller uppdateras eftersom den krävs för följande modd</translation>
+        <translation type="vanished">Denna modd kan inte avinstalleras eller uppdateras eftersom den krävs för följande modd</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="399"/>
+        <source>This mod cannot be enabled because it translates into a different language.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="400"/>
+        <source>This mod can not be enabled because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="401"/>
+        <source>This mod can not be installed because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="402"/>
         <source>This is a submod and it cannot be installed or uninstalled separately from its parent mod</source>
         <translation>Detta är en undermodd/submodd och den kan inte installeras eller avinstalleras separat från huvud-modden</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="377"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="421"/>
         <source>Notes</source>
         <translation>Anteckningar</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="643"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
         <source>All supported files</source>
         <translation>Alla filer som stöds</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="644"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
         <source>Maps</source>
         <translation>Kartor</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
         <source>Campaigns</source>
         <translation>Kampanjer</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
         <source>Configs</source>
         <translation>Konfigurationer</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="649"/>
         <source>Mods</source>
         <translation>Moddar</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
         <source>Gog files</source>
         <translation>GOG-filer</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
         <source>All files (*.*)</source>
         <translation>Alla filer (*.*)</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
         <source>Select files (configs, mods, maps, campaigns, gog files) to install...</source>
         <translation>Välj filer (konfigurationsfiler, moddar, kartor, kampanjer och GOG-filer) som ska installeras...</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Replace config file?</source>
         <translation>Byt ut konfigurationsfilen?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Do you want to replace %1?</source>
         <translation>Vill du ersätta %1?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="720"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="723"/>
         <source>Downloading %1. %p% (%v MB out of %m MB) finished</source>
         <translation>Laddar ner %1. %p% (%v MB av %m MB) slutfört</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="745"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="748"/>
         <source>Download failed</source>
         <translation>Nedladdning misslyckades</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="746"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="749"/>
         <source>Unable to download all files.
 
 Encountered errors:
@@ -488,7 +477,7 @@ Fel påträffat:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="747"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="750"/>
         <source>
 
 Install successfully downloaded?</source>
@@ -497,39 +486,39 @@ Install successfully downloaded?</source>
 Installation framgångsrikt nedladdad?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="852"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="865"/>
         <source>Installing chronicles</source>
         <translation>Installera Chronicles</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="925"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="927"/>
         <source>Installing mod %1</source>
         <translation>Installera modd %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="994"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="971"/>
         <source>Operation failed</source>
         <translation>Åtgärden misslyckades</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="995"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="972"/>
         <source>Encountered errors:
 </source>
         <translation>Fel påträffades:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1030"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1007"/>
         <source>screenshots</source>
         <translation>skärmdumpar</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1036"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1013"/>
         <source>Screenshot %1</source>
         <translation>Skärmbild %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="284"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="312"/>
         <source>Mod is incompatible</source>
         <translation>Denna modd är inkompatibel</translation>
     </message>
@@ -537,97 +526,77 @@ Installation framgångsrikt nedladdad?</translation>
 <context>
     <name>CModManager</name>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="168"/>
         <source>Can not install submod</source>
-        <translation>Det går inte att installera undermodd/submodd</translation>
+        <translation type="vanished">Det går inte att installera undermodd/submodd</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="171"/>
         <source>Mod is already installed</source>
-        <translation>Modden är redan installerad</translation>
+        <translation type="vanished">Modden är redan installerad</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="180"/>
         <source>Can not uninstall submod</source>
-        <translation>Det går inte att avinstallera undermodd/submodd</translation>
+        <translation type="vanished">Det går inte att avinstallera undermodd/submodd</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="183"/>
         <source>Mod is not installed</source>
-        <translation>Modden är inte installerad</translation>
+        <translation type="vanished">Modden är inte installerad</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="193"/>
         <source>Mod is already enabled</source>
-        <translation>Modden är redan aktiverad</translation>
+        <translation type="vanished">Modden är redan aktiverad</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="196"/>
-        <location filename="../modManager/cmodmanager.cpp" line="239"/>
         <source>Mod must be installed first</source>
-        <translation>Modden måste installeras först</translation>
+        <translation type="vanished">Modden måste installeras först</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="200"/>
         <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
-        <translation>Modden är inte kompatibel. Vänligen uppdatera VCMI och kontrollera att du har den senaste kompatibla versionen av modden</translation>
+        <translation type="vanished">Modden är inte kompatibel. Vänligen uppdatera VCMI och kontrollera att du har den senaste kompatibla versionen av modden</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="205"/>
         <source>Required mod %1 is missing</source>
-        <translation>Den obligatorisk modden %1 saknas</translation>
+        <translation type="vanished">Den obligatorisk modden %1 saknas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="210"/>
         <source>Required mod %1 is not enabled</source>
-        <translation>Den obligatoriska modden %1 är inte aktiverad</translation>
+        <translation type="vanished">Den obligatoriska modden %1 är inte aktiverad</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="219"/>
-        <location filename="../modManager/cmodmanager.cpp" line="226"/>
         <source>This mod conflicts with %1</source>
-        <translation>Denna modd är i konflikt med %1</translation>
+        <translation type="vanished">Denna modd är i konflikt med %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="236"/>
         <source>Mod is already disabled</source>
-        <translation>Modden är redan inaktiverad</translation>
+        <translation type="vanished">Modden är redan inaktiverad</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="246"/>
         <source>This mod is needed to run %1</source>
-        <translation>Denna modden krävs för att köra %1</translation>
+        <translation type="vanished">Denna modden krävs för att köra %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="288"/>
         <source>Mod archive is missing</source>
-        <translation>Modd-arkiv saknas</translation>
+        <translation type="vanished">Modd-arkiv saknas</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="291"/>
         <source>Mod with such name is already installed</source>
-        <translation>En modd med samma namn är redan installerad</translation>
+        <translation type="vanished">En modd med samma namn är redan installerad</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="296"/>
         <source>Mod archive is invalid or corrupted</source>
-        <translation>Modd-arkivet är ogiltigt eller korrupt</translation>
+        <translation type="vanished">Modd-arkivet är ogiltigt eller korrupt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="322"/>
         <source>Failed to extract mod data</source>
-        <translation>Misslyckades att extrahera data från modd</translation>
+        <translation type="vanished">Misslyckades att extrahera data från modd</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="350"/>
         <source>Data with this mod was not found</source>
-        <translation>Modd-data för denna modd hittades inte</translation>
+        <translation type="vanished">Modd-data för denna modd hittades inte</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="354"/>
         <source>Mod is located in protected directory, please remove it manually:
 </source>
-        <translation>Modden är placerad i en skyddad mapp. Vänligen radera den manuellt:
+        <translation type="vanished">Modden är placerad i en skyddad mapp. Vänligen radera den manuellt:
 </translation>
     </message>
 </context>
@@ -1093,29 +1062,26 @@ Exklusivt helskärmsläge - spelet kommer att täcka hela skärmen och använda
 <context>
     <name>File size</name>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="21"/>
         <source>%1 B</source>
-        <translation>%1 B</translation>
+        <translation type="vanished">%1 B</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="22"/>
         <source>%1 KiB</source>
-        <translation>%1 KiB</translation>
+        <translation type="vanished">%1 KiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="23"/>
+        <location filename="../modManager/modstate.cpp" line="140"/>
+        <location filename="../modManager/modstatemodel.cpp" line="95"/>
         <source>%1 MiB</source>
         <translation>%1 MiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="24"/>
         <source>%1 GiB</source>
-        <translation>%1 GiB</translation>
+        <translation type="vanished">%1 GiB</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="25"/>
         <source>%1 TiB</source>
-        <translation>%1 TiB</translation>
+        <translation type="vanished">%1 TiB</translation>
     </message>
 </context>
 <context>
@@ -1563,16 +1529,209 @@ Orsak till fel: </translation>
 <context>
     <name>ModFields</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="169"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="190"/>
         <source>Name</source>
         <translation>Namn</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="172"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="193"/>
         <source>Type</source>
         <translation>Typ</translation>
     </message>
 </context>
+<context>
+    <name>ModStateController</name>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="126"/>
+        <source>Can not install submod</source>
+        <translation type="unfinished">Det går inte att installera undermodd/submodd</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="129"/>
+        <source>Mod is already installed</source>
+        <translation type="unfinished">Modden är redan installerad</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="138"/>
+        <source>Can not uninstall submod</source>
+        <translation type="unfinished">Det går inte att avinstallera undermodd/submodd</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="141"/>
+        <source>Mod is not installed</source>
+        <translation type="unfinished">Modden är inte installerad</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="151"/>
+        <source>Mod is already enabled</source>
+        <translation type="unfinished">Modden är redan aktiverad</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="154"/>
+        <location filename="../modManager/modstatecontroller.cpp" line="180"/>
+        <source>Mod must be installed first</source>
+        <translation type="unfinished">Modden måste installeras först</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="158"/>
+        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
+        <translation type="unfinished">Modden är inte kompatibel. Vänligen uppdatera VCMI och kontrollera att du har den senaste kompatibla versionen av modden</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="161"/>
+        <source>Can not enable translation mod for a different language!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="166"/>
+        <source>Required mod %1 is missing</source>
+        <translation type="unfinished">Den obligatorisk modden %1 saknas</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="177"/>
+        <source>Mod is already disabled</source>
+        <translation type="unfinished">Modden är redan inaktiverad</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="190"/>
+        <source>Mod archive is missing</source>
+        <translation type="unfinished">Modd-arkiv saknas</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="193"/>
+        <source>Mod with such name is already installed</source>
+        <translation type="unfinished">En modd med samma namn är redan installerad</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="198"/>
+        <source>Mod archive is invalid or corrupted</source>
+        <translation type="unfinished">Modd-arkivet är ogiltigt eller korrupt</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="224"/>
+        <source>Failed to extract mod data</source>
+        <translation type="unfinished">Misslyckades att extrahera data från modd</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="250"/>
+        <source>Data with this mod was not found</source>
+        <translation type="unfinished">Modd-data för denna modd hittades inte</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="254"/>
+        <source>Mod is located in protected directory, please remove it manually:
+</source>
+        <translation type="unfinished">Modden är placerad i en skyddad mapp. Vänligen radera den manuellt:
+</translation>
+    </message>
+</context>
+<context>
+    <name>ModStateItemModel</name>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="36"/>
+        <source>Translation</source>
+        <translation type="unfinished">Översättning</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="37"/>
+        <source>Town</source>
+        <translation type="unfinished">Stad</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="38"/>
+        <source>Test</source>
+        <translation type="unfinished">Test</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="39"/>
+        <source>Templates</source>
+        <translation type="unfinished">Modeller</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="40"/>
+        <source>Spells</source>
+        <translation type="unfinished">Trollformler</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="41"/>
+        <source>Music</source>
+        <translation type="unfinished">Musik</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="42"/>
+        <source>Maps</source>
+        <translation type="unfinished">Kartor</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="43"/>
+        <source>Sounds</source>
+        <translation type="unfinished">Ljud</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="44"/>
+        <source>Skills</source>
+        <translation type="unfinished">Färdigheter</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="45"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="63"/>
+        <source>Other</source>
+        <translation type="unfinished">Övrigt</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="46"/>
+        <source>Objects</source>
+        <translation type="unfinished">Objekt</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="47"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="48"/>
+        <source>Mechanics</source>
+        <translation type="unfinished">Mekanik</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="49"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="50"/>
+        <source>Interface</source>
+        <translation type="unfinished">Gränssnitt</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="51"/>
+        <source>Heroes</source>
+        <translation type="unfinished">Hjälte</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="52"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="53"/>
+        <source>Graphical</source>
+        <translation type="unfinished">Grafik</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
+        <source>Expansion</source>
+        <translation type="unfinished">Expansion/Tillägg</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Varelser</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="56"/>
+        <source>Compatibility</source>
+        <translation type="unfinished">Kompatibilitet</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
+        <source>Artifacts</source>
+        <translation type="unfinished">Artefakter</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="58"/>
+        <source>AI</source>
+        <translation type="unfinished">AI</translation>
+    </message>
+</context>
 <context>
     <name>QObject</name>
     <message>

+ 304 - 145
launcher/translation/ukrainian.ts

@@ -90,108 +90,84 @@
 <context>
     <name>CModListModel</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="42"/>
         <source>Translation</source>
-        <translation>Переклад</translation>
+        <translation type="vanished">Переклад</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="43"/>
         <source>Town</source>
-        <translation>Місто</translation>
+        <translation type="vanished">Місто</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="44"/>
         <source>Test</source>
-        <translation>Тестування</translation>
+        <translation type="vanished">Тестування</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="45"/>
         <source>Templates</source>
-        <translation>Шаблони</translation>
+        <translation type="vanished">Шаблони</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="46"/>
         <source>Spells</source>
-        <translation>Закляття</translation>
+        <translation type="vanished">Закляття</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="47"/>
         <source>Music</source>
-        <translation>Музика</translation>
+        <translation type="vanished">Музика</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="48"/>
         <source>Maps</source>
-        <translation>Мапи</translation>
+        <translation type="vanished">Мапи</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="49"/>
         <source>Sounds</source>
-        <translation>Звуки</translation>
+        <translation type="vanished">Звуки</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="50"/>
         <source>Skills</source>
-        <translation>Вміння</translation>
+        <translation type="vanished">Вміння</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="51"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="69"/>
         <source>Other</source>
-        <translation>Інше</translation>
+        <translation type="vanished">Інше</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="52"/>
         <source>Objects</source>
-        <translation>Об&apos;єкти</translation>
+        <translation type="vanished">Об&apos;єкти</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="53"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="54"/>
         <source>Mechanics</source>
-        <translation>Механіки</translation>
+        <translation type="vanished">Механіки</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="55"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="56"/>
         <source>Interface</source>
-        <translation>Інтерфейс</translation>
+        <translation type="vanished">Інтерфейс</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="57"/>
         <source>Heroes</source>
-        <translation>Герої</translation>
+        <translation type="vanished">Герої</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="58"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="59"/>
         <source>Graphical</source>
-        <translation>Графічний</translation>
+        <translation type="vanished">Графічний</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="60"/>
         <source>Expansion</source>
-        <translation>Розширення</translation>
+        <translation type="vanished">Розширення</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="61"/>
         <source>Creatures</source>
-        <translation>Істоти</translation>
+        <translation type="vanished">Істоти</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="62"/>
         <source>Compatibility</source>
-        <translation>Сумісність</translation>
+        <translation type="vanished">Сумісність</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="63"/>
         <source>Artifacts</source>
-        <translation>Артефакти</translation>
+        <translation type="vanished">Артефакти</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="64"/>
         <source>AI</source>
-        <translation>ШІ</translation>
+        <translation type="vanished">ШІ</translation>
     </message>
 </context>
 <context>
@@ -233,7 +209,7 @@
     </message>
     <message>
         <location filename="../modManager/cmodlistview_moc.ui" line="163"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="395"/>
         <source>Description</source>
         <translation>Опис</translation>
     </message>
@@ -293,189 +269,202 @@
         <translation>Відмінити</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="289"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="317"/>
         <source>Mod name</source>
         <translation>Назва модифікації</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="290"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="320"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
         <source>Installed version</source>
         <translation>Встановлена версія</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="291"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="328"/>
         <source>Latest version</source>
         <translation>Найновіша версія</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="294"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="332"/>
         <source>Size</source>
         <translation>Розмір</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="296"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="335"/>
         <source>Download size</source>
         <translation>Розмір для завантаження</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="337"/>
         <source>Authors</source>
         <translation>Автори</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="301"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="340"/>
         <source>License</source>
         <translation>Ліцензія</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="304"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="343"/>
         <source>Contact</source>
         <translation>Контакти</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="313"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
         <source>Compatibility</source>
         <translation>Сумісність</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="315"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>Required VCMI version</source>
         <translation>Необхідна версія VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>Supported VCMI version</source>
         <translation>Підтримувана версія VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>please upgrade mod</source>
         <translation>будь ласка, оновіть модифікацію</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="193"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="824"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="189"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="827"/>
         <source>mods repository index</source>
         <translation>каталог модифікацій</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>or newer</source>
         <translation>або новіше</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="365"/>
         <source>Supported VCMI versions</source>
         <translation>Підтримувані версії VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="350"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="381"/>
         <source>Languages</source>
         <translation>Мови</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="393"/>
         <source>Required mods</source>
         <translation>Необхідні модифікації</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="353"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="394"/>
         <source>Conflicting mods</source>
         <translation>Конфліктуючі модифікації</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="358"/>
         <source>This mod can not be installed or enabled because the following dependencies are not present</source>
-        <translation>Цю модифікацію не можна встановити чи активувати, оскільки відсутні наступні залежності</translation>
+        <translation type="vanished">Цю модифікацію не можна встановити чи активувати, оскільки відсутні наступні залежності</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="359"/>
         <source>This mod can not be enabled because the following mods are incompatible with it</source>
-        <translation>Цю модифікацію не можна ввімкнути, оскільки наступні модифікації несумісні з цією модифікацією</translation>
+        <translation type="vanished">Цю модифікацію не можна ввімкнути, оскільки наступні модифікації несумісні з цією модифікацією</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>This mod cannot be disabled because it is required by the following mods</source>
-        <translation>Цю модифікацію не можна відключити, оскільки вона необхідна для запуску наступних модифікацій</translation>
+        <translation type="vanished">Цю модифікацію не можна відключити, оскільки вона необхідна для запуску наступних модифікацій</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="361"/>
         <source>This mod cannot be uninstalled or updated because it is required by the following mods</source>
-        <translation>Цю модифікацію не можна видалити або оновити, оскільки вона необхідна для запуску наступних модифікацій</translation>
+        <translation type="vanished">Цю модифікацію не можна видалити або оновити, оскільки вона необхідна для запуску наступних модифікацій</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="399"/>
+        <source>This mod cannot be enabled because it translates into a different language.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="400"/>
+        <source>This mod can not be enabled because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="401"/>
+        <source>This mod can not be installed because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="402"/>
         <source>This is a submod and it cannot be installed or uninstalled separately from its parent mod</source>
         <translation>Це вкладена модифікація, і її не можна встановити або видалити окремо від батьківської модифікації</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="377"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="421"/>
         <source>Notes</source>
         <translation>Примітки</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="643"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
         <source>All supported files</source>
         <translation>Усі підтримувані файли</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="644"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
         <source>Maps</source>
         <translation>Мапи</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
         <source>Campaigns</source>
         <translation>Кампанії</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
         <source>Configs</source>
         <translation>Налаштування</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="649"/>
         <source>Mods</source>
         <translation>Модифікації</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
         <source>Gog files</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
         <source>All files (*.*)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
         <source>Select files (configs, mods, maps, campaigns, gog files) to install...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Replace config file?</source>
         <translation>Замінити файл налаштувань?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Do you want to replace %1?</source>
         <translation>Ви дійсно хочете замінити %1?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="720"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="723"/>
         <source>Downloading %1. %p% (%v MB out of %m MB) finished</source>
         <translation>Завантажується %1. %p% (%v MB з %m MB) завершено</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="745"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="748"/>
         <source>Download failed</source>
         <translation>Помилка завантаження</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="746"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="749"/>
         <source>Unable to download all files.
 
 Encountered errors:
@@ -488,7 +477,7 @@ Encountered errors:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="747"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="750"/>
         <source>
 
 Install successfully downloaded?</source>
@@ -497,39 +486,39 @@ Install successfully downloaded?</source>
 Встановити успішно завантажені?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="852"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="865"/>
         <source>Installing chronicles</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="925"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="927"/>
         <source>Installing mod %1</source>
         <translation>Встановлення модифікації %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="994"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="971"/>
         <source>Operation failed</source>
         <translation>Операція завершилася невдало</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="995"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="972"/>
         <source>Encountered errors:
 </source>
         <translation>Виникли помилки:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1030"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1007"/>
         <source>screenshots</source>
         <translation>знімки екрану</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1036"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1013"/>
         <source>Screenshot %1</source>
         <translation>Знімок екрану %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="284"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="312"/>
         <source>Mod is incompatible</source>
         <translation>Модифікація несумісна</translation>
     </message>
@@ -537,97 +526,77 @@ Install successfully downloaded?</source>
 <context>
     <name>CModManager</name>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="168"/>
         <source>Can not install submod</source>
-        <translation>Неможливо встановити вкладену модифікацію</translation>
+        <translation type="vanished">Неможливо встановити вкладену модифікацію</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="171"/>
         <source>Mod is already installed</source>
-        <translation>Модифікація вже встановлена</translation>
+        <translation type="vanished">Модифікація вже встановлена</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="180"/>
         <source>Can not uninstall submod</source>
-        <translation>Неможливо видалити вкладену модифікацію</translation>
+        <translation type="vanished">Неможливо видалити вкладену модифікацію</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="183"/>
         <source>Mod is not installed</source>
-        <translation>Модифікація не встановлена</translation>
+        <translation type="vanished">Модифікація не встановлена</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="193"/>
         <source>Mod is already enabled</source>
-        <translation>Модифікація вже увімкнена</translation>
+        <translation type="vanished">Модифікація вже увімкнена</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="196"/>
-        <location filename="../modManager/cmodmanager.cpp" line="239"/>
         <source>Mod must be installed first</source>
-        <translation>Спочатку потрібно встановити модифікацію</translation>
+        <translation type="vanished">Спочатку потрібно встановити модифікацію</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="200"/>
         <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
-        <translation>Модифікація несумісна, будь ласка, оновіть VCMI та перевірте останні версії модифікацій</translation>
+        <translation type="vanished">Модифікація несумісна, будь ласка, оновіть VCMI та перевірте останні версії модифікацій</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="205"/>
         <source>Required mod %1 is missing</source>
-        <translation>Необхідна модифікація %1 відсутня</translation>
+        <translation type="vanished">Необхідна модифікація %1 відсутня</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="210"/>
         <source>Required mod %1 is not enabled</source>
-        <translation>Необхідну модифікацію %1 не ввімкнено</translation>
+        <translation type="vanished">Необхідну модифікацію %1 не ввімкнено</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="219"/>
-        <location filename="../modManager/cmodmanager.cpp" line="226"/>
         <source>This mod conflicts with %1</source>
-        <translation>Ця модифікація несумісна з %1</translation>
+        <translation type="vanished">Ця модифікація несумісна з %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="236"/>
         <source>Mod is already disabled</source>
-        <translation>Модифікацію вже вимкнено</translation>
+        <translation type="vanished">Модифікацію вже вимкнено</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="246"/>
         <source>This mod is needed to run %1</source>
-        <translation>Ця модифікація необхідна для запуску %1</translation>
+        <translation type="vanished">Ця модифікація необхідна для запуску %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="288"/>
         <source>Mod archive is missing</source>
-        <translation>Архів з модифікацією відсутній</translation>
+        <translation type="vanished">Архів з модифікацією відсутній</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="291"/>
         <source>Mod with such name is already installed</source>
-        <translation>Модифікацію з такою назвою вже встановлено</translation>
+        <translation type="vanished">Модифікацію з такою назвою вже встановлено</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="296"/>
         <source>Mod archive is invalid or corrupted</source>
-        <translation>Архів модифікації непридатний або пошкоджений</translation>
+        <translation type="vanished">Архів модифікації непридатний або пошкоджений</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="322"/>
         <source>Failed to extract mod data</source>
-        <translation>Не вдалося видобути дані модифікації</translation>
+        <translation type="vanished">Не вдалося видобути дані модифікації</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="350"/>
         <source>Data with this mod was not found</source>
-        <translation>Дані з цією модифікацією не знайдено</translation>
+        <translation type="vanished">Дані з цією модифікацією не знайдено</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodmanager.cpp" line="354"/>
         <source>Mod is located in protected directory, please remove it manually:
 </source>
-        <translation>Модифікація знаходиться в захищеному каталозі, будь ласка, видаліть її вручну:
+        <translation type="vanished">Модифікація знаходиться в захищеному каталозі, будь ласка, видаліть її вручну:
 </translation>
     </message>
 </context>
@@ -1093,29 +1062,26 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use
 <context>
     <name>File size</name>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="21"/>
         <source>%1 B</source>
-        <translation>%1 Б</translation>
+        <translation type="vanished">%1 Б</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="22"/>
         <source>%1 KiB</source>
-        <translation>%1 КіБ</translation>
+        <translation type="vanished">%1 КіБ</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="23"/>
+        <location filename="../modManager/modstate.cpp" line="140"/>
+        <location filename="../modManager/modstatemodel.cpp" line="95"/>
         <source>%1 MiB</source>
         <translation>%1 МіБ</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="24"/>
         <source>%1 GiB</source>
-        <translation>%1 ГіБ</translation>
+        <translation type="vanished">%1 ГіБ</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="25"/>
         <source>%1 TiB</source>
-        <translation>%1 ТіБ</translation>
+        <translation type="vanished">%1 ТіБ</translation>
     </message>
 </context>
 <context>
@@ -1565,16 +1531,209 @@ error reason: </source>
 <context>
     <name>ModFields</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="169"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="190"/>
         <source>Name</source>
         <translation>Назва</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="172"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="193"/>
         <source>Type</source>
         <translation>Тип</translation>
     </message>
 </context>
+<context>
+    <name>ModStateController</name>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="126"/>
+        <source>Can not install submod</source>
+        <translation type="unfinished">Неможливо встановити вкладену модифікацію</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="129"/>
+        <source>Mod is already installed</source>
+        <translation type="unfinished">Модифікація вже встановлена</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="138"/>
+        <source>Can not uninstall submod</source>
+        <translation type="unfinished">Неможливо видалити вкладену модифікацію</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="141"/>
+        <source>Mod is not installed</source>
+        <translation type="unfinished">Модифікація не встановлена</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="151"/>
+        <source>Mod is already enabled</source>
+        <translation type="unfinished">Модифікація вже увімкнена</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="154"/>
+        <location filename="../modManager/modstatecontroller.cpp" line="180"/>
+        <source>Mod must be installed first</source>
+        <translation type="unfinished">Спочатку потрібно встановити модифікацію</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="158"/>
+        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
+        <translation type="unfinished">Модифікація несумісна, будь ласка, оновіть VCMI та перевірте останні версії модифікацій</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="161"/>
+        <source>Can not enable translation mod for a different language!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="166"/>
+        <source>Required mod %1 is missing</source>
+        <translation type="unfinished">Необхідна модифікація %1 відсутня</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="177"/>
+        <source>Mod is already disabled</source>
+        <translation type="unfinished">Модифікацію вже вимкнено</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="190"/>
+        <source>Mod archive is missing</source>
+        <translation type="unfinished">Архів з модифікацією відсутній</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="193"/>
+        <source>Mod with such name is already installed</source>
+        <translation type="unfinished">Модифікацію з такою назвою вже встановлено</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="198"/>
+        <source>Mod archive is invalid or corrupted</source>
+        <translation type="unfinished">Архів модифікації непридатний або пошкоджений</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="224"/>
+        <source>Failed to extract mod data</source>
+        <translation type="unfinished">Не вдалося видобути дані модифікації</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="250"/>
+        <source>Data with this mod was not found</source>
+        <translation type="unfinished">Дані з цією модифікацією не знайдено</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="254"/>
+        <source>Mod is located in protected directory, please remove it manually:
+</source>
+        <translation type="unfinished">Модифікація знаходиться в захищеному каталозі, будь ласка, видаліть її вручну:
+</translation>
+    </message>
+</context>
+<context>
+    <name>ModStateItemModel</name>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="36"/>
+        <source>Translation</source>
+        <translation type="unfinished">Переклад</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="37"/>
+        <source>Town</source>
+        <translation type="unfinished">Місто</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="38"/>
+        <source>Test</source>
+        <translation type="unfinished">Тестування</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="39"/>
+        <source>Templates</source>
+        <translation type="unfinished">Шаблони</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="40"/>
+        <source>Spells</source>
+        <translation type="unfinished">Закляття</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="41"/>
+        <source>Music</source>
+        <translation type="unfinished">Музика</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="42"/>
+        <source>Maps</source>
+        <translation type="unfinished">Мапи</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="43"/>
+        <source>Sounds</source>
+        <translation type="unfinished">Звуки</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="44"/>
+        <source>Skills</source>
+        <translation type="unfinished">Вміння</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="45"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="63"/>
+        <source>Other</source>
+        <translation type="unfinished">Інше</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="46"/>
+        <source>Objects</source>
+        <translation type="unfinished">Об&apos;єкти</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="47"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="48"/>
+        <source>Mechanics</source>
+        <translation type="unfinished">Механіки</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="49"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="50"/>
+        <source>Interface</source>
+        <translation type="unfinished">Інтерфейс</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="51"/>
+        <source>Heroes</source>
+        <translation type="unfinished">Герої</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="52"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="53"/>
+        <source>Graphical</source>
+        <translation type="unfinished">Графічний</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
+        <source>Expansion</source>
+        <translation type="unfinished">Розширення</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Істоти</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="56"/>
+        <source>Compatibility</source>
+        <translation type="unfinished">Сумісність</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
+        <source>Artifacts</source>
+        <translation type="unfinished">Артефакти</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="58"/>
+        <source>AI</source>
+        <translation type="unfinished">ШІ</translation>
+    </message>
+</context>
 <context>
     <name>QObject</name>
     <message>

+ 280 - 218
launcher/translation/vietnamese.ts

@@ -90,108 +90,80 @@
 <context>
     <name>CModListModel</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="42"/>
         <source>Translation</source>
-        <translation>Bản dịch</translation>
+        <translation type="vanished">Bản dịch</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="43"/>
         <source>Town</source>
-        <translation>Thành phố</translation>
+        <translation type="vanished">Thành phố</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="44"/>
         <source>Test</source>
-        <translation>Kiểm tra</translation>
+        <translation type="vanished">Kiểm tra</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="45"/>
         <source>Templates</source>
-        <translation>Mẫu</translation>
+        <translation type="vanished">Mẫu</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="46"/>
         <source>Spells</source>
-        <translation>Phép</translation>
+        <translation type="vanished">Phép</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="47"/>
         <source>Music</source>
-        <translation>Nhạc</translation>
+        <translation type="vanished">Nhạc</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="48"/>
-        <source>Maps</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="49"/>
         <source>Sounds</source>
-        <translation>Âm thanh</translation>
+        <translation type="vanished">Âm thanh</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="50"/>
         <source>Skills</source>
-        <translation>Kĩ năng</translation>
+        <translation type="vanished">Kĩ năng</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="51"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="69"/>
         <source>Other</source>
-        <translation>Khác</translation>
+        <translation type="vanished">Khác</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="52"/>
         <source>Objects</source>
-        <translation>Đối tượng</translation>
+        <translation type="vanished">Đối tượng</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="53"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="54"/>
         <source>Mechanics</source>
-        <translation>Cơ chế</translation>
+        <translation type="vanished">Cơ chế</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="55"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="56"/>
         <source>Interface</source>
-        <translation>Giao diện</translation>
+        <translation type="vanished">Giao diện</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="57"/>
         <source>Heroes</source>
-        <translation>Tướng</translation>
+        <translation type="vanished">Tướng</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="58"/>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="59"/>
         <source>Graphical</source>
-        <translation>Đồ họa</translation>
+        <translation type="vanished">Đồ họa</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="60"/>
         <source>Expansion</source>
-        <translation>Bản mở rộng</translation>
+        <translation type="vanished">Bản mở rộng</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="61"/>
         <source>Creatures</source>
-        <translation>Quái</translation>
+        <translation type="vanished">Quái</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="62"/>
         <source>Compatibility</source>
-        <translation type="unfinished">Tương thích</translation>
+        <translation type="obsolete">Tương thích</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="63"/>
         <source>Artifacts</source>
-        <translation>Vật phẩm</translation>
+        <translation type="vanished">Vật phẩm</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="64"/>
         <source>AI</source>
-        <translation>Trí tuệ nhân tạo</translation>
+        <translation type="vanished">Trí tuệ nhân tạo</translation>
     </message>
 </context>
 <context>
@@ -233,7 +205,7 @@
     </message>
     <message>
         <location filename="../modManager/cmodlistview_moc.ui" line="163"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="395"/>
         <source>Description</source>
         <translation>Mô tả</translation>
     </message>
@@ -293,189 +265,202 @@
         <translation>Hủy</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="289"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="317"/>
         <source>Mod name</source>
         <translation>Tên bản sửa đổi</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="290"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="320"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
         <source>Installed version</source>
         <translation>Phiên bản cài đặt</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="291"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="328"/>
         <source>Latest version</source>
         <translation>Phiên bản mới nhất</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="294"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="332"/>
         <source>Size</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="296"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="335"/>
         <source>Download size</source>
         <translation>Kích thước tải về</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="337"/>
         <source>Authors</source>
         <translation>Tác giả</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="301"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="340"/>
         <source>License</source>
         <translation>Giấy phép</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="304"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="343"/>
         <source>Contact</source>
         <translation>Liên hệ</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="313"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
         <source>Compatibility</source>
         <translation>Tương thích</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="315"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="354"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>Required VCMI version</source>
         <translation>Cần phiên bản VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>Supported VCMI version</source>
         <translation>Hỗ trợ phiên bản VCMI</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="321"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>please upgrade mod</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="193"/>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="824"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="189"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="827"/>
         <source>mods repository index</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="323"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
         <source>or newer</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="326"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="365"/>
         <source>Supported VCMI versions</source>
         <translation>Phiên bản VCMI hỗ trợ</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="350"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="381"/>
         <source>Languages</source>
         <translation>Ngôn ngữ</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="352"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="393"/>
         <source>Required mods</source>
         <translation>Cần các bản sửa đổi</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="353"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="394"/>
         <source>Conflicting mods</source>
         <translation>Bản sửa đổi không tương thích</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="358"/>
         <source>This mod can not be installed or enabled because the following dependencies are not present</source>
-        <translation>Bản sửa đổi này không thể cài đặt hoặc kích hoạt do thiếu các bản sửa đổi sau</translation>
+        <translation type="vanished">Bản sửa đổi này không thể cài đặt hoặc kích hoạt do thiếu các bản sửa đổi sau</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="359"/>
         <source>This mod can not be enabled because the following mods are incompatible with it</source>
-        <translation>Bản sửa đổi này không thể kích hoạt do không tương thích các bản sửa đổi sau</translation>
+        <translation type="vanished">Bản sửa đổi này không thể kích hoạt do không tương thích các bản sửa đổi sau</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="360"/>
         <source>This mod cannot be disabled because it is required by the following mods</source>
-        <translation>Bản sửa đổi này không thể tắt do cần thiết cho các bản sửa đổi sau</translation>
+        <translation type="vanished">Bản sửa đổi này không thể tắt do cần thiết cho các bản sửa đổi sau</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="361"/>
         <source>This mod cannot be uninstalled or updated because it is required by the following mods</source>
-        <translation>Bản sửa đổi này không thể gỡ bỏ hoặc nâng cấp do cần thiết cho các bản sửa đổi sau</translation>
+        <translation type="vanished">Bản sửa đổi này không thể gỡ bỏ hoặc nâng cấp do cần thiết cho các bản sửa đổi sau</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="362"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="399"/>
+        <source>This mod cannot be enabled because it translates into a different language.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="400"/>
+        <source>This mod can not be enabled because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="401"/>
+        <source>This mod can not be installed because the following dependencies are not present</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="402"/>
         <source>This is a submod and it cannot be installed or uninstalled separately from its parent mod</source>
         <translation>Đây là bản con, không thể cài đặt hoặc gỡ bỏ tách biệt với bản cha</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="377"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="421"/>
         <source>Notes</source>
         <translation>Ghi chú</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="643"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
         <source>All supported files</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="644"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
         <source>Maps</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="645"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
         <source>Campaigns</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="646"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
         <source>Configs</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="647"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="649"/>
         <source>Mods</source>
         <translation type="unfinished">Bản sửa đổi</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="648"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
         <source>Gog files</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="650"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
         <source>All files (*.*)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="652"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
         <source>Select files (configs, mods, maps, campaigns, gog files) to install...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Replace config file?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="677"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="679"/>
         <source>Do you want to replace %1?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="720"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="723"/>
         <source>Downloading %1. %p% (%v MB out of %m MB) finished</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="745"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="748"/>
         <source>Download failed</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="746"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="749"/>
         <source>Unable to download all files.
 
 Encountered errors:
@@ -484,145 +469,49 @@ Encountered errors:
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="747"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="750"/>
         <source>
 
 Install successfully downloaded?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="852"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="865"/>
         <source>Installing chronicles</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="925"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="927"/>
         <source>Installing mod %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="994"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="971"/>
         <source>Operation failed</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="995"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="972"/>
         <source>Encountered errors:
 </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1030"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1007"/>
         <source>screenshots</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1036"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1013"/>
         <source>Screenshot %1</source>
         <translation>Hình ảnh %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="284"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="312"/>
         <source>Mod is incompatible</source>
         <translation>Bản sửa đổi này không tương thích</translation>
     </message>
 </context>
-<context>
-    <name>CModManager</name>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="168"/>
-        <source>Can not install submod</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="171"/>
-        <source>Mod is already installed</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="180"/>
-        <source>Can not uninstall submod</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="183"/>
-        <source>Mod is not installed</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="193"/>
-        <source>Mod is already enabled</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="196"/>
-        <location filename="../modManager/cmodmanager.cpp" line="239"/>
-        <source>Mod must be installed first</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="200"/>
-        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="205"/>
-        <source>Required mod %1 is missing</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="210"/>
-        <source>Required mod %1 is not enabled</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="219"/>
-        <location filename="../modManager/cmodmanager.cpp" line="226"/>
-        <source>This mod conflicts with %1</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="236"/>
-        <source>Mod is already disabled</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="246"/>
-        <source>This mod is needed to run %1</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="288"/>
-        <source>Mod archive is missing</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="291"/>
-        <source>Mod with such name is already installed</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="296"/>
-        <source>Mod archive is invalid or corrupted</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="322"/>
-        <source>Failed to extract mod data</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="350"/>
-        <source>Data with this mod was not found</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodmanager.cpp" line="354"/>
-        <source>Mod is located in protected directory, please remove it manually:
-</source>
-        <translation type="unfinished"></translation>
-    </message>
-</context>
 <context>
     <name>CSettingsView</name>
     <message>
@@ -1085,30 +974,11 @@ Toàn màn hình riêng biệt - Trò chơi chạy toàn màn hình và dùng đ
 <context>
     <name>File size</name>
     <message>
-        <location filename="../modManager/cmodlist.cpp" line="21"/>
-        <source>%1 B</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="22"/>
-        <source>%1 KiB</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="23"/>
+        <location filename="../modManager/modstate.cpp" line="140"/>
+        <location filename="../modManager/modstatemodel.cpp" line="95"/>
         <source>%1 MiB</source>
         <translation type="unfinished"></translation>
     </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="24"/>
-        <source>%1 GiB</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../modManager/cmodlist.cpp" line="25"/>
-        <source>%1 TiB</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>FirstLaunchView</name>
@@ -1552,16 +1422,208 @@ error reason: </source>
 <context>
     <name>ModFields</name>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="169"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="190"/>
         <source>Name</source>
         <translation type="unfinished">Tên</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistmodel_moc.cpp" line="172"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="193"/>
         <source>Type</source>
         <translation type="unfinished">Loại</translation>
     </message>
 </context>
+<context>
+    <name>ModStateController</name>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="126"/>
+        <source>Can not install submod</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="129"/>
+        <source>Mod is already installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="138"/>
+        <source>Can not uninstall submod</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="141"/>
+        <source>Mod is not installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="151"/>
+        <source>Mod is already enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="154"/>
+        <location filename="../modManager/modstatecontroller.cpp" line="180"/>
+        <source>Mod must be installed first</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="158"/>
+        <source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="161"/>
+        <source>Can not enable translation mod for a different language!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="166"/>
+        <source>Required mod %1 is missing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="177"/>
+        <source>Mod is already disabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="190"/>
+        <source>Mod archive is missing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="193"/>
+        <source>Mod with such name is already installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="198"/>
+        <source>Mod archive is invalid or corrupted</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="224"/>
+        <source>Failed to extract mod data</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="250"/>
+        <source>Data with this mod was not found</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstatecontroller.cpp" line="254"/>
+        <source>Mod is located in protected directory, please remove it manually:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>ModStateItemModel</name>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="36"/>
+        <source>Translation</source>
+        <translation type="unfinished">Bản dịch</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="37"/>
+        <source>Town</source>
+        <translation type="unfinished">Thành phố</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="38"/>
+        <source>Test</source>
+        <translation type="unfinished">Kiểm tra</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="39"/>
+        <source>Templates</source>
+        <translation type="unfinished">Mẫu</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="40"/>
+        <source>Spells</source>
+        <translation type="unfinished">Phép</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="41"/>
+        <source>Music</source>
+        <translation type="unfinished">Nhạc</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="42"/>
+        <source>Maps</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="43"/>
+        <source>Sounds</source>
+        <translation type="unfinished">Âm thanh</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="44"/>
+        <source>Skills</source>
+        <translation type="unfinished">Kĩ năng</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="45"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="63"/>
+        <source>Other</source>
+        <translation type="unfinished">Khác</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="46"/>
+        <source>Objects</source>
+        <translation type="unfinished">Đối tượng</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="47"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="48"/>
+        <source>Mechanics</source>
+        <translation type="unfinished">Cơ chế</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="49"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="50"/>
+        <source>Interface</source>
+        <translation type="unfinished">Giao diện</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="51"/>
+        <source>Heroes</source>
+        <translation type="unfinished">Tướng</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="52"/>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="53"/>
+        <source>Graphical</source>
+        <translation type="unfinished">Đồ họa</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
+        <source>Expansion</source>
+        <translation type="unfinished">Bản mở rộng</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Quái</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="56"/>
+        <source>Compatibility</source>
+        <translation type="unfinished">Tương thích</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
+        <source>Artifacts</source>
+        <translation type="unfinished">Vật phẩm</translation>
+    </message>
+    <message>
+        <location filename="../modManager/modstateitemmodel_moc.cpp" line="58"/>
+        <source>AI</source>
+        <translation type="unfinished">Trí tuệ nhân tạo</translation>
+    </message>
+</context>
 <context>
     <name>QObject</name>
     <message>

+ 4 - 2
lib/CMakeLists.txt

@@ -157,10 +157,11 @@ set(lib_MAIN_SRCS
 
 	modding/ActiveModsInSaveList.cpp
 	modding/CModHandler.cpp
-	modding/CModInfo.cpp
 	modding/CModVersion.cpp
 	modding/ContentTypeHandler.cpp
 	modding/IdentifierStorage.cpp
+	modding/ModDescription.cpp
+	modding/ModManager.cpp
 	modding/ModUtility.cpp
 	modding/ModVerificationInfo.cpp
 
@@ -547,11 +548,12 @@ set(lib_MAIN_HEADERS
 
 	modding/ActiveModsInSaveList.h
 	modding/CModHandler.h
-	modding/CModInfo.h
 	modding/CModVersion.h
 	modding/ContentTypeHandler.h
 	modding/IdentifierStorage.h
+	modding/ModDescription.h
 	modding/ModIncompatibility.h
+	modding/ModManager.h
 	modding/ModScope.h
 	modding/ModUtility.h
 	modding/ModVerificationInfo.h

+ 0 - 1
lib/IGameCallback.cpp

@@ -41,7 +41,6 @@
 #include "gameState/QuestInfo.h"
 #include "mapping/CMap.h"
 #include "modding/CModHandler.h"
-#include "modding/CModInfo.h"
 #include "modding/IdentifierStorage.h"
 #include "modding/CModVersion.h"
 #include "modding/ActiveModsInSaveList.h"

+ 22 - 34
lib/VCMI_Lib.cpp

@@ -26,7 +26,6 @@
 #include "entities/hero/CHeroHandler.h"
 #include "texts/CGeneralTextHandler.h"
 #include "modding/CModHandler.h"
-#include "modding/CModInfo.h"
 #include "modding/IdentifierStorage.h"
 #include "modding/CModVersion.h"
 #include "IGameEventsReceiver.h"
@@ -157,55 +156,44 @@ void LibClasses::loadModFilesystem()
 	CStopWatch loadTime;
 	modh = std::make_unique<CModHandler>();
 	identifiersHandler = std::make_unique<CIdentifierStorage>();
-	modh->loadMods();
 	logGlobal->info("\tMod handler: %d ms", loadTime.getDiff());
 
 	modh->loadModFilesystems();
 	logGlobal->info("\tMod filesystems: %d ms", loadTime.getDiff());
 }
 
-static void logHandlerLoaded(const std::string & name, CStopWatch & timer)
-{
-	logGlobal->info("\t\t %s handler: %d ms", name, timer.getDiff());
-}
-
-template <class Handler> void createHandler(std::shared_ptr<Handler> & handler, const std::string &name, CStopWatch &timer)
+template <class Handler> void createHandler(std::shared_ptr<Handler> & handler)
 {
 	handler = std::make_shared<Handler>();
-	logHandlerLoaded(name, timer);
 }
 
 void LibClasses::init(bool onlyEssential)
 {
-	CStopWatch pomtime;
-	CStopWatch totalTime;
-
-	createHandler(settingsHandler, "Game Settings", pomtime);
+	createHandler(settingsHandler);
 	modh->initializeConfig();
 
-	createHandler(generaltexth, "General text", pomtime);
-	createHandler(bth, "Bonus type", pomtime);
-	createHandler(roadTypeHandler, "Road", pomtime);
-	createHandler(riverTypeHandler, "River", pomtime);
-	createHandler(terrainTypeHandler, "Terrain", pomtime);
-	createHandler(heroh, "Hero", pomtime);
-	createHandler(heroclassesh, "Hero classes", pomtime);
-	createHandler(arth, "Artifact", pomtime);
-	createHandler(creh, "Creature", pomtime);
-	createHandler(townh, "Town", pomtime);
-	createHandler(biomeHandler, "Obstacle set", pomtime);
-	createHandler(objh, "Object", pomtime);
-	createHandler(objtypeh, "Object types information", pomtime);
-	createHandler(spellh, "Spell", pomtime);
-	createHandler(skillh, "Skill", pomtime);
-	createHandler(terviewh, "Terrain view pattern", pomtime);
-	createHandler(tplh, "Template", pomtime); //templates need already resolved identifiers (refactor?)
+	createHandler(generaltexth);
+	createHandler(bth);
+	createHandler(roadTypeHandler);
+	createHandler(riverTypeHandler);
+	createHandler(terrainTypeHandler);
+	createHandler(heroh);
+	createHandler(heroclassesh);
+	createHandler(arth);
+	createHandler(creh);
+	createHandler(townh);
+	createHandler(biomeHandler);
+	createHandler(objh);
+	createHandler(objtypeh);
+	createHandler(spellh);
+	createHandler(skillh);
+	createHandler(terviewh);
+	createHandler(tplh); //templates need already resolved identifiers (refactor?)
 #if SCRIPTING_ENABLED
-	createHandler(scriptHandler, "Script", pomtime);
+	createHandler(scriptHandler);
 #endif
-	createHandler(battlefieldsHandler, "Battlefields", pomtime);
-	createHandler(obstacleHandler, "Obstacles", pomtime);
-	logGlobal->info("\tInitializing handlers: %d ms", totalTime.getDiff());
+	createHandler(battlefieldsHandler);
+	createHandler(obstacleHandler);
 
 	modh->load();
 	modh->afterLoad(onlyEssential);

+ 1 - 0
lib/filesystem/Filesystem.cpp

@@ -212,6 +212,7 @@ ISimpleResourceLoader * CResourceHandler::get()
 
 ISimpleResourceLoader * CResourceHandler::get(const std::string & identifier)
 {
+	assert(knownLoaders.count(identifier));
 	return knownLoaders.at(identifier);
 }
 

+ 1 - 1
lib/json/JsonNode.h

@@ -187,7 +187,7 @@ void convert(std::map<std::string, Type> & value, const JsonNode & node)
 {
 	value.clear();
 	for(const JsonMap::value_type & entry : node.Struct())
-		value.insert(entry.first, entry.second.convertTo<Type>());
+		value.emplace(entry.first, entry.second.convertTo<Type>());
 }
 
 template<typename Type>

+ 1 - 1
lib/mapObjectConstructors/CObjectClassesHandler.cpp

@@ -523,7 +523,7 @@ void CObjectClassesHandler::afterLoadFinalization()
 
 			obj->afterLoadFinalization();
 			if(obj->getTemplates().empty())
-				logGlobal->warn("No templates found for %s:%s", entry->getJsonKey(), obj->getJsonKey());
+				logMod->debug("No templates found for %s:%s", entry->getJsonKey(), obj->getJsonKey());
 		}
 	}
 

+ 2 - 2
lib/mapObjects/ObstacleSetHandler.cpp

@@ -43,7 +43,7 @@ void ObstacleSet::removeEmptyTemplates()
 	{
 		if (tmpl->getBlockedOffsets().empty())
 		{
-			logMod->warn("Obstacle template %s blocks no tiles, removing it", tmpl->stringID);
+			logMod->debug("Obstacle template %s blocks no tiles, removing it", tmpl->stringID);
 			return true;
 		}
 		return false;
@@ -457,7 +457,7 @@ void ObstacleSetHandler::addTemplate(const std::string & scope, const std::strin
 
 	if (VLC->identifiersHandler->getIdentifier(scope, "obstacleTemplate", strippedName, true))
 	{
-		logMod->warn("Duplicate obstacle template: %s", strippedName);
+		logMod->debug("Duplicate obstacle template: %s", strippedName);
 		return;
 	}
 	else

+ 2 - 2
lib/mapping/CMapService.cpp

@@ -17,8 +17,8 @@
 #include "../filesystem/CMemoryStream.h"
 #include "../filesystem/CMemoryBuffer.h"
 #include "../modding/CModHandler.h"
+#include "../modding/ModDescription.h"
 #include "../modding/ModScope.h"
-#include "../modding/CModInfo.h"
 #include "../VCMI_Lib.h"
 
 #include "CMap.h"
@@ -99,7 +99,7 @@ ModCompatibilityInfo CMapService::verifyMapHeaderMods(const CMapHeader & map)
 		if(vstd::contains(activeMods, mapMod.first))
 		{
 			const auto & modInfo = VLC->modh->getModInfo(mapMod.first);
-			if(modInfo.getVerificationInfo().version.compatible(mapMod.second.version))
+			if(modInfo.getVersion().compatible(mapMod.second.version))
 				continue;
 		}
 		missingMods[mapMod.first] = mapMod.second;

+ 5 - 5
lib/modding/ActiveModsInSaveList.cpp

@@ -11,7 +11,7 @@
 #include "ActiveModsInSaveList.h"
 
 #include "../VCMI_Lib.h"
-#include "CModInfo.h"
+#include "ModDescription.h"
 #include "CModHandler.h"
 #include "ModIncompatibility.h"
 
@@ -21,13 +21,13 @@ std::vector<TModID> ActiveModsInSaveList::getActiveGameplayAffectingMods()
 {
 	std::vector<TModID> result;
 	for (auto const & entry : VLC->modh->getActiveMods())
-		if (VLC->modh->getModInfo(entry).checkModGameplayAffecting())
+		if (VLC->modh->getModInfo(entry).affectsGameplay())
 			result.push_back(entry);
 
 	return result;
 }
 
-const ModVerificationInfo & ActiveModsInSaveList::getVerificationInfo(TModID mod)
+ModVerificationInfo ActiveModsInSaveList::getVerificationInfo(TModID mod)
 {
 	return VLC->modh->getModInfo(mod).getVerificationInfo();
 }
@@ -44,10 +44,10 @@ void ActiveModsInSaveList::verifyActiveMods(const std::map<TModID, ModVerificati
 			missingMods.push_back(modList.at(compared.first).name);
 
 		if (compared.second == ModVerificationStatus::DISABLED)
-			missingMods.push_back(VLC->modh->getModInfo(compared.first).getVerificationInfo().name);
+			missingMods.push_back(VLC->modh->getModInfo(compared.first).getName());
 
 		if (compared.second == ModVerificationStatus::EXCESSIVE)
-			excessiveMods.push_back(VLC->modh->getModInfo(compared.first).getVerificationInfo().name);
+			excessiveMods.push_back(VLC->modh->getModInfo(compared.first).getName());
 	}
 
 	if(!missingMods.empty() || !excessiveMods.empty())

+ 5 - 2
lib/modding/ActiveModsInSaveList.h

@@ -17,7 +17,7 @@ VCMI_LIB_NAMESPACE_BEGIN
 class ActiveModsInSaveList
 {
 	std::vector<TModID> getActiveGameplayAffectingMods();
-	const ModVerificationInfo & getVerificationInfo(TModID mod);
+	ModVerificationInfo getVerificationInfo(TModID mod);
 
 	/// Checks whether provided mod list is compatible with current VLC and throws on failure
 	void verifyActiveMods(const std::map<TModID, ModVerificationInfo> & modList);
@@ -29,7 +29,10 @@ public:
 			std::vector<TModID> activeMods = getActiveGameplayAffectingMods();
 			h & activeMods;
 			for(const auto & m : activeMods)
-				h & getVerificationInfo(m);
+			{
+				ModVerificationInfo info = getVerificationInfo(m);
+				h & info;
+			}
 		}
 		else
 		{

+ 120 - 384
lib/modding/CModHandler.cpp

@@ -10,297 +10,45 @@
 #include "StdInc.h"
 #include "CModHandler.h"
 
-#include "CModInfo.h"
-#include "ModScope.h"
 #include "ContentTypeHandler.h"
 #include "IdentifierStorage.h"
-#include "ModIncompatibility.h"
+#include "ModDescription.h"
+#include "ModManager.h"
+#include "ModScope.h"
 
-#include "../CCreatureHandler.h"
 #include "../CConfigHandler.h"
-#include "../CStopWatch.h"
+#include "../CCreatureHandler.h"
 #include "../GameSettings.h"
 #include "../ScriptHandler.h"
-#include "../constants/StringConstants.h"
+#include "../VCMI_Lib.h"
 #include "../filesystem/Filesystem.h"
 #include "../json/JsonUtils.h"
-#include "../spells/CSpellHandler.h"
 #include "../texts/CGeneralTextHandler.h"
 #include "../texts/Languages.h"
-#include "../VCMI_Lib.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-static JsonNode loadModSettings(const JsonPath & path)
-{
-	if (CResourceHandler::get("local")->existsResource(ResourcePath(path)))
-	{
-		return JsonNode(path);
-	}
-	// Probably new install. Create initial configuration
-	CResourceHandler::get("local")->createResource(path.getOriginalName() + ".json");
-	return JsonNode();
-}
-
 CModHandler::CModHandler()
 	: content(std::make_shared<CContentHandler>())
-	, coreMod(std::make_unique<CModInfo>())
+	, modManager(std::make_unique<ModManager>())
 {
 }
 
 CModHandler::~CModHandler() = default;
 
-// currentList is passed by value to get current list of depending mods
-bool CModHandler::hasCircularDependency(const TModID & modID, std::set<TModID> currentList) const
-{
-	const CModInfo & mod = allMods.at(modID);
-
-	// Mod already present? We found a loop
-	if (vstd::contains(currentList, modID))
-	{
-		logMod->error("Error: Circular dependency detected! Printing dependency list:");
-		logMod->error("\t%s -> ", mod.getVerificationInfo().name);
-		return true;
-	}
-
-	currentList.insert(modID);
-
-	// recursively check every dependency of this mod
-	for(const TModID & dependency : mod.dependencies)
-	{
-		if (hasCircularDependency(dependency, currentList))
-		{
-			logMod->error("\t%s ->\n", mod.getVerificationInfo().name); // conflict detected, print dependency list
-			return true;
-		}
-	}
-	return false;
-}
-
-// Returned vector affects the resource loaders call order (see CFilesystemList::load).
-// The loaders call order matters when dependent mod overrides resources in its dependencies.
-std::vector <TModID> CModHandler::validateAndSortDependencies(std::vector <TModID> modsToResolve) const
-{
-	// Topological sort algorithm.
-	// TODO: Investigate possible ways to improve performance.
-	boost::range::sort(modsToResolve); // Sort mods per name
-	std::vector <TModID> sortedValidMods; // Vector keeps order of elements (LIFO)
-	sortedValidMods.reserve(modsToResolve.size()); // push_back calls won't cause memory reallocation
-	std::set <TModID> resolvedModIDs; // Use a set for validation for performance reason, but set does not keep order of elements
-	std::set <TModID> notResolvedModIDs(modsToResolve.begin(), modsToResolve.end()); // Use a set for validation for performance reason
-
-	// Mod is resolved if it has no dependencies or all its dependencies are already resolved
-	auto isResolved = [&](const CModInfo & mod) -> bool
-	{
-		if(mod.dependencies.size() > resolvedModIDs.size())
-			return false;
-
-		for(const TModID & dependency : mod.dependencies)
-		{
-			if(!vstd::contains(resolvedModIDs, dependency))
-				return false;
-		}
-
-		for(const TModID & softDependency : mod.softDependencies)
-		{
-			if(vstd::contains(notResolvedModIDs, softDependency))
-				return false;
-		}
-
-		for(const TModID & conflict : mod.conflicts)
-		{
-			if(vstd::contains(resolvedModIDs, conflict))
-				return false;
-		}
-		for(const TModID & reverseConflict : resolvedModIDs)
-		{
-			if (vstd::contains(allMods.at(reverseConflict).conflicts, mod.identifier))
-				return false;
-		}
-		return true;
-	};
-
-	while(true)
-	{
-		std::set <TModID> resolvedOnCurrentTreeLevel;
-		for(auto it = modsToResolve.begin(); it != modsToResolve.end();) // One iteration - one level of mods tree
-		{
-			if(isResolved(allMods.at(*it)))
-			{
-				resolvedOnCurrentTreeLevel.insert(*it); // Not to the resolvedModIDs, so current node children will be resolved on the next iteration
-				sortedValidMods.push_back(*it);
-				it = modsToResolve.erase(it);
-				continue;
-			}
-			it++;
-		}
-		if(!resolvedOnCurrentTreeLevel.empty())
-		{
-			resolvedModIDs.insert(resolvedOnCurrentTreeLevel.begin(), resolvedOnCurrentTreeLevel.end());
-			for(const auto & it : resolvedOnCurrentTreeLevel)
-				notResolvedModIDs.erase(it);
-			continue;
-		}
-		// If there are no valid mods on the current mods tree level, no more mod can be resolved, should be ended.
-		break;
-	}
-
-	modLoadErrors = std::make_unique<MetaString>();
-
-	auto addErrorMessage = [this](const std::string & textID, const std::string & brokenModID, const std::string & missingModID)
-	{
-		modLoadErrors->appendTextID(textID);
-
-		if (allMods.count(brokenModID))
-			modLoadErrors->replaceRawString(allMods.at(brokenModID).getVerificationInfo().name);
-		else
-			modLoadErrors->replaceRawString(brokenModID);
-
-		if (allMods.count(missingModID))
-			modLoadErrors->replaceRawString(allMods.at(missingModID).getVerificationInfo().name);
-		else
-			modLoadErrors->replaceRawString(missingModID);
-
-	};
-
-	// Left mods have unresolved dependencies, output all to log.
-	for(const auto & brokenModID : modsToResolve)
-	{
-		const CModInfo & brokenMod = allMods.at(brokenModID);
-		bool showErrorMessage = false;
-		for(const TModID & dependency : brokenMod.dependencies)
-		{
-			if(!vstd::contains(resolvedModIDs, dependency) && brokenMod.config["modType"].String() != "Compatibility")
-			{
-				addErrorMessage("vcmi.server.errors.modNoDependency", brokenModID, dependency);
-				showErrorMessage = true;
-			}
-		}
-		for(const TModID & conflict : brokenMod.conflicts)
-		{
-			if(vstd::contains(resolvedModIDs, conflict))
-			{
-				addErrorMessage("vcmi.server.errors.modConflict", brokenModID, conflict);
-				showErrorMessage = true;
-			}
-		}
-		for(const TModID & reverseConflict : resolvedModIDs)
-		{
-			if (vstd::contains(allMods.at(reverseConflict).conflicts, brokenModID))
-			{
-				addErrorMessage("vcmi.server.errors.modConflict", brokenModID, reverseConflict);
-				showErrorMessage = true;
-			}
-		}
-
-		// some mods may in a (soft) dependency loop.
-		if(!showErrorMessage && brokenMod.config["modType"].String() != "Compatibility")
-		{
-			modLoadErrors->appendTextID("vcmi.server.errors.modDependencyLoop");
-			if (allMods.count(brokenModID))
-				modLoadErrors->replaceRawString(allMods.at(brokenModID).getVerificationInfo().name);
-			else
-				modLoadErrors->replaceRawString(brokenModID);
-		}
-
-	}
-	return sortedValidMods;
-}
-
-std::vector<std::string> CModHandler::getModList(const std::string & path) const
-{
-	std::string modDir = boost::to_upper_copy(path + "MODS/");
-	size_t depth = boost::range::count(modDir, '/');
-
-	auto list = CResourceHandler::get("initial")->getFilteredFiles([&](const ResourcePath & id) ->  bool
-	{
-		if (id.getType() != EResType::DIRECTORY)
-			return false;
-		if (!boost::algorithm::starts_with(id.getName(), modDir))
-			return false;
-		if (boost::range::count(id.getName(), '/') != depth )
-			return false;
-		return true;
-	});
-
-	//storage for found mods
-	std::vector<std::string> foundMods;
-	for(const auto & entry : list)
-	{
-		std::string name = entry.getName();
-		name.erase(0, modDir.size()); //Remove path prefix
-
-		if (!name.empty())
-			foundMods.push_back(name);
-	}
-	return foundMods;
-}
-
-
-
-void CModHandler::loadMods(const std::string & path, const std::string & parent, const JsonNode & modSettings, bool enableMods)
-{
-	for(const std::string & modName : getModList(path))
-		loadOneMod(modName, parent, modSettings, enableMods);
-}
-
-void CModHandler::loadOneMod(std::string modName, const std::string & parent, const JsonNode & modSettings, bool enableMods)
-{
-	boost::to_lower(modName);
-	std::string modFullName = parent.empty() ? modName : parent + '.' + modName;
-
-	if ( ModScope::isScopeReserved(modFullName))
-	{
-		logMod->error("Can not load mod %s - this name is reserved for internal use!", modFullName);
-		return;
-	}
-
-	if(CResourceHandler::get("initial")->existsResource(CModInfo::getModFile(modFullName)))
-	{
-		CModInfo mod(modFullName, modSettings[modName], JsonNode(CModInfo::getModFile(modFullName)));
-		if (!parent.empty()) // this is submod, add parent to dependencies
-			mod.dependencies.insert(parent);
-
-		allMods[modFullName] = mod;
-		if (mod.isEnabled() && enableMods)
-			activeMods.push_back(modFullName);
-
-		loadMods(CModInfo::getModDir(modFullName) + '/', modFullName, modSettings[modName]["mods"], enableMods && mod.isEnabled());
-	}
-}
-
-void CModHandler::loadMods()
-{
-	JsonNode modConfig;
-
-	modConfig = loadModSettings(JsonPath::builtin("config/modSettings.json"));
-	loadMods("", "", modConfig["activeMods"], true);
-
-	coreMod = std::make_unique<CModInfo>(ModScope::scopeBuiltin(), modConfig[ModScope::scopeBuiltin()], JsonNode(JsonPath::builtin("config/gameConfig.json")));
-}
-
 std::vector<std::string> CModHandler::getAllMods() const
 {
-	std::vector<std::string> modlist;
-	modlist.reserve(allMods.size());
-	for (auto & entry : allMods)
-		modlist.push_back(entry.first);
-	return modlist;
+	return modManager->getAllMods();
 }
 
-std::vector<std::string> CModHandler::getActiveMods() const
+const std::vector<std::string> & CModHandler::getActiveMods() const
 {
-	return activeMods;
+	return modManager->getActiveMods();
 }
 
-std::string CModHandler::getModLoadErrors() const
+const ModDescription & CModHandler::getModInfo(const TModID & modId) const
 {
-	return modLoadErrors->toString();
-}
-
-const CModInfo & CModHandler::getModInfo(const TModID & modId) const
-{
-	return allMods.at(modId);
+	return modManager->getModDescription(modId);
 }
 
 static JsonNode genDefaultFS()
@@ -315,86 +63,67 @@ static JsonNode genDefaultFS()
 	return defaultFS;
 }
 
-static ISimpleResourceLoader * genModFilesystem(const std::string & modName, const JsonNode & conf)
+static std::string getModDirectory(const TModID & modName)
 {
-	static const JsonNode defaultFS = genDefaultFS();
-
-	if (!conf["filesystem"].isNull())
-		return CResourceHandler::createFileSystem(CModInfo::getModDir(modName), conf["filesystem"]);
-	else
-		return CResourceHandler::createFileSystem(CModInfo::getModDir(modName), defaultFS);
+	std::string result = modName;
+	boost::to_upper(result);
+	boost::algorithm::replace_all(result, ".", "/MODS/");
+	return "MODS/" + result;
 }
 
-static ui32 calculateModChecksum(const std::string & modName, ISimpleResourceLoader * filesystem)
+static ISimpleResourceLoader * genModFilesystem(const std::string & modName, const JsonNode & conf)
 {
-	boost::crc_32_type modChecksum;
-	// first - add current VCMI version into checksum to force re-validation on VCMI updates
-	modChecksum.process_bytes(reinterpret_cast<const void*>(GameConstants::VCMI_VERSION.data()), GameConstants::VCMI_VERSION.size());
-
-	// second - add mod.json into checksum because filesystem does not contains this file
-	// FIXME: remove workaround for core mod
-	if (modName != ModScope::scopeBuiltin())
-	{
-		auto modConfFile = CModInfo::getModFile(modName);
-		ui32 configChecksum = CResourceHandler::get("initial")->load(modConfFile)->calculateCRC32();
-		modChecksum.process_bytes(reinterpret_cast<const void *>(&configChecksum), sizeof(configChecksum));
-	}
-	// third - add all detected text files from this mod into checksum
-	auto files = filesystem->getFilteredFiles([](const ResourcePath & resID)
-	{
-		return (resID.getType() == EResType::TEXT || resID.getType() == EResType::JSON) &&
-			   ( boost::starts_with(resID.getName(), "DATA") || boost::starts_with(resID.getName(), "CONFIG"));
-	});
+	static const JsonNode defaultFS = genDefaultFS();
 
-	for (const ResourcePath & file : files)
-	{
-		ui32 fileChecksum = filesystem->load(file)->calculateCRC32();
-		modChecksum.process_bytes(reinterpret_cast<const void *>(&fileChecksum), sizeof(fileChecksum));
-	}
-	return modChecksum.checksum();
+	if (!conf.isNull())
+		return CResourceHandler::createFileSystem(getModDirectory(modName), conf);
+	else
+		return CResourceHandler::createFileSystem(getModDirectory(modName), defaultFS);
 }
 
 void CModHandler::loadModFilesystems()
 {
 	CGeneralTextHandler::detectInstallParameters();
 
-	activeMods = validateAndSortDependencies(activeMods);
+	const auto & activeMods = modManager->getActiveMods();
 
-	coreMod->updateChecksum(calculateModChecksum(ModScope::scopeBuiltin(), CResourceHandler::get(ModScope::scopeBuiltin())));
+	std::map<TModID, ISimpleResourceLoader *> modFilesystems;
 
-	std::map<std::string, ISimpleResourceLoader *> modFilesystems;
-
-	for(std::string & modName : activeMods)
-		modFilesystems[modName] = genModFilesystem(modName, allMods[modName].config);
+	for(const TModID & modName : activeMods)
+		modFilesystems[modName] = genModFilesystem(modName, getModInfo(modName).getFilesystemConfig());
 
-	for(std::string & modName : activeMods)
-		CResourceHandler::addFilesystem("data", modName, modFilesystems[modName]);
+	for(const TModID & modName : activeMods)
+		if (modName != "core") // virtual mod 'core' has no filesystem on its own - shared with base install
+			CResourceHandler::addFilesystem("data", modName, modFilesystems[modName]);
 
 	if (settings["mods"]["validation"].String() == "full")
+		checkModFilesystemsConflicts(modFilesystems);
+}
+
+void CModHandler::checkModFilesystemsConflicts(const std::map<TModID, ISimpleResourceLoader *> & modFilesystems)
+{
+	for(const auto & [leftName, leftFilesystem] : modFilesystems)
 	{
-		for(std::string & leftModName : activeMods)
+		for(const auto & [rightName, rightFilesystem] : modFilesystems)
 		{
-			for(std::string & rightModName : activeMods)
-			{
-				if (leftModName == rightModName)
-					continue;
+			if (leftName == rightName)
+				continue;
 
-				if (getModDependencies(leftModName).count(rightModName) || getModDependencies(rightModName).count(leftModName))
-					continue;
+			if (getModDependencies(leftName).count(rightName) || getModDependencies(rightName).count(leftName))
+				continue;
 
-				if (getModSoftDependencies(leftModName).count(rightModName) || getModSoftDependencies(rightModName).count(leftModName))
-					continue;
+			if (getModSoftDependencies(leftName).count(rightName) || getModSoftDependencies(rightName).count(leftName))
+				continue;
 
-				const auto & filter = [](const ResourcePath &path){return path.getType() != EResType::DIRECTORY && path.getType() != EResType::JSON;};
+			const auto & filter = [](const ResourcePath &path){return path.getType() != EResType::DIRECTORY && path.getType() != EResType::JSON;};
 
-				std::unordered_set<ResourcePath> leftResources = modFilesystems[leftModName]->getFilteredFiles(filter);
-				std::unordered_set<ResourcePath> rightResources = modFilesystems[rightModName]->getFilteredFiles(filter);
+			std::unordered_set<ResourcePath> leftResources = leftFilesystem->getFilteredFiles(filter);
+			std::unordered_set<ResourcePath> rightResources = rightFilesystem->getFilteredFiles(filter);
 
-				for (auto const & leftFile : leftResources)
-				{
-					if (rightResources.count(leftFile))
-						logMod->warn("Potential confict detected between '%s' and '%s': both mods add file '%s'", leftModName, rightModName, leftFile.getOriginalName());
-				}
+			for (auto const & leftFile : leftResources)
+			{
+				if (rightResources.count(leftFile))
+					logMod->warn("Potential confict detected between '%s' and '%s': both mods add file '%s'", leftName, rightName, leftFile.getOriginalName());
 			}
 		}
 	}
@@ -404,7 +133,8 @@ TModID CModHandler::findResourceOrigin(const ResourcePath & name) const
 {
 	try
 	{
-		for(const auto & modID : boost::adaptors::reverse(activeMods))
+		auto activeMode = modManager->getActiveMods();
+		for(const auto & modID : boost::adaptors::reverse(activeMode))
 		{
 			if(CResourceHandler::get(modID)->existsResource(name))
 				return modID;
@@ -459,7 +189,7 @@ std::string CModHandler::getModLanguage(const TModID& modId) const
 		return VLC->generaltexth->getInstalledLanguage();
 	if(modId == "map")
 		return VLC->generaltexth->getPreferredLanguage();
-	return allMods.at(modId).baseLanguage;
+	return getModInfo(modId).getBaseLanguage();
 }
 
 std::set<TModID> CModHandler::getModDependencies(const TModID & modId) const
@@ -470,11 +200,9 @@ std::set<TModID> CModHandler::getModDependencies(const TModID & modId) const
 
 std::set<TModID> CModHandler::getModDependencies(const TModID & modId, bool & isModFound) const
 {
-	auto it = allMods.find(modId);
-	isModFound = (it != allMods.end());
-
-	if(isModFound)
-		return it->second.dependencies;
+	isModFound = modManager->isModActive(modId);
+	if (isModFound)
+		return modManager->getModDescription(modId).getDependencies();
 
 	logMod->error("Mod not found: '%s'", modId);
 	return {};
@@ -482,54 +210,37 @@ std::set<TModID> CModHandler::getModDependencies(const TModID & modId, bool & is
 
 std::set<TModID> CModHandler::getModSoftDependencies(const TModID & modId) const
 {
-	auto it = allMods.find(modId);
-	if(it != allMods.end())
-		return it->second.softDependencies;
-	logMod->error("Mod not found: '%s'", modId);
-	return {};
+	return modManager->getModDescription(modId).getSoftDependencies();
 }
 
 std::set<TModID> CModHandler::getModEnabledSoftDependencies(const TModID & modId) const
 {
 	std::set<TModID> softDependencies = getModSoftDependencies(modId);
-	for (auto it = softDependencies.begin(); it != softDependencies.end();)
-	{
-		if (allMods.find(*it) == allMods.end())
-			it = softDependencies.erase(it);
-		else
-			it++;
-	}
+
+	vstd::erase_if(softDependencies, [this](const TModID & dependency){ return !modManager->isModActive(dependency);});
+
 	return softDependencies;
 }
 
 void CModHandler::initializeConfig()
 {
-	VLC->settingsHandler->loadBase(JsonUtils::assembleFromFiles(coreMod->config["settings"]));
-
-	for(const TModID & modName : activeMods)
+	for(const TModID & modName : getActiveMods())
 	{
-		const auto & mod = allMods[modName];
-		if (!mod.config["settings"].isNull())
-			VLC->settingsHandler->loadBase(mod.config["settings"]);
+		const auto & mod = getModInfo(modName);
+		if (!mod.getLocalConfig()["settings"].isNull())
+			VLC->settingsHandler->loadBase(mod.getLocalConfig()["settings"]);
 	}
 }
 
-CModVersion CModHandler::getModVersion(TModID modName) const
-{
-	if (allMods.count(modName))
-		return allMods.at(modName).getVerificationInfo().version;
-	return {};
-}
-
 void CModHandler::loadTranslation(const TModID & modName)
 {
-	const auto & mod = allMods[modName];
+	const auto & mod = getModInfo(modName);
 
 	std::string preferredLanguage = VLC->generaltexth->getPreferredLanguage();
-	std::string modBaseLanguage = allMods[modName].baseLanguage;
+	std::string modBaseLanguage = getModInfo(modName).getBaseLanguage();
 
-	JsonNode baseTranslation = JsonUtils::assembleFromFiles(mod.config["translations"]);
-	JsonNode extraTranslation = JsonUtils::assembleFromFiles(mod.config[preferredLanguage]["translations"]);
+	JsonNode baseTranslation = JsonUtils::assembleFromFiles(mod.getLocalConfig()["translations"]);
+	JsonNode extraTranslation = JsonUtils::assembleFromFiles(mod.getLocalConfig()[preferredLanguage]["translations"]);
 
 	VLC->generaltexth->loadTranslationOverrides(modName, modBaseLanguage, baseTranslation);
 	VLC->generaltexth->loadTranslationOverrides(modName, preferredLanguage, extraTranslation);
@@ -537,29 +248,45 @@ void CModHandler::loadTranslation(const TModID & modName)
 
 void CModHandler::load()
 {
-	CStopWatch totalTime;
-	CStopWatch timer;
-
-	logMod->info("\tInitializing content handler: %d ms", timer.getDiff());
+	logMod->info("\tInitializing content handler");
 
 	content->init();
 
+	const auto & activeMods = getActiveMods();
+
+	validationPassed.insert(activeMods.begin(), activeMods.end());
+
 	for(const TModID & modName : activeMods)
 	{
-		logMod->trace("Generating checksum for %s", modName);
-		allMods[modName].updateChecksum(calculateModChecksum(modName, CResourceHandler::get(modName)));
+		modChecksums[modName] = this->modManager->computeChecksum(modName);
 	}
 
-	// first - load virtual builtin mod that contains all data
-	// TODO? move all data into real mods? RoE, AB, SoD, WoG
-	content->preloadData(*coreMod);
 	for(const TModID & modName : activeMods)
-		content->preloadData(allMods[modName]);
-	logMod->info("\tParsing mod data: %d ms", timer.getDiff());
+	{
+		const auto & modInfo = getModInfo(modName);
+		bool isValid = content->preloadData(modInfo, isModValidationNeeded(modInfo));
+		if (isValid)
+			logGlobal->info("\t\tParsing mod: OK (%s)", modInfo.getName());
+		else
+			logGlobal->warn("\t\tParsing mod: Issues found! (%s)", modInfo.getName());
+
+		if (!isValid)
+			validationPassed.erase(modName);
+	}
+	logMod->info("\tParsing mod data");
 
-	content->load(*coreMod);
 	for(const TModID & modName : activeMods)
-		content->load(allMods[modName]);
+	{
+		const auto & modInfo = getModInfo(modName);
+		bool isValid = content->load(getModInfo(modName), isModValidationNeeded(getModInfo(modName)));
+		if (isValid)
+			logGlobal->info("\t\tLoading mod: OK (%s)", modInfo.getName());
+		else
+			logGlobal->warn("\t\tLoading mod: Issues found! (%s)", modInfo.getName());
+
+		if (!isValid)
+			validationPassed.erase(modName);
+	}
 
 #if SCRIPTING_ENABLED
 	VLC->scriptHandler->performRegistration(VLC);//todo: this should be done before any other handlers load
@@ -570,33 +297,42 @@ void CModHandler::load()
 	for(const TModID & modName : activeMods)
 		loadTranslation(modName);
 
-	logMod->info("\tLoading mod data: %d ms", timer.getDiff());
+	logMod->info("\tLoading mod data");
 	VLC->creh->loadCrExpMod();
 	VLC->identifiersHandler->finalize();
-	logMod->info("\tResolving identifiers: %d ms", timer.getDiff());
+	logMod->info("\tResolving identifiers");
 
 	content->afterLoadFinalization();
-	logMod->info("\tHandlers post-load finalization: %d ms ", timer.getDiff());
-	logMod->info("\tAll game content loaded in %d ms", totalTime.getDiff());
+	logMod->info("\tHandlers post-load finalization");
+	logMod->info("\tAll game content loaded");
 }
 
 void CModHandler::afterLoad(bool onlyEssential)
 {
 	JsonNode modSettings;
-	for (auto & modEntry : allMods)
+	for (const auto & modEntry : getActiveMods())
 	{
-		std::string pointer = "/" + boost::algorithm::replace_all_copy(modEntry.first, ".", "/mods/");
-
-		modSettings["activeMods"].resolvePointer(pointer) = modEntry.second.saveLocalData();
+		if (validationPassed.count(modEntry))
+			modManager->setValidatedChecksum(modEntry, modChecksums.at(modEntry));
+		else
+			modManager->setValidatedChecksum(modEntry, std::nullopt);
 	}
-	modSettings[ModScope::scopeBuiltin()] = coreMod->saveLocalData();
-	modSettings[ModScope::scopeBuiltin()]["name"].String() = "Original game files";
 
-	if(!onlyEssential)
-	{
-		std::fstream file(CResourceHandler::get()->getResourceName(ResourcePath("config/modSettings.json"))->c_str(), std::ofstream::out | std::ofstream::trunc);
-		file << modSettings.toString();
-	}
+	modManager->saveConfigurationState();
+}
+
+bool CModHandler::isModValidationNeeded(const ModDescription & mod) const
+{
+	if (settings["mods"]["validation"].String() == "full")
+		return true;
+
+	if (modManager->getValidatedChecksum(mod.getID()) == modChecksums.at(mod.getID()))
+		return false;
+
+	if (settings["mods"]["validation"].String() == "off")
+		return false;
+
+	return true;
 }
 
 VCMI_LIB_NAMESPACE_END

+ 12 - 36
lib/modding/CModHandler.h

@@ -12,51 +12,30 @@
 VCMI_LIB_NAMESPACE_BEGIN
 
 class CModHandler;
-class CModIdentifier;
-class CModInfo;
-struct CModVersion;
-class JsonNode;
-class IHandlerBase;
-class CIdentifierStorage;
+class ModDescription;
 class CContentHandler;
-struct ModVerificationInfo;
 class ResourcePath;
-class MetaString;
+class ModManager;
+class ISimpleResourceLoader;
 
 using TModID = std::string;
 
 class DLL_LINKAGE CModHandler final : boost::noncopyable
 {
-	std::map <TModID, CModInfo> allMods;
-	std::vector <TModID> activeMods;//active mods, in order in which they were loaded
-	std::unique_ptr<CModInfo> coreMod;
-	mutable std::unique_ptr<MetaString> modLoadErrors;
-
-	bool hasCircularDependency(const TModID & mod, std::set<TModID> currentList = std::set<TModID>()) const;
-
-	/**
-	* 1. Set apart mods with resolved dependencies from mods which have unresolved dependencies
-	* 2. Sort resolved mods using topological algorithm
-	* 3. Log all problem mods and their unresolved dependencies
-	*
-	* @param modsToResolve list of valid mod IDs (checkDependencies returned true - TODO: Clarify it.)
-	* @return a vector of the topologically sorted resolved mods: child nodes (dependent mods) have greater index than parents
-	*/
-	std::vector <TModID> validateAndSortDependencies(std::vector <TModID> modsToResolve) const;
-
-	std::vector<std::string> getModList(const std::string & path) const;
-	void loadMods(const std::string & path, const std::string & parent, const JsonNode & modSettings, bool enableMods);
-	void loadOneMod(std::string modName, const std::string & parent, const JsonNode & modSettings, bool enableMods);
+	std::unique_ptr<ModManager> modManager;
+	std::map<std::string, uint32_t> modChecksums;
+	std::set<std::string> validationPassed;
+
 	void loadTranslation(const TModID & modName);
+	void checkModFilesystemsConflicts(const std::map<TModID, ISimpleResourceLoader *> & modFilesystems);
 
-	CModVersion getModVersion(TModID modName) const;
+	bool isModValidationNeeded(const ModDescription & mod) const;
 
 public:
-	std::shared_ptr<CContentHandler> content; //(!)Do not serialize FIXME: make private
+	std::shared_ptr<CContentHandler> content;
 
 	/// receives list of available mods and trying to load mod.json from all of them
 	void initializeConfig();
-	void loadMods();
 	void loadModFilesystems();
 
 	/// returns ID of mod that provides selected file resource
@@ -77,12 +56,9 @@ public:
 
 	/// returns list of all (active) mods
 	std::vector<std::string> getAllMods() const;
-	std::vector<std::string> getActiveMods() const;
+	const std::vector<std::string> & getActiveMods() const;
 
-	/// Returns human-readable string that describes errors encounter during mod loading, such as missing dependencies
-	std::string getModLoadErrors() const;
-	
-	const CModInfo & getModInfo(const TModID & modId) const;
+	const ModDescription & getModInfo(const TModID & modId) const;
 
 	/// load content from all available mods
 	void load();

+ 0 - 206
lib/modding/CModInfo.cpp

@@ -1,206 +0,0 @@
-/*
- * CModInfo.cpp, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-#include "StdInc.h"
-#include "CModInfo.h"
-
-#include "../texts/CGeneralTextHandler.h"
-#include "../VCMI_Lib.h"
-#include "../filesystem/Filesystem.h"
-
-VCMI_LIB_NAMESPACE_BEGIN
-
-static JsonNode addMeta(JsonNode config, const std::string & meta)
-{
-	config.setModScope(meta);
-	return config;
-}
-
-std::set<TModID> CModInfo::readModList(const JsonNode & input)
-{
-	std::set<TModID> result;
-
-	for (auto const & string : input.convertTo<std::set<std::string>>())
-		result.insert(boost::to_lower_copy(string));
-
-	return result;
-}
-
-CModInfo::CModInfo():
-	explicitlyEnabled(false),
-	implicitlyEnabled(true),
-	validation(PENDING)
-{
-
-}
-
-CModInfo::CModInfo(const std::string & identifier, const JsonNode & local, const JsonNode & config):
-	identifier(identifier),
-	dependencies(readModList(config["depends"])),
-	softDependencies(readModList(config["softDepends"])),
-	conflicts(readModList(config["conflicts"])),
-	explicitlyEnabled(false),
-	implicitlyEnabled(true),
-	validation(PENDING),
-	config(addMeta(config, identifier))
-{
-	if (!config["name"].String().empty())
-		verificationInfo.name = config["name"].String();
-	else
-		verificationInfo.name = identifier;
-
-	verificationInfo.version = CModVersion::fromString(config["version"].String());
-	verificationInfo.parent = identifier.substr(0, identifier.find_last_of('.'));
-	if(verificationInfo.parent == identifier)
-		verificationInfo.parent.clear();
-
-	if(!config["compatibility"].isNull())
-	{
-		vcmiCompatibleMin = CModVersion::fromString(config["compatibility"]["min"].String());
-		vcmiCompatibleMax = CModVersion::fromString(config["compatibility"]["max"].String());
-	}
-
-	if (!config["language"].isNull())
-		baseLanguage = config["language"].String();
-	else
-		baseLanguage = "english";
-
-	loadLocalData(local);
-}
-
-JsonNode CModInfo::saveLocalData() const
-{
-	std::ostringstream stream;
-	stream << std::noshowbase << std::hex << std::setw(8) << std::setfill('0') << verificationInfo.checksum;
-
-	JsonNode conf;
-	conf["active"].Bool() = explicitlyEnabled;
-	conf["validated"].Bool() = validation != FAILED;
-	conf["checksum"].String() = stream.str();
-	return conf;
-}
-
-std::string CModInfo::getModDir(const std::string & name)
-{
-	return "MODS/" + boost::algorithm::replace_all_copy(name, ".", "/MODS/");
-}
-
-JsonPath CModInfo::getModFile(const std::string & name)
-{
-	return JsonPath::builtinTODO(getModDir(name) + "/mod.json");
-}
-
-void CModInfo::updateChecksum(ui32 newChecksum)
-{
-	// comment-out next line to force validation of all mods ignoring checksum
-	if (newChecksum != verificationInfo.checksum)
-	{
-		verificationInfo.checksum = newChecksum;
-		validation = PENDING;
-	}
-}
-
-void CModInfo::loadLocalData(const JsonNode & data)
-{
-	bool validated = false;
-	implicitlyEnabled = true;
-	explicitlyEnabled = !config["keepDisabled"].Bool();
-	verificationInfo.checksum = 0;
-	if (data.isStruct())
-	{
-		explicitlyEnabled = data["active"].Bool();
-		validated = data["validated"].Bool();
-		updateChecksum(strtol(data["checksum"].String().c_str(), nullptr, 16));
-	}
-
-	//check compatibility
-	implicitlyEnabled &= (vcmiCompatibleMin.isNull() || CModVersion::GameVersion().compatible(vcmiCompatibleMin, true, true));
-	implicitlyEnabled &= (vcmiCompatibleMax.isNull() || vcmiCompatibleMax.compatible(CModVersion::GameVersion(), true, true));
-
-	if(!implicitlyEnabled)
-		logGlobal->warn("Mod %s is incompatible with current version of VCMI and cannot be enabled", verificationInfo.name);
-
-	if (config["modType"].String() == "Translation")
-	{
-		if (baseLanguage != CGeneralTextHandler::getPreferredLanguage())
-		{
-			if (identifier.find_last_of('.') == std::string::npos)
-				logGlobal->warn("Translation mod %s was not loaded: language mismatch!", verificationInfo.name);
-			implicitlyEnabled = false;
-		}
-	}
-	if (config["modType"].String() == "Compatibility")
-	{
-		// compatibility mods are always explicitly enabled
-		// however they may be implicitly disabled - if one of their dependencies is missing
-		explicitlyEnabled = true;
-	}
-
-	if (isEnabled())
-		validation = validated ? PASSED : PENDING;
-	else
-		validation = validated ? PASSED : FAILED;
-
-	verificationInfo.impactsGameplay = checkModGameplayAffecting();
-}
-
-bool CModInfo::checkModGameplayAffecting() const
-{
-	if (modGameplayAffecting.has_value())
-		return *modGameplayAffecting;
-
-	static const std::vector<std::string> keysToTest = {
-		"heroClasses",
-		"artifacts",
-		"creatures",
-		"factions",
-		"objects",
-		"heroes",
-		"spells",
-		"skills",
-		"templates",
-		"scripts",
-		"battlefields",
-		"terrains",
-		"rivers",
-		"roads",
-		"obstacles"
-	};
-
-	JsonPath modFileResource(CModInfo::getModFile(identifier));
-
-	if(CResourceHandler::get("initial")->existsResource(modFileResource))
-	{
-		const JsonNode modConfig(modFileResource);
-
-		for(const auto & key : keysToTest)
-		{
-			if (!modConfig[key].isNull())
-			{
-				modGameplayAffecting = true;
-				return *modGameplayAffecting;
-			}
-		}
-	}
-	modGameplayAffecting = false;
-	return *modGameplayAffecting;
-}
-
-const ModVerificationInfo & CModInfo::getVerificationInfo() const
-{
-	assert(!verificationInfo.name.empty());
-	return verificationInfo;
-}
-
-bool CModInfo::isEnabled() const
-{
-	return implicitlyEnabled && explicitlyEnabled;
-}
-
-VCMI_LIB_NAMESPACE_END

+ 0 - 85
lib/modding/CModInfo.h

@@ -1,85 +0,0 @@
-/*
- * CModInfo.h, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-#pragma once
-
-#include "../json/JsonNode.h"
-#include "ModVerificationInfo.h"
-
-VCMI_LIB_NAMESPACE_BEGIN
-
-class DLL_LINKAGE CModInfo
-{
-	/// cached result of checkModGameplayAffecting() call
-	/// Do not serialize - depends on local mod version, not server/save mod version
-	mutable std::optional<bool> modGameplayAffecting;
-
-	static std::set<TModID> readModList(const JsonNode & input);
-public:
-	enum EValidationStatus
-	{
-		PENDING,
-		FAILED,
-		PASSED
-	};
-	
-	/// identifier, identical to name of folder with mod
-	std::string identifier;
-
-	/// detailed mod description
-	std::string description;
-
-	/// Base language of mod, all mod strings are assumed to be in this language
-	std::string baseLanguage;
-
-	/// vcmi versions compatible with the mod
-	CModVersion vcmiCompatibleMin, vcmiCompatibleMax;
-
-	/// list of mods that should be loaded before this one
-	std::set <TModID> dependencies;
-
-	/// list of mods if they are enabled, should be loaded before this one. this mod will overwrite any conflicting items from its soft dependency mods
-	std::set <TModID> softDependencies;
-
-	/// list of mods that can't be used in the same time as this one
-	std::set <TModID> conflicts;
-
-	EValidationStatus validation;
-
-	JsonNode config;
-
-	CModInfo();
-	CModInfo(const std::string & identifier, const JsonNode & local, const JsonNode & config);
-
-	JsonNode saveLocalData() const;
-	void updateChecksum(ui32 newChecksum);
-
-	bool isEnabled() const;
-
-	static std::string getModDir(const std::string & name);
-	static JsonPath getModFile(const std::string & name);
-
-	/// return true if this mod can affect gameplay, e.g. adds or modifies any game objects
-	bool checkModGameplayAffecting() const;
-	
-	const ModVerificationInfo & getVerificationInfo() const;
-
-private:
-	/// true if mod is enabled by user, e.g. in Launcher UI
-	bool explicitlyEnabled;
-
-	/// true if mod can be loaded - compatible and has no missing deps
-	bool implicitlyEnabled;
-	
-	ModVerificationInfo verificationInfo;
-
-	void loadLocalData(const JsonNode & data);
-};
-
-VCMI_LIB_NAMESPACE_END

+ 12 - 56
lib/modding/ContentTypeHandler.cpp

@@ -11,7 +11,8 @@
 #include "ContentTypeHandler.h"
 
 #include "CModHandler.h"
-#include "CModInfo.h"
+#include "ModDescription.h"
+#include "ModManager.h"
 #include "ModScope.h"
 
 #include "../BattleFieldHandler.h"
@@ -54,7 +55,7 @@ ContentTypeHandler::ContentTypeHandler(IHandlerBase * handler, const std::string
 
 bool ContentTypeHandler::preloadModData(const std::string & modName, const JsonNode & fileList, bool validate)
 {
-	bool result = false;
+	bool result = true;
 	JsonNode data = JsonUtils::assembleFromFiles(fileList, result);
 	data.setModScope(modName);
 
@@ -170,7 +171,7 @@ void ContentTypeHandler::afterLoadFinalization()
 		{
 			if (data.second.modData.isNull())
 			{
-				for (auto node : data.second.patches.Struct())
+				for (const auto & node : data.second.patches.Struct())
 					logMod->warn("Mod '%s' have added patch for object '%s' from mod '%s', but this mod was not loaded or has no new objects.", node.second.getModScope(), node.first, data.first);
 			}
 
@@ -258,22 +259,26 @@ void CContentHandler::init()
 	handlers.insert(std::make_pair("biomes", ContentTypeHandler(VLC->biomeHandler.get(), "biome")));
 }
 
-bool CContentHandler::preloadModData(const std::string & modName, JsonNode modConfig, bool validate)
+bool CContentHandler::preloadData(const ModDescription & mod, bool validate)
 {
 	bool result = true;
+
+	if (!JsonUtils::validate(mod.getLocalConfig(), "vcmi:mod", mod.getID()))
+		result = false;
+
 	for(auto & handler : handlers)
 	{
-		result &= handler.second.preloadModData(modName, modConfig[handler.first], validate);
+		result &= handler.second.preloadModData(mod.getID(), mod.getLocalValue(handler.first), validate);
 	}
 	return result;
 }
 
-bool CContentHandler::loadMod(const std::string & modName, bool validate)
+bool CContentHandler::load(const ModDescription & mod, bool validate)
 {
 	bool result = true;
 	for(auto & handler : handlers)
 	{
-		result &= handler.second.loadMod(modName, validate);
+		result &= handler.second.loadMod(mod.getID(), validate);
 	}
 	return result;
 }
@@ -294,58 +299,9 @@ void CContentHandler::afterLoadFinalization()
 	}
 }
 
-void CContentHandler::preloadData(CModInfo & mod)
-{
-	bool validate = validateMod(mod);
-
-	// print message in format [<8-symbols checksum>] <modname>
-	auto & info = mod.getVerificationInfo();
-	logMod->info("\t\t[%08x]%s", info.checksum, info.name);
-
-	if (validate && mod.identifier != ModScope::scopeBuiltin())
-	{
-		if (!JsonUtils::validate(mod.config, "vcmi:mod", mod.identifier))
-			mod.validation = CModInfo::FAILED;
-	}
-	if (!preloadModData(mod.identifier, mod.config, validate))
-		mod.validation = CModInfo::FAILED;
-}
-
-void CContentHandler::load(CModInfo & mod)
-{
-	bool validate = validateMod(mod);
-
-	if (!loadMod(mod.identifier, validate))
-		mod.validation = CModInfo::FAILED;
-
-	if (validate)
-	{
-		if (mod.validation != CModInfo::FAILED)
-			logMod->info("\t\t[DONE] %s", mod.getVerificationInfo().name);
-		else
-			logMod->error("\t\t[FAIL] %s", mod.getVerificationInfo().name);
-	}
-	else
-		logMod->info("\t\t[SKIP] %s", mod.getVerificationInfo().name);
-}
-
 const ContentTypeHandler & CContentHandler::operator[](const std::string & name) const
 {
 	return handlers.at(name);
 }
 
-bool CContentHandler::validateMod(const CModInfo & mod) const
-{
-	if (settings["mods"]["validation"].String() == "full")
-		return true;
-
-	if (mod.validation == CModInfo::PASSED)
-		return false;
-
-	if (settings["mods"]["validation"].String() == "off")
-		return false;
-
-	return true;
-}
-
 VCMI_LIB_NAMESPACE_END

+ 3 - 10
lib/modding/ContentTypeHandler.h

@@ -14,7 +14,7 @@
 VCMI_LIB_NAMESPACE_BEGIN
 
 class IHandlerBase;
-class CModInfo;
+class ModDescription;
 
 /// internal type to handle loading of one data type (e.g. artifacts, creatures)
 class DLL_LINKAGE ContentTypeHandler
@@ -50,23 +50,16 @@ public:
 /// class used to load all game data into handlers. Used only during loading
 class DLL_LINKAGE CContentHandler
 {
-	/// preloads all data from fileList as data from modName.
-	bool preloadModData(const std::string & modName, JsonNode modConfig, bool validate);
-
-	/// actually loads data in mod
-	bool loadMod(const std::string & modName, bool validate);
-
 	std::map<std::string, ContentTypeHandler> handlers;
 
-	bool validateMod(const CModInfo & mod) const;
 public:
 	void init();
 
 	/// preloads all data from fileList as data from modName.
-	void preloadData(CModInfo & mod);
+	bool preloadData(const ModDescription & mod, bool validateMod);
 
 	/// actually loads data in mod
-	void load(CModInfo & mod);
+	bool load(const ModDescription & mod, bool validateMod);
 
 	void loadCustom();
 

+ 219 - 0
lib/modding/ModDescription.cpp

@@ -0,0 +1,219 @@
+/*
+ * ModDescription.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+#include "ModDescription.h"
+
+#include "CModVersion.h"
+#include "ModVerificationInfo.h"
+
+#include "../json/JsonNode.h"
+#include "../texts/CGeneralTextHandler.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+ModDescription::ModDescription(const TModID & fullID, const JsonNode & localConfig, const JsonNode & repositoryConfig)
+	: identifier(fullID)
+	, localConfig(std::make_unique<JsonNode>(localConfig))
+	, repositoryConfig(std::make_unique<JsonNode>(repositoryConfig))
+	, dependencies(loadModList(getValue("depends")))
+	, softDependencies(loadModList(getValue("softDepends")))
+	, conflicts(loadModList(getValue("conflicts")))
+{
+	if(getID() != "core")
+		dependencies.emplace("core");
+
+	if (!getParentID().empty())
+		dependencies.emplace(getParentID());
+}
+
+ModDescription::~ModDescription() = default;
+
+TModSet ModDescription::loadModList(const JsonNode & configNode) const
+{
+	TModSet result;
+	for(const auto & entry : configNode.Vector())
+		result.insert(boost::algorithm::to_lower_copy(entry.String()));
+	return result;
+}
+
+const TModID & ModDescription::getID() const
+{
+	return identifier;
+}
+
+TModID ModDescription::getParentID() const
+{
+	size_t dotPos = identifier.find_last_of('.');
+
+	if(dotPos == std::string::npos)
+		return {};
+
+	return identifier.substr(0, dotPos);
+}
+
+TModID ModDescription::getTopParentID() const
+{
+	size_t dotPos = identifier.find('.');
+
+	if(dotPos == std::string::npos)
+		return {};
+
+	return identifier.substr(0, dotPos);
+}
+
+const TModSet & ModDescription::getDependencies() const
+{
+	return dependencies;
+}
+
+const TModSet & ModDescription::getSoftDependencies() const
+{
+	return softDependencies;
+}
+
+const TModSet & ModDescription::getConflicts() const
+{
+	return conflicts;
+}
+
+const std::string & ModDescription::getBaseLanguage() const
+{
+	static const std::string defaultLanguage = "english";
+
+	return getValue("language").isString() ? getValue("language").String() : defaultLanguage;
+}
+
+const std::string & ModDescription::getName() const
+{
+	return getLocalizedValue("name").String();
+}
+
+const JsonNode & ModDescription::getFilesystemConfig() const
+{
+	return getLocalValue("filesystem");
+}
+
+const JsonNode & ModDescription::getLocalConfig() const
+{
+	return *localConfig;
+}
+
+const JsonNode & ModDescription::getLocalizedValue(const std::string & keyName) const
+{
+	const std::string language = CGeneralTextHandler::getPreferredLanguage();
+	const JsonNode & languageNode = getValue(language);
+	const JsonNode & baseValue = getValue(keyName);
+	const JsonNode & localizedValue = languageNode[keyName];
+
+	if (localizedValue.isNull())
+		return baseValue;
+	else
+		return localizedValue;
+}
+
+const JsonNode & ModDescription::getValue(const std::string & keyName) const
+{
+	const JsonNode & localValue = getLocalValue(keyName);
+	if (localValue.isNull())
+		return getRepositoryValue(keyName);
+	else
+		return getLocalValue(keyName);
+}
+
+const JsonNode & ModDescription::getLocalValue(const std::string & keyName) const
+{
+	return getLocalConfig()[keyName];
+}
+
+const JsonNode & ModDescription::getRepositoryValue(const std::string & keyName) const
+{
+	return (*repositoryConfig)[keyName];
+}
+
+CModVersion ModDescription::getVersion() const
+{
+	return CModVersion::fromString(getValue("version").String());
+}
+
+ModVerificationInfo ModDescription::getVerificationInfo() const
+{
+	ModVerificationInfo result;
+	result.name = getName();
+	result.version = getVersion();
+	result.impactsGameplay = affectsGameplay();
+	result.parent = getParentID();
+
+	return result;
+}
+
+bool ModDescription::isCompatible() const
+{
+	const JsonNode & compatibility = getValue("compatibility");
+
+	if (compatibility.isNull())
+		return true;
+
+	auto vcmiCompatibleMin = CModVersion::fromString(compatibility["min"].String());
+	auto vcmiCompatibleMax = CModVersion::fromString(compatibility["max"].String());
+
+	bool compatible = true;
+	compatible &= (vcmiCompatibleMin.isNull() || CModVersion::GameVersion().compatible(vcmiCompatibleMin, true, true));
+	compatible &= (vcmiCompatibleMax.isNull() || vcmiCompatibleMax.compatible(CModVersion::GameVersion(), true, true));
+
+	return compatible;
+}
+
+bool ModDescription::isCompatibility() const
+{
+	return getValue("modType").String() == "Compatibility";
+}
+
+bool ModDescription::isTranslation() const
+{
+	return getValue("modType").String() == "Translation";
+}
+
+bool ModDescription::keepDisabled() const
+{
+	return getValue("keepDisabled").Bool();
+}
+
+bool ModDescription::isInstalled() const
+{
+	return !localConfig->isNull();
+}
+
+bool ModDescription::affectsGameplay() const
+{
+	static const std::array keysToTest = {
+		"artifacts",
+		"battlefields",
+		"creatures",
+		"factions",
+		"heroClasses",
+		"heroes",
+		"objects",
+		"obstacles",
+		"rivers",
+		"roads",
+		"settings",
+		"skills",
+		"spells",
+		"terrains",
+	};
+
+	for(const auto & key : keysToTest)
+		if (!getLocalValue(key).isNull())
+			return true;
+
+	return false;
+}
+
+VCMI_LIB_NAMESPACE_END

+ 69 - 0
lib/modding/ModDescription.h

@@ -0,0 +1,69 @@
+/*
+ * ModDescription.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+struct CModVersion;
+struct ModVerificationInfo;
+class JsonNode;
+
+using TModID = std::string;
+using TModList = std::vector<TModID>;
+using TModSet = std::set<TModID>;
+
+class DLL_LINKAGE ModDescription : boost::noncopyable
+{
+	TModID identifier;
+
+	std::unique_ptr<JsonNode> localConfig;
+	std::unique_ptr<JsonNode> repositoryConfig;
+
+	TModSet dependencies;
+	TModSet softDependencies;
+	TModSet conflicts;
+
+	TModSet loadModList(const JsonNode & configNode) const;
+
+public:
+	ModDescription(const TModID & fullID, const JsonNode & localConfig, const JsonNode & repositoryConfig);
+	~ModDescription();
+
+	const TModID & getID() const;
+	TModID getParentID() const;
+	TModID getTopParentID() const;
+
+	const TModSet & getDependencies() const;
+	const TModSet & getSoftDependencies() const;
+	const TModSet & getConflicts() const;
+
+	const std::string & getBaseLanguage() const;
+	const std::string & getName() const;
+
+	const JsonNode & getFilesystemConfig() const;
+	const JsonNode & getLocalConfig() const;
+	const JsonNode & getValue(const std::string & keyName) const;
+	const JsonNode & getLocalizedValue(const std::string & keyName) const;
+	const JsonNode & getLocalValue(const std::string & keyName) const;
+	const JsonNode & getRepositoryValue(const std::string & keyName) const;
+
+	CModVersion getVersion() const;
+	ModVerificationInfo getVerificationInfo() const;
+
+	bool isCompatible() const;
+
+	bool affectsGameplay() const;
+	bool isCompatibility() const;
+	bool isTranslation() const;
+	bool keepDisabled() const;
+	bool isInstalled() const;
+};
+
+VCMI_LIB_NAMESPACE_END

+ 706 - 0
lib/modding/ModManager.cpp

@@ -0,0 +1,706 @@
+/*
+ * ModManager.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+#include "ModManager.h"
+
+#include "ModDescription.h"
+#include "ModScope.h"
+
+#include "../constants/StringConstants.h"
+#include "../filesystem/Filesystem.h"
+#include "../json/JsonNode.h"
+#include "../texts/CGeneralTextHandler.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+static std::string getModDirectory(const TModID & modName)
+{
+	std::string result = modName;
+	boost::to_upper(result);
+	boost::algorithm::replace_all(result, ".", "/MODS/");
+	return "MODS/" + result;
+}
+
+static std::string getModSettingsDirectory(const TModID & modName)
+{
+	return getModDirectory(modName) + "/MODS/";
+}
+
+static JsonPath getModDescriptionFile(const TModID & modName)
+{
+	return JsonPath::builtin(getModDirectory(modName) + "/mod");
+}
+
+ModsState::ModsState()
+{
+	modList.push_back(ModScope::scopeBuiltin());
+
+	std::vector<TModID> testLocations = scanModsDirectory("MODS/");
+
+	while(!testLocations.empty())
+	{
+		std::string target = testLocations.back();
+		testLocations.pop_back();
+		modList.push_back(boost::algorithm::to_lower_copy(target));
+
+		for(const auto & submod : scanModsDirectory(getModSettingsDirectory(target)))
+			testLocations.push_back(target + '.' + submod);
+	}
+}
+
+TModList ModsState::getInstalledMods() const
+{
+	return modList;
+}
+
+uint32_t ModsState::computeChecksum(const TModID & modName) const
+{
+	boost::crc_32_type modChecksum;
+	// first - add current VCMI version into checksum to force re-validation on VCMI updates
+	modChecksum.process_bytes(static_cast<const void*>(GameConstants::VCMI_VERSION.data()), GameConstants::VCMI_VERSION.size());
+
+	// second - add mod.json into checksum because filesystem does not contains this file
+	if (modName != ModScope::scopeBuiltin())
+	{
+		auto modConfFile = getModDescriptionFile(modName);
+		ui32 configChecksum = CResourceHandler::get("initial")->load(modConfFile)->calculateCRC32();
+		modChecksum.process_bytes(static_cast<const void *>(&configChecksum), sizeof(configChecksum));
+	}
+
+	// third - add all detected text files from this mod into checksum
+	const auto & filesystem = CResourceHandler::get(modName);
+
+	auto files = filesystem->getFilteredFiles([](const ResourcePath & resID)
+	{
+		return resID.getType() == EResType::JSON && boost::starts_with(resID.getName(), "CONFIG");
+	});
+
+	for (const ResourcePath & file : files)
+	{
+		ui32 fileChecksum = filesystem->load(file)->calculateCRC32();
+		modChecksum.process_bytes(static_cast<const void *>(&fileChecksum), sizeof(fileChecksum));
+	}
+	return modChecksum.checksum();
+}
+
+double ModsState::getInstalledModSizeMegabytes(const TModID & modName) const
+{
+	ResourcePath resDir(getModDirectory(modName), EResType::DIRECTORY);
+	std::string path = CResourceHandler::get()->getResourceName(resDir)->string();
+
+	size_t sizeBytes = 0;
+	for(boost::filesystem::recursive_directory_iterator it(path); it != boost::filesystem::recursive_directory_iterator(); ++it)
+	{
+		if(!boost::filesystem::is_directory(*it))
+			sizeBytes += boost::filesystem::file_size(*it);
+	}
+
+	double sizeMegabytes = sizeBytes / static_cast<double>(1024*1024);
+	return sizeMegabytes;
+}
+
+std::vector<TModID> ModsState::scanModsDirectory(const std::string & modDir) const
+{
+	size_t depth = boost::range::count(modDir, '/');
+
+	const auto & modScanFilter = [&](const ResourcePath & id) -> bool
+	{
+		if(id.getType() != EResType::DIRECTORY)
+			return false;
+		if(!boost::algorithm::starts_with(id.getName(), modDir))
+			return false;
+		if(boost::range::count(id.getName(), '/') != depth)
+			return false;
+		return true;
+	};
+
+	auto list = CResourceHandler::get("initial")->getFilteredFiles(modScanFilter);
+
+	//storage for found mods
+	std::vector<TModID> foundMods;
+	for(const auto & entry : list)
+	{
+		std::string name = entry.getName();
+		name.erase(0, modDir.size()); //Remove path prefix
+
+		if(name.empty())
+			continue;
+
+		if(name.find('.') != std::string::npos)
+			continue;
+
+		if (ModScope::isScopeReserved(boost::to_lower_copy(name)))
+			continue;
+
+		if(!CResourceHandler::get("initial")->existsResource(JsonPath::builtin(entry.getName() + "/MOD")))
+			continue;
+
+		foundMods.push_back(name);
+	}
+	return foundMods;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+ModsPresetState::ModsPresetState()
+{
+	static const JsonPath settingsPath = JsonPath::builtin("config/modSettings.json");
+
+	if(CResourceHandler::get("local")->existsResource(ResourcePath(settingsPath)))
+	{
+		modConfig = JsonNode(settingsPath);
+	}
+	else
+	{
+		// Probably new install. Create initial configuration
+		CResourceHandler::get("local")->createResource(settingsPath.getOriginalName() + ".json");
+	}
+
+	if(modConfig["presets"].isNull())
+	{
+		modConfig["activePreset"] = JsonNode("default");
+		if(modConfig["activeMods"].isNull())
+			createInitialPreset(); // new install
+		else
+			importInitialPreset(); // 1.5 format import
+	}
+}
+
+void ModsPresetState::createInitialPreset()
+{
+	// TODO: scan mods directory for all its content? Probably unnecessary since this looks like new install, but who knows?
+	modConfig["presets"]["default"]["mods"].Vector().emplace_back("vcmi");
+}
+
+void ModsPresetState::importInitialPreset()
+{
+	JsonNode preset;
+
+	for(const auto & mod : modConfig["activeMods"].Struct())
+	{
+		if(mod.second["active"].Bool())
+			preset["mods"].Vector().emplace_back(mod.first);
+
+		for(const auto & submod : mod.second["mods"].Struct())
+			preset["settings"][mod.first][submod.first] = submod.second["active"];
+	}
+	modConfig["presets"]["default"] = preset;
+}
+
+const JsonNode & ModsPresetState::getActivePresetConfig() const
+{
+	const std::string & currentPresetName = modConfig["activePreset"].String();
+	const JsonNode & currentPreset = modConfig["presets"][currentPresetName];
+	return currentPreset;
+}
+
+TModList ModsPresetState::getActiveRootMods() const
+{
+	const JsonNode & modsToActivateJson = getActivePresetConfig()["mods"];
+	auto modsToActivate = modsToActivateJson.convertTo<std::vector<TModID>>();
+	if (!vstd::contains(modsToActivate, ModScope::scopeBuiltin()))
+		modsToActivate.push_back(ModScope::scopeBuiltin());
+	return modsToActivate;
+}
+
+std::map<TModID, bool> ModsPresetState::getModSettings(const TModID & modID) const
+{
+	const JsonNode & modSettingsJson = getActivePresetConfig()["settings"][modID];
+	auto modSettings = modSettingsJson.convertTo<std::map<TModID, bool>>();
+	return modSettings;
+}
+
+std::optional<uint32_t> ModsPresetState::getValidatedChecksum(const TModID & modName) const
+{
+	const JsonNode & node = modConfig["validatedMods"][modName];
+	if (node.isNull())
+		return std::nullopt;
+	else
+		return node.Integer();
+}
+
+void ModsPresetState::setModActive(const TModID & modID, bool isActive)
+{
+	size_t dotPos = modID.find('.');
+
+	if(dotPos != std::string::npos)
+	{
+		std::string rootMod = modID.substr(0, dotPos);
+		std::string settingID = modID.substr(dotPos + 1);
+		setSettingActive(rootMod, settingID, isActive);
+	}
+	else
+	{
+		if (isActive)
+			addRootMod(modID);
+		else
+			eraseRootMod(modID);
+	}
+}
+
+void ModsPresetState::addRootMod(const TModID & modName)
+{
+	const std::string & currentPresetName = modConfig["activePreset"].String();
+	JsonNode & currentPreset = modConfig["presets"][currentPresetName];
+
+	if (!vstd::contains(currentPreset["mods"].Vector(), JsonNode(modName)))
+		currentPreset["mods"].Vector().emplace_back(modName);
+}
+
+void ModsPresetState::setSettingActive(const TModID & modName, const TModID & settingName, bool isActive)
+{
+	const std::string & currentPresetName = modConfig["activePreset"].String();
+	JsonNode & currentPreset = modConfig["presets"][currentPresetName];
+
+	currentPreset["settings"][modName][settingName].Bool() = isActive;
+}
+
+void ModsPresetState::removeOldMods(const TModList & modsToKeep)
+{
+	const std::string & currentPresetName = modConfig["activePreset"].String();
+	JsonNode & currentPreset = modConfig["presets"][currentPresetName];
+
+	vstd::erase_if(currentPreset["mods"].Vector(), [&](const JsonNode & entry){
+		return !vstd::contains(modsToKeep, entry.String());
+	});
+
+	vstd::erase_if(currentPreset["settings"].Struct(), [&](const auto & entry){
+		return !vstd::contains(modsToKeep, entry.first);
+	});
+}
+
+void ModsPresetState::eraseRootMod(const TModID & modName)
+{
+	const std::string & currentPresetName = modConfig["activePreset"].String();
+	JsonNode & currentPreset = modConfig["presets"][currentPresetName];
+	vstd::erase(currentPreset["mods"].Vector(), JsonNode(modName));
+}
+
+void ModsPresetState::eraseModSetting(const TModID & modName, const TModID & settingName)
+{
+	const std::string & currentPresetName = modConfig["activePreset"].String();
+	JsonNode & currentPreset = modConfig["presets"][currentPresetName];
+	currentPreset["settings"][modName].Struct().erase(modName);
+}
+
+std::vector<TModID> ModsPresetState::getActiveMods() const
+{
+	TModList activeRootMods = getActiveRootMods();
+	TModList allActiveMods;
+
+	for(const auto & activeMod : activeRootMods)
+	{
+		assert(!vstd::contains(allActiveMods, activeMod));
+		allActiveMods.push_back(activeMod);
+
+		for(const auto & submod : getModSettings(activeMod))
+		{
+			if(submod.second)
+			{
+				assert(!vstd::contains(allActiveMods, activeMod + '.' + submod.first));
+				allActiveMods.push_back(activeMod + '.' + submod.first);
+			}
+		}
+	}
+	return allActiveMods;
+}
+
+void ModsPresetState::setValidatedChecksum(const TModID & modName, std::optional<uint32_t> value)
+{
+	if (value.has_value())
+		modConfig["validatedMods"][modName].Integer() = *value;
+	else
+		modConfig["validatedMods"].Struct().erase(modName);
+}
+
+void ModsPresetState::saveConfigurationState() const
+{
+	std::fstream file(CResourceHandler::get()->getResourceName(ResourcePath("config/modSettings.json"))->c_str(), std::ofstream::out | std::ofstream::trunc);
+	file << modConfig.toCompactString();
+}
+
+ModsStorage::ModsStorage(const std::vector<TModID> & modsToLoad, const JsonNode & repositoryList)
+{
+	JsonNode coreModConfig(JsonPath::builtin("config/gameConfig.json"));
+	coreModConfig.setModScope(ModScope::scopeBuiltin());
+	mods.try_emplace(ModScope::scopeBuiltin(), ModScope::scopeBuiltin(), coreModConfig, JsonNode());
+
+	for(auto modID : modsToLoad)
+	{
+		if(ModScope::isScopeReserved(modID))
+			continue;
+
+		JsonNode modConfig(getModDescriptionFile(modID));
+		modConfig.setModScope(modID);
+
+		if(modConfig["modType"].isNull())
+		{
+			logMod->error("Can not load mod %s - invalid mod config file!", modID);
+			continue;
+		}
+
+		mods.try_emplace(modID, modID, modConfig, repositoryList[modID]);
+	}
+
+	for(const auto & mod : repositoryList.Struct())
+	{
+		if (vstd::contains(modsToLoad, mod.first))
+			continue;
+
+		if (mod.second["modType"].isNull() || mod.second["name"].isNull())
+			continue;
+
+		mods.try_emplace(mod.first, mod.first, JsonNode(), mod.second);
+	}
+}
+
+const ModDescription & ModsStorage::getMod(const TModID & fullID) const
+{
+	return mods.at(fullID);
+}
+
+TModList ModsStorage::getAllMods() const
+{
+	TModList result;
+	for (const auto & mod : mods)
+		result.push_back(mod.first);
+
+	return result;
+}
+
+ModManager::ModManager()
+	:ModManager(JsonNode())
+{
+}
+
+ModManager::ModManager(const JsonNode & repositoryList)
+	: modsState(std::make_unique<ModsState>())
+	, modsPreset(std::make_unique<ModsPresetState>())
+{
+	modsStorage = std::make_unique<ModsStorage>(modsState->getInstalledMods(), repositoryList);
+
+	eraseMissingModsFromPreset();
+	addNewModsToPreset();
+
+	std::vector<TModID> desiredModList = modsPreset->getActiveMods();
+	ModDependenciesResolver newResolver(desiredModList, *modsStorage);
+	updatePreset(newResolver);
+}
+
+ModManager::~ModManager() = default;
+
+const ModDescription & ModManager::getModDescription(const TModID & modID) const
+{
+	assert(boost::to_lower_copy(modID) == modID);
+	return modsStorage->getMod(modID);
+}
+
+bool ModManager::isModSettingActive(const TModID & rootModID, const TModID & modSettingID) const
+{
+	return modsPreset->getModSettings(rootModID).at(modSettingID);
+}
+
+bool ModManager::isModActive(const TModID & modID) const
+{
+	return vstd::contains(getActiveMods(), modID);
+}
+
+const TModList & ModManager::getActiveMods() const
+{
+	return depedencyResolver->getActiveMods();
+}
+
+uint32_t ModManager::computeChecksum(const TModID & modName) const
+{
+	return modsState->computeChecksum(modName);
+}
+
+std::optional<uint32_t> ModManager::getValidatedChecksum(const TModID & modName) const
+{
+	return modsPreset->getValidatedChecksum(modName);
+}
+
+void ModManager::setValidatedChecksum(const TModID & modName, std::optional<uint32_t> value)
+{
+	modsPreset->setValidatedChecksum(modName, value);
+}
+
+void ModManager::saveConfigurationState() const
+{
+	modsPreset->saveConfigurationState();
+}
+
+TModList ModManager::getAllMods() const
+{
+	return modsStorage->getAllMods();
+}
+
+double ModManager::getInstalledModSizeMegabytes(const TModID & modName) const
+{
+	return modsState->getInstalledModSizeMegabytes(modName);
+}
+
+void ModManager::eraseMissingModsFromPreset()
+{
+	const TModList & installedMods = modsState->getInstalledMods();
+	const TModList & rootMods = modsPreset->getActiveRootMods();
+
+	modsPreset->removeOldMods(installedMods);
+
+	for(const auto & rootMod : rootMods)
+	{
+		const auto & modSettings = modsPreset->getModSettings(rootMod);
+
+		for(const auto & modSetting : modSettings)
+		{
+			TModID fullModID = rootMod + '.' + modSetting.first;
+			if(!vstd::contains(installedMods, fullModID))
+			{
+				modsPreset->eraseModSetting(rootMod, modSetting.first);
+				continue;
+			}
+		}
+	}
+}
+
+void ModManager::addNewModsToPreset()
+{
+	const TModList & installedMods = modsState->getInstalledMods();
+
+	for(const auto & modID : installedMods)
+	{
+		size_t dotPos = modID.find('.');
+
+		if(dotPos == std::string::npos)
+			continue; // only look up submods aka mod settings
+
+		std::string rootMod = modID.substr(0, dotPos);
+		std::string settingID = modID.substr(dotPos + 1);
+
+		const auto & modSettings = modsPreset->getModSettings(rootMod);
+
+		if (!modSettings.count(settingID))
+			modsPreset->setSettingActive(rootMod, settingID, !modsStorage->getMod(modID).keepDisabled());
+	}
+}
+
+TModList ModManager::collectDependenciesRecursive(const TModID & modID) const
+{
+	TModList result;
+	TModList toTest;
+
+	toTest.push_back(modID);
+	while (!toTest.empty())
+	{
+		TModID currentModID = toTest.back();
+		const auto & currentMod = getModDescription(currentModID);
+		toTest.pop_back();
+		result.push_back(currentModID);
+
+		if (!currentMod.isInstalled())
+			throw std::runtime_error("Unable to enable mod " + modID + "! Dependency " + currentModID + " is not installed!");
+
+		for (const auto & dependency : currentMod.getDependencies())
+		{
+			if (!vstd::contains(result, dependency))
+				toTest.push_back(dependency);
+		}
+	}
+
+	return result;
+}
+
+void ModManager::tryEnableMods(const TModList & modList)
+{
+	TModList requiredActiveMods;
+	TModList additionalActiveMods = getActiveMods();
+
+	for (const auto & modName : modList)
+	{
+		for (const auto & dependency : collectDependenciesRecursive(modName))
+		{
+			if (!vstd::contains(requiredActiveMods, dependency))
+			{
+				requiredActiveMods.push_back(dependency);
+				vstd::erase(additionalActiveMods, dependency);
+			}
+		}
+
+		assert(!vstd::contains(additionalActiveMods, modName));
+		assert(vstd::contains(requiredActiveMods, modName));// FIXME: fails on attempt to enable broken mod / translation to other language
+	}
+
+	ModDependenciesResolver testResolver(requiredActiveMods, *modsStorage);
+
+	testResolver.tryAddMods(additionalActiveMods, *modsStorage);
+
+	TModList additionalActiveSubmods;
+	for (const auto & modName : modList)
+	{
+		if (modName.find('.') != std::string::npos)
+			continue;
+
+		auto modSettings = modsPreset->getModSettings(modName);
+		for (const auto & entry : modSettings)
+		{
+			TModID fullModID = modName + '.' + entry.first;
+			if (entry.second && !vstd::contains(requiredActiveMods, fullModID))
+				additionalActiveSubmods.push_back(fullModID);
+		}
+	}
+
+	testResolver.tryAddMods(additionalActiveSubmods, *modsStorage);
+
+	for (const auto & modName : modList)
+		if (!vstd::contains(testResolver.getActiveMods(), modName))
+			throw std::runtime_error("Failed to enable mod! Mod " + modName + " remains disabled!");
+
+	updatePreset(testResolver);
+}
+
+void ModManager::tryDisableMod(const TModID & modName)
+{
+	auto desiredActiveMods = getActiveMods();
+	assert(vstd::contains(desiredActiveMods, modName));
+
+	vstd::erase(desiredActiveMods, modName);
+
+	ModDependenciesResolver testResolver(desiredActiveMods, *modsStorage);
+
+	if (vstd::contains(testResolver.getActiveMods(), modName))
+		throw std::runtime_error("Failed to disable mod! Mod " + modName + " remains enabled!");
+
+	modsPreset->setModActive(modName, false);
+	updatePreset(testResolver);
+}
+
+void ModManager::updatePreset(const ModDependenciesResolver & testResolver)
+{
+	const auto & newActiveMods = testResolver.getActiveMods();
+	const auto & newBrokenMods = testResolver.getBrokenMods();
+
+	for (const auto & modID : newActiveMods)
+	{
+		assert(vstd::contains(modsState->getInstalledMods(), modID));
+		modsPreset->setModActive(modID, true);
+	}
+
+	for (const auto & modID : newBrokenMods)
+	{
+		const auto & mod = getModDescription(modID);
+		if (vstd::contains(newActiveMods, mod.getTopParentID()))
+			modsPreset->setModActive(modID, false);
+	}
+
+	std::vector<TModID> desiredModList = modsPreset->getActiveMods();
+
+	// Try to enable all existing compatibility patches. Ignore on failure
+	for (const auto & rootMod : modsPreset->getActiveRootMods())
+	{
+		for (const auto & modSetting : modsPreset->getModSettings(rootMod))
+		{
+			if (modSetting.second)
+				continue;
+
+			TModID fullModID = rootMod + '.' + modSetting.first;
+			const auto & modDescription = modsStorage->getMod(fullModID);
+
+			if (modDescription.isCompatibility())
+				desiredModList.push_back(fullModID);
+		}
+	}
+
+	depedencyResolver = std::make_unique<ModDependenciesResolver>(desiredModList, *modsStorage);
+	modsPreset->saveConfigurationState();
+}
+
+ModDependenciesResolver::ModDependenciesResolver(const TModList & modsToResolve, const ModsStorage & storage)
+{
+	tryAddMods(modsToResolve, storage);
+}
+
+const TModList & ModDependenciesResolver::getActiveMods() const
+{
+	return activeMods;
+}
+
+const TModList & ModDependenciesResolver::getBrokenMods() const
+{
+	return brokenMods;
+}
+
+void ModDependenciesResolver::tryAddMods(TModList modsToResolve, const ModsStorage & storage)
+{
+	// Topological sort algorithm.
+	boost::range::sort(modsToResolve); // Sort mods per name
+	std::vector<TModID> sortedValidMods(activeMods.begin(), activeMods.end()); // Vector keeps order of elements (LIFO)
+	std::set<TModID> resolvedModIDs(activeMods.begin(), activeMods.end()); // Use a set for validation for performance reason, but set does not keep order of elements
+	std::set<TModID> notResolvedModIDs(modsToResolve.begin(), modsToResolve.end()); // Use a set for validation for performance reason
+
+	// Mod is resolved if it has no dependencies or all its dependencies are already resolved
+	auto isResolved = [&](const ModDescription & mod) -> bool
+	{
+		if (mod.isTranslation() && CGeneralTextHandler::getPreferredLanguage() != mod.getBaseLanguage())
+			return false;
+
+		if(mod.getDependencies().size() > resolvedModIDs.size())
+			return false;
+
+		for(const TModID & dependency : mod.getDependencies())
+			if(!vstd::contains(resolvedModIDs, dependency))
+				return false;
+
+		for(const TModID & softDependency : mod.getSoftDependencies())
+			if(vstd::contains(notResolvedModIDs, softDependency))
+				return false;
+
+		for(const TModID & conflict : mod.getConflicts())
+			if(vstd::contains(resolvedModIDs, conflict))
+				return false;
+
+		for(const TModID & reverseConflict : resolvedModIDs)
+			if(vstd::contains(storage.getMod(reverseConflict).getConflicts(), mod.getID()))
+				return false;
+
+		return true;
+	};
+
+	while(true)
+	{
+		std::set<TModID> resolvedOnCurrentTreeLevel;
+		for(auto it = modsToResolve.begin(); it != modsToResolve.end();) // One iteration - one level of mods tree
+		{
+			if(isResolved(storage.getMod(*it)))
+			{
+				resolvedOnCurrentTreeLevel.insert(*it); // Not to the resolvedModIDs, so current node children will be resolved on the next iteration
+				assert(!vstd::contains(sortedValidMods, *it));
+				sortedValidMods.push_back(*it);
+				it = modsToResolve.erase(it);
+				continue;
+			}
+			it++;
+		}
+		if(!resolvedOnCurrentTreeLevel.empty())
+		{
+			resolvedModIDs.insert(resolvedOnCurrentTreeLevel.begin(), resolvedOnCurrentTreeLevel.end());
+			for(const auto & it : resolvedOnCurrentTreeLevel)
+				notResolvedModIDs.erase(it);
+			continue;
+		}
+		// If there are no valid mods on the current mods tree level, no more mod can be resolved, should be ended.
+		break;
+	}
+
+	assert(!sortedValidMods.empty());
+	activeMods = sortedValidMods;
+	brokenMods.insert(brokenMods.end(), modsToResolve.begin(), modsToResolve.end());
+}
+
+VCMI_LIB_NAMESPACE_END

+ 144 - 0
lib/modding/ModManager.h

@@ -0,0 +1,144 @@
+/*
+ * ModManager.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "../json/JsonNode.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+class JsonNode;
+class ModDescription;
+struct CModVersion;
+
+using TModID = std::string;
+using TModList = std::vector<TModID>;
+using TModSet = std::set<TModID>;
+
+/// Provides interface to access list of locally installed mods
+class ModsState : boost::noncopyable
+{
+	TModList modList;
+
+	TModList scanModsDirectory(const std::string & modDir) const;
+
+public:
+	ModsState();
+
+	TModList getInstalledMods() const;
+	double getInstalledModSizeMegabytes(const TModID & modName) const;
+
+	uint32_t computeChecksum(const TModID & modName) const;
+};
+
+/// Provides interface to access or change current mod preset
+class ModsPresetState : boost::noncopyable
+{
+	JsonNode modConfig;
+
+	void createInitialPreset();
+	void importInitialPreset();
+
+	const JsonNode & getActivePresetConfig() const;
+
+public:
+	ModsPresetState();
+
+	void setModActive(const TModID & modName, bool isActive);
+
+	void addRootMod(const TModID & modName);
+	void eraseRootMod(const TModID & modName);
+	void removeOldMods(const TModList & modsToKeep);
+
+	void setSettingActive(const TModID & modName, const TModID & settingName, bool isActive);
+	void eraseModSetting(const TModID & modName, const TModID & settingName);
+
+	/// Returns list of all mods active in current preset. Mod order is unspecified
+	TModList getActiveMods() const;
+
+	/// Returns list of currently active root mods (non-submod)
+	TModList getActiveRootMods() const;
+
+	/// Returns list of all known settings (submods) for a specified mod
+	std::map<TModID, bool> getModSettings(const TModID & modID) const;
+	std::optional<uint32_t> getValidatedChecksum(const TModID & modName) const;
+	void setValidatedChecksum(const TModID & modName, std::optional<uint32_t> value);
+
+	void saveConfigurationState() const;
+};
+
+/// Provides access to mod properties
+class ModsStorage : boost::noncopyable
+{
+	std::map<TModID, ModDescription> mods;
+
+public:
+	ModsStorage(const TModList & modsToLoad, const JsonNode & repositoryList);
+
+	const ModDescription & getMod(const TModID & fullID) const;
+
+	TModList getAllMods() const;
+};
+
+class ModDependenciesResolver : boost::noncopyable
+{
+	/// all currently active mods, in their load order
+	TModList activeMods;
+
+	/// Mods from current preset that failed to load due to invalid dependencies
+	TModList brokenMods;
+
+public:
+	ModDependenciesResolver(const TModList & modsToResolve, const ModsStorage & storage);
+
+	void tryAddMods(TModList modsToResolve, const ModsStorage & storage);
+
+	const TModList & getActiveMods() const;
+	const TModList & getBrokenMods() const;
+};
+
+/// Provides public interface to access mod state
+class DLL_LINKAGE ModManager : boost::noncopyable
+{
+	std::unique_ptr<ModsState> modsState;
+	std::unique_ptr<ModsPresetState> modsPreset;
+	std::unique_ptr<ModsStorage> modsStorage;
+	std::unique_ptr<ModDependenciesResolver> depedencyResolver;
+
+	void generateLoadOrder(TModList desiredModList);
+	void eraseMissingModsFromPreset();
+	void addNewModsToPreset();
+	void updatePreset(const ModDependenciesResolver & newData);
+
+	TModList collectDependenciesRecursive(const TModID & modID) const;
+
+	void tryEnableMod(const TModID & modList);
+
+public:
+	ModManager(const JsonNode & repositoryList);
+	ModManager();
+	~ModManager();
+
+	const ModDescription & getModDescription(const TModID & modID) const;
+	const TModList & getActiveMods() const;
+	TModList getAllMods() const;
+
+	bool isModSettingActive(const TModID & rootModID, const TModID & modSettingID) const;
+	bool isModActive(const TModID & modID) const;
+	uint32_t computeChecksum(const TModID & modName) const;
+	std::optional<uint32_t> getValidatedChecksum(const TModID & modName) const;
+	void setValidatedChecksum(const TModID & modName, std::optional<uint32_t> value);
+	void saveConfigurationState() const;
+	double getInstalledModSizeMegabytes(const TModID & modName) const;
+
+	void tryEnableMods(const TModList & modList);
+	void tryDisableMod(const TModID & modName);
+};
+
+VCMI_LIB_NAMESPACE_END

+ 5 - 5
lib/modding/ModVerificationInfo.cpp

@@ -10,8 +10,8 @@
 #include "StdInc.h"
 #include "ModVerificationInfo.h"
 
-#include "CModInfo.h"
 #include "CModHandler.h"
+#include "ModDescription.h"
 #include "ModIncompatibility.h"
 
 #include "../json/JsonNode.h"
@@ -68,7 +68,7 @@ ModListVerificationStatus ModVerificationInfo::verifyListAgainstLocalMods(const
 		if(modList.count(m))
 			continue;
 
-		if(VLC->modh->getModInfo(m).checkModGameplayAffecting())
+		if(VLC->modh->getModInfo(m).affectsGameplay())
 			result[m] = ModVerificationStatus::EXCESSIVE;
 	}
 
@@ -88,8 +88,8 @@ ModListVerificationStatus ModVerificationInfo::verifyListAgainstLocalMods(const
 			continue;
 		}
 
-		auto & localModInfo = VLC->modh->getModInfo(remoteModId).getVerificationInfo();
-		modAffectsGameplay |= VLC->modh->getModInfo(remoteModId).checkModGameplayAffecting();
+		const auto & localVersion = VLC->modh->getModInfo(remoteModId).getVersion();
+		modAffectsGameplay |= VLC->modh->getModInfo(remoteModId).affectsGameplay();
 
 		// skip it. Such mods should only be present in old saves or if mod changed and no longer affects gameplay
 		if (!modAffectsGameplay)
@@ -101,7 +101,7 @@ ModListVerificationStatus ModVerificationInfo::verifyListAgainstLocalMods(const
 			continue;
 		}
 
-		if(remoteModInfo.version != localModInfo.version)
+		if(remoteModInfo.version != localVersion)
 		{
 			result[remoteModId] = ModVerificationStatus::VERSION_MISMATCH;
 			continue;

+ 1 - 1
mapeditor/mapcontroller.cpp

@@ -23,7 +23,7 @@
 #include "../lib/mapping/CMapEditManager.h"
 #include "../lib/mapping/ObstacleProxy.h"
 #include "../lib/modding/CModHandler.h"
-#include "../lib/modding/CModInfo.h"
+#include "../lib/modding/ModDescription.h"
 #include "../lib/TerrainHandler.h"
 #include "../lib/CSkillHandler.h"
 #include "../lib/spells/CSpellHandler.h"

+ 1 - 2
mapeditor/mapcontroller.h

@@ -13,9 +13,8 @@
 #include "maphandler.h"
 #include "mapview.h"
 
-#include "../lib/modding/CModInfo.h"
-
 VCMI_LIB_NAMESPACE_BEGIN
+struct ModVerificationInfo;
 using ModCompatibilityInfo = std::map<std::string, ModVerificationInfo>;
 class EditorObstaclePlacer;
 VCMI_LIB_NAMESPACE_END

+ 5 - 5
mapeditor/mapsettings/modsettings.cpp

@@ -11,9 +11,9 @@
 #include "modsettings.h"
 #include "ui_modsettings.h"
 #include "../mapcontroller.h"
+#include "../../lib/modding/ModDescription.h"
 #include "../../lib/modding/CModHandler.h"
 #include "../../lib/mapping/CMapService.h"
-#include "../../lib/modding/CModInfo.h"
 
 void traverseNode(QTreeWidgetItem * item, std::function<void(QTreeWidgetItem*)> action)
 {
@@ -45,12 +45,12 @@ void ModSettings::initialize(MapController & c)
 	QSet<QString> modsToProcess;
 	ui->treeMods->blockSignals(true);
 
-	auto createModTreeWidgetItem = [&](QTreeWidgetItem * parent, const CModInfo & modInfo)
+	auto createModTreeWidgetItem = [&](QTreeWidgetItem * parent, const ModDescription & modInfo)
 	{
-		auto item = new QTreeWidgetItem(parent, {QString::fromStdString(modInfo.getVerificationInfo().name), QString::fromStdString(modInfo.getVerificationInfo().version.toString())});
-		item->setData(0, Qt::UserRole, QVariant(QString::fromStdString(modInfo.identifier)));
+		auto item = new QTreeWidgetItem(parent, {QString::fromStdString(modInfo.getName()), QString::fromStdString(modInfo.getVersion().toString())});
+		item->setData(0, Qt::UserRole, QVariant(QString::fromStdString(modInfo.getID())));
 		item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
-		item->setCheckState(0, controller->map()->mods.count(modInfo.identifier) ? Qt::Checked : Qt::Unchecked);
+		item->setCheckState(0, controller->map()->mods.count(modInfo.getID()) ? Qt::Checked : Qt::Unchecked);
 		//set parent check
 		if(parent && item->checkState(0) == Qt::Checked)
 			parent->setCheckState(0, Qt::Checked);

+ 1 - 1
mapeditor/validator.cpp

@@ -16,7 +16,7 @@
 #include "../lib/mapping/CMap.h"
 #include "../lib/mapObjects/MapObjects.h"
 #include "../lib/modding/CModHandler.h"
-#include "../lib/modding/CModInfo.h"
+#include "../lib/modding/ModDescription.h"
 #include "../lib/spells/CSpellHandler.h"
 
 Validator::Validator(const CMap * map, QWidget *parent) :

+ 3 - 2
server/GlobalLobbyProcessor.cpp

@@ -15,7 +15,8 @@
 #include "../lib/json/JsonUtils.h"
 #include "../lib/VCMI_Lib.h"
 #include "../lib/modding/CModHandler.h"
-#include "../lib/modding/CModInfo.h"
+#include "../lib/modding/ModDescription.h"
+#include "../lib/modding/ModVerificationInfo.h"
 
 GlobalLobbyProcessor::GlobalLobbyProcessor(CVCMIServer & owner)
 	: owner(owner)
@@ -161,7 +162,7 @@ JsonNode GlobalLobbyProcessor::getHostModList() const
 
 	for (auto const & modName : VLC->modh->getActiveMods())
 	{
-		if(VLC->modh->getModInfo(modName).checkModGameplayAffecting())
+		if(VLC->modh->getModInfo(modName).affectsGameplay())
 			info[modName] = VLC->modh->getModInfo(modName).getVerificationInfo();
 	}
 

+ 4 - 4
vcmiqt/jsonutils.cpp

@@ -79,7 +79,7 @@ QVariant toVariant(const JsonNode & node)
 	return QVariant();
 }
 
-QVariant JsonFromFile(QString filename)
+JsonNode jsonFromFile(QString filename)
 {
 	QFile file(filename);
 	if(!file.open(QFile::ReadOnly))
@@ -90,7 +90,7 @@ QVariant JsonFromFile(QString filename)
 
 	const auto data = file.readAll();
 	JsonNode node(reinterpret_cast<const std::byte*>(data.data()), data.size(), filename.toStdString());
-	return toVariant(node);
+	return node;
 }
 
 JsonNode toJson(QVariant object)
@@ -113,10 +113,10 @@ JsonNode toJson(QVariant object)
 	return ret;
 }
 
-void JsonToFile(QString filename, QVariant object)
+void jsonToFile(QString filename, const JsonNode & object)
 {
 	std::fstream file(qstringToPath(filename).c_str(), std::ios::out | std::ios_base::binary);
-	file << toJson(object).toString();
+	file << object.toCompactString();
 }
 
 }

+ 2 - 2
vcmiqt/jsonutils.h

@@ -20,10 +20,10 @@ class JsonNode;
 namespace JsonUtils
 {
 VCMIQT_LINKAGE QVariant toVariant(const JsonNode & node);
-VCMIQT_LINKAGE QVariant JsonFromFile(QString filename);
+VCMIQT_LINKAGE JsonNode jsonFromFile(QString filename);
 
 VCMIQT_LINKAGE JsonNode toJson(QVariant object);
-VCMIQT_LINKAGE void JsonToFile(QString filename, QVariant object);
+VCMIQT_LINKAGE void jsonToFile(QString filename, const JsonNode & object);
 }
 
 VCMI_LIB_NAMESPACE_END