mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
592 lines
17 KiB
C++
592 lines
17 KiB
C++
#include "pqRemoteCommandDialog.h"
|
|
#include "ui_pqRemoteCommandDialogForm.h"
|
|
#include "pqRemoteCommandTemplateDialog.h"
|
|
|
|
#include <QDebug>
|
|
#include <QSettings>
|
|
#include <QInputDialog>
|
|
#include <QMessageBox>
|
|
#include <QList>
|
|
#include <QStringList>
|
|
#include <QString>
|
|
|
|
#include "vtkIndent.h"
|
|
|
|
#include "pqApplicationCore.h"
|
|
#include "pqSettings.h"
|
|
#include "pqFileDialog.h"
|
|
|
|
#include <string>
|
|
|
|
#define pqErrorMacro(estr)\
|
|
qDebug()\
|
|
<< "Error in:" << endl\
|
|
<< __FILE__ << ", line " << __LINE__ << endl\
|
|
<< "" estr << endl;
|
|
|
|
// User interface
|
|
//=============================================================================
|
|
class pqRemoteCommandDialogUI
|
|
:
|
|
public Ui::pqRemoteCommandDialogForm
|
|
{};
|
|
|
|
|
|
// command token map, the following tokens may be provided by
|
|
// the user to be substituted into the selected command template
|
|
// at run time.
|
|
enum {
|
|
TERM_EXEC=0,
|
|
TERM_OPTS,
|
|
SSH_EXEC,
|
|
FE_URL,
|
|
PV_HOST,
|
|
PV_PID,
|
|
N_TOKENS
|
|
};
|
|
|
|
const char *tokens[] = {
|
|
"$TERM_EXEC$",
|
|
"$TERM_OPTS$",
|
|
"$SSH_EXEC$",
|
|
"$FE_URL$",
|
|
"$PV_HOST$",
|
|
"$PV_PID$"
|
|
};
|
|
|
|
// a command set is slected based on host system types.
|
|
// client | server | descr
|
|
//--------+--------+----------
|
|
// 0 | -1 | unix cli
|
|
// 0 | 0 | unix unix
|
|
// 0 | 1 | unix win
|
|
// 1 | -1 | win cli
|
|
// 1 | 0 | win unix
|
|
// 1 | 1 | win win
|
|
// the command set identifier is computed as follows:
|
|
// csid=10*server+client
|
|
enum {
|
|
SET_UNIX_ONLY=-10,
|
|
SET_UNIX_UNIX=0,
|
|
SET_UNIX_WIN=10,
|
|
SET_WIN_ONLY=-9,
|
|
SET_WIN_UNIX=1,
|
|
SET_WIN_WIN=11
|
|
};
|
|
|
|
namespace {
|
|
|
|
//*****************************************************************************
|
|
int commandSetId(int clientType, int serverType)
|
|
{
|
|
return 10*serverType+clientType;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
int searchAndReplace(
|
|
const string &searchFor,
|
|
const string &replaceWith,
|
|
string &inText)
|
|
{
|
|
int nFound=0;
|
|
const size_t n=searchFor.size();
|
|
size_t at=string::npos;
|
|
while ((at=inText.find(searchFor))!=string::npos)
|
|
{
|
|
inText.replace(at,n,replaceWith);
|
|
++nFound;
|
|
}
|
|
return nFound;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
int searchAndReplace(
|
|
const char *searchFor,
|
|
const char *replaceWith,
|
|
string &inText)
|
|
{
|
|
string searchForStr(searchFor);
|
|
string replaceWithStr(replaceWith);
|
|
return searchAndReplace(searchForStr,replaceWithStr,inText);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
void addWinDefaults(QStringList &cmds)
|
|
{
|
|
// TERM_EXEC, TERM_OPTS,SSH_EXEC,FE_URL,last used template
|
|
cmds
|
|
<< "cmd.exe"
|
|
<< ""
|
|
<< "plink.exe"
|
|
<< "USER$CLUSTER.COM"
|
|
<< "0";
|
|
}
|
|
|
|
//*****************************************************************************
|
|
void addUnixDefaults(QStringList &cmds)
|
|
{
|
|
// TERM_EXEC, TERM_OPTS,SSH_EXEC,FE_URL,last used template
|
|
cmds
|
|
<< "xterm"
|
|
<< "-geometry 200x40 -fg white -bg black -T $PV_HOST$:$PV_PID$"
|
|
<< "ssh"
|
|
<< "USER@CLUSTER.COM"
|
|
<< "0";
|
|
}
|
|
|
|
//*****************************************************************************
|
|
void addUnixOnlyCommands(QStringList &cmds)
|
|
{
|
|
cmds
|
|
<< "local gdb" << "$TERM_EXEC$ $TERM_OPTS$ -e gdb --pid=$PV_PID$"
|
|
<< "local stack trace" << "$TERM_EXEC$ -e kill -INT $PV_PID$"
|
|
<< "local kill process" << "$TERM_EXEC$ -e kill -KILL $PV_PID$";
|
|
}
|
|
|
|
//*****************************************************************************
|
|
void addUnixUnixCommands(QStringList &cmds)
|
|
{
|
|
cmds
|
|
<< "remote top" << "$TERM_EXEC$ $TERM_OPTS$ -e $SSH_EXEC$ -t $PV_HOST$ top"
|
|
<< "remote gdb" << "$TERM_EXEC$ $TERM_OPTS$ -e $SSH_EXEC$ -t $PV_HOST$ gdb --pid=$PV_PID$"
|
|
<< "remote stack trace" << "$TERM_EXEC$ -e $SSH_EXEC$ -t $PV_HOST$ kill -INT --pid=$PV_PID$"
|
|
<< "remote kill process" << "$TERM_EXEC$ -e $SSH_EXEC$ -t $PV_HOST$ kill -KILL --pid=$PV_PID$"
|
|
<< "remote w/login top" << "$TERM_EXEC$ $TERM_OPTS$ -e $SSH_EXEC$ -t $FE_URL$ ssh -t $PV_HOST$ top"
|
|
<< "remote w/login gdb" << "$TERM_EXEC$ $TERM_OPTS$ -e $SSH_EXEC$ -t $FE_URL$ ssh -t $PV_HOST$ gdb --pid=$PV_PID$"
|
|
<< "remote w/login stack trace" << "$TERM_EXEC$ -e $SSH_EXEC$ -t $FE_URL$ ssh -t $PV_HOST$ kill -INT --pid=$PV_PID$"
|
|
<< "remote w/login kill process" << "$TERM_EXEC$ -e $SSH_EXEC$ -t $FE_URL$ ssh -t $PV_HOST$ kill -KILL --pid=$PV_PID$";
|
|
}
|
|
|
|
//*****************************************************************************
|
|
void addUnixWinCommands(QStringList &cmds)
|
|
{
|
|
(void)cmds;
|
|
// TODO
|
|
// base these off from WinOnly commands
|
|
}
|
|
|
|
//*****************************************************************************
|
|
void addWinOnlyCommands(QStringList &cmds)
|
|
{
|
|
(void)cmds;
|
|
// TODO
|
|
// scripts to attach a debugger etc...
|
|
cmds
|
|
<< "local debug" << "$TERM_EXEC$ /K start \"C:\\Program Files\\Debugging Tools for Windows (x86)\\windbg.exe\" -p $PV_PID$ /g";
|
|
}
|
|
|
|
//*****************************************************************************
|
|
void addWinUnixCommands(QStringList &cmds)
|
|
{
|
|
cmds
|
|
<< "remote top" << "$TERM_EXEC$ /K start $SSH_EXEC$ -t $PV_HOST$ top"
|
|
<< "remote gdb" << "$TERM_EXEC$ /K start $SSH_EXEC$ -t $PV_HOST$ gdb --pid=$PV_PID$"
|
|
<< "remote stack trace" << "$TERM_EXEC$ /K start $SSH_EXEC$ -t $PV_HOST$ kill -INT --pid=$PV_PID$"
|
|
<< "remote kill process" << "$TERM_EXEC$ /K start $SSH_EXEC$ -t $PV_HOST$ kill -KILL --pid=$PV_PID$"
|
|
<< "remote w/login top" << "$TERM_EXEC$ /K start $SSH_EXEC$ -t $FE_URL$ ssh -t $PV_HOST$ top"
|
|
<< "remote w/login gdb" << "$TERM_EXEC$ /K start $SSH_EXEC$ -t $FE_URL$ ssh -t $PV_HOST$ gdb --pid=$PV_PID$"
|
|
<< "remote w/login stack trace" << "$TERM_EXEC$ /K start $SSH_EXEC$ -t $FE_URL$ ssh -t $PV_HOST$ kill -INT --pid=$PV_PID$"
|
|
<< "remote w/login kill process" << "$TERM_EXEC$ /K start $SSH_EXEC$ -t $FE_URL$ ssh -t $PV_HOST$ kill -KILL --pid=$PV_PID$";
|
|
}
|
|
|
|
//*****************************************************************************
|
|
void addWinWinCommands(QStringList &cmds)
|
|
{
|
|
(void)cmds;
|
|
// TODO
|
|
// base these off from WinOnly commands
|
|
}
|
|
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
pqRemoteCommandDialog::pqRemoteCommandDialog(
|
|
QWidget *Parent,
|
|
Qt::WindowFlags flags,
|
|
int clientSystemType,
|
|
int serverSystemType)
|
|
:
|
|
QDialog(Parent,flags),
|
|
Ui(0)
|
|
{
|
|
this->Ui = new pqRemoteCommandDialogUI;
|
|
this->Ui->setupUi(this);
|
|
|
|
int csid=commandSetId(clientSystemType,serverSystemType);
|
|
switch(csid)
|
|
{
|
|
case SET_UNIX_ONLY:
|
|
this->CommandSetName="UnixOnly";
|
|
::addUnixDefaults(this->CommandSet);
|
|
::addUnixOnlyCommands(this->CommandSet);
|
|
break;
|
|
case SET_UNIX_UNIX:
|
|
this->CommandSetName="UnixUnix";
|
|
::addUnixDefaults(this->CommandSet);
|
|
::addUnixUnixCommands(this->CommandSet);
|
|
break;
|
|
case SET_UNIX_WIN:
|
|
this->CommandSetName="UnixWin";
|
|
::addUnixDefaults(this->CommandSet);
|
|
::addUnixWinCommands(this->CommandSet);
|
|
break;
|
|
case SET_WIN_ONLY:
|
|
this->CommandSetName="WinOnly";
|
|
::addWinDefaults(this->CommandSet);
|
|
::addWinOnlyCommands(this->CommandSet);
|
|
break;
|
|
case SET_WIN_UNIX:
|
|
this->CommandSetName="WinUnix";
|
|
::addWinDefaults(this->CommandSet);
|
|
::addWinUnixCommands(this->CommandSet);
|
|
break;
|
|
case SET_WIN_WIN:
|
|
this->CommandSetName="WinWin";
|
|
::addWinDefaults(this->CommandSet);
|
|
::addWinWinCommands(this->CommandSet);
|
|
break;
|
|
default:
|
|
pqErrorMacro("invalid commandSetType " << csid);
|
|
return;
|
|
}
|
|
|
|
// load users last used values
|
|
this->Restore();
|
|
|
|
// initialize token processing related arrays
|
|
this->Tokens.resize(N_TOKENS);
|
|
for (int i=0; i<N_TOKENS; ++i)
|
|
{
|
|
this->Tokens[i]=tokens[i];
|
|
}
|
|
|
|
this->TokenValues.resize(N_TOKENS);
|
|
|
|
this->TokenWidgets.push_back(this->Ui->xtExec);
|
|
this->TokenWidgets.push_back(this->Ui->xtOpts);
|
|
this->TokenWidgets.push_back(this->Ui->sshExec);
|
|
this->TokenWidgets.push_back(this->Ui->feUrl);
|
|
|
|
// sync the UI
|
|
this->UpdateTokenValues();
|
|
this->UpdateForm();
|
|
this->UpdateCommandPreview();
|
|
|
|
// plumbing that responds to user edits/changes
|
|
|
|
// template drop down
|
|
QObject::connect(
|
|
this->Ui->addCommand,
|
|
SIGNAL(clicked()),
|
|
this,
|
|
SLOT(AddCommandTemplate()));
|
|
|
|
QObject::connect(
|
|
this->Ui->editCommand,
|
|
SIGNAL(clicked()),
|
|
this,
|
|
SLOT(EditCommandTemplate()));
|
|
|
|
QObject::connect(
|
|
this->Ui->deleteCommand,
|
|
SIGNAL(clicked()),
|
|
this,
|
|
SLOT(DeleteCommandTemplate()));
|
|
|
|
QObject::connect(
|
|
this->Ui->commandTemplates, SIGNAL(currentIndexChanged(int)),
|
|
this, SLOT(UpdateCommandPreview()));
|
|
|
|
QObject::connect(
|
|
this->Ui->commandTemplates, SIGNAL(currentIndexChanged(int)),
|
|
this, SLOT(UpdateForm()));
|
|
|
|
// line edits
|
|
QObject::connect(
|
|
this->Ui->sshExec, SIGNAL(textChanged(const QString &)),
|
|
this, SLOT(UpdateTokenValues()));
|
|
QObject::connect(
|
|
this->Ui->sshExec, SIGNAL(textChanged(const QString &)),
|
|
this, SLOT(UpdateCommandPreview()));
|
|
QObject::connect(
|
|
this->Ui->sshExecBrowse, SIGNAL(released()),
|
|
this, SLOT(FindSshExecutable()));
|
|
|
|
QObject::connect(
|
|
this->Ui->xtExec, SIGNAL(textChanged(const QString &)),
|
|
this, SLOT(UpdateTokenValues()));
|
|
QObject::connect(
|
|
this->Ui->xtExec, SIGNAL(textChanged(const QString &)),
|
|
this, SLOT(UpdateCommandPreview()));
|
|
QObject::connect(
|
|
this->Ui->xtExecBrowse, SIGNAL(released()),
|
|
this, SLOT(FindXTermExecutable()));
|
|
|
|
QObject::connect(
|
|
this->Ui->pvHost, SIGNAL(textChanged(const QString &)),
|
|
this, SLOT(UpdateTokenValues()));
|
|
QObject::connect(
|
|
this->Ui->pvHost, SIGNAL(textChanged(const QString &)),
|
|
this, SLOT(UpdateCommandPreview()));
|
|
|
|
QObject::connect(
|
|
this->Ui->xtOpts, SIGNAL(textChanged(const QString &)),
|
|
this, SLOT(UpdateTokenValues()));
|
|
QObject::connect(
|
|
this->Ui->xtOpts, SIGNAL(textChanged(const QString &)),
|
|
this, SLOT(UpdateCommandPreview()));
|
|
|
|
QObject::connect(
|
|
this->Ui->feUrl, SIGNAL(textChanged(const QString &)),
|
|
this, SLOT(UpdateTokenValues()));
|
|
QObject::connect(
|
|
this->Ui->feUrl, SIGNAL(textChanged(const QString &)),
|
|
this, SLOT(UpdateCommandPreview()));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
pqRemoteCommandDialog::~pqRemoteCommandDialog()
|
|
{
|
|
this->Save();
|
|
|
|
delete this->Ui;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqRemoteCommandDialog::Save()
|
|
{
|
|
string group="RemoteCommandDialog";
|
|
group+=this->CommandSetName;
|
|
|
|
QStringList defaults;
|
|
|
|
defaults
|
|
<< this->Ui->xtExec->text()
|
|
<< this->Ui->xtOpts->text()
|
|
<< this->Ui->sshExec->text()
|
|
<< this->Ui->feUrl->text()
|
|
<< QString("%1").arg(this->Ui->commandTemplates->currentIndex());
|
|
|
|
int nCmds=this->Ui->commandTemplates->count();
|
|
for (int i=0; i<nCmds; ++i)
|
|
{
|
|
defaults
|
|
<< this->Ui->commandTemplates->itemText(i)
|
|
<< this->Ui->commandTemplates->itemData(i).toString();
|
|
}
|
|
|
|
pqSettings *settings=pqApplicationCore::instance()->settings();
|
|
settings->beginGroup(group.c_str());
|
|
settings->setValue("defaults",defaults);
|
|
settings->setValue("test","test");
|
|
settings->endGroup();
|
|
settings->sync();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqRemoteCommandDialog::Restore()
|
|
{
|
|
string group="RemoteCommandDialog";
|
|
group+=this->CommandSetName;
|
|
|
|
QStringList defaults;
|
|
|
|
pqSettings *settings=pqApplicationCore::instance()->settings();
|
|
settings->sync();
|
|
settings->beginGroup(group.c_str());
|
|
defaults=settings->value("defaults",this->CommandSet).toStringList();
|
|
settings->endGroup();
|
|
|
|
this->Ui->xtExec->setText(defaults.at(0));
|
|
this->Ui->xtOpts->setText(defaults.at(1));
|
|
this->Ui->sshExec->setText(defaults.at(2));
|
|
this->Ui->feUrl->setText(defaults.at(3));
|
|
int lastTemplateId = defaults.at(4).toInt();
|
|
int n=defaults.size();
|
|
for (int i=5; i<n; i+=2)
|
|
{
|
|
this->Ui->commandTemplates->addItem(defaults.at(i),defaults.at(i+1));
|
|
}
|
|
this->Ui->commandTemplates->setCurrentIndex(lastTemplateId);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqRemoteCommandDialog::SetActiveHost(string host)
|
|
{
|
|
this->TokenValues[PV_HOST]=host;
|
|
this->Ui->pvHost->setText (host.c_str());
|
|
this->UpdateCommandPreview();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqRemoteCommandDialog::SetActivePid(string pid)
|
|
{
|
|
this->TokenValues[PV_PID]=pid;
|
|
this->UpdateCommandPreview();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqRemoteCommandDialog::AddCommandTemplate()
|
|
{
|
|
// remind the user of the available tokens.
|
|
QString toks(tokens[0]);
|
|
for (int i=1; i<N_TOKENS; ++i)
|
|
{
|
|
toks+=" ";
|
|
toks+=tokens[i];
|
|
}
|
|
|
|
pqRemoteCommandTemplateDialog dialog(this,0);
|
|
dialog.SetCommandName(QString("new command"));
|
|
dialog.SetCommandTemplate(toks);
|
|
|
|
if ((dialog.exec()==QDialog::Accepted) && dialog.GetModified())
|
|
{
|
|
QString commandName=dialog.GetCommandName();
|
|
QString commandTemplate=dialog.GetCommandTemplate();
|
|
|
|
this->Ui->commandTemplates->addItem(commandName,commandTemplate);
|
|
|
|
|
|
int itemId=this->Ui->commandTemplates->count()-1;
|
|
this->Ui->commandTemplates->setCurrentIndex(itemId);
|
|
|
|
this->UpdateCommandPreview();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqRemoteCommandDialog::DeleteCommandTemplate()
|
|
{
|
|
int idx=this->Ui->commandTemplates->currentIndex();
|
|
this->Ui->commandTemplates->removeItem(idx);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqRemoteCommandDialog::EditCommandTemplate()
|
|
{
|
|
int itemId=this->Ui->commandTemplates->currentIndex();
|
|
QString commandName=this->Ui->commandTemplates->itemText(itemId);
|
|
QString commandTemplate=this->Ui->commandTemplates->itemData(itemId).toString();
|
|
|
|
pqRemoteCommandTemplateDialog dialog(this,0);
|
|
dialog.SetCommandName(commandName);
|
|
dialog.SetCommandTemplate(commandTemplate);
|
|
|
|
if ((dialog.exec()==QDialog::Accepted) && dialog.GetModified())
|
|
{
|
|
commandName=dialog.GetCommandName();
|
|
commandTemplate=dialog.GetCommandTemplate();
|
|
|
|
this->Ui->commandTemplates->setItemText(itemId,commandName);
|
|
this->Ui->commandTemplates->setItemData(itemId,commandTemplate);
|
|
|
|
this->UpdateCommandPreview();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqRemoteCommandDialog::UpdateTokenValues()
|
|
{
|
|
this->TokenValues[TERM_EXEC]
|
|
= (const char *)this->Ui->xtExec->text().toLatin1();
|
|
|
|
this->TokenValues[TERM_OPTS]
|
|
= (const char *)this->Ui->xtOpts->text().toLatin1();
|
|
|
|
this->TokenValues[SSH_EXEC]
|
|
= (const char *)this->Ui->sshExec->text().toLatin1();
|
|
|
|
this->TokenValues[PV_HOST]
|
|
= (const char *)this->Ui->pvHost->text().toLatin1();
|
|
|
|
this->TokenValues[FE_URL]
|
|
= (const char *)this->Ui->feUrl->text().toLatin1();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void pqRemoteCommandDialog::UpdateForm()
|
|
{
|
|
// this would enable or disable the various field depending
|
|
// on whether or not the token is used in the current command
|
|
// template. however, it may be confusing to users as to when
|
|
// they should change field values, so leaving them active
|
|
// all the time is probably the best thing to do.
|
|
/*
|
|
string command
|
|
= (const char*)this->Ui->commandTemplates->currentText().toLatin1();
|
|
|
|
int nWidgets = this->TokenWidgets.size();
|
|
for (int i=0; i<nWidgets; ++i)
|
|
{
|
|
if (command.find(this->Tokens[i])!=string::npos)
|
|
{
|
|
this->TokenWidgets[i]->setEnabled(true);
|
|
}
|
|
else
|
|
{
|
|
this->TokenWidgets[i]->setEnabled(false);
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
string pqRemoteCommandDialog::GetCommand()
|
|
{
|
|
string command
|
|
= (const char*)this->Ui->commandTemplates->itemData(
|
|
this->Ui->commandTemplates->currentIndex()).toString().toLatin1();
|
|
|
|
size_t nTokens = this->TokenValues.size();
|
|
for (size_t i=0; i<nTokens; ++i)
|
|
{
|
|
::searchAndReplace(
|
|
this->Tokens[i],
|
|
this->TokenValues[i],
|
|
command);
|
|
}
|
|
|
|
return command;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void pqRemoteCommandDialog::UpdateCommandPreview()
|
|
{
|
|
string command=this->GetCommand();
|
|
this->Ui->previewCommand->setText(command.c_str());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void pqRemoteCommandDialog::FindSshExecutable()
|
|
{
|
|
string exe=this->LocateFile();
|
|
this->Ui->sshExec->setText(exe.c_str());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void pqRemoteCommandDialog::FindXTermExecutable()
|
|
{
|
|
string exe=this->LocateFile();
|
|
this->Ui->xtExec->setText(exe.c_str());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
string pqRemoteCommandDialog::LocateFile()
|
|
{
|
|
QString filters=QString("All Files (*)");
|
|
|
|
pqFileDialog dialog(0,this,"Find file","",filters);
|
|
dialog.setFileMode(pqFileDialog::ExistingFile);
|
|
|
|
if (dialog.exec()==QDialog::Accepted)
|
|
{
|
|
string filename((const char *)dialog.getSelectedFiles()[0].toLatin1());
|
|
// escape whitespace
|
|
::searchAndReplace(" ","^",filename);
|
|
return filename;
|
|
}
|
|
|
|
return "";
|
|
}
|