Project

General

Profile

Bug #2019 » clone.py

Filippi Marco, 12/29/2014 02:31 AM

 
# Copyright 2008 Dan Smith <dsmith@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 threading
import os

import gtk
import gobject

from chirp import platform, directory, detect, chirp_common
from chirpui import miscwidgets, cloneprog, inputdialog, common, config

AUTO_DETECT_STRING = "Auto Detect (Icom Only)"

class CloneSettings:
def __init__(self):
self.port = None
self.radio_class = None

def __str__(self):
s = ""
if self.radio_class:
return _("{vendor} {model} on {port}").format(\
vendor=self.radio_class.VENDOR,
model=self.radio_class.MODEL,
port=self.port)

class CloneSettingsDialog(gtk.Dialog):
def __make_field(self, label, widget):
l = gtk.Label(label)
self.__table.attach(l, 0, 1, self.__row, self.__row+1)
self.__table.attach(widget, 1, 2, self.__row, self.__row+1)
self.__row += 1

l.show()
widget.show()

def __make_port(self, port):
conf = config.get("state")

ports = platform.get_platform().list_serial_ports()
if not port:
if conf.get("last_port"):
port = conf.get("last_port")
elif ports:
port = ports[0]
else:
port = ""
if not port in ports:
ports.insert(0, port)

return miscwidgets.make_choice(ports, True, port)

def __make_model(self):
return miscwidgets.make_choice([], False)

def __make_vendor(self, model):
vendors = {}
for rclass in sorted(directory.DRV_TO_RADIO.values()):
if not issubclass(rclass, chirp_common.CloneModeRadio) and \
not issubclass(rclass, chirp_common.LiveRadio):
continue

if not vendors.has_key(rclass.VENDOR):
vendors[rclass.VENDOR] = []

vendors[rclass.VENDOR].append(rclass)

self.__vendors = vendors

conf = config.get("state")
if not conf.get("last_vendor"):
conf.set("last_vendor", sorted(vendors.keys())[0])

last_vendor = conf.get("last_vendor")
if last_vendor not in vendors.keys():
last_vendor = vendors.keys()[0]

v = miscwidgets.make_choice(sorted(vendors.keys()), False, last_vendor)

def _changed(box, vendors, model):
models = vendors[box.get_active_text()]

added_models = []

model.get_model().clear()
for rclass in sorted(models, key=lambda c: c.__name__):
if rclass.MODEL not in added_models:
model.append_text(rclass.MODEL)
added_models.append(rclass.MODEL)

if box.get_active_text() in detect.DETECT_FUNCTIONS:
model.insert_text(0, _("Detect"))
added_models.insert(0, _("Detect"))

model_names = [x.MODEL for x in models]
if conf.get("last_model") in model_names:
model.set_active(added_models.index(conf.get("last_model")))
else:
model.set_active(0)

v.connect("changed", _changed, vendors, model)
_changed(v, vendors, model)

return v

def __make_ui(self, settings):
self.__table = gtk.Table(3, 2)
self.__table.set_row_spacings(3)
self.__table.set_col_spacings(10)
self.__row = 0

self.__port = self.__make_port(settings and settings.port or None)
self.__modl = self.__make_model()
self.__vend = self.__make_vendor(self.__modl)

self.__make_field(_("Port"), self.__port)
self.__make_field(_("Vendor"), self.__vend)
self.__make_field(_("Model"), self.__modl)

if settings and settings.radio_class:
common.combo_select(self.__vend, settings.radio_class.VENDOR)
self.__modl.get_model().clear()
self.__modl.append_text(settings.radio_class.MODEL)
common.combo_select(self.__modl, settings.radio_class.MODEL)
self.__vend.set_sensitive(False)
self.__modl.set_sensitive(False)
self.__prompt_force_after = gtk.CheckButton()
try:
self.__prompt_force_after.set_tooltip_text(
_("Try this if download work but upload fails immediately"))
except:
pass
self.__prompt_force_after.set_active(
config.get("upload_prompt").get_bool("force_after"))
self.__make_field(
_("Force alternative\nopen schema"),
self.__prompt_force_after)

self.__table.show()
self.vbox.pack_start(self.__table, 1, 1, 1)

def __init__(self, settings=None, parent=None, title=_("Radio")):
buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_OK, gtk.RESPONSE_OK)
gtk.Dialog.__init__(self, title,
parent=parent,
flags=gtk.DIALOG_MODAL)
self.__make_ui(settings)
self.__cancel_button = self.add_button(gtk.STOCK_CANCEL,
gtk.RESPONSE_CANCEL)
self.__okay_button = self.add_button(gtk.STOCK_OK,
gtk.RESPONSE_OK)
self.__okay_button.grab_default()
self.__okay_button.grab_focus()

def run(self):
r = gtk.Dialog.run(self)
if r != gtk.RESPONSE_OK:
return None

vendor = self.__vend.get_active_text()
model = self.__modl.get_active_text()

cs = CloneSettings()
cs.port = self.__port.get_active_text()
if model == _("Detect"):
try:
cs.radio_class = detect.DETECT_FUNCTIONS[vendor](cs.port)
if not cs.radio_class:
raise Exception(_("Unable to detect radio on {port}").format(port=cs.port))
except Exception, e:
d = inputdialog.ExceptionDialog(e)
d.run()
d.destroy()
return None
else:
for rclass in directory.DRV_TO_RADIO.values():
if rclass.MODEL == model:
cs.radio_class = rclass
break
if not cs.radio_class:
common.show_error(_("Internal error: Unable to upload to {model}").format(model=model))
print self.__vendors
return None

conf = config.get("state")
conf.set("last_port", cs.port)
conf.set("last_vendor", cs.radio_class.VENDOR)
conf.set("last_model", model)
try:
if self.__prompt_force_after != None:
config.get("upload_prompt").set_bool("force_after", self.__prompt_force_after.get_active())
except:
pass

return cs

class CloneCancelledException(Exception):
pass

class CloneThread(threading.Thread):
def __status(self, status):
gobject.idle_add(self.__progw.status, status)

def __init__(self, radio, direction, cb=None, parent=None):
threading.Thread.__init__(self)

self.__radio = radio
self.__out = direction == "out"
self.__cback = cb
self.__cancelled = False

self.__progw = cloneprog.CloneProg(parent=parent, cancel=self.cancel)

def cancel(self):
self.__radio.pipe.close()
self.__cancelled = True

def run(self):
print "Clone thread started"

gobject.idle_add(self.__progw.show)

self.__radio.status_fn = self.__status

try:
if self.__out:
self.__radio.sync_out()
else:
self.__radio.sync_in()

emsg = None
except Exception, e:
common.log_exception()
print _("Clone failed: {error}").format(error=e)
emsg = e

gobject.idle_add(self.__progw.hide)

# NB: Compulsory close of the radio's serial connection
self.__radio.pipe.close()

print "Clone thread ended"

if self.__cback and not self.__cancelled:
gobject.idle_add(self.__cback, self.__radio, emsg)

if __name__ == "__main__":
d = CloneSettingsDialog("/dev/ttyUSB0")
r = d.run()
print r
(2-2/3)