2007-05-30 21:56:52 +00:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
2007-02-18 18:23:52 +00:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2014-02-18 02:34:20 +01:00
*
2007-02-18 18:23:52 +00:00
*/
2008-05-13 10:41:32 +00:00
# include "engines/metaengine.h"
2008-07-29 16:29:28 +00:00
# include "common/algorithm.h"
2008-06-11 06:22:02 +00:00
# include "common/config-manager.h"
2011-04-24 11:34:27 +03:00
# include "common/debug.h"
# include "common/system.h"
2011-03-31 06:35:43 -04:00
# include "common/taskbar.h"
2010-06-15 10:44:51 +00:00
# include "common/translation.h"
2007-02-18 18:23:52 +00:00
# include "gui/massadd.h"
2011-05-21 15:45:51 +01:00
# ifndef DISABLE_MASS_ADD
2007-02-18 18:23:52 +00:00
namespace GUI {
/*
TODO :
- Themify this dialog
- Add a ListWidget showing all the games we are going to add , and update it live
- Add a ' busy ' mouse cursor ( animated ? ) which indicates to the user that
something is in progress , and show this cursor while we scan
*/
enum {
// Upper bound (im milliseconds) we want to spend in handleTickle.
// Setting this low makes the GUI more responsive but also slows
// down the scanning.
kMaxScanTime = 50
} ;
enum {
kOkCmd = ' OK ' ,
kCancelCmd = ' CNCL '
} ;
2008-10-02 16:58:59 +00:00
MassAddDialog : : MassAddDialog ( const Common : : FSNode & startDir )
2008-10-14 17:53:52 +00:00
: Dialog ( " MassAdd " ) ,
2007-02-18 18:23:52 +00:00
_dirsScanned ( 0 ) ,
2011-05-02 13:39:34 +02:00
_oldGamesCount ( 0 ) ,
2011-03-31 06:35:43 -04:00
_dirTotal ( 0 ) ,
2020-01-05 17:48:04 +01:00
_okButton ( nullptr ) ,
_dirProgressText ( nullptr ) ,
_gameProgressText ( nullptr ) {
2007-02-18 18:23:52 +00:00
2020-06-11 21:25:05 +05:30
U32StringArray l ;
2009-06-06 17:49:59 +00:00
2007-02-18 18:23:52 +00:00
// The dir we start our scan at
_scanStack . push ( startDir ) ;
2011-04-04 12:49:49 -04:00
// Removed for now... Why would you put a title on mass add dialog called "Mass Add Dialog"?
// new StaticTextWidget(this, "massadddialog_caption", "Mass Add Dialog");
2007-02-18 18:23:52 +00:00
2008-10-14 17:53:52 +00:00
_dirProgressText = new StaticTextWidget ( this , " MassAdd.DirProgressText " ,
2020-06-13 22:12:25 +05:30
( _ ( " ... progress ... " ) ) ) ;
2007-02-18 18:23:52 +00:00
2008-10-14 17:53:52 +00:00
_gameProgressText = new StaticTextWidget ( this , " MassAdd.GameProgressText " ,
2020-06-13 22:12:25 +05:30
( _ ( " ... progress ... " ) ) ) ;
2008-12-22 11:22:15 +00:00
2008-10-14 17:53:52 +00:00
_dirProgressText - > setAlign ( Graphics : : kTextAlignCenter ) ;
_gameProgressText - > setAlign ( Graphics : : kTextAlignCenter ) ;
2007-02-18 18:23:52 +00:00
2009-06-06 17:49:59 +00:00
_list = new ListWidget ( this , " MassAdd.GameList " ) ;
_list - > setEditable ( false ) ;
_list - > setNumberingMode ( kListNumberingOff ) ;
_list - > setList ( l ) ;
2020-06-13 23:06:08 +05:30
_okButton = new ButtonWidget ( this , " MassAdd.Ok " , Common : : U32String ( " Ok " ) , Common : : U32String ( " " ) , kOkCmd , Common : : ASCII_RETURN ) ;
2007-02-18 18:23:52 +00:00
_okButton - > setEnabled ( false ) ;
2020-06-13 23:06:08 +05:30
new ButtonWidget ( this , " MassAdd.Cancel " , Common : : U32String ( " Cancel " ) , Common : : U32String ( " " ) , kCancelCmd , Common : : ASCII_ESCAPE ) ;
2007-02-18 18:23:52 +00:00
2008-06-11 06:22:02 +00:00
// Build a map from all configured game paths to the targets using them
const Common : : ConfigManager : : DomainMap & domains = ConfMan . getGameDomains ( ) ;
Common : : ConfigManager : : DomainMap : : const_iterator iter ;
for ( iter = domains . begin ( ) ; iter ! = domains . end ( ) ; + + iter ) {
# ifdef __DS__
// DS port uses an extra section called 'ds'. This prevents the section from being
// detected as a game.
if ( iter - > _key = = " ds " ) {
continue ;
}
# endif
2010-03-29 20:31:23 +00:00
Common : : String path ( iter - > _value . getVal ( " path " ) ) ;
2008-06-11 06:22:02 +00:00
// Remove trailing slash, so that "/foo" and "/foo/" match.
// This works around a bug in the POSIX FS code (and others?)
// where paths are not normalized (so FSNodes refering to identical
// FS objects may return different values in path()).
while ( path ! = " / " & & path . lastChar ( ) = = ' / ' )
path . deleteLastChar ( ) ;
if ( ! path . empty ( ) )
_pathToTargets [ path ] . push_back ( iter - > _key ) ;
}
2007-02-18 18:23:52 +00:00
}
2009-06-06 17:49:59 +00:00
struct GameTargetLess {
2018-05-06 15:51:03 +02:00
bool operator ( ) ( const DetectedGame & x , const DetectedGame & y ) const {
2017-12-03 12:19:08 +01:00
return x . preferredTarget . compareToIgnoreCase ( y . preferredTarget ) < 0 ;
2008-07-29 16:29:28 +00:00
}
} ;
2009-06-06 17:49:59 +00:00
struct GameDescLess {
2018-05-06 15:51:03 +02:00
bool operator ( ) ( const DetectedGame & x , const DetectedGame & y ) const {
2017-12-03 12:19:08 +01:00
return x . description . compareToIgnoreCase ( y . description ) < 0 ;
2009-06-06 17:49:59 +00:00
}
} ;
2007-02-18 18:23:52 +00:00
void MassAddDialog : : handleCommand ( CommandSender * sender , uint32 cmd , uint32 data ) {
2011-04-29 12:15:49 -04:00
# if defined(USE_TASKBAR)
2011-04-04 12:49:49 -04:00
// Remove progress bar and count from taskbar
2011-03-31 06:35:43 -04:00
g_system - > getTaskbarManager ( ) - > setProgressState ( Common : : TaskbarManager : : kTaskbarNoProgress ) ;
2011-04-04 12:49:49 -04:00
g_system - > getTaskbarManager ( ) - > setCount ( 0 ) ;
2011-04-29 12:15:49 -04:00
# endif
2011-03-31 06:35:43 -04:00
2007-02-18 18:23:52 +00:00
// FIXME: It's a really bad thing that we use two arbitrary constants
if ( cmd = = kOkCmd ) {
2008-07-29 16:29:28 +00:00
// Sort the detected games. This is not strictly necessary, but nice for
// people who want to edit their config file by hand after a mass add.
2017-12-03 12:19:08 +01:00
Common : : sort ( _games . begin ( ) , _games . end ( ) , GameTargetLess ( ) ) ;
2007-02-18 18:23:52 +00:00
// Add all the detected games to the config
2018-05-06 15:51:03 +02:00
for ( DetectedGames : : iterator iter = _games . begin ( ) ; iter ! = _games . end ( ) ; + + iter ) {
2009-12-15 08:19:34 +00:00
debug ( 1 , " Added gameid '%s', desc '%s' \n " ,
2017-12-03 12:19:08 +01:00
iter - > gameId . c_str ( ) ,
iter - > description . c_str ( ) ) ;
2018-02-04 08:46:12 +01:00
iter - > gameId = EngineMan . createTargetForGame ( * iter ) ;
2007-02-18 18:23:52 +00:00
}
// Write everything to disk
ConfMan . flushToDisk ( ) ;
2009-06-06 17:49:59 +00:00
// And scroll to first detected game
2009-09-15 14:34:21 +00:00
if ( ! _games . empty ( ) ) {
2017-12-03 12:19:08 +01:00
Common : : sort ( _games . begin ( ) , _games . end ( ) , GameDescLess ( ) ) ;
ConfMan . set ( " temp_selection " , _games . front ( ) . gameId ) ;
2009-09-15 14:34:21 +00:00
}
2009-06-06 17:49:59 +00:00
2007-02-18 18:23:52 +00:00
close ( ) ;
} else if ( cmd = = kCancelCmd ) {
// User cancelled, so we don't do anything and just leave.
2009-12-15 08:19:34 +00:00
_games . clear ( ) ;
2007-02-18 18:23:52 +00:00
close ( ) ;
} else {
Dialog : : handleCommand ( sender , cmd , data ) ;
}
}
void MassAddDialog : : handleTickle ( ) {
if ( _scanStack . empty ( ) )
return ; // We have finished scanning
uint32 t = g_system - > getMillis ( ) ;
// Perform a breadth-first scan of the filesystem.
while ( ! _scanStack . empty ( ) & & ( g_system - > getMillis ( ) - t ) < kMaxScanTime ) {
2008-10-02 16:58:59 +00:00
Common : : FSNode dir = _scanStack . pop ( ) ;
2007-09-19 08:40:12 +00:00
2008-09-03 11:22:51 +00:00
Common : : FSList files ;
2008-10-02 16:58:59 +00:00
if ( ! dir . getChildren ( files , Common : : FSNode : : kListAll ) ) {
2009-02-17 21:02:47 +00:00
continue ;
2007-02-18 18:23:52 +00:00
}
2007-09-19 08:40:12 +00:00
2007-02-18 18:23:52 +00:00
// Run the detector on the dir
2017-12-02 17:14:22 +01:00
DetectionResults detectionResults = EngineMan . detectGames ( files ) ;
if ( detectionResults . foundUnknownGames ( ) ) {
Common : : String report = detectionResults . generateUnknownGameReport ( false , 80 ) ;
g_system - > logMessage ( LogMessageType : : kInfo , report . c_str ( ) ) ;
}
2007-09-19 08:40:12 +00:00
2008-03-29 23:20:53 +00:00
// Just add all detected games / game variants. If we get more than one,
// that either means the directory contains multiple games, or the detector
// could not fully determine which game variant it was seeing. In either
// case, let the user choose which entries he wants to keep.
2008-06-11 06:22:02 +00:00
//
// However, we only add games which are not already in the config file.
2017-12-02 17:14:22 +01:00
DetectedGames candidates = detectionResults . listRecognizedGames ( ) ;
for ( DetectedGames : : const_iterator cand = candidates . begin ( ) ; cand ! = candidates . end ( ) ; + + cand ) {
2018-05-06 15:51:03 +02:00
const DetectedGame & result = * cand ;
2008-06-11 06:22:02 +00:00
Common : : String path = dir . getPath ( ) ;
// Remove trailing slashes
while ( path ! = " / " & & path . lastChar ( ) = = ' / ' )
path . deleteLastChar ( ) ;
2016-09-15 18:39:45 +02:00
// Check for existing config entries for this path/engineid/gameid/lang/platform combination
2008-06-11 06:22:02 +00:00
if ( _pathToTargets . contains ( path ) ) {
2018-06-30 19:12:56 +02:00
Common : : String resultPlatformCode = Common : : getPlatformCode ( result . platform ) ;
Common : : String resultLanguageCode = Common : : getLanguageCode ( result . language ) ;
2017-12-03 12:19:08 +01:00
2008-06-11 06:22:02 +00:00
bool duplicate = false ;
2010-03-18 15:09:24 +00:00
const StringArray & targets = _pathToTargets [ path ] ;
for ( StringArray : : const_iterator iter = targets . begin ( ) ; iter ! = targets . end ( ) ; + + iter ) {
2016-09-15 18:39:45 +02:00
// If the engineid, gameid, platform and language match -> skip it
2008-06-11 06:22:02 +00:00
Common : : ConfigManager : : Domain * dom = ConfMan . getDomain ( * iter ) ;
assert ( dom ) ;
2016-09-15 18:39:45 +02:00
if ( ( * dom ) [ " engineid " ] = = result . engineId & &
( * dom ) [ " gameid " ] = = result . gameId & &
2017-12-03 12:19:08 +01:00
( * dom ) [ " platform " ] = = resultPlatformCode & &
( * dom ) [ " language " ] = = resultLanguageCode ) {
2008-06-11 06:22:02 +00:00
duplicate = true ;
break ;
}
}
2011-05-02 13:39:34 +02:00
if ( duplicate ) {
_oldGamesCount + + ;
2018-09-23 07:00:11 +02:00
continue ; // Skip duplicates
2011-05-02 13:39:34 +02:00
}
2008-06-11 06:22:02 +00:00
}
2007-02-18 18:23:52 +00:00
_games . push_back ( result ) ;
2009-06-06 17:49:59 +00:00
2017-12-03 12:19:08 +01:00
_list - > append ( result . description ) ;
2007-02-18 18:23:52 +00:00
}
2007-09-19 08:40:12 +00:00
2007-02-18 18:23:52 +00:00
// Recurse into all subdirs
2008-09-03 11:22:51 +00:00
for ( Common : : FSList : : const_iterator file = files . begin ( ) ; file ! = files . end ( ) ; + + file ) {
2007-02-18 18:23:52 +00:00
if ( file - > isDirectory ( ) ) {
_scanStack . push ( * file ) ;
2011-03-31 06:35:43 -04:00
_dirTotal + + ;
2007-02-18 18:23:52 +00:00
}
}
_dirsScanned + + ;
2011-03-31 06:35:43 -04:00
2011-04-29 12:15:49 -04:00
# if defined(USE_TASKBAR)
2011-03-31 06:35:43 -04:00
g_system - > getTaskbarManager ( ) - > setProgressValue ( _dirsScanned , _dirTotal ) ;
2011-04-04 12:49:49 -04:00
g_system - > getTaskbarManager ( ) - > setCount ( _games . size ( ) ) ;
2011-04-29 12:15:49 -04:00
# endif
2007-02-18 18:23:52 +00:00
}
2007-09-19 08:40:12 +00:00
2007-02-18 18:23:52 +00:00
// Update the dialog
2020-06-13 22:12:25 +05:30
Common : : U32String buf ;
2007-02-18 18:23:52 +00:00
if ( _scanStack . empty ( ) ) {
// Enable the OK button
_okButton - > setEnabled ( true ) ;
2011-06-02 00:07:18 +02:00
buf = _ ( " Scan complete! " ) ;
2007-02-18 18:23:52 +00:00
_dirProgressText - > setLabel ( buf ) ;
2007-09-19 08:40:12 +00:00
2020-06-15 00:55:56 +05:30
buf = Common : : String : : format ( Common : : convertFromU32String ( _ ( " Discovered %d new games, ignored %d previously added games. " ) ) . c_str ( ) , _games . size ( ) , _oldGamesCount ) ;
2007-02-18 18:23:52 +00:00
_gameProgressText - > setLabel ( buf ) ;
} else {
2020-06-15 00:55:56 +05:30
buf = Common : : String : : format ( Common : : convertFromU32String ( _ ( " Scanned %d directories ... " ) ) . c_str ( ) , _dirsScanned ) ;
2007-02-18 18:23:52 +00:00
_dirProgressText - > setLabel ( buf ) ;
2007-09-19 08:40:12 +00:00
2020-06-15 00:55:56 +05:30
buf = Common : : String : : format ( Common : : convertFromU32String ( _ ( " Discovered %d new games, ignored %d previously added games ... " ) ) . c_str ( ) , _games . size ( ) , _oldGamesCount ) ;
2007-02-18 18:23:52 +00:00
_gameProgressText - > setLabel ( buf ) ;
}
2009-06-06 17:49:59 +00:00
if ( _games . size ( ) > 0 ) {
_list - > scrollToEnd ( ) ;
}
2018-01-07 10:39:22 +01:00
drawDialog ( kDrawLayerForeground ) ;
2007-02-18 18:23:52 +00:00
}
2009-10-04 21:26:33 +00:00
} // End of namespace GUI
2007-02-18 18:23:52 +00:00
2011-05-21 15:45:51 +01:00
# endif // DISABLE_MASS_ADD