//Author: Timothy Pearson <kb9vqf@pearsoncomputing.net>, (C) 2012
//Copyright: See COPYING file that comes with this distribution
// TDE MDI interface based on a (passable) tutorial by Andrea Bergia et al.
# include "remotemdi.h"
# include <cassert>
using namespace std ;
# include <kapplication.h>
# include <klocale.h>
# include <kdebug.h>
# include <kconfig.h>
# include <kmessagebox.h>
# include <tqlabel.h>
# include <tqtimer.h>
# include <tqlayout.h>
# include <kiconloader.h>
# include <kstdaction.h>
# include <kstatusbar.h>
# include <kmdichildview.h>
# include <klistbox.h>
# include <kactionclasses.h>
# include <kedittoolbar.h>
# include <kkeydialog.h>
# include "views/instrumentview.h"
# include "dialogs/selectserverdlg.h"
RemoteMDI : : RemoteMDI ( )
: KMdiMainFrm ( 0 , " RemoteMDI " , KMdi : : ChildframeMode ) , m_children ( 0 ) , m_rsvSvrSocket ( NULL )
{
setXMLFile ( " remotelabui.rc " ) ;
// Create some actions
KStdAction : : close ( this , SLOT ( closeCurrent ( ) ) , actionCollection ( ) ) ;
KStdAction : : quit ( this , SLOT ( close ( ) ) , actionCollection ( ) ) ;
KActionCollection * const ac = actionCollection ( ) ;
setStandardToolBarMenuEnabled ( true ) ;
KStdAction : : quit ( TQT_TQOBJECT ( this ) , TQT_SLOT ( close ( ) ) , ac ) ;
KStdAction : : configureToolbars ( TQT_TQOBJECT ( this ) , TQT_SLOT ( configToolbars ( ) ) , ac ) ;
KStdAction : : keyBindings ( TQT_TQOBJECT ( this ) , TQT_SLOT ( configKeys ( ) ) , ac ) ;
connect_action = new KAction ( i18n ( " Connect to Server " ) , " connect_creating " , KShortcut ( ) , TQT_TQOBJECT ( this ) , TQT_SLOT ( connectToServer ( ) ) , ac , " connect_server " ) ;
disconnect_action = new KAction ( i18n ( " Disconnect from Server " ) , " connect_no " , KShortcut ( ) , TQT_TQOBJECT ( this ) , TQT_SLOT ( disconnectFromServer ( ) ) , ac , " disconnect_server " ) ;
// Add Window menu
if ( ! isFakingSDIApplication ( ) ) {
menuBar ( ) - > insertItem ( i18n ( " &Window " ) , windowMenu ( ) ) ;
}
createGUI ( 0 ) ;
// When we change view, change the status bar text
connect ( this , SIGNAL ( viewActivated ( KMdiChildView * ) ) , this , SLOT ( currentChanged ( KMdiChildView * ) ) ) ;
ac - > setHighlightingEnabled ( true ) ;
connect ( ac , TQT_SIGNAL ( actionStatusText ( const TQString & ) ) , statusBar ( ) , TQT_SLOT ( message ( const TQString & ) ) ) ;
connect ( ac , TQT_SIGNAL ( clearStatusText ( ) ) , statusBar ( ) , TQT_SLOT ( clear ( ) ) ) ;
// Create the status bar
statusBar ( ) - > message ( i18n ( " No view! " ) ) ;
processActions ( ) ;
processLockouts ( ) ;
}
RemoteMDI : : ~ RemoteMDI ( )
{
while ( m_pCurrentWindow ) {
closeCurrent ( ) ;
}
if ( m_rsvSvrSocket ) {
m_rsvSvrSocket - > close ( ) ;
while ( m_rsvSvrSocket - > state ( ) = = TQSocket : : Closing ) {
tqApp - > processEvents ( ) ;
}
}
}
void RemoteMDI : : processActions ( ) {
// Add dynamic actions
// RAJA FIXME
KActionCollection * const ac = actionCollection ( ) ;
TQPtrList < KAction > dut_actions ;
inst_fpgaviewer_menu = new KAction ( i18n ( " Launch FPGA Viewer " ) , " remote " , KShortcut ( ) , TQT_TQOBJECT ( this ) , TQT_SLOT ( startModule ( ) ) , ac , " libremotelab_fpgaviewer " ) ;
dut_actions . append ( inst_fpgaviewer_menu ) ;
unplugActionList ( " dutMenu_actionlist " ) ;
unplugActionList ( " dutToolBar_actionlist " ) ;
plugActionList ( " dutMenu_actionlist " , dut_actions ) ;
plugActionList ( " dutToolBar_actionlist " , dut_actions ) ;
TQPtrList < KAction > instrument_actions ;
inst_sa_menu = new KAction ( i18n ( " Launch Spectrum Analyzer " ) , " remote " , KShortcut ( ) , TQT_TQOBJECT ( this ) , TQT_SLOT ( startModule ( ) ) , ac , " libremotelab_commanalyzer " ) ;
instrument_actions . append ( inst_sa_menu ) ;
unplugActionList ( " instrumentMenu_actionlist " ) ;
unplugActionList ( " instrumentToolBar_actionlist " ) ;
plugActionList ( " instrumentMenu_actionlist " , instrument_actions ) ;
plugActionList ( " instrumentToolBar_actionlist " , instrument_actions ) ;
TQPtrList < KAction > service_actions ;
// Nothing here yet!
unplugActionList ( " serviceMenu_actionlist " ) ;
unplugActionList ( " serviceToolBar_actionlist " ) ;
plugActionList ( " serviceMenu_actionlist " , service_actions ) ;
plugActionList ( " serviceToolBar_actionlist " , service_actions ) ;
}
void RemoteMDI : : startModule ( ) {
const KAction * sendingAction = dynamic_cast < const KAction * > ( sender ( ) ) ;
if ( sendingAction ) {
// RAJA FIXME
bool serviceFound = false ;
ServiceType st ;
for ( ServiceList : : Iterator it ( m_activeStation . services . begin ( ) ) ; it ! = m_activeStation . services . end ( ) ; + + it ) {
st = * it ;
if ( st . clientLibrary = = sendingAction - > name ( ) ) {
serviceFound = true ;
}
}
if ( ! serviceFound ) {
KMessageBox : : error ( this , i18n ( " <qt>The active laboratory workspace does not support the requested service</qt> " ) , i18n ( " Service Unavailable " ) ) ;
return ;
}
RemoteLab : : InstrumentView * view = new RemoteLab : : InstrumentView ( sendingAction - > name ( ) , st . name , ( mdiMode ( ) = = KMdi : : ToplevelMode ) ? 0 : this ) ;
openNewWindow ( view ) ;
if ( m_serverHost ! = " " ) {
view - > connectServer ( m_serverHost ) ;
}
}
}
void RemoteMDI : : connectToServer ( ) {
if ( m_rsvSvrSocket ) {
if ( m_rsvSvrSocket - > state ( ) ! = TQSocket : : Idle ) {
printf ( " [DEBUG] Not connecting because the socket is still in state %d \n \r " , m_rsvSvrSocket - > state ( ) ) ; fflush ( stdout ) ;
return ;
}
}
connect_action - > setEnabled ( false ) ;
disconnect_action - > setEnabled ( true ) ;
// Connect to the central reservation/control server
if ( ! m_rsvSvrSocket ) {
m_rsvSvrSocket = new TDEKerberosClientSocket ( this ) ;
connect ( m_rsvSvrSocket , SIGNAL ( connectionClosed ( ) ) , this , SLOT ( connectionClosedHandler ( ) ) ) ;
}
m_rsvSvrSocket - > setServiceName ( " remotefpga " ) ;
if ( m_serverHost ! = " " ) {
m_rsvSvrSocket - > setServerFQDN ( m_serverHost ) ;
m_rsvSvrSocket - > connectToHost ( m_serverHost , 4004 ) ;
TQTimer connectionTimeout ;
connectionTimeout . start ( 5000 , TRUE ) ;
while ( ( m_rsvSvrSocket - > state ( ) = = TQSocket : : Connecting ) | | ( m_rsvSvrSocket - > state ( ) = = TQSocket : : HostLookup ) ) {
tqApp - > processEvents ( ) ;
if ( ! connectionTimeout . isActive ( ) ) {
break ;
}
}
connectionTimeout . stop ( ) ;
if ( m_rsvSvrSocket - > state ( ) = = TQSocket : : Connected ) {
printf ( " [DEBUG] Initial connection established... \n \r " ) ; fflush ( stdout ) ;
if ( m_rsvSvrSocket - > setUsingKerberos ( true ) ! = 0 ) {
disconnectFromServer ( ) ;
KMessageBox : : error ( this , i18n ( " <qt>Unable to establish Kerberos protocol with remote server<p>Please verify that you currently hold a valid Kerberos ticket</qt> " ) , i18n ( " Connection Failed " ) ) ;
}
else {
// Connection established!
// Read magic number and proto version from server
TQDataStream * ds = new TQDataStream ( m_rsvSvrSocket ) ;
TQ_UINT32 magicnum ;
TQ_UINT32 protover ;
* ds > > magicnum ;
* ds > > protover ;
printf ( " [DEBUG] Got magic number %d and protocol version %d \n \r " , magicnum , protover ) ; fflush ( stdout ) ;
delete ds ;
if ( ( magicnum = = MAGIC_NUMBER ) & & ( protover = = PROTOCOL_VERSION ) ) {
disconnect_action - > setEnabled ( true ) ;
promptForStationType ( ) ;
}
else {
disconnectFromServer ( ) ;
KMessageBox : : error ( this , i18n ( " <qt>The remote server is not compatible with this client</qt> " ) , i18n ( " Connection Failed " ) ) ;
}
}
}
else {
disconnectFromServer ( ) ;
KMessageBox : : error ( this , i18n ( " <qt>Unable to establish connection to remote server</qt> " ) , i18n ( " Connection Failed " ) ) ;
}
}
else {
disconnectFromServer ( ) ;
KMessageBox : : error ( this , i18n ( " <qt>The address of the remote server has not been specified</qt> " ) , i18n ( " Connection Failed " ) ) ;
}
processLockouts ( ) ;
}
void RemoteMDI : : promptForStationType ( ) {
if ( ! m_rsvSvrSocket ) {
return ;
}
if ( m_rsvSvrSocket - > state ( ) ! = TQSocket : : Connected ) {
return ;
}
TQDataStream ds ( m_rsvSvrSocket ) ;
// Request list of laboratory stations
StationList slist ;
ds < < TQString ( " LIST " ) ;
ds > > slist ;
printf ( " [RAJA DEBUG 200.2] Got list of stations, count is %d \n \r " , slist . count ( ) ) ; fflush ( stdout ) ;
SelectServerDialog select ( this , 0 , slist ) ;
const int ret = select . exec ( ) ;
if ( ret = = KDialog : : Accepted ) {
TQString result ;
ds < < TQString ( " BIND " ) ;
ds < < select . m_selectedStation ;
ds > > result ;
printf ( " [RAJA DEBUG 100.0] '%s' \n \r " , result . ascii ( ) ) ; fflush ( stdout ) ;
if ( result = = " OK " ) {
// Success!
m_activeStation = select . m_selectedStation ;
}
else if ( result = = " ERRUNAVAL " ) {
KMessageBox : : error ( this , i18n ( " <qt>No stations of the specified type are currently available<p>Please try again later</qt> " ) , i18n ( " Insufficient Laboratory Resources " ) ) ;
disconnectFromServer ( ) ;
}
else if ( result = = " ERRPREVCN " ) {
KMessageBox : : error ( this , i18n ( " <qt>You are already connected to a laboratory station<p>Please disconnect and try again</qt> " ) , i18n ( " Multiple Connections Detected " ) ) ;
disconnectFromServer ( ) ;
}
else {
KMessageBox : : error ( this , i18n ( " <qt>Unknown server error<p>Please reconnect and try again</qt> " ) , i18n ( " Internal Error " ) ) ;
disconnectFromServer ( ) ;
}
}
else {
disconnectFromServer ( ) ;
}
}
void RemoteMDI : : disconnectFromServer ( ) {
connect_action - > setEnabled ( false ) ;
disconnect_action - > setEnabled ( false ) ;
// Close all windows
KMdiIterator < KMdiChildView * > * it = createIterator ( ) ;
while ( it - > currentItem ( ) ) {
KMdiChildView * c = dynamic_cast < KMdiChildView * > ( it - > currentItem ( ) ) ;
if ( c ) {
closeSpecifiedWindow ( c ) ;
}
it - > next ( ) ;
}
deleteIterator ( it ) ;
if ( m_rsvSvrSocket ) {
m_rsvSvrSocket - > clearPendingData ( ) ;
m_rsvSvrSocket - > close ( ) ;
delete m_rsvSvrSocket ;
m_rsvSvrSocket = NULL ;
}
connect_action - > setEnabled ( true ) ;
processLockouts ( ) ;
}
void RemoteMDI : : connectionClosedHandler ( ) {
disconnectFromServer ( ) ;
KMessageBox : : error ( this , i18n ( " <qt>The remote server has closed the connection</qt> " ) , i18n ( " Connection Terminated " ) ) ;
}
void RemoteMDI : : processLockouts ( ) {
bool connected = false ;
if ( m_rsvSvrSocket ) {
connected = ( m_rsvSvrSocket - > state ( ) = = TQSocket : : Connected ) ;
}
printf ( " [RAJA DEBUG 600.0] connected: %d \n \r " , connected ) ; fflush ( stdout ) ;
connect_action - > setEnabled ( ! connected ) ;
disconnect_action - > setEnabled ( connected ) ;
inst_fpgaviewer_menu - > setEnabled ( connected ) ;
inst_sa_menu - > setEnabled ( connected ) ;
}
void RemoteMDI : : configToolbars ( ) {
KEditToolbar dialog ( factory ( ) , this ) ;
dialog . showButtonApply ( false ) ;
if ( dialog . exec ( ) ) {
applyMainWindowSettings ( kapp - > config ( ) , " window " ) ;
}
}
void RemoteMDI : : configKeys ( ) {
KKeyDialog : : configure ( actionCollection ( ) , this ) ;
}
void RemoteMDI : : setServerHost ( TQString server ) {
m_serverHost = server ;
}
void RemoteMDI : : openNewWindow ( KMdiChildView * view ) {
// Add a child view
m_children + + ;
// The child view will be our child only if we aren't in Toplevel mode
if ( ! view ) {
view = new KMdiChildView ( i18n ( " View %1 " ) . arg ( m_children ) , ( mdiMode ( ) = = KMdi : : ToplevelMode ) ? 0 : this ) ;
}
( new TQHBoxLayout ( view ) ) - > setAutoAdd ( true ) ;
// Add to the MDI and set as current
if ( mdiMode ( ) = = KMdi : : ToplevelMode ) {
addWindow ( view , KMdi : : Detach ) ;
}
else {
addWindow ( view ) ;
}
currentChanged ( view ) ;
// Handle termination
connect ( view , SIGNAL ( childWindowCloseRequest ( KMdiChildView * ) ) , this , SLOT ( childClosed ( KMdiChildView * ) ) ) ;
}
void RemoteMDI : : childWindowCloseRequest ( KMdiChildView * pWnd ) {
RemoteLab : : InstrumentView * iview = dynamic_cast < RemoteLab : : InstrumentView * > ( pWnd ) ;
if ( iview ) {
// Give the child a chance to finish what it was doing and exit cleanly (i.e. without crashing!)
iview - > closeConnections ( ) ;
iview - > hide ( ) ;
// RAJA FIXME
// Executing KMdiMainFrm::childWindowCloseRequest(pWnd) here will probably cause a crash
// We need to call this AFTER control has been returned to the main event loop at least once
// This is related to my lack of proper returning to the event loop, which MUST BE FIXED
// KMdiMainFrm::childWindowCloseRequest(pWnd); // RAJA UNCOMMENT ME
}
}
void RemoteMDI : : currentChanged ( KMdiChildView * current ) {
// Update status bar and list box
statusBar ( ) - > message ( i18n ( " %1 activated " ) . arg ( current - > tabCaption ( ) ) ) ;
}
void RemoteMDI : : closeCurrent ( ) {
// If there's a current view, close it
if ( m_pCurrentWindow ) {
closeSpecifiedWindow ( m_pCurrentWindow ) ;
}
}
void RemoteMDI : : closeSpecifiedWindow ( KMdiChildView * window ) {
if ( window ) {
// Notify the status bar of the removal of the window
statusBar ( ) - > message ( i18n ( " %1 removed " ) . arg ( window - > tabCaption ( ) ) ) ;
// We could also call removeWindowFromMdi, but it doesn't delete the
// pointer. This way, we're sure that the view will get deleted.
closeWindow ( window ) ;
// Synchronize combo box
if ( m_pCurrentWindow ) {
currentChanged ( m_pCurrentWindow ) ;
}
}
}
void RemoteMDI : : childClosed ( KMdiChildView * w ) {
assert ( w ) ;
// Set as active
w - > activate ( ) ;
assert ( w = = m_pCurrentWindow ) ;
// Notify the status bar of the removal of the window
statusBar ( ) - > message ( i18n ( " %1 removed " ) . arg ( w - > tabCaption ( ) ) ) ;
// Remove the view from MDI, BUT DO NOT DELETE IT! It is automatically deleted by TQt since it was closed.
removeWindowFromMdi ( w ) ;
}
bool RemoteMDI : : queryClose ( ) {
// Close all open connections
KMdiIterator < KMdiChildView * > * it = createIterator ( ) ;
while ( it - > currentItem ( ) ) {
KMdiChildView * c = dynamic_cast < KMdiChildView * > ( it - > currentItem ( ) ) ;
if ( c ) {
RemoteLab : : InstrumentView * iview = dynamic_cast < RemoteLab : : InstrumentView * > ( c ) ;
if ( iview ) {
iview - > closeConnections ( ) ;
}
}
it - > next ( ) ;
}
deleteIterator ( it ) ;
// Save current MDI settings (window positions, etc.)
KConfig * c = kapp - > config ( ) ;
// RAJA FIXME
c - > sync ( ) ;
// Allow this window to close
return true ;
}
# include "remotemdi.moc"