[gnome-games/applygsoc2009: 37/76] XXX: Make notes working
- From: Pablo Castellano <pablog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games/applygsoc2009: 37/76] XXX: Make notes working
- Date: Mon, 6 Sep 2010 02:50:19 +0000 (UTC)
commit 7ca828da14152bb074329b8ddca0b32eb1cb3479
Author: Pablo Castellano <pablog src gnome org>
Date: Thu Aug 26 15:47:26 2010 +0200
XXX: Make notes working
* Use another class, NotesModel, to track notes. SudokuModel knows nothing
about notes.
gnome-sudoku/src/lib/gsudoku.py | 193 ++++++++++++++++++---------------------
gnome-sudoku/src/lib/main.py | 10 +-
2 files changed, 91 insertions(+), 112 deletions(-)
---
diff --git a/gnome-sudoku/src/lib/gsudoku.py b/gnome-sudoku/src/lib/gsudoku.py
index 4b424a7..17d5c38 100644
--- a/gnome-sudoku/src/lib/gsudoku.py
+++ b/gnome-sudoku/src/lib/gsudoku.py
@@ -92,6 +92,7 @@ class SudokuView (SudokuNumberGrid, gobject.GObject):
self._model = None
self._do_highlight_cells = False
+ self._notes_model = None
for e in self.__entries__.values():
e.show()
@@ -113,6 +114,10 @@ class SudokuView (SudokuNumberGrid, gobject.GObject):
self.set_readonly_appearance(x, y, True)
self.set_value(x, y, val)
+ def connect_to_notes_model(self, model):
+ self._notes_model = model
+ self._notes_model.add_observer(self)
+
def update(self, values):
"""Update the GUI, called by a Model
@@ -145,8 +150,7 @@ class SudokuView (SudokuNumberGrid, gobject.GObject):
self._model.set_value(x, y, value)
def _notes_changed_cb(self, widget, top_note, bottom_note):
- print "user input: notes", (widget.x, widget.y, top_note, bottom_note)
- self._model.set_notes(widget.x, widget.y, top_note, bottom_note)
+ self._notes_model.set_notes(widget.x, widget.y, top_note, bottom_note)
def _focus_callback(self, widget, event):
if self._do_highlight_cells:
@@ -245,11 +249,81 @@ class NumberBoxModel:
self.conflict = conflict
+class NotesModel:
+ """Track notes for a SudokuModel
+
+ Act as a observer of SudokuModel, and a model/observable for SudokuView.
+ SudokuModel should know nothing about notes.
+ """
+
+ def __init__(self, sudoku_model, group_size):
+ self._notes = {}
+ self._observers = []
+ self._group_size = group_size
+ self._model = sudoku_model
+ self._model.add_observer(self)
+
+ self._always_show_hints = False
+
+ def toggle_auto_hint(self, flag):
+ if flag:
+ self._always_show_hints = True
+ self.update_all_hints()
+ else:
+ self._always_show_hints = False
+ self.clear_hints()
+
+ def add_observer(self, observer):
+ self._observers.append(observer)
+
+ def _signal_observers(self, changes):
+ for observer in self._observers:
+ observer.update(changes)
+
+ def set_notes(self, x, y, top_note=None, bottom_note=None):
+ if (x, y) not in self._notes:
+ self._notes[(x, y)] = [None, None]
+
+ if top_note is not None:
+ self._notes[(x, y)][0] = top_note
+ if bottom_note is not None:
+ self._notes[(x, y)][0] = bottom_note
+
+ change = NumberBoxModel(x, y,
+ top_note=top_note, bottom_note=bottom_note)
+ self._signal_observers([change])
+
+ def update(self, changes):
+ if not self._always_show_hints:
+ return
+
+ self.update_all_hints()
+
+ def update_all_hints(self):
+ for x in range(self._group_size):
+ for y in range(self._group_size):
+ self._update_hint_for_entry(x, y)
+
+ def _update_hint_for_entry(self, x, y):
+ # no need to show anything if it's already filled, being correct or not
+ if self._model.get_value(x, y):
+ self.set_notes(x, y, bottom_note="")
+ return
+
+ vals = self._model.grid.possible_values(x, y)
+ vals = list(vals)
+ vals.sort()
+ if vals:
+ txt = ''.join([str(v) for v in vals])
+ self.set_notes(x, y, bottom_note=txt)
+ else:
+ self.set_notes(x, y, bottom_note="X")
+
+
class SudokuModel:
def __init__ (self, grid, group_size):
self.hints = 0
- self.always_show_hints = False
self.auto_fills = 0
self.show_impossible_implications = False
self.impossible_hints = 0
@@ -279,6 +353,9 @@ class SudokuModel:
return True;
+ def get_value(self, x, y):
+ return self.grid._get_(x, y)
+
def set_hint_square (self, square):
if self.hint_square is not None:
self.hint_square.set_border_color(None)
@@ -315,25 +392,6 @@ class SudokuModel:
self.set_hint_square(random.choice(squares))
self.hints += 1
- def _show_hint_for_entry (self, entry, interactive = False):
- if interactive:
- set_method = entry.set_note_text_interactive
- else:
- set_method = entry.set_note_text
- vals = self.grid.possible_values(entry.x, entry.y)
- vals = list(vals)
- vals.sort()
- if vals:
- ''.join([str(v) for v in vals])
- txt = ''.join([str(v) for v in vals])
- if txt != entry.get_text():
- set_method(bottom_text = txt, for_hint = True)
- elif not entry.get_text():
- if entry.get_text() != 'X':
- set_method(bottom_text = 'X', for_hint = True)
- else:
- set_method(bottom_text = "", for_hint = True)
-
def reset_grid (self):
'''Remove all untracked values from the grid
@@ -353,62 +411,6 @@ class SudokuModel:
self.remove(x, y)
return removed
- def clear_notes (self, side = 'Both', tracker = None):
- '''Remove notes
-
- The list of notes removed by this function are returned in a list.
- The notes are returned in the format (x, y, (side, pos, tid, note)) where:
- x and y are the cell's coordinates
- side is either 'Top' or 'Bottom'
- pos is the index of the note within the notelist
- tid is the tracker id for the note
- note is the value of the note
-
- The side argument determines what notes get cleared as well as what
- notes get returned.
- 'Both' - Clears both the top and bottom notes(default)
- 'Top' - Clear only the top notes
- 'Bottom' - Clear only the bottom notes
- 'AutoHint' - Clear all bottom notes for all trackers
- 'All' - Reset all notes
-
- For 'Top', 'Bottom', and 'Both', the tracker argument can be supplied
- to clear for a specific tracker. Set tracker to None(default) to
- operate on just what is currently displayed.
- '''
- # Storage for removed notes
- removed = []
- for x in range(self.group_size):
- for y in range(self.group_size):
- e = self.__entries__[(x, y)]
- if side in ['Top', 'Both']:
- if tracker == None:
- top_display_list = e.get_note_display(e.top_note_list)[0]
- else:
- top_display_list = e.get_note_display(e.top_note_list, tracker, False)[0]
- for offset, (notelist_index, tracker_id, note) in enumerate(top_display_list):
- removed.append((x, y, ('Top', notelist_index, tracker_id, note)))
- del e.top_note_list[notelist_index - offset]
- if side in ['Bottom', 'Both']:
- if tracker == None:
- bottom_display_list = e.get_note_display(e.bottom_note_list)[0]
- else:
- bottom_display_list = e.get_note_display(e.bottom_note_list, tracker, False)[0]
- for offset, (notelist_index, tracker_id, note) in enumerate(bottom_display_list):
- removed.append((x, y, ('Bottom', notelist_index, tracker_id, note)))
- del e.bottom_note_list[notelist_index - offset]
- if side == 'All':
- for notelist_index, (tracker_id, note) in enumerate(e.top_note_list):
- removed.append((x, y, ('Top', notelist_index, tracker_id, note)))
- e.top_note_list = []
- if side in ['All', 'AutoHint']:
- for notelist_index, (tracker_id, note) in enumerate(e.bottom_note_list):
- removed.append((x, y, ('Bottom', notelist_index, tracker_id, note)))
- e.bottom_note_list = []
- # Redraw the notes
- self.update_all_notes()
- return removed
-
def apply_notelist(self, notelist, apply_tracker = False):
'''Re-apply notes
@@ -496,17 +498,6 @@ class SudokuModel:
widget.set_value(new_value)
self._entry_validate(widget)
- def update_all_hints (self):
- for x in range(self.group_size):
- for y in range(self.group_size):
- e = self.__entries__[(x, y)]
- if e.read_only:
- pass
- elif e.get_text():
- e.set_note_text(bottom_text = '')
- else:
- self._show_hint_for_entry(e)
-
def update_all_notes (self):
'''Display the notes for all the cells
@@ -517,18 +508,6 @@ class SudokuModel:
for y in range(self.group_size):
self.__entries__[(x, y)].show_note_text()
- def _entry_validate (self, widget, *args):
- val = widget.get_value()
- if (args and args[0] == 'undo-change'):
- # When undoing from one value to another - remove the errors from
- # the previous value and add the new value to the proper tracker
- self._remove_error_highlight()
- self.add_value(widget.x, widget.y, val, widget.tracker_id)
- else:
- self.add_value(widget.x, widget.y, val)
- if self.grid.check_for_completeness():
- self.emit('puzzle-finished')
-
def highlight_conflicts (self, x, y):
'''highlight any squares that conflict with position x,y.
@@ -555,10 +534,13 @@ class SudokuModel:
change = NumberBoxModel(x=entry[0], y=entry[1], conflict=False)
result.append(change)
- try:
- self.grid.add(x, y, value) # force=True???
- except sudoku.ConflictError, err:
- new_conflicts = self.grid.find_conflicts(x, y, value)
+ if not value: # should use unified way to update the grid
+ self.grid.remove(x, y)
+ else:
+ try:
+ self.grid.add(x, y, value) # force=True???
+ except sudoku.ConflictError, err:
+ new_conflicts = self.grid.find_conflicts(x, y, value)
has_conflict = True if new_conflicts else False
result.append(NumberBoxModel(x, y, value, conflict=has_conflict))
if new_conflicts:
@@ -767,4 +749,3 @@ class SudokuModel:
# Update all hints if we need to
if self.always_show_hints and not self.doing_initial_setup:
self.update_all_hints()
-
diff --git a/gnome-sudoku/src/lib/main.py b/gnome-sudoku/src/lib/main.py
index aaa28a5..83d7d14 100644
--- a/gnome-sudoku/src/lib/main.py
+++ b/gnome-sudoku/src/lib/main.py
@@ -113,7 +113,10 @@ class UI (gconf_wrapper.GConfWrapper):
self._puzzle = puzzle
if game_type == game_selector.NewOrSavedGameSelector.NEW_GAME:
self._main_model = gsudoku.SudokuModel(puzzle, 9)
+ self._notes_model = gsudoku.NotesModel(self._main_model, group_size=9)
+
self._main_grid_vew.connect_to_model(self._main_model)
+ self._main_grid_vew.connect_to_notes_model(self._notes_model)
# self._main_grid_vew.connect('puzzle-finished', self.you_win_callback)
elif game_type == game_selector.NewOrSavedGameSelector.SAVED_GAME:
saver.open_game(self, puzzle)
@@ -480,12 +483,7 @@ class UI (gconf_wrapper.GConfWrapper):
self.gsd.show_hint()
def auto_hint_cb (self, action):
- if action.get_active():
- self.gsd.always_show_hints = True
- self.gsd.update_all_hints()
- else:
- self.gsd.always_show_hints = False
- self.gsd.clear_notes('AutoHint')
+ self._notes_model.toggle_auto_hint(action.get_active())
def impossible_implication_cb (self, action):
if action.get_active():
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]