Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F193419
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
21 KB
Subscribers
None
View Options
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -1,393 +1,401 @@
#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 <QStandardPaths>
#include <QStyle>
#include <QTextCodec>
#include <QTextEdit>
#include <QTimer>
#include <QVBoxLayout>
#include <QtConcurrentRun>
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags)
: QDialog(parent, flags)
, _exitCode(0)
, _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;
_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()));
QTimer::singleShot(0, this, SLOT(startExecution()));
}
MainWindow::~MainWindow()
{
delete _updater;
}
//---------------------------------------------------------------------------
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();
logon(pset);
+ _logFile = pset.logFile;
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;
}
+
+ if (!_logFile.isEmpty())
+ saveProtocol(_logFile);
}
//---------------------------------------------------------------------------
int MainWindow::executeAction()
{
ProgramSettings pset = processArguments();
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::logon(ProgramSettings& a_pset)
{
if (!a_pset.host.isEmpty() || !a_pset.username.isEmpty())
return;
KLogon* logon = KLogon::create();
if (!logon)
return;
QString defaultDSN;
QString ospoName;
HKEY k;
DWORD cb = 0;
QString valuename("System Directory");
if ((RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\irs\\b04"), 0, KEY_QUERY_VALUE, &k) == ERROR_SUCCESS
|| 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();
systemini.endGroup();
systemini.beginGroup("Common");
ospoName = systemini.value("SystemName").toString().replace(QLatin1Char('B'),QStringLiteral("ОСПО Б-"));
}
QString username = QString::fromLocal8Bit(qgetenv("USERNAME"));
QHash<QString, QString> aliases = loadAliases(ospoName);
if (aliases.contains(username))
username = aliases[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;
}
//---------------------------------------------------------------------------
QHash<QString, QString> MainWindow::loadAliases(const QString& a_ospoName)
{
QHash<QString, QString> result;
QApplication::setOrganizationName(a_ospoName);
QString filename = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).at(1);
filename.replace(QApplication::applicationName(), QStringLiteral("aliases.conf"));
QFile inf(filename);
if (inf.open(QIODevice::ReadOnly))
{
QTextStream is(&inf);
is.setCodec(QTextCodec::codecForName("UTF-8"));
while ( !is.atEnd() )
{
QStringList chunks = is.readLine().split(QLatin1Char(':'));
if (chunks.size() == 2)
result[chunks.at(0).trimmed()] = chunks.at(1).trimmed();
}
}
return result;
}
//---------------------------------------------------------------------------
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()
+void MainWindow::saveProtocol(const QString& a_fileName)
{
- QString filename = QFileDialog::getSaveFileName(this,
- QStringLiteral("Сохранить протокол в файл…"), QString(),
- QStringLiteral("Текстовые файлы (*.txt);;Все файлы (*.*)"));
+ QString filename = a_fileName;
+ if (filename.isEmpty())
+ 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();
}
}
}
//!главное окно приложения
diff --git a/src/mainwindow.h b/src/mainwindow.h
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -1,63 +1,64 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QDialog>
#include <QFutureWatcher>
#include <QString>
class QLabel;
class QListWidget;
class QPushButton;
class QProgressBar;
class QTextEdit;
class ProgramSettings;
class SqlErrorDialog;
class SqlProcessor;
class DatabaseUpdater;
class ProgramSettings;
class KActivityIndicator;
class MainWindow : public QDialog
{
Q_OBJECT
public:
MainWindow(QWidget* parent = 0, Qt::WindowFlags flags = 0);
~MainWindow() override;
private slots:
- void saveProtocol();
+ void saveProtocol(const QString& a_fileName = QString());
void closeDialog();
void startExecution();
void finishExecution();
void error(const QString& a_error);
void message(const QString& a_message);
void logConnectionParameters(const QString& a_host, const QString& a_database,
const QString& a_username);
void sqlError(const QString& a_dbError, const QString& a_commandDescription,
const QString& a_command);
protected:
void closeEvent(QCloseEvent* a_event) override;
private:
int executeAction();
void logon(ProgramSettings& a_pset);
void errorHtmlToLog(const QString& a_errorHtml);
static QString toHtml(const QString& a_text);
static QHash<QString, QString> loadAliases(const QString &a_ospoName);
int _exitCode;
int _errorCount;
+ QString _logFile;
QTextEdit* _protocol;
QLabel* _lblWait;
QPushButton* _btnSave;
QPushButton* _btnClose;
KActivityIndicator* _ai;
QProgressBar* _progress;
QFutureWatcher<int> _futureWatcher;
DatabaseUpdater* _updater;
};
//!главное окно приложения
#endif //MAINWINDOW_H
diff --git a/src/psettings.cpp b/src/psettings.cpp
--- a/src/psettings.cpp
+++ b/src/psettings.cpp
@@ -1,71 +1,73 @@
#include "psettings.h"
#include <QCommandLineParser>
ProgramSettings processArguments()
{
ProgramSettings result;
QString USERNAME_VALUE = QStringLiteral("пользователь");
QString PASSWORD_VALUE = QStringLiteral("пароль");
QString DATABASE_VALUE = QStringLiteral("база_данных");
QString HOST_VALUE = QStringLiteral("адрес_сервера");
QString PORT_VALUE = QStringLiteral("номер_порта");
QString FILE_VALUE = QStringLiteral("file.dmv");
QString LOGFILE_VALUE = QStringLiteral("файл_журнала");
QString USERNAME_OPTION = QStringLiteral("U");
QString PASSWORD_OPTION = QStringLiteral("W");
QString DATABASE_OPTION = QStringLiteral("d");
QString DROPDB_OPTION = QStringLiteral("0");
QString HOST_OPTION = QStringLiteral("h");
QString PORT_OPTION = QStringLiteral("p");
QString FILE_OPTION = QStringLiteral("f");
QString LOGFILE_OPTION = QStringLiteral("L");
QString URIDB_OPTION = QStringLiteral("u");
QString HELP_OPTION = QStringLiteral("help");
//обработать аргументы командной строки
QCommandLineParser parser;
QCommandLineOption helpOption(HELP_OPTION, QStringLiteral("Показать справку") );
parser.addOption(helpOption);
QCommandLineOption usernameOption(USERNAME_OPTION, QStringLiteral("Имя пользователя"), USERNAME_VALUE);
parser.addOption(usernameOption);
QCommandLineOption databaseOption(DATABASE_OPTION, QStringLiteral("Имя базы данных"), DATABASE_VALUE);
parser.addOption(databaseOption);
QCommandLineOption filenameOption(FILE_OPTION, QStringLiteral("Управляющий файл"), FILE_VALUE);
parser.addOption(filenameOption);
QCommandLineOption hostOption(HOST_OPTION, QStringLiteral("Адрес сервера"), HOST_VALUE);
parser.addOption(hostOption);
QCommandLineOption portOption(PORT_OPTION, QStringLiteral("Порт сервера"), PORT_VALUE);
parser.addOption(portOption);
QCommandLineOption passwordOption(PASSWORD_OPTION, QStringLiteral("Пароль"), PASSWORD_VALUE);
parser.addOption(passwordOption);
- QCommandLineOption logfileOption(LOGFILE_OPTION, QStringLiteral("Сохранить протокол работы в файл"), LOGFILE_VALUE);
- parser.addOption(logfileOption);
+ QCommandLineOption logFileOption(LOGFILE_OPTION, QStringLiteral("Сохранить протокол работы в файл"), LOGFILE_VALUE);
+ parser.addOption(logFileOption);
QCommandLineOption dropdbOption(DROPDB_OPTION, QStringLiteral("Сначала удалить базу данных"));
parser.addOption(dropdbOption);
QCommandLineOption uridbOption(URIDB_OPTION, QStringLiteral("Не создавать учебную базу данных"));
parser.addOption(uridbOption);
parser.addPositionalArgument(FILE_VALUE, QStringLiteral("Управляющий файл"), FILE_VALUE);
parser.process(*qApp);
//записать прочитанные значения в структуру ProgramSettings
result.username = parser.value(usernameOption);
result.password = parser.value(passwordOption);
result.database = parser.value(databaseOption);
result.host = parser.value(hostOption);
result.port = parser.value(portOption);
- result.logfile = parser.value(logfileOption);
+ result.logFile = parser.value(logFileOption);
result.dropdb = parser.isSet(dropdbOption);
result.uridb = !parser.isSet(uridbOption);
if (parser.isSet(filenameOption))
result.controlFile = parser.value(filenameOption);
else if (parser.positionalArguments().size() > 0)
result.controlFile = parser.positionalArguments().at(0);
+ if (parser.isSet(logFileOption))
+ result.logFile = parser.value(logFileOption);
if (parser.isSet(helpOption))
result.helpText = parser.helpText();
return result;
}
diff --git a/src/psettings.h b/src/psettings.h
--- a/src/psettings.h
+++ b/src/psettings.h
@@ -1,26 +1,26 @@
#if !defined PSETTINGS_H
#define PSETTINGS_H
#include <QString>
class ProgramSettings
{
public:
ProgramSettings() : dbVersion(0), dropdb(false), uridb(true) {}
QString username;
QString password;
QString database;
QString host;
QString port;
QString controlFile;
- QString logfile;
+ QString logFile;
QString packageId;
QString helpText;
int dbVersion;
bool dropdb;
bool uridb;
};
ProgramSettings processArguments();
#endif
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Jun 11, 8:14 PM (1 d, 12 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
126731
Attached To
rRCT Программа создания/обновления структуры БД
Event Timeline
Log In to Comment