1 /* This file is part of the KDE project
2 Copyright (C) 2009 Adam Pigg <adam@piggz.co.uk>
3 Copyright (C) 2014-2016 Jarosław Staniek <staniek@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License version 2 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18 */
19
20 #include "importtablewizard.h"
21 #include "importoptionsdlg.h"
22 #include "migratemanager.h"
23 #include "keximigrate.h"
24 #include "keximigratedata.h"
25 #include "AlterSchemaWidget.h"
26 #include <KexiIcon.h>
27 #include <core/kexidbconnectionset.h>
28 #include <core/kexi.h>
29 #include <core/kexipartmanager.h>
30 #include <kexiutils/utils.h>
31 #include <kexidbdrivercombobox.h>
32 #include <kexitextmsghandler.h>
33 #include <kexipart.h>
34 #include <KexiMainWindowIface.h>
35 #include <kexiproject.h>
36 #include <widget/kexicharencodingcombobox.h>
37 #include <widget/kexiprjtypeselector.h>
38 #include <widget/KexiConnectionSelectorWidget.h>
39 #include <widget/KexiProjectSelectorWidget.h>
40 #include <widget/KexiDBCaptionPage.h>
41 #include <widget/KexiNameWidget.h>
42
43 #include <KDbConnectionData>
44 #include <KDbDriver>
45 #include <KDbDriverManager>
46 #include <KDbDriverManager>
47 #include <KDbSqlResult>
48 #include <KDbTransactionGuard>
49 #include <KDbUtils>
50
51 #include <KMessageBox>
52
53 #include <QSet>
54 #include <QVBoxLayout>
55 #include <QListWidget>
56 #include <QStringList>
57 #include <QProgressBar>
58 #include <QCheckBox>
59 #include <QMimeDatabase>
60 #include <QMimeType>
61 #include <QPushButton>
62 #include <QDebug>
63
64 using namespace KexiMigration;
65
66 #define RECORDS_FOR_PREVIEW 3
67
ImportTableWizard(KDbConnection * curDB,QWidget * parent,QMap<QString,QString> * args,Qt::WindowFlags flags)68 ImportTableWizard::ImportTableWizard ( KDbConnection* curDB, QWidget* parent, QMap<QString, QString>* args, Qt::WindowFlags flags)
69 : KAssistantDialog ( parent, flags ),
70 m_args(args)
71 {
72 m_connection = curDB;
73 m_migrateDriver = 0;
74 m_prjSet = 0;
75 m_importComplete = false;
76 m_importWasCanceled = false;
77 m_sourceDbEncoding = QString::fromLatin1(KexiUtils::encoding()); //default
78
79 KexiMainWindowIface::global()->setReasonableDialogSize(this);
80
81 setupIntroPage();
82 setupSrcConn();
83 setupSrcDB();
84 setupTableSelectPage();
85 setupAlterTablePage();
86 setupImportingPage();
87 setupProgressPage();
88 setupFinishPage();
89
90 setValid(m_srcConnPageItem, false);
91
92 connect(this, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), this, SLOT(slot_currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)));
93 //! @todo Change this to message prompt when we move to non-dialog wizard.
94 connect(m_srcConnSel, SIGNAL(connectionSelected(bool)), this,
95 SLOT(slotConnPageItemSelected(bool)));
96 connect(m_srcConnSel, &KexiConnectionSelectorWidget::connectionItemHighlighted,
97 [this]() { setValid(m_srcConnPageItem, true); });
98 connect(m_srcConnSel, &KexiConnectionSelectorWidget::connectionItemExecuted, [this]() {
99 setValid(m_srcConnPageItem, true);
100 next();
101 });
102 }
103
104
~ImportTableWizard()105 ImportTableWizard::~ImportTableWizard()
106 {
107 delete m_prjSet;
108 delete m_srcConnSel;
109 }
110
back()111 void ImportTableWizard::back() {
112 KAssistantDialog::back();
113 }
114
next()115 void ImportTableWizard::next() {
116 if (currentPage() == m_srcConnPageItem) {
117 if (fileBasedSrcSelected()) {
118 setAppropriate(m_srcDBPageItem, false);
119 } else {
120 setAppropriate(m_srcDBPageItem, true);
121 }
122 } else if (currentPage() == m_alterTablePageItem) {
123 if (m_alterSchemaWidget->nameExists(m_alterSchemaWidget->nameWidget()->nameText())) {
124 KMessageBox::information(this,
125 xi18nc("@info",
126 "<resource>%1</resource> name is already used by an existing table. "
127 "Enter different table name to continue.",
128 m_alterSchemaWidget->nameWidget()->nameText()),
129 xi18n("Name Already Used"));
130 return;
131 }
132 }
133
134 KAssistantDialog::next();
135 }
136
accept()137 void ImportTableWizard::accept() {
138 if (m_args) {
139 if (m_finishCheckBox->isChecked()) {
140 m_args->insert("destinationTableName",m_alterSchemaWidget->nameWidget()->nameText());
141 } else {
142 m_args->remove("destinationTableName");
143 }
144 }
145
146 QDialog::accept();
147 }
148
reject()149 void ImportTableWizard::reject() {
150 QDialog::reject();
151 }
152
153 //===========================================================
154 //
setupIntroPage()155 void ImportTableWizard::setupIntroPage()
156 {
157 m_introPageWidget = new QWidget(this);
158 QVBoxLayout *vbox = new QVBoxLayout();
159
160 m_introPageWidget->setLayout(vbox);
161
162 KexiUtils::setStandardMarginsAndSpacing(vbox);
163
164 QLabel *lblIntro = new QLabel(m_introPageWidget);
165 lblIntro->setAlignment(Qt::AlignTop | Qt::AlignLeft);
166 lblIntro->setWordWrap(true);
167 lblIntro->setText(
168 xi18nc("@info",
169 "<para>Table Importing Assistant allows you to import a table from an existing "
170 "database into the current Kexi project.</para>"
171 "<para>Click <interface>Next</interface> button to continue or "
172 "<interface>Cancel</interface> button to exit this assistant.</para>"));
173 vbox->addWidget(lblIntro);
174
175 m_introPageItem = new KPageWidgetItem(m_introPageWidget,
176 xi18n("Welcome to the Table Importing Assistant"));
177 addPage(m_introPageItem);
178 }
179
setupSrcConn()180 void ImportTableWizard::setupSrcConn()
181 {
182 m_srcConnPageWidget = new QWidget(this);
183 QVBoxLayout *vbox = new QVBoxLayout(m_srcConnPageWidget);
184
185 m_srcConnSel = new KexiConnectionSelectorWidget(&Kexi::connset(),
186 QUrl("kfiledialog:///ProjectMigrationSourceDir"),
187 KexiConnectionSelectorWidget::Opening, m_srcConnPageWidget);
188
189 m_srcConnSel->hideConnectonIcon();
190 m_srcConnSel->showSimpleConnection();
191
192 //! @todo remove when support for kexi files as source prj is added in migration
193 const QStringList excludedMimeTypes({
194 KDb::defaultFileBasedDriverMimeType(),
195 "application/x-kexiproject-shortcut",
196 "application/x-kexi-connectiondata"});
197 m_srcConnSel->setExcludedMimeTypes(excludedMimeTypes);
198
199 vbox->addWidget(m_srcConnSel);
200
201 m_srcConnPageItem = new KPageWidgetItem(m_srcConnPageWidget, xi18n("Select Location for Source Database"));
202 addPage(m_srcConnPageItem);
203 }
204
setupSrcDB()205 void ImportTableWizard::setupSrcDB()
206 {
207 // arrivesrcdbPage creates widgets on that page
208 m_srcDBPageWidget = new QWidget(this);
209 m_srcDBName = NULL;
210
211 m_srcDBPageItem = new KPageWidgetItem(m_srcDBPageWidget, xi18n("Select Source Database"));
212 addPage(m_srcDBPageItem);
213 }
214
215
setupTableSelectPage()216 void ImportTableWizard::setupTableSelectPage() {
217 m_tablesPageWidget = new QWidget(this);
218 QVBoxLayout *vbox = new QVBoxLayout(m_tablesPageWidget);
219 KexiUtils::setStandardMarginsAndSpacing(vbox);
220
221 m_tableListWidget = new QListWidget(this);
222 m_tableListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
223 connect(m_tableListWidget, SIGNAL(itemSelectionChanged()),
224 this, SLOT(slotTableListWidgetSelectionChanged()));
225
226 vbox->addWidget(m_tableListWidget);
227
228 m_tablesPageItem = new KPageWidgetItem(m_tablesPageWidget, xi18n("Select the Table to Import"));
229 addPage(m_tablesPageItem);
230 }
231
232 //===========================================================
233 //
setupImportingPage()234 void ImportTableWizard::setupImportingPage()
235 {
236 m_importingPageWidget = new QWidget(this);
237 m_importingPageWidget->hide();
238 QVBoxLayout *vbox = new QVBoxLayout(m_importingPageWidget);
239 KexiUtils::setStandardMarginsAndSpacing(vbox);
240 m_lblImportingTxt = new QLabel(m_importingPageWidget);
241 m_lblImportingTxt->setAlignment(Qt::AlignTop | Qt::AlignLeft);
242 m_lblImportingTxt->setWordWrap(true);
243
244 m_lblImportingErrTxt = new QLabel(m_importingPageWidget);
245 m_lblImportingErrTxt->setAlignment(Qt::AlignTop | Qt::AlignLeft);
246 m_lblImportingErrTxt->setWordWrap(true);
247
248 vbox->addWidget(m_lblImportingTxt);
249 vbox->addWidget(m_lblImportingErrTxt);
250 vbox->addStretch(1);
251
252 QWidget *options_widget = new QWidget(m_importingPageWidget);
253 vbox->addWidget(options_widget);
254 QVBoxLayout *options_vbox = new QVBoxLayout(options_widget);
255 options_vbox->setSpacing(KexiUtils::spacingHint());
256 m_importOptionsButton = new QPushButton(koIcon("configure"), xi18n("Advanced Options"), options_widget);
257 connect(m_importOptionsButton, SIGNAL(clicked()),this, SLOT(slotOptionsButtonClicked()));
258 options_vbox->addWidget(m_importOptionsButton);
259 options_vbox->addStretch(1);
260
261 m_importingPageWidget->show();
262
263 m_importingPageItem = new KPageWidgetItem(m_importingPageWidget, xi18n("Importing"));
264 addPage(m_importingPageItem);
265 }
266
setupAlterTablePage()267 void ImportTableWizard::setupAlterTablePage()
268 {
269 m_alterTablePageWidget = new QWidget(this);
270 m_alterTablePageWidget->hide();
271
272 QVBoxLayout *vbox = new QVBoxLayout(m_alterTablePageWidget);
273 KexiUtils::setStandardMarginsAndSpacing(vbox);
274
275 m_alterSchemaWidget = new KexiMigration::AlterSchemaWidget(this);
276 vbox->addWidget(m_alterSchemaWidget);
277 m_alterTablePageWidget->show();
278
279 m_alterTablePageItem = new KPageWidgetItem(m_alterTablePageWidget, xi18n("Alter the Detected Table Design"));
280 addPage(m_alterTablePageItem);
281 }
282
setupProgressPage()283 void ImportTableWizard::setupProgressPage()
284 {
285 m_progressPageWidget = new QWidget(this);
286 m_progressPageWidget->hide();
287 QVBoxLayout *vbox = new QVBoxLayout(m_progressPageWidget);
288 KexiUtils::setStandardMarginsAndSpacing(vbox);
289 m_progressPageWidget->setLayout(vbox);
290 m_progressLbl = new QLabel(m_progressPageWidget);
291 m_progressLbl->setAlignment(Qt::AlignTop | Qt::AlignLeft);
292 m_progressLbl->setWordWrap(true);
293 m_rowsImportedLbl = new QLabel(m_progressPageWidget);
294
295 m_importingProgressBar = new QProgressBar(m_progressPageWidget);
296 m_importingProgressBar->setMinimum(0);
297 m_importingProgressBar->setMaximum(0);
298 m_importingProgressBar->setValue(0);
299
300 vbox->addWidget(m_progressLbl);
301 vbox->addWidget(m_rowsImportedLbl);
302 vbox->addWidget(m_importingProgressBar);
303 vbox->addStretch(1);
304
305 m_progressPageItem = new KPageWidgetItem(m_progressPageWidget, xi18n("Processing Import"));
306 addPage(m_progressPageItem);
307 }
308
setupFinishPage()309 void ImportTableWizard::setupFinishPage()
310 {
311 m_finishPageWidget = new QWidget(this);
312 m_finishPageWidget->hide();
313 QVBoxLayout *vbox = new QVBoxLayout(m_finishPageWidget);
314 KexiUtils::setStandardMarginsAndSpacing(vbox);
315 m_finishLbl = new QLabel(m_finishPageWidget);
316 m_finishLbl->setAlignment(Qt::AlignTop | Qt::AlignLeft);
317 m_finishLbl->setWordWrap(true);
318
319 vbox->addWidget(m_finishLbl);
320 m_finishCheckBox = new QCheckBox(xi18n("Open imported table"),
321 m_finishPageWidget);
322 m_finishCheckBox->setChecked(true);
323 vbox->addSpacing(KexiUtils::spacingHint());
324 vbox->addWidget(m_finishCheckBox);
325 vbox->addStretch(1);
326
327 m_finishPageItem = new KPageWidgetItem(m_finishPageWidget, xi18n("Success"));
328 addPage(m_finishPageItem);
329 }
330
slot_currentPageChanged(KPageWidgetItem * curPage,KPageWidgetItem * prevPage)331 void ImportTableWizard::slot_currentPageChanged(KPageWidgetItem* curPage,KPageWidgetItem* prevPage)
332 {
333 Q_UNUSED(prevPage);
334 if (curPage == m_introPageItem) {
335 }
336 else if (curPage == m_srcConnPageItem) {
337 arriveSrcConnPage();
338 } else if (curPage == m_srcDBPageItem) {
339 arriveSrcDBPage();
340 } else if (curPage == m_tablesPageItem) {
341 arriveTableSelectPage(prevPage);
342 } else if (curPage == m_alterTablePageItem) {
343 if (prevPage == m_tablesPageItem) {
344 arriveAlterTablePage();
345 }
346 } else if (curPage == m_importingPageItem) {
347 arriveImportingPage();
348 } else if (curPage == m_progressPageItem) {
349 arriveProgressPage();
350 } else if (curPage == m_finishPageItem) {
351 arriveFinishPage();
352 }
353 }
354
arriveSrcConnPage()355 void ImportTableWizard::arriveSrcConnPage()
356 {
357 }
358
arriveSrcDBPage()359 void ImportTableWizard::arriveSrcDBPage()
360 {
361 if (fileBasedSrcSelected()) {
362 //! @todo Back button doesn't work after selecting a file to import
363 } else {
364 delete m_prjSet;
365 m_prjSet = 0;
366 m_srcDBPageWidget->hide();
367 qDebug() << "Looks like we need a project selector widget!";
368
369 KDbConnectionData* conndata = m_srcConnSel->selectedConnectionData();
370 if (conndata) {
371 KexiGUIMessageHandler handler;
372 m_prjSet = new KexiProjectSet(&handler);
373 if (!m_prjSet->setConnectionData(conndata)) {
374 handler.showErrorMessage(m_prjSet->result());
375 delete m_prjSet;
376 m_prjSet = 0;
377 return;
378 }
379 if (!m_srcDBName) {
380 QVBoxLayout *vbox = new QVBoxLayout(m_srcDBPageWidget);
381 KexiUtils::setStandardMarginsAndSpacing(vbox);
382 m_srcDBName = new KexiProjectSelectorWidget(m_srcDBPageWidget);
383 vbox->addWidget(m_srcDBName);
384 m_srcDBName->label()->setText(xi18n("Select source database you wish to import:"));
385 }
386 m_srcDBName->setProjectSet(m_prjSet);
387 }
388 m_srcDBPageWidget->show();
389 }
390 }
391
arriveTableSelectPage(KPageWidgetItem * prevPage)392 void ImportTableWizard::arriveTableSelectPage(KPageWidgetItem *prevPage)
393 {
394 if (prevPage == m_alterTablePageItem) {
395 if (m_tableListWidget->count() == 1) { //we was skiping it before
396 back();
397 }
398 } else {
399 Kexi::ObjectStatus result;
400 KexiUtils::WaitCursor wait;
401 m_tableListWidget->clear();
402 m_migrateDriver = prepareImport(&result);
403
404 bool ok = m_migrateDriver;
405 if (ok) {
406 if (!m_sourceDbEncoding.isEmpty()) {
407 m_migrateDriver->setPropertyValue(
408 "source_database_nonunicode_encoding",
409 QVariant(m_sourceDbEncoding.toUpper().remove(' ')) // "CP1250", not "cp 1250"
410 );
411 }
412 ok = m_migrateDriver->connectSource(&result);
413 }
414 if (ok) {
415 QStringList tableNames;
416 if (m_migrateDriver->tableNames(&tableNames)) {
417 m_tableListWidget->addItems(tableNames);
418 }
419 if (m_tableListWidget->item(0)) {
420 m_tableListWidget->item(0)->setSelected(true);
421 if (m_tableListWidget->count() == 1) {
422 KexiUtils::removeWaitCursor();
423 next();
424 }
425 }
426 }
427 KexiUtils::removeWaitCursor();
428 if (!ok) {
429 QString errMessage =result.message.isEmpty() ? xi18n("Unknown error") : result.message;
430 QString errDescription = result.description.isEmpty() ? errMessage : result.description;
431 KMessageBox::error(this, errMessage, errDescription);
432 setValid(m_tablesPageItem, false);
433 }
434 }
435 }
436
arriveAlterTablePage()437 void ImportTableWizard::arriveAlterTablePage()
438 {
439 //! @todo handle errors
440 if (m_tableListWidget->selectedItems().isEmpty())
441 return;
442 //! @todo (js) support multiple tables?
443 #if 0
444 foreach(QListWidgetItem *table, m_tableListWidget->selectedItems()) {
445 m_importTableName = table->text();
446 }
447 #else
448 m_importTableName = m_tableListWidget->selectedItems().first()->text();
449 #endif
450
451 QScopedPointer<KDbTableSchema> ts(new KDbTableSchema);
452 if (!m_migrateDriver->readTableSchema(m_importTableName, ts.data())) {
453 return;
454 }
455
456 setValid(m_alterTablePageItem, ts->fieldCount() > 0);
457 if (isValid(m_alterTablePageItem)) {
458 connect(m_alterSchemaWidget->nameWidget(), SIGNAL(textChanged()), this, SLOT(slotNameChanged()), Qt::UniqueConnection);
459 }
460
461 m_alterSchemaWidget->setTableSchema(ts.take());
462 if (!readFromTable()) {
463 m_alterSchemaWidget->setTableSchema(nullptr);
464 back();
465 KMessageBox::information(this,
466 xi18nc("@info", "Could not import table <resource>%1</resource>. "
467 "Select different table or cancel importing.", m_importTableName));
468 }
469 }
470
readFromTable()471 bool ImportTableWizard::readFromTable()
472 {
473 QSharedPointer<KDbSqlResult> tableResult = m_migrateDriver->readFromTable(m_importTableName);
474 KDbTableSchema *newSchema = m_alterSchemaWidget->newSchema();
475 if (!tableResult || tableResult->lastResult().isError()
476 || tableResult->fieldsCount() != newSchema->fieldCount())
477 {
478 back();
479 KMessageBox::information(this,
480 xi18nc("@info", "Could not import table <resource>%1</resource>. "
481 "Select different table or cancel importing.", m_importTableName));
482 return false;
483 }
484 QScopedPointer<QList<KDbRecordData*>> data(new QList<KDbRecordData*>);
485 for (int i = 0; i < RECORDS_FOR_PREVIEW; ++i) {
486 QSharedPointer<KDbRecordData> record(tableResult->fetchRecordData());
487 if (!record) {
488 if (tableResult->lastResult().isError()) {
489 return false;
490 }
491 break;
492 }
493 data->append(record.data());
494 }
495 if (data->isEmpty()) {
496 back();
497 KMessageBox::information(this,
498 xi18nc("@info", "No data has been found in table <resource>%1</resource>. "
499 "Select different table or cancel importing.", m_importTableName));
500 return false;
501 }
502 m_alterSchemaWidget->model()->setRowCount(data->count());
503 m_alterSchemaWidget->setData(data.take());
504 return true;
505 }
506
arriveImportingPage()507 void ImportTableWizard::arriveImportingPage()
508 {
509 m_importingPageWidget->hide();
510 #if 0
511 if (checkUserInput()) {
512 //setNextEnabled(m_importingPageWidget, true);
513 user2Button->setEnabled(true);
514 } else {
515 //setNextEnabled(m_importingPageWidget, false);
516 user2Button->setEnabled(false);
517 }
518 #endif
519
520 QString txt;
521
522 txt = xi18nc("@info Table import wizard, final message", "<para>All required information has now been gathered. "
523 "Click <interface>Next</interface> button to start importing table <resource>%1</resource>.</para>"
524 "<para><note>Depending on size of the table this may take some time.</note></para>",
525 m_alterSchemaWidget->nameWidget()->nameText());
526
527 m_lblImportingTxt->setText(txt);
528
529 //temp. hack for MS Access driver only
530 //! @todo for other databases we will need KexiMigration::Connection
531 //! and KexiMigration::Driver classes
532 bool showOptions = false;
533 if (fileBasedSrcSelected()) {
534 Kexi::ObjectStatus result;
535 KexiMigrate* sourceDriver = prepareImport(&result);
536 if (sourceDriver) {
537 showOptions = !result.error()
538 && sourceDriver->propertyValue("source_database_has_nonunicode_encoding").toBool();
539 sourceDriver->setData(nullptr);
540 }
541 }
542 if (showOptions)
543 m_importOptionsButton->show();
544 else
545 m_importOptionsButton->hide();
546
547 m_importingPageWidget->show();
548 setAppropriate(m_progressPageItem, true);
549 }
550
arriveProgressPage()551 void ImportTableWizard::arriveProgressPage()
552 {
553 m_progressLbl->setText(xi18nc("@info", "Please wait while the table is imported."));
554
555 backButton()->setEnabled(false);
556 nextButton()->setEnabled(false);
557
558 connect(button(QDialogButtonBox::Cancel), &QPushButton::clicked,
559 this, &ImportTableWizard::slotCancelClicked);
560
561 QApplication::setOverrideCursor(Qt::BusyCursor);
562 m_importComplete = doImport();
563 QApplication::restoreOverrideCursor();
564
565 disconnect(button(QDialogButtonBox::Cancel), &QPushButton::clicked,
566 this, &ImportTableWizard::slotCancelClicked);
567
568 next();
569 }
570
arriveFinishPage()571 void ImportTableWizard::arriveFinishPage()
572 {
573 if (m_importComplete) {
574 m_finishPageItem->setHeader(xi18n("Success"));
575 m_finishLbl->setText(xi18nc("@info",
576 "Table <resource>%1</resource> has been imported.",
577 m_alterSchemaWidget->nameWidget()->nameText()));
578 } else {
579 m_finishPageItem->setHeader(xi18n("Failure"));
580 m_finishLbl->setText(xi18n("An error occurred."));
581 }
582 m_migrateDriver->disconnectSource();
583 button(QDialogButtonBox::Cancel)->setEnabled(!m_importComplete);
584 m_finishCheckBox->setVisible(m_importComplete);
585 finishButton()->setEnabled(m_importComplete);
586 nextButton()->setEnabled(m_importComplete);
587 setAppropriate(m_progressPageItem, false);
588 }
589
fileBasedSrcSelected() const590 bool ImportTableWizard::fileBasedSrcSelected() const
591 {
592 return m_srcConnSel->selectedConnectionType() == KexiConnectionSelectorWidget::FileBased;
593 }
594
prepareImport(Kexi::ObjectStatus * result)595 KexiMigrate* ImportTableWizard::prepareImport(Kexi::ObjectStatus *result)
596 {
597 Q_ASSERT(result);
598 // Find a source (migration) driver name
599 QString sourceDriverId = driverIdForSelectedSource();
600 if (sourceDriverId.isEmpty()) {
601 result->setStatus(xi18n("No appropriate migration driver found."),
602 m_migrateManager.possibleProblemsMessage());
603 }
604
605 // Get a source (migration) driver
606 KexiMigrate* sourceDriver = 0;
607 if (!result->error()) {
608 sourceDriver = m_migrateManager.driver(sourceDriverId);
609 if (!sourceDriver || m_migrateManager.result().isError()) {
610 qDebug() << "Import migrate driver error...";
611 result->setStatus(m_migrateManager.resultable());
612 }
613 }
614
615 // Set up source (migration) data required for connection
616 if (sourceDriver && !result->error()) {
617 #if 0
618 // Setup progress feedback for the GUI
619 if (sourceDriver->progressSupported()) {
620 m_progressBar->updateGeometry();
621 disconnect(sourceDriver, SIGNAL(progressPercent(int)),
622 this, SLOT(progressUpdated(int)));
623 connect(sourceDriver, SIGNAL(progressPercent(int)),
624 this, SLOT(progressUpdated(int)));
625 progressUpdated(0);
626 }
627 #endif
628
629 bool keepData = true;
630
631 #if 0
632 if (m_importTypeStructureAndDataCheckBox->isChecked()) {
633 qDebug() << "Structure and data selected";
634 keepData = true;
635 } else if (m_importTypeStructureOnlyCheckBox->isChecked()) {
636 qDebug() << "structure only selected";
637 keepData = false;
638 } else {
639 qDebug() << "Neither radio button is selected (not possible?) presume keep data";
640 keepData = true;
641 }
642 #endif
643
644 KexiMigration::Data* md = new KexiMigration::Data();
645
646 if (fileBasedSrcSelected()) {
647 KDbConnectionData* conn_data = new KDbConnectionData();
648 conn_data->setDatabaseName(m_srcConnSel->selectedFile());
649 md->source = conn_data;
650 md->sourceName.clear();
651 } else {
652 md->source = m_srcConnSel->selectedConnectionData();
653 md->sourceName = m_srcDBName->selectedProjectData()->databaseName();
654
655 }
656
657 md->setShouldCopyData(keepData);
658 sourceDriver->setData(md);
659
660 return sourceDriver;
661 }
662 return 0;
663 }
664
665 //===========================================================
666 //
driverIdForSelectedSource()667 QString ImportTableWizard::driverIdForSelectedSource()
668 {
669 if (fileBasedSrcSelected()) {
670 QMimeDatabase db;
671 QMimeType mime = db.mimeTypeForFile(m_srcConnSel->selectedFile());
672 if (!mime.isValid()
673 || mime.name() == "application/octet-stream"
674 || mime.name() == "text/plain"
675 || mime.name() == "application/zip")
676 {
677 //try by URL:
678 mime = db.mimeTypeForFile(m_srcConnSel->selectedFile());
679 }
680 if (!mime.isValid()) {
681 return QString();
682 }
683 const QStringList ids(m_migrateManager.driverIdsForMimeType(mime.name()));
684 //! @todo do we want to return first migrate driver for the mime type or allow to select it?
685 return ids.isEmpty() ? QString() : ids.first();
686 }
687 return m_srcConnSel->selectedConnectionData()
688 ? m_srcConnSel->selectedConnectionData()->databaseName() : QString();
689 }
690
doImport()691 bool ImportTableWizard::doImport()
692 {
693 KexiGUIMessageHandler msg;
694
695 KexiProject* project = KexiMainWindowIface::global()->project();
696 if (!project) {
697 msg.showErrorMessage(KDbMessageHandler::Error, xi18n("No project available."));
698 return false;
699 }
700
701 KexiPart::Part *part = Kexi::partManager().partForPluginId("org.kexi-project.table");
702 if (!part) {
703 msg.showErrorMessage(Kexi::partManager().result());
704 return false;
705 }
706
707 KDbTableSchema* newSchema = m_alterSchemaWidget->newSchema();
708 if (!newSchema) {
709 msg.showErrorMessage(KDbMessageHandler::Error, xi18n("No table was selected to import."));
710 return false;
711 }
712 newSchema->setName(m_alterSchemaWidget->nameWidget()->nameText());
713 newSchema->setCaption(m_alterSchemaWidget->nameWidget()->captionText());
714
715 KexiPart::Item* partItemForSavedTable = project->createPartItem(part->info(), newSchema->name());
716 if (!partItemForSavedTable) {
717 msg.showErrorMessage(project->result());
718 return false;
719 }
720
721 //Create the table
722 if (!m_connection->createTable(newSchema,
723 KDbConnection::CreateTableOption::Default | KDbConnection::CreateTableOption::DropDestination))
724 {
725 msg.showErrorMessage(KDbMessageHandler::Error,
726 xi18nc("@info", "Unable to create table <resource>%1</resource>.",
727 newSchema->name()));
728 return false;
729 }
730 m_alterSchemaWidget->takeTableSchema(); //m_connection takes ownership of the KDbTableSchema object
731
732 //Import the data
733 QApplication::setOverrideCursor(Qt::BusyCursor);
734 QList<QVariant> row;
735 unsigned int fieldCount = newSchema->fieldCount();
736 m_migrateDriver->moveFirst();
737 KDbTransactionGuard tg(m_connection);
738 if (m_connection->result().isError()) {
739 QApplication::restoreOverrideCursor();
740 return false;
741 }
742 do {
743 for (unsigned int i = 0; i < fieldCount; ++i) {
744 if (m_importWasCanceled) {
745 return false;
746 }
747 if (i % 100 == 0) {
748 QApplication::processEvents();
749 }
750 row.append(m_migrateDriver->value(i));
751 }
752 m_connection->insertRecord(newSchema, row);
753 row.clear();
754 } while (m_migrateDriver->moveNext());
755 if (!tg.commit()) {
756 QApplication::restoreOverrideCursor();
757 return false;
758 }
759 QApplication::restoreOverrideCursor();
760
761 //Done so save part and update gui
762 partItemForSavedTable->setIdentifier(newSchema->id());
763 project->addStoredItem(part->info(), partItemForSavedTable);
764
765 return true;
766 }
767
slotConnPageItemSelected(bool isSelected)768 void ImportTableWizard::slotConnPageItemSelected(bool isSelected)
769 {
770 setValid(m_srcConnPageItem, isSelected);
771 if (isSelected && fileBasedSrcSelected()) {
772 next();
773 }
774 }
775
slotTableListWidgetSelectionChanged()776 void ImportTableWizard::slotTableListWidgetSelectionChanged()
777 {
778 setValid(m_tablesPageItem, !m_tableListWidget->selectedItems().isEmpty());
779 }
780
slotNameChanged()781 void ImportTableWizard::slotNameChanged()
782 {
783 setValid(m_alterTablePageItem, !m_alterSchemaWidget->nameWidget()->captionText().isEmpty());
784 }
785
slotCancelClicked()786 void ImportTableWizard::slotCancelClicked()
787 {
788 m_importWasCanceled = true;
789 }
790
slotOptionsButtonClicked()791 void ImportTableWizard::slotOptionsButtonClicked()
792 {
793 OptionsDialog dlg(m_srcConnSel->selectedFile(), m_sourceDbEncoding, this);
794 if (QDialog::Accepted == dlg.exec()) {
795 m_sourceDbEncoding = dlg.encodingComboBox()->selectedEncoding();
796 }
797 }
798