From d44269935822d232856b82943cd7314f06897ca8 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Sun, 20 Mar 2016 03:48:50 +0100 Subject: [PATCH 01/10] gui/dictionary_editor: fix call to util.SetTopApp --- plover/gui/dictionary_editor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plover/gui/dictionary_editor.py b/plover/gui/dictionary_editor.py index 949fad275..457583dff 100644 --- a/plover/gui/dictionary_editor.py +++ b/plover/gui/dictionary_editor.py @@ -358,4 +358,4 @@ def clear_instance(): clear_instance) Show.dialog_instance.Show() Show.dialog_instance.Raise() - util.SetTopApp() + util.SetTopApp(Show.dialog_instance) From df660cf55c3f51ef0cdf2c78524fbb98df02cf0d Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Thu, 3 Mar 2016 19:37:33 +0100 Subject: [PATCH 02/10] gui/dictionary_editor: don't uppercase strokes --- plover/dictionary_editor_store.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/plover/dictionary_editor_store.py b/plover/dictionary_editor_store.py index d0212d5ec..1c0667076 100644 --- a/plover/dictionary_editor_store.py +++ b/plover/dictionary_editor_store.py @@ -141,7 +141,7 @@ def SaveChanges(self): dict = (self.engine .get_dictionary() .get_by_path(added_item.dictionary)) - dict.__setitem__(self._splitStrokes(added_item.stroke), + dict.__setitem__(normalize_steno(added_item.stroke), added_item.translation) # Updates @@ -150,7 +150,7 @@ def SaveChanges(self): dict = (self.engine .get_dictionary() .get_by_path(modified_item.dictionary)) - dict.__setitem__(self._splitStrokes(modified_item.stroke), + dict.__setitem__(normalize_steno(modified_item.stroke), modified_item.translation) # Deletes @@ -158,7 +158,7 @@ def SaveChanges(self): dict = (self.engine .get_dictionary() .get_by_path(deleted_item.dictionary)) - dict.__delitem__(self._splitStrokes(deleted_item.stroke)) + dict.__delitem__(normalize_steno(deleted_item.stroke)) self.engine.get_dictionary().save_all() @@ -226,7 +226,3 @@ def _applySort(self): reverse=reverse_sort) else: self.sorted_keys = self.filtered_keys[:] - - def _splitStrokes(self, strokes_string): - result = normalize_steno(strokes_string.upper()) - return result From 5679c44908f6883398410ef8cc147f8e77d613d4 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Sun, 20 Mar 2016 04:15:54 +0100 Subject: [PATCH 03/10] gui/dictionary_editor: minor simplifications --- plover/dictionary_editor_store.py | 33 +++++++++++-------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/plover/dictionary_editor_store.py b/plover/dictionary_editor_store.py index 1c0667076..abf94ad1c 100644 --- a/plover/dictionary_editor_store.py +++ b/plover/dictionary_editor_store.py @@ -54,12 +54,12 @@ def __init__(self, engine, config): self.pending_changes = False - for dict in reversed(self.engine.get_dictionary().dicts): - for dk, translation in dict.iteritems(): + for dictionary in reversed(self.engine.get_dictionary().dicts): + for dk, translation in dictionary.iteritems(): joined = '/'.join(dk) item = DictionaryItem(joined, translation, - dict.get_path(), + dictionary, item_id) self.all_keys.append(item) item_id += 1 @@ -78,7 +78,7 @@ def GetValue(self, row, col): elif col is COL_TRANSLATION: result = shorten_unicode(item.translation) elif col is COL_DICTIONARY: - result = item.dictionary + result = item.dictionary.get_path() return result def SetValue(self, row, col, value): @@ -137,28 +137,17 @@ def SaveChanges(self): self.pending_changes = False # Creates - for added_item in self.added_items: - dict = (self.engine - .get_dictionary() - .get_by_path(added_item.dictionary)) - dict.__setitem__(normalize_steno(added_item.stroke), - added_item.translation) + for item in self.added_items: + item.dictionary[normalize_steno(item.stroke)] = item.translation # Updates - for modified_item_id in self.modified_items: - modified_item = self.all_keys[modified_item_id] - dict = (self.engine - .get_dictionary() - .get_by_path(modified_item.dictionary)) - dict.__setitem__(normalize_steno(modified_item.stroke), - modified_item.translation) + for item_id in self.modified_items: + item = self.all_keys[item_id] + item.dictionary[normalize_steno(item.stroke)] = item.translation # Deletes - for deleted_item in self.deleted_items: - dict = (self.engine - .get_dictionary() - .get_by_path(deleted_item.dictionary)) - dict.__delitem__(normalize_steno(deleted_item.stroke)) + for item in self.deleted_items: + del item.dictionary[normalize_steno(item.stroke)] self.engine.get_dictionary().save_all() From e9dab191b07ca8b3cded26b5d0b75c138b6db197 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Wed, 2 Mar 2016 23:55:14 +0100 Subject: [PATCH 04/10] gui/add_translation: don't uppercase strokes --- plover/gui/add_translation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plover/gui/add_translation.py b/plover/gui/add_translation.py index b14f5b2f9..be5fb9e9c 100644 --- a/plover/gui/add_translation.py +++ b/plover/gui/add_translation.py @@ -233,7 +233,7 @@ def _apply_opacity(self, opacity): self.SetTransparent(alpha_byte) def _normalized_strokes(self): - strokes = self.strokes_text.GetValue().upper().replace('/', ' ').split() + strokes = self.strokes_text.GetValue().replace('/', ' ').split() strokes = normalize_steno('/'.join(strokes)) return strokes From 7257dc8a7594a0c1b66b6b056c4280f972974257 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Sun, 20 Mar 2016 05:42:09 +0100 Subject: [PATCH 05/10] steno_dictionary: improve save API - only one 'save' function, with an optional 'path_list' parameter to only save those dictionaries - don't save read-only (no 'save' function set) dictionaries --- plover/steno_dictionary.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/plover/steno_dictionary.py b/plover/steno_dictionary.py index ee22275f5..53c056a44 100644 --- a/plover/steno_dictionary.py +++ b/plover/steno_dictionary.py @@ -167,13 +167,19 @@ def set(self, key, value): if self.dicts: self.dicts[0][key] = value - def save(self): - if self.dicts: - self.dicts[0].save() - - def save_all(self): - for dict in self.dicts: - dict.save() + def save(self, path_list=None): + '''Save the dictionaries in . + + If is None, all writable dictionaries are saved''' + if path_list is None: + dict_list = [dictionary + for dictionary in self.dicts + if dictionary.save is not None] + else: + dict_list = [self.get_by_path(path) + for path in path_list] + for dictionary in dict_list: + dictionary.save() def get_by_path(self, path): for d in self.dicts: From 19019e6c7f3f5752854a0c8698708d888087a55d Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Sun, 20 Mar 2016 05:46:11 +0100 Subject: [PATCH 06/10] gui/dictionary_editor: update save code --- plover/dictionary_editor_store.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plover/dictionary_editor_store.py b/plover/dictionary_editor_store.py index abf94ad1c..d283fc5bf 100644 --- a/plover/dictionary_editor_store.py +++ b/plover/dictionary_editor_store.py @@ -136,20 +136,26 @@ def DeleteSelected(self, row): def SaveChanges(self): self.pending_changes = False + # Set of dictionaries (paths) that needs saving. + needs_saving = set() + # Creates for item in self.added_items: item.dictionary[normalize_steno(item.stroke)] = item.translation + needs_saving.add(item.dictionary.get_path()) # Updates for item_id in self.modified_items: item = self.all_keys[item_id] item.dictionary[normalize_steno(item.stroke)] = item.translation + needs_saving.add(item.dictionary.get_path()) # Deletes for item in self.deleted_items: del item.dictionary[normalize_steno(item.stroke)] + needs_saving.add(item.dictionary.get_path()) - self.engine.get_dictionary().save_all() + self.engine.get_dictionary().save(needs_saving) def Sort(self, column): if column is not COL_STROKE and column is not COL_TRANSLATION: From f49520436effe576be8a2e4f7004da3abd4524dc Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Sun, 20 Mar 2016 05:49:02 +0100 Subject: [PATCH 07/10] gui/add_translation: update save code --- plover/gui/add_translation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plover/gui/add_translation.py b/plover/gui/add_translation.py index be5fb9e9c..639a98b90 100644 --- a/plover/gui/add_translation.py +++ b/plover/gui/add_translation.py @@ -133,7 +133,7 @@ def on_add_translation(self, event=None): translation = self.translation_text.GetValue().strip() if strokes and translation: d.set(strokes, translation) - d.save() + d.save(path_list=(d.dicts[0].get_path(),)) self.Close() def on_close(self, event=None): From 13a940ce929000cf4261c34fb6155792666f2c0e Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Sun, 20 Mar 2016 18:51:40 +0100 Subject: [PATCH 08/10] steno_dictionary: minor simplifications --- plover/steno_dictionary.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/plover/steno_dictionary.py b/plover/steno_dictionary.py index 53c056a44..744c5eb82 100644 --- a/plover/steno_dictionary.py +++ b/plover/steno_dictionary.py @@ -51,15 +51,14 @@ def __getitem__(self, key): def __setitem__(self, key, value): self._longest_key = max(self._longest_key, len(key)) - self._dict.__setitem__(key, value) + self._dict[key] = value self.reverse[value].append(key) # Case-insensitive reverse dict self.casereverse[value.lower()].add(value) def __delitem__(self, key): - value = self._dict[key] + value = self._dict.pop(key) self.reverse[value].remove(key) - self._dict.__delitem__(key) if len(key) == self.longest_key: if self._dict: self._longest_key = max(len(x) for x in self._dict.iterkeys()) @@ -67,10 +66,9 @@ def __delitem__(self, key): self._longest_key = 0 def __contains__(self, key): - contained = self._dict.__contains__(key) - if not contained: + value = self._dict.get(key) + if value is None: return False - value = self._dict[key] for f in self.filters: if f(key, value): return False @@ -138,7 +136,7 @@ def set_dicts(self, dicts): def lookup(self, key): for d in self.dicts: - value = d.get(key, None) + value = d.get(key) if value: for f in self.filters: if f(key, value): @@ -147,19 +145,19 @@ def lookup(self, key): def raw_lookup(self, key): for d in self.dicts: - value = d.get(key, None) + value = d.get(key) if value: return value def reverse_lookup(self, value): for d in self.dicts: - key = d.reverse.get(value, None) + key = d.reverse.get(value) if key: return key def casereverse_lookup(self, value): for d in self.dicts: - key = d.casereverse.get(value, None) + key = d.casereverse.get(value) if key: return key From 7faeb305c95ee08bf315499916bcd8b67fd283b8 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Sun, 20 Mar 2016 19:19:56 +0100 Subject: [PATCH 09/10] gui/dictionary_editor: handle read-only dictionaries Don't allow modifying entries from read-only dictionaries. --- plover/dictionary_editor_store.py | 4 ++++ plover/gui/dictionary_editor.py | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/plover/dictionary_editor_store.py b/plover/dictionary_editor_store.py index d283fc5bf..c82337d50 100644 --- a/plover/dictionary_editor_store.py +++ b/plover/dictionary_editor_store.py @@ -66,6 +66,10 @@ def __init__(self, engine, config): self.filtered_keys = self.all_keys[:] self.sorted_keys = self.filtered_keys[:] + def is_row_read_only(self, row): + item = self.sorted_keys[row] + return item.dictionary.save is None + def GetNumberOfRows(self): return len(self.sorted_keys) diff --git a/plover/gui/dictionary_editor.py b/plover/gui/dictionary_editor.py index 457583dff..7ed26625c 100644 --- a/plover/gui/dictionary_editor.py +++ b/plover/gui/dictionary_editor.py @@ -91,12 +91,6 @@ def __init__(self, parent, engine, config, on_exit): self.grid.SetColSize(COL_TRANSLATION, 250) self.grid.SetColSize(COL_DICTIONARY, 150) - read_only_right_aligned = wx.grid.GridCellAttr() - read_only_right_aligned.SetReadOnly(True) - read_only_right_aligned.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE) - self.grid.SetColAttr(COL_DICTIONARY, read_only_right_aligned) - self.grid.SetColAttr(COL_SPACER, read_only_right_aligned) - global_sizer.Add(self.grid, 1, wx.EXPAND) buttons_sizer = wx.BoxSizer(wx.HORIZONTAL) @@ -302,6 +296,18 @@ def GetValue(self, row, col): def SetValue(self, row, col, value): self.store.SetValue(row, col, value) + def GetAttr(self, row, col, params): + if col in (COL_DICTIONARY, COL_SPACER): + attr = wx.grid.GridCellAttr() + attr.SetReadOnly(True) + attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE) + return attr + if self.store.is_row_read_only(row): + attr = wx.grid.GridCellAttr() + attr.SetReadOnly(True) + return attr + return None + def ResetView(self, grid): grid.BeginBatch() From fbb3cc5bac9ad47c7357499d486c99c0af426af2 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Tue, 22 Mar 2016 17:44:29 +0100 Subject: [PATCH 10/10] gui/dictionary_editor: improve selection handling - track selection (so multiple-rows selections work as expected) - correctly ignore read-only rows on deletion - insert new row before the selection first non-read only selected rows (if any), and automatically show/select/focus the new row --- plover/gui/dictionary_editor.py | 46 ++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/plover/gui/dictionary_editor.py b/plover/gui/dictionary_editor.py index 7ed26625c..2939e6501 100644 --- a/plover/gui/dictionary_editor.py +++ b/plover/gui/dictionary_editor.py @@ -8,7 +8,7 @@ from plover.dictionary_editor_store import COL_TRANSLATION from plover.dictionary_editor_store import COL_DICTIONARY from plover.dictionary_editor_store import COL_SPACER -from wx.grid import EVT_GRID_LABEL_LEFT_CLICK +from wx.grid import EVT_GRID_LABEL_LEFT_CLICK, EVT_GRID_SELECT_CELL, EVT_GRID_RANGE_SELECT from wx.grid import PyGridTableBase TITLE = 'Plover: Dictionary Editor' @@ -198,11 +198,18 @@ def __init__(self, *args, **kwargs): self._changedRow = None + # We need to keep track of the selection ourselves... + self.Bind(EVT_GRID_SELECT_CELL, self._on_select_cell) + self.Bind(EVT_GRID_RANGE_SELECT, self._on_select_range) + self.selection = set() + def CreateGrid(self, store, rows, cols): """ Create the grid """ wx.grid.Grid.CreateGrid(self, rows, cols) wx.grid.Grid.DisableDragRowSize(self) + # TODO: enable this when wx is fixed... + # self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows) self.store = store @@ -219,14 +226,28 @@ def RefreshView(self): self._table.ResetView(self) def InsertNew(self): - selected_row = self.GetGridCursorRow() - self.store.InsertNew(selected_row) - self._table.ResetView(self) + for row in self.selection: + if not self.store.is_row_read_only(row): + self.store.InsertNew(row) + self._table.ResetView(self) + self.SetFocus() + self.ClearSelection() + self.SelectRow(row) + self.SetGridCursor(row, 0) + self.MakeCellVisible(row, 0) + break + else: + self.ClearSelection() def DeleteSelected(self): - selected_row = self.GetGridCursorRow() - self.store.DeleteSelected(selected_row) - self._table.ResetView(self) + delete_selection = [row for row in self.selection + if not self.store.is_row_read_only(row)] + if delete_selection: + # Delete in reverse order, so row numbers are stable. + for row in sorted(delete_selection, reverse=True): + self.store.DeleteSelected(row) + self._table.ResetView(self) + self.ClearSelection() def _onLabelClick(self, evt): """ Handle Grid label click""" @@ -255,6 +276,17 @@ def _updateGridLabel(self, column, mode): (directionLabel if column == i else "")) self._table.SetColLabelValue(i, label) + def _on_select_cell(self, evt): + row = evt.GetRow() + self.selection = set((row,)) + + def _on_select_range(self, evt): + select_range = set(range(evt.GetTopRow(), evt.GetBottomRow() + 1)) + if evt.Selecting(): + self.selection |= select_range + else: + self.selection -= select_range + class DictionaryEditorGridTable(PyGridTableBase): """