# 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 qt
import os
import os.path
import sys
import chestnut_dialer
import chestnut_dialer.application
from chestnut_dialer import _
import chestnut_dialer.qt_ui.mainwindow
import chestnut_dialer.qt_ui.connectingbox
from chestnut_dialer.account_set import NoAccountException
class AccButton(qt.QPushButton):
accid = None
callback = None
def __init__(self, accid, callback, *args):
apply(qt.QPushButton.__init__, (self,) + args)
self.accid = accid
self.callback = callback
self.connect(self, qt.SIGNAL("clicked()"), self.accclick)
def accclick(self):
self.callback(self.accid)
def closeEvent(self, e):
self.callback = None
e.accept()
class SelectAccountBox(qt.QVBox):
sv = None
sv_pos = 0
sv_pos_attempt = 0
accounts = None
connect_callback = None
btn_group = None
def __init__(self, accounts, connect_callback, *args):
apply(qt.QVBox.__init__, (self,) + args)
self.accounts = accounts
self.connect_callback = connect_callback
self.setSpacing(5)
qt.QLabel(_("Select account for dial"), self).setAlignment(4)
self.refresh()
def closeEvent(self, e):
self.accounts = None
self.connect_callback = None
SelectAccountBox.sv_pos = self.sv.contentsY()
e.accept()
def refresh(self):
acc_list = self.accounts.ls_accounts()
acc_list.sort(lambda a,b: cmp(a[0].lower(), b[0].lower()))
if self.sv != None:
SelectAccountBox.sv_pos = self.sv.contentsY()
self.sv.close()
self.sv = qt.QScrollView(self)
self.sv.setResizePolicy(qt.QScrollView.AutoOneFit)
self.btn_group = qt.QVButtonGroup(self.sv.viewport())
self.btn_group.setFrameShape(qt.QFrame.NoFrame)
self.btn_group.setInsideMargin(0)
self.btn_group.setInsideSpacing(0)
self.sv.addChild(self.btn_group)
for name, accid in acc_list:
AccButton(accid, self.connect_callback, name.replace("&", "&&"),
self.btn_group)
self.sv.show()
self.timerid = self.startTimer(100)
def timerEvent(self, e):
self.sv.setContentsPos(0, SelectAccountBox.sv_pos)
self.sv_pos_attempt += 1
if (self.sv.contentsY() == SelectAccountBox.sv_pos or
self.sv_pos_attempt > 5):
self.killTimer(self.timerid)
class ConnectingBox(chestnut_dialer.qt_ui.connectingbox.ConnectingBox):
def __init__(self, acc_name, terminate_callback, stop_accel, *args):
apply(chestnut_dialer.qt_ui.connectingbox.ConnectingBox.__init__,
(self,) + args)
self.TitleLabel.setText(_("Connecting to %s") % acc_name)
self.connect(self.StopButton, qt.SIGNAL("clicked()"),
terminate_callback)
self.StopButton.setAccel(qt.QKeySequence(qt.QString(stop_accel)))
def add_text(self, text):
self.MessageText.insert(text)
class StatusBox(qt.QVBox):
connection = None
params = [
'account_name',
'speed',
'time',
'interface',
'local_ip',
'remote_ip',
'netmask',
'rx',
'tx',
'rx_bytes',
'tx_bytes']
def __init__(self, connection, disconnect_callback,
disconnect_accel, *args):
apply(qt.QVBox.__init__, (self,) + args)
param_titles = [
_("Connected to:"),
_("Speed:"),
_("Time:"),
_("Interface:"),
_("Local IP:"),
_("Remote IP:"),
_("Netmask:"),
_("Receive:"),
_("Send:"),
_("Receive bytes:"),
_("Send bytes:")]
self.connection = connection
self.setSpacing(5)
sv = qt.QScrollView(self)
sv.setResizePolicy(qt.QScrollView.AutoOneFit)
grid = qt.QGrid(2, sv.viewport())
grid.setMargin(5)
grid.setSpacing(2)
self.param_widgets = []
for i in range(0, len(self.params)):
l = qt.QLabel(param_titles[i], grid)
l.setAlignment(qt.Qt.AlignRight)
l.setSizePolicy(qt.QSizePolicy.Preferred, qt.QSizePolicy.Preferred)
w = qt.QLineEdit(grid)
w.setFrame(1)
w.setFrameStyle(qt.QFrame.Box | qt.QFrame.Plain)
w.setLineWidth(1)
w.setReadOnly(1)
w.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Preferred)
w.setPaletteBackgroundColor(l.paletteBackgroundColor())
self.param_widgets.append(w)
w = qt.QWidget(grid)
w.setSizePolicy(qt.QSizePolicy.Preferred, qt.QSizePolicy.Expanding)
sv.addChild(grid)
bg = qt.QButtonGroup(self)
bg.setFrameShape(qt.QButtonGroup.NoFrame)
bg.setAlignment(qt.QButtonGroup.AlignHCenter)
bg.setColumnLayout(0,qt.Qt.Vertical)
bg.layout().setSpacing(5)
bg.layout().setMargin(5)
bgLayout = qt.QHBoxLayout(bg.layout())
bgLayout.setAlignment(qt.Qt.AlignTop)
refreshButton = qt.QPushButton(bg)
refreshButton.setText(_("Refresh"))
self.connect(refreshButton, qt.SIGNAL("clicked()"),
self.updateStatus)
bgLayout.addWidget(refreshButton)
disconnectButton = qt.QPushButton(bg)
disconnectButton.setText(_("Disconnect"))
self.connect(disconnectButton, qt.SIGNAL("clicked()"),
disconnect_callback)
disconnectButton.setAccel(qt.QKeySequence(
qt.QString(disconnect_accel)))
bgLayout.addWidget(disconnectButton)
self.updateStatus()
def closeEvent(self, e):
self.connection = None
self.param_widgets = None
e.accept()
def updateStatus(self):
info = self.connection.get_info()
for i in range(0, len(self.params)):
try: self.param_widgets[i].setText(unicode(info[self.params[i]]))
except KeyError: pass
class MainWindow(chestnut_dialer.qt_ui.mainwindow.MainWindow):
timers = None
canclosefunc = None
def __init__(self, canclosefunc, *args):
apply(chestnut_dialer.qt_ui.mainwindow.MainWindow.__init__,
(self,) + args)
self.LogoButton.setPixmap(qt.QPixmap(
chestnut_dialer.logo_file))
self.ModeTglBox.setColumnLayout(1, qt.QGroupBox.Horizontal)
self.ModeTglBox.setInsideMargin(0)
self.timers = {}
self.canclosefunc = canclosefunc
def closeEvent(self, e):
if self.canclosefunc():
self.canclosefunc = None
self.timers = {}
e.accept()
def register_timer(self, period, func):
timerid = self.startTimer(period)
if timerid: self.timers.update({timerid: func})
return timerid
def unregister_timer(self, timerid):
self.killTimer(timerid)
if self.timers.has_key(timerid):
del(self.timers[timerid])
def timerEvent(self, e):
if self.timers.has_key(e.timerId()):
apply(self.timers[e.timerId()], [])
class Application(chestnut_dialer.application.Application):
qtapp = None
main_window = None
box_container = None
current_box = None
modes_info = None
avaible_modes = None
current_mode = None
mode_tgl_box = None
dockicons_dir = None
current_qt_style = None
current_icon_name = "disconnected"
last_acc_mode = None
connection_monitor_tid = None
event_monitor_tid = None
update_status_tid = None
connecting_log = ""
def __init__(self, params):
chestnut_dialer.application.Application.__init__(self)
app_args = [sys.argv[0]]
for p in params.keys():
app_args.append("-" + p)
if params[p]: app_args.append(params[p])
self.qtapp = qt.QApplication(app_args)
if not params.has_key("style"):
try: self.set_qt_style(self.config.qt_ui.style)
except AttributeError: pass
self.main_window = MainWindow(self.canclose)
try:
w, h = self.config.qt_ui.main_window_size.split("x")
self.main_window.resize(int(w), int(h))
except AttributeError: pass
self.update_main_window_title()
self.tr = self.main_window.tr
self.accel_map = {
"Main/Dial": "Ctrl+d",
"Main/AccountsConf": "Ctrl+a",
"Main/Config": "Ctrl+c",
"Main/Connecting": "Ctrl+n",
"Main/Connecting/Stop": "Ctrl+s",
"Main/Status": "Ctrl+s",
"Main/Status/Disconnect": "Ctrl+d",
"Main/Quit": "Ctrl+q"}
self.avaible_modes = ()
self.modes_info = {
"SelectAccount": {
"get-box-method": self.get_select_account_box,
"display-text": _("Dial"),
"accel-path": "Main/Dial"},
"AccountsConf": {
"get-box-method": self.get_accounts_conf_box,
"display-text": _("AccountsConf"),
"accel-path": "Main/AccountsConf"},
"Config": {
"get-box-method": self.get_config_box,
"display-text": _("Config"),
"accel-path": "Main/Config"},
"Connecting": {
"get-box-method": self.get_connecting_box,
"display-text": _("Connecting"),
"accel-path": "Main/Connecting"},
"Status": {
"get-box-method": self.get_status_box,
"display-text": _("Status"),
"accel-path": "Main/Status"}}
self.box_container = self.main_window.BoxContainer
self.box_cont_layout = qt.QVBoxLayout(self.box_container)
self.mode_tgl_box = self.main_window.ModeTglBox
self.main_window.connect(self.main_window.ExitButton,
qt.SIGNAL("clicked()"), self.main_window, qt.SLOT("close()"))
self.main_window.connect(self.main_window.LogoButton,
qt.SIGNAL("clicked()"), self.about_action)
try: self.update_accel_map(self.config.qt_ui.accel_map)
except AttributeError: self.update_accel_map("")
self.update_icon()
self.qtapp.setMainWidget(self.main_window)
self.main_window.show()
self.event_monitor_tid = self.main_window.register_timer(
2000, self.event_monitor_signal)
self.select_account_action()
def run(self):
self.qtapp.exec_loop()
return chestnut_dialer.EX_OK
def exit(self):
self.qtapp.exit()
def canclose(self):
self.config.qt_ui.main_window_size = "%dx%d" % (
self.main_window.size().width(), self.main_window.size().height())
if (self.is_connection_init() and self.config.confirm_exit and
qt.QMessageBox.warning(self.main_window,
_("Confirmation"), _("Disconnect and exit?"),
qt.QMessageBox.Yes, qt.QMessageBox.No,
qt.QMessageBox.NoButton) == qt.QMessageBox.No):
return 0
return 1
def set_icon(self, icon_name):
icon_file = chestnut_dialer.get_dockicon_file(
self.config.dockicons_dir, icon_name)
if icon_file: self.main_window.setIcon(qt.QPixmap(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):
self.main_window.setCaption(self.get_window_title())
def set_qt_style(self, stylename):
self.qtapp.setStyle(stylename)
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 modes != self.avaible_modes:
for m in self.modes_info.keys():
minfo = self.modes_info[m]
if minfo.has_key("tgl-widget"):
minfo["tgl-widget"].close()
del(minfo["tgl-widget"])
for m in modes:
modinfo = self.modes_info[m]
tgl = qt.QPushButton(modinfo["display-text"], self.mode_tgl_box)
tgl.setToggleButton(1)
try:
tgl.setAccel(qt.QKeySequence(
qt.QString(self.accel_map[modinfo["accel-path"]])))
except KeyError: pass
if m == self.current_mode: tgl.setOn(1)
self.mode_tgl_box.connect(tgl, qt.SIGNAL("clicked()"),
self.mode_tgl_toggled_event)
modinfo.update({"tgl-widget": tgl})
tgl.show()
self.avaible_modes = modes
def mode_tgl_toggled_event(self):
for m in self.modes_info.keys():
minfo = self.modes_info[m]
if minfo.has_key("tgl-widget") and minfo["tgl-widget"].isOn():
self.set_mode(m)
return
def set_mode(self, mode):
if mode == self.current_mode: return
minfo = self.modes_info[mode]
if not minfo.has_key("tgl-widget"): self.update_modes()
if not minfo["tgl-widget"].isOn():
minfo["tgl-widget"].setOn(1)
if self.current_box != None: self.current_box.close()
if minfo["get-box-method"] != None:
self.current_box = minfo["get-box-method"](None)
else:
self.current_box = qt.QLabel("Empty", None)
self.current_box.reparent(self.box_container, 0, qt.QPoint(0,0), 1)
self.box_cont_layout.addWidget(self.current_box)
self.current_box.setSizePolicy(qt.QSizePolicy(
qt.QSizePolicy.Expanding, qt.QSizePolicy.Expanding))
self.current_mode = mode
if mode in ("SelectAccount", "AccountsConf"):
self.last_acc_mode = mode
def get_select_account_box(self, parent):
return SelectAccountBox(self.accounts,
self.connect_action, parent)
def get_connecting_box(self, parent):
box = ConnectingBox(self.current_account.name,
self.disconnect_action, self.accel_map["Main/Connecting/Stop"], parent)
box.add_text(self.connecting_log)
return box
def get_status_box(self, parent):
return StatusBox(self.get_connection(),
self.disconnect_action, self.accel_map["Main/Status/Disconnect"], parent)
def get_accounts_conf_box(self, parent):
import chestnut_dialer.qt_ui.config
return chestnut_dialer.qt_ui.config.AccountsConfBox(self, parent)
def get_config_box(self, parent):
import chestnut_dialer.qt_ui.config
return chestnut_dialer.qt_ui.config.ConfigBox(self, parent)
def select_account_action(self):
self.set_mode("SelectAccount")
def connect_action(self, acc_id):
try: self.connect(self.accounts.get_account(acc_id))
except NoAccountException: self.on_accounts_changed()
def disconnect_action(self):
self.disconnect()
def about_action(self):
self.show_help("")
def update_status_monitor(self):
self.update_main_window_title()
if self.current_mode == "Status" and self.current_box != None:
self.current_box.updateStatus()
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 = self.main_window.register_timer(
300, 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()
self.main_window.unregister_timer(self.connection_monitor_tid)
self.connection_monitor_tid = self.main_window.register_timer(
int(self.config.monitor_period * 1000),
self.connection_monitor_signal)
self.update_status_tid = self.main_window.register_timer(
int(self.config.status_refresh_period * 1000),
self.update_status_monitor)
def on_connection_setup_extra(self):
try: action = self.config.qt_ui.on_connect
except AttributeError: action = ""
if action == "iconify": self.main_window.showMinimized()
def on_connection_stop(self, reason):
self.main_window.unregister_timer(self.connection_monitor_tid)
if self.update_status_tid != None:
self.main_window.unregister_timer(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]
s = qt.QString()
if qt.QMessageBox.warning(self.main_window,
_("Connection terminated"),
_("Connection terminated.\nReason: %s.\nRestore connection with %s?") %
(reson_msg, self.current_account.name),
qt.QMessageBox.Yes, qt.QMessageBox.No,
qt.QMessageBox.NoButton) == qt.QMessageBox.Yes:
self.connect_action(self.current_account.id)
return
self.update_modes()
if (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":
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,
"qt_ui.style": self.update_style,
"qt_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 update_style(self, style):
if self.current_qt_style != style and style != "":
self.set_qt_style(style)
def ask_password(self):
passwd, ok = qt.QInputDialog.getText(
_("Enter Password"), _("Password"),
qt.QLineEdit.Password, "", self.main_window)
return (unicode(passwd), not ok)
def show_help(self, node):
docdir = chestnut_dialer.get_html_doc_dir_locale()
try: browser = self.config.qt_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:
qt.QMessageBox.warning(self.main_window, _("Warning"),
_("""You don't have any HTML browser configured.
Please specify an HTML browser in the
Options Dialog in the External Programs tab."""),
qt.QMessageBox.Ok, qt.QMessageBox.NoButton)
def update_accel_map(self, m):
try:
for path, accel in map(lambda e: e.split(':'), m.split(';')):
if not self.accel_map.has_key(path): continue
k = qt.QKeySequence(qt.QString(accel))
if k.isEmpty(): continue
self.accel_map[path] = unicode(qt.QString(k))
except ValueError: pass
mnew = ';'.join(map(lambda p: "%s:%s" % (p, self.accel_map[p]),
self.accel_map.keys()))
if mnew != m:
self.config.qt_ui.accel_map = mnew
for m in self.avaible_modes:
modinfo = self.modes_info[m]
try:
modinfo["tgl-widget"].setAccel(qt.QKeySequence(
qt.QString(self.accel_map[modinfo["accel-path"]])))
except KeyError: pass
self.main_window.ExitButton.setAccel(qt.QKeySequence(
qt.QString(self.accel_map["Main/Quit"])))
|