You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

411 lines
12 KiB

//Author: Timothy Pearson <kb9vqf@pearsoncomputing.net>, (C) 2012
//Copyright: See COPYING file that comes with this distribution
// TDE MDI interface based on excellent 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");
inst_sa_menu = new KAction(i18n("Launch Spectrum Analyzer"), "remote", KShortcut(), TQT_TQOBJECT(this), TQT_SLOT(startSpectrumAnalyzer()), ac, "spectrum_analyzer");
// 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!"));
// Create the list of the opened windows
m_listBox = new KListBox(this);
m_listBox->setCaption(i18n("Opened windows"));
addToolWindow(m_listBox, KDockWidget::DockLeft, getMainDockWidget());
connect(m_listBox, SIGNAL(executed(TQListBoxItem *)), this, SLOT(listBoxExecuted(TQListBoxItem*)));
connect(m_listBox, SIGNAL(rightButtonClicked(TQListBoxItem*, const TQPoint&)), this, SLOT(listBoxRightClicked(TQListBoxItem*)));
processLockouts();
}
RemoteMDI::~RemoteMDI()
{
while (m_pCurrentWindow) {
closeCurrent();
}
if (m_rsvSvrSocket) {
m_rsvSvrSocket->close();
while (m_rsvSvrSocket->state() == TQSocket::Closing) {
tqApp->processEvents();
}
}
}
void RemoteMDI::connectToServer() {
if (m_rsvSvrSocket) {
if (m_rsvSvrSocket->state() != TQSocket::Idle) {
return;
}
}
connect_action->setEnabled(false);
disconnect_action->setEnabled(false);
// 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);
while ((m_rsvSvrSocket->state() == TQSocket::Connecting) || (m_rsvSvrSocket->state() == TQSocket::HostLookup)) {
tqApp->processEvents();
}
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;
if (result == "OK") {
// Success, do nothing
}
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 {
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);
if (m_rsvSvrSocket) {
m_rsvSvrSocket->close();
while (m_rsvSvrSocket->state() == TQSocket::Closing) {
tqApp->processEvents();
}
}
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_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::startSpectrumAnalyzer() {
RemoteLab::InstrumentView* saview = new RemoteLab::InstrumentView("libremotelab_commanalyzer", i18n("Communications Analyzer"), (mdiMode() == KMdi::ToplevelMode) ? 0 : this);
openNewWindow(saview);
if (m_serverHost != "") {
saview->connectServer(m_serverHost);
}
}
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 the item to the window list
m_window.append(view);
m_listBox->insertItem(view->tabCaption());
// 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)
{
// Update status bar and list box
statusBar()->message(i18n( "%1 activated").arg(current->tabCaption()));
TQListBoxItem *item = m_listBox->findItem(current->tabCaption());
assert(item);
m_listBox->setCurrentItem(item);
}
void RemoteMDI::closeCurrent()
{
// If there's a current view, close it
if ( m_pCurrentWindow != 0 ) {
// Notify the status bar of the removal of the window
statusBar()->message(i18n("%1 removed").arg(m_pCurrentWindow->tabCaption()));
// Remove from the window list
m_window.remove(m_window.find(m_pCurrentWindow));
// Remove from the list box
TQListBoxItem *item = m_listBox->findItem(m_pCurrentWindow->tabCaption());
assert( item );
delete item;
// We could also call removeWindowFromMdi, but it doesn't delete the
// pointer. This way, we're sure that the view will get deleted.
closeWindow(m_pCurrentWindow);
}
// Synchronize combo box
if (m_pCurrentWindow) {
currentChanged(m_pCurrentWindow);
}
}
void RemoteMDI::listBoxExecuted(TQListBoxItem *item)
{
// Get the current item's text
TQString text = item->text();
// Active the corresponding tab
for (TQValueList< KMdiChildView *>::iterator it = m_window.begin(); it != m_window.end(); ++it ) {
// Get the view
KMdiChildView *view = *it;
assert(view);
// Is the view we need to show?
if (view->caption() == text) {
view->activate();
break;
}
}
}
void RemoteMDI::listBoxRightClicked(TQListBoxItem *item)
{
// Get the current item's text
TQString text = item->text();
// Bring up a menu for the corresponding window
// RAJA FIXME
for (TQValueList< KMdiChildView *>::iterator it = m_window.begin(); it != m_window.end(); ++it ) {
// Get the view
KMdiChildView *view = *it;
assert(view);
// Is the view we need to show?
if (view->caption() == text) {
view->activate();
break;
}
}
}
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 from the window list
m_window.remove(m_window.find(w));
// Remove from the list box
TQListBoxItem *item = m_listBox->findItem( w->tabCaption() );
assert(item);
delete item;
// 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
for (TQValueList< KMdiChildView *>::iterator it = m_window.begin(); it != m_window.end(); ++it ) {
RemoteLab::InstrumentView* iview = dynamic_cast<RemoteLab::InstrumentView*>(*it);
if (iview) {
iview->closeConnections();
}
}
// 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"