Phil Dibowitz wrote:
> Stephen Warren wrote:
>> Version 6 of congruity is released.
>>
>> congruity is a Python/wxPython-based GUI for libconcord. It is intended
>> to handle downloads from the Harmony website, program the remote, and
>> communicate results back to the website - i.e. provide an open-source
>> replacement for the website interaction portion of the existing
>> proprietary GUI application.
>
> I'm getting a syntax error - though I have made no attempt to debug it:
>
> [EMAIL PROTECTED] congruity-6]$ congruity
> File "/usr/bin/congruity", line 58
> finally:
> ^
> SyntaxError: invalid syntax
Try the attached congruity script. I may have been relying on Python 2.5
syntax (I guess I should test with an older Python version sometime...)
#!/usr/bin/python
# This code NOT copyright Stephen Warren <[EMAIL PROTECTED]>
# This code is released into the public domain.
from ctypes import *
import os
import os.path
import sys
import thread
import time
import traceback
import wx
import wx.lib.dialogs
import libconcord
version = "6+"
def program_callback_imp(count, current, total, cb_func):
if not cb_func:
return
try:
cb_func(False, (current * 100) / total)
except:
print
traceback.print_exc()
def exception_message():
msg = ''
if type(sys.exc_value) == libconcord.LibConcordException:
msg += sys.exc_value.result_str + '\n\n'
msg += traceback.format_exc()
return msg
def program(type, xml, xml_size, handler):
action_func = {
libconcord.LC_FILE_TYPE_CONNECTIVITY: program_body_connectivity,
libconcord.LC_FILE_TYPE_CONFIGURATION: program_body_configuration,
libconcord.LC_FILE_TYPE_FIRMWARE: program_body_firmware
}[type]
need_deinit = [False]
try:
try:
program_callback = libconcord.callback_type(program_callback_imp)
program_body_connect(program_callback, handler, need_deinit)
set_time = action_func(xml, xml_size, program_callback, handler)
need_deinit[0] = False
program_body_disconnect(program_callback, handler)
if set_time:
program_body_reconnect_set_time(program_callback, handler,
need_deinit)
handler.on_final_status(True, '')
except:
handler.on_final_status(False, exception_message())
finally:
try:
if need_de_init[0]:
program_disconnect(handler)
except:
pass
def program_body_connect(program_callback, handler, need_deinit):
if handler:
handler.on_requesting_id(False, 0)
libconcord.init_concord()
need_deinit[0] = True
if handler:
handler_f = py_object(handler.on_requesting_id)
else:
handler_f = None
libconcord.get_identity(
program_callback,
handler_f
)
sys.stdout.flush()
if handler:
handler.on_requesting_id(True, 100)
def program_body_connectivity(xml, xml_size, program_callback, handler):
handler.on_web_notify_final(False, 0)
libconcord.post_connect_test_success(xml, xml_size)
handler.on_web_notify_final(True, 100)
return False
def program_body_configuration(xml, xml_size, program_callback, handler):
handler.on_web_notify_init(False, 0)
libconcord.post_preconfig(xml, xml_size)
handler.on_web_notify_init(True, 100)
handler.on_prepare(False, 0)
bin_data = POINTER(c_ubyte)()
bin_size = c_uint()
libconcord.find_config_binary(
xml,
xml_size,
byref(bin_data),
byref(bin_size)
)
handler.on_prepare(False, 50)
libconcord.invalidate_flash()
handler.on_prepare(True, 100)
handler.on_erasing_flash(False, 0)
libconcord.erase_config(
bin_size,
program_callback,
py_object(handler.on_erasing_flash)
)
handler.on_erasing_flash(True, 100)
handler.on_writing_config(False, 0)
libconcord.write_config_to_remote(
bin_data,
bin_size,
program_callback,
py_object(handler.on_writing_config)
)
handler.on_writing_config(True, 100)
handler.on_verifying_config(False, 0)
libconcord.verify_remote_config(
bin_data,
bin_size,
program_callback,
py_object(handler.on_verifying_config)
)
handler.on_verifying_config(True, 100)
handler.on_web_notify_final(False, 0)
libconcord.post_postconfig(xml, xml_size)
handler.on_web_notify_final(True, 100)
libconcord.reset_remote()
return True
def program_body_firmware(xml, xml_size, program_callback, handler):
handler.on_prepare(False, 0)
# is_fw_update_supported returns error code; 0 OK, otherwise failure
if not libconcord.is_fw_update_supported(0):
is_direct = False
elif not libconcord.is_fw_update_supported(1):
is_direct = True
else:
raise Exception('Firmware update not supported on this remote.')
handler.on_prepare(True, 25)
bin_data = POINTER(c_ubyte)()
bin_size = c_uint()
libconcord.extract_firmware_binary(
xml,
xml_size,
byref(bin_data),
byref(bin_size)
)
handler.on_prepare(True, 50)
if not is_direct:
libconcord.prep_firmware()
handler.on_prepare(True, 75)
libconcord.invalidate_flash()
handler.on_prepare(True, 100)
handler.on_erasing_flash(False, 0)
libconcord.erase_firmware(
is_direct,
program_callback,
py_object(handler.on_erasing_flash)
)
handler.on_erasing_flash(True, 100)
handler.on_writing_config(False, 0)
libconcord.write_firmware_to_remote(
bin_data,
bin_size,
c_int(is_direct and 1 or 0),
program_callback,
py_object(handler.on_writing_config)
)
handler.on_writing_config(True, 100)
handler.on_finalize(False, 0)
if not is_direct:
libconcord.finish_firmware()
handler.on_finalize(True, 100)
handler.on_web_notify_final(False, 0)
libconcord.post_postfirmware(xml, xml_size)
handler.on_web_notify_final(True, 100)
libconcord.reset_remote()
return True
def program_body_disconnect(program_callback, handler):
libconcord.deinit_concord()
def program_body_reconnect_set_time(program_callback, handler, need_deinit):
max_attempts = 60
connected = False
for attempt in range(max_attempts):
handler.on_reconnect(False, (attempt * 100) / max_attempts)
try:
program_body_connect(program_callback, None, need_deinit)
connected = True
break
except:
pass
time.sleep(1)
if not connected:
# Force exception if we still can't connect
program_body_connect(program_callback, None, need_deinit)
handler.on_reconnect(True, 100)
handler.on_set_time(False, 0)
libconcord.set_time()
handler.on_set_time(True, 100)
need_deinit[0] = False
program_body_disconnect(program_callback, handler)
class HandlerProxy(object):
def __init__(self, real_handler):
self.real_handler = real_handler
def on_requesting_id(self, is_done, percent):
wx.CallAfter(self.real_handler.on_requesting_id, is_done, percent)
def on_web_notify_init(self, is_done, percent):
wx.CallAfter(self.real_handler.on_web_notify_init, is_done, percent)
def on_prepare(self, is_done, percent):
wx.CallAfter(self.real_handler.on_prepare, is_done, percent)
def on_erasing_flash(self, is_done, percent):
wx.CallAfter(self.real_handler.on_erasing_flash, is_done, percent)
def on_writing_config(self, is_done, percent):
wx.CallAfter(self.real_handler.on_writing_config, is_done, percent)
def on_verifying_config(self, is_done, percent):
wx.CallAfter(self.real_handler.on_verifying_config, is_done, percent)
def on_finalize(self, is_done, percent):
wx.CallAfter(self.real_handler.on_finalize, is_done, percent)
def on_web_notify_final(self, is_done, percent):
wx.CallAfter(self.real_handler.on_web_notify_final, is_done, percent)
def on_reconnect(self, is_done, percent):
wx.CallAfter(self.real_handler.on_reconnect, is_done, percent)
def on_set_time(self, is_done, percent):
wx.CallAfter(self.real_handler.on_set_time, is_done, percent)
def on_final_status(self, was_success, log):
wx.CallAfter(self.real_handler.on_final_status, was_success, log)
class MessagePanelBase(wx.Panel):
def __init__(self, parent, resources, message):
self.resources = resources
wx.Panel.__init__(self, parent)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.text_message = wx.StaticText(self, -1, message)
self.text_message.Wrap(450)
self.sizer.Add(self.text_message, 0, wx.ALIGN_LEFT | wx.ALL, 5)
self.SetSizer(self.sizer)
def OnActivated(self):
pass
class WelcomePanel(MessagePanelBase):
def __init__(self, parent, resources):
MessagePanelBase.__init__(
self,
parent,
resources,
"Welcome to congruity; a programming application " +
"for Logitech Harmony remote controls.\n\n" +
"Click Next to start programming."
)
def GetTitle(self):
return "Welcome"
def IsTerminal(self):
return False
def GetExitCode(self):
return None
def IsNextInitiallyDisabled(self):
return False
def IsCancelable(self):
return True
def GetNext(self):
try:
xml = POINTER(c_ubyte)()
xml_size = c_uint()
libconcord.read_file(
self.resources.ezhex_filename,
byref(xml),
byref(xml_size)
)
self.resources.SetXmlData(xml, xml_size)
except:
self.resources.page_failure.SetMessages(
"The programming file cannot be read. " +
"Programming cannot continue.",
exception_message()
)
return self.resources.page_failure
try:
type = c_int()
libconcord.identify_file(xml, xml_size, byref(type))
next_page = {
libconcord.LC_FILE_TYPE_CONNECTIVITY:
self.resources.page_check_connectivity,
libconcord.LC_FILE_TYPE_CONFIGURATION:
self.resources.page_write_configuration,
libconcord.LC_FILE_TYPE_FIRMWARE:
self.resources.page_update_firmware
}.get(type.value, None)
if next_page:
return next_page
self.resources.page_failure.SetMessages(
"This kind of programming file is not currently " +
"supported. Programming cannot continue.",
None
)
return self.resources.page_failure
except:
self.resources.page_failure.SetMessages(
"The programming file could not be parsed " +
"to determine its type. Programming cannot continue.",
exception_message()
)
return self.resources.page_failure
class ProgramRemotePanelBase(wx.Panel):
def __init__(self, parent, resources, file_type):
self.parent = parent
self.resources = resources
self.file_type = file_type
wx.Panel.__init__(self, parent)
sizer = wx.GridBagSizer(5, 5)
iw = max(
resources.icon_in_progress.GetWidth(),
resources.icon_complete.GetWidth(),
resources.icon_failed.GetWidth()
)
ih = max(
resources.icon_in_progress.GetHeight(),
resources.icon_complete.GetHeight(),
resources.icon_failed.GetHeight()
)
iwh = (iw, ih)
vpos = 0
self.bmp_identify = wx.StaticBitmap(self, -1, resources.icon_unstarted,
None, iwh)
self.text_identify = wx.StaticText(self, -1, "Identify Remote")
self.gauge_identify = wx.Gauge(self, -1, 100, None, (250, ih))
sizer.Add(self.bmp_identify, (vpos, 0), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_BOTTOM | wx.ALL, 5)
sizer.Add(self.text_identify, (vpos, 1), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
sizer.Add(self.gauge_identify, (vpos, 2), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_BOTTOM | wx.ALL, 5)
vpos += 1
if self.file_type == libconcord.LC_FILE_TYPE_CONFIGURATION:
self.bmp_web_notify_init = wx.StaticBitmap(self, -1,
resources.icon_unstarted, None, iwh)
self.text_web_notify_init = wx.StaticText(self, -1, "Check Website")
self.gauge_web_notify_init = wx.Gauge(self, -1, 100, None, (250,
ih))
sizer.Add(self.bmp_web_notify_init, (vpos, 0), (1, 1),
wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.ALL, 5)
sizer.Add(self.text_web_notify_init, (vpos, 1), (1, 1),
wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
sizer.Add(self.gauge_web_notify_init, (vpos, 2), (1, 1),
wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.ALL, 5)
vpos += 1
if self.file_type != libconcord.LC_FILE_TYPE_CONNECTIVITY:
self.bmp_prepare = wx.StaticBitmap(self, -1,
resources.icon_unstarted, None, iwh)
self.text_prepare = wx.StaticText(self, -1, "Prepare Remote")
self.gauge_prepare = wx.Gauge(self, -1, 100, None, (250, ih))
sizer.Add(self.bmp_prepare, (vpos, 0), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_BOTTOM | wx.ALL, 5)
sizer.Add(self.text_prepare, (vpos, 1), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
sizer.Add(self.gauge_prepare, (vpos, 2), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_BOTTOM | wx.ALL, 5)
vpos += 1
self.bmp_erase_flash = wx.StaticBitmap(self, -1,
resources.icon_unstarted, None, iwh)
self.text_erase_flash = wx.StaticText(self, -1, "Erase Flash")
self.gauge_erase_flash = wx.Gauge(self, -1, 100, None, (250, ih))
sizer.Add(self.bmp_erase_flash, (vpos, 0), (1, 1), wx.ALIGN_LEFT
| wx.ALIGN_BOTTOM | wx.ALL, 5)
sizer.Add(self.text_erase_flash, (vpos, 1), (1, 1), wx.ALIGN_LEFT
| wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
sizer.Add(self.gauge_erase_flash, (vpos, 2), (1, 1), wx.ALIGN_LEFT
| wx.ALIGN_BOTTOM | wx.ALL, 5)
vpos += 1
if self.file_type == libconcord.LC_FILE_TYPE_CONFIGURATION:
write_type = "Configuration"
else:
write_type = "Firmware"
self.bmp_write_config = wx.StaticBitmap(self, -1,
resources.icon_unstarted, None, iwh)
self.text_write_config = wx.StaticText(self, -1, "Write " +
write_type)
self.gauge_write_config = wx.Gauge(self, -1, 100, None, (250, ih))
sizer.Add(self.bmp_write_config, (vpos, 0), (1, 1), wx.ALIGN_LEFT
| wx.ALIGN_BOTTOM | wx.ALL, 5)
sizer.Add(self.text_write_config, (vpos, 1), (1, 1), wx.ALIGN_LEFT
| wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
sizer.Add(self.gauge_write_config, (vpos, 2), (1, 1), wx.ALIGN_LEFT
| wx.ALIGN_BOTTOM | wx.ALL, 5)
vpos += 1
if self.file_type == libconcord.LC_FILE_TYPE_CONFIGURATION:
self.bmp_verify_config = wx.StaticBitmap(self, -1,
resources.icon_unstarted, None, iwh)
self.text_verify_config = wx.StaticText(self, -1, "Verify Upgrade")
self.gauge_verify_config = wx.Gauge(self, -1, 100, None, (250, ih))
sizer.Add(self.bmp_verify_config, (vpos, 0), (1, 1),
wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.ALL, 5)
sizer.Add(self.text_verify_config, (vpos, 1), (1, 1),
wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
sizer.Add(self.gauge_verify_config, (vpos, 2), (1, 1),
wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.ALL, 5)
vpos += 1
if self.file_type == libconcord.LC_FILE_TYPE_FIRMWARE:
self.bmp_finalize = wx.StaticBitmap(self, -1,
resources.icon_unstarted, None, iwh)
self.text_finalize = wx.StaticText(self, -1, "Finalize Programming")
self.gauge_finalize = wx.Gauge(self, -1, 100, None, (250, ih))
sizer.Add(self.bmp_finalize, (vpos, 0), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_BOTTOM | wx.ALL, 5)
sizer.Add(self.text_finalize, (vpos, 1), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
sizer.Add(self.gauge_finalize, (vpos, 2), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_BOTTOM | wx.ALL, 5)
vpos += 1
self.bmp_web_notify_final = wx.StaticBitmap(self, -1,
resources.icon_unstarted, None, iwh)
self.text_web_notify_final = wx.StaticText(self, -1, "Notify Website")
self.gauge_web_notify_final = wx.Gauge(self, -1, 100, None, (250, ih))
sizer.Add(self.bmp_web_notify_final, (vpos, 0), (1, 1), wx.ALIGN_LEFT
| wx.ALIGN_BOTTOM | wx.ALL, 5)
sizer.Add(self.text_web_notify_final, (vpos, 1), (1, 1), wx.ALIGN_LEFT
| wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
sizer.Add(self.gauge_web_notify_final, (vpos, 2), (1, 1), wx.ALIGN_LEFT
| wx.ALIGN_BOTTOM | wx.ALL, 5)
vpos += 1
if self.file_type != libconcord.LC_FILE_TYPE_CONNECTIVITY:
self.bmp_reconnect = wx.StaticBitmap(self, -1,
resources.icon_unstarted, None, iwh)
self.text_reconnect = wx.StaticText(self, -1, "Reconnect to Remote")
self.gauge_reconnect = wx.Gauge(self, -1, 100, None, (250, ih))
sizer.Add(self.bmp_reconnect, (vpos, 0), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_BOTTOM | wx.ALL, 5)
sizer.Add(self.text_reconnect, (vpos, 1), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
sizer.Add(self.gauge_reconnect, (vpos, 2), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_BOTTOM | wx.ALL, 5)
vpos += 1
self.bmp_set_time = wx.StaticBitmap(self, -1,
resources.icon_unstarted, None, iwh)
self.text_set_time = wx.StaticText(self, -1, "Set Time")
self.gauge_set_time = wx.Gauge(self, -1, 100, None, (250, ih))
sizer.Add(self.bmp_set_time, (vpos, 0), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_BOTTOM | wx.ALL, 5)
sizer.Add(self.text_set_time, (vpos, 1), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
sizer.Add(self.gauge_set_time, (vpos, 2), (1, 1), wx.ALIGN_LEFT |
wx.ALIGN_BOTTOM | wx.ALL, 5)
vpos += 1
sizer.AddGrowableCol(2)
self.SetSizerAndFit(sizer)
self.failure_bitmap = None
self.was_success = False
def _worker_function(self):
handler = HandlerProxy(self)
program(self.file_type, self.resources.xml, self.resources.xml_size,
handler)
def _on_progress(self, is_done, percent, bitmap, gauge):
if is_done:
bitmap.SetBitmap(self.resources.icon_complete)
else:
bitmap.SetBitmap(self.resources.icon_in_progress)
self.failure_bitmap = bitmap
gauge.SetValue(percent)
def on_requesting_id(self, is_done, percent):
self._on_progress(is_done, percent, self.bmp_identify,
self.gauge_identify)
def on_web_notify_init(self, is_done, percent):
self._on_progress(is_done, percent, self.bmp_web_notify_init,
self.gauge_web_notify_init)
def on_prepare(self, is_done, percent):
if self.file_type == libconcord.LC_FILE_TYPE_CONNECTIVITY:
return
self._on_progress(is_done, percent, self.bmp_prepare,
self.gauge_prepare)
def on_erasing_flash(self, is_done, percent):
if self.file_type == libconcord.LC_FILE_TYPE_CONNECTIVITY:
return
self._on_progress(is_done, percent, self.bmp_erase_flash,
self.gauge_erase_flash)
def on_writing_config(self, is_done, percent):
if self.file_type == libconcord.LC_FILE_TYPE_CONNECTIVITY:
return
self._on_progress(is_done, percent, self.bmp_write_config,
self.gauge_write_config)
def on_verifying_config(self, is_done, percent):
if self.file_type == libconcord.LC_FILE_TYPE_CONNECTIVITY:
return
self._on_progress(is_done, percent, self.bmp_verify_config,
self.gauge_verify_config)
def on_finalize(self, is_done, percent):
if self.file_type == libconcord.LC_FILE_TYPE_CONNECTIVITY:
return
self._on_progress(is_done, percent, self.bmp_finalize,
self.gauge_finalize)
def on_web_notify_final(self, is_done, percent):
self._on_progress(is_done, percent, self.bmp_web_notify_final,
self.gauge_web_notify_final)
def on_reconnect(self, is_done, percent):
self._on_progress(is_done, percent, self.bmp_reconnect,
self.gauge_reconnect)
def on_set_time(self, is_done, percent):
self._on_progress(is_done, percent, self.bmp_set_time,
self.gauge_set_time)
def on_final_status(self, was_success, log):
if not was_success:
bitmap = self.failure_bitmap
if not bitmap:
bitmap = self.bmp_identify
bitmap.SetBitmap(self.resources.icon_failed)
self.resources.page_failure.SetMessages('Programming failed.', log)
self.was_success = was_success
self.parent.ReenableNext()
def OnActivated(self):
thread.start_new_thread(self._worker_function, ())
def GetTitle(self):
return {
libconcord.LC_FILE_TYPE_CONNECTIVITY: "Checking Connectivity",
libconcord.LC_FILE_TYPE_CONFIGURATION: "Updating Configuration",
libconcord.LC_FILE_TYPE_FIRMWARE: "Updating Firmware"
}[self.file_type]
def IsTerminal(self):
return False
def GetExitCode(self):
return None
def IsNextInitiallyDisabled(self):
return True
def IsCancelable(self):
return False
def GetNext(self):
if self.was_success:
return self.resources.page_success
else:
return self.resources.page_failure
class CheckConnectivityPanel(ProgramRemotePanelBase):
def __init__(self, parent, resources):
ProgramRemotePanelBase.__init__(self, parent, resources,
libconcord.LC_FILE_TYPE_CONNECTIVITY)
class WriteConfigurationPanel(ProgramRemotePanelBase):
def __init__(self, parent, resources):
ProgramRemotePanelBase.__init__(self, parent, resources,
libconcord.LC_FILE_TYPE_CONFIGURATION)
class UpdateFirmwarePanel(ProgramRemotePanelBase):
def __init__(self, parent, resources):
ProgramRemotePanelBase.__init__(self, parent, resources,
libconcord.LC_FILE_TYPE_FIRMWARE)
class SuccessPanel(MessagePanelBase):
def __init__(self, parent, resources):
MessagePanelBase.__init__(self, parent, resources, "Programming has
completed successfully.")
def OnActivated(self):
pass
def GetTitle(self):
return "Success"
def IsTerminal(self):
return True
def GetExitCode(self):
return 0
def IsNextInitiallyDisabled(self):
return False
def IsCancelable(self):
return False
def GetNext(self):
return None
class FailurePanel(wx.Panel):
def __init__(self, parent, resources):
self.parent = parent
self.resources = resources
wx.Panel.__init__(self, parent)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.text_message = wx.StaticText(self, -1, "Programming failed; see
below for details")
self.text_message.Wrap(450)
self.sizer.Add(self.text_message, 0, wx.ALIGN_LEFT | wx.ALL, 5)
self.btn_details = wx.Button(self, -1, "&Details...")
self.Bind(wx.EVT_BUTTON, self.OnShowLogText, self.btn_details)
self.sizer.Add(self.btn_details, 0, wx.ALIGN_LEFT | wx.ALL, 5)
self.SetSizerAndFit(self.sizer)
self.log_text = ''
def SetMessages(self, message, traceback):
msg = message
if traceback:
msg += "\n\nSee below for details."
else:
self.btn_details.Hide()
self.text_message.SetLabel(msg)
self.log_text = traceback
def OnShowLogText(self, event):
size = self.parent.GetClientSizeTuple()
size = (size[0] * 90 / 100, size[1] * 90 / 100)
wx.lib.dialogs.ScrolledMessageDialog(self, self.log_text, "Error Log",
(-1, -1), size).ShowModal()
self.parent.ReenableNext()
def OnActivated(self):
self.btn_details.SetFocus()
def GetTitle(self):
return "Failure"
def IsTerminal(self):
return True
def GetExitCode(self):
return 1
def IsNextInitiallyDisabled(self):
return False
def IsCancelable(self):
return False
def GetNext(self):
return None
class Wizard(wx.Dialog):
def __init__(self, resources):
wx.Dialog.__init__(self, None, -1, 'Congruity version ' + version)
sizer_main = wx.BoxSizer(wx.VERTICAL)
sizer_top = wx.BoxSizer(wx.HORIZONTAL)
bitmap = wx.StaticBitmap(self, -1, resources.img_remote)
sizer_top.Add(bitmap, 0, wx.EXPAND | wx.ALL, 5)
self.sizer_top_right = wx.BoxSizer(wx.VERTICAL)
self.title = wx.StaticText(self, -1, "Title")
font = wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)
self.title.SetFont(font)
self.sizer_top_right.Add(self.title, 0, wx.EXPAND)
divider_top_right = wx.StaticLine(self, -1, None, None,
wx.LI_HORIZONTAL)
self.sizer_top_right.Add(divider_top_right, 0, wx.EXPAND)
sizer_top.Add(self.sizer_top_right, 1, wx.EXPAND | wx.ALL, 5)
sizer_main.Add(sizer_top, 1, wx.EXPAND | wx.ALL, 5)
divider_main = wx.StaticLine(self, -1, None, None, wx.LI_HORIZONTAL)
sizer_main.Add(divider_main, 0, wx.EXPAND | wx.ALL, 5)
sizer_buttons = wx.BoxSizer(wx.HORIZONTAL)
panel_btn_dummy = wx.Panel(self)
sizer_buttons.Add(panel_btn_dummy, 1, wx.EXPAND | wx.ALL, 5)
self.btn_next = wx.Button(self, -1, "&Next >")
self.Bind(wx.EVT_BUTTON, self._OnNext, self.btn_next)
sizer_buttons.Add(self.btn_next, 0, wx.EXPAND | wx.ALL, 5)
self.btn_cancel = wx.Button(self, -1, "&Cancel")
self.Bind(wx.EVT_BUTTON, self._OnCancel, self.btn_cancel)
sizer_buttons.Add(self.btn_cancel, 0, wx.EXPAND | wx.ALL, 5)
sizer_main.Add(sizer_buttons, 0, wx.EXPAND | wx.ALL, 5)
self.SetSizerAndFit(sizer_main)
self.cur_page = None
def SetPages(self, pages):
def tuple_max(a, b):
return (max(a[0], b[0]), max(a[1], b[1]))
self.pages = pages
for page in self.pages:
page.Hide()
self.size_wiz = self.GetSizeTuple()
for page in self.pages:
page.Show()
self.sizer_top_right.Add(page, 1, wx.EXPAND)
self.Fit()
size_page = self.GetSizeTuple()
self.size_wiz = tuple_max(self.size_wiz, size_page)
page.Hide()
self.sizer_top_right.Remove(page)
self.SetSize(self.size_wiz)
def SetInitialPage(self, page):
if self.cur_page:
raise Exception("Current page already set")
self._SetPage(page)
def ReenableNext(self):
self.btn_next.Enable(True)
self.btn_next.SetFocus()
def _OnNext(self, event):
if self.cur_page.IsTerminal():
os._exit(self.cur_page.GetExitCode())
next_page = self.cur_page.GetNext()
self._SetPage(next_page)
def _OnCancel(self, event):
os._exit(0)
def _SetPage(self, page):
if not page in self.pages:
raise Exception("Invalid page")
if self.cur_page:
self.cur_page.Hide()
self.sizer_top_right.Remove(self.cur_page)
self.cur_page = page
self.cur_page.Show()
self.sizer_top_right.Add(self.cur_page, 1, wx.EXPAND)
self.title.SetLabel(self.cur_page.GetTitle())
self.Layout()
is_terminal = self.cur_page.IsTerminal()
if is_terminal:
self.btn_next.SetLabel("&Finish")
else:
self.btn_next.SetLabel("&Next >")
self.btn_next.Enable(not self.cur_page.IsNextInitiallyDisabled())
self.btn_cancel.Enable((not is_terminal) and
self.cur_page.IsCancelable())
self.btn_next.SetFocus()
self.cur_page.OnActivated()
class Resources(object):
def __init__(self, appdir):
self.appdir = appdir
def SetEzHexFilename(self, ezhex_filename):
self.ezhex_filename = ezhex_filename
def LoadImages(self):
def load(filename, appdir = self.appdir):
dirs = ['/usr/share/congruity', appdir, '.']
for dir in dirs:
fpath = os.path.join(dir, filename)
if not os.path.isfile(fpath):
continue
print fpath
return wx.Image(fpath, wx.BITMAP_TYPE_PNG).ConvertToBitmap()
raise Exception("Can't load " + filename)
self.img_remote = load("remote.png")
self.icon_unstarted = load("icon-unstarted.png")
self.icon_in_progress = load("icon-in-progress.png")
self.icon_complete = load("icon-complete.png")
self.icon_failed = load("icon-failed.png")
def CreatePages(self, wizard):
self.page_welcome = WelcomePanel(wizard, self)
self.page_check_connectivity = CheckConnectivityPanel(wizard, self)
self.page_write_configuration = WriteConfigurationPanel(wizard, self)
self.page_update_firmware = UpdateFirmwarePanel(wizard, self)
self.page_success = SuccessPanel(wizard, self)
self.page_failure = FailurePanel(wizard, self)
def SetXmlData(self, xml, xml_size):
self.xml = xml
self.xml_size = xml_size
def main(argv):
app = argv.pop(0)
appdir = os.path.dirname(app)
while len(argv) and argv[0].startswith('-'):
arg = argv.pop(0)
if arg == '--version':
print version
sys.exit(0)
else:
print >>sys.stderr, "ERROR: Option '%s' not recognized" % arg
sys.exit(0)
if len(argv) != 1:
print >>sys.stderr, "ERROR: Precisely one filename argument is required"
sys.exit(0)
ezhex_filename = argv.pop(0)
app = wx.PySimpleApp()
wx.InitAllImageHandlers()
resources = Resources(appdir)
resources.LoadImages()
resources.SetEzHexFilename(ezhex_filename)
wizard = Wizard(resources)
resources.CreatePages(wizard)
wizard.SetPages([
resources.page_welcome,
resources.page_check_connectivity,
resources.page_write_configuration,
resources.page_update_firmware,
resources.page_success,
resources.page_failure
])
wizard.SetInitialPage(resources.page_welcome)
wizard.Show()
app.MainLoop()
if __name__ == "__main__":
main(sys.argv)
-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference
Don't miss this year's exciting event. There's still time to save $100.
Use priority code J8TL2D2.
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
_______________________________________________
concordance-devel mailing list
concordance-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/concordance-devel