2013-02-25 20:22:07 +00:00
# include "launchersettings.hpp"
2013-02-11 14:01:00 +00:00
# include <QTextStream>
# include <QString>
# include <QRegExp>
2020-06-24 10:51:26 +00:00
# include <QMultiMap>
2013-02-11 14:01:00 +00:00
2013-11-04 03:36:41 +00:00
# include <QDebug>
2020-04-26 13:31:39 +00:00
# include <components/files/configurationmanager.hpp>
2015-01-10 05:46:47 +00:00
const char Config : : LauncherSettings : : sCurrentContentListKey [ ] = " Profiles/currentprofile " ;
const char Config : : LauncherSettings : : sLauncherConfigFileName [ ] = " launcher.cfg " ;
const char Config : : LauncherSettings : : sContentListsSectionPrefix [ ] = " Profiles/ " ;
2020-04-26 13:31:39 +00:00
const char Config : : LauncherSettings : : sDirectoryListSuffix [ ] = " /data " ;
const char Config : : LauncherSettings : : sArchiveListSuffix [ ] = " /fallback-archive " ;
2015-01-10 05:46:47 +00:00
const char Config : : LauncherSettings : : sContentListSuffix [ ] = " /content " ;
2013-12-24 23:50:25 +00:00
QStringList Config : : LauncherSettings : : subKeys ( const QString & key )
2013-02-15 00:20:48 +00:00
{
2020-06-24 10:51:26 +00:00
QMultiMap < QString , QString > settings = SettingsBase : : getSettings ( ) ;
2013-02-19 14:58:01 +00:00
QStringList keys = settings . uniqueKeys ( ) ;
2013-02-15 00:20:48 +00:00
QRegExp keyRe ( " (.+) / " ) ;
QStringList result ;
2019-10-06 11:39:27 +00:00
for ( const QString & currentKey : keys )
{
2014-04-16 14:54:55 +00:00
if ( keyRe . indexIn ( currentKey ) ! = - 1 )
{
2013-02-15 00:20:48 +00:00
QString prefixedKey = keyRe . cap ( 1 ) ;
2014-04-16 14:54:55 +00:00
if ( prefixedKey . startsWith ( key ) )
{
2013-02-15 00:20:48 +00:00
QString subKey = prefixedKey . remove ( key ) ;
if ( ! subKey . isEmpty ( ) )
result . append ( subKey ) ;
}
}
}
result . removeDuplicates ( ) ;
return result ;
}
2013-02-11 14:01:00 +00:00
2015-01-10 05:46:47 +00:00
2013-12-24 23:50:25 +00:00
bool Config : : LauncherSettings : : writeFile ( QTextStream & stream )
2013-02-11 14:01:00 +00:00
{
QString sectionPrefix ;
QRegExp sectionRe ( " ([^/]+) / ( . + ) $ " ) ;
2020-06-24 10:51:26 +00:00
QMultiMap < QString , QString > settings = SettingsBase : : getSettings ( ) ;
2013-02-11 14:01:00 +00:00
QMapIterator < QString , QString > i ( settings ) ;
2013-02-19 14:58:01 +00:00
i . toBack ( ) ;
while ( i . hasPrevious ( ) ) {
i . previous ( ) ;
2013-02-11 14:01:00 +00:00
QString prefix ;
QString key ;
if ( sectionRe . exactMatch ( i . key ( ) ) ) {
prefix = sectionRe . cap ( 1 ) ;
key = sectionRe . cap ( 2 ) ;
}
2013-02-24 23:56:04 +00:00
// Get rid of legacy settings
if ( key . contains ( QChar ( ' \\ ' ) ) )
continue ;
if ( key = = QLatin1String ( " CurrentProfile " ) )
continue ;
2013-02-11 14:01:00 +00:00
if ( sectionPrefix ! = prefix ) {
sectionPrefix = prefix ;
stream < < " \n [ " < < prefix < < " ] \n " ;
}
stream < < key < < " = " < < i . value ( ) < < " \n " ;
}
return true ;
}
2015-01-10 05:46:47 +00:00
QStringList Config : : LauncherSettings : : getContentLists ( )
{
return subKeys ( QString ( sContentListsSectionPrefix ) ) ;
}
2020-04-26 13:31:39 +00:00
QString Config : : LauncherSettings : : makeDirectoryListKey ( const QString & contentListName )
{
return QString ( sContentListsSectionPrefix ) + contentListName + QString ( sDirectoryListSuffix ) ;
}
QString Config : : LauncherSettings : : makeArchiveListKey ( const QString & contentListName )
{
return QString ( sContentListsSectionPrefix ) + contentListName + QString ( sArchiveListSuffix ) ;
}
2015-01-10 05:46:47 +00:00
QString Config : : LauncherSettings : : makeContentListKey ( const QString & contentListName )
{
return QString ( sContentListsSectionPrefix ) + contentListName + QString ( sContentListSuffix ) ;
}
void Config : : LauncherSettings : : setContentList ( const GameSettings & gameSettings )
{
// obtain content list from game settings (if present)
2020-04-26 13:31:39 +00:00
QStringList dirs ( gameSettings . getDataDirs ( ) ) ;
const QStringList archives ( gameSettings . getArchiveList ( ) ) ;
2015-01-10 05:46:47 +00:00
const QStringList files ( gameSettings . getContentList ( ) ) ;
2015-02-21 19:46:12 +00:00
// if openmw.cfg has no content, exit so we don't create an empty content list.
2020-04-26 13:31:39 +00:00
if ( dirs . isEmpty ( ) | | files . isEmpty ( ) )
2015-02-21 19:46:12 +00:00
{
return ;
}
2020-04-26 13:31:39 +00:00
// global and local data directories are not part of any profile
2022-06-19 11:28:33 +00:00
const auto globalDataDir = QString ( gameSettings . getGlobalDataDir ( ) . string ( ) . c_str ( ) ) ; //TODO(Project579): This will probably break in windows with unicode paths
2020-04-26 13:31:39 +00:00
const auto dataLocal = gameSettings . getDataLocal ( ) ;
dirs . removeAll ( globalDataDir ) ;
dirs . removeAll ( dataLocal ) ;
2015-01-10 05:46:47 +00:00
// if any existing profile in launcher matches the content list, make that profile the default
2019-10-06 11:39:27 +00:00
for ( const QString & listName : getContentLists ( ) )
2015-01-10 05:46:47 +00:00
{
2020-04-26 13:31:39 +00:00
if ( isEqual ( files , getContentListFiles ( listName ) ) & &
isEqual ( archives , getArchiveList ( listName ) ) & &
isEqual ( dirs , getDataDirectoryList ( listName ) ) )
2015-01-10 05:46:47 +00:00
{
setCurrentContentListName ( listName ) ;
return ;
}
}
// otherwise, add content list
QString newContentListName ( makeNewContentListName ( ) ) ;
setCurrentContentListName ( newContentListName ) ;
2020-04-26 13:31:39 +00:00
setContentList ( newContentListName , dirs , archives , files ) ;
2015-01-10 05:46:47 +00:00
}
void Config : : LauncherSettings : : removeContentList ( const QString & contentListName )
{
2020-04-26 13:31:39 +00:00
remove ( makeDirectoryListKey ( contentListName ) ) ;
remove ( makeArchiveListKey ( contentListName ) ) ;
2015-01-10 05:46:47 +00:00
remove ( makeContentListKey ( contentListName ) ) ;
}
void Config : : LauncherSettings : : setCurrentContentListName ( const QString & contentListName )
{
remove ( QString ( sCurrentContentListKey ) ) ;
setValue ( QString ( sCurrentContentListKey ) , contentListName ) ;
}
2020-04-26 13:31:39 +00:00
void Config : : LauncherSettings : : setContentList ( const QString & contentListName , const QStringList & dirNames , const QStringList & archiveNames , const QStringList & fileNames )
2015-01-10 05:46:47 +00:00
{
2020-04-26 13:31:39 +00:00
auto const assign = [ this ] ( const QString key , const QStringList & list )
2015-01-10 05:46:47 +00:00
{
2020-04-26 13:31:39 +00:00
for ( auto const & item : list )
setMultiValue ( key , item ) ;
} ;
removeContentList ( contentListName ) ;
assign ( makeDirectoryListKey ( contentListName ) , dirNames ) ;
assign ( makeArchiveListKey ( contentListName ) , archiveNames ) ;
assign ( makeContentListKey ( contentListName ) , fileNames ) ;
2015-01-10 05:46:47 +00:00
}
QString Config : : LauncherSettings : : getCurrentContentListName ( ) const
{
return value ( QString ( sCurrentContentListKey ) ) ;
}
2020-04-26 13:31:39 +00:00
QStringList Config : : LauncherSettings : : getDataDirectoryList ( const QString & contentListName ) const
{
// QMap returns multiple rows in LIFO order, so need to reverse
return reverse ( getSettings ( ) . values ( makeDirectoryListKey ( contentListName ) ) ) ;
}
QStringList Config : : LauncherSettings : : getArchiveList ( const QString & contentListName ) const
{
// QMap returns multiple rows in LIFO order, so need to reverse
return reverse ( getSettings ( ) . values ( makeArchiveListKey ( contentListName ) ) ) ;
}
2015-01-10 05:46:47 +00:00
QStringList Config : : LauncherSettings : : getContentListFiles ( const QString & contentListName ) const
{
// QMap returns multiple rows in LIFO order, so need to reverse
return reverse ( getSettings ( ) . values ( makeContentListKey ( contentListName ) ) ) ;
}
QStringList Config : : LauncherSettings : : reverse ( const QStringList & toReverse )
{
QStringList result ;
result . reserve ( toReverse . size ( ) ) ;
std : : reverse_copy ( toReverse . begin ( ) , toReverse . end ( ) , std : : back_inserter ( result ) ) ;
return result ;
}
bool Config : : LauncherSettings : : isEqual ( const QStringList & list1 , const QStringList & list2 )
{
if ( list1 . count ( ) ! = list2 . count ( ) )
{
return false ;
}
for ( int i = 0 ; i < list1 . count ( ) ; + + i )
{
if ( list1 . at ( i ) ! = list2 . at ( i ) )
{
return false ;
}
}
// if get here, lists are same
return true ;
}
QString Config : : LauncherSettings : : makeNewContentListName ( )
{
// basically, use date and time as the name e.g. YYYY-MM-DDThh:mm:ss
time_t rawtime ;
struct tm * timeinfo ;
time ( & rawtime ) ;
timeinfo = localtime ( & rawtime ) ;
int base = 10 ;
QChar zeroPad ( ' 0 ' ) ;
return QString ( " %1-%2-%3T%4:%5:%6 " )
. arg ( timeinfo - > tm_year + 1900 , 4 ) . arg ( timeinfo - > tm_mon + 1 , 2 , base , zeroPad ) . arg ( timeinfo - > tm_mday , 2 , base , zeroPad )
. arg ( timeinfo - > tm_hour , 2 , base , zeroPad ) . arg ( timeinfo - > tm_min , 2 , base , zeroPad ) . arg ( timeinfo - > tm_sec , 2 , base , zeroPad ) ;
}