/
LostDead
/
TestProgramm
Обзор
Документация
Войти
/
LostDead
/
TestProgramm
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
mainwindow.cpp
1 081 строка
38 KB
Maksi
first_commit
27 янв 2026, 05:31
27 янв 2026, 05:31
d072a23
Код
Авторство
О чём код?
#include "mainwindow.h" #include <QDir> #include <QFileInfo> #include <QDateTime> #include <QScrollBar> #include <QTextBlock> #include <QTextCodec> #include <QToolBar> #include <QStatusBar> #include <QToolButton> #include <QFrame> #include <QProgressBar> #include <QSplitter> #include <QFontDatabase> #include <QApplication> #include <QDesktopServices> #include <QUrl> #include <QTimer> #include <QInputDialog> #include <QMenu> #include <QShortcut> #include <QSettings> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , currentFolderPath("") , currentWorkingDirectory(QDir::homePath()) , process(new QProcess(this)) , historyIndex(-1) , settings(new QSettings("PowerShellStudio", "COM_Analyzer", this)) { // Устанавливаем кодировку UTF-8 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); setupUI(); setupToolBar(); setupStatusBar(); setupConnections(); applyModernStyle(); loadSettings(); startPowerShell(); setWindowTitle("PowerShell Studio - Integrated Console"); resize(1200, 800); } MainWindow::~MainWindow() { saveSettings(); if (process->state() == QProcess::Running) { writeToPowerShell("exit"); process->waitForFinished(2000); process->kill(); } } void MainWindow::applyModernStyle() { // Устанавливаем стиль Fusion и настраиваем палитру QApplication::setStyle("Fusion"); QPalette darkPalette; darkPalette.setColor(QPalette::Window, QColor(45, 45, 48)); darkPalette.setColor(QPalette::WindowText, Qt::white); darkPalette.setColor(QPalette::Base, QColor(30, 30, 30)); darkPalette.setColor(QPalette::AlternateBase, QColor(45, 45, 48)); darkPalette.setColor(QPalette::ToolTipBase, Qt::white); darkPalette.setColor(QPalette::ToolTipText, Qt::white); darkPalette.setColor(QPalette::Text, Qt::white); darkPalette.setColor(QPalette::Button, QColor(62, 62, 66)); darkPalette.setColor(QPalette::ButtonText, Qt::white); darkPalette.setColor(QPalette::BrightText, Qt::red); darkPalette.setColor(QPalette::Link, QColor(0, 122, 204)); darkPalette.setColor(QPalette::Highlight, QColor(0, 122, 204)); darkPalette.setColor(QPalette::HighlightedText, Qt::white); qApp->setPalette(darkPalette); // Стили для виджетов QString styleSheet = R"( QMainWindow { background-color: #2d2d30; } QTabWidget::pane { border: 1px solid #3e3e42; background-color: #252526; border-radius: 4px; } QTabBar::tab { background-color: #2d2d30; color: #cccccc; padding: 8px 16px; margin-right: 2px; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:selected { background-color: #1e1e1e; color: white; border-bottom: 2px solid #007acc; } QTabBar::tab:hover:!selected { background-color: #3e3e42; } QGroupBox { color: #cccccc; border: 1px solid #3e3e42; border-radius: 4px; margin-top: 10px; padding-top: 10px; font-weight: bold; } QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 5px 0 5px; color: #cccccc; } QPushButton { background-color: #0e639c; color: white; border: none; padding: 8px 16px; border-radius: 4px; font-weight: 500; min-height: 32px; } QPushButton:hover { background-color: #1177bb; } QPushButton:pressed { background-color: #0c4c7c; } QPushButton:disabled { background-color: #3e3e42; color: #7a7a7a; } QListWidget { background-color: #252526; color: #cccccc; border: 1px solid #3e3e42; border-radius: 4px; outline: none; } QListWidget::item { padding: 8px; border-bottom: 1px solid #3e3e42; } QListWidget::item:selected { background-color: #094771; color: white; border-radius: 2px; } QListWidget::item:hover:!selected { background-color: #2a2d2e; } QLabel { color: #cccccc; } QLineEdit { background-color: #3c3c3c; color: white; border: 1px solid #3e3e42; border-radius: 4px; padding: 8px; selection-background-color: #094771; } QLineEdit:focus { border: 1px solid #007acc; } QStatusBar { background-color: #007acc; color: white; } QToolBar { background-color: #333337; border: none; spacing: 4px; padding: 4px; } QToolButton { background-color: transparent; border: 1px solid transparent; border-radius: 4px; padding: 6px; } QToolButton:hover { background-color: #3e3e42; border: 1px solid #007acc; } QProgressBar { border: 1px solid #3e3e42; border-radius: 4px; text-align: center; color: white; } QProgressBar::chunk { background-color: #007acc; border-radius: 4px; } )"; setStyleSheet(styleSheet); // Устанавливаем шрифты QFont font("Segoe UI", 10); qApp->setFont(font); // Специальный стиль для консоли consoleOutput->setStyleSheet(R"( QPlainTextEdit { background-color: #1e1e1e; color: #d4d4d4; font-family: 'Cascadia Code', 'Consolas', monospace; font-size: 11pt; border: 1px solid #3e3e42; border-radius: 4px; padding: 8px; } )"); consoleInput->setStyleSheet(R"( QLineEdit { background-color: #252526; color: #d4d4d4; border: 1px solid #3e3e42; border-radius: 4px; padding: 10px; font-family: 'Cascadia Code', 'Consolas', monospace; font-size: 11pt; } QLineEdit:focus { border: 2px solid #007acc; background-color: #1e1e1e; } )"); } void MainWindow::setupToolBar() { mainToolBar = addToolBar("Главная"); mainToolBar->setMovable(false); mainToolBar->setIconSize(QSize(20, 20)); folderAction = mainToolBar->addAction("📁 Открыть папку"); folderAction->setToolTip("Выбрать папку со скриптами"); mainToolBar->addSeparator(); runAction = mainToolBar->addAction("▶ Запуск"); runAction->setToolTip("Запустить выбранный скрипт"); stopAction = mainToolBar->addAction("⏹ Остановить"); stopAction->setToolTip("Остановить выполнение"); stopAction->setEnabled(false); mainToolBar->addSeparator(); refreshAction = mainToolBar->addAction("🔄 Обновить"); refreshAction->setToolTip("Обновить список скриптов"); clearAction = mainToolBar->addAction("🗑 Очистить"); clearAction->setToolTip("Очистить консоль"); mainToolBar->addSeparator(); aboutAction = mainToolBar->addAction("ℹ О программе"); aboutAction->setToolTip("О программе"); } void MainWindow::setupStatusBar() { statusBar()->setStyleSheet("QStatusBar { background-color: #007acc; color: white; padding: 4px; }"); powerShellStatus = new QLabel("⚡ PowerShell: Запускается...", statusBar()); progressBar = new QProgressBar(statusBar()); progressBar->setMaximumWidth(200); progressBar->setTextVisible(false); progressBar->setVisible(false); statusBar()->addPermanentWidget(powerShellStatus, 1); statusBar()->addPermanentWidget(progressBar); } void MainWindow::setupUI() { // Основной виджет с вкладками tabWidget = new QTabWidget(this); tabWidget->setDocumentMode(true); setCentralWidget(tabWidget); // ========== ВКЛАДКА СКРИПТОВ ========== scriptsTab = new QWidget(); scriptsLayout = new QVBoxLayout(scriptsTab); // Создаем splitter для разделения на левую и правую панели mainSplitter = new QSplitter(Qt::Horizontal, scriptsTab); mainSplitter->setChildrenCollapsible(false); mainSplitter->setHandleWidth(2); mainSplitter->setStyleSheet("QSplitter::handle { background-color: #3e3e42; }"); // ЛЕВАЯ ПАНЕЛЬ - Информация о файлах leftPanel = new QWidget(); leftLayout = new QVBoxLayout(leftPanel); leftLayout->setContentsMargins(5, 5, 5, 5); // Группа выбора папки folderGroup = new QGroupBox("Рабочая папка", leftPanel); folderLayout = new QVBoxLayout(); folderPathLabel = new QLabel("Папка не выбрана", folderGroup); folderPathLabel->setWordWrap(true); folderPathLabel->setStyleSheet("QLabel { padding: 8px; background-color: #252526; border-radius: 4px; }"); browseButton = new QPushButton("Выбрать папку", folderGroup); openLocationButton = new QPushButton("Открыть в проводнике", folderGroup); openLocationButton->setEnabled(false); folderLayout->addWidget(folderPathLabel); folderLayout->addWidget(browseButton); folderLayout->addWidget(openLocationButton); folderGroup->setLayout(folderLayout); // Группа информации о файле fileInfoGroup = new QGroupBox("Информация о скрипте", leftPanel); fileInfoLayout = new QVBoxLayout(); fileNameLabel = new QLabel("Файл: не выбран", fileInfoGroup); fileSizeLabel = new QLabel("Размер: -", fileInfoGroup); fileModifiedLabel = new QLabel("Изменен: -", fileInfoGroup); editButton = new QPushButton("Редактировать скрипт", fileInfoGroup); editButton->setEnabled(false); fileInfoLayout->addWidget(fileNameLabel); fileInfoLayout->addWidget(fileSizeLabel); fileInfoLayout->addWidget(fileModifiedLabel); fileInfoLayout->addWidget(editButton); fileInfoLayout->addStretch(); fileInfoGroup->setLayout(fileInfoLayout); leftLayout->addWidget(folderGroup); leftLayout->addWidget(fileInfoGroup); leftLayout->addStretch(); // ПРАВАЯ ПАНЕЛЬ - Список скриптов rightPanel = new QWidget(); rightLayout = new QVBoxLayout(rightPanel); rightLayout->setContentsMargins(5, 5, 5, 5); scriptsGroup = new QGroupBox("Скрипты PowerShell", rightPanel); scriptsGroupLayout = new QVBoxLayout(); // Панель кнопок над списком QHBoxLayout *topButtonLayout = new QHBoxLayout(); newScriptButton = new QPushButton("+ Новый скрипт", scriptsGroup); refreshButton = new QPushButton("Обновить", scriptsGroup); topButtonLayout->addWidget(newScriptButton); topButtonLayout->addWidget(refreshButton); topButtonLayout->addStretch(); // Поле поиска QHBoxLayout *searchLayout = new QHBoxLayout(); searchEdit = new QLineEdit(scriptsGroup); searchEdit->setPlaceholderText("Поиск скриптов..."); searchButton = new QPushButton("🔍", scriptsGroup); searchLayout->addWidget(searchEdit); searchLayout->addWidget(searchButton); // Список скриптов scriptsList = new QListWidget(scriptsGroup); scriptsList->setAlternatingRowColors(true); scriptsList->setSelectionMode(QListWidget::SingleSelection); // Панель кнопок под списком QHBoxLayout *bottomButtonLayout = new QHBoxLayout(); runButton = new QPushButton("▶ Выполнить", scriptsGroup); stopButton = new QPushButton("⏹ Остановить", scriptsGroup); stopButton->setEnabled(false); bottomButtonLayout->addWidget(runButton); bottomButtonLayout->addWidget(stopButton); bottomButtonLayout->addStretch(); scriptsGroupLayout->addLayout(topButtonLayout); scriptsGroupLayout->addLayout(searchLayout); scriptsGroupLayout->addWidget(scriptsList); scriptsGroupLayout->addLayout(bottomButtonLayout); scriptsGroup->setLayout(scriptsGroupLayout); rightLayout->addWidget(scriptsGroup); // Добавляем панели в splitter mainSplitter->addWidget(leftPanel); mainSplitter->addWidget(rightPanel); mainSplitter->setStretchFactor(0, 1); mainSplitter->setStretchFactor(1, 3); scriptsLayout->addWidget(mainSplitter); // ========== ВКЛАДКА КОНСОЛИ ========== consoleTab = new QWidget(); consoleLayout = new QVBoxLayout(consoleTab); consoleLayout->setContentsMargins(10, 10, 10, 10); consoleLayout->setSpacing(10); // Заголовок консоли QHBoxLayout *consoleHeaderLayout = new QHBoxLayout(); QLabel *consoleTitle = new QLabel("Консоль PowerShell", consoleTab); consoleTitle->setStyleSheet("QLabel { font-size: 14pt; font-weight: bold; color: #cccccc; }"); consoleStatus = new QLabel("Готов", consoleTab); consoleStatus->setStyleSheet("QLabel { padding: 4px 12px; background-color: #0e639c; color: white; border-radius: 12px; }"); consoleHeaderLayout->addWidget(consoleTitle); consoleHeaderLayout->addStretch(); consoleHeaderLayout->addWidget(consoleStatus); // Консольный вывод consoleOutput = new QPlainTextEdit(consoleTab); consoleOutput->setReadOnly(true); consoleOutput->setFont(QFont("Cascadia Code", 10)); // Панель ввода QFrame *inputFrame = new QFrame(consoleTab); inputFrame->setFrameShape(QFrame::StyledPanel); QVBoxLayout *inputLayout = new QVBoxLayout(inputFrame); QLabel *inputLabel = new QLabel("Ввод команды:", inputFrame); inputLabel->setStyleSheet("QLabel { color: #cccccc; font-weight: bold; }"); consoleInput = new QLineEdit(inputFrame); consoleInput->setPlaceholderText("Введите команду PowerShell и нажмите Enter..."); inputLayout->addWidget(inputLabel); inputLayout->addWidget(consoleInput); consoleLayout->addLayout(consoleHeaderLayout); consoleLayout->addWidget(consoleOutput, 1); consoleLayout->addWidget(inputFrame); // Добавляем вкладки tabWidget->addTab(scriptsTab, "Скрипты"); tabWidget->addTab(consoleTab, "Консоль"); // Устанавливаем иконки для вкладок tabWidget->setTabIcon(0, QApplication::style()->standardIcon(QStyle::SP_DirIcon)); tabWidget->setTabIcon(1, QApplication::style()->standardIcon(QStyle::SP_ComputerIcon)); // Включаем контекстное меню для списка scriptsList->setContextMenuPolicy(Qt::CustomContextMenu); connect(scriptsList, &QWidget::customContextMenuRequested, this, &MainWindow::showScriptContextMenu); } void MainWindow::setupConnections() { // Панель инструментов connect(folderAction, &QAction::triggered, this, &MainWindow::selectFolder); connect(runAction, &QAction::triggered, this, &MainWindow::runSelectedScript); connect(stopAction, &QAction::triggered, this, &MainWindow::stopScript); connect(refreshAction, &QAction::triggered, this, &MainWindow::updateScriptList); connect(clearAction, &QAction::triggered, this, &MainWindow::clearConsole); connect(aboutAction, &QAction::triggered, this, &MainWindow::showAbout); // Кнопки connect(browseButton, &QPushButton::clicked, this, &MainWindow::selectFolder); connect(openLocationButton, &QPushButton::clicked, this, &MainWindow::openScriptLocation); connect(refreshButton, &QPushButton::clicked, this, &MainWindow::updateScriptList); connect(runButton, &QPushButton::clicked, this, &MainWindow::runSelectedScript); connect(stopButton, &QPushButton::clicked, this, &MainWindow::stopScript); connect(newScriptButton, &QPushButton::clicked, this, &MainWindow::createNewScript); connect(editButton, &QPushButton::clicked, this, &MainWindow::editScript); // Поиск connect(searchButton, &QPushButton::clicked, this, &MainWindow::filterScripts); connect(searchEdit, &QLineEdit::returnPressed, this, &MainWindow::filterScripts); // Список connect(scriptsList, &QListWidget::itemDoubleClicked, this, &MainWindow::runDoubleClickedScript); connect(scriptsList, &QListWidget::itemSelectionChanged, this, &MainWindow::updateScriptInfo); // Консоль connect(consoleInput, &QLineEdit::returnPressed, this, &MainWindow::executeCommand); connect(process, &QProcess::readyReadStandardOutput, this, &MainWindow::readScriptOutput); connect(process, &QProcess::readyReadStandardError, this, &MainWindow::readScriptError); connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &MainWindow::scriptFinished); connect(process, &QProcess::started, this, [this]() { powerShellStatus->setText("⚡ PowerShell: Запущен"); consoleStatus->setText("Выполняется"); consoleStatus->setStyleSheet("QLabel { padding: 4px 12px; background-color: #0e639c; color: white; border-radius: 12px; }"); stopButton->setEnabled(true); stopAction->setEnabled(true); progressBar->setVisible(true); }); connect(process, &QProcess::stateChanged, this, &MainWindow::updatePowerShellStatus); // Добавляем горячие клавиши QShortcut *shortcutRun = new QShortcut(QKeySequence(Qt::Key_F5), this); connect(shortcutRun, &QShortcut::activated, this, &MainWindow::runSelectedScript); QShortcut *shortcutStop = new QShortcut(QKeySequence(Qt::Key_F6), this); connect(shortcutStop, &QShortcut::activated, this, &MainWindow::stopScript); QShortcut *shortcutClear = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_L), this); connect(shortcutClear, &QShortcut::activated, this, &MainWindow::clearConsole); QShortcut *shortcutFocusConsole = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_T), this); connect(shortcutFocusConsole, &QShortcut::activated, [this]() { tabWidget->setCurrentIndex(1); consoleInput->setFocus(); }); } void MainWindow::saveSettings() { settings->setValue("Window/Size", size()); settings->setValue("Window/Position", pos()); settings->setValue("Splitter/Sizes", mainSplitter->saveState()); settings->setValue("LastFolder", currentFolderPath); } void MainWindow::loadSettings() { resize(settings->value("Window/Size", QSize(1200, 800)).toSize()); move(settings->value("Window/Position", QPoint(100, 100)).toPoint()); mainSplitter->restoreState(settings->value("Splitter/Sizes").toByteArray()); QString lastFolder = settings->value("LastFolder").toString(); if (!lastFolder.isEmpty() && QDir(lastFolder).exists()) { currentFolderPath = lastFolder; currentWorkingDirectory = lastFolder; folderPathLabel->setText(lastFolder); folderPathLabel->setToolTip(lastFolder); openLocationButton->setEnabled(true); updateScriptList(); } } void MainWindow::selectFolder() { QString folder = QFileDialog::getExistingDirectory( this, "Выберите папку со скриптами PowerShell", currentWorkingDirectory, QFileDialog::ShowDirsOnly | QFileDialog::ReadOnly ); if (!folder.isEmpty()) { currentFolderPath = folder; currentWorkingDirectory = folder; process->setWorkingDirectory(folder); folderPathLabel->setText(folder); folderPathLabel->setToolTip(folder); openLocationButton->setEnabled(true); updateScriptList(); } } void MainWindow::updateScriptList() { if (currentFolderPath.isEmpty()) { QMessageBox::information(this, "Информация", "Выберите папку со скриптами для начала работы."); return; } scriptsList->clear(); QDir dir(currentFolderPath); QStringList filters = {"*.ps1", "*.psm1", "*.psd1"}; QStringList scriptFiles = dir.entryList(filters, QDir::Files, QDir::Name); if (scriptFiles.isEmpty()) { QListWidgetItem *item = new QListWidgetItem("📁 Скрипты не найдены", scriptsList); item->setFlags(item->flags() & ~Qt::ItemIsSelectable); runButton->setEnabled(false); runAction->setEnabled(false); } else { for (const QString &fileName : scriptFiles) { QFileInfo fileInfo(dir.filePath(fileName)); QString displayText = QString("📄 %1\n ⚙ %2 | 📅 %3") .arg(fileName) .arg(formatFileSize(fileInfo.size())) .arg(fileInfo.lastModified().toString("dd.MM.yyyy HH:mm")); QListWidgetItem *item = new QListWidgetItem(displayText, scriptsList); item->setData(Qt::UserRole, fileInfo.absoluteFilePath()); item->setToolTip(fileInfo.absoluteFilePath()); // Цветовое кодирование по размеру файла if (fileInfo.size() > 1024 * 1024) { // > 1MB item->setForeground(Qt::yellow); } else if (fileInfo.size() > 1024 * 100) { // > 100KB item->setForeground(Qt::green); } } runButton->setEnabled(true); runAction->setEnabled(true); } } void MainWindow::filterScripts() { QString filter = searchEdit->text().trimmed(); if (filter.isEmpty()) { // Показываем все элементы for (int i = 0; i < scriptsList->count(); ++i) { scriptsList->item(i)->setHidden(false); } return; } for (int i = 0; i < scriptsList->count(); ++i) { QListWidgetItem *item = scriptsList->item(i); bool match = item->text().contains(filter, Qt::CaseInsensitive); item->setHidden(!match); } } QString MainWindow::formatFileSize(qint64 bytes) { if (bytes < 1024) return QString("%1 B").arg(bytes); else if (bytes < 1024 * 1024) return QString("%1 KB").arg(bytes / 1024.0, 0, 'f', 1); else return QString("%1 MB").arg(bytes / (1024.0 * 1024.0), 0, 'f', 1); } void MainWindow::updateScriptInfo() { QListWidgetItem *currentItem = scriptsList->currentItem(); if (!currentItem) { fileNameLabel->setText("Файл: не выбран"); fileSizeLabel->setText("Размер: -"); fileModifiedLabel->setText("Изменен: -"); editButton->setEnabled(false); return; } QString scriptPath = currentItem->data(Qt::UserRole).toString(); QFileInfo fileInfo(scriptPath); fileNameLabel->setText(QString("Файл: %1").arg(fileInfo.fileName())); fileSizeLabel->setText(QString("Размер: %1").arg(formatFileSize(fileInfo.size()))); fileModifiedLabel->setText(QString("Изменен: %1").arg(fileInfo.lastModified().toString("dd.MM.yyyy HH:mm:ss"))); editButton->setEnabled(true); } void MainWindow::runSelectedScript() { QListWidgetItem *currentItem = scriptsList->currentItem(); if (!currentItem) { QMessageBox::information(this, "Информация", "Выберите скрипт из списка."); return; } QString scriptPath = currentItem->data(Qt::UserRole).toString(); // Переключаемся на вкладку консоли tabWidget->setCurrentIndex(1); // Выполняем скрипт QString command = "& \"" + scriptPath + "\""; consoleOutput->appendPlainText(QString("\n[%1] Запуск скрипта: %2") .arg(QDateTime::currentDateTime().toString("HH:mm:ss")) .arg(QFileInfo(scriptPath).fileName())); consoleOutput->appendPlainText(QString("PS> %1").arg(command)); writeToPowerShell(command + "\n"); progressBar->setRange(0, 0); // Индикатор прогресса без конца } void MainWindow::runDoubleClickedScript(QListWidgetItem *item) { if (item) { runSelectedScript(); } } void MainWindow::executeScript(const QString &scriptPath) { Q_UNUSED(scriptPath); // Метод для обратной совместимости } void MainWindow::startPowerShell() { // Настраиваем процесс PowerShell для интерактивного использования QString program; QStringList arguments; #ifdef Q_OS_WINDOWS program = "powershell.exe"; arguments << "-NoExit" << "-NoLogo" << "-Command" << "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; $OutputEncoding = [System.Text.Encoding]::UTF8; $host.UI.RawUI.WindowTitle='PowerShell в COM Analyzer';"; // Настраиваем среду для корректной работы с UTF-8 QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert("PYTHONIOENCODING", "utf-8"); env.insert("PYTHONUTF8", "1"); process->setProcessEnvironment(env); #else program = "pwsh"; arguments << "-NoLogo" << "-Command" << "$host.UI.RawUI.WindowTitle='PowerShell в COM Analyzer';"; #endif process->setProgram(program); process->setArguments(arguments); // Настраиваем режим работы с процессом process->setProcessChannelMode(QProcess::SeparateChannels); process->setWorkingDirectory(currentWorkingDirectory); // Подключаем сигналы к слотам для чтения connect(process, &QProcess::readyReadStandardOutput, [this]() { QByteArray output = process->readAllStandardOutput(); QString text; // Пробуем разные кодировки для правильного отображения кириллицы QTextCodec *codec = QTextCodec::codecForName("UTF-8"); if (codec) { text = codec->toUnicode(output); } else { text = QString::fromLocal8Bit(output); } // Если текст содержит мусор, пробуем другие кодировки if (text.contains("�") || (text.isEmpty() && !output.isEmpty())) { // Пробуем Windows-1251 QTextCodec *codec1251 = QTextCodec::codecForName("Windows-1251"); if (codec1251) { text = codec1251->toUnicode(output); } } if (!text.isEmpty()) { consoleOutput->moveCursor(QTextCursor::End); consoleOutput->insertPlainText(text); consoleOutput->moveCursor(QTextCursor::End); // Прокручиваем вниз QScrollBar *scrollbar = consoleOutput->verticalScrollBar(); scrollbar->setValue(scrollbar->maximum()); } }); connect(process, &QProcess::readyReadStandardError, [this]() { QByteArray error = process->readAllStandardError(); QString text; // Пробуем разные кодировки для правильного отображения кириллицы QTextCodec *codec = QTextCodec::codecForName("UTF-8"); if (codec) { text = codec->toUnicode(error); } else { text = QString::fromLocal8Bit(error); } // Если текст содержит мусор, пробуем другие кодировки if (text.contains("�") || (text.isEmpty() && !error.isEmpty())) { // Пробуем Windows-1251 QTextCodec *codec1251 = QTextCodec::codecForName("Windows-1251"); if (codec1251) { text = codec1251->toUnicode(error); } } if (!text.isEmpty()) { consoleOutput->moveCursor(QTextCursor::End); consoleOutput->insertPlainText("\n[ОШИБКА]: " + text); consoleOutput->moveCursor(QTextCursor::End); } }); // Запускаем процесс process->start(); process->waitForStarted(); // После запуска устанавливаем кодировку UTF-8 в PowerShell if (process->state() == QProcess::Running) { // Команда для установки UTF-8 кодировки в PowerShell QString setupEncoding = "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; $OutputEncoding = [System.Text.Encoding]::UTF8;"; process->write(setupEncoding.toUtf8() + "\n"); process->waitForBytesWritten(1000); } // Отправляем приветственное сообщение consoleOutput->appendPlainText("PowerShell Integrated Console"); consoleOutput->appendPlainText("Введите 'exit' для выхода"); consoleOutput->appendPlainText("========================================"); consoleOutput->appendPlainText(""); } void MainWindow::writeToPowerShell(const QString &command) { if (process->state() == QProcess::Running) { // Отправляем команду в UTF-8 кодировке QString commandToSend = command; // Добавляем перевод строки, если его нет if (!commandToSend.endsWith('\n')) { commandToSend += '\n'; } process->write(commandToSend.toUtf8()); process->waitForBytesWritten(); } else { consoleOutput->appendPlainText("[ОШИБКА]: PowerShell не запущен!"); // Попробуем перезапустить QTimer::singleShot(1000, this, &MainWindow::startPowerShell); } } void MainWindow::onConsoleTextChanged() { // Автоматическая прокрутка вниз QScrollBar *scrollbar = consoleOutput->verticalScrollBar(); scrollbar->setValue(scrollbar->maximum()); } void MainWindow::executeCommand() { QString command = consoleInput->text().trimmed(); if (command.isEmpty()) return; commandHistory.append(command); historyIndex = commandHistory.size(); consoleOutput->appendPlainText(QString("\n[%1] PS> %2") .arg(QDateTime::currentDateTime().toString("HH:mm:ss")) .arg(command)); if (command.toLower() == "clear" || command.toLower() == "cls") { consoleOutput->clear(); consoleInput->clear(); return; } if (command.toLower() == "exit") { if (process->state() == QProcess::Running) { process->write("exit\n"); process->waitForFinished(2000); } QApplication::quit(); return; } writeToPowerShell(command + "\n"); consoleInput->clear(); } void MainWindow::readScriptOutput() { QByteArray output = process->readAllStandardOutput(); QString text = QString::fromUtf8(output); if (!text.isEmpty()) { consoleOutput->moveCursor(QTextCursor::End); consoleOutput->insertPlainText(text); consoleOutput->moveCursor(QTextCursor::End); } } void MainWindow::readScriptError() { QByteArray error = process->readAllStandardError(); QString text = QString::fromUtf8(error); if (!text.isEmpty()) { consoleOutput->moveCursor(QTextCursor::End); consoleOutput->insertPlainText("\n[ОШИБКА]: " + text); consoleOutput->moveCursor(QTextCursor::End); } } void MainWindow::scriptFinished(int exitCode, QProcess::ExitStatus exitStatus) { progressBar->setRange(0, 100); progressBar->setValue(100); QTimer::singleShot(1000, this, [this]() { progressBar->setVisible(false); }); consoleOutput->appendPlainText(QString("\n[%1] Команда завершена с кодом: %2") .arg(QDateTime::currentDateTime().toString("HH:mm:ss")) .arg(exitCode)); if (exitStatus != QProcess::NormalExit) { consoleOutput->appendPlainText("[ПРЕДУПРЕЖДЕНИЕ]: Процесс завершился аварийно"); } consoleStatus->setText("Готов"); consoleStatus->setStyleSheet("QLabel { padding: 4px 12px; background-color: #388e3c; color: white; border-radius: 12px; }"); stopButton->setEnabled(false); stopAction->setEnabled(false); } void MainWindow::updatePowerShellStatus() { if (process->state() == QProcess::Running) { powerShellStatus->setText("⚡ PowerShell: Запущен"); } else if (process->state() == QProcess::Starting) { powerShellStatus->setText("⚡ PowerShell: Запускается..."); } else { powerShellStatus->setText("⚡ PowerShell: Остановлен"); } } void MainWindow::clearConsole() { consoleOutput->clear(); consoleOutput->appendPlainText("Консоль очищена"); } void MainWindow::stopScript() { if (process->state() == QProcess::Running) { process->kill(); consoleOutput->appendPlainText("\n[ВНИМАНИЕ]: Выполнение прервано пользователем"); } } void MainWindow::openScriptLocation() { if (!currentFolderPath.isEmpty()) { QDesktopServices::openUrl(QUrl::fromLocalFile(currentFolderPath)); } } void MainWindow::editScript() { QListWidgetItem *currentItem = scriptsList->currentItem(); if (!currentItem) return; QString scriptPath = currentItem->data(Qt::UserRole).toString(); QDesktopServices::openUrl(QUrl::fromLocalFile(scriptPath)); } void MainWindow::createNewScript() { if (currentFolderPath.isEmpty()) { QMessageBox::information(this, "Информация", "Сначала выберите папку для сохранения скрипта."); return; } bool ok; QString scriptName = QInputDialog::getText(this, "Новый скрипт", "Введите имя скрипта:", QLineEdit::Normal, "НовыйСкрипт.ps1", &ok); if (ok && !scriptName.isEmpty()) { if (!scriptName.endsWith(".ps1")) { scriptName += ".ps1"; } QString scriptPath = QDir(currentFolderPath).filePath(scriptName); QFile file(scriptPath); if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { QString content = "# Скрипт PowerShell\n# Создан: " + QDateTime::currentDateTime().toString("dd.MM.yyyy HH:mm") + "\n\nWrite-Host \"Привет, мир!\"\n"; file.write(content.toUtf8()); file.close(); updateScriptList(); QMessageBox::information(this, "Успех", QString("Скрипт '%1' успешно создан.").arg(scriptName)); } else { QMessageBox::warning(this, "Ошибка", "Не удалось создать файл."); } } } void MainWindow::showAbout() { QMessageBox::about(this, "О программе", "<h3>PowerShell Studio</h3>" "<p>Версия 1.0.0</p>" "<p>Интегрированная среда для работы со скриптами PowerShell</p>" "<p>© 2024 Все права защищены</p>" "<hr>" "<p>Программа предоставляет удобный интерфейс для:</p>" "<ul>" "<li>Просмотра и управления скриптами PowerShell</li>" "<li>Запуска скриптов с визуальным выводом</li>" "<li>Работы с интерактивной консолью PowerShell</li>" "</ul>"); } void MainWindow::showScriptContextMenu(const QPoint &pos) { QListWidgetItem *item = scriptsList->itemAt(pos); if (!item) return; QMenu contextMenu(this); QAction *runAction = contextMenu.addAction("▶ Запустить"); QAction *editAction = contextMenu.addAction("✏ Редактировать"); QAction *openFolderAction = contextMenu.addAction("📂 Открыть папку"); contextMenu.addSeparator(); QAction *deleteAction = contextMenu.addAction("🗑 Удалить"); QAction *selectedAction = contextMenu.exec(scriptsList->mapToGlobal(pos)); if (selectedAction == runAction) { runSelectedScript(); } else if (selectedAction == editAction) { editScript(); } else if (selectedAction == openFolderAction) { openScriptLocation(); } else if (selectedAction == deleteAction) { deleteScript(item); } } void MainWindow::deleteScript(QListWidgetItem *item) { if (!item) return; QString scriptPath = item->data(Qt::UserRole).toString(); QString scriptName = QFileInfo(scriptPath).fileName(); QMessageBox::StandardButton reply; reply = QMessageBox::question(this, "Подтверждение", QString("Вы уверены, что хотите удалить скрипт '%1'?").arg(scriptName), QMessageBox::Yes | QMessageBox::No); if (reply == QMessageBox::Yes) { if (QFile::remove(scriptPath)) { delete scriptsList->takeItem(scriptsList->row(item)); QMessageBox::information(this, "Успех", "Скрипт удален"); } else { QMessageBox::warning(this, "Ошибка", "Не удалось удалить скрипт"); } } } void MainWindow::keyPressEvent(QKeyEvent *event) { if (tabWidget->currentIndex() == 1) { if (event->key() == Qt::Key_Up) { if (!commandHistory.isEmpty() && historyIndex > 0) { historyIndex--; consoleInput->setText(commandHistory[historyIndex]); } event->accept(); return; } else if (event->key() == Qt::Key_Down) { if (!commandHistory.isEmpty() && historyIndex < commandHistory.size() - 1) { historyIndex++; consoleInput->setText(commandHistory[historyIndex]); } else { historyIndex = commandHistory.size(); consoleInput->clear(); } event->accept(); return; } } QMainWindow::keyPressEvent(event); }