diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,441 +1,441 @@ #include "stable.h" #include "mainwindow.h" #include "updater.h" #include "psettings.h" #include "sqlerrordlg.h" #include #include #include #include #ifdef Q_OS_WIN32 #include #endif //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- MainWindow::MainWindow( QWidget* parent, Qt::WindowFlags flags ) : QDialog( parent, flags ) , _exitCode( 0 ) , _actionEventType( QEvent::User ) , _errorCount( 0 ) , _updater( new DatabaseUpdater ) { setWindowTitle( QString::fromUtf8( "Создание/обновление базы данных" ) ); 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( QString::fromUtf8( "Сохранить" ) ); _btnClose = new QPushButton( QString::fromUtf8( "Закрыть" ) ); _btnSave->setVisible( false ); _btnClose->setVisible( false ); _btnClose->setDefault( true ); leftLayout->addWidget( picture ); leftLayout->addStretch(); leftLayout->addWidget( _btnSave ); leftLayout->addWidget( _btnClose ); QLabel* label = new QLabel( QString::fromUtf8( "Протокол работы" ) ); 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->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 rc = QtConcurrent::run( _updater, &DatabaseUpdater::run, pset ); _futureWatcher.setFuture( rc ); } //--------------------------------------------------------------------------- void MainWindow::finishExecution() { _ai->stop(); _ai->setVisible( false ); //проверяем число ошибок, т.к. при выполнении без транзакции run() всегда возвращает 0 if ( _errorCount == 0 ) { int before = _updater->revisionBefore(); int after = _updater->revisionAfter(); if ( before == after ) message( QString::fromUtf8( "База данных в актуальном состоянии." ) ); else if ( before == 0 ) message( QString::fromUtf8( "База данных создана и обновлена до версии %1." ).arg( after ) ); else message( QString::fromUtf8( "База данных версии %1 обновлена до версии %2." ). arg( before ).arg( after ) ); _exitCode = (before & 0xFFFF) | ((after & 0xFFFF) << 16); closeDialog(); //при успешном завершении, то окно закрывается автоматически } else { _btnClose->show(); _btnSave->show(); _btnClose->setFocus(); message( QString::fromUtf8( "Выполнение прервано в результате ошибки." "
База данных не изменилась.") ); _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( QString::fromUtf8( "База данных в актуальном состоянии." ) ); else if ( before == 0 ) message( QString::fromUtf8( "База данных создана и обновлена до версии %1." ).arg( after ) ); else message( QString::fromUtf8( "База данных версии %1 обновлена до версии %2." ). arg( before ).arg( after ) ); rc = (before & 0xFFFF) | ((after & 0xFFFF) << 16); } else { _btnClose->show(); _btnSave->show(); _btnClose->setFocus(); message( QString::fromUtf8( "Выполнение прервано в результате ошибки." "
База данных не изменилась.") ); 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 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; QString curArg; QStringListIterator args( QApplication::arguments() ); args.next(); //пропускаем первый параметр - имя программы while ( args.hasNext() ) { curArg = args.next(); if ( curArg.startsWith( "--" ) ) {//обработка длинного параметра curArg.remove( 0, 2 ); QMutableHashIterator option( params ); while ( option.hasNext() ) { option.next(); key = option.key(); if ( curArg.startsWith( key ) && curArg.at( key.size() ) == '=' ) option.setValue( curArg.right( curArg.size() - key.size() - 1 ) ); } key.clear(); } else 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; #if defined(Q_OS_WIN) 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( QString::fromUtf8( "Отказ от ввода имени и пароля пользователя" ) ); else { a_pset.host = logon->host(); a_pset.username = logon->username(); a_pset.password = logon->password(); } delete logon; #else QString username = QString::fromLocal8Bit( getenv( "USER" ) ); #endif } //--------------------------------------------------------------------------- void MainWindow::logConnectionParameters( const QString& a_host, const QString& a_database, const QString& a_username ) { message( QString::fromUtf8( "Подключение к базе данных
" "  Сервер: %1
  База данных: %2
" "  Пользователь: %3").arg( a_host, a_database, a_username ) ); } //--------------------------------------------------------------------------- void MainWindow::sqlError( const QString& a_dbError, const QString& a_commandDescription, const QString& a_command ) { QString s; if ( !a_commandDescription.isEmpty() ) s.append( QString::fromUtf8( "Операция:
%1
" ).arg( a_commandDescription ) ); s.append( QString::fromUtf8( "Сообщение об ошибке:
%1" ).arg( a_dbError ) ); if ( !a_command.isEmpty() ) s.append( QString::fromUtf8( "Текст команды:
%1
" ).arg( a_command ) ); error( s ); } //--------------------------------------------------------------------------- void MainWindow::error( const QString& a_error ) { QString error = a_error; QTextCursor cursor = _protocol->textCursor(); cursor.insertHtml( QString::fromUtf8( "Ошибка
" ) ); - cursor.insertHtml( error.replace( QChar('\n'), "
" ) ); + cursor.insertHtml( error.replace( '<', "<" ).replace( '>', ">" ).replace( QChar('\n'), "
" ) ); cursor.insertHtml( QString::fromUtf8( "
" ) ); _protocol->moveCursor( QTextCursor::End ); ++_errorCount; } //--------------------------------------------------------------------------- void MainWindow::message( const QString& a_message ) { QString message = a_message; _protocol->textCursor().insertHtml( message.replace( QChar('\n'), "
" ).append( "
" ) ); _protocol->moveCursor( QTextCursor::End ); } //--------------------------------------------------------------------------- void MainWindow::closeDialog() { QDialog::done( _exitCode ); } //--------------------------------------------------------------------------- void MainWindow::saveProtocol() { QString filename = QFileDialog::getSaveFileName( this, QString::fromUtf8( "Сохранить протокол в файл…" ), QString(), QString::fromUtf8( "Текстовые файлы (*.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(); //toPlainText(); } } } //!главное окно приложения