Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F193421
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
18 KB
Subscribers
None
View Options
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('<', "<").replace('>', ">").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(" ");
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
Details
Attached
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
Attached To
rRCT Программа создания/обновления структуры БД
Event Timeline
Log In to Comment