Make sure user can save non local games when:

- Quit
- Start new game
- Start network game

svn path=/trunk/; revision=6909
This commit is contained in:
Robert Ancell 2007-11-03 05:33:32 +00:00
parent 3ccfe0a810
commit ab18cda88a
6 changed files with 116 additions and 82 deletions

1
TODO
View file

@ -1,4 +1,3 @@
Offer to save old game when starting a new one ***
Add option to autoresign when starting new game
Have pop-up menu on tab headers (i.e. game menu).
Advanced save options (i.e. PGN fields).

View file

@ -530,16 +530,11 @@ class View(ui.ViewFeedback):
f.close()
self.game.fileName = fileName
self.game.needsSaving = False
def getFileName(self):
"""Called by ui.ViewFeedback"""
return self.game.fileName
def needsSaving(self):
"""Called by ui.ViewFeedback"""
return self.game.needsSaving
def resign(self):
"""Called by ui.ViewFeedback"""
p = self.game.getHumanPlayer()

View file

@ -464,33 +464,33 @@ class GtkUI(glchess.ui.UI):
# Update the open dialogs
for dialog in self.__joinGameDialogs:
dialog.removeNetworkGame(game)
def requestSave(self, title):
"""Extends glchess.ui.UI"""
dialog = gtk.MessageDialog(flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
type = gtk.MESSAGE_WARNING,
message_format = title)
dialog.format_secondary_text("If you don't save the changes to this game will be permanently lost")
dialog.add_button(_('Close _without saving'), gtk.RESPONSE_OK)
dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)
dialog.add_button(gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)
response = dialog.run()
dialog.destroy()
if response == gtk.RESPONSE_ACCEPT:
return glchess.ui.SAVE_YES
elif response == gtk.RESPONSE_OK:
return glchess.ui.SAVE_NO
else:
return glchess.ui.SAVE_ABORT
def close(self):
"""Extends glchess.ui.UI"""
# Check if the current view needs saving
if self.view.feedback.needsSaving():
dialog = gtk.MessageDialog(flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
type = gtk.MESSAGE_WARNING,
message_format = _('Save game before closing?'))
dialog.format_secondary_text("If you don't save the changes to this game will be permanently lost")
dialog.add_button(_('Close _without saving'), gtk.RESPONSE_OK)
dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)
dialog.add_button(gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)
response = dialog.run()
if response == gtk.RESPONSE_ACCEPT:
self.view.feedback.save()
elif response == gtk.RESPONSE_REJECT:
dialog.destroy()
return False
# Save the window size
if self.width is not None:
glchess.config.set('width', self.width)
if self.height is not None:
glchess.config.set('height', self.height)
return True
# Protected methods

View file

