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