AdaptixC2-Mod0/Source/UI/Widgets/SessionsTableWidget.cpp
2026-04-06 00:20:51 -05:00

812 lines
29 KiB
C++

#include <Agent/Agent.h>
#include <UI/Widgets/SessionsTableWidget.h>
#include <UI/Widgets/BrowserFilesWidget.h>
#include <UI/Widgets/BrowserProcessWidget.h>
#include <UI/Widgets/ConsoleWidget.h>
#include <UI/Widgets/TerminalContainerWidget.h>
#include <UI/Widgets/AdaptixWidget.h>
#include <UI/Widgets/TasksWidget.h>
#include <UI/Widgets/DockWidgetRegister.h>
#include <UI/Dialogs/DialogTunnel.h>
#include <UI/Dialogs/DialogAgentData.h>
#include <Client/AxScript/AxScriptManager.h>
#include <Client/Requestor.h>
#include <Client/Settings.h>
#include <Client/TunnelEndpoint.h>
#include <Client/AuthProfile.h>
#include <MainAdaptix.h>
REGISTER_DOCK_WIDGET(SessionsTableWidget, "Sessions", true)
SessionsTableWidget::SessionsTableWidget( AdaptixWidget* w ) : DockTab("Sessions table", w->GetProfile()->GetProject(), ":/icons/format_list")
{
this->adaptixWidget = w;
this->createUI();
connect( tableView, &QTableView::doubleClicked, this, &SessionsTableWidget::handleTableDoubleClicked );
connect( tableView, &QTableView::customContextMenuRequested, this, &SessionsTableWidget::handleSessionsTableMenu );
connect(tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this](const QItemSelection &selected, const QItemSelection &deselected){
Q_UNUSED(selected)
Q_UNUSED(deselected)
if (!inputFilter->hasFocus())
tableView->setFocus();
});
connect(inputFilter, &QLineEdit::textChanged, this, &SessionsTableWidget::onFilterChanged);
connect(inputFilter, &QLineEdit::returnPressed, this, [this]() { proxyModel->setTextFilter(inputFilter->text()); });
connect(comboAgentType, &QComboBox::currentTextChanged, this, &SessionsTableWidget::onFilterChanged);
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
connect(checkOnlyActive, &QCheckBox::checkStateChanged, this, &SessionsTableWidget::onFilterChanged);
#else
connect(checkOnlyActive, &QCheckBox::stateChanged, this, &SessionsTableWidget::onFilterChanged);
#endif
connect(hideButton, &ClickableLabel::clicked, this, &SessionsTableWidget::toggleSearchPanel);
shortcutSearch = new QShortcut(QKeySequence("Ctrl+F"), this);
shortcutSearch->setContext(Qt::WidgetWithChildrenShortcut);
connect(shortcutSearch, &QShortcut::activated, this, &SessionsTableWidget::toggleSearchPanel);
auto shortcutEsc = new QShortcut(QKeySequence(Qt::Key_Escape), inputFilter);
shortcutEsc->setContext(Qt::WidgetShortcut);
connect(shortcutEsc, &QShortcut::activated, this, [this]() { searchWidget->setVisible(false); });
this->dockWidget->setWidget(this);
}
SessionsTableWidget::~SessionsTableWidget() = default;
void SessionsTableWidget::SetUpdatesEnabled(const bool enabled)
{
if (!enabled) {
bufferingEnabled = true;
} else {
bufferingEnabled = false;
flushPendingAgents();
}
if (proxyModel)
proxyModel->setDynamicSortFilter(enabled);
if (tableView)
tableView->setSortingEnabled(enabled);
tableView->setUpdatesEnabled(enabled);
}
void SessionsTableWidget::flushPendingAgents()
{
if (pendingAgents.isEmpty())
return;
QStringList ids;
{
QReadLocker locker(&adaptixWidget->AgentsMapLock);
for (Agent* agent : pendingAgents) {
if (adaptixWidget->AgentsMap.contains(agent->data.Id))
ids.append(agent->data.Id);
}
}
if (!ids.isEmpty())
agentsModel->add(ids);
pendingAgents.clear();
}
void SessionsTableWidget::createUI()
{
auto horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
searchWidget = new QWidget(this);
searchWidget->setVisible(false);
inputFilter = new QLineEdit(searchWidget);
inputFilter->setPlaceholderText("filter: (admin | root) & ^(test)");
inputFilter->setMaximumWidth(300);
autoSearchCheck = new QCheckBox("auto", searchWidget);
autoSearchCheck->setChecked(true);
autoSearchCheck->setToolTip("Auto search on text change. If unchecked, press Enter to search.");
comboAgentType = new QComboBox(searchWidget);
comboAgentType->setMinimumWidth(150);
comboAgentType->addItem("All types");
checkOnlyActive = new QCheckBox("only active", searchWidget);
hideButton = new ClickableLabel(" x ");
hideButton->setCursor(Qt::PointingHandCursor);
searchLayout = new QHBoxLayout(searchWidget);
searchLayout->setContentsMargins(0, 4, 0, 0);
searchLayout->setSpacing(4);
searchLayout->addWidget(inputFilter);
searchLayout->addWidget(autoSearchCheck);
searchLayout->addSpacing(8);
searchLayout->addWidget(comboAgentType);
searchLayout->addSpacing(8);
searchLayout->addWidget(checkOnlyActive);
searchLayout->addSpacing(8);
searchLayout->addWidget(hideButton);
searchLayout->addSpacerItem(horizontalSpacer);
agentsModel = new AgentsTableModel(adaptixWidget, this);
proxyModel = new AgentsFilterProxyModel(adaptixWidget, this);
proxyModel->setSourceModel(agentsModel);
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
tableView = new QTableView( this );
tableView->setModel(proxyModel);
tableView->setHorizontalHeader(new BoldHeaderView(Qt::Horizontal, tableView));
tableView->setContextMenuPolicy( Qt::CustomContextMenu );
tableView->setAutoFillBackground( false );
tableView->setShowGrid( false );
tableView->setSortingEnabled( true );
tableView->setWordWrap( false );
tableView->setCornerButtonEnabled( false );
tableView->setSelectionBehavior( QAbstractItemView::SelectRows );
tableView->setFocusPolicy( Qt::NoFocus );
tableView->setAlternatingRowColors( true );
tableView->horizontalHeader()->setSectionResizeMode( QHeaderView::Stretch );
tableView->horizontalHeader()->setCascadingSectionResizes( true );
tableView->horizontalHeader()->setHighlightSections( false );
tableView->horizontalHeader()->setSectionsMovable( true );
tableView->horizontalHeader()->setFirstSectionMovable( false );
tableView->verticalHeader()->setVisible( false );
columnStateReady = false;
connect(tableView->horizontalHeader(), &QHeaderView::sectionMoved, this, [this](int, int) {
if (!columnStateReady)
return;
this->SaveColumnOrder();
});
auto* header = tableView->horizontalHeader();
header->setContextMenuPolicy(Qt::CustomContextMenu);
connect(header, &QWidget::customContextMenuRequested, this, [this, header](const QPoint &pos) {
const int logical = header->logicalIndexAt(pos);
if (logical < 0 || logical >= SC_ColumnCount)
return;
QMenu menu(this);
QAction* actAutoFit = menu.addAction("Auto fit this column");
QAction* chosen = menu.exec(header->mapToGlobal(pos));
if (chosen == actAutoFit)
this->AutoFitColumnToContents(logical);
});
tableView->sortByColumn(SC_Created, Qt::AscendingOrder);
tableView->setItemDelegate(new PaddingDelegate(tableView));
this->UpdateColumnsVisible();
this->RestoreColumnState();
QTimer::singleShot(0, this, [this]() {
columnStateReady = true;
});
mainGridLayout = new QGridLayout( this );
mainGridLayout->setContentsMargins( 0, 0, 0, 0);
mainGridLayout->addWidget( searchWidget, 0, 0, 1, 1);
mainGridLayout->addWidget( tableView, 1, 0, 1, 1);
}
void SessionsTableWidget::AddAgentItem( Agent* newAgent )
{
if (bufferingEnabled) {
pendingAgents.append(newAgent);
return;
}
agentsModel->add(newAgent->data.Id);
if (adaptixWidget->IsSynchronized())
this->UpdateColumnsSize();
}
void SessionsTableWidget::UpdateAgentItem(const AgentData &oldDatam, const Agent* agent) const
{
agentsModel->update(agent->data.Id);
if (oldDatam.Username != agent->data.Username || oldDatam.Impersonated != agent->data.Impersonated )
this->UpdateColumnsSize();
}
void SessionsTableWidget::RemoveAgentItem(const QString &agentId) const
{
Agent* agent = nullptr;
{
QWriteLocker locker(&adaptixWidget->AgentsMapLock);
if (!adaptixWidget->AgentsMap.contains(agentId))
return;
agent = adaptixWidget->AgentsMap[agentId];
adaptixWidget->AgentsMap.remove(agentId);
}
delete agent;
agentsModel->remove(agentId);
}
void SessionsTableWidget::UpdateColumnsVisible() const
{
for (int i = 0; i < SC_ColumnCount; i++) {
if (GlobalClient->settings->data.SessionsTableColumns[i])
tableView->showColumn(i);
else
tableView->hideColumn(i);
}
}
void SessionsTableWidget::UpdateColumnsSize() const
{
tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
tableView->horizontalHeader()->setSectionResizeMode(SC_Tags, QHeaderView::Stretch);
int wDomain = tableView->columnWidth(SC_Domain);
int wComputer = tableView->columnWidth(SC_Computer);
int wUser = tableView->columnWidth(SC_User);
int wOs = tableView->columnWidth(SC_Os);
int wProcess = tableView->columnWidth(SC_Process);
tableView->horizontalHeader()->setSectionResizeMode(SC_Domain, QHeaderView::Interactive);
tableView->horizontalHeader()->setSectionResizeMode(SC_Computer, QHeaderView::Interactive);
tableView->horizontalHeader()->setSectionResizeMode(SC_User, QHeaderView::Interactive);
tableView->horizontalHeader()->setSectionResizeMode(SC_Os, QHeaderView::Interactive);
tableView->horizontalHeader()->setSectionResizeMode(SC_Process, QHeaderView::Interactive);
tableView->setColumnWidth(SC_Domain, wDomain);
tableView->setColumnWidth(SC_Computer, wComputer);
tableView->setColumnWidth(SC_User, wUser);
tableView->setColumnWidth(SC_Os, wOs);
tableView->setColumnWidth(SC_Process, wProcess);
}
void SessionsTableWidget::UpdateData() const
{
auto f = qobject_cast<AgentsFilterProxyModel*>(proxyModel);
f->updateVisible();
}
void SessionsTableWidget::UpdateAgentTypeComboBox() const
{
QSet<QString> types;
{
QReadLocker locker(&adaptixWidget->AgentsMapLock);
for (const auto& agent : adaptixWidget->AgentsMap) {
if (agent && !agent->data.Name.isEmpty())
types.insert(agent->data.Name);
}
}
QString currentType = comboAgentType->currentText();
comboAgentType->blockSignals(true);
comboAgentType->clear();
comboAgentType->addItem("All types");
QStringList typeList = types.values();
typeList.sort();
comboAgentType->addItems(typeList);
int idx = comboAgentType->findText(currentType);
if (idx >= 0)
comboAgentType->setCurrentIndex(idx);
comboAgentType->blockSignals(false);
}
void SessionsTableWidget::Clear() const
{
QList<Agent*> toDelete;
{
QWriteLocker locker(&adaptixWidget->AgentsMapLock);
toDelete = adaptixWidget->AgentsMap.values();
adaptixWidget->AgentsMap.clear();
}
qDeleteAll(toDelete);
agentsModel->clear();
checkOnlyActive->setChecked(false);
inputFilter->clear();
comboAgentType->clear();
comboAgentType->addItem("All types");
}
/// SLOTS
void SessionsTableWidget::toggleSearchPanel() const
{
if (this->searchWidget->isVisible()) {
this->searchWidget->setVisible(false);
proxyModel->setSearchVisible(false);
}
else {
this->searchWidget->setVisible(true);
proxyModel->setSearchVisible(true);
inputFilter->setFocus();
}
}
void SessionsTableWidget::handleTableDoubleClicked(const QModelIndex &index) const
{
auto idx = tableView->currentIndex();
if (!idx.isValid())
return;
QString AgentId = proxyModel->index(idx.row(), SC_AgentID).data().toString();
if (AgentId.isEmpty())
return;
adaptixWidget->LoadConsoleUI(AgentId);
}
void SessionsTableWidget::onFilterChanged() const
{
if (autoSearchCheck->isChecked()) {
proxyModel->setTextFilter(inputFilter->text());
}
proxyModel->setOnlyActive(checkOnlyActive->isChecked());
QSet<QString> selectedTypes;
QString currentType = comboAgentType->currentText();
if (currentType != "All types" && !currentType.isEmpty()) {
selectedTypes.insert(currentType);
}
proxyModel->setAgentTypes(selectedTypes);
}
/// Menu
void SessionsTableWidget::handleSessionsTableMenu(const QPoint &pos)
{
QMenu ctxMenu;
QModelIndex index = tableView->indexAt(pos);
if (index.isValid()) {
QStringList agentIds;
QModelIndexList selectedRows = tableView->selectionModel()->selectedRows();
for (const QModelIndex &proxyIndex : selectedRows) {
QModelIndex sourceIndex = proxyModel->mapToSource(proxyIndex);
if (!sourceIndex.isValid()) continue;
QString agentId = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_AgentID), Qt::DisplayRole).toString();
agentIds.append(agentId);
}
auto agentMenu = ctxMenu.addMenu("Agent");
agentMenu->addAction("Execute command", this, &SessionsTableWidget::actionExecuteCommand);
agentMenu->addAction("Task manager", this, &SessionsTableWidget::actionTasksBrowserOpen);
agentMenu->addSeparator();
int agentCount = adaptixWidget->ScriptManager->AddMenuSession(agentMenu, "SessionAgent", agentIds);
if (agentCount > 0)
agentMenu->addSeparator();
agentMenu->addAction("Remove console data", this, &SessionsTableWidget::actionConsoleDelete);
agentMenu->addAction("Remove from server", this, &SessionsTableWidget::actionAgentRemove);
auto sessionMenu = ctxMenu.addMenu("Session");
sessionMenu->addAction("Mark as Active", this, &SessionsTableWidget::actionMarkActive);
sessionMenu->addAction("Mark as Inactive", this, &SessionsTableWidget::actionMarkInactive);
sessionMenu->addSeparator();
if ( agentIds.size() == 1 )
sessionMenu->addAction("Set data", this, &SessionsTableWidget::actionSetData);
sessionMenu->addAction("Set tag", this, &SessionsTableWidget::actionItemTag);
sessionMenu->addSeparator();
sessionMenu->addAction("Set items color", this, &SessionsTableWidget::actionItemColor);
sessionMenu->addAction("Set text color", this, &SessionsTableWidget::actionTextColor);
sessionMenu->addAction("Reset color", this, &SessionsTableWidget::actionColorReset);
sessionMenu->addSeparator();
sessionMenu->addAction("Hide on client", this, &SessionsTableWidget::actionItemHide);
ctxMenu.addAction("Console", this, &SessionsTableWidget::actionConsoleOpen);
ctxMenu.addSeparator();
ctxMenu.addMenu(agentMenu);
auto browserMenu = ctxMenu.addMenu("Browsers");
int browserCount = adaptixWidget->ScriptManager->AddMenuSession(browserMenu, "SessionBrowser", agentIds);
if (browserCount > 0)
ctxMenu.addMenu(browserMenu);
else
ctxMenu.removeAction(browserMenu->menuAction());
auto accessMenu = ctxMenu.addMenu("Access");
int accessCount = adaptixWidget->ScriptManager->AddMenuSession(accessMenu, "SessionAccess", agentIds);
if (accessCount > 0)
ctxMenu.addMenu(accessMenu);
else
ctxMenu.removeAction(accessMenu->menuAction());
adaptixWidget->ScriptManager->AddMenuSession(&ctxMenu, "SessionMain", agentIds);
ctxMenu.addSeparator();
ctxMenu.addMenu(sessionMenu);
}
ctxMenu.addAction("Show all items", this, &SessionsTableWidget::actionItemsShowAll);
ctxMenu.exec(tableView->viewport()->mapToGlobal(pos));
}
void SessionsTableWidget::actionConsoleOpen() const
{
QModelIndexList selectedRows = tableView->selectionModel()->selectedRows();
for (const QModelIndex &proxyIndex : selectedRows) {
QModelIndex sourceIndex = proxyModel->mapToSource(proxyIndex);
if (!sourceIndex.isValid()) continue;
QString agentId = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_AgentID), Qt::DisplayRole).toString();
adaptixWidget->LoadConsoleUI(agentId);
}
}
void SessionsTableWidget::actionExecuteCommand()
{
QStringList listId;
QModelIndexList selectedRows = tableView->selectionModel()->selectedRows();
for (const QModelIndex &proxyIndex : selectedRows) {
QModelIndex sourceIndex = proxyModel->mapToSource(proxyIndex);
if (!sourceIndex.isValid()) continue;
QString agentId = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_AgentID), Qt::DisplayRole).toString();
listId.append(agentId);
}
if(listId.empty())
return;
bool ok = false;
QString cmd = QInputDialog::getText(this,"Execute Command", "Command", QLineEdit::Normal, "", &ok);
if (!ok)
return;
QReadLocker locker(&adaptixWidget->AgentsMapLock);
for(auto id : listId) {
if (adaptixWidget->AgentsMap.contains(id)) {
adaptixWidget->AgentsMap[id]->Console->SetInput(cmd);
adaptixWidget->AgentsMap[id]->Console->processInput();
}
}
}
void SessionsTableWidget::actionTasksBrowserOpen() const
{
auto idx = tableView->currentIndex();
if (idx.isValid()) {
QString agentId = proxyModel->index(idx.row(), SC_AgentID).data().toString();
adaptixWidget->TasksDock->SetAgentFilter(agentId);
adaptixWidget->SetTasksUI();
}
}
void SessionsTableWidget::actionMarkActive() const
{
QStringList listId;
QModelIndexList selectedRows = tableView->selectionModel()->selectedRows();
for (const QModelIndex &proxyIndex : selectedRows) {
QModelIndex sourceIndex = proxyModel->mapToSource(proxyIndex);
if (!sourceIndex.isValid()) continue;
QString agentId = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_AgentID), Qt::DisplayRole).toString();
listId.append(agentId);
}
if(listId.empty())
return;
HttpReqAgentSetMarkAsync(listId, "", *(adaptixWidget->GetProfile()), [](bool success, const QString& message, const QJsonObject&) {
if (!success)
MessageError(message.isEmpty() ? "Response timeout" : message);
});
}
void SessionsTableWidget::actionMarkInactive() const
{
QStringList listId;
QModelIndexList selectedRows = tableView->selectionModel()->selectedRows();
for (const QModelIndex &proxyIndex : selectedRows) {
QModelIndex sourceIndex = proxyModel->mapToSource(proxyIndex);
if (!sourceIndex.isValid()) continue;
QString agentId = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_AgentID), Qt::DisplayRole).toString();
listId.append(agentId);
}
if(listId.empty())
return;
HttpReqAgentSetMarkAsync(listId, "Inactive", *(adaptixWidget->GetProfile()), [](bool success, const QString& message, const QJsonObject&) {
if (!success)
MessageError(message.isEmpty() ? "Response timeout" : message);
});
}
void SessionsTableWidget::actionItemColor() const
{
QStringList listId;
QModelIndexList selectedRows = tableView->selectionModel()->selectedRows();
for (const QModelIndex &proxyIndex : selectedRows) {
QModelIndex sourceIndex = proxyModel->mapToSource(proxyIndex);
if (!sourceIndex.isValid()) continue;
QString agentId = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_AgentID), Qt::DisplayRole).toString();
listId.append(agentId);
}
if(listId.empty())
return;
QColor itemColor = QColorDialog::getColor(Qt::white, nullptr, "Select items color");
if (itemColor.isValid()) {
QString itemColorHex = itemColor.name();
HttpReqAgentSetColorAsync(listId, itemColorHex, "", false, *(adaptixWidget->GetProfile()), [](bool success, const QString& message, const QJsonObject&) {
if (!success)
MessageError(message.isEmpty() ? "Response timeout" : message);
});
}
}
void SessionsTableWidget::actionTextColor() const
{
QStringList listId;
QModelIndexList selectedRows = tableView->selectionModel()->selectedRows();
for (const QModelIndex &proxyIndex : selectedRows) {
QModelIndex sourceIndex = proxyModel->mapToSource(proxyIndex);
if (!sourceIndex.isValid()) continue;
QString agentId = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_AgentID), Qt::DisplayRole).toString();
listId.append(agentId);
}
if(listId.empty())
return;
QColor textColor = QColorDialog::getColor(Qt::white, nullptr, "Select text color");
if (textColor.isValid()) {
QString textColorHex = textColor.name();
HttpReqAgentSetColorAsync(listId, "", textColorHex, false, *(adaptixWidget->GetProfile()), [](bool success, const QString& message, const QJsonObject&) {
if (!success)
MessageError(message.isEmpty() ? "Response timeout" : message);
});
}
}
void SessionsTableWidget::actionColorReset() const
{
QStringList listId;
QModelIndexList selectedRows = tableView->selectionModel()->selectedRows();
for (const QModelIndex &proxyIndex : selectedRows) {
QModelIndex sourceIndex = proxyModel->mapToSource(proxyIndex);
if (!sourceIndex.isValid()) continue;
QString agentId = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_AgentID), Qt::DisplayRole).toString();
listId.append(agentId);
}
if(listId.empty())
return;
HttpReqAgentSetColorAsync(listId, "", "", true, *(adaptixWidget->GetProfile()), [](bool success, const QString& message, const QJsonObject&) {
if (!success)
MessageError(message.isEmpty() ? "Response timeout" : message);
});
}
void SessionsTableWidget::actionConsoleDelete()
{
QMessageBox::StandardButton reply = QMessageBox::question(this, "Clear Confirmation",
"Are you sure you want to delete all agent console data and history from server (tasks will not be deleted from TaskManager)?\n\n"
"If you want to temporarily hide the contents of the agent console, do so through the agent console menu.",
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No);
if (reply != QMessageBox::Yes)
return;
QStringList listId;
QModelIndexList selectedRows = tableView->selectionModel()->selectedRows();
for (const QModelIndex &proxyIndex : selectedRows) {
QModelIndex sourceIndex = proxyModel->mapToSource(proxyIndex);
if (!sourceIndex.isValid()) continue;
QString agentId = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_AgentID), Qt::DisplayRole).toString();
listId.append(agentId);
}
if(listId.empty())
return;
{
QReadLocker locker(&adaptixWidget->AgentsMapLock);
for (auto id : listId) {
if (adaptixWidget->AgentsMap.contains(id))
adaptixWidget->AgentsMap[id]->Console->Clear();
}
}
HttpReqConsoleRemoveAsync(listId, *(adaptixWidget->GetProfile()), [](bool success, const QString& message, const QJsonObject&) {
if (!success)
MessageError(message.isEmpty() ? "Response timeout" : message);
});
}
void SessionsTableWidget::actionAgentRemove()
{
QMessageBox::StandardButton reply = QMessageBox::question(this, "Delete Confirmation",
"Are you sure you want to delete all information about the selected agents from the server?\n\n"
"If you want to hide the record, simply choose: 'Item -> Hide on Client'.",
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No);
if (reply != QMessageBox::Yes)
return;
QStringList listId;
QModelIndexList selectedRows = tableView->selectionModel()->selectedRows();
for (const QModelIndex &proxyIndex : selectedRows) {
QModelIndex sourceIndex = proxyModel->mapToSource(proxyIndex);
if (!sourceIndex.isValid()) continue;
QString agentId = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_AgentID), Qt::DisplayRole).toString();
listId.append(agentId);
}
if(listId.empty())
return;
HttpReqAgentRemoveAsync(listId, *(adaptixWidget->GetProfile()), [](bool success, const QString& message, const QJsonObject&) {
if (!success)
MessageError(message.isEmpty() ? "Response timeout" : message);
});
}
void SessionsTableWidget::actionItemTag() const
{
QString tag = "";
QStringList listId;
QModelIndexList selectedRows = tableView->selectionModel()->selectedRows();
for (const QModelIndex &proxyIndex : selectedRows) {
QModelIndex sourceIndex = proxyModel->mapToSource(proxyIndex);
if (!sourceIndex.isValid()) continue;
QString cTag = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_Tags), Qt::DisplayRole).toString();
QString agentId = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_AgentID), Qt::DisplayRole).toString();
listId.append(agentId);
if (tag.isEmpty())
tag = cTag;
}
if(listId.empty())
return;
bool inputOk;
QString newTag = QInputDialog::getText(nullptr, "Set tags", "New tag", QLineEdit::Normal,tag, &inputOk);
if ( inputOk ) {
HttpReqAgentSetTagAsync(listId, newTag, *(adaptixWidget->GetProfile()), [](bool success, const QString& message, const QJsonObject&) {
if (!success)
MessageError(message.isEmpty() ? "Response timeout" : message);
});
}
}
void SessionsTableWidget::actionItemHide() const
{
bool refact = false;
QModelIndexList selectedRows = tableView->selectionModel()->selectedRows();
QReadLocker locker(&adaptixWidget->AgentsMapLock);
for (const QModelIndex &proxyIndex : selectedRows) {
QModelIndex sourceIndex = proxyModel->mapToSource(proxyIndex);
if (!sourceIndex.isValid()) continue;
QString agentId = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_AgentID), Qt::DisplayRole).toString();
if (adaptixWidget->AgentsMap.contains(agentId)) {
adaptixWidget->AgentsMap[agentId]->show = false;
refact = true;
}
}
locker.unlock();
if (refact) this->UpdateData();
}
void SessionsTableWidget::actionItemsShowAll() const
{
bool refact = false;
{
QReadLocker locker(&adaptixWidget->AgentsMapLock);
for (auto agent : adaptixWidget->AgentsMap) {
if (agent->show == false) {
agent->show = true;
refact = true;
}
}
}
if (refact) this->UpdateData();
}
void SessionsTableWidget::actionSetData() const
{
auto idx = tableView->currentIndex();
if (!idx.isValid())
return;
QModelIndex sourceIndex = proxyModel->mapToSource(idx);
if (!sourceIndex.isValid())
return;
QString agentId = agentsModel->data(agentsModel->index(sourceIndex.row(), SC_AgentID), Qt::DisplayRole).toString();
AgentData agentData;
{
QReadLocker locker(&adaptixWidget->AgentsMapLock);
if (!adaptixWidget->AgentsMap.contains(agentId))
return;
agentData = adaptixWidget->AgentsMap[agentId]->data;
}
auto* dialog = new DialogAgentData();
dialog->SetProfile(*(adaptixWidget->GetProfile()));
dialog->SetAgentData(agentData);
dialog->Start();
}
void SessionsTableWidget::RestoreColumnState() const
{
QHeaderView* header = tableView->horizontalHeader();
for (int logicalIndex = 0; logicalIndex < SC_ColumnCount; logicalIndex++) {
int savedVisualIndex = GlobalClient->settings->data.SessionsColumnOrder[logicalIndex];
if (savedVisualIndex >= 0 && savedVisualIndex < SC_ColumnCount) {
int currentVisualIndex = header->visualIndex(logicalIndex);
if (currentVisualIndex != savedVisualIndex) {
header->moveSection(currentVisualIndex, savedVisualIndex);
}
}
}
}
void SessionsTableWidget::SaveColumnOrder() const
{
QHeaderView* header = tableView->horizontalHeader();
for (int logicalIndex = 0; logicalIndex < SC_ColumnCount; logicalIndex++) {
GlobalClient->settings->data.SessionsColumnOrder[logicalIndex] = header->visualIndex(logicalIndex);
}
GlobalClient->settings->SaveToDB();
}
void SessionsTableWidget::AutoFitColumnToContents(const int logicalIndex) const
{
if (!tableView || !proxyModel)
return;
if (logicalIndex < 0 || logicalIndex >= SC_ColumnCount)
return;
if (tableView->isColumnHidden(logicalIndex))
return;
const int rowCount = proxyModel->rowCount();
int maxWidth = 0;
for (int row = 0; row < rowCount; row++) {
const QModelIndex idx = proxyModel->index(row, logicalIndex);
if (!idx.isValid())
continue;
const QSize hint = tableView->sizeHintForIndex(idx);
maxWidth = qMax(maxWidth, hint.width());
}
maxWidth += 24;
if (maxWidth < 50)
maxWidth = 50;
tableView->horizontalHeader()->setSectionResizeMode(logicalIndex, QHeaderView::Interactive);
tableView->setColumnWidth(logicalIndex, maxWidth);
}