mirror of
https://github.com/Adaptix-Framework/AdaptixC2
synced 2026-06-08 10:20:39 +00:00
367 lines
12 KiB
C++
367 lines
12 KiB
C++
#include <UI/Widgets/ScreenshotsWidget.h>
|
|
#include <UI/Widgets/AdaptixWidget.h>
|
|
#include <UI/Widgets/DockWidgetRegister.h>
|
|
#include <Client/Requestor.h>
|
|
#include <Client/AuthProfile.h>
|
|
#include <Utils/CustomElements.h>
|
|
#include <Utils/NonBlockingDialogs.h>
|
|
|
|
REGISTER_DOCK_WIDGET(ScreenshotsWidget, "Screenshots", true)
|
|
|
|
ImageFrame::ImageFrame(QWidget* parent) : QWidget(parent), label(new QLabel), scrollArea(new QScrollArea(this)), ctrlPressed(false), scaleFactor(1.0)
|
|
{
|
|
setFocusPolicy(Qt::StrongFocus);
|
|
|
|
label->setBackgroundRole(QPalette::Base);
|
|
label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
|
label->setScaledContents(true);
|
|
|
|
scrollArea->setBackgroundRole(QPalette::Dark);
|
|
scrollArea->setWidget(label);
|
|
scrollArea->viewport()->installEventFilter(this);
|
|
|
|
auto layout = new QVBoxLayout(this);
|
|
layout->addWidget(scrollArea);
|
|
setLayout(layout);
|
|
}
|
|
|
|
void ImageFrame::setPixmap(const QPixmap& pix)
|
|
{
|
|
originalPixmap = pix;
|
|
label->setPixmap(originalPixmap);
|
|
scaleFactor = 1.0;
|
|
resizeImage();
|
|
}
|
|
|
|
void ImageFrame::resizeImage() const
|
|
{
|
|
if (!originalPixmap.isNull()) {
|
|
label->resize(scaleFactor * originalPixmap.size());
|
|
}
|
|
}
|
|
|
|
void ImageFrame::resizeEvent(QResizeEvent* e)
|
|
{
|
|
QWidget::resizeEvent(e);
|
|
resizeImage();
|
|
}
|
|
|
|
QPixmap ImageFrame::pixmap() const
|
|
{
|
|
return originalPixmap;
|
|
}
|
|
|
|
void ImageFrame::keyPressEvent(QKeyEvent* e)
|
|
{
|
|
if (e->key() == Qt::Key_Control)
|
|
ctrlPressed = true;
|
|
QWidget::keyPressEvent(e);
|
|
}
|
|
|
|
void ImageFrame::keyReleaseEvent(QKeyEvent* e)
|
|
{
|
|
if (e->key() == Qt::Key_Control)
|
|
ctrlPressed = false;
|
|
QWidget::keyReleaseEvent(e);
|
|
}
|
|
|
|
bool ImageFrame::eventFilter(QObject* obj, QEvent* e)
|
|
{
|
|
if (obj == scrollArea->viewport() && e->type() == QEvent::Wheel) {
|
|
auto we = static_cast<QWheelEvent*>(e);
|
|
if (ctrlPressed) {
|
|
const double step = (we->angleDelta().y() > 0) ? 1.1 : 0.9;
|
|
scaleFactor *= step;
|
|
scaleFactor = std::clamp(scaleFactor, 0.3, 4.0);
|
|
resizeImage();
|
|
return true;
|
|
}
|
|
}
|
|
return QWidget::eventFilter(obj, e);
|
|
}
|
|
|
|
void ImageFrame::clear()
|
|
{
|
|
originalPixmap = QPixmap();
|
|
label->setPixmap(QPixmap());
|
|
scaleFactor = 1.0;
|
|
resizeImage();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ScreenshotsWidget::ScreenshotsWidget(AdaptixWidget* w) : DockTab("Screenshots", w->GetProfile()->GetProject(), ":/icons/picture")
|
|
{
|
|
this->adaptixWidget = w;
|
|
this->createUI();
|
|
|
|
connect(tableWidget, &QTableWidget::customContextMenuRequested, this, &ScreenshotsWidget::handleScreenshotsMenu);
|
|
connect(tableWidget->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &ScreenshotsWidget::onTableItemSelection);
|
|
connect(tableWidget, &QTableWidget::itemSelectionChanged, this, [this](){tableWidget->setFocus();});
|
|
connect(splitter, &QSplitter::splitterMoved, imageFrame, &ImageFrame::resizeImage);
|
|
|
|
this->dockWidget->setWidget(this);
|
|
}
|
|
|
|
ScreenshotsWidget::~ScreenshotsWidget() = default;
|
|
|
|
void ScreenshotsWidget::SetUpdatesEnabled(const bool enabled)
|
|
{
|
|
tableWidget->setUpdatesEnabled(enabled);
|
|
}
|
|
|
|
void ScreenshotsWidget::createUI()
|
|
{
|
|
tableWidget = new QTableWidget(this );
|
|
tableWidget->setContextMenuPolicy( Qt::CustomContextMenu );
|
|
tableWidget->setAutoFillBackground( false );
|
|
tableWidget->setShowGrid( false );
|
|
tableWidget->setSortingEnabled( true );
|
|
tableWidget->setWordWrap( true );
|
|
tableWidget->setCornerButtonEnabled( false );
|
|
tableWidget->setSelectionBehavior( QAbstractItemView::SelectRows );
|
|
tableWidget->setFocusPolicy( Qt::NoFocus );
|
|
tableWidget->setAlternatingRowColors( true );
|
|
tableWidget->horizontalHeader()->setSectionResizeMode( QHeaderView::Stretch );
|
|
tableWidget->horizontalHeader()->setCascadingSectionResizes( true );
|
|
tableWidget->horizontalHeader()->setHighlightSections( false );
|
|
tableWidget->verticalHeader()->setVisible( false );
|
|
tableWidget->setColumnCount(5);
|
|
|
|
tableWidget->setHorizontalHeaderItem( 0, new QTableWidgetItem( "ID" ) );
|
|
tableWidget->setHorizontalHeaderItem( 1, new QTableWidgetItem( "User" ) );
|
|
tableWidget->setHorizontalHeaderItem( 2, new QTableWidgetItem( "Computer" ) );
|
|
tableWidget->setHorizontalHeaderItem( 3, new QTableWidgetItem( "Note" ) );
|
|
tableWidget->setHorizontalHeaderItem( 4, new QTableWidgetItem( "Date" ) );
|
|
|
|
tableWidget->setItemDelegate(new PaddingDelegate(tableWidget));
|
|
|
|
tableWidget->hideColumn( 0 );
|
|
|
|
imageFrame = new ImageFrame(this);
|
|
|
|
splitter = new QSplitter(this);
|
|
splitter->setOrientation(Qt::Horizontal);
|
|
splitter->addWidget(tableWidget);
|
|
splitter->addWidget(imageFrame);
|
|
splitter->setSizes(QList<int>() << 80 << 200);
|
|
|
|
mainGridLayout = new QGridLayout(this );
|
|
mainGridLayout->setContentsMargins(0, 0, 0, 0 );
|
|
mainGridLayout->addWidget(splitter, 0, 0, 1, 1 );
|
|
}
|
|
|
|
void ScreenshotsWidget::Clear() const
|
|
{
|
|
adaptixWidget->Screenshots.clear();
|
|
|
|
QSignalBlocker blocker(tableWidget->selectionModel());
|
|
|
|
for (int index = tableWidget->rowCount(); index > 0; index-- )
|
|
tableWidget->removeRow(index -1 );
|
|
|
|
imageFrame->clear();
|
|
|
|
}
|
|
|
|
void ScreenshotsWidget::AddScreenshotItem(const ScreenData &newScreen) const
|
|
{
|
|
if( tableWidget->rowCount() < 1 )
|
|
tableWidget->setRowCount( 1 );
|
|
else
|
|
tableWidget->setRowCount( tableWidget->rowCount() + 1 );
|
|
|
|
auto item_ScreenId = new QTableWidgetItem( newScreen.ScreenId );
|
|
auto item_User = new QTableWidgetItem( newScreen.User );
|
|
auto item_Computer = new QTableWidgetItem( newScreen.Computer );
|
|
auto item_Note = new QTableWidgetItem( newScreen.Note );
|
|
auto item_Date = new QTableWidgetItem( newScreen.Date );
|
|
|
|
item_ScreenId->setTextAlignment( Qt::AlignCenter );
|
|
item_ScreenId->setFlags( item_ScreenId->flags() ^ Qt::ItemIsEditable );
|
|
|
|
item_User->setTextAlignment( Qt::AlignCenter );
|
|
item_User->setFlags( item_User->flags() ^ Qt::ItemIsEditable );
|
|
|
|
item_Computer->setTextAlignment( Qt::AlignCenter );
|
|
item_Computer->setFlags( item_Computer->flags() ^ Qt::ItemIsEditable );
|
|
|
|
item_Note->setTextAlignment( Qt::AlignLeft | Qt::AlignVCenter );
|
|
item_Note->setFlags( item_Note->flags() ^ Qt::ItemIsEditable );
|
|
|
|
item_Date->setTextAlignment( Qt::AlignCenter );
|
|
item_Date->setFlags( item_Date->flags() ^ Qt::ItemIsEditable );
|
|
|
|
bool isSortingEnabled = tableWidget->isSortingEnabled();
|
|
tableWidget->setSortingEnabled( false );
|
|
tableWidget->setItem( tableWidget->rowCount() - 1, 0, item_ScreenId );
|
|
tableWidget->setItem( tableWidget->rowCount() - 1, 1, item_User );
|
|
tableWidget->setItem( tableWidget->rowCount() - 1, 2, item_Computer );
|
|
tableWidget->setItem( tableWidget->rowCount() - 1, 3, item_Note );
|
|
tableWidget->setItem( tableWidget->rowCount() - 1, 4, item_Date );
|
|
tableWidget->setSortingEnabled( isSortingEnabled );
|
|
|
|
tableWidget->horizontalHeader()->setSectionResizeMode( 1, QHeaderView::ResizeToContents );
|
|
tableWidget->horizontalHeader()->setSectionResizeMode( 2, QHeaderView::ResizeToContents );
|
|
tableWidget->horizontalHeader()->setSectionResizeMode( 3, QHeaderView::ResizeToContents );
|
|
|
|
tableWidget->verticalHeader()->setSectionResizeMode(tableWidget->rowCount() - 1, QHeaderView::ResizeToContents);
|
|
|
|
adaptixWidget->Screenshots[newScreen.ScreenId] = newScreen;
|
|
}
|
|
|
|
void ScreenshotsWidget::EditScreenshotItem(const QString &screenId, const QString ¬e) const
|
|
{
|
|
if (!adaptixWidget->Screenshots.contains(screenId))
|
|
return;
|
|
|
|
adaptixWidget->Screenshots[screenId].Note = note;
|
|
|
|
for (int row = 0; row < tableWidget->rowCount(); ++row) {
|
|
QTableWidgetItem *item = tableWidget->item(row, 0);
|
|
if ( item && item->text() == screenId ) {
|
|
tableWidget->item(row, 3)->setText(note);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScreenshotsWidget::RemoveScreenshotItem(const QString &screenId) const
|
|
{
|
|
if (!adaptixWidget->Screenshots.contains(screenId))
|
|
return;
|
|
|
|
adaptixWidget->Screenshots.remove(screenId);
|
|
|
|
for ( int row = 0; row < tableWidget->rowCount(); row++ ) {
|
|
if ( tableWidget->item( row, 0 )->text() == screenId ) {
|
|
tableWidget->removeRow( row );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (tableWidget->rowCount() == 0)
|
|
imageFrame->clear();
|
|
}
|
|
|
|
/// SLOTS
|
|
|
|
void ScreenshotsWidget::handleScreenshotsMenu(const QPoint &pos )
|
|
{
|
|
if ( !tableWidget->itemAt(pos) )
|
|
return;
|
|
|
|
auto ctxMenu = QMenu();
|
|
ctxMenu.addAction("Set note", this, &ScreenshotsWidget::actionNote );
|
|
ctxMenu.addAction("Download", this, &ScreenshotsWidget::actionDownload );
|
|
ctxMenu.addAction("Delete", this, &ScreenshotsWidget::actionDelete );
|
|
|
|
ctxMenu.exec(tableWidget->horizontalHeader()->viewport()->mapToGlobal(pos ) );
|
|
}
|
|
|
|
void ScreenshotsWidget::actionNote() const
|
|
{
|
|
QStringList listId;
|
|
for( int rowIndex = 0 ; rowIndex < tableWidget->rowCount() ; rowIndex++ ) {
|
|
if ( tableWidget->item(rowIndex, 0)->isSelected() ) {
|
|
QString screenId = tableWidget->item(rowIndex, 0)->text();
|
|
listId.append(screenId);
|
|
}
|
|
}
|
|
|
|
if(listId.empty())
|
|
return;
|
|
|
|
QString note = "";
|
|
if(listId.size() == 1)
|
|
note = tableWidget->item(tableWidget->currentRow(), 3)->text();
|
|
|
|
bool inputOk;
|
|
QString newNote = QInputDialog::getText(nullptr, "Set note", "New note", QLineEdit::Normal,note, &inputOk);
|
|
if ( inputOk ) {
|
|
QString message = QString();
|
|
bool ok = false;
|
|
bool result = HttpReqScreenSetNote(listId, newNote, *(adaptixWidget->GetProfile()), &message, &ok);
|
|
if( !result ) {
|
|
MessageError("Response timeout");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScreenshotsWidget::actionDownload() const
|
|
{
|
|
if (tableWidget->selectionModel()->selectedRows().empty())
|
|
return;
|
|
|
|
QString screenId = tableWidget->item( tableWidget->currentRow(), 0 )->text();
|
|
if (!adaptixWidget->Screenshots.contains(screenId))
|
|
return;
|
|
|
|
ScreenData screenData = adaptixWidget->Screenshots[screenId];
|
|
|
|
NonBlockingDialogs::getSaveFileName(const_cast<ScreenshotsWidget*>(this), "Save File", "screenshot.png", "All Files (*.*)",
|
|
[this, screenData](const QString& filePath) {
|
|
if (filePath.isEmpty())
|
|
return;
|
|
|
|
QFile file(filePath);
|
|
if (!file.open(QIODevice::WriteOnly)) {
|
|
MessageError("Failed to open file for writing");
|
|
return;
|
|
}
|
|
|
|
file.write( screenData.Content );
|
|
file.close();
|
|
|
|
QInputDialog inputDialog;
|
|
inputDialog.setWindowTitle("Sync file");
|
|
inputDialog.setLabelText("File saved to:");
|
|
inputDialog.setTextEchoMode(QLineEdit::Normal);
|
|
inputDialog.setTextValue(filePath);
|
|
inputDialog.adjustSize();
|
|
inputDialog.move(QGuiApplication::primaryScreen()->geometry().center() - inputDialog.geometry().center());
|
|
inputDialog.exec();
|
|
});
|
|
}
|
|
|
|
void ScreenshotsWidget::actionDelete() const
|
|
{
|
|
QStringList listId;
|
|
for( int rowIndex = 0 ; rowIndex < tableWidget->rowCount() ; rowIndex++ ) {
|
|
if ( tableWidget->item(rowIndex, 0)->isSelected() ) {
|
|
QString screenId = tableWidget->item(rowIndex, 0)->text();
|
|
listId.append(screenId);
|
|
}
|
|
}
|
|
|
|
if(listId.empty())
|
|
return;
|
|
|
|
QString message = QString();
|
|
bool ok = false;
|
|
bool result = HttpReqScreenRemove(listId, *(adaptixWidget->GetProfile()), &message, &ok);
|
|
if( !result ) {
|
|
MessageError("Response timeout");
|
|
return;
|
|
}
|
|
}
|
|
|
|
void ScreenshotsWidget::onTableItemSelection(const QModelIndex ¤t, const QModelIndex &previous) const
|
|
{
|
|
int row = current.row();
|
|
if (row < 0)
|
|
return;
|
|
|
|
QString screenId = tableWidget->item(row,0)->text();
|
|
|
|
if (!adaptixWidget->Screenshots.contains(screenId) )
|
|
return;
|
|
|
|
ScreenData screenData = adaptixWidget->Screenshots[screenId];
|
|
auto image = QPixmap();
|
|
if (image.loadFromData(screenData.Content))
|
|
imageFrame->setPixmap(image);
|
|
} |