1 /*
2  * Hedgewars, a free turn based strategy game
3  * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; version 2 of the License
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 /**
20  * @file
21  * @brief DataManager class implementation
22  */
23 
24 #include <QMap>
25 #include <QStringList>
26 #include <QStandardItemModel>
27 #include <QFileInfo>
28 #include <QSettings>
29 #include <QColor>
30 
31 #include <SDL.h>
32 
33 #include "hwconsts.h"
34 #include "HWApplication.h"
35 #include "sdlkeys.h"
36 #include "KeyMap.h"
37 #include "physfs.h"
38 
39 #include "DataManager.h"
40 
41 #include "GameStyleModel.h"
42 #include "HatModel.h"
43 #include "MapModel.h"
44 #include "ThemeModel.h"
45 
DataManager()46 DataManager::DataManager()
47 {
48     m_hatModel = NULL;
49     m_staticMapModel = NULL;
50     m_missionMapModel = NULL;
51     m_themeModel = NULL;
52     m_colorsModel = NULL;
53     m_bindsModel = NULL;
54     m_gameStyleModel = NULL;
55 }
56 
57 
instance()58 DataManager & DataManager::instance()
59 {
60     static DataManager instance;
61     return instance;
62 }
63 
64 
entryList(const QString & subDirectory,QDir::Filters filters,const QStringList & nameFilters,bool withDLC) const65 QStringList DataManager::entryList(
66     const QString & subDirectory,
67     QDir::Filters filters,
68     const QStringList & nameFilters,
69     bool withDLC
70 ) const
71 {
72     QDir tmpDir(QString("physfs://%1").arg(subDirectory));
73     QStringList result = tmpDir.entryList(nameFilters, filters);
74 
75     // sort case-insensitive
76     QMap<QString, QString> sortedFileNames;
77     QString absolutePath = datadir->absolutePath().toLocal8Bit().data();
78     foreach ( QString fn, result)
79     {
80         // Filter out DLC entries if desired
81         QString realDir = PHYSFS_getRealDir(QString(subDirectory + "/" + fn).toLocal8Bit().data());
82         if(withDLC || realDir == absolutePath)
83             sortedFileNames.insert(fn.toLower(), fn);
84     }
85     result = sortedFileNames.values();
86 
87     return result;
88 }
89 
gameStyleModel()90 GameStyleModel * DataManager::gameStyleModel()
91 {
92     if (m_gameStyleModel == NULL) {
93         m_gameStyleModel = new GameStyleModel();
94         m_gameStyleModel->loadGameStyles();
95     }
96     return m_gameStyleModel;
97 }
98 
hatModel()99 HatModel * DataManager::hatModel()
100 {
101     if (m_hatModel == NULL) {
102         m_hatModel = new HatModel();
103         m_hatModel->loadHats();
104     }
105     return m_hatModel;
106 }
107 
staticMapModel()108 MapModel * DataManager::staticMapModel()
109 {
110     if (m_staticMapModel == NULL) {
111         m_staticMapModel = new MapModel(MapModel::StaticMap, this);
112     }
113     return m_staticMapModel;
114 }
115 
missionMapModel()116 MapModel * DataManager::missionMapModel()
117 {
118     if (m_missionMapModel == NULL) {
119         m_missionMapModel = new MapModel(MapModel::MissionMap, this);
120     }
121     return m_missionMapModel;
122 }
123 
themeModel()124 ThemeModel * DataManager::themeModel()
125 {
126     if (m_themeModel == NULL) {
127         m_themeModel = new ThemeModel();
128     }
129     return m_themeModel;
130 }
131 
colorsModel()132 QStandardItemModel * DataManager::colorsModel()
133 {
134     if(m_colorsModel == NULL)
135     {
136         m_colorsModel = new QStandardItemModel();
137 
138         int i = 0;
139         while(colors[i])
140         {
141             QStandardItem * item = new QStandardItem();
142             item->setData(QColor(colors[i]));
143             m_colorsModel->appendRow(item);
144             ++i;
145         }
146     }
147 
148     return m_colorsModel;
149 }
150 
bindsModel()151 QStandardItemModel * DataManager::bindsModel()
152 {
153     KeyMap km = KeyMap::instance();
154     if(m_bindsModel == NULL)
155     {
156         m_bindsModel = new QStandardItemModel();
157 
158         QStandardItem * firstItem = new QStandardItem();
159         firstItem->setData(tr("Use Default"), Qt::DisplayRole);
160         firstItem->setData("default", Qt::UserRole + 1);
161         m_bindsModel->appendRow(firstItem);
162 
163         for(int j = 0; sdlkeys[j][1][0] != '\0'; j++)
164         {
165             QStandardItem * item = new QStandardItem();
166             QString keyId = QString(sdlkeys[j][0]);
167             QString keyDisplay;
168             bool isKeyboard = sdlkeys_iskeyboard[j] == true;
169             if (keyId == "none" || (!isKeyboard))
170                 keyDisplay = HWApplication::translate("binds (keys)", sdlkeys[j][1]);
171             else
172                 // Get key name with respect to keyboard layout
173                 keyDisplay = QString(SDL_GetKeyName(SDL_GetKeyFromScancode(km.getScancodeFromKeyname(sdlkeys[j][0]))));
174 
175             bool kbFallback = keyDisplay.trimmed().isEmpty();
176             if (kbFallback)
177             {
178                 keyDisplay = QString(sdlkeys[j][1]);
179                 if ((QString(sdlkeys[j][0]) != "f13") && (QString(sdlkeys[j][0]) != "f14") && (QString(sdlkeys[j][0]) != "f15"))
180                 {
181                     // If SDL doesn't know a name, show fallback name and a warning
182                     //: Name of QWERTY US keyboard layout
183                     keyDisplay = keyDisplay + QString(" ") + HWApplication::translate("binds (keys)", "(QWERTY)");
184                 }
185             }
186             if (isKeyboard)
187             {
188                 if (!kbFallback)
189                     keyDisplay = HWApplication::translate("binds (keys)", keyDisplay.toUtf8().constData());
190                 keyDisplay = HWApplication::translate("binds (keys)", "Keyboard") + QString(": ") + keyDisplay;
191             }
192             item->setData(keyDisplay, Qt::DisplayRole);
193             item->setData(sdlkeys[j][0], Qt::UserRole + 1);
194             m_bindsModel->appendRow(item);
195         }
196     }
197 
198     return m_bindsModel;
199 }
200 
settingsFileName()201 QString DataManager::settingsFileName()
202 {
203     if(m_settingsFileName.isEmpty())
204     {
205         QFile settingsFile(cfgdir->absoluteFilePath("settings.ini"));
206 
207         if(!settingsFile.exists())
208         {
209             QFile oldSettingsFile(cfgdir->absoluteFilePath("hedgewars.ini"));
210 
211             settingsFile.open(QFile::WriteOnly);
212             settingsFile.close();
213 
214             if(oldSettingsFile.exists())
215             {
216                 QSettings sOld(oldSettingsFile.fileName(), QSettings::IniFormat);
217                 QSettings sNew(settingsFile.fileName(), QSettings::IniFormat);
218                 sNew.setIniCodec("UTF-8");
219 
220                 foreach(const QString & key, sOld.allKeys())
221                 {
222                     if(key.startsWith("colors/color"))
223                         sNew.setValue(key, sOld.value(key).value<QColor>().name());
224                     else
225                         sNew.setValue(key, sOld.value(key));
226                 }
227             }
228         }
229 
230         m_settingsFileName = settingsFile.fileName();
231     }
232 
233     return m_settingsFileName;
234 }
235 
safeFileName(QString fileName)236 QString DataManager::safeFileName(QString fileName)
237 {
238     fileName.replace('\\', '_');
239     fileName.replace('/', '_');
240     fileName.replace(':', '_');
241 
242     return fileName;
243 }
244 
reload()245 void DataManager::reload()
246 {
247     // removed for now (also code was a bit unclean, could lead to segfault if
248     // reload() is called before all members are initialized - because currently
249     // they are initialized in the getter methods rather than the constructor)
250 }
251 
resetColors()252 void DataManager::resetColors()
253 {
254     for(int i = colorsModel()->rowCount() - 1; i >= 0; --i)
255     {
256         m_colorsModel->item(i)->setData(QColor(colors[i]));
257     }
258 }
259 
ensureFileExists(const QString & fileName)260 bool DataManager::ensureFileExists(const QString &fileName)
261 {
262     QFile tmpfile(fileName);
263     if (!tmpfile.exists())
264         return tmpfile.open(QFile::WriteOnly);
265     else
266         return true;
267 }
268