//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 ) , connToServerConnecting ( false ) , connToServerState ( - 1 ) , connToServerTimeoutTimer ( 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 ( ) ) ;
}
setMenuForSDIModeSysButtons ( menuBar ( ) ) ;
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 & ) ) , this , TQT_SLOT ( updateStatusBarMainMessage ( const TQString & ) ) ) ;
connect ( ac , TQT_SIGNAL ( clearStatusText ( ) ) , statusBar ( ) , TQT_SLOT ( clear ( ) ) ) ;
// Create the status bar
updateStatusBarMainMessage ( i18n ( " No active instruments " ) ) ;
processActions ( ) ;
processLockouts ( ) ;
}
RemoteMDI : : ~ RemoteMDI ( )
{
while ( m_pCurrentWindow ) {
closeCurrent ( ) ;
}
if ( m_rsvSvrSocket ) {
m_rsvSvrSocket - > clearPendingData ( ) ;
m_rsvSvrSocket - > close ( ) ;
delete m_rsvSvrSocket ;
m_rsvSvrSocket = NULL ;
}
}
void RemoteMDI : : updateStatusBarMessage ( ) {
TQString windowStatusBarMessage ;
if ( m_pCurrentWindow ) {
windowStatusBarMessage = m_windowStatusBarMapping [ TQT_TQOBJECT ( m_pCurrentWindow ) ] ;
}
KStatusBar * sb = statusBar ( ) ;
if ( sb ) {
sb - > message ( m_mainStatusBarMessage + ( ( windowStatusBarMessage ! = " " ) ? " [ " + i18n ( " Instrument " ) + " : " + windowStatusBarMessage + " ] " : " " ) ) ;
}
}
void RemoteMDI : : updateStatusBarMainMessage ( const TQString & message ) {
m_mainStatusBarMessage = message ;
updateStatusBarMessage ( ) ;
}
void RemoteMDI : : updateStatusBarWindowMessage ( const TQString & message , const TQObject * window ) {
const TQObject * windowObject = window ;
if ( ! windowObject ) {
windowObject = sender ( ) ;
}
if ( windowObject ) {
m_windowStatusBarMapping [ windowObject ] = message ;
}
updateStatusBarMessage ( ) ;
}
void RemoteMDI : : resizeEvent ( TQResizeEvent * e ) {
KMdiMainFrm : : resizeEvent ( e ) ;
setSysButtonsAtMenuPosition ( ) ;
}
void RemoteMDI : : processActions ( ) {
// Add dynamic actions
KActionCollection * const ac = actionCollection ( ) ;
KAction * action ;
ServiceType st ;
for ( ServiceList : : Iterator it ( m_activeStation . services . begin ( ) ) ; it ! = m_activeStation . services . end ( ) ; + + it ) {
st = * it ;
action = new KAction ( i18n ( " Launch " ) + " " + st . name , st . clientLibrary , KShortcut ( ) , TQT_TQOBJECT ( this ) , TQT_SLOT ( startModule ( ) ) , ac , st . clientLibrary . ascii ( ) ) ;
m_instrumentActionList . append ( action ) ;
}
plugActionList ( " instrumentMenu_actionlist " , m_instrumentActionList ) ;
plugActionList ( " instrumentToolBar_actionlist " , m_instrumentActionList ) ;
}
void RemoteMDI : : startModule ( ) {
const KAction * sendingAction = dynamic_cast < const KAction * > ( sender ( ) ) ;
if ( sendingAction ) {
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 ;
break ;
}
}
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 ( st . clientLibrary , st . name , ( mdiMode ( ) = = KMdi : : ToplevelMode ) ? 0 : this ) ;
view - > setName ( st . clientLibrary . ascii ( ) ) ;
connect ( view , SIGNAL ( statusMessageSet ( const TQString & ) ) , this , SLOT ( updateStatusBarWindowMessage ( const TQString & ) ) ) ;
if ( st . singleInstance ) {
const_cast < KAction * > ( sendingAction ) - > setEnabled ( false ) ;
}
openNewWindow ( view ) ;
if ( m_serverHost ! = " " ) {
view - > connectServer ( m_serverHost ) ;
}
}
}
void RemoteMDI : : finishConnectingToServer ( ) {
if ( ! m_rsvSvrSocket ) {
connToServerState = - 1 ;
connToServerConnecting = false ;
processLockouts ( ) ;
return ;
}
if ( connToServerConnecting ) {
switch ( connToServerState ) {
case 0 :
if ( ! connToServerTimeoutTimer ) {
connToServerTimeoutTimer = new TQTimer ;
connToServerTimeoutTimer - > start ( 5000 , TRUE ) ;
}
if ( ( m_rsvSvrSocket - > state ( ) = = TQSocket : : Connecting ) | | ( m_rsvSvrSocket - > state ( ) = = TQSocket : : HostLookup ) ) {
if ( ! connToServerTimeoutTimer - > isActive ( ) ) {
connToServerState = - 3 ;
connToServerConnecting = false ;
disconnectFromServer ( ) ;
KMessageBox : : error ( this , i18n ( " <qt>Unable to establish connection to remote server</qt> " ) , i18n ( " Connection Failed " ) ) ;
}
}
else {
if ( m_rsvSvrSocket - > state ( ) = = TQSocket : : Connected ) {
printf ( " [DEBUG] Initial connection established... \n \r " ) ; fflush ( stdout ) ;
m_rsvSvrSocket - > setDataTimeout ( 5000 ) ;
m_rsvSvrSocket - > setUsingKerberos ( true ) ;
connToServerState = 1 ;
}
else {
connToServerState = - 1 ;
connToServerConnecting = false ;
disconnectFromServer ( ) ;
KMessageBox : : error ( this , i18n ( " <qt>Unable to establish connection to remote server</qt> " ) , i18n ( " Connection Failed " ) ) ;
}
}
break ;
case 1 :
if ( m_rsvSvrSocket - > kerberosStatus ( ) = = TDEKerberosClientSocket : : KerberosInitializing ) {
// Do nothing
}
else {
if ( m_rsvSvrSocket - > kerberosStatus ( ) ! = TDEKerberosClientSocket : : KerberosInUse ) {
connToServerState = - 1 ;
connToServerConnecting = false ;
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 {
connToServerState = 2 ;
}
}
break ;
case 2 :
// 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 " ) ) ;
}
connToServerState = 3 ;
connToServerConnecting = false ;
processLockouts ( ) ;
break ;
}
TQTimer : : singleShot ( 0 , this , SLOT ( finishConnectingToServer ( ) ) ) ;
}
}
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 ( ) ) ) ;
connect ( m_rsvSvrSocket , TQT_SIGNAL ( statusMessageUpdated ( const TQString & ) ) , this , TQT_SLOT ( updateStatusBarMainMessage ( const TQString & ) ) ) ;
}
m_rsvSvrSocket - > setServiceName ( " remotefpga " ) ;
if ( m_serverHost ! = " " ) {
m_rsvSvrSocket - > setServerFQDN ( m_serverHost ) ;
m_rsvSvrSocket - > connectToHost ( m_serverHost , 4004 ) ;
// Finish connecting when appropriate
connToServerState = 0 ;
connToServerConnecting = true ;
TQTimer : : singleShot ( 0 , this , SLOT ( finishConnectingToServer ( ) ) ) ;
}
}
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 ;
processActions ( ) ;
}
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 ) ;
m_instrumentActionList . clear ( ) ;
unplugActionList ( " instrumentMenu_actionlist " ) ;
unplugActionList ( " instrumentToolBar_actionlist " ) ;
// 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 ) & & ( connToServerConnecting = = false ) & & ( connToServerState > 0 ) ) ;
}
printf ( " [RAJA DEBUG 600.0] connected: %d \n \r " , connected ) ; fflush ( stdout ) ;
connect_action - > setEnabled ( ! connected ) ;
disconnect_action - > setEnabled ( connected ) ;
for ( TQPtrList < KAction > : : Iterator it ( m_instrumentActionList . begin ( ) ) ; it ! = m_instrumentActionList . end ( ) ; + + it ) {
( * it ) - > 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 ( ) ;
KMdiMainFrm : : childWindowCloseRequest ( pWnd ) ;
}
}
void RemoteMDI : : currentChanged ( KMdiChildView * current ) {
RemoteLab : : InstrumentView * view = dynamic_cast < RemoteLab : : InstrumentView * > ( current ) ;
// Plug/unplug menus
if ( view ) {
unplugActionList ( " selectedInstrument_actionlist " ) ;
plugActionList ( " selectedInstrument_actionlist " , view - > menuActionList ( ) ) ;
}
// Update status bar and list box
updateStatusBarMainMessage ( i18n ( " Instrument %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
updateStatusBarWindowMessage ( TQString : : null , TQT_TQOBJECT ( window ) ) ;
updateStatusBarMainMessage ( i18n ( " Instrument %1 removed " ) . arg ( window - > tabCaption ( ) ) ) ;
// Unplug menus
unplugActionList ( " selectedInstrument_actionlist " ) ;
// 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 ) ;
// Unplug menus
unplugActionList ( " selectedInstrument_actionlist " ) ;
// Notify the status bar of the removal of the window
updateStatusBarWindowMessage ( TQString : : null , TQT_TQOBJECT ( w ) ) ;
updateStatusBarMainMessage ( i18n ( " Instrument %1 removed " ) . arg ( w - > tabCaption ( ) ) ) ;
// Re-enable associated action
RemoteLab : : InstrumentView * view = dynamic_cast < RemoteLab : : InstrumentView * > ( w ) ;
if ( view ) {
TQString libraryName = view - > name ( ) ;
for ( TQPtrList < KAction > : : Iterator it ( m_instrumentActionList . begin ( ) ) ; it ! = m_instrumentActionList . end ( ) ; + + it ) {
if ( ( * it ) - > name ( ) = = libraryName ) {
( * it ) - > setEnabled ( true ) ;
}
}
}
// Remove status bar text
m_windowStatusBarMapping . remove ( TQT_TQOBJECT ( w ) ) ;
// 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"