@ -83,7 +83,7 @@ class ChessGame(game.ChessGame):
self.fileName = None
self.inHistory = False
self.needsSaving = True
self.needsSaving = False
# Call parent constructor
game.ChessGame.__init__(self)
@ -278,6 +278,15 @@ class ChessGame(game.ChessGame):
self.application._removeGame(self)
self.view.controller.close()
def save(self):
"""Save this game"""
if len(self.getMoves()) < 2:
return
pgnGame = chess.pgn.PGNGame()
self.toPGN(pgnGame)
self.application.history.save(pgnGame, self.fileName)
self.needsSaving = False
class UI(ui.UIFeedback):
"""
"""
@ -340,7 +349,9 @@ class UI(ui.UIFeedback):
b = None
else:
b = (game.black.type, game.black.level)
g = self.application.addGame(game.name, game.white.name, w, game.black.name, b)
g = self.application.addLocalGame(game.name, game.white.name, w, game.black.name, b)
if g is None:
return
self.application.logger.addLine('Starting game %s between %s (%s) and %s (%s). (%i moves)' % \
(game.name,
game.white.name, str(game.white.type),
@ -441,18 +452,24 @@ class Application:
if fd is not None:
self.ioHandlers.pop(fd)
def setGame(self, g):
def addGame(self, name):
if self.__game is not None:
# FIXME: Ask user if not a history game
self._save(self.__game)
self.__game = g
def addNetworkGame(self, name):
g = ChessGame(self, name)
self.setGame(g)
return g
# Save the current game to the history
if self.__game.inHistory:
response = ui.SAVE_YES
elif self.__game.needsSaving:
response = self.ui.controller.requestSave('Save current game?')
else:
response = ui.SAVE_NO
def addGame(self, name, whiteName, whiteType, blackName, blackType):
if response is ui.SAVE_YES:
self.__game.save()
elif response is ui.SAVE_ABORT:
return None
self.__game = ChessGame(self, name)
return self.__game
def addLocalGame(self, name, whiteName, whiteType, blackName, blackType):
"""Add a chess game into glChess.
'name' is the name of the game (string).
@ -466,8 +483,10 @@ class Application:
# FIXME: Replace arguments with player objects
# Create the game
g = ChessGame(self, name)
self.setGame(g)
g = self.addGame(name)
if g is None:
return None
g.inHistory = True
msg = ''
if whiteType is None:
@ -533,7 +552,9 @@ class Application:
self.ui.controller.reportGameLoaded(gameProperties)
return
newGame = self.addGame(gameProperties.name, gameProperties.white.name, w, gameProperties.black.name, b)
newGame = self.addLocalGame(gameProperties.name, gameProperties.white.name, w, gameProperties.black.name, b)
if newGame is None:
return
newGame.date = pgnGame.getTag(chess.pgn.TAG_DATE)
newGame.fileName = path
if gameProperties.moves:
@ -581,8 +602,8 @@ class Application:
except ValuError:
blackTime = duration
newGame.setTimer(duration, whiteTime / 1000, blackTime / 1000)
# No change from when loaded
# No need to save freshly loaded game
newGame.needsSaving = False
return newGame
@ -648,30 +669,29 @@ class Application:
def quit(self):
"""Quit glChess"""
# Save the current game to the history
if self.__game is not None and self.__game.inHistory:
self._save(self.__game)
if self.__game is not None:
if self.__game.inHistory:
response = ui.SAVE_YES
elif self.__game.needsSaving:
response = self.ui.controller.requestSave(_('Save game before closing?'))
else:
response = ui.SAVE_NO
if response == ui.SAVE_YES:
self.__game.save()
elif response == ui.SAVE_ABORT:
return
# Abort current game (will delete AIs etc)
self.__game.abort()
# Notify the UI
if not self.ui.controller.close():
return
# Abort current game (will delete AIs etc)
if self.__game is not None:
self.__game.abort()
self.ui.controller.close()
# Exit the application
sys.exit()
# Private methods
def _save(self, g):
if len(g.getMoves()) < 2:
return
pgnGame = chess.pgn.PGNGame()
g.toPGN(pgnGame)
self.history.save(pgnGame, g.fileName)
g.needsSaving = False
def __autoload(self):
"""Restore games from the autosave file"""

View file

@ -230,7 +230,7 @@ class GGZConnection(ggz.ClientFeedback):
def onJoin(self, table, isSpectator, channel):
self.dialog.controller.joinTable(table)
g = GGZChess(self.dialog.ui, channel)
g = GGZChess(self.dialog.game, channel)
return g
def onLeave(self, reason):
@ -250,8 +250,8 @@ class GGZChess:
"""
"""
def __init__(self, ui, channel):
self.ui = ui
def __init__(self, game, channel):
self.game = game
self.channel = channel
self.protocol = ggz.Chess(self)
@ -280,8 +280,6 @@ class GGZChess:
def onStart(self):
print ('onStart',)
g = self.ui.application.addNetworkGame('Network Game')
# Create remote player
if self.seatNum == 0:
name = self.blackName
@ -290,15 +288,15 @@ class GGZChess:
self.remotePlayer = game.ChessPlayer(name)
self.remotePlayer.onPlayerMoved = self.onPlayerMoved # FIXME: HACK HACK HACK!
p = g.addHumanPlayer('Human')
p = self.game.addHumanPlayer('Human')
if self.seatNum == 0:
g.setWhite(p)
g.setBlack(self.remotePlayer)
self.game.setWhite(p)
self.game.setBlack(self.remotePlayer)
else:
g.setWhite(self.remotePlayer)
g.setBlack(p)
self.game.setWhite(self.remotePlayer)
self.game.setBlack(p)
g.start()
self.game.start()
def onPlayerMoved(self, player, move):
#FIXME: HACK HACK HACK!
@ -349,14 +347,29 @@ class GGZNetworkDialog(ui.NetworkFeedback):
print 'Entering room %s' % room.id
self.decoder._performAction(self.decoder.client.enterRoom, (room,))
def _addGame(self):
self.game = self.ui.application.addGame('Network Game')
if self.game is None:
# FIXME: Notify user game aborted
return False
return True
def startTable(self):
"""Called by ui.NetworkFeedback"""
if self.decoder.room.game is not None:
print 'Starting table'
self.decoder.client.startTable(self.decoder.room.game.id, 'glChess test game (do not join!)', self.profile.login)
if self.decoder.room.game is None:
return
if not self._addGame():
return
print 'Starting table'
self.decoder.client.startTable(self.decoder.room.game.id, 'glChess test game (do not join!)', self.profile.login)
def joinTable(self, table):
"""Called by ui.NetworkFeedback"""
if not self._addGame():
return
print 'Starting table %s' % table.id
self.decoder.client.joinTable(table)

View file

@ -193,14 +193,7 @@ class ViewFeedback:
Returns the file name (string) or None if game is not saved.
"""
return None
def needsSaving(self):
"""Check if this game needs saving.
Return True if it does otherwise False.
"""
return False
def save(self, filename = None):
"""Save the game using this view.
@ -369,6 +362,11 @@ class Log:
def close(self):
"""
"""
pass
SAVE_YES = 'SAVE_YES'
SAVE_NO = 'SAVE_NO'
SAVE_ABORT = 'SAVE_ABORT'
class UI:
"""Template class for a glChess UI.
@ -456,6 +454,15 @@ class UI:
'game' is the game that has removed (as registered with addNetworkGame()).
"""
pass
def requestSave(self, title):
"""Request a game is saved.
'title' is the request to make to the user.
Returns SAVE_YES, SAVE_NO or SAVE_ABORT.
"""
pass
def close(self):
"""Report the application has ended"""