Page MenuHomePhabricator

No OneTemporary

diff --git a/restruct.pro b/restruct.pro
--- a/restruct.pro
+++ b/restruct.pro
@@ -1,53 +1,51 @@
######################################################################
# Project started 11.01.2008 at 13:10
######################################################################
QT += core concurrent
TEMPLATE = app
TARGET = restruct
CONFIG += c++14
isEmpty(INCLUDEPATH): INCLUDEPATH = $$(HOME)/src/include
isEmpty(LIBS): LIBS = -L$$(HOME)/src/lib
INCLUDEPATH += src
isEmpty(LIBPQ_INC) {
unix: PREFIX = /usr
win32:PREFIX = /build
INCLUDEPATH += $${PREFIX}/include/postgresql $${PREFIX}/include/postgresql/internal
}
else {
INCLUDEPATH += $${LIBPQ_INC} $${LIBPQ_INC}/internal
win32: INCLUDEPATH += $${LIBPQ_INC}/server/port/win32
}
LIBS += -lktools -lsqlproc -lpq
SOURCES += src/updater.cpp \
- src/mainconsole.cpp \
src/exitcode.cpp
HEADERS += \
src/updater.h \
src/psettings.h \
- src/mainconsole.h \
src/exitcode.h
RESOURCES += resource/project.qrc
win32 {
QT += gui widgets
SOURCES += src/main_win.cpp src/mainwindow.cpp
HEADERS += src/mainwindow.h
RC_FILE = resource/project.rc
LIBS += -luuid -loleaut32 -lgdi32 -luser32
}
unix {
CONFIG += console
- SOURCES += src/main_lin.cpp
- HEADERS +=
+ SOURCES += src/main_lin.cpp src/mainconsole.cpp
+ HEADERS += src/mainconsole.h
}
target.path = /bin # install location
INSTALLS += target
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -1,460 +1,460 @@
#include "exitcode.h"
#include "mainwindow.h"
#include "psettings.h"
#include "updater.h"
#include <kactivityindicator.h>
#include <ksettings.h>
#include <sqlproc.h>
#include <klogon_win.h>
#include <QApplication>
#include <QCloseEvent>
#include <QEvent>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QLabel>
#include <QProgressBar>
#include <QPushButton>
#include <QShortcut>
#include <QStyle>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QtConcurrentRun>
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags)
: QDialog(parent, flags)
, _exitCode(0)
, _actionEventType(QEvent::User)
, _errorCount(0)
, _updater(new DatabaseUpdater)
{
setWindowTitle(QStringLiteral("Создание/обновление базы данных"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setSizeGripEnabled(true);
QHBoxLayout* mainLayout = new QHBoxLayout;
QVBoxLayout* leftLayout = new QVBoxLayout;
QVBoxLayout* rightLayout = new QVBoxLayout;
QHBoxLayout* bottomRightLayout = new QHBoxLayout;
leftLayout->setContentsMargins(0,
2 * style()->pixelMetric(QStyle::PM_LayoutTopMargin),
style()->pixelMetric(QStyle::PM_LayoutRightMargin), 0);
QLabel* picture = new QLabel;
picture->setPixmap(QPixmap(":/picture.png"));
//кнопки, скрытые до завершения процесса
_btnSave = new QPushButton(QStringLiteral("Сохранить"));
_btnClose = new QPushButton(QStringLiteral("Закрыть"));
_btnSave->setVisible(false);
_btnClose->setVisible(false);
_btnClose->setDefault(true);
leftLayout->addWidget(picture);
leftLayout->addStretch();
leftLayout->addWidget(_btnSave);
leftLayout->addWidget(_btnClose);
QLabel* label = new QLabel(QStringLiteral("Протокол работы"));
rightLayout->addWidget(label);
_protocol = new QTextEdit();
_protocol->setReadOnly(true);
label->setBuddy(_protocol);
rightLayout->addWidget(_protocol);
//индикаторы выполнения
_progress = new QProgressBar;
_progress->setTextVisible(false);
- _ai = new KActivityIndicator(KActivityIndicator::Gray);
+ _ai = new KActivityIndicator;
_ai->setVisible(false);
bottomRightLayout->addWidget(_progress);
bottomRightLayout->addWidget(_ai);
rightLayout->addLayout(bottomRightLayout);
mainLayout->addLayout(leftLayout);
mainLayout->addLayout(rightLayout);
setLayout(mainLayout);
//нажатие Esc не соединяется со слотом, чтобы окно не закрывалось
new QShortcut(QKeySequence(Qt::Key_Escape), this);
//соединить сигналы со слотами
connect(_btnSave, SIGNAL(clicked()), this, SLOT(saveProtocol()));
connect(_btnClose, SIGNAL(clicked()), this, SLOT(closeDialog()));
//получить незадействованный тип события
_actionEventType = QEvent::registerEventType();
}
MainWindow::~MainWindow()
{
delete _updater;
}
//---------------------------------------------------------------------------
void MainWindow::showEvent(QShowEvent* a_event)
{
QDialog::showEvent(a_event);
qApp->postEvent(this, new QEvent(QEvent::Type(_actionEventType)));
}
//---------------------------------------------------------------------------
bool MainWindow::event(QEvent* a_event)
{
if (a_event->type() == _actionEventType)
{
startExecution();
a_event->accept();
return true;
}
return QWidget::event(a_event);
}
//---------------------------------------------------------------------------
void MainWindow::closeEvent(QCloseEvent* a_event)
{
if (_futureWatcher.isRunning())
a_event->ignore();
else
a_event->accept();
}
//---------------------------------------------------------------------------
void MainWindow::startExecution()
{
if (_futureWatcher.isRunning())
return;
ProgramSettings pset;
processArguments(pset);
logon(pset);
connect(_updater, SIGNAL(progress(int)), _progress, SLOT(setValue(int)));
connect(_updater, SIGNAL(error(const QString&)), this, SLOT(error(const QString&)));
connect(_updater, SIGNAL(message(const QString&)), this, SLOT(message(const QString&)));
connect(_updater, SIGNAL(sqlError(const QString&, const QString&, const QString&)),
this, SLOT(sqlError(const QString&, const QString&, const QString&)));
connect(_updater, SIGNAL(logConnectionParameters(const QString&, const QString&, const QString&)),
this, SLOT(logConnectionParameters(const QString&, const QString&, const QString&)));
connect(&_futureWatcher, SIGNAL(finished()), this, SLOT(finishExecution()));
_ai->setVisible(true);
_ai->start();
//int rc = _updater.run( pset );
QFuture<int> rc = QtConcurrent::run(_updater, &DatabaseUpdater::run, pset);
_futureWatcher.setFuture(rc);
}
//---------------------------------------------------------------------------
void MainWindow::finishExecution()
{
_ai->stop();
_ai->setVisible(false);
//проверяем число ошибок, т.к. при выполнении без транзакции run() всегда возвращает 0
if (_errorCount == 0)
{
ExitCode rc(_updater->revisionBefore(), _updater->revisionAfter());
message(rc.message());
_exitCode = rc.exitCode();
closeDialog(); //при успешном завершении, то окно закрывается автоматически
}
else
{
_btnClose->show();
_btnSave->show();
_btnClose->setFocus();
message(QStringLiteral("Выполнение прервано в результате ошибки.\nБаза данных не изменилась."));
_exitCode = -1;
}
}
//---------------------------------------------------------------------------
int MainWindow::executeAction()
{
ProgramSettings pset;
processArguments(pset);
logon(pset);
_ai->start();
DatabaseUpdater updater;
connect(&updater, SIGNAL(progress(int)), _progress, SLOT(setValue(int)));
connect(&updater, SIGNAL(error(const QString&)), this, SLOT(error(const QString&)));
connect(&updater, SIGNAL(message(const QString&)), this, SLOT(message(const QString&)));
connect(&updater, SIGNAL(sqlError(const QString&, const QString&, const QString&)),
this, SLOT(sqlError(const QString&, const QString&, const QString&)));
connect(&updater, SIGNAL(logConnectionParameters(const QString&, const QString&, const QString&)),
this, SLOT(logConnectionParameters(const QString&, const QString&, const QString&)));
int rc = updater.run(pset);
//проверяем число ошибок, т.к. при выполнении без транзакции run() всегда возвращает 0
if (_errorCount == 0)
{
int before = updater.revisionBefore();
int after = updater.revisionAfter();
if (before == after)
message(QStringLiteral("База данных в актуальном состоянии."));
else if (before == 0)
message(QStringLiteral("База данных создана и обновлена до версии %1.").arg(after));
else
message(QStringLiteral("База данных версии %1 обновлена до версии %2.").arg(before).arg(after));
rc = (before & 0xFFFF) | ((after & 0xFFFF) << 16);
}
else
{
_btnClose->show();
_btnSave->show();
_btnClose->setFocus();
message(QStringLiteral("Выполнение прервано в результате ошибки."
"<br>База данных не изменилась."));
rc = -1;
}
return rc;
}
void MainWindow::processArguments(ProgramSettings& a_pset)
{
QString USERNAME_PARAM("username");
QString PASSWORD_PARAM("password");
QString DATABASE_PARAM("database");
QString DROPDB_PARAM("dropdb");
QString HOST_PARAM("host");
QString PORT_PARAM("port");
QString FILE_PARAM("file");
//заполнить параметры default значениями
QHash<QString, QString> params;
params.insert(USERNAME_PARAM, QString());
params.insert(PASSWORD_PARAM, QString());
params.insert(DATABASE_PARAM, QString());
params.insert(DROPDB_PARAM, QString());
params.insert(HOST_PARAM, QString());
params.insert(PORT_PARAM, QString());
params.insert(FILE_PARAM, QString());
//чтение аргументов
QString key;
QStringList arguments = QApplication::arguments();
auto end = arguments.cend();
auto begin = arguments.cbegin();
for (auto it = begin + 1; it != end; ++it) //пропускаем первый параметр - имя программы
{
QString curArg = *it;
if (curArg.at(0) == QChar('-'))
{ //обработка короткого параметра
key.clear();
switch (curArg.at(1).toLatin1())
{
case 'U':
key = USERNAME_PARAM;
break;
case 'd':
key = DATABASE_PARAM;
break;
case 'f':
key = FILE_PARAM;
break;
case 'h':
key = HOST_PARAM;
break;
case 'p':
key = PORT_PARAM;
break;
case 'W':
key = PASSWORD_PARAM;
break;
case '0':
params[ DROPDB_PARAM ] = '1';
break;
}
}
else
{ //обработка одиночного параметра
if (key.isEmpty())
key = FILE_PARAM;
params[ key ] = curArg;
key.clear();
}
}
//записать прочитанные значения в структуру ProgramSettings
a_pset.username = params.value(USERNAME_PARAM);
a_pset.password = params.value(PASSWORD_PARAM);
a_pset.database = params.value(DATABASE_PARAM);
a_pset.host = params.value(HOST_PARAM);
a_pset.port = params.value(PORT_PARAM);
a_pset.controlFile = params.value(FILE_PARAM);
a_pset.dropdb = !params.value(DROPDB_PARAM).isEmpty();
}
//---------------------------------------------------------------------------
void MainWindow::logon(ProgramSettings& a_pset)
{
if (!a_pset.host.isEmpty() || !a_pset.username.isEmpty())
return;
KLogon* logon = KLogon::create();
if (!logon)
return;
QString defaultDSN;
HKEY k;
DWORD cb = 0;
QString valuename("System Directory");
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\irs\\b03"), 0, KEY_QUERY_VALUE, &k) == ERROR_SUCCESS
&& RegQueryValueEx(k, LPCTSTR(valuename.constData()), 0, 0, 0, &cb) == ERROR_SUCCESS
&& cb > 0)
{
QString systemdir;
systemdir.resize((cb / sizeof(QChar)) - 1);
RegQueryValueEx(k, LPCTSTR(valuename.constData()), 0, 0, LPBYTE(systemdir.data()), &cb);
RegCloseKey(k);
KSettings systemini(systemdir + "/system.ini");
systemini.beginGroup("Database");
defaultDSN = systemini.value("DefaultDSN").toString();
}
QString username = QString::fromLocal8Bit(qgetenv("USERNAME"));
logon->setParent(winId());
logon->setUsername(username);
if (!defaultDSN.isNull())
logon->setDSN(defaultDSN);
if (!logon->execute())
emit message(QStringLiteral("Отказ от ввода имени и пароля пользователя"));
else
{
a_pset.host = logon->host();
a_pset.username = logon->username();
a_pset.password = logon->password();
}
delete logon;
}
//---------------------------------------------------------------------------
void MainWindow::logConnectionParameters(const QString& a_host,
const QString& a_database,
const QString& a_username)
{
message(QStringLiteral("Подключение к базе данных\n"
"\tСервер: **%1**\n\tБаза данных: **%2**\n"
"\tПользователь: **%3**")
.arg(a_host, a_database, a_username));
}
//---------------------------------------------------------------------------
void MainWindow::sqlError(const QString& a_dbError,
const QString& a_commandDescription,
const QString& a_command)
{
QString errorHtml;
if (!a_commandDescription.isEmpty())
errorHtml.append(QStringLiteral("<font color=\"#0000FF\">Операция:</font><br>")).append(a_commandDescription).append("<br>");
QString dbError = a_dbError;
errorHtml.append(QStringLiteral("<font color=\"#0000FF\">Сообщение об ошибке:</font><pre>")).append(dbError.trimmed().replace('\n', "<br>")).append("</pre>");
if (!a_command.isEmpty())
errorHtml.append(QStringLiteral("<font color=\"#0000FF\">Текст команды:</font><pre>")).append(a_command).append("</pre>");
errorHtmlToLog(errorHtml);
}
//---------------------------------------------------------------------------
void MainWindow::error(const QString& a_error)
{
QString errorHtml = a_error;
errorHtmlToLog(errorHtml.replace('<', "&lt;").replace('>', "&gt;").replace('\n', "<br>"));
}
//---------------------------------------------------------------------------
void MainWindow::errorHtmlToLog(const QString& a_errorHtml)
{
QString errorHtml = a_errorHtml;
QTextCursor cursor = _protocol->textCursor();
cursor.insertHtml(QStringLiteral("<font color=\"#0000FF\">Ошибка</font><br>"));
cursor.insertHtml(errorHtml);
cursor.insertHtml(QStringLiteral("<hr>"));
_protocol->moveCursor(QTextCursor::End);
++_errorCount;
}
QString MainWindow::toHtml(const QString& a_text)
{
QString result = a_text;
static const QString BOLD = QStringLiteral("**");
static const QString HTML_BOLD_BEGIN = QStringLiteral("<b>");
static const QString HTML_BOLD_END = QStringLiteral("</b>");
static const QString HTML_BR = QStringLiteral("<br>");
static const QString HTML_NBSP = QStringLiteral("&nbsp;&nbsp;");
static const QChar NL('\n');
static const QChar TAB('\t');
bool begin = true;
int pos = result.indexOf(BOLD);
while (pos >= 0)
{
result.replace(pos, BOLD.size(), begin ? HTML_BOLD_BEGIN : HTML_BOLD_END);
begin = !begin;
pos = result.indexOf(BOLD, pos + 1);
}
if (result.contains(NL))
result.replace(NL, HTML_BR);
if (result.contains(TAB))
result.replace(TAB, HTML_NBSP);
return result;
}
//---------------------------------------------------------------------------
void MainWindow::message(const QString& a_message)
{
QString message = a_message;
_protocol->textCursor().insertHtml(toHtml(message).append(QStringLiteral("<br>")));
_protocol->moveCursor(QTextCursor::End);
}
//---------------------------------------------------------------------------
void MainWindow::closeDialog()
{
QDialog::done(_exitCode);
}
//---------------------------------------------------------------------------
void MainWindow::saveProtocol()
{
QString filename = QFileDialog::getSaveFileName(this,
QStringLiteral("Сохранить протокол в файл…"), QString(),
QStringLiteral("Текстовые файлы (*.txt);;Все файлы (*.*)"));
if (!filename.isEmpty())
{
QFile outf(filename);
if (outf.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
QTextStream os(&outf);
os.setGenerateByteOrderMark(true);
os.setCodec("UTF-8");
os << _protocol->toPlainText();
}
}
}
//!главное окно приложения

File Metadata

Mime Type
text/x-diff
Expires
Wed, Jun 11, 8:15 PM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
127138

Event Timeline