kexi

KexiStartup.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "KexiStartup.h"
00021 #ifdef Q_WS_WIN
00022 # include "KexiStartup_p_win.h"
00023 #else
00024 # include "KexiStartup_p.h"
00025 #endif
00026 
00027 #include "kexiproject.h"
00028 #include "kexiprojectdata.h"
00029 #include "kexiprojectset.h"
00030 #include "kexiguimsghandler.h"
00031 
00032 #include <kexidb/driver.h>
00033 #include <kexidb/drivermanager.h>
00034 #include "KexiStartupDialog.h"
00035 #include "KexiConnSelector.h"
00036 #include "KexiProjectSelectorBase.h"
00037 #include "KexiProjectSelector.h"
00038 #include "KexiNewProjectWizard.h"
00039 #include <kexidbconnectionwidget.h>
00040 #include <kexidbshortcutfile.h>
00041 
00042 #include <kdebug.h>
00043 #include <klocale.h>
00044 #include <kmimetype.h>
00045 #include <kmessagebox.h>
00046 #include <kcmdlineargs.h>
00047 #include <kdeversion.h>
00048 #include <kprogress.h>
00049 #include <ktextedit.h>
00050 #include <kstaticdeleter.h>
00051 
00052 #include <unistd.h>
00053 
00054 #if KDE_IS_VERSION(3,1,9)
00055 # include <kuser.h>
00056 #endif
00057 
00058 #include <qcstring.h>
00059 #include <qapplication.h>
00060 #include <qlayout.h>
00061 
00062 namespace Kexi {
00063     static KStaticDeleter<KexiStartupHandler> Kexi_startupHandlerDeleter;
00064     KexiStartupHandler* _startupHandler = 0;
00065 
00066     KexiStartupHandler& startupHandler()
00067     {
00068         if (!_startupHandler)
00069             Kexi_startupHandlerDeleter.setObject( _startupHandler, new KexiStartupHandler() );
00070         return *_startupHandler; 
00071     }
00072 }
00073 
00074 //---------------------------------
00075 
00077 class KexiStartupHandlerPrivate
00078 {
00079     public:
00080         KexiStartupHandlerPrivate()
00081          : passwordDialog(0)//, showConnectionDetailsExecuted(false)
00082             , shortcutFile(0), connShortcutFile(0), connDialog(0), startupDialog(0)
00083         {
00084         }
00085 
00086         ~KexiStartupHandlerPrivate()
00087         {
00088             delete passwordDialog;
00089             delete connDialog;
00090             delete startupDialog;
00091         }
00092 
00093         KexiDBPasswordDialog* passwordDialog;
00094 //      bool showConnectionDetailsExecuted : 1;
00095         KexiDBShortcutFile *shortcutFile;
00096         KexiDBConnShortcutFile *connShortcutFile;
00097         KexiDBConnectionDialog *connDialog;
00098         QString shortcutFileGroupKey;
00099         KexiStartupDialog *startupDialog;
00100 };
00101 
00102 //---------------------------------
00103 
00104 static bool stripQuotes(const QString &item, QString &name)
00105 {
00106     if (item.left(1)=="\"" && item.right(1)=="\"") {
00107         name = item.mid(1, item.length()-2);
00108         return true;
00109     }
00110     name = item;
00111     return false;
00112 }
00113 
00114 void updateProgressBar(KProgressDialog *pd, char *buffer, int buflen)
00115 {
00116     char *p = buffer;
00117     QCString line(80);
00118     for (int i=0; i<buflen; i++, p++) {
00119         if ((i==0 || buffer[i-1]=='\n') && buffer[i]=='%') {
00120             bool ok;
00121             int j=0;
00122 //          char *q=++p;
00123             ++i;
00124             line="";
00125             for (;i<buflen && *p>='0' && *p<='9'; j++, i++, p++)
00126                 line+=QChar(*p);
00127             --i; --p;
00128             int percent = line.toInt(&ok);
00129             if (ok && percent>=0 && percent<=100 && pd->progressBar()->progress()<percent) {
00130 //              kdDebug() << percent << endl;
00131                 pd->progressBar()->setProgress(percent);
00132                 qApp->processEvents(100);
00133             }
00134         }
00135     }
00136 }
00137 
00138 //---------------------------------
00139 
00140 KexiDBPasswordDialog::KexiDBPasswordDialog(QWidget *parent, KexiDB::ConnectionData& cdata, bool showDetailsButton)
00141  : KPasswordDialog( KPasswordDialog::Password, false/*keep*/, 
00142     showDetailsButton ? (int)KDialogBase::User1 : 0, parent )
00143  , m_cdata(&cdata)
00144  , m_showConnectionDetailsRequested(false)
00145 {
00146     QString msg = "<H2>" + i18n("Opening database") + "</H2><p>"
00147      + i18n("Please enter the password.") + "</p>";
00148 /*      msg += cdata.userName.isEmpty() ?
00149             "<p>"+i18n("Please enter the password.")
00150             : "<p>"+i18n("Please enter the password for user.").arg("<b>"+cdata.userName+"</b>");*/
00151 
00152     QString srv = cdata.serverInfoString(false);
00153     if (srv.isEmpty() || srv.lower()=="localhost")
00154         srv = i18n("local database server");
00155 
00156     msg += ("</p><p>"+i18n("Database server: %1").arg(QString("<nobr>")+srv+"</nobr>")+"</p>");
00157         
00158     QString usr;
00159     if (cdata.userName.isEmpty())
00160         usr = i18n("unspecified user", "(unspecified)");
00161     else
00162         usr = cdata.userName;
00163     
00164     msg += ("<p>"+i18n("Username: %1").arg(usr)+"</p>");
00165 
00166     setPrompt( msg );
00167     if (showDetailsButton) {
00168         connect( this, SIGNAL(user1Clicked()), 
00169             this, SLOT(slotShowConnectionDetails()) );
00170         setButtonText(KDialogBase::User1, i18n("&Details")+ " >>");
00171     }
00172     setButtonOK(KGuiItem(i18n("&Open"), "fileopen"));
00173 }
00174 
00175 KexiDBPasswordDialog::~KexiDBPasswordDialog()
00176 {
00177 }
00178 
00179 void KexiDBPasswordDialog::done(int r)
00180 {
00181     if (r == QDialog::Accepted) {
00182         m_cdata->password = QString::fromLatin1(password());
00183     }
00184 //  if (d->showConnectionDetailsExecuted || ret == QDialog::Accepted) {
00185 /*          } else {
00186                 m_action = Exit;
00187                 return true;
00188             }
00189         }*/
00190     KPasswordDialog::done(r);
00191 }
00192 
00193 void KexiDBPasswordDialog::slotShowConnectionDetails()
00194 {
00195     m_showConnectionDetailsRequested = true;
00196     close();
00197 }
00198 
00199 //---------------------------------
00200 KexiStartupHandler::KexiStartupHandler()
00201  : QObject(0,"KexiStartupHandler")
00202  , KexiStartupData()
00203  , d( new KexiStartupHandlerPrivate() )
00204 {
00205 }
00206 
00207 KexiStartupHandler::~KexiStartupHandler()
00208 {
00209     delete d;
00210 }
00211 
00212 bool KexiStartupHandler::getAutoopenObjects(KCmdLineArgs *args, const QCString &action_name)
00213 {
00214     QCStringList list = args->getOptionList(action_name);
00215     QCStringList::ConstIterator it;
00216     bool atLeastOneFound = false;
00217     for ( it = list.constBegin(); it!=list.constEnd(); ++it) {
00218         QString type_name, obj_name, item=*it;
00219         int idx;
00220         bool name_required = true;
00221         if (action_name=="new") {
00222             obj_name = "";
00223             stripQuotes(item, type_name);
00224             name_required = false;
00225         }
00226         else {//open, design, text...
00227             //option with " " (default type == "table")
00228             if (stripQuotes(item, obj_name)) {
00229                 type_name = "table";
00230             }
00231             else if ((idx = item.find(':'))!=-1) {
00232                 //option with type name specified:
00233                 type_name = item.left(idx).lower();
00234                 obj_name = item.mid(idx+1);
00235                 //optional: remove ""
00236                 if (obj_name.left(1)=="\"" && obj_name.right(1)=="\"")
00237                     obj_name = obj_name.mid(1, obj_name.length()-2);
00238             }
00239             else {
00240                 //just obj. name: type name is "table" by default
00241                 obj_name = item;
00242                 type_name = "table";
00243             }
00244         }
00245         if (type_name.isEmpty())
00246             continue;
00247         if (name_required && obj_name.isEmpty())
00248             continue;
00249 
00250         KexiProjectData::ObjectInfo info;
00251         info["name"]=obj_name;
00252         info["type"]=type_name;
00253         info["action"]=action_name;
00254         //ok, now add info for this object
00255         atLeastOneFound = true;
00256         if (projectData())
00257             projectData()->autoopenObjects.append( info );
00258         else
00259             return true; //no need to find more because we do not have projectData() anyway
00260     } //for
00261     return atLeastOneFound;
00262 }
00263 
00264 tristate KexiStartupHandler::init(int /*argc*/, char ** /*argv*/)
00265 {
00266     m_action = DoNothing;
00267 //  d->showConnectionDetailsExecuted = false;
00268     KCmdLineArgs *args = KCmdLineArgs::parsedArgs(0);
00269     if (!args)
00270         return true;
00271 
00272     KexiDB::ConnectionData cdata;
00273 
00274     const QString connectionShortcutFileName( args->getOption("connection") );
00275     if (!connectionShortcutFileName.isEmpty()) {
00276         KexiDBConnShortcutFile connectionShortcut( connectionShortcutFileName );
00277         if (!connectionShortcut.loadConnectionData(cdata)) {
00280             KMessageBox::sorry( 0, "<qt>"
00281                 +i18n("Could not read connection information from connection shortcut "
00282                 "file <nobr>\"%1\"</nobr>.<br><br>Check whether the file has valid contents.")
00283                 .arg(QDir::convertSeparators(connectionShortcut.fileName())));
00284             return false;
00285         }
00286     }
00287     
00288     if (!args->getOption("dbdriver").isEmpty())
00289         cdata.driverName = args->getOption("dbdriver");
00290 
00291     QString fileType( args->getOption("type").lower() );
00292     if (args->count()>0 && (!fileType.isEmpty() && fileType!="project" && fileType!="shortcut" && fileType!="connection")) {
00293         KMessageBox::sorry( 0, 
00294             i18n("You have specified invalid argument (\"%1\") for \"type\" command-line option.")
00295             .arg(fileType));
00296         return false;
00297     }
00298 
00299 //  if (cdata.driverName.isEmpty())
00300 //      cdata.driverName = KexiDB::Driver::defaultFileBasedDriverName();
00301 #ifdef KEXI_SERVER_SUPPORT
00302     if (!args->getOption("host").isEmpty())
00303         cdata.hostName = args->getOption("host");
00304     if (!args->getOption("local-socket").isEmpty())
00305         cdata.localSocketFileName = args->getOption("local-socket");
00306     if (!args->getOption("user").isEmpty())
00307         cdata.userName = args->getOption("user");
00308 #endif
00309 //  cdata.password = args->getOption("password");
00310     bool fileDriverSelected;
00311     if (cdata.driverName.isEmpty())
00312         fileDriverSelected = true;
00313     else {
00314         KexiDB::DriverManager dm;
00315         KexiDB::Driver::Info dinfo = dm.driverInfo(cdata.driverName);
00316         if (dinfo.name.isEmpty()) {
00317             //driver name provided explicity, but not found
00318             KMessageBox::sorry(0, dm.errorMsg());
00319             return false;
00320         }
00321         fileDriverSelected = dinfo.fileBased;
00322     }
00323     bool projectFileExists = false;
00324 
00325     //obfuscate the password, if present
00326 //removed
00327 /*
00328     for (int i=1; i<(argc-1); i++) {
00329         if (qstrcmp("--password",argv[i])==0
00330             || qstrcmp("-password",argv[i])==0)
00331         {
00332             QCString pwd(argv[i+1]);
00333             if (!pwd.isEmpty()) {
00334                 pwd.fill(' ');
00335                 pwd[0]='x';
00336                 qstrcpy(argv[i+1], (const char*)pwd);
00337             }
00338             break;
00339         }
00340     }
00341     */
00342     
00343 #ifdef KEXI_SERVER_SUPPORT
00344     const QString portStr = args->getOption("port");
00345     if (!portStr.isEmpty()) {
00346         bool ok;
00347         const int p = portStr.toInt(&ok);
00348         if (ok && p > 0)
00349             cdata.port = p;
00350         else {
00351             KMessageBox::sorry( 0, 
00352                 i18n("You have specified invalid port number \"%1\"."));
00353             return false;
00354         }
00355     }
00356 #endif
00357 
00358 #ifdef KEXI_SHOW_UNIMPLEMENTED
00359     m_forcedFinalMode = args->isSet("final-mode");
00360     m_forcedDesignMode = args->isSet("design-mode");
00361 #else
00362     m_forcedFinalMode = false;
00363     m_forcedDesignMode = false;
00364 #endif
00365     bool createDB = args->isSet("createdb");
00366     const bool alsoOpenDB = args->isSet("create-opendb");
00367     if (alsoOpenDB)
00368         createDB = true;
00369     const bool dropDB = args->isSet("dropdb");
00370     const bool openExisting = !createDB && !dropDB;
00371     const QString couldnotMsg = QString::fromLatin1("\n")
00372         +i18n("Could not start Kexi application this way.");
00373     
00374     if (createDB && dropDB) {
00375         KMessageBox::sorry( 0, i18n(
00376             "You have used both \"createdb\" and \"dropdb\" startup options.")+couldnotMsg);
00377         return false;
00378     };
00379 
00380     if (createDB || dropDB) {
00381         if (args->count()<1) {
00382             KMessageBox::sorry( 0, i18n("No project name specified.") );
00383             return false;
00384         }
00385         m_action = Exit;
00386     }
00387 
00388 //TODO: add option for non-gui; integrate with KWallet; 
00389 //      move to static KexiProject method
00390     if (!fileDriverSelected && !cdata.driverName.isEmpty() && cdata.password.isEmpty()) {
00391 
00392         if (cdata.password.isEmpty()) {
00393             delete d->passwordDialog;
00394             d->passwordDialog = new KexiDBPasswordDialog(0, cdata, true);
00395 //          connect( d->passwordDialog, SIGNAL(user1Clicked()), 
00396 //              this, SLOT(slotShowConnectionDetails()) );
00397             const int ret = d->passwordDialog->exec();
00398             if (d->passwordDialog->showConnectionDetailsRequested() || ret == QDialog::Accepted) {
00399 //              if ( ret == QDialog::Accepted ) {
00400         //      if (QDialog::Accepted == KPasswordDialog::getPassword(pwd, msg)) {
00401 //moved             cdata.password = QString(pwd);
00402 //              }
00403             } else {
00404                 m_action = Exit;
00405                 return true;
00406             }
00407         }
00408     }
00409 
00410 /*  kdDebug() << "ARGC==" << args->count() << endl;
00411     for (int i=0;i<args->count();i++) {
00412         kdDebug() << "ARG" <<i<< "= " << args->arg(i) <<endl;
00413     }*/
00414 
00415     if (m_forcedFinalMode && m_forcedDesignMode) {
00416         KMessageBox::sorry( 0, i18n(
00417         "You have used both \"final-mode\" and \"design-mode\" startup options.")+couldnotMsg);
00418         return false;
00419     }
00420 
00421     //database filenames, shortcut filenames or db names on a server
00422     if (args->count()>=1) {
00423         QString prjName;
00424         if (fileDriverSelected)
00425             prjName = QFile::decodeName(args->arg(0));
00426         else
00427             prjName = QString::fromLocal8Bit(args->arg(0));
00428         
00429         if (fileDriverSelected) {
00430             QFileInfo finfo(prjName);
00431             cdata.setFileName( finfo.absFilePath() );
00432             projectFileExists = finfo.exists();
00433 
00434             if (dropDB && !projectFileExists) {
00435                 KMessageBox::sorry(0, 
00436                     i18n("Could not remove project.\nThe file \"%1\" does not exist.")
00437                     .arg(QDir::convertSeparators(cdata.dbFileName())));
00438                 return 0;
00439             }
00440         }
00441 
00442         if (createDB) {
00443             if (cdata.driverName.isEmpty())
00444                 cdata.driverName = KexiDB::Driver::defaultFileBasedDriverName();
00445             m_projectData = new KexiProjectData(cdata, prjName); //dummy
00446         }
00447         else {
00448             if (fileDriverSelected) {
00449                 int detectOptions = 0;
00450                 if (fileType=="project")
00451                     detectOptions |= ThisIsAProjectFile;
00452                 else if (fileType=="shortcut")
00453                     detectOptions |= ThisIsAShortcutToAProjectFile;
00454                 else if (fileType=="connection")
00455                     detectOptions |= ThisIsAShortcutToAConnectionData;
00456 
00457                 if (dropDB)
00458                     detectOptions |= DontConvert;
00459 
00460                 QString detectedDriverName;
00461                 const tristate res = detectActionForFile( m_importActionData, detectedDriverName, 
00462                     cdata.driverName, cdata.fileName(), 0, detectOptions );
00463                 if (true != res)
00464                     return res;
00465 
00466                 if (m_importActionData) { //importing action
00467                     m_action = ImportProject;
00468                     return true;
00469                 }
00470 
00471                 //opening action
00472                 cdata.driverName = detectedDriverName;
00473                 if (cdata.driverName=="shortcut") {
00474                     //get information for a shortcut file
00475                     d->shortcutFile = new KexiDBShortcutFile(cdata.fileName());
00476                     m_projectData = new KexiProjectData();
00477                     if (!d->shortcutFile->loadProjectData(*m_projectData, &d->shortcutFileGroupKey)) {
00478                         KMessageBox::sorry(0, i18n("Could not open shortcut file\n\"%1\".")
00479                             .arg(QDir::convertSeparators(cdata.fileName())));
00480                         delete m_projectData;
00481                         m_projectData = 0;
00482                         delete d->shortcutFile;
00483                         d->shortcutFile = 0;
00484                         return false;
00485                     }
00486                     d->connDialog = new KexiDBConnectionDialog(
00487                         *m_projectData, d->shortcutFile->fileName());
00488                     connect(d->connDialog, SIGNAL(saveChanges()), 
00489                         this, SLOT(slotSaveShortcutFileChanges()));
00490                     int res = d->connDialog->exec();
00491                     if (res == QDialog::Accepted) {
00492                         //get (possibly changed) prj data
00493                         *m_projectData = d->connDialog->currentProjectData();
00494                     }
00495 
00496                     delete d->connDialog;
00497                     d->connDialog = 0;
00498                     delete d->shortcutFile;
00499                     d->shortcutFile = 0;
00500 
00501                     if (res == QDialog::Rejected) {
00502                         delete m_projectData;
00503                         m_projectData = 0;
00504                         return cancelled;
00505                     }
00506                 }
00507                 else if (cdata.driverName=="connection") {
00508                     //get information for a connection file
00509                     d->connShortcutFile = new KexiDBConnShortcutFile(cdata.fileName());
00510                     if (!d->connShortcutFile->loadConnectionData(cdata, &d->shortcutFileGroupKey)) {
00511                         KMessageBox::sorry(0, i18n("Could not open connection data file\n\"%1\".")
00512                             .arg(QDir::convertSeparators(cdata.fileName())));
00513                         delete d->connShortcutFile;
00514                         d->connShortcutFile = 0;
00515                         return false;
00516                     }
00517                     bool cancel = false;
00518                     const bool showConnectionDialog = !args->isSet("skip-dialog");
00519                     while (true) {
00520                         if (showConnectionDialog) {
00521                             //show connection dialog, so user can change parameters
00522                             if (!d->connDialog) {
00523                                 d->connDialog = new KexiDBConnectionDialog(
00524                                     cdata, d->connShortcutFile->fileName());
00525                                 connect(d->connDialog, SIGNAL(saveChanges()), 
00526                                     this, SLOT(slotSaveShortcutFileChanges()));
00527                             }
00528                             const int res = d->connDialog->exec();
00529                             if (res == QDialog::Accepted) {
00530                                 //get (possibly changed) prj data
00531                                 cdata = *d->connDialog->currentProjectData().constConnectionData();
00532                             }
00533                             else {
00534                                 cancel = true;
00535                                 break;
00536                             }
00537                         }
00538                         m_projectData = selectProject(&cdata, cancel);
00539                         if (m_projectData || cancel || !showConnectionDialog)
00540                             break;
00541                     }
00542 
00543                     delete d->connShortcutFile;
00544                     d->connShortcutFile = 0;
00545                     delete d->connDialog;
00546                     d->connDialog = 0;
00547 
00548                     if (cancel)
00549                         return cancelled;
00550                 }
00551                 else
00552                     m_projectData = new KexiProjectData(cdata, prjName);
00553             }
00554             else
00555                 m_projectData = new KexiProjectData(cdata, prjName);
00556 
00557         }
00558 //      if (!m_projectData)
00559 //          return false;
00560     }
00561     if (args->count()>1) {
00562         //TODO: KRun another Kexi instances
00563     }
00564 
00565     //let's show connection details, user asked for that in the "password dialog"
00566     if (d->passwordDialog && d->passwordDialog->showConnectionDetailsRequested()) {
00567         d->connDialog = new KexiDBConnectionDialog(*m_projectData);
00568 //      connect(d->connDialog->tabWidget->mainWidget, SIGNAL(saveChanges()), 
00569 //          this, SLOT(slotSaveShortcutFileChanges()));
00570         int res = d->connDialog->exec();
00571 
00572         if (res == QDialog::Accepted) {
00573             //get (possibly changed) prj data
00574             *m_projectData = d->connDialog->currentProjectData();
00575         }
00576 
00577         delete d->connDialog;
00578         d->connDialog = 0;
00579 
00580         if (res == QDialog::Rejected) {
00581             delete m_projectData;
00582             m_projectData = 0;
00583             return cancelled;
00584         }
00585     }
00586 
00587     //---autoopen objects:
00588     const bool atLeastOneAOOFound = getAutoopenObjects(args, "open")
00589         || getAutoopenObjects(args, "design")
00590         || getAutoopenObjects(args, "edittext")
00591         || getAutoopenObjects(args, "new")
00592         || getAutoopenObjects(args, "print")
00593         || getAutoopenObjects(args, "print-preview");
00594 
00595     if (atLeastOneAOOFound && !openExisting) {
00596         KMessageBox::information( 0, 
00597             i18n("You have specified a few database objects to be opened automatically, "
00598                 "using startup options.\n"
00599                 "These options will be ignored because it is not available while creating "
00600                 "or dropping projects."));
00601     }
00602 
00603     if (createDB) {
00604         bool creationNancelled;
00605         KexiGUIMessageHandler gui;
00606         KexiProject *prj = KexiProject::createBlankProject(creationNancelled, projectData(), &gui);
00607         bool ok = prj!=0;
00608         delete prj;
00609         if (creationNancelled)
00610             return cancelled;
00611         if (!alsoOpenDB) {
00612             if (ok) {
00613                 KMessageBox::information( 0, i18n("Project \"%1\" created successfully.")
00614                     .arg( QDir::convertSeparators(projectData()->databaseName()) ));
00615             }
00616             return ok;
00617         }
00618     }
00619     else if (dropDB) {
00620         KexiGUIMessageHandler gui;
00621         tristate res = KexiProject::dropProject(projectData(), &gui, false/*ask*/);
00622         if (res)
00623             KMessageBox::information( 0, i18n("Project \"%1\" dropped successfully.")
00624                 .arg( QDir::convertSeparators(projectData()->databaseName()) ));
00625         return res!=false;
00626     }
00627 
00628     //------
00629 
00630 /*  if (m_forcedFinalMode || (m_projectData && projectData->finalMode())) {
00631         //TODO: maybe also auto allow to open objects...
00632         KexiMainWindowImpl::initFinal(m_projectData);
00633         return;
00634     }*/
00635 
00636     if (!m_projectData) {
00637         cdata = KexiDB::ConnectionData(); //clear
00638 
00639         if (!KexiStartupDialog::shouldBeShown())
00640             return true;
00641 
00642         if (!d->startupDialog) {
00643             //create d->startupDialog for reuse because it can be used again after conn err.
00644             d->startupDialog = new KexiStartupDialog(
00645                 KexiStartupDialog::Everything, KexiStartupDialog::CheckBoxDoNotShowAgain,
00646                 Kexi::connset(), Kexi::recentProjects(), 0, "KexiStartupDialog");
00647         }
00648         if (d->startupDialog->exec()!=QDialog::Accepted)
00649             return true;
00650 
00651         int r = d->startupDialog->result();
00652         if (r==KexiStartupDialog::TemplateResult) {
00653 //          kdDebug() << "Template key == " << d->startupDialog->selectedTemplateKey() << endl;
00654             QString selectedTemplateKey( d->startupDialog->selectedTemplateKey() );
00655             if (selectedTemplateKey=="blank") {
00656                 m_action = CreateBlankProject;
00657                 return true;
00658             }
00659             else if (selectedTemplateKey=="import") {
00660                 m_action = ImportProject;
00661                 return true;
00662             }
00663             
00665             return true;
00666         }
00667         else if (r==KexiStartupDialog::OpenExistingResult) {
00668 //          kdDebug() << "Existing project --------" << endl;
00669             QString selFile = d->startupDialog->selectedExistingFile();
00670             if (!selFile.isEmpty()) {
00671                 //file-based project
00672 //              kdDebug() << "Project File: " << selFile << endl;
00673                 cdata.setFileName( selFile );
00674                 QString detectedDriverName;
00675                 const tristate res = detectActionForFile( m_importActionData, detectedDriverName, 
00676                     cdata.driverName, selFile );
00677                 if (true != res)
00678                     return res;
00679                 if (m_importActionData) { //importing action
00680                     m_action = ImportProject;
00681                     return true;
00682                 }
00683 
00684                 if (detectedDriverName.isEmpty())
00685                     return false;
00686                 cdata.driverName = detectedDriverName;
00687                 m_projectData = new KexiProjectData(cdata, selFile);
00688             }
00689             else if (d->startupDialog->selectedExistingConnection()) {
00690 //              kdDebug() << "Existing connection: " <<
00691 //                  d->startupDialog->selectedExistingConnection()->serverInfoString() << endl;
00692                 KexiDB::ConnectionData *cdata = d->startupDialog->selectedExistingConnection();
00693                 //ok, now we will try to show projects for this connection to the user
00694                 bool cancelled;
00695                 m_projectData = selectProject( cdata, cancelled );
00696                 if (!m_projectData && !cancelled || cancelled) {
00697                         //try again
00698                         return init(0, 0);
00699                 }
00700                 //not needed anymore
00701                 delete d->startupDialog;
00702                 d->startupDialog = 0;
00703             }
00704         }
00705         else if (r==KexiStartupDialog::OpenRecentResult) {
00706 //          kdDebug() << "Recent project --------" << endl;
00707             const KexiProjectData *data = d->startupDialog->selectedProjectData();
00708             if (data) {
00709 //              kdDebug() << "Selected project: database=" << data->databaseName()
00710 //                  << " connection=" << data->constConnectionData()->serverInfoString() << endl;
00711             }
00713             return data!=0;
00714         }
00715 
00716         if (!m_projectData)
00717             return true;
00718     }
00719     
00720     if (m_projectData && (openExisting || (createDB && alsoOpenDB))) {
00721         m_action = OpenProject;
00722     }
00723     //show if wasn't show yet
00724 //  importantInfo(true);
00725     
00726     return true;
00727 }
00728 
00729 tristate KexiStartupHandler::detectActionForFile( 
00730     KexiStartupData::Import& detectedImportAction, QString& detectedDriverName,
00731     const QString& _suggestedDriverName, const QString &dbFileName, QWidget *parent, int options )
00732 {
00733     detectedImportAction = KexiStartupData::Import(); //clear
00734     QString suggestedDriverName(_suggestedDriverName); //safe
00735     detectedDriverName = QString::null;
00736     QFileInfo finfo(dbFileName);
00737     if (dbFileName.isEmpty() || !finfo.isReadable()) {
00738         KMessageBox::sorry(parent, i18n("<p>Could not open project.</p>")
00739             +i18n("<p>The file <nobr>\"%1\"</nobr> does not exist or is not readable.</p>")
00740             .arg(QDir::convertSeparators(dbFileName))
00741             +i18n("Check the file's permissions and whether it is already opened "
00742             "and locked by another application."));
00743         return false;
00744     }
00745 
00746     KMimeType::Ptr ptr;
00747     QString mimename;
00748 
00749     const bool thisIsShortcut = (options & ThisIsAShortcutToAProjectFile) 
00750         || (options & ThisIsAShortcutToAConnectionData);
00751 
00752     if ((options & ThisIsAProjectFile) || !thisIsShortcut) {
00753         //try this detection if "project file" mode is forced or no type is forced:
00754         ptr = KMimeType::findByFileContent(dbFileName);
00755         mimename = ptr.data()->name();
00756         kdDebug() << "KexiStartupHandler::detectActionForFile(): found mime is: " 
00757             << mimename << endl;
00758         if (mimename.isEmpty() || mimename=="application/octet-stream" || mimename=="text/plain") {
00759             //try by URL:
00760             ptr = KMimeType::findByURL(dbFileName);
00761             mimename = ptr.data()->name();
00762         }
00763     }
00764     if (mimename.isEmpty() || mimename=="application/octet-stream") {
00765         // perhaps the file is locked
00766         QFile f(dbFileName);
00767         if (!f.open(IO_ReadOnly)) {
00768             // BTW: similar error msg is provided in SQLiteConnection::drv_useDatabase()
00769             KMessageBox::sorry(parent, i18n("<p>Could not open project.</p>")
00770                 +i18n("<p>The file <nobr>\"%1\"</nobr> is not readable.</p>")
00771                 .arg(QDir::convertSeparators(dbFileName))
00772                 +i18n("Check the file's permissions and whether it is already opened "
00773                     "and locked by another application."));
00774             return false;
00775         }
00776     }
00777     if ((options & ThisIsAShortcutToAProjectFile) || mimename=="application/x-kexiproject-shortcut") {
00778         detectedDriverName = "shortcut";
00779         return true;
00780     }
00781 
00782     if ((options & ThisIsAShortcutToAConnectionData) || mimename=="application/x-kexi-connectiondata") {
00783         detectedDriverName = "connection";
00784         return true;
00785     }
00786 
00789     if (ptr.data()) {
00790         if (mimename=="application/x-msaccess") {
00791             if (KMessageBox::Yes != KMessageBox::questionYesNo(parent, i18n(
00792                 "\"%1\" is an external file of type:\n\"%2\".\n"
00793                 "Do you want to import the file as a Kexi project?")
00794                 .arg(QDir::convertSeparators(dbFileName)).arg(ptr.data()->comment()),
00795                 i18n("Open External File"), KGuiItem(i18n("Import...")), KStdGuiItem::cancel() ) )
00796             {
00797                 return cancelled;
00798             }
00799             detectedImportAction.mimeType = mimename;
00800             detectedImportAction.fileName = dbFileName;
00801             return true;
00802         }
00803     }
00804 
00805     if (!finfo.isWritable()) {
00807     }
00808 
00809     // "application/x-kexiproject-sqlite", etc.:
00810     QString tmpDriverName = Kexi::driverManager().lookupByMime(mimename).latin1();
00811 //@todo What about trying to reuse KOFFICE FILTER CHAINS here?
00812     bool useDetectedDriver = suggestedDriverName.isEmpty() || suggestedDriverName.lower()==detectedDriverName.lower();
00813     if (!useDetectedDriver) {
00814         int res = KMessageBox::warningYesNoCancel(parent, i18n(
00815             "The project file \"%1\" is recognized as compatible with \"%2\" database driver, "
00816             "while you have asked for \"%3\" database driver to be used.\n"
00817             "Do you want to use \"%4\" database driver?")
00818             .arg(QDir::convertSeparators(dbFileName))
00819             .arg(tmpDriverName).arg(suggestedDriverName).arg(tmpDriverName));
00820         if (KMessageBox::Yes == res)
00821             useDetectedDriver = true;
00822         else if (KMessageBox::Cancel == res)
00823             return cancelled;
00824     }
00825     if (useDetectedDriver) {
00826         detectedDriverName = tmpDriverName;
00827     }
00828     else {//use suggested driver
00829         detectedDriverName = suggestedDriverName;
00830     }
00831 //  kdDebug() << "KexiStartupHandler::detectActionForFile(): driver name: " << detectedDriverName << endl;
00832 //hardcoded for convenience:
00833     const QString newFileFormat = "SQLite3";
00834     if (!(options & DontConvert) 
00835         && detectedDriverName.lower()=="sqlite2" && detectedDriverName.lower()!=suggestedDriverName.lower()
00836         && KMessageBox::Yes == KMessageBox::questionYesNo(parent, i18n(
00837             "Previous version of database file format (\"%1\") is detected in the \"%2\" "
00838             "project file.\nDo you want to convert the project to a new \"%3\" format (recommended)?")
00839             .arg(detectedDriverName).arg(QDir::convertSeparators(dbFileName)).arg(newFileFormat)) )
00840     {
00841 //      SQLite2ToSQLite3Migration *migr = new 
00842         SQLite2ToSQLite3Migration migr( finfo.absFilePath() );
00843         tristate res = migr.run();
00844 //      kdDebug() << "--- migr.run() END ---" <<endl;
00845         if (!res) {
00846             //TODO msg
00847             KMessageBox::sorry(parent, i18n(
00848                 "Failed to convert project file \"%1\" to a new \"%2\" format.\n"
00849                 "The file format remains unchanged.")
00850                 .arg(QDir::convertSeparators(dbFileName)).arg(newFileFormat) );
00851             //continue...
00852         }
00853         if (res)
00854             detectedDriverName = newFileFormat;
00855     }
00856 //  action.driverName = detectedDriverName;
00857     if (detectedDriverName.isEmpty()) {
00858         QString possibleProblemsInfoMsg( Kexi::driverManager().possibleProblemsInfoMsg() );
00859         if (!possibleProblemsInfoMsg.isEmpty()) {
00860             possibleProblemsInfoMsg.prepend(QString::fromLatin1("<p>")+i18n("Possible problems:"));
00861             possibleProblemsInfoMsg += QString::fromLatin1("</p>");
00862         }
00863         KMessageBox::detailedSorry(parent, 
00864             i18n( "The file \"%1\" is not recognized as being supported by Kexi.")
00865                 .arg(QDir::convertSeparators(dbFileName)),
00866             QString::fromLatin1("<p>")
00867             +i18n("Database driver for this file type not found.\nDetected MIME type: %1")
00868                 .arg(mimename)
00869             +(ptr.data()->comment().isEmpty() 
00870                 ? QString::fromLatin1(".") : QString::fromLatin1(" (%1).").arg(ptr.data()->comment()))
00871             +QString::fromLatin1("</p>")
00872             +possibleProblemsInfoMsg);
00873         return false;
00874     }
00875     return true;
00876 }
00877 
00878 KexiProjectData*
00879 KexiStartupHandler::selectProject(KexiDB::ConnectionData *cdata, bool& cancelled, QWidget *parent)
00880 {
00881     clearStatus();
00882     cancelled = false;
00883     if (!cdata)
00884         return 0;
00885     if (!cdata->savePassword && cdata->password.isEmpty()) {
00886         if (!d->passwordDialog)
00887             d->passwordDialog = new KexiDBPasswordDialog(0, *cdata, false);
00888         const int ret = d->passwordDialog->exec();
00889         if (d->passwordDialog->showConnectionDetailsRequested() || ret == QDialog::Accepted) {
00890 
00891         } else {
00892             cancelled = true;
00893             return 0;
00894         }
00895     }
00896     KexiProjectData* projectData = 0;
00897     //dialog for selecting a project
00898     KexiProjectSelectorDialog prjdlg( parent, "prjdlg", cdata, true, false );
00899     if (!prjdlg.projectSet() || prjdlg.projectSet()->error()) {
00900         KexiGUIMessageHandler msgh;
00901         if (prjdlg.projectSet())
00902             msgh.showErrorMessage(prjdlg.projectSet(), 
00903                 i18n("Could not load list of available projects for <b>%1</b> database server.")
00904                 .arg(cdata->serverInfoString(true)));
00905         else
00906             msgh.showErrorMessage(
00907                 i18n("Could not load list of available projects for <b>%1</b> database server.")
00908                 .arg(cdata->serverInfoString(true)));
00909 //      setStatus(i18n("Could not load list of available projects for database server \"%1\"")
00910 //      .arg(cdata->serverInfoString(true)), prjdlg.projectSet()->errorMsg());
00911         return 0;
00912     }
00913     if (prjdlg.exec()!=QDialog::Accepted) {
00914         cancelled = true;
00915         return 0;
00916     }
00917     if (prjdlg.selectedProjectData()) {
00918         //deep copy
00919         projectData = new KexiProjectData(*prjdlg.selectedProjectData());
00920     }
00921     return projectData;
00922 }
00923 
00924 void KexiStartupHandler::slotSaveShortcutFileChanges()
00925 {
00926     bool ok = true;
00927     if (d->shortcutFile)
00928         ok = d->shortcutFile->saveProjectData(d->connDialog->currentProjectData(), 
00929             d->connDialog->savePasswordOptionSelected(), 
00930             &d->shortcutFileGroupKey );
00931     else if (d->connShortcutFile)
00932         ok = d->connShortcutFile->saveConnectionData(
00933             *d->connDialog->currentProjectData().connectionData(), 
00934             d->connDialog->savePasswordOptionSelected(), 
00935             &d->shortcutFileGroupKey );
00936 
00937     if (!ok) {
00938         KMessageBox::sorry(0, i18n("Failed saving connection data to\n\"%1\" file.")
00939             .arg(QDir::convertSeparators(d->shortcutFile->fileName())));
00940     }
00941 }
00942 
00943 /*void KexiStartupHandler::slotShowConnectionDetails()
00944 {
00945     d->passwordDialog->close();
00946     d->showConnectionDetailsExecuted = true;
00947 }*/
00948 
00949 #include "KexiStartup.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys