# Copyright (C) 2003, 2004 Konstantin Korikov
# 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 2 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import gtk
import gtk.glade
import gobject
import os
import os.path
import chestnut_dialer
import chestnut_dialer.application
import chestnut_dialer.gtk2_ui.box
import chestnut_dialer.config
from chestnut_dialer import _
from chestnut_dialer.account_set import NoAccountException
main_glade_file = os.path.dirname(__file__) + "/main.glade"
class Application(chestnut_dialer.application.Application):
main_window = None
box_container = None
current_box = None
modes_info = None
avaible_modes = None
current_mode = None
mode_tgl_cont = None
mode_tgl_box = None
main_window_glade_file = os.path.dirname(__file__) + "/main_window.glade"
connection_monitor_tid = None
event_monitor_tid = None
update_status_tid = None
current_icon_name = "disconnected"
last_acc_mode = None
accel_group = None
connecting_log = ""
def __init__(self, params):
chestnut_dialer.application.Application.__init__(self)
self.avaible_modes = ()
self.modes_info = {
"SelectAccount": {
"get-box-method": self.get_select_account_box,
"display-text": _("Dial"),
"accel-path": "<ChestnutDialer-Main>/Dial"},
"AccountsConf": {
"get-box-method": self.get_accounts_conf_box,
"display-text": _("AccountsConf"),
"accel-path": "<ChestnutDialer-Main>/AccountsConf"},
"Config": {
"get-box-method": self.get_config_box,
"display-text": _("Config"),
"accel-path": "<ChestnutDialer-Main>/Config"},
"Connecting": {
"get-box-method": self.get_connecting_box,
"display-text": _("Connecting"),
"accel-path": "<ChestnutDialer-Main>/Connecting"},
"Status": {
"get-box-method": self.get_status_box,
"display-text": _("Status"),
"accel-path": "<ChestnutDialer-Main>/Status"}}
if chestnut_dialer.config.use_nls:
gtk.glade.bindtextdomain(chestnut_dialer.domain,
chestnut_dialer.config.locale_dir)
self.accel_group = gtk.AccelGroup()
self.check_accel_map()
self.event_monitor_tid = gobject.timeout_add(2000, self.gtk_timeout,
self.event_monitor_signal)
self.select_account_action()
def destroy(self):
gobject.source_remove(self.event_monitor_tid)
for m in self.modes_info.keys():
if self.modes_info[m].has_key("box"):
self.modes_info[m]["box"].destroy()
self.modes_info = None
chestnut_dialer.application.Application.destroy(self)
def run(self):
try: gtk.main()
except AttributeError: gtk.mainloop()
return chestnut_dialer.EX_OK
def exit(self):
self.drop_main_window_action()
try: gtk.main_quit()
except AttributeError: gtk.mainquit()
def set_main_window_icon(self, icon_file):
self.main_window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_file))
def set_icon(self, icon_name):
icon_file = chestnut_dialer.get_dockicon_file(
self.config.dockicons_dir, icon_name)
if self.main_window and icon_file:
self.set_main_window_icon(icon_file)
self.current_icon_name = icon_name
def update_icon(self, *args):
self.set_icon(self.current_icon_name)
def update_main_window_title(self, *args):
if self.main_window:
self.main_window.set_title(self.get_window_title())
def setup_main_window(self, box):
if not self.main_window:
xml = gtk.glade.XML(self.main_window_glade_file, "MainWindow",
chestnut_dialer.domain)
self.main_window = xml.get_widget("MainWindow")
try:
w, h = self.config.gtk2_ui.main_window_size.split("x")
self.main_window.set_default_size(int(w), int(h))
except AttributeError: pass
icon_file = chestnut_dialer.get_dockicon_file(
self.config.dockicons_dir, self.current_icon_name)
if icon_file: self.set_main_window_icon(icon_file)
self.update_main_window_title()
self.box_container = xml.get_widget("MainBox")
self.mode_tgl_cont = xml.get_widget("ModeTglCont")
self.main_window.add_accel_group(self.accel_group)
xml.signal_connect("exit", self.exit_action)
xml.signal_connect("about", self.about_action)
xml.signal_connect("close", self.drop_main_window_action)
self.main_window.connect("destroy", self.main_window_destroyed_event)
xml.get_widget("QuitButton").set_accel_path(
"<ChestnutDialer-Main>/Quit", self.accel_group)
self.update_modes()
if self.current_box :
self.current_box.destroy()
self.box_container.remove(self.current_box.widget)
self.current_box.widget.destroy()
self.current_box = None
self.current_box = box
if box != None:
self.box_container.add(box.widget)
box.setup_accels(self.accel_group)
self.main_window.show_all()
def main_window_destroyed_event(self, *args):
self.main_window = None
if self.current_box :
self.current_box.destroy()
self.current_box.widget.destroy()
self.current_box = None
self.exit()
def update_modes(self):
if self.is_connection_setup():
modes = ("Status", "AccountsConf", "Config")
elif self.is_connection_init():
modes = ("Connecting", "AccountsConf", "Config")
else:
modes = ("SelectAccount", "AccountsConf", "Config")
if self.main_window == None:
self.mode_tgl_box = None
self.current_mode = None
self.avaible_modes = modes
if self.modes_info != None:
for m in self.modes_info.keys():
minfo = self.modes_info[m]
if minfo.has_key("tgl-widget"):
del(minfo["tgl-widget"])
else:
if modes != self.avaible_modes or self.mode_tgl_box == None:
for m in self.modes_info.keys():
minfo = self.modes_info[m]
if minfo.has_key("tgl-widget"):
del(minfo["tgl-widget"])
new_mode_tgl_box = gtk.VButtonBox()
new_mode_tgl_box.set_layout(1)
new_mode_tgl_box.set_spacing(0)
for m in modes:
modinfo = self.modes_info[m]
tgl = gtk.ToggleButton(modinfo["display-text"])
if m == self.current_mode:
tgl.set_active(1)
tgl.set_sensitive(0)
tgl.connect("toggled",
self.mode_tgl_toggled_event, m)
new_mode_tgl_box.add(tgl)
modinfo.update({"tgl-widget": tgl})
if modinfo.has_key("accel-path"):
tgl.set_accel_path(modinfo["accel-path"], self.accel_group)
if self.mode_tgl_box:
self.mode_tgl_cont.remove(self.mode_tgl_box)
self.mode_tgl_box.destroy()
self.mode_tgl_box = new_mode_tgl_box
self.mode_tgl_cont.add(self.mode_tgl_box)
self.mode_tgl_box.show_all()
self.avaible_modes = modes
def mode_tgl_toggled_event(self, tgl, mode):
if tgl.get_active():
tgl.set_sensitive(0)
cur_mode_info = (self.current_mode and
self.modes_info[self.current_mode] or None)
if (cur_mode_info and cur_mode_info.has_key("tgl-widget")):
t = cur_mode_info["tgl-widget"]
t.set_active(0)
t.set_sensitive(1)
self.current_mode = mode
new_mode_info = self.modes_info[mode]
self.setup_main_window(new_mode_info["get-box-method"]())
if mode in ("SelectAccount", "AccountsConf"):
self.last_acc_mode = mode
def set_mode(self, mode):
if not self.main_window:
self.setup_main_window(None)
minfo = self.modes_info[mode]
if not minfo.has_key("tgl-widget"): self.update_modes()
minfo["tgl-widget"].set_active(1)
def get_select_account_box(self):
return chestnut_dialer.gtk2_ui.box.SelectAccountBox(
self.accounts, self.connect_action)
def get_accounts_conf_box(self):
import chestnut_dialer.gtk2_ui.confbox
return chestnut_dialer.gtk2_ui.confbox.AccountsConfBox(self)
def get_config_box(self):
import chestnut_dialer.gtk2_ui.confbox
return chestnut_dialer.gtk2_ui.confbox.ConfigBox(self)
def get_connecting_box(self):
box = chestnut_dialer.gtk2_ui.box.ConnectingBox(self.current_account.name,
self.disconnect_action)
box.add_text(self.connecting_log)
return box
def get_status_box(self):
return chestnut_dialer.gtk2_ui.box.StatusBox(self.get_connection(),
self.disconnect_action)
def exit_action(self, *args):
if self.is_connection_init() and self.config.confirm_exit:
msgbox = gtk.MessageDialog(self.main_window,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO,
_("Disconnect and exit?"))
r = msgbox.run()
msgbox.destroy()
if r == gtk.RESPONSE_YES: self.exit()
else: self.exit()
def drop_main_window_action(self, *args):
if self.main_window:
self.config.gtk2_ui.main_window_size = "x".join(
map(lambda i: str(i), self.main_window.get_size()))
self.main_window.destroy()
self.main_window = None
def connect_action(self, widget, acc_id):
try: self.connect(self.accounts.get_account(acc_id))
except NoAccountException: self.on_accounts_changed()
def disconnect_action(self, *args):
self.disconnect()
def select_account_action(self, *args):
self.set_mode("SelectAccount")
def accounts_conf_action(self, *args):
self.set_mode("AccountsConf")
def config_action(self, *args):
self.set_mode("Config")
def status_action(self, *args):
self.set_mode("Status")
def about_action(self, *args):
self.show_help("")
def gtk_timeout(self, func):
func()
return 1
def update_status_monitor(self):
self.update_main_window_title()
if self.current_mode == "Status" and self.current_box != None:
self.current_box.refresh()
return 1
def on_connection_init(self):
self.connecting_log = ""
self.set_mode("Connecting")
self.set_icon("connecting")
self.update_main_window_title()
self.connection_monitor_tid = gobject.timeout_add(300, self.gtk_timeout,
self.connection_monitor_signal)
def on_connection_setup(self):
self.set_mode("Status")
self.set_icon("connected")
self.update_main_window_title()
self.on_connection_setup_extra()
gobject.source_remove(self.connection_monitor_tid)
self.connection_monitor_tid = gobject.timeout_add(
int(self.config.monitor_period * 1000),
self.gtk_timeout, self.connection_monitor_signal)
self.update_status_tid = gobject.timeout_add(
int(self.config.status_refresh_period * 1000),
self.update_status_monitor)
def on_connection_setup_extra(self):
try: action = self.config.gtk2_ui.on_connect
except AttributeError: action = ""
if action == "iconify" and self.main_window:
self.main_window.iconify()
def on_connection_stop(self, reason):
gobject.source_remove(self.connection_monitor_tid)
if self.update_status_tid != None:
gobject.source_remove(self.update_status_tid)
self.update_status_tid = None
self.set_icon("disconnected")
self.update_main_window_title()
if reason != 0:
reson_msg = (
_("normal termination"),
_("unknown termination"),
_("no dialtone"),
_("busy"),
_("no carrier"),
_("authentication failed"))[reason]
msgbox = gtk.MessageDialog(self.main_window,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO,
_("Connection terminated.\nReason: %s.\nRestore connection with %s?") %
(reson_msg, self.current_account.name))
r = msgbox.run()
msgbox.destroy()
if r == gtk.RESPONSE_YES:
self.connect_action(None, self.current_account.id)
return
self.update_modes()
if (self.main_window and
self.current_mode in ("Connecting", "Status", None)):
self.set_mode(self.last_acc_mode or "SelectAccount")
def on_connection_debug_msg(self, msg):
self.connecting_log += msg
if self.current_mode == "Connecting" and self.current_box:
self.current_box.add_text(msg)
def on_config_attr_changed(self, name, value):
try:
func = {
"wnd_title_fmt_disconnected": self.update_main_window_title,
"wnd_title_fmt_connecting": self.update_main_window_title,
"wnd_title_fmt_connected": self.update_main_window_title,
"dockicons_dir": self.update_icon,
"gtk2_ui.accel_map": self.update_accel_map,
}[name]
except KeyError: pass
else: func(value)
def on_accounts_changed(self):
self.update_main_window_title()
if (self.current_box != None and
hasattr(self.current_box, "refresh")):
self.current_box.refresh()
def ask_password(self):
xml = gtk.glade.XML(main_glade_file, "EnterPasswordDialog",
chestnut_dialer.domain)
dialog = xml.get_widget("EnterPasswordDialog")
cancel = dialog.run() == gtk.RESPONSE_CANCEL
passwd = unicode(xml.get_widget("Password").get_text(), "UTF-8")
dialog.destroy()
return (passwd, cancel)
def show_help(self, node):
docdir = chestnut_dialer.get_html_doc_dir_locale()
try: browser = self.config.gtk2_ui.browser
except AttributeError: browser = None
if browser:
if browser.find("%s") < 0: browser += " %s"
cmd = browser % chestnut_dialer.escape_shell(
"file://%s/%s.html" % (docdir,
node.replace(' ', '-') or "index")) + " &"
os.system(cmd)
else:
msgbox = gtk.MessageDialog(None,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
_("""You don't have any HTML browser configured.
Please specify an HTML browser in the
Options Dialog in the External Programs tab."""))
msgbox.run()
msgbox.destroy()
def show_help_action(self, widget, node):
self.show_help(node)
def check_accel_map(self):
defm = {
"<ChestnutDialer-Main>/Dial": "<Ctrl>d",
"<ChestnutDialer-Main>/AccountsConf": "<Ctrl>a",
"<ChestnutDialer-Main>/Config": "<Ctrl>c",
"<ChestnutDialer-Main>/Connecting": "<Ctrl>n",
"<ChestnutDialer-Main>/Connecting/Stop": "<Ctrl>s",
"<ChestnutDialer-Main>/Status": "<Ctrl>s",
"<ChestnutDialer-Main>/Status/Disconnect": "<Ctrl>d",
"<ChestnutDialer-Main>/Quit": "<Ctrl>q"}
try: m = self.config.gtk2_ui.accel_map
except AttributeError: m = ""
mnew = []
try:
for path, accel in map(lambda e: e.split(':'), m.split(';')):
if not defm.has_key(path): continue
key, mods = gtk.accelerator_parse(accel)
gtk.accel_map_change_entry(path, key, mods, True)
mnew.append("%s:%s" % (path, accel))
del defm[path]
except ValueError: pass
for path in defm.keys():
accel = defm[path]
key, mods = gtk.accelerator_parse(accel)
gtk.accel_map_change_entry(path, key, mods, True)
mnew.append("%s:%s" % (path, accel))
mnew = ';'.join(mnew)
if mnew != m:
self.config.gtk2_ui.accel_map = mnew
def update_accel_map(self, m):
for path, accel in map(lambda e: e.split(':'), m.split(';')):
key, mods = gtk.accelerator_parse(accel)
gtk.accel_map_change_entry(path, key, mods, True)
|