Cmdr/src/cmd_line.cpp
Maurice ONeal fb4d0bed87 Added Windows Build/Install Support
linux_build.sh is now replaced by the build.py and install.py Python
scripts. with this comes cross platform build/install support
between Windows and Linux.

as of v4.x.2.x of the MRCI protocol, the TEXT type id is now
formatted in UTF8 instead of UTF16LE unicode. this change also
affected the tcp rev and several async commands so client code had
to be ajusted accordingly.
2020-08-09 17:22:31 -04:00

295 lines
6.7 KiB
C++

#include "cmd_line.h"
// This file is part of Cmdr.
// Cmdr 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.
// Cmdr 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 Cmdr under the LICENSE.md file. If not, see
// <http://www.gnu.org/licenses/>.
CmdLine::CmdLine(QWidget *parent) : QComboBox(parent)
{
localData = Shared::localData;
flags = 0;
setEditable(true);
setDuplicatesEnabled(true);
loadTheme(localData, this);
if (!localData->contains("command_hist"))
{
localData->insert("command_hist", QJsonArray());
}
if (!localData->contains("hist_limit"))
{
localData->insert("hist_limit", DEFAULT_HIST_LIMIT);
}
saveLocalData(localData);
syncHistFromFile();
connect(lineEdit(), SIGNAL(selectionChanged()), this, SLOT(selectionCheck()));
connect(lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(hideText(QString)));
connect(lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(checkForHistReset(QString)));
}
void CmdLine::cacheTxt(quint8 typeId, QString txt)
{
Shared::cacheTxt(Shared::TXT_IN, typeId, txt);
if (!(*Shared::activeDisp))
{
emit txtInCache();
}
}
void CmdLine::setFlags(int flgs)
{
flags |= flgs;
}
void CmdLine::unsetFlags(int flgs)
{
flags &= ~flgs;
}
void CmdLine::selectionCheck()
{
if (flags & HIDDEN) lineEdit()->deselect();
}
void CmdLine::hideText(const QString &txt)
{
if (flags & HIDDEN)
{
int currentPos = lineEdit()->cursorPosition();
if (txt.size() > hiddenText.size())
{
int len = txt.size() - hiddenText.size();
hiddenText.insert(currentPos - len, txt.mid(currentPos - len, len));
lineEdit()->setText(QString(hiddenText.size(), '#'));
}
else if (hiddenText.size() > txt.size())
{
int len = hiddenText.size() - txt.size();
hiddenText.remove(currentPos, len);
}
lineEdit()->setCursorPosition(currentPos);
}
}
void CmdLine::checkForHistReset(const QString &txt)
{
if (txt.isEmpty()) setCurrentIndex(-1);
}
QString CmdLine::cmdNameOnly(const QString &line)
{
QString ret = line;
int pos = line.indexOf(" ");
if (pos != -1)
{
ret = line.left(pos);
}
return ret.toLower();
}
void CmdLine::echo(const QString &line)
{
if (!line.trimmed().isEmpty())
{
cacheTxt(TEXT, line + "\n\n");
}
}
void CmdLine::clearHist()
{
localData->insert("command_hist", QJsonArray());
saveLocalData(localData);
clear();
lineEdit()->clear();
}
void CmdLine::syncHistToFile()
{
QJsonArray hist;
for (int i = 0; i < count(); ++i)
{
hist.append(itemData(i, Qt::DisplayRole).toString());
}
localData->insert("command_hist", hist);
saveLocalData(localData);
}
void CmdLine::syncHistFromFile()
{
clear();
QJsonArray hist = localData->value("command_hist").toArray();
for (auto item : hist)
{
addItem(item.toString());
}
setCurrentIndex(-1);
setInsertPolicy(QComboBox::InsertAtTop);
lineEdit()->clear();
}
void CmdLine::toHost(const QString &cmdName, const QString &args)
{
if (flags & HOST_HOOK)
{
emit dataToHookedHost(args.toUtf8(), TEXT);
}
else if (!cmdName.isEmpty())
{
quint16 cmdId = Shared::hostCmds->key(cmdName);
if (!Shared::hostCmds->values().contains(cmdName))
{
cacheTxt(ERR, "err: No such command: " + cmdName + "\n\n");
}
else if (Shared::genfileCmds->contains(cmdId))
{
emit setHostCmdId(cmdId);
emit setGenfileType(Shared::genfileTypes->value(cmdId));
emit dataToGenFile(args.toUtf8());
}
else
{
emit dataToHost(cmdId, args.toUtf8(), TEXT);
}
}
}
void CmdLine::toLocalCmd(const QString &cmdName, const QString &args)
{
if (flags & LOCAL_HOOK)
{
emit dataToHookedCmdObj(args);
}
else
{
emit dataToCommandObj(cmdName, args);
}
}
void CmdLine::procCmdLine(const QString &line)
{
QString cmdName;
QString argsLine;
if (!(flags & (GEN_HOOK | HOST_HOOK | LOCAL_HOOK)))
{
cmdName = cmdNameOnly(line.trimmed());
argsLine = line.trimmed().mid(cmdName.size() + 1);
}
else if (Shared::hookBypass->contains(cmdNameOnly(line), Qt::CaseInsensitive))
{
cmdName = cmdNameOnly(line.trimmed());
argsLine = line.trimmed().mid(cmdName.size() + 1);
}
else if (flags & HIDDEN)
{
argsLine = hiddenText;
}
else
{
argsLine = line.trimmed();
}
if (flags & GEN_HOOK)
{
emit dataToGenFile(argsLine.toUtf8());
}
else if (Shared::clientCmds->contains(cmdName))
{
toLocalCmd(cmdName, argsLine);
}
else
{
toHost(cmdName, argsLine);
}
}
void CmdLine::contextMenuEvent(QContextMenuEvent *event)
{
QMenu *menu = lineEdit()->createStandardContextMenu();
menu->addAction("Clear History", this, SLOT(clearHist()));
menu->exec(event->globalPos());
menu->deleteLater();
}
void CmdLine::duplicateScan(const QString &txt)
{
// this will remove any duplicates in the command line history, skipping over 1st line.
// why not setDuplicatesEnabled(false)? the problem with that is it does an "inplace
// replace" which means the duplicate item does not move from its position on the list
// when inserted. i want this app to "float the duplicate to the top" when inserted
// hence why i created this function.
if (!(flags & HIDDEN))
{
for (int i = 1; i < count(); ++i)
{
if (itemText(i) == txt)
{
removeItem(i);
}
}
}
}
void CmdLine::keyReleaseEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Return)
{
echo(lineEdit()->text());
procCmdLine(lineEdit()->text());
duplicateScan(lineEdit()->text());
if (flags & HIDDEN)
{
removeItem(0);
unsetFlags(HIDDEN);
hiddenText.clear();
}
lineEdit()->clear();
syncHistToFile();
setCurrentIndex(-1);
}
else
{
QComboBox::keyReleaseEvent(event);
}
}