[chirp_devel] [PATCH 2 of 2] Add memory detail editor

Dan Smith
Mon May 7 17:22:05 PDT 2012


# HG changeset patch
# User Dan Smith <dsmith at danplanet.com>
# Date 1336436519 25200
# Node ID 06d821868172fdd77282ebef4c785d050be09360
# Parent  d059f6451dc6c0e6c173b624cb8616e7e28c74c7
Add memory detail editor

This adds an "Edit" option to the right-click context menu for a memory,
which opens a dialog window allowing somewhat easier atomic editing of a
memory's values. I think this will provide an easier way to expose some
more complicated and radio-specific features of the memory objects,
such as split tones and perhaps even D-STAR attributes.

#00

diff -r d059f6451dc6 -r 06d821868172 chirpui/memdetail.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chirpui/memdetail.py	Mon May 07 17:21:59 2012 -0700
@@ -0,0 +1,175 @@
+# Copyright 2012 Dan Smith <dsmith at danplanet.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import gtk
+
+from chirp import chirp_common
+from chirpui import miscwidgets
+
+POL = ["NN", "NR", "RN", "RR"]
+
+class ValueEditor:
+    """Base class"""
+    def __init__(self, features, memory, errfn, name, data=None):
+        self._features = features
+        self._memory = memory
+        self._errfn = errfn
+        self._name = name
+        self._widget = None
+        self._init(data)
+
+    def _init(self, data):
+        """Type-specific initialization"""
+
+    def get_widget(self):
+        """Returns the widget associated with this editor"""
+        return self._widget
+
+    def _mem_value(self):
+        """Returns the raw value from the memory associated with this name"""
+        return getattr(self._memory, self._name)
+
+    def _get_value(self):
+        """Returns the value from the widget that should be set in the memory"""
+
+    def update(self):
+        """Updates the memory object with self._getvalue()"""
+
+        try:
+            setattr(self._memory, self._name, self._get_value())
+        except ValueError, e:
+            self._errfn(self._name, str(e))
+            return str(e)
+        print self._memory
+        
+        # Validate!
+
+        self._errfn(self._name, None)
+
+class StringEditor(ValueEditor):
+    def _init(self, data):
+        self._widget = gtk.Entry(int(data))
+        self._widget.set_text(str(self._mem_value()))
+        self._widget.connect("changed", self.changed)
+
+    def _get_value(self):
+        return self._widget.get_text()
+
+    def changed(self, _widget):
+        self.update()
+
+class ChoiceEditor(ValueEditor):
+    def _init(self, data):
+        self._widget = miscwidgets.make_choice([str(x) for x in data],
+                                               False,
+                                               str(self._mem_value()))
+        self._widget.connect("changed", self.changed)
+
+    def _get_value(self):
+        return self._widget.get_active_text()
+
+    def changed(self, _widget):
+        self.update()
+
+class FloatChoiceEditor(ChoiceEditor):
+    def _get_value(self):
+        return float(self._widget.get_active_text())
+
+class FreqEditor(StringEditor):
+    def _init(self, data):
+        StringEditor._init(self, 0)
+        self._widget.set_text(chirp_common.format_freq(self._mem_value()))
+
+    def _get_value(self):
+        return chirp_common.parse_freq(self._widget.get_text())
+
+class OffsetEditor(FreqEditor):
+    pass
+
+class MemoryDetailEditor(gtk.Dialog):
+    """Detail editor for a memory"""
+
+    def _make_ui(self):
+        tab = gtk.Table(len(self._order), 3, False)
+        self.vbox.pack_start(tab, 1, 1, 1)
+        tab.show()
+
+        row = 0
+
+        def err(name, msg):
+            _img = self._editors[name][1]
+            if msg is None:
+                _img.clear()
+            else:
+                _img.set_from_stock(gtk.STOCK_NO, gtk.ICON_SIZE_MENU)
+
+        for name in self._order:
+            labeltxt, editorcls, data = self._elements[name]
+
+            label = gtk.Label(labeltxt)
+            img = gtk.Image()
+
+            editor = editorcls(self._features, self._memory,
+                               err, name, data)
+
+            label.show()
+            tab.attach(label, 0, 1, row, row+1)
+
+            img.set_size_request(15, -1)
+            img.show()
+            tab.attach(img, 2, 3, row, row+1)
+
+            editor.get_widget().show()
+            tab.attach(editor.get_widget(), 1, 2, row, row+1)
+
+            self._editors[name] = editor, img
+            row += 1
+
+    def __init__(self, features, memory, parent=None):
+        gtk.Dialog.__init__(self,
+                            title=_("Edit Memory #{num}").format(num=memory.number),
+                            parent=parent,
+                            buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
+                                     gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
+        self._features = features
+        self._memory = memory
+
+        self._editors = {}
+        self._elements = {
+            "freq" : (_("Frequency"), FreqEditor, None),
+            "name" : (_("Name"), StringEditor, features.valid_name_length),
+            "tmode" : (_("Tone Mode"), ChoiceEditor, features.valid_tmodes),
+            "rtone" : (_("Tone"), FloatChoiceEditor, chirp_common.TONES),
+            "ctone" : (_("ToneSql"), FloatChoiceEditor, chirp_common.TONES),
+            "dtcs"  : (_("DTCS Code"), ChoiceEditor, chirp_common.DTCS_CODES),
+            "dtcs_polarity" : (_("DTCS Pol"), ChoiceEditor, POL),
+            "cross_mode" : (_("Cross mode"), ChoiceEditor, features.valid_cross_modes),
+            "duplex" : (_("Duplex"), ChoiceEditor, features.valid_duplexes),
+            "offset" : (_("Offset"), OffsetEditor, None),
+            "mode" : (_("Mode"), ChoiceEditor, features.valid_modes),
+            # Power
+            "tuning_step" : (_("Tune Step"), FloatChoiceEditor, features.valid_tuning_steps),
+            "skip" : (_("Skip"), ChoiceEditor, features.valid_skips),
+            "comment" : (_("Comment"), StringEditor, 256),
+            }
+        self._order = ["freq", "name", "tmode", "rtone", "ctone",
+                       "dtcs", "dtcs_polarity", "duplex", "offset",
+                       "mode", "tuning_step", "skip", "comment"]
+
+        self._make_ui()
+        self.set_default_size(400, -1)
+
+    def get_memory(self):
+        return self._memory
diff -r d059f6451dc6 -r 06d821868172 chirpui/memedit.py
--- a/chirpui/memedit.py	Mon May 07 17:21:59 2012 -0700
+++ b/chirpui/memedit.py	Mon May 07 17:21:59 2012 -0700
@@ -32,7 +32,7 @@
 import pickle
 import os
 
-from chirpui import common, shiftdialog, miscwidgets, config
+from chirpui import common, shiftdialog, miscwidgets, config, memdetail
 from chirp import chirp_common, errors, directory, import_logic
 
 def handle_toggle(_, path, store, col):
@@ -612,6 +612,18 @@
         job.set_desc(_("Getting raw memory {number}").format(number=loc_b))
         self.rthread.submit(job)
 
+    def edit_memory(self, memory):
+        dlg = memdetail.MemoryDetailEditor(self._features, memory)
+        r = dlg.run()
+        if r == gtk.RESPONSE_OK:
+            self.need_refresh = True
+            mem = dlg.get_memory()
+            job = common.RadioJob(self._set_memory_cb, "set_memory", mem)
+            job.set_desc(_("Writing memory {number}").format(number=mem.number))
+            self.rthread.submit(job)
+            self.emit("changed")
+        dlg.destroy()
+
     def mh(self, _action, store, paths):
         action = _action.get_name()
         iter = store.get_iter(paths[0])
@@ -648,6 +660,9 @@
             self._show_raw(cur_pos)
         elif action == "devdiffraw":
             self._diff_raw(paths)
+        elif action == "edit":
+            job = common.RadioJob(self.edit_memory, "get_memory", cur_pos)
+            self.rthread.submit(job)
 
         if changed:
             self.emit("changed")
@@ -671,7 +686,8 @@
 
         menu_xml = """
 <ui>
-  <popup name="Menu">
+  <popup name="Menu"> 
+    <menuitem action="edit"/>
     <menuitem action="insert_prev"/>
     <menuitem action="insert_next"/>
     <menuitem action="delete"/>
@@ -694,6 +710,7 @@
         istwo = len(paths) == 2
 
         actions = [
+            ("edit", _("Edit")),
             ("insert_prev", _("Insert row above")),
             ("insert_next", _("Insert row below")),
             ("delete", issingle and _("Delete") or _("Delete all")),



More information about the chirp_devel mailing list