diff --git a/src/migration/importtablewizard.cpp b/src/migration/importtablewizard.cpp index 2a0d6ceef..84223666e 100644 --- a/src/migration/importtablewizard.cpp +++ b/src/migration/importtablewizard.cpp @@ -1,785 +1,797 @@ /* This file is part of the KDE project Copyright (C) 2009 Adam Pigg Copyright (C) 2014-2016 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "importtablewizard.h" #include "importoptionsdlg.h" #include "migratemanager.h" #include "keximigrate.h" #include "keximigratedata.h" #include "AlterSchemaWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KexiMigration; #define RECORDS_FOR_PREVIEW 3 ImportTableWizard::ImportTableWizard ( KDbConnection* curDB, QWidget* parent, QMap* args, Qt::WindowFlags flags) : KAssistantDialog ( parent, flags ), m_args(args) { m_connection = curDB; m_migrateDriver = 0; m_prjSet = 0; m_importComplete = false; m_importWasCanceled = false; m_sourceDbEncoding = QString::fromLatin1(KexiUtils::encoding()); //default KexiMainWindowIface::global()->setReasonableDialogSize(this); setupIntroPage(); setupSrcConn(); setupSrcDB(); setupTableSelectPage(); setupAlterTablePage(); setupImportingPage(); setupProgressPage(); setupFinishPage(); setValid(m_srcConnPageItem, false); connect(this, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), this, SLOT(slot_currentPageChanged(KPageWidgetItem*,KPageWidgetItem*))); //! @todo Change this to message prompt when we move to non-dialog wizard. - connect(m_srcConnSel, SIGNAL(connectionSelected(bool)), this, SLOT(slotConnPageItemSelected(bool))); + connect(m_srcConnSel, SIGNAL(connectionSelected(bool)), this, + SLOT(slotConnPageItemSelected(bool))); + connect(m_srcConnSel, &KexiConnectionSelectorWidget::connectionItemHighlighted, + [this]() { setValid(m_srcConnPageItem, true); }); + connect(m_srcConnSel, &KexiConnectionSelectorWidget::connectionItemExecuted, [this]() { + setValid(m_srcConnPageItem, true); + next(); + }); } ImportTableWizard::~ImportTableWizard() { delete m_prjSet; delete m_srcConnSel; } void ImportTableWizard::back() { KAssistantDialog::back(); } void ImportTableWizard::next() { if (currentPage() == m_srcConnPageItem) { if (fileBasedSrcSelected()) { setAppropriate(m_srcDBPageItem, false); } else { setAppropriate(m_srcDBPageItem, true); } } else if (currentPage() == m_alterTablePageItem) { if (m_alterSchemaWidget->nameExists(m_alterSchemaWidget->nameWidget()->nameText())) { KMessageBox::information(this, xi18nc("@info", "%1 name is already used by an existing table. " "Enter different table name to continue.", m_alterSchemaWidget->nameWidget()->nameText()), xi18n("Name Already Used")); return; } } KAssistantDialog::next(); } void ImportTableWizard::accept() { if (m_args) { if (m_finishCheckBox->isChecked()) { m_args->insert("destinationTableName",m_alterSchemaWidget->nameWidget()->nameText()); } else { m_args->remove("destinationTableName"); } } QDialog::accept(); } void ImportTableWizard::reject() { QDialog::reject(); } //=========================================================== // void ImportTableWizard::setupIntroPage() { m_introPageWidget = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(); m_introPageWidget->setLayout(vbox); KexiUtils::setStandardMarginsAndSpacing(vbox); QLabel *lblIntro = new QLabel(m_introPageWidget); lblIntro->setAlignment(Qt::AlignTop | Qt::AlignLeft); lblIntro->setWordWrap(true); lblIntro->setText( xi18nc("@info", "Table Importing Assistant allows you to import a table from an existing " "database into the current Kexi project." "Click Next button to continue or " "Cancel button to exit this assistant.")); vbox->addWidget(lblIntro); m_introPageItem = new KPageWidgetItem(m_introPageWidget, xi18n("Welcome to the Table Importing Assistant")); addPage(m_introPageItem); } void ImportTableWizard::setupSrcConn() { m_srcConnPageWidget = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(m_srcConnPageWidget); m_srcConnSel = new KexiConnectionSelectorWidget(&Kexi::connset(), QUrl("kfiledialog:///ProjectMigrationSourceDir"), KexiConnectionSelectorWidget::Opening, m_srcConnPageWidget); m_srcConnSel->hideConnectonIcon(); m_srcConnSel->showSimpleConnection(); //! @todo remove when support for kexi files as source prj is added in migration const QStringList excludedMimeTypes({ KDb::defaultFileBasedDriverMimeType(), "application/x-kexiproject-shortcut", "application/x-kexi-connectiondata"}); m_srcConnSel->setExcludedMimeTypes(excludedMimeTypes); vbox->addWidget(m_srcConnSel); m_srcConnPageItem = new KPageWidgetItem(m_srcConnPageWidget, xi18n("Select Location for Source Database")); addPage(m_srcConnPageItem); } void ImportTableWizard::setupSrcDB() { // arrivesrcdbPage creates widgets on that page m_srcDBPageWidget = new QWidget(this); m_srcDBName = NULL; m_srcDBPageItem = new KPageWidgetItem(m_srcDBPageWidget, xi18n("Select Source Database")); addPage(m_srcDBPageItem); } void ImportTableWizard::setupTableSelectPage() { m_tablesPageWidget = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(m_tablesPageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); m_tableListWidget = new QListWidget(this); m_tableListWidget->setSelectionMode(QAbstractItemView::SingleSelection); connect(m_tableListWidget, SIGNAL(itemSelectionChanged()), this, SLOT(slotTableListWidgetSelectionChanged())); vbox->addWidget(m_tableListWidget); m_tablesPageItem = new KPageWidgetItem(m_tablesPageWidget, xi18n("Select the Table to Import")); addPage(m_tablesPageItem); } //=========================================================== // void ImportTableWizard::setupImportingPage() { m_importingPageWidget = new QWidget(this); m_importingPageWidget->hide(); QVBoxLayout *vbox = new QVBoxLayout(m_importingPageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); m_lblImportingTxt = new QLabel(m_importingPageWidget); m_lblImportingTxt->setAlignment(Qt::AlignTop | Qt::AlignLeft); m_lblImportingTxt->setWordWrap(true); m_lblImportingErrTxt = new QLabel(m_importingPageWidget); m_lblImportingErrTxt->setAlignment(Qt::AlignTop | Qt::AlignLeft); m_lblImportingErrTxt->setWordWrap(true); vbox->addWidget(m_lblImportingTxt); vbox->addWidget(m_lblImportingErrTxt); vbox->addStretch(1); QWidget *options_widget = new QWidget(m_importingPageWidget); vbox->addWidget(options_widget); QVBoxLayout *options_vbox = new QVBoxLayout(options_widget); options_vbox->setSpacing(KexiUtils::spacingHint()); m_importOptionsButton = new QPushButton(koIcon("configure"), xi18n("Advanced Options"), options_widget); connect(m_importOptionsButton, SIGNAL(clicked()),this, SLOT(slotOptionsButtonClicked())); options_vbox->addWidget(m_importOptionsButton); options_vbox->addStretch(1); m_importingPageWidget->show(); m_importingPageItem = new KPageWidgetItem(m_importingPageWidget, xi18n("Importing")); addPage(m_importingPageItem); } void ImportTableWizard::setupAlterTablePage() { m_alterTablePageWidget = new QWidget(this); m_alterTablePageWidget->hide(); QVBoxLayout *vbox = new QVBoxLayout(m_alterTablePageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); m_alterSchemaWidget = new KexiMigration::AlterSchemaWidget(this); vbox->addWidget(m_alterSchemaWidget); m_alterTablePageWidget->show(); m_alterTablePageItem = new KPageWidgetItem(m_alterTablePageWidget, xi18n("Alter the Detected Table Design")); addPage(m_alterTablePageItem); } void ImportTableWizard::setupProgressPage() { m_progressPageWidget = new QWidget(this); m_progressPageWidget->hide(); QVBoxLayout *vbox = new QVBoxLayout(m_progressPageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); m_progressPageWidget->setLayout(vbox); m_progressLbl = new QLabel(m_progressPageWidget); m_progressLbl->setAlignment(Qt::AlignTop | Qt::AlignLeft); m_progressLbl->setWordWrap(true); m_rowsImportedLbl = new QLabel(m_progressPageWidget); m_importingProgressBar = new QProgressBar(m_progressPageWidget); m_importingProgressBar->setMinimum(0); m_importingProgressBar->setMaximum(0); m_importingProgressBar->setValue(0); vbox->addWidget(m_progressLbl); vbox->addWidget(m_rowsImportedLbl); vbox->addWidget(m_importingProgressBar); vbox->addStretch(1); m_progressPageItem = new KPageWidgetItem(m_progressPageWidget, xi18n("Processing Import")); addPage(m_progressPageItem); } void ImportTableWizard::setupFinishPage() { m_finishPageWidget = new QWidget(this); m_finishPageWidget->hide(); QVBoxLayout *vbox = new QVBoxLayout(m_finishPageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); m_finishLbl = new QLabel(m_finishPageWidget); m_finishLbl->setAlignment(Qt::AlignTop | Qt::AlignLeft); m_finishLbl->setWordWrap(true); vbox->addWidget(m_finishLbl); m_finishCheckBox = new QCheckBox(xi18n("Open imported table"), m_finishPageWidget); m_finishCheckBox->setChecked(true); vbox->addSpacing(KexiUtils::spacingHint()); vbox->addWidget(m_finishCheckBox); vbox->addStretch(1); m_finishPageItem = new KPageWidgetItem(m_finishPageWidget, xi18n("Success")); addPage(m_finishPageItem); } void ImportTableWizard::slot_currentPageChanged(KPageWidgetItem* curPage,KPageWidgetItem* prevPage) { Q_UNUSED(prevPage); if (curPage == m_introPageItem) { } else if (curPage == m_srcConnPageItem) { arriveSrcConnPage(); } else if (curPage == m_srcDBPageItem) { arriveSrcDBPage(); } else if (curPage == m_tablesPageItem) { arriveTableSelectPage(prevPage); } else if (curPage == m_alterTablePageItem) { if (prevPage == m_tablesPageItem) { arriveAlterTablePage(); } } else if (curPage == m_importingPageItem) { arriveImportingPage(); } else if (curPage == m_progressPageItem) { arriveProgressPage(); } else if (curPage == m_finishPageItem) { arriveFinishPage(); } } void ImportTableWizard::arriveSrcConnPage() { } void ImportTableWizard::arriveSrcDBPage() { if (fileBasedSrcSelected()) { //! @todo Back button doesn't work after selecting a file to import - } else if (!m_srcDBName) { + } else { + delete m_prjSet; + m_prjSet = 0; m_srcDBPageWidget->hide(); qDebug() << "Looks like we need a project selector widget!"; KDbConnectionData* conndata = m_srcConnSel->selectedConnectionData(); if (conndata) { KexiGUIMessageHandler handler; m_prjSet = new KexiProjectSet(&handler); if (!m_prjSet->setConnectionData(conndata)) { handler.showErrorMessage(m_prjSet->result()); delete m_prjSet; m_prjSet = 0; return; } - QVBoxLayout *vbox = new QVBoxLayout(m_srcDBPageWidget); - KexiUtils::setStandardMarginsAndSpacing(vbox); - m_srcDBName = new KexiProjectSelectorWidget(m_srcDBPageWidget, m_prjSet); - vbox->addWidget(m_srcDBName); - m_srcDBName->label()->setText(xi18n("Select source database you wish to import:")); + if (!m_srcDBName) { + QVBoxLayout *vbox = new QVBoxLayout(m_srcDBPageWidget); + KexiUtils::setStandardMarginsAndSpacing(vbox); + m_srcDBName = new KexiProjectSelectorWidget(m_srcDBPageWidget); + vbox->addWidget(m_srcDBName); + m_srcDBName->label()->setText(xi18n("Select source database you wish to import:")); + } + m_srcDBName->setProjectSet(m_prjSet); } m_srcDBPageWidget->show(); } } void ImportTableWizard::arriveTableSelectPage(KPageWidgetItem *prevPage) { if (prevPage == m_alterTablePageItem) { if (m_tableListWidget->count() == 1) { //we was skiping it before back(); } } else { Kexi::ObjectStatus result; KexiUtils::WaitCursor wait; m_tableListWidget->clear(); m_migrateDriver = prepareImport(&result); bool ok = m_migrateDriver; if (ok) { if (!m_sourceDbEncoding.isEmpty()) { m_migrateDriver->setPropertyValue( "source_database_nonunicode_encoding", QVariant(m_sourceDbEncoding.toUpper().remove(' ')) // "CP1250", not "cp 1250" ); } ok = m_migrateDriver->connectSource(&result); } if (ok) { QStringList tableNames; if (m_migrateDriver->tableNames(&tableNames)) { m_tableListWidget->addItems(tableNames); } if (m_tableListWidget->item(0)) { m_tableListWidget->item(0)->setSelected(true); if (m_tableListWidget->count() == 1) { KexiUtils::removeWaitCursor(); next(); } } } KexiUtils::removeWaitCursor(); if (!ok) { QString errMessage =result.message.isEmpty() ? xi18n("Unknown error") : result.message; QString errDescription = result.description.isEmpty() ? errMessage : result.description; KMessageBox::error(this, errMessage, errDescription); setValid(m_tablesPageItem, false); } } } void ImportTableWizard::arriveAlterTablePage() { //! @todo handle errors if (m_tableListWidget->selectedItems().isEmpty()) return; //! @todo (js) support multiple tables? #if 0 foreach(QListWidgetItem *table, m_tableListWidget->selectedItems()) { m_importTableName = table->text(); } #else m_importTableName = m_tableListWidget->selectedItems().first()->text(); #endif QScopedPointer ts(new KDbTableSchema); if (!m_migrateDriver->readTableSchema(m_importTableName, ts.data())) { return; } setValid(m_alterTablePageItem, ts->fieldCount() > 0); if (isValid(m_alterTablePageItem)) { connect(m_alterSchemaWidget->nameWidget(), SIGNAL(textChanged()), this, SLOT(slotNameChanged()), Qt::UniqueConnection); } m_alterSchemaWidget->setTableSchema(ts.take()); if (!readFromTable()) { m_alterSchemaWidget->setTableSchema(nullptr); back(); KMessageBox::information(this, xi18nc("@info", "Could not import table %1. " "Select different table or cancel importing.", m_importTableName)); } } bool ImportTableWizard::readFromTable() { QSharedPointer tableResult = m_migrateDriver->readFromTable(m_importTableName); KDbTableSchema *newSchema = m_alterSchemaWidget->newSchema(); if (!tableResult || tableResult->lastResult().isError() || tableResult->fieldsCount() != newSchema->fieldCount()) { back(); KMessageBox::information(this, xi18nc("@info", "Could not import table %1. " "Select different table or cancel importing.", m_importTableName)); return false; } QScopedPointer> data(new QList); for (int i = 0; i < RECORDS_FOR_PREVIEW; ++i) { QSharedPointer record(tableResult->fetchRecordData()); if (!record) { if (tableResult->lastResult().isError()) { return false; } break; } data->append(record.data()); } if (data->isEmpty()) { back(); KMessageBox::information(this, xi18nc("@info", "No data has been found in table %1. " "Select different table or cancel importing.", m_importTableName)); return false; } m_alterSchemaWidget->model()->setRowCount(data->count()); m_alterSchemaWidget->setData(data.take()); return true; } void ImportTableWizard::arriveImportingPage() { m_importingPageWidget->hide(); #if 0 if (checkUserInput()) { //setNextEnabled(m_importingPageWidget, true); user2Button->setEnabled(true); } else { //setNextEnabled(m_importingPageWidget, false); user2Button->setEnabled(false); } #endif QString txt; txt = xi18nc("@info Table import wizard, final message", "All required information has now been gathered. " "Click Next button to start importing table %1." "Depending on size of the table this may take some time.", m_alterSchemaWidget->nameWidget()->nameText()); m_lblImportingTxt->setText(txt); //temp. hack for MS Access driver only //! @todo for other databases we will need KexiMigration::Connection //! and KexiMigration::Driver classes bool showOptions = false; if (fileBasedSrcSelected()) { Kexi::ObjectStatus result; KexiMigrate* sourceDriver = prepareImport(&result); if (sourceDriver) { showOptions = !result.error() && sourceDriver->propertyValue("source_database_has_nonunicode_encoding").toBool(); sourceDriver->setData(nullptr); } } if (showOptions) m_importOptionsButton->show(); else m_importOptionsButton->hide(); m_importingPageWidget->show(); setAppropriate(m_progressPageItem, true); } void ImportTableWizard::arriveProgressPage() { m_progressLbl->setText(xi18nc("@info", "Please wait while the table is imported.")); backButton()->setEnabled(false); nextButton()->setEnabled(false); connect(button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &ImportTableWizard::slotCancelClicked); QApplication::setOverrideCursor(Qt::BusyCursor); m_importComplete = doImport(); QApplication::restoreOverrideCursor(); disconnect(button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &ImportTableWizard::slotCancelClicked); next(); } void ImportTableWizard::arriveFinishPage() { if (m_importComplete) { m_finishPageItem->setHeader(xi18n("Success")); m_finishLbl->setText(xi18nc("@info", "Table %1 has been imported.", m_alterSchemaWidget->nameWidget()->nameText())); } else { m_finishPageItem->setHeader(xi18n("Failure")); m_finishLbl->setText(xi18n("An error occurred.")); } m_migrateDriver->disconnectSource(); button(QDialogButtonBox::Cancel)->setEnabled(!m_importComplete); m_finishCheckBox->setVisible(m_importComplete); finishButton()->setEnabled(m_importComplete); nextButton()->setEnabled(m_importComplete); setAppropriate(m_progressPageItem, false); } bool ImportTableWizard::fileBasedSrcSelected() const { return m_srcConnSel->selectedConnectionType() == KexiConnectionSelectorWidget::FileBased; } KexiMigrate* ImportTableWizard::prepareImport(Kexi::ObjectStatus *result) { Q_ASSERT(result); // Find a source (migration) driver name QString sourceDriverId = driverIdForSelectedSource(); if (sourceDriverId.isEmpty()) { result->setStatus(xi18n("No appropriate migration driver found."), m_migrateManager.possibleProblemsMessage()); } // Get a source (migration) driver KexiMigrate* sourceDriver = 0; if (!result->error()) { sourceDriver = m_migrateManager.driver(sourceDriverId); if (!sourceDriver || m_migrateManager.result().isError()) { qDebug() << "Import migrate driver error..."; result->setStatus(m_migrateManager.resultable()); } } // Set up source (migration) data required for connection if (sourceDriver && !result->error()) { #if 0 // Setup progress feedback for the GUI if (sourceDriver->progressSupported()) { m_progressBar->updateGeometry(); disconnect(sourceDriver, SIGNAL(progressPercent(int)), this, SLOT(progressUpdated(int))); connect(sourceDriver, SIGNAL(progressPercent(int)), this, SLOT(progressUpdated(int))); progressUpdated(0); } #endif bool keepData = true; #if 0 if (m_importTypeStructureAndDataCheckBox->isChecked()) { qDebug() << "Structure and data selected"; keepData = true; } else if (m_importTypeStructureOnlyCheckBox->isChecked()) { qDebug() << "structure only selected"; keepData = false; } else { qDebug() << "Neither radio button is selected (not possible?) presume keep data"; keepData = true; } #endif KexiMigration::Data* md = new KexiMigration::Data(); if (fileBasedSrcSelected()) { KDbConnectionData* conn_data = new KDbConnectionData(); conn_data->setDatabaseName(m_srcConnSel->selectedFile()); md->source = conn_data; md->sourceName.clear(); } else { md->source = m_srcConnSel->selectedConnectionData(); md->sourceName = m_srcDBName->selectedProjectData()->databaseName(); } md->setShouldCopyData(keepData); sourceDriver->setData(md); return sourceDriver; } return 0; } //=========================================================== // QString ImportTableWizard::driverIdForSelectedSource() { if (fileBasedSrcSelected()) { QMimeDatabase db; QMimeType mime = db.mimeTypeForFile(m_srcConnSel->selectedFile()); if (!mime.isValid() || mime.name() == "application/octet-stream" || mime.name() == "text/plain" || mime.name() == "application/zip") { //try by URL: mime = db.mimeTypeForFile(m_srcConnSel->selectedFile()); } if (!mime.isValid()) { return QString(); } const QStringList ids(m_migrateManager.driverIdsForMimeType(mime.name())); //! @todo do we want to return first migrate driver for the mime type or allow to select it? return ids.isEmpty() ? QString() : ids.first(); } return m_srcConnSel->selectedConnectionData() ? m_srcConnSel->selectedConnectionData()->databaseName() : QString(); } bool ImportTableWizard::doImport() { KexiGUIMessageHandler msg; KexiProject* project = KexiMainWindowIface::global()->project(); if (!project) { msg.showErrorMessage(KDbMessageHandler::Error, xi18n("No project available.")); return false; } KexiPart::Part *part = Kexi::partManager().partForPluginId("org.kexi-project.table"); if (!part) { msg.showErrorMessage(Kexi::partManager().result()); return false; } KDbTableSchema* newSchema = m_alterSchemaWidget->newSchema(); if (!newSchema) { msg.showErrorMessage(KDbMessageHandler::Error, xi18n("No table was selected to import.")); return false; } newSchema->setName(m_alterSchemaWidget->nameWidget()->nameText()); newSchema->setCaption(m_alterSchemaWidget->nameWidget()->captionText()); KexiPart::Item* partItemForSavedTable = project->createPartItem(part->info(), newSchema->name()); if (!partItemForSavedTable) { msg.showErrorMessage(project->result()); return false; } //Create the table if (!m_connection->createTable(newSchema, KDbConnection::CreateTableOption::Default | KDbConnection::CreateTableOption::DropDestination)) { msg.showErrorMessage(KDbMessageHandler::Error, xi18nc("@info", "Unable to create table %1.", newSchema->name())); return false; } m_alterSchemaWidget->takeTableSchema(); //m_connection takes ownership of the KDbTableSchema object //Import the data QApplication::setOverrideCursor(Qt::BusyCursor); QList row; unsigned int fieldCount = newSchema->fieldCount(); m_migrateDriver->moveFirst(); KDbTransactionGuard tg(m_connection); if (m_connection->result().isError()) { QApplication::restoreOverrideCursor(); return false; } do { for (unsigned int i = 0; i < fieldCount; ++i) { if (m_importWasCanceled) { return false; } if (i % 100 == 0) { QApplication::processEvents(); } row.append(m_migrateDriver->value(i)); } m_connection->insertRecord(newSchema, row); row.clear(); } while (m_migrateDriver->moveNext()); if (!tg.commit()) { QApplication::restoreOverrideCursor(); return false; } QApplication::restoreOverrideCursor(); //Done so save part and update gui partItemForSavedTable->setIdentifier(newSchema->id()); project->addStoredItem(part->info(), partItemForSavedTable); return true; } void ImportTableWizard::slotConnPageItemSelected(bool isSelected) { setValid(m_srcConnPageItem, isSelected); if (isSelected && fileBasedSrcSelected()) { next(); } } void ImportTableWizard::slotTableListWidgetSelectionChanged() { setValid(m_tablesPageItem, !m_tableListWidget->selectedItems().isEmpty()); } void ImportTableWizard::slotNameChanged() { setValid(m_alterTablePageItem, !m_alterSchemaWidget->nameWidget()->captionText().isEmpty()); } void ImportTableWizard::slotCancelClicked() { m_importWasCanceled = true; } void ImportTableWizard::slotOptionsButtonClicked() { OptionsDialog dlg(m_srcConnSel->selectedFile(), m_sourceDbEncoding, this); if (QDialog::Accepted == dlg.exec()) { m_sourceDbEncoding = dlg.encodingComboBox()->selectedEncoding(); } } diff --git a/src/widget/KexiConnectionSelectorWidget.cpp b/src/widget/KexiConnectionSelectorWidget.cpp index 60f5c4781..412848a6e 100644 --- a/src/widget/KexiConnectionSelectorWidget.cpp +++ b/src/widget/KexiConnectionSelectorWidget.cpp @@ -1,551 +1,552 @@ /* This file is part of the KDE project Copyright (C) 2003-2017 Jarosław Staniek Copyright (C) 2012 Dimitrios T. Tanis This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KexiConnectionSelectorWidget.h" #include "ui_KexiConnectionSelector.h" #include "kexiprjtypeselector.h" #include "kexidbconnectionwidget.h" #include "KexiFileWidgetInterface.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class KexiConnectionSelector : public QWidget, public Ui_KexiConnectionSelector { Q_OBJECT public: explicit KexiConnectionSelector(QWidget *parent) : QWidget(parent) { setupUi(this); setObjectName("conn_sel"); lblIcon->setPixmap(koDesktopIconCStr(Kexi::serverIconName())); lblIcon->setFixedSize(lblIcon->pixmap()->size()); btn_add->setToolTip(xi18n("Add a new database connection")); btn_edit->setToolTip(xi18n("Edit selected database connection")); btn_remove->setToolTip(xi18n("Delete selected database connections")); } ~KexiConnectionSelector() { } }; /*================================================================*/ ConnectionDataLVItem::ConnectionDataLVItem(KDbConnectionData *data, const KDbDriverMetaData &driverMetaData, QTreeWidget* list) : QTreeWidgetItem(list) , m_data(data) { update(driverMetaData); } ConnectionDataLVItem::~ConnectionDataLVItem() { } void ConnectionDataLVItem::update(const KDbDriverMetaData &driverMetaData) { setText(0, m_data->caption() + " "); const QString sfile = xi18n("File"); QString driverName = driverMetaData.name(); QString column1; if (driverMetaData.isFileBased()) { column1 = xi18nc("file (driver name)", "%1 (%2)", sfile, driverName); } else { column1 = driverName; } setText(1, column1 + " "); setText(2, (driverMetaData.isFileBased() ? QString("<%1>").arg(sfile.toLower()) : m_data->toUserVisibleString()) + " "); } /*================================================================*/ //! @internal class Q_DECL_HIDDEN KexiConnectionSelectorWidget::Private { public: Private() : conn_sel_shown(false) , confirmOverwrites(true) { } void updateRemoteListColumns() { remote->list->resizeColumnToContents(0); // name remote->list->resizeColumnToContents(1); // type } QWidget *fileWidget() { return fileIface ? fileIface->widget() : nullptr; } KexiFileWidgetInterface *fileIface = nullptr; KexiConnectionSelector *remote; QWidget* openExistingWidget; KexiPrjTypeSelector* prjTypeSelector; QUrl startDirOrVariable; KexiConnectionSelectorWidget::OperationMode operationMode; QStackedWidget *stack; QPointer conn_set; KDbDriverManager manager; bool conn_sel_shown; //!< helper bool confirmOverwrites; KexiUtils::PaintBlocker* descGroupBoxPaintBlocker; bool isConnectionSelected; bool fileWidgetFrameVisible = true; QPointer errorMessagePopup; }; /*================================================================*/ KexiConnectionSelectorWidget::KexiConnectionSelectorWidget( KexiDBConnectionSet *conn_set, const QUrl& startDirOrVariable, OperationMode mode, QWidget* parent) : QWidget(parent) , d(new Private()) { Q_ASSERT(conn_set); d->conn_set = conn_set; d->startDirOrVariable = startDirOrVariable; d->operationMode = mode; setWindowIcon(Kexi::defaultFileBasedDriverIcon()); QBoxLayout* globalLyr = new QVBoxLayout(this); globalLyr->setContentsMargins(QMargins()); //create header with radio buttons d->openExistingWidget = new QWidget(this); d->openExistingWidget->setObjectName("openExistingWidget"); QVBoxLayout* openExistingWidgetLyr = new QVBoxLayout(d->openExistingWidget); openExistingWidgetLyr->setContentsMargins(0, 0, 0, 0); d->prjTypeSelector = new KexiPrjTypeSelector(d->openExistingWidget); connect(d->prjTypeSelector->buttonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(slotPrjTypeSelected(QAbstractButton*))); openExistingWidgetLyr->addWidget(d->prjTypeSelector); d->prjTypeSelector->setContentsMargins(0, 0, 0, KexiUtils::spacingHint()); //openExistingWidgetLyr->addSpacing(KexiUtils::spacingHint()); QFrame* line = new QFrame(d->openExistingWidget); line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); openExistingWidgetLyr->addWidget(line); globalLyr->addWidget(d->openExistingWidget); d->stack = new QStackedWidget(this); d->stack->setObjectName("stack"); globalLyr->addWidget(d->stack, 1); d->remote = new KexiConnectionSelector(d->stack); connect(d->remote->btn_add, SIGNAL(clicked()), this, SLOT(slotRemoteAddBtnClicked())); connect(d->remote->btn_edit, SIGNAL(clicked()), this, SLOT(slotRemoteEditBtnClicked())); connect(d->remote->btn_remove, SIGNAL(clicked()), this, SLOT(slotRemoteRemoveBtnClicked())); d->stack->addWidget(d->remote); if (d->remote->layout()) d->remote->layout()->setMargin(0); connect(d->remote->list, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotConnectionItemExecuted(QTreeWidgetItem*))); connect(d->remote->list, SIGNAL(itemSelectionChanged()), this, SLOT(slotConnectionSelectionChanged())); d->remote->list->installEventFilter(this); d->descGroupBoxPaintBlocker = new KexiUtils::PaintBlocker(d->remote->descGroupBox); d->descGroupBoxPaintBlocker->setEnabled(false); d->isConnectionSelected = false; } KexiConnectionSelectorWidget::~KexiConnectionSelectorWidget() { delete d; } void KexiConnectionSelectorWidget::showAdvancedConnection() { d->prjTypeSelector->option_server->setChecked(true); slotPrjTypeSelected(d->prjTypeSelector->option_server); } void KexiConnectionSelectorWidget::slotPrjTypeSelected(QAbstractButton *btn) { if (btn == d->prjTypeSelector->option_file) { //file-based prj type showSimpleConnection(); } else if (btn == d->prjTypeSelector->option_server) { //server-based prj type if (KDbDriverManager().hasDatabaseServerDrivers()) { if (!d->conn_sel_shown) { d->conn_sel_shown = true; //show connections (on demand): foreach(KDbConnectionData* connData, d->conn_set->list()) { addConnectionData(connData); // else { //this error should be more verbose: // qWarning() << "no driver found for '" << it.current()->driverName << "'!"; // } } if (d->remote->list->topLevelItemCount() > 0) { d->updateRemoteListColumns(); d->remote->list->sortByColumn(0, Qt::AscendingOrder); d->remote->list->topLevelItem(0)->setSelected(true); } d->remote->descGroupBox->layout()->setMargin(2); d->remote->list->setFocus(); slotConnectionSelectionChanged(); } d->stack->setCurrentWidget(d->remote); } else { if (!d->errorMessagePopup) { QWidget *errorMessagePopupParent = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(errorMessagePopupParent); d->errorMessagePopup = new KexiServerDriverNotFoundMessage(errorMessagePopupParent); vbox->addWidget(d->errorMessagePopup); vbox->addStretch(0); d->stack->addWidget(errorMessagePopupParent); d->errorMessagePopup->setAutoDelete(false); d->stack->setCurrentWidget(d->errorMessagePopup->parentWidget()); d->errorMessagePopup->animatedShow(); } else { d->stack->setCurrentWidget(d->errorMessagePopup->parentWidget()); } } } } ConnectionDataLVItem* KexiConnectionSelectorWidget::addConnectionData(KDbConnectionData* data) { const KDbDriverMetaData* driverMetaData = d->manager.driverMetaData(data->driverId()); return driverMetaData ? new ConnectionDataLVItem(data, *driverMetaData, d->remote->list) : 0; } void KexiConnectionSelectorWidget::showSimpleConnection() { d->prjTypeSelector->option_file->setChecked(true); if (!d->fileIface) { d->fileIface = KexiFileWidgetInterface::createWidget( d->startDirOrVariable, d->operationMode == Opening ? KexiFileFilters::Opening : KexiFileFilters::SavingFileBasedDB, d->stack); d->fileIface->setWidgetFrame(d->fileWidgetFrameVisible); d->fileIface->setConfirmOverwrites(d->confirmOverwrites); d->stack->addWidget(d->fileIface->widget()); d->fileIface->connectFileSelectedSignal(this, SLOT(slotFileConnectionSelected(QString))); } d->stack->setCurrentWidget(d->fileIface->widget()); } void KexiConnectionSelectorWidget::setFileWidgetFrameVisible(bool set) { d->fileWidgetFrameVisible = set; if (d->fileIface) { d->fileIface->setWidgetFrame(d->fileWidgetFrameVisible); } } KexiConnectionSelectorWidget::ConnectionType KexiConnectionSelectorWidget::selectedConnectionType() const { return (d->stack->currentWidget() == d->fileWidget()) ? FileBased : ServerBased; } KDbConnectionData* KexiConnectionSelectorWidget::selectedConnectionData() const { QList items = d->remote->list->selectedItems(); if (items.isEmpty()) return 0; ConnectionDataLVItem *item = static_cast(items.first()); if (!item) return 0; return item->data(); } QString KexiConnectionSelectorWidget::selectedFile() const { if (selectedConnectionType() != KexiConnectionSelectorWidget::FileBased) { return QString(); } return d->fileIface->selectedFile(); } void KexiConnectionSelectorWidget::setSelectedFile(const QString& name) { if (selectedConnectionType() != KexiConnectionSelectorWidget::FileBased) { return; } return d->fileIface->setSelectedFile(name); } void KexiConnectionSelectorWidget::slotConnectionItemExecuted(QTreeWidgetItem* item) { emit connectionItemExecuted(static_cast(item)); slotConnectionSelected(); } void KexiConnectionSelectorWidget::slotConnectionItemExecuted() { QList items = d->remote->list->selectedItems(); if (items.isEmpty()) return; slotConnectionItemExecuted(items.first()); slotConnectionSelected(); } void KexiConnectionSelectorWidget::slotConnectionSelectionChanged() { QList items = d->remote->list->selectedItems(); if (items.isEmpty()) return; ConnectionDataLVItem* item = static_cast(items.first()); d->remote->btn_edit->setEnabled(item); d->remote->btn_remove->setEnabled(item); QString desc; if (item) { desc = item->data()->description(); } d->descGroupBoxPaintBlocker->setEnabled(desc.isEmpty()); d->remote->descriptionLabel->setText(desc); + emit connectionSelected(d->isConnectionSelected); emit connectionItemHighlighted(item); } QTreeWidget* KexiConnectionSelectorWidget::connectionsList() const { return d->remote->list; } void KexiConnectionSelectorWidget::setFocus() { QWidget::setFocus(); if (d->stack->currentWidget() == d->fileWidget()) { d->fileWidget()->setFocus(); } else { d->remote->list->setFocus(); } } void KexiConnectionSelectorWidget::hideHelpers() { d->openExistingWidget->hide(); } void KexiConnectionSelectorWidget::setConfirmOverwrites(bool set) { d->confirmOverwrites = set; if (d->fileIface) { d->fileIface->setConfirmOverwrites(d->confirmOverwrites); } } bool KexiConnectionSelectorWidget::confirmOverwrites() const { return d->confirmOverwrites; } void KexiConnectionSelectorWidget::slotRemoteAddBtnClicked() { KDbConnectionData data; KexiDBConnectionDialog dlg(this, data, QString(), KGuiItem(xi18nc("@action:button Add Database Connection", "&Add"), koIconName("dialog-ok"), xi18n("Add database connection"))); dlg.setWindowTitle(xi18nc("@title:window", "Add a New Database Connection")); if (QDialog::Accepted != dlg.exec()) return; //store this conn. data KDbConnectionData *newData = new KDbConnectionData(*dlg.currentProjectData().connectionData()); KDbMessageGuard mg(d->conn_set); if (!d->conn_set->addConnectionData(newData)) { delete newData; return; } ConnectionDataLVItem* item = addConnectionData(newData); if (item) { d->remote->list->clearSelection(); d->updateRemoteListColumns(); item->setSelected(true); slotConnectionSelectionChanged(); } } void KexiConnectionSelectorWidget::slotRemoteEditBtnClicked() { QList items = d->remote->list->selectedItems(); if (items.isEmpty()) return; ConnectionDataLVItem* item = static_cast(items.first()); if (!item) return; KexiDBConnectionDialog dlg(this, *item->data(), QString(), KGuiItem(xi18nc("@action:button Save Database Connection", "&Save"), koIconName("document-save"), xi18n("Save changes made to this database connection"))); dlg.setWindowTitle(xi18nc("@title:window", "Edit Database Connection")); if (QDialog::Accepted != dlg.exec()) return; KDbMessageGuard mg(d->conn_set); if (!d->conn_set->saveConnectionData(item->data(), *dlg.currentProjectData().connectionData())) { return; } const KDbDriverMetaData *driverMetaData = d->manager.driverMetaData(item->data()->driverId()); if (driverMetaData) { item->update(*driverMetaData); d->updateRemoteListColumns(); slotConnectionSelectionChanged(); //to update descr. edit } } void KexiConnectionSelectorWidget::slotRemoteRemoveBtnClicked() { QList items = d->remote->list->selectedItems(); if (items.isEmpty()) return; ConnectionDataLVItem* item = static_cast(items.first()); if (!item) return; if (KMessageBox::Yes != KMessageBox::questionYesNo(this, xi18nc("@info", "Do you want to delete database connection %1 from " "the list of available connections?", item->data()->toUserVisibleString()), QString(), //caption KStandardGuiItem::del(), KStandardGuiItem::cancel(), QString(), //dont'ask name KMessageBox::Notify | KMessageBox::Dangerous)) { return; } QTreeWidgetItem* nextItem = d->remote->list->itemBelow(item); if (!nextItem) nextItem = d->remote->list->itemAbove(item); KDbMessageGuard mg(d->conn_set); if (!d->conn_set->removeConnectionData(item->data())) return; delete item->data(); delete item; if (nextItem) nextItem->setSelected(true); d->updateRemoteListColumns(); } void KexiConnectionSelectorWidget::hideConnectonIcon() { d->remote->lblIcon->setFixedWidth(0); d->remote->lblIcon->setPixmap(QPixmap()); } void KexiConnectionSelectorWidget::hideDescription() { d->remote->lblIcon->hide(); d->remote->label->hide(); } void KexiConnectionSelectorWidget::setExcludedMimeTypes(const QStringList &mimeTypes) { d->fileIface->setExcludedMimeTypes(mimeTypes); } bool KexiConnectionSelectorWidget::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(event); if ((ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return) && ke->modifiers() == Qt::NoModifier) { slotConnectionItemExecuted(); return true; } } return QWidget::eventFilter(watched, event); } void KexiConnectionSelectorWidget::slotFileConnectionSelected(const QString &name) { Q_UNUSED(name) d->isConnectionSelected = !d->fileIface->selectedFile().isEmpty(); emit connectionSelected(d->isConnectionSelected); emit fileSelected(name); } void KexiConnectionSelectorWidget::slotConnectionSelected() { d->isConnectionSelected = !d->remote->list->selectedItems().isEmpty(); emit connectionSelected(d->isConnectionSelected); } bool KexiConnectionSelectorWidget::hasSelectedConnection() const { return d->isConnectionSelected; } void KexiConnectionSelectorWidget::setFileMode(KexiFileFilters::Mode mode) { if (d->fileIface) { d->fileIface->setMode(mode); } } void KexiConnectionSelectorWidget::setAdditionalMimeTypes(const QStringList &mimeTypes) { if (d->fileIface) { d->fileIface->setAdditionalMimeTypes(mimeTypes); } } bool KexiConnectionSelectorWidget::checkSelectedFile() { if (d->fileIface) { return d->fileIface->checkSelectedFile(); } return false; } QString KexiConnectionSelectorWidget::highlightedFile() const { if (d->fileIface) { return d->fileIface->highlightedFile(); } return QString(); } #include "KexiConnectionSelectorWidget.moc"