2013-04-27 22:23:19 +00:00
#!/usr/bin/env python
2015-03-06 23:31:46 +00:00
# Copyright (C) 2013 Christian T. Jacobs.
2013-04-27 22:23:19 +00:00
# This file is part of PyQSO.
# PyQSO 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.
#
# PyQSO 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 PyQSO. If not, see <http://www.gnu.org/licenses/>.
from gi . repository import Gtk , GObject
import logging
import telnetlib
from pyqso . telnet_connection_dialog import *
2013-06-30 01:42:03 +00:00
class DXCluster ( Gtk . VBox ) :
2013-09-04 20:12:04 +00:00
""" A tool for connecting to a DX cluster (specifically Telnet-based DX clusters). """
2013-04-27 22:23:19 +00:00
2013-08-03 19:11:00 +00:00
def __init__ ( self , parent ) :
2015-10-03 16:51:25 +00:00
""" Set up the DX cluster ' s Gtk.VBox, and set up a timer so that PyQSO can retrieve new data from the Telnet server every few seconds.
: arg parent : The parent Gtk window .
"""
2013-09-14 21:12:10 +00:00
logging . debug ( " Setting up the DX cluster... " )
2013-06-30 01:42:03 +00:00
Gtk . VBox . __init__ ( self , spacing = 2 )
2013-04-27 22:23:19 +00:00
self . connection = None
2013-08-03 19:11:00 +00:00
self . parent = parent
2013-04-27 22:23:19 +00:00
# Set up the toolbar
self . toolbar = Gtk . HBox ( spacing = 2 )
self . buttons = { }
# Connect
icon = Gtk . Image ( )
icon . set_from_stock ( Gtk . STOCK_CONNECT , Gtk . IconSize . BUTTON )
button = Gtk . Button ( )
button . add ( icon )
2013-10-01 21:18:50 +00:00
button . set_tooltip_text ( ' Connect to Telnet Server ' )
2013-04-27 22:23:19 +00:00
button . connect ( " clicked " , self . telnet_connect )
self . toolbar . pack_start ( button , False , False , 0 )
self . buttons [ " CONNECT " ] = button
# Disconnect
icon = Gtk . Image ( )
icon . set_from_stock ( Gtk . STOCK_DISCONNECT , Gtk . IconSize . BUTTON )
button = Gtk . Button ( )
button . add ( icon )
2013-10-01 21:18:50 +00:00
button . set_tooltip_text ( ' Disconnect from Telnet Server ' )
2013-04-27 22:23:19 +00:00
button . connect ( " clicked " , self . telnet_disconnect )
self . toolbar . pack_start ( button , False , False , 0 )
self . buttons [ " DISCONNECT " ] = button
self . toolbar . pack_start ( Gtk . SeparatorToolItem ( ) , False , False , 0 )
self . command = Gtk . Entry ( )
self . toolbar . pack_start ( self . command , False , False , 0 )
2013-04-27 22:55:50 +00:00
self . send = Gtk . Button ( " Send Command " )
self . send . connect ( " clicked " , self . telnet_send_command )
self . toolbar . pack_start ( self . send , False , False , 0 )
2013-04-27 22:23:19 +00:00
2013-06-30 01:42:03 +00:00
self . pack_start ( self . toolbar , False , False , 0 )
2013-04-27 22:23:19 +00:00
# A TextView object to display the output from the Telnet server.
self . renderer = Gtk . TextView ( )
self . renderer . set_editable ( False )
2013-06-07 20:56:36 +00:00
self . renderer . set_cursor_visible ( False )
2013-04-27 22:23:19 +00:00
sw = Gtk . ScrolledWindow ( )
sw . set_shadow_type ( Gtk . ShadowType . ETCHED_IN )
sw . set_policy ( Gtk . PolicyType . AUTOMATIC , Gtk . PolicyType . AUTOMATIC )
sw . add ( self . renderer )
self . buffer = self . renderer . get_buffer ( )
2013-06-30 01:42:03 +00:00
self . pack_start ( sw , True , True , 0 )
2013-04-27 22:23:19 +00:00
2013-04-27 22:55:50 +00:00
self . set_connect_button_sensitive ( True )
2013-04-27 22:23:19 +00:00
self . show_all ( )
2013-09-14 21:12:10 +00:00
logging . debug ( " DX cluster ready! " )
2013-04-27 22:23:19 +00:00
return
def telnet_connect ( self , widget = None ) :
2013-09-14 20:33:01 +00:00
""" Connect to a user-specified Telnet server, with the host and login details specified in the Gtk.Entry boxes in the TelnetConnectionDialog. """
2013-08-03 19:11:00 +00:00
dialog = TelnetConnectionDialog ( self . parent )
2013-04-27 22:23:19 +00:00
response = dialog . run ( )
if ( response == Gtk . ResponseType . OK ) :
connection_info = dialog . get_connection_info ( )
host = connection_info [ " HOST " ] . get_text ( )
port = connection_info [ " PORT " ] . get_text ( )
username = connection_info [ " USERNAME " ] . get_text ( )
password = connection_info [ " PASSWORD " ] . get_text ( )
dialog . destroy ( )
else :
dialog . destroy ( )
return
if ( host == " " ) :
logging . error ( " No Telnet server specified. " )
return
if ( port == " " ) :
port = 23 # The default Telnet port
else :
port = int ( port )
try :
self . connection = telnetlib . Telnet ( host , port )
if ( username ) :
self . connection . read_until ( " login: " )
self . connection . write ( username + " \n " )
if ( password ) :
self . connection . read_until ( " password: " )
self . connection . write ( password + " \n " )
except :
logging . exception ( " Could not create a connection to the Telnet server " )
2013-04-27 22:55:50 +00:00
self . connection = None
2013-04-27 22:23:19 +00:00
return
2013-04-27 22:55:50 +00:00
self . set_connect_button_sensitive ( False )
2013-04-27 22:23:19 +00:00
2013-09-14 21:12:10 +00:00
self . check_io_event = GObject . timeout_add ( 1000 , self . _on_telnet_io )
2013-04-27 22:23:19 +00:00
return
def telnet_disconnect ( self , widget = None ) :
2013-09-14 21:12:10 +00:00
""" Disconnect from a Telnet server and remove the I/O timer. """
2013-04-27 22:23:19 +00:00
if ( self . connection ) :
self . connection . close ( )
self . buffer . set_text ( " " )
self . connection = None
2013-04-27 22:55:50 +00:00
self . set_connect_button_sensitive ( True )
2013-09-14 21:12:10 +00:00
GObject . source_remove ( self . check_io_event )
2013-04-27 22:23:19 +00:00
return
def telnet_send_command ( self , widget = None ) :
2013-09-14 20:33:01 +00:00
""" Send the user-specified command in the Gtk.Entry box to the Telnet server (if PyQSO is connected to one). """
2013-04-27 22:23:19 +00:00
if ( self . connection ) :
self . connection . write ( self . command . get_text ( ) + " \n " )
2013-04-27 22:55:50 +00:00
self . command . set_text ( " " )
2013-04-27 22:23:19 +00:00
return
2013-09-14 21:12:10 +00:00
def _on_telnet_io ( self ) :
2015-10-03 16:51:25 +00:00
""" Retrieve any new data from the Telnet server and print it out in the Gtk.TextView widget.
: returns : Always returns True to satisfy the GObject timer .
: rtype : bool
"""
2013-04-27 22:23:19 +00:00
if ( self . connection ) :
2013-06-07 23:54:53 +00:00
text = self . connection . read_very_eager ( )
2015-02-28 16:19:52 +00:00
try :
text = text . replace ( u " \u0007 " , " " ) # Remove the BEL Unicode character from the end of the line
2015-09-30 08:57:11 +00:00
except UnicodeDecodeError :
2015-02-28 16:19:52 +00:00
pass
2013-06-07 23:54:53 +00:00
# Allow auto-scrolling to the new text entry if the focus is already at
# the very end of the Gtk.TextView. Otherwise, don't auto-scroll
# in case the user is reading something further up.
# Note: This is based on the code from http://forums.gentoo.org/viewtopic-t-445598-view-next.html
end_iter = self . buffer . get_end_iter ( )
end_mark = self . buffer . create_mark ( None , end_iter )
self . renderer . move_mark_onscreen ( end_mark )
at_end = self . buffer . get_iter_at_mark ( end_mark ) . equal ( end_iter )
self . buffer . insert ( end_iter , text )
if ( at_end ) :
end_mark = self . buffer . create_mark ( None , end_iter )
self . renderer . scroll_mark_onscreen ( end_mark )
2013-04-27 22:55:50 +00:00
return True
def set_connect_button_sensitive ( self , sensitive ) :
2015-10-03 16:51:25 +00:00
""" Enable/disable the relevant buttons for connecting/disconnecting from a DX cluster, so that users cannot click the connect button if PyQSO is already connected.
: arg bool sensitive : If True , enable the Connect button and disable the Disconnect button . If False , vice versa .
"""
2013-04-27 22:55:50 +00:00
self . buttons [ " CONNECT " ] . set_sensitive ( sensitive )
self . buttons [ " DISCONNECT " ] . set_sensitive ( not sensitive )
self . send . set_sensitive ( not sensitive )
return
2013-04-27 22:23:19 +00:00