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:
parent
3ccfe0a810
commit
ab18cda88a
6 changed files with 116 additions and 82 deletions
1
TODO
1
TODO
|
@ -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).
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"""
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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"""
|
||||
|
|
Loading…
Reference in a new issue