Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--PascalTriangle.activity/pascaltriangle.py71
1 files changed, 71 insertions, 0 deletions
diff --git a/PascalTriangle.activity/pascaltriangle.py b/PascalTriangle.activity/pascaltriangle.py
index 083693d..95d422d 100644
--- a/PascalTriangle.activity/pascaltriangle.py
+++ b/PascalTriangle.activity/pascaltriangle.py
@@ -27,6 +27,8 @@ import random
from gi.repository import Gtk, Gdk
import cairo
from gettext import gettext as _
+import pickle
+import logging
class PascalTriangleActivity(activity.Activity):
@@ -44,6 +46,9 @@ class PascalTriangleActivity(activity.Activity):
self.max_participants = 1 # No sharing
+ # Set up logging first.
+ self._logger = logging.getLogger('pascal-triangle-activity')
+
# Create the standard activity toolbox.
toolbar_box = ToolbarBox()
self.set_toolbar_box(toolbar_box)
@@ -62,6 +67,7 @@ class PascalTriangleActivity(activity.Activity):
hint_button = HintButton(self)
hint_button.show()
main_toolbar.insert(hint_button, -1)
+ self._hint_button = hint_button
separator = Gtk.SeparatorToolItem()
separator.props.draw = True
@@ -114,6 +120,7 @@ class PascalTriangleActivity(activity.Activity):
self._triangle_size = int(slider.get_value())
slider.connect('value-changed', self.__slider_value_changed_cb, None)
+ self._slider = slider
# Parent and show the drawing area.
self.set_canvas(overlay)
@@ -153,6 +160,70 @@ class PascalTriangleActivity(activity.Activity):
self._drawing_area.queue_draw()
+ def read_file(self, file_path):
+ """Read a saved game from the journal.
+
+ If this fails, the current game state will be left untouched. If extra
+ state over what was expected is present in the save file, it will be
+ ignored. For documentation on the save format, see write_file().
+ """
+ obj = None
+ try:
+ with open(file_path, 'rb') as file_fd:
+ obj = pickle.load(file_fd)
+ if len(obj) < 5:
+ raise pickle.UnpicklingError, 'Invalid tuple.'
+ except EnvironmentError as err:
+ self._logger.warning('Error reading save file ā€˜%sā€™: %s' %
+ (file_path, err))
+ return
+ except pickle.UnpicklingError as err:
+ self._logger.warning('Malformed save file ā€˜%sā€™: %s' %
+ (file_path, err))
+ return
+
+ # Restore the UI state. Setting the triangle size will start a new
+ # game, so we must restore other state afterwards. From this point
+ # onwards, the code can't fail.
+ triangle_size = obj[0]
+ self._slider.set_value(triangle_size)
+
+ show_hints = obj[4]
+ self._hint_button.set_active(show_hints)
+
+ # Access the obj elements by index so that we don't fail if obj has
+ # more than the expected number of elements (e.g. if we've somehow
+ # got a save file from a newer version of the activity which saves
+ # more state).
+ self._blank_cells = obj[1]
+ self._current_cell = obj[2]
+ self._current_cell_text = obj[3]
+
+ # Redraw everything.
+ self._drawing_area.queue_draw()
+
+ def write_file(self, file_path):
+ """Write a game to the journal.
+
+ The game state is pickled as a tuple of at least 5 elements. This
+ format may be extended in future by appending elements to the tuple;
+ read_file() is guaranteed to ignore extra tuple elements. The existing
+ tuple elements must be stable, though.
+ """
+ obj = (
+ self._triangle_size,
+ self._blank_cells,
+ self._current_cell,
+ self._current_cell_text,
+ self._show_hints,
+ )
+
+ try:
+ with open(file_path, 'wb') as file_fd:
+ pickle.dump(obj, file_fd, pickle.HIGHEST_PROTOCOL)
+ except EnvironmentError as err:
+ self._logger.warning('Error saving game: %s' % err)
+
def _update_current_cell(self, index):
"""Change position of the currently selected cell and clear any pending
text edits."""