#include "BackupDialog.h" #include "ui_BackupDialog.h" #include "BackupFormatModel.h" #include #include #include #include #include BackupDialog::BackupDialog(QWidget *parent) : QDialog(parent), ui(new Ui::BackupDialog) { ui->setupUi(this); auto format_model = new BackupFormatModel(this); ui->backupFormat->setModel(format_model); } BackupDialog::~BackupDialog() { delete ui; } void BackupDialog::setConfig(const ConnectionConfig &cfg) { m_config = cfg; } void BackupDialog::ConnectTo(QProcess *process) { disconnectCurrentProcess(); m_process = process; if (process) { process->setProcessChannelMode(QProcess::MergedChannels); process->setReadChannel(QProcess::StandardOutput); connect(process, SIGNAL(readyRead()), this, SLOT(on_process_readyRead())); connect(process, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(on_process_errorOccurred(QProcess::ProcessError))); connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_process_finished(int, QProcess::ExitStatus))); } } void BackupDialog::disconnectCurrentProcess() { if (m_process) { disconnect(m_process, SIGNAL(readyRead()), this, SLOT(on_process_readyRead())); disconnect(m_process, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(on_process_errorOccurred(QProcess::ProcessError))); disconnect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_process_finished(int, QProcess::ExitStatus))); m_process = nullptr; } } void BackupDialog::writeOutput(QString s) { ui->stdOutput->appendPlainText(s); QScrollBar *bar = ui->stdOutput->verticalScrollBar(); bar->setValue(bar->maximum()); } void BackupDialog::on_process_readyRead() { QByteArray data = m_process->readAllStandardOutput(); writeOutput(QString::fromUtf8(data)); } void BackupDialog::on_process_errorOccurred(QProcess::ProcessError error) { QString msg; switch (error) { case 0: msg = tr("Failed to start"); break; case 1: msg = tr("Crashed"); break; case 2: msg = tr("Timedout"); break; case 3: msg = tr("Read error"); break; case 4: msg = tr("Write error"); break; case 5: msg = tr("Unknown error"); break; default: msg = tr("Unexpected error"); } auto res = QMessageBox::critical(this, "pglab", msg, QMessageBox::Close); if (res == QMessageBox::Yes) { QApplication::quit(); } } void BackupDialog::on_process_finished(int exitCode, QProcess::ExitStatus ) { writeOutput(tr("Completed, with exitcode %1\n").arg(exitCode)); } void BackupDialog::setParams(QStringList &args) { QString short_args("-"); if (ui->chkbxVerbose->checkState() == Qt::Checked) short_args += "v"; if (ui->chkbxClean->checkState() == Qt::Checked) short_args += "c"; if (ui->chkbxCreate->checkState() == Qt::Checked) short_args += "C"; if (ui->chkbxIncludeBlobs->checkState() == Qt::Checked) short_args += "b"; switch (ui->what->currentIndex()) { case 1: short_args += "a"; break; case 2: short_args += "s"; break; } if (ui->oids->checkState() == Qt::Checked) short_args += "o"; if (ui->noAcl->checkState() == Qt::Checked) short_args += "x"; if (short_args.length() > 1) // larger then one because always includes '-' args << short_args; // Todo check path exists and name is valid? QFileInfo fi(QDir::fromNativeSeparators(ui->editFilename->text())); QDir dir(fi.absolutePath()); if (!dir.exists()) dir.mkdir(fi.absolutePath()); args << "-f" << ui->editFilename->text(); // R"-(c:\temp\backup.sql)-"; int format_index = ui->backupFormat->currentIndex(); auto format_model_base = ui->backupFormat->model(); BackupFormatModel *bfm = dynamic_cast(format_model_base); if (bfm) { QVariant v = bfm->data(bfm->index(format_index, 1)); QString format("-F"); format += v.toString(); args << format; } int jobs = ui->jobs->value(); if (jobs > 0) args << "-j" << QString::number(jobs); int compression = ui->compression->value(); if (compression >= 0) args << "-Z" << QString::number(compression); } void BackupDialog::on_btnStart_clicked() { ui->stdOutput->clear(); QString program = R"-(C:\Prog\bigsql\pg96\bin\pg_dump.exe)-"; QStringList arguments; setParams(arguments); // BOOL res = AllocConsole(); // if (!res) { // DWORD error = GetLastError(); // QMessageBox::critical(this, "pglab", tr("AllocConsole failed %1").arg(error), QMessageBox::Close); // } // HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); // DWORD written; // res = WriteConsoleOutputCharacter(out, L"Hello, world!\n", 14, {0, 0}, &written); // PROCESS_INFORMATION proc_info; // STARTUPINFO startup_info; // memset(&startup_info, 0, sizeof(startup_info)); // startup_info.cb = sizeof(startup_info); // startup_info.lpReserved; // startup_info.lpDesktop; // startup_info.lpTitle; // startup_info.dwX; // startup_info.dwY; // startup_info.dwXSize; // startup_info.dwYSize; // startup_info.dwXCountChars; // startup_info.dwYCountChars; // startup_info.dwFillAttribute; // startup_info.dwFlags = STARTF_USESTDHANDLES; // startup_info.wShowWindow; // startup_info.cbReserved2; // startup_info.lpReserved2; // startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); // startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); // startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); // res = CreateProcess( // LR"_(C:\Prog\build-conoutputtest-Desktop_Qt_5_8_0_MSVC2015_32bit2-Debug\debug\conoutputtest.exe)_", // NULL, // _Inout_opt_ LPTSTR lpCommandLine, // NULL, // _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, // NULL, // _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, // TRUE, // 0, // _In_ DWORD dwCreationFlags, // NULL, // _In_opt_ LPVOID lpEnvironment, // NULL, // _In_opt_ LPCTSTR lpCurrentDirectory, // &startup_info, // _In_ LPSTARTUPINFO lpStartupInfo, // &proc_info // _Out_ LPPROCESS_INFORMATION lpProcessInformation // ); // QString program = R"_(C:\prog\build-conoutputtest-Desktop_Qt_5_8_0_MSVC2015_32bit2-Debug\debug\conoutputtest.exe)_"; // QStringList arguments; // arguments << "/C" << "DIR /S c:\\"; // Database connection paramters are passed through the environment as this is far less visible to others. Commandline // parameters can often be viewed even if the user is not the owner of the process. // We use the systemEnvironment as a sane default. Then we let the connection overwrite all PG variables in it. QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); m_config.writeToEnvironment(env); env.insert("SESSIONNAME", "Console"); auto p = new QProcess(this); ConnectTo(p); p->setProcessEnvironment(env); #ifdef _WIN32 p->setCreateProcessArgumentsModifier([] (QProcess::CreateProcessArguments *args) { args->flags |= CREATE_NEW_CONSOLE; args->flags &= ~DETACHED_PROCESS; args->startupInfo->dwFlags &= ~STARTF_USESTDHANDLES; }); #endif p->start(program, arguments); } void BackupDialog::on_backupFormat_currentIndexChanged(int index) { int format_index = ui->backupFormat->currentIndex(); auto format_model_base = ui->backupFormat->model(); BackupFormatModel *bfm = dynamic_cast(format_model_base); if (bfm) { QVariant v = bfm->data(bfm->index(format_index, 1)); QString format = v.toString(); bool comp_enable = (format == "c" || format == "d"); ui->compression->setEnabled(comp_enable); if (!comp_enable) ui->compression->setValue(-1); bool jobs_enable = (format == "d"); ui->jobs->setEnabled(jobs_enable); if (!jobs_enable) ui->jobs->setValue(0); } } void BackupDialog::on_selectDestination_clicked() { QString home_dir = QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory); QString fn = QFileDialog::getSaveFileName(this, tr("Save backup"), home_dir, tr("Backup file (*.backup)")); if (!fn.isEmpty()) { ui->editFilename->setText(QDir::toNativeSeparators(fn)); } }