/*
patience - - main program
Copyright ( C ) 1995 Paul Olav Tvete
Permission to use , copy , modify , and distribute this software and its
documentation for any purpose and without fee is hereby granted ,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation .
This file is provided AS IS with no warranties of any kind . The author
shall have no liability with respect to the infringement of copyrights ,
trade secrets or any patents by this file or any part thereof . In no
event will the author be liable for any lost revenue or profits or
other special , indirect and consequential damages .
Heavily modified by Mario Weilguni < mweilguni @ sime . com >
*/
# include <stdio.h>
# include <tqregexp.h>
# include <tqtimer.h>
# include <tqimage.h>
# include <kapplication.h>
# include <klocale.h>
# include <kaction.h>
# include <kdebug.h>
# include <kcarddialog.h>
# include <kinputdialog.h>
# include <kstandarddirs.h>
# include <kfiledialog.h>
# include <ktempfile.h>
# include <kio/netaccess.h>
# include <kmessagebox.h>
# include <kstatusbar.h>
# include <kaccelmanager.h>
# include <kmenubar.h>
# include "pwidget.h"
# include "version.h"
# include "dealer.h"
# include "cardmaps.h"
# include "speeds.h"
# include "gamestatsimpl.h"
static pWidget * current_pwidget = 0 ;
void saveGame ( int ) {
current_pwidget - > saveGame ( ) ;
}
pWidget : : pWidget ( )
: KMainWindow ( 0 , " pwidget " ) , dill ( 0 )
{
current_pwidget = this ;
// KCrash::setEmergencySaveFunction(::saveGame);
KStdAction : : quit ( TQT_TQOBJECT ( kapp ) , TQT_SLOT ( quit ( ) ) , actionCollection ( ) , " game_exit " ) ;
undo = KStdAction : : undo ( TQT_TQOBJECT ( this ) , TQT_SLOT ( undoMove ( ) ) ,
actionCollection ( ) , " undo_move " ) ;
undo - > setEnabled ( false ) ;
( void ) KStdAction : : openNew ( TQT_TQOBJECT ( this ) , TQT_SLOT ( newGame ( ) ) ,
actionCollection ( ) , " new_game " ) ;
( void ) KStdAction : : open ( TQT_TQOBJECT ( this ) , TQT_SLOT ( openGame ( ) ) ,
actionCollection ( ) , " open " ) ;
recent = KStdAction : : openRecent ( TQT_TQOBJECT ( this ) , TQT_SLOT ( openGame ( const KURL & ) ) ,
actionCollection ( ) , " open_recent " ) ;
recent - > loadEntries ( KGlobal : : config ( ) ) ;
( void ) KStdAction : : saveAs ( TQT_TQOBJECT ( this ) , TQT_SLOT ( saveGame ( ) ) ,
actionCollection ( ) , " save " ) ;
( void ) new KAction ( i18n ( " &Choose Game... " ) , 0 , TQT_TQOBJECT ( this ) , TQT_SLOT ( chooseGame ( ) ) ,
actionCollection ( ) , " choose_game " ) ;
( void ) new KAction ( i18n ( " Restart &Game " ) , TQString : : tqfromLatin1 ( " reload " ) , 0 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( restart ( ) ) ,
actionCollection ( ) , " restart_game " ) ;
( void ) KStdAction : : help ( TQT_TQOBJECT ( this ) , TQT_SLOT ( helpGame ( ) ) , actionCollection ( ) , " help_game " ) ;
games = new KSelectAction ( i18n ( " &Game Type " ) , 0 , TQT_TQOBJECT ( this ) ,
TQT_SLOT ( newGameType ( ) ) ,
actionCollection ( ) , " game_type " ) ;
TQStringList list ;
TQValueList < DealerInfo * > : : ConstIterator it ;
uint max_type = 0 ;
for ( it = DealerInfoList : : self ( ) - > games ( ) . begin ( ) ;
it ! = DealerInfoList : : self ( ) - > games ( ) . end ( ) ; + + it )
{
// while we develop, it may happen that some lower
// indices do not exist
uint index = ( * it ) - > gameindex ;
for ( uint i = 0 ; i < = index ; i + + )
if ( list . count ( ) < = i )
list . append ( " unknown " ) ;
list [ index ] = i18n ( ( * it ) - > name ) ;
if ( max_type < index )
max_type = index ;
}
games - > setItems ( list ) ;
KGlobal : : dirs ( ) - > addResourceType ( " wallpaper " , KStandardDirs : : kde_default ( " data " ) + " kpat/backgrounds/ " ) ;
KGlobal : : dirs ( ) - > addResourceType ( " wallpaper " , KStandardDirs : : kde_default ( " data " ) + " ksnake/backgrounds/ " ) ;
wallpapers = new KSelectAction ( i18n ( " &Change Background " ) , 0 , TQT_TQOBJECT ( this ) ,
TQT_SLOT ( changeWallpaper ( ) ) ,
actionCollection ( ) , " wallpaper " ) ;
list . clear ( ) ;
wallpaperlist . clear ( ) ;
TQStringList wallpaperlist2 = KGlobal : : dirs ( ) - > findAllResources ( " wallpaper " , TQString ( ) ,
false , true , list ) ;
TQStringList list2 ;
for ( TQStringList : : ConstIterator it = list . begin ( ) ; it ! = list . end ( ) ; + + it ) {
TQString file = * it ;
int rindex = file . findRev ( ' . ' ) ;
if ( rindex ! = - 1 ) {
TQString ext = file . mid ( rindex + 1 ) . lower ( ) ;
if ( ext = = " jpeg " | | ext = = " png " | | ext = = " jpg " ) {
list2 . append ( file . left ( rindex ) ) ;
wallpaperlist . append ( file ) ;
}
}
}
wallpapers - > setItems ( list2 ) ;
wallpapers - > setCurrentItem ( list2 . findIndex ( " No-Ones-Laughing-3 " ) ) ;
changeWallpaper ( ) ;
( void ) new cardMap ( midcolor ) ;
backs = new KAction ( i18n ( " &Switch Cards... " ) , 0 , TQT_TQOBJECT ( this ) ,
TQT_SLOT ( changeBackside ( ) ) ,
actionCollection ( ) , " backside " ) ;
stats = new KAction ( i18n ( " &Statistics " ) , 0 , TQT_TQOBJECT ( this ) , TQT_SLOT ( showStats ( ) ) ,
actionCollection ( ) , " game_stats " ) ;
animation = new KToggleAction ( i18n ( " &Animation on Startup " ) ,
0 , TQT_TQOBJECT ( this ) , TQT_SLOT ( animationChanged ( ) ) ,
actionCollection ( ) , " animation " ) ;
dropaction = new KToggleAction ( i18n ( " &Enable Autodrop " ) ,
0 , TQT_TQOBJECT ( this ) , TQT_SLOT ( enableAutoDrop ( ) ) ,
actionCollection ( ) , " enable_autodrop " ) ;
dropaction - > setCheckedState ( i18n ( " Disable Autodrop " ) ) ;
KConfig * config = kapp - > config ( ) ;
KConfigGroupSaver cs ( config , settings_group ) ;
TQString bgpath = config - > readPathEntry ( " Background " ) ;
kdDebug ( 11111 ) < < " bgpath ' " < < bgpath < < " ' " < < endl ;
if ( bgpath . isEmpty ( ) )
bgpath = locate ( " wallpaper " , " No-Ones-Laughing-3.jpg " ) ;
background = TQPixmap ( bgpath ) ;
bool animate = config - > readBoolEntry ( " Animation " , true ) ;
animation - > setChecked ( animate ) ;
bool autodrop = config - > readBoolEntry ( " Autodrop " , true ) ;
dropaction - > setChecked ( autodrop ) ;
uint game = config - > readNumEntry ( " DefaultGame " , 0 ) ;
if ( game > max_type )
game = max_type ;
games - > setCurrentItem ( game ) ;
statusBar ( ) - > insertItem ( " " , 1 , 0 , true ) ;
createGUI ( TQString ( ) , false ) ;
KAcceleratorManager : : manage ( menuBar ( ) ) ;
newGameType ( ) ;
adjustSize ( ) ;
setAutoSaveSettings ( ) ;
}
pWidget : : ~ pWidget ( )
{
delete dill ;
}
void pWidget : : undoMove ( ) {
if ( dill )
dill - > undo ( ) ;
}
void pWidget : : helpGame ( )
{
if ( ! dill )
return ;
kapp - > invokeHelp ( dill - > anchorName ( ) ) ;
}
void pWidget : : undoPossible ( bool poss )
{
undo - > setEnabled ( poss ) ;
}
void pWidget : : changeBackside ( ) {
KConfig * config = kapp - > config ( ) ;
KConfigGroupSaver kcs ( config , settings_group ) ;
TQString deck = config - > readEntry ( " Back " , KCardDialog : : getDefaultDeck ( ) ) ;
TQString cards = config - > readEntry ( " Cards " , KCardDialog : : getDefaultCardDir ( ) ) ;
if ( KCardDialog : : getCardDeck ( deck , cards , this , KCardDialog : : Both ) = = TQDialog : : Accepted )
{
TQString imgname = KCardDialog : : getCardPath ( cards , 11 ) ;
TQImage image ;
image . load ( imgname ) ;
if ( image . isNull ( ) ) {
kdDebug ( 11111 ) < < " cannot load card pixmap \" " < < imgname < < " \" in " < < cards < < " \n " ;
return ;
}
bool change = false ;
if ( image . width ( ) ! = cardMap : : CARDX ( ) | | image . height ( ) ! = cardMap : : CARDY ( ) )
{
change = true ;
if ( KMessageBox : : warningContinueCancel ( this , i18n ( " The cards you have chosen have a different "
" size than the ones you are currently using. "
" This requires the current game to be restarted. " ) ) = = KMessageBox : : Cancel )
return ;
}
setBackSide ( deck , cards ) ;
if ( change ) {
newGameType ( ) ;
}
}
}
void pWidget : : changeWallpaper ( )
{
TQString bgpath = locate ( " wallpaper " , wallpaperlist [ wallpapers - > currentItem ( ) ] ) ;
if ( bgpath . isEmpty ( ) )
return ;
background = TQPixmap ( bgpath ) ;
if ( background . isNull ( ) ) {
KMessageBox : : sorry ( this , i18n ( " <qt>Couldn't load wallpaper<br/>%1</qt> " ) . tqarg ( bgpath ) ) ;
return ;
}
TQImage bg = background . convertToImage ( ) . convertDepth ( 8 , 0 ) ;
if ( bg . isNull ( ) | | ! bg . numColors ( ) )
return ;
long r = 0 ;
long g = 0 ;
long b = 0 ;
for ( int i = 0 ; i < bg . numColors ( ) ; + + i )
{
TQRgb rgb = bg . color ( i ) ;
r + = tqRed ( rgb ) ;
g + = tqGreen ( rgb ) ;
b + = tqBlue ( rgb ) ;
}
r / = bg . numColors ( ) ;
b / = bg . numColors ( ) ;
g / = bg . numColors ( ) ;
midcolor = TQColor ( r , b , g ) ;
if ( dill ) {
KConfig * config = kapp - > config ( ) ;
KConfigGroupSaver kcs ( config , settings_group ) ;
TQString deck = config - > readEntry ( " Back " , KCardDialog : : getDefaultDeck ( ) ) ;
TQString dummy = config - > readEntry ( " Cards " , KCardDialog : : getDefaultCardDir ( ) ) ;
setBackSide ( deck , dummy ) ;
config - > writePathEntry ( " Background " , bgpath ) ;
dill - > setBackgroundPixmap ( background , midcolor ) ;
dill - > canvas ( ) - > setAllChanged ( ) ;
dill - > canvas ( ) - > update ( ) ;
}
}
void pWidget : : animationChanged ( ) {
bool anim = animation - > isChecked ( ) ;
KConfig * config = kapp - > config ( ) ;
KConfigGroupSaver cs ( config , settings_group ) ;
config - > writeEntry ( " Animation " , anim ) ;
}
void pWidget : : enableAutoDrop ( )
{
bool drop = dropaction - > isChecked ( ) ;
KConfig * config = kapp - > config ( ) ;
KConfigGroupSaver cs ( config , settings_group ) ;
config - > writeEntry ( " Autodrop " , drop ) ;
dill - > setAutoDropEnabled ( drop ) ;
}
void pWidget : : newGame ( )
{
// Check if the user is already running a game, and if she is,
// then ask if she wants to abort it.
if ( ! dill - > isGameWon ( ) & & ! dill - > isGameLost ( )
& & KMessageBox : : warningContinueCancel ( 0 ,
i18n ( " You are already running an unfinished game. "
" If you abort the old game to start a new one, "
" the old game will be registered as a loss in "
" the statistics file. \n "
" What do you want to do? " ) ,
i18n ( " Abort Current Game? " ) ,
i18n ( " Abort Old Game " ) ,
" careaboutstats " ) = = KMessageBox : : Cancel )
return ;
dill - > setGameNumber ( kapp - > random ( ) ) ;
setGameCaption ( ) ;
restart ( ) ;
}
void pWidget : : restart ( )
{
statusBar ( ) - > clear ( ) ;
dill - > startNew ( ) ;
}
void pWidget : : setGameCaption ( )
{
TQString name = games - > currentText ( ) ;
TQString newname ;
TQString gamenum ;
gamenum . setNum ( dill - > gameNumber ( ) ) ;
for ( uint i = 0 ; i < name . length ( ) ; i + + )
if ( name . at ( i ) ! = TQChar ( ' & ' ) )
newname + = name . at ( i ) ;
setCaption ( newname + " - " + gamenum ) ;
}
void pWidget : : newGameType ( )
{
delete dill ;
dill = 0 ;
slotUpdateMoves ( ) ;
uint id = games - > currentItem ( ) ;
for ( TQValueList < DealerInfo * > : : ConstIterator it = DealerInfoList : : self ( ) - > games ( ) . begin ( ) ; it ! = DealerInfoList : : self ( ) - > games ( ) . end ( ) ; + + it ) {
if ( ( * it ) - > gameindex = = id ) {
dill = ( * it ) - > createGame ( this ) ;
TQString name = ( * it ) - > name ;
name = name . replace ( TQRegExp ( " [&'] " ) , " " ) ;
name = name . replace ( TQRegExp ( " [ ] " ) , " _ " ) . lower ( ) ;
dill - > setAnchorName ( " game_ " + name ) ;
connect ( dill , TQT_SIGNAL ( saveGame ( ) ) , TQT_SLOT ( saveGame ( ) ) ) ;
connect ( dill , TQT_SIGNAL ( gameInfo ( const TQString & ) ) ,
TQT_SLOT ( slotGameInfo ( const TQString & ) ) ) ;
connect ( dill , TQT_SIGNAL ( updateMoves ( ) ) ,
TQT_SLOT ( slotUpdateMoves ( ) ) ) ;
dill - > setGameId ( id ) ;
dill - > setupActions ( ) ;
dill - > setBackgroundPixmap ( background , midcolor ) ;
dill - > startNew ( ) ;
break ;
}
}
if ( ! dill ) {
kdError ( ) < < " unimplemented game type " < < id < < endl ;
dill = DealerInfoList : : self ( ) - > games ( ) . first ( ) - > createGame ( this ) ;
}
connect ( dill , TQT_SIGNAL ( undoPossible ( bool ) ) , TQT_SLOT ( undoPossible ( bool ) ) ) ;
connect ( dill , TQT_SIGNAL ( gameWon ( bool ) ) , TQT_SLOT ( gameWon ( bool ) ) ) ;
connect ( dill , TQT_SIGNAL ( gameLost ( ) ) , TQT_SLOT ( gameLost ( ) ) ) ;
dill - > setAutoDropEnabled ( dropaction - > isChecked ( ) ) ;
// it's a bit tricky - we have to do this here as the
// base class constructor runs before the derived class's
dill - > takeState ( ) ;
setGameCaption ( ) ;
KConfig * config = kapp - > config ( ) ;
KConfigGroupSaver kcs ( config , settings_group ) ;
config - > writeEntry ( " DefaultGame " , id ) ;
TQSize min ( 700 , 400 ) ;
min = min . expandedTo ( dill - > minimumCardSize ( ) ) ;
dill - > setMinimumSize ( min ) ;
dill - > resize ( min ) ;
updateGeometry ( ) ;
setCentralWidget ( dill ) ;
dill - > show ( ) ;
}
void pWidget : : showEvent ( TQShowEvent * e )
{
if ( dill )
dill - > setMinimumSize ( TQSize ( 0 , 0 ) ) ;
KMainWindow : : showEvent ( e ) ;
}
void pWidget : : slotGameInfo ( const TQString & text )
{
statusBar ( ) - > message ( text , 3000 ) ;
}
void pWidget : : slotUpdateMoves ( )
{
int moves = 0 ;
if ( dill ) moves = dill - > getMoves ( ) ;
statusBar ( ) - > changeItem ( i18n ( " 1 move " , " %n moves " , moves ) , 1 ) ;
}
void pWidget : : setBackSide ( const TQString & deck , const TQString & cards )
{
KConfig * config = kapp - > config ( ) ;
KConfigGroupSaver kcs ( config , settings_group ) ;
TQPixmap pm ( deck ) ;
if ( ! pm . isNull ( ) ) {
cardMap : : self ( ) - > setBackSide ( pm , false ) ;
config - > writeEntry ( " Back " , deck ) ;
bool ret = cardMap : : self ( ) - > setCardDir ( cards ) ;
if ( ! ret ) {
config - > writeEntry ( " Back " , " " ) ;
}
config - > writeEntry ( " Cards " , cards ) ;
cardMap : : self ( ) - > setBackSide ( pm , true ) ;
} else
KMessageBox : : sorry ( this ,
i18n ( " Could not load background image! " ) ) ;
if ( dill ) {
dill - > canvas ( ) - > setAllChanged ( ) ;
dill - > canvas ( ) - > update ( ) ;
}
}
void pWidget : : chooseGame ( )
{
bool ok ;
long number = KInputDialog : : getText ( i18n ( " Game Number " ) , i18n ( " Enter a game number (FreeCell deals are the same as in the FreeCell FAQ): " ) , TQString : : number ( dill - > gameNumber ( ) ) , 0 , this ) . toLong ( & ok ) ;
if ( ok ) {
dill - > setGameNumber ( number ) ;
setGameCaption ( ) ;
restart ( ) ;
}
}
void pWidget : : gameWon ( bool withhelp )
{
TQString congrats ;
if ( withhelp )
congrats = i18n ( " Congratulations! We have won! " ) ;
else
congrats = i18n ( " Congratulations! You have won! " ) ;
# if TEST_SOLVER == 0
KMessageBox : : information ( this , congrats , i18n ( " Congratulations! " ) ) ;
# endif
TQTimer : : singleShot ( 0 , TQT_TQOBJECT ( this ) , TQT_SLOT ( newGame ( ) ) ) ;
# if TEST_SOLVER == 1
dill - > demo ( ) ;
# endif
}
void pWidget : : gameLost ( )
{
TQString dontAskAgainName = " gameLostDontAskAgain " ;
// The following code is taken out of kmessagebox.cpp in kdeui.
// Is there a better way?
KConfig * config = 0 ;
TQString grpNotifMsgs = TQString : : tqfromLatin1 ( " Notification Messages " ) ;
config = KGlobal : : config ( ) ;
KConfigGroupSaver saver ( config ,
TQString : : tqfromLatin1 ( " Notification Messages " ) ) ;
TQString dontAsk = config - > readEntry ( dontAskAgainName ) . lower ( ) ;
// If we are ordered never to ask again and to continue the game,
// then do so.
if ( dontAsk = = " no " )
return ;
// If it says yes, we ask anyway. Just starting a new game would
// be incredibly annoying.
if ( dontAsk = = " yes " )
dontAskAgainName = TQString ( ) ;
if ( KMessageBox : : questionYesNo ( this , i18n ( " You could not win this game, "
" but there is always a second try. \n Start a new game? " ) ,
i18n ( " Could Not Win! " ) ,
i18n ( " New Game " ) ,
KStdGuiItem : : cont ( ) ,
dontAskAgainName ) = = KMessageBox : : Yes ) {
TQTimer : : singleShot ( 0 , TQT_TQOBJECT ( this ) , TQT_SLOT ( newGame ( ) ) ) ;
}
}
void pWidget : : openGame ( const KURL & url )
{
TQString tmpFile ;
if ( KIO : : NetAccess : : download ( url , tmpFile , this ) )
{
TQFile of ( tmpFile ) ;
of . open ( IO_ReadOnly ) ;
TQDomDocument doc ;
TQString error ;
if ( ! doc . setContent ( & of , & error ) )
{
KMessageBox : : sorry ( this , error ) ;
return ;
}
uint id = doc . documentElement ( ) . attribute ( " id " ) . toUInt ( ) ;
if ( id ! = ( TQ_UINT32 ) games - > currentItem ( ) ) {
games - > setCurrentItem ( id ) ;
newGameType ( ) ;
if ( ! dill ) {
KMessageBox : : error ( this , i18n ( " The saved game is of unknown type! " ) ) ;
games - > setCurrentItem ( 0 ) ;
newGameType ( ) ;
}
}
dill - > openGame ( doc ) ;
setGameCaption ( ) ;
KIO : : NetAccess : : removeTempFile ( tmpFile ) ;
recent - > addURL ( url ) ;
recent - > saveEntries ( KGlobal : : config ( ) ) ;
}
}
void pWidget : : openGame ( )
{
KURL url = KFileDialog : : getOpenURL ( ) ;
openGame ( url ) ;
}
void pWidget : : saveGame ( )
{
KURL url = KFileDialog : : getSaveURL ( ) ;
KTempFile file ;
TQDomDocument doc ( " kpat " ) ;
dill - > saveGame ( doc ) ;
TQTextStream * stream = file . textStream ( ) ;
* stream < < doc . toString ( ) ;
file . close ( ) ;
KIO : : NetAccess : : upload ( file . name ( ) , url , this ) ;
recent - > addURL ( url ) ;
recent - > saveEntries ( KGlobal : : config ( ) ) ;
}
void pWidget : : showStats ( )
{
GameStatsImpl * dlg = new GameStatsImpl ( this , " statistics dialog " ) ;
if ( dill )
dlg - > showGameType ( dill - > gameId ( ) ) ;
dlg - > exec ( ) ;
}
# include "pwidget.moc"