[gnome-games/applygsoc2009: 37/76] XXX: Make notes working



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]