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         QString fileName;
00425         if (fileDriverSelected) {
00426             fileName = QFile::decodeName(args->arg(0));
00427         }
00428         else {
00429             prjName = QString::fromLocal8Bit(args->arg(0));
00430         }
00431         
00432         if (fileDriverSelected) {
00433             QFileInfo finfo(fileName);
00434             prjName = finfo.fileName(); //filename only, to avoid messy names like when Kexi is started with "../../db" arg
00435             cdata.setFileName( finfo.absFilePath() );
00436             projectFileExists = finfo.exists();
00437 
00438             if (dropDB && !projectFileExists) {
00439                 KMessageBox::sorry(0, 
00440                     i18n("Could not remove project.\nThe file \"%1\" does not exist.")
00441                     .arg(QDir::convertSeparators(cdata.dbFileName())));
00442                 return 0;
00443             }
00444         }
00445 
00446         if (createDB) {
00447             if (cdata.driverName.isEmpty())
00448                 cdata.driverName = KexiDB::Driver::defaultFileBasedDriverName();
00449             m_projectData = new KexiProjectData(cdata, prjName); //dummy
00450         }
00451         else {
00452             if (fileDriverSelected) {
00453                 int detectOptions = 0;
00454                 if (fileType=="project")
00455                     detectOptions |= ThisIsAProjectFile;
00456                 else if (fileType=="shortcut")
00457                     detectOptions |= ThisIsAShortcutToAProjectFile;
00458                 else if (fileType=="connection")
00459                     detectOptions |= ThisIsAShortcutToAConnectionData;
00460 
00461                 if (dropDB)
00462                     detectOptions |= DontConvert;
00463 
00464                 QString detectedDriverName;
00465                 const tristate res = detectActionForFile( m_importActionData, detectedDriverName, 
00466                     cdata.driverName, cdata.fileName(), 0, detectOptions );
00467                 if (true != res)
00468                     return res;
00469 
00470                 if (m_importActionData) { //importing action
00471                     m_action = ImportProject;
00472                     return true;
00473                 }
00474 
00475                 //opening action
00476                 cdata.driverName = detectedDriverName;
00477                 if (cdata.driverName=="shortcut") {
00478                     //get information for a shortcut file
00479                     d->shortcutFile = new KexiDBShortcutFile(cdata.fileName());
00480                     m_projectData = new KexiProjectData();
00481                     if (!d->shortcutFile->loadProjectData(*m_projectData, &d->shortcutFileGroupKey)) {
00482                         KMessageBox::sorry(0, i18n("Could not open shortcut file\n\"%1\".")
00483                             .arg(QDir::convertSeparators(cdata.fileName())));
00484                         delete m_projectData;
00485                         m_projectData = 0;
00486                         delete d->shortcutFile;
00487                         d->shortcutFile = 0;
00488                         return false;
00489                     }
00490                     d->connDialog = new KexiDBConnectionDialog(
00491                         *m_projectData, d->shortcutFile->fileName());
00492                     connect(d->connDialog, SIGNAL(saveChanges()), 
00493                         this, SLOT(slotSaveShortcutFileChanges()));
00494                     int res = d->connDialog->exec();
00495                     if (res == QDialog::Accepted) {
00496                         //get (possibly changed) prj data
00497                         *m_projectData = d->connDialog->currentProjectData();
00498                     }
00499 
00500                     delete d->connDialog;
00501                     d->connDialog = 0;
00502                     delete d->shortcutFile;
00503                     d->shortcutFile = 0;
00504 
00505                     if (res == QDialog::Rejected) {
00506                         delete m_projectData;
00507                         m_projectData = 0;
00508                         return cancelled;
00509                     }
00510                 }
00511                 else if (cdata.driverName=="connection") {
00512                     //get information for a connection file
00513                     d->connShortcutFile = new KexiDBConnShortcutFile(cdata.fileName());
00514                     if (!d->connShortcutFile->loadConnectionData(cdata, &d->shortcutFileGroupKey)) {
00515                         KMessageBox::sorry(0, i18n("Could not open connection data file\n\"%1\".")
00516                             .arg(QDir::convertSeparators(cdata.fileName())));
00517                         delete d->connShortcutFile;
00518                         d->connShortcutFile = 0;
00519                         return false;
00520                     }
00521                     bool cancel = false;
00522                     const bool showConnectionDialog = !args->isSet("skip-dialog");
00523                     while (true) {
00524                         if (showConnectionDialog) {
00525                             //show connection dialog, so user can change parameters
00526                             if (!d->connDialog) {
00527                                 d->connDialog = new KexiDBConnectionDialog(
00528                                     cdata, d->connShortcutFile->fileName());
00529                                 connect(d->connDialog, SIGNAL(saveChanges()), 
00530                                     this, SLOT(slotSaveShortcutFileChanges()));
00531                             }
00532                             const int res = d->connDialog->exec();
00533                             if (res == QDialog::Accepted) {
00534                                 //get (possibly changed) prj data
00535                                 cdata = *d->connDialog->currentProjectData().constConnectionData();
00536                             }
00537                             else {
00538                                 cancel = true;
00539                                 break;
00540                             }
00541                         }
00542                         m_projectData = selectProject(&cdata, cancel);
00543                         if (m_projectData || cancel || !showConnectionDialog)
00544                             break;
00545                     }
00546 
00547                     delete d->connShortcutFile;
00548                     d->connShortcutFile = 0;
00549                     delete d->connDialog;
00550                     d->connDialog = 0;
00551 
00552                     if (cancel)
00553                         return cancelled;
00554                 }
00555                 else
00556                     m_projectData = new KexiProjectData(cdata, prjName);
00557             }
00558             else
00559                 m_projectData = new KexiProjectData(cdata, prjName);
00560 
00561         }
00562 //      if (!m_projectData)
00563 //          return false;
00564     }
00565     if (args->count()>1) {
00566         //TODO: KRun another Kexi instances
00567     }
00568 
00569     //let's show connection details, user asked for that in the "password dialog"
00570     if (d->passwordDialog && d->passwordDialog->showConnectionDetailsRequested()) {
00571         d->connDialog = new KexiDBConnectionDialog(*m_projectData);
00572 //      connect(d->connDialog->tabWidget->mainWidget, SIGNAL(saveChanges()), 
00573 //          this, SLOT(slotSaveShortcutFileChanges()));
00574         int res = d->connDialog->exec();
00575 
00576         if (res == QDialog::Accepted) {
00577             //get (possibly changed) prj data
00578             *m_projectData = d->connDialog->currentProjectData();
00579         }
00580 
00581         delete d->connDialog;
00582         d->connDialog = 0;
00583 
00584         if (res == QDialog::Rejected) {
00585             delete m_projectData;
00586             m_projectData = 0;
00587             return cancelled;
00588         }
00589     }
00590 
00591     //---autoopen objects:
00592     const bool atLeastOneAOOFound = getAutoopenObjects(args, "open")
00593         || getAutoopenObjects(args, "design")
00594         || getAutoopenObjects(args, "edittext")
00595         || getAutoopenObjects(args, "new")
00596         || getAutoopenObjects(args, "print")
00597         || getAutoopenObjects(args, "print-preview");
00598 
00599     if (atLeastOneAOOFound && !openExisting) {
00600         KMessageBox::information( 0, 
00601             i18n("You have specified a few database objects to be opened automatically, "
00602                 "using startup options.\n"
00603                 "These options will be ignored because it is not available while creating "
00604                 "or dropping projects."));
00605     }
00606 
00607     if (createDB) {
00608         bool creationNancelled;
00609         KexiGUIMessageHandler gui;
00610         KexiProject *prj = KexiProject::createBlankProject(creationNancelled, projectData(), &gui);
00611         bool ok = prj!=0;
00612         delete prj;
00613         if (creationNancelled)
00614             return cancelled;
00615         if (!alsoOpenDB) {
00616             if (ok) {
00617                 KMessageBox::information( 0, i18n("Project \"%1\" created successfully.")
00618                     .arg( QDir::convertSeparators(projectData()->databaseName()) ));
00619             }
00620             return ok;
00621         }
00622     }
00623     else if (dropDB) {
00624         KexiGUIMessageHandler gui;
00625         tristate res = KexiProject::dropProject(projectData(), &gui, false/*ask*/);
00626         if (res)
00627             KMessageBox::information( 0, i18n("Project \"%1\" dropped successfully.")
00628                 .arg( QDir::convertSeparators(projectData()->databaseName()) ));
00629         return res!=false;
00630     }
00631 
00632     //------
00633 
00634 /*  if (m_forcedFinalMode || (m_projectData && projectData->finalMode())) {
00635         //TODO: maybe also auto allow to open objects...
00636         KexiMainWindowImpl::initFinal(m_projectData);
00637         return;
00638     }*/
00639 
00640     if (!m_projectData) {
00641         cdata = KexiDB::ConnectionData(); //clear
00642 
00643         if (!KexiStartupDialog::shouldBeShown())
00644             return true;
00645 
00646         if (!d->startupDialog) {
00647             //create d->startupDialog for reuse because it can be used again after conn err.
00648             d->startupDialog = new KexiStartupDialog(
00649                 KexiStartupDialog::Everything, KexiStartupDialog::CheckBoxDoNotShowAgain,
00650                 Kexi::connset(), Kexi::recentProjects(), 0, "KexiStartupDialog");
00651         }
00652         if (d->startupDialog->exec()!=QDialog::Accepted)
00653             return true;
00654 
00655         int r = d->startupDialog->result();
00656         if (r==KexiStartupDialog::TemplateResult) {
00657 //          kdDebug() << "Template key == " << d->startupDialog->selectedTemplateKey() << endl;
00658             QString selectedTemplateKey( d->startupDialog->selectedTemplateKey() );
00659             if (selectedTemplateKey=="blank") {
00660                 m_action = CreateBlankProject;
00661                 return true;
00662             }
00663             else if (selectedTemplateKey=="import") {
00664                 m_action = ImportProject;
00665                 return true;
00666             }
00667             
00669             return true;
00670         }
00671         else if (r==KexiStartupDialog::OpenExistingResult) {
00672 //          kdDebug() << "Existing project --------" << endl;
00673             QString selFile = d->startupDialog->selectedExistingFile();
00674             if (!selFile.isEmpty()) {
00675                 //file-based project
00676 //              kdDebug() << "Project File: " << selFile << endl;
00677                 cdata.setFileName( selFile );
00678                 QString detectedDriverName;
00679                 const tristate res = detectActionForFile( m_importActionData, detectedDriverName, 
00680                     cdata.driverName, selFile );
00681                 if (true != res)
00682                     return res;
00683                 if (m_importActionData) { //importing action
00684                     m_action = ImportProject;
00685                     return true;
00686                 }
00687 
00688                 if (detectedDriverName.isEmpty())
00689                     return false;
00690                 cdata.driverName = detectedDriverName;
00691                 m_projectData = new KexiProjectData(cdata, selFile);
00692             }
00693             else if (d->startupDialog->selectedExistingConnection()) {
00694 //              kdDebug() << "Existing connection: " <<
00695 //                  d->startupDialog->selectedExistingConnection()->serverInfoString() << endl;
00696                 KexiDB::ConnectionData *cdata = d->startupDialog->selectedExistingConnection();
00697                 //ok, now we will try to show projects for this connection to the user
00698                 bool cancelled;
00699                 m_projectData = selectProject( cdata, cancelled );
00700                 if (!m_projectData && !cancelled || cancelled) {
00701                         //try again
00702                         return init(0, 0);
00703                 }
00704                 //not needed anymore
00705                 delete d->startupDialog;
00706                 d->startupDialog = 0;
00707             }
00708         }
00709         else if (r==KexiStartupDialog::OpenRecentResult) {
00710 //          kdDebug() << "Recent project --------" << endl;
00711             const KexiProjectData *data = d->startupDialog->selectedProjectData();
00712             if (data) {
00713 //              kdDebug() << "Selected project: database=" << data->databaseName()
00714 //                  << " connection=" << data->constConnectionData()->serverInfoString() << endl;
00715             }
00717             return data!=0;
00718         }
00719 
00720         if (!m_projectData)
00721             return true;
00722     }
00723     
00724     if (m_projectData && (openExisting || (createDB && alsoOpenDB))) {
00725         m_action = OpenProject;
00726     }
00727     //show if wasn't show yet
00728 //  importantInfo(true);
00729     
00730     return true;
00731 }
00732 
00733 tristate KexiStartupHandler::detectActionForFile( 
00734     KexiStartupData::Import& detectedImportAction, QString& detectedDriverName,
00735     const QString& _suggestedDriverName, const QString &dbFileName, QWidget *parent, int options )
00736 {
00737     detectedImportAction = KexiStartupData::Import(); //clear
00738     QString suggestedDriverName(_suggestedDriverName); //safe
00739     detectedDriverName = QString::null;
00740     QFileInfo finfo(dbFileName);
00741     if (dbFileName.isEmpty() || !finfo.isReadable()) {
00742         KMessageBox::sorry(parent, i18n("<p>Could not open project.</p>")
00743             +i18n("<p>The file <nobr>\"%1\"</nobr> does not exist or is not readable.</p>")
00744             .arg(QDir::convertSeparators(dbFileName))
00745             +i18n("Check the file's permissions and whether it is already opened "
00746             "and locked by another application."));
00747         return false;
00748     }
00749 
00750     KMimeType::Ptr ptr;
00751     QString mimename;
00752 
00753     const bool thisIsShortcut = (options & ThisIsAShortcutToAProjectFile) 
00754         || (options & ThisIsAShortcutToAConnectionData);
00755 
00756     if ((options & ThisIsAProjectFile) || !thisIsShortcut) {
00757         //try this detection if "project file" mode is forced or no type is forced:
00758         ptr = KMimeType::findByFileContent(dbFileName);
00759         mimename = ptr.data()->name();
00760         kdDebug() << "KexiStartupHandler::detectActionForFile(): found mime is: " 
00761             << mimename << endl;
00762         if (mimename.isEmpty() || mimename=="application/octet-stream" || mimename=="text/plain") {
00763             //try by URL:
00764             ptr = KMimeType::findByURL(dbFileName);
00765             mimename = ptr.data()->name();
00766         }
00767     }
00768     if (mimename.isEmpty() || mimename=="application/octet-stream") {
00769         // perhaps the file is locked
00770         QFile f(dbFileName);
00771         if (!f.open(IO_ReadOnly)) {
00772             // BTW: similar error msg is provided in SQLiteConnection::drv_useDatabase()
00773             KMessageBox::sorry(parent, i18n("<p>Could not open project.</p>")
00774                 +i18n("<p>The file <nobr>\"%1\"</nobr> is not readable.</p>")
00775                 .arg(QDir::convertSeparators(dbFileName))
00776                 +i18n("Check the file's permissions and whether it is already opened "
00777                     "and locked by another application."));
00778             return false;
00779         }
00780     }
00781     if ((options & ThisIsAShortcutToAProjectFile) || mimename=="application/x-kexiproject-shortcut") {
00782         detectedDriverName = "shortcut";
00783         return true;
00784     }
00785 
00786     if ((options & ThisIsAShortcutToAConnectionData) || mimename=="application/x-kexi-connectiondata") {
00787         detectedDriverName = "connection";
00788         return true;
00789     }
00790 
00793     if (ptr.data()) {
00794         if (mimename=="application/x-msaccess") {
00795             if (KMessageBox::Yes != KMessageBox::questionYesNo(parent, i18n(
00796                 "\"%1\" is an external file of type:\n\"%2\".\n"
00797                 "Do you want to import the file as a Kexi project?")
00798                 .arg(QDir::convertSeparators(dbFileName)).arg(ptr.data()->comment()),
00799                 i18n("Open External File"), KGuiItem(i18n("Import...")), KStdGuiItem::cancel() ) )
00800             {
00801                 return cancelled;
00802             }
00803             detectedImportAction.mimeType = mimename;
00804             detectedImportAction.fileName = dbFileName;
00805             return true;
00806         }
00807     }
00808 
00809     if (!finfo.isWritable()) {
00811     }
00812 
00813     // "application/x-kexiproject-sqlite", etc.:
00814     QString tmpDriverName = Kexi::driverManager().lookupByMime(mimename).latin1();
00815 //@todo What about trying to reuse KOFFICE FILTER CHAINS here?
00816     bool useDetectedDriver = suggestedDriverName.isEmpty() || suggestedDriverName.lower()==detectedDriverName.lower();
00817     if (!useDetectedDriver) {
00818         int res = KMessageBox::warningYesNoCancel(parent, i18n(
00819             "The project file \"%1\" is recognized as compatible with \"%2\" database driver, "
00820             "while you have asked for \"%3\" database driver to be used.\n"
00821             "Do you want to use \"%4\" database driver?")
00822             .arg(QDir::convertSeparators(dbFileName))
00823             .arg(tmpDriverName).arg(suggestedDriverName).arg(tmpDriverName));
00824         if (KMessageBox::Yes == res)
00825             useDetectedDriver = true;
00826         else if (KMessageBox::Cancel == res)
00827             return cancelled;
00828     }
00829     if (useDetectedDriver) {
00830         detectedDriverName = tmpDriverName;
00831     }
00832     else {//use suggested driver
00833         detectedDriverName = suggestedDriverName;
00834     }
00835 //  kdDebug() << "KexiStartupHandler::detectActionForFile(): driver name: " << detectedDriverName << endl;
00836 //hardcoded for convenience:
00837     const QString newFileFormat = "SQLite3";
00838     if (!(options & DontConvert) 
00839         && detectedDriverName.lower()=="sqlite2" && detectedDriverName.lower()!=suggestedDriverName.lower()
00840         && KMessageBox::Yes == KMessageBox::questionYesNo(parent, i18n(
00841             "Previous version of database file format (\"%1\") is detected in the \"%2\" "
00842             "project file.\nDo you want to convert the project to a new \"%3\" format (recommended)?")
00843             .arg(detectedDriverName).arg(QDir::convertSeparators(dbFileName)).arg(newFileFormat)) )
00844     {
00845 //      SQLite2ToSQLite3Migration *migr = new 
00846         SQLite2ToSQLite3Migration migr( finfo.absFilePath() );
00847         tristate res = migr.run();
00848 //      kdDebug() << "--- migr.run() END ---" <<endl;
00849         if (!res) {
00850             //TODO msg
00851             KMessageBox::sorry(parent, i18n(
00852                 "Failed to convert project file \"%1\" to a new \"%2\" format.\n"
00853                 "The file format remains unchanged.")
00854                 .arg(QDir::convertSeparators(dbFileName)).arg(newFileFormat) );
00855             //continue...
00856         }
00857         if (res)
00858             detectedDriverName = newFileFormat;
00859     }
00860 //  action.driverName = detectedDriverName;
00861     if (detectedDriverName.isEmpty()) {
00862         QString possibleProblemsInfoMsg( Kexi::driverManager().possibleProblemsInfoMsg() );
00863         if (!possibleProblemsInfoMsg.isEmpty()) {
00864             possibleProblemsInfoMsg.prepend(QString::fromLatin1("<p>")+i18n("Possible problems:"));
00865             possibleProblemsInfoMsg += QString::fromLatin1("</p>");
00866         }
00867         KMessageBox::detailedSorry(parent, 
00868             i18n( "The file \"%1\" is not recognized as being supported by Kexi.")
00869                 .arg(QDir::convertSeparators(dbFileName)),
00870             QString::fromLatin1("<p>")
00871             +i18n("Database driver for this file type not found.\nDetected MIME type: %1")
00872                 .arg(mimename)
00873             +(ptr.data()->comment().isEmpty() 
00874                 ? QString::fromLatin1(".") : QString::fromLatin1(" (%1).").arg(ptr.data()->comment()))
00875             +QString::fromLatin1("</p>")
00876             +possibleProblemsInfoMsg);
00877         return false;
00878     }
00879     return true;
00880 }
00881 
00882 KexiProjectData*
00883 KexiStartupHandler::selectProject(KexiDB::ConnectionData *cdata, bool& cancelled, QWidget *parent)
00884 {
00885     clearStatus();
00886     cancelled = false;
00887     if (!cdata)
00888         return 0;
00889     if (!cdata->savePassword && cdata->password.isEmpty()) {
00890         if (!d->passwordDialog)
00891             d->passwordDialog = new KexiDBPasswordDialog(0, *cdata, false);
00892         const int ret = d->passwordDialog->exec();
00893         if (d->passwordDialog->showConnectionDetailsRequested() || ret == QDialog::Accepted) {
00894 
00895         } else {
00896             cancelled = true;
00897             return 0;
00898         }
00899     }
00900     KexiProjectData* projectData = 0;
00901     //dialog for selecting a project
00902     KexiProjectSelectorDialog prjdlg( parent, "prjdlg", cdata, true, false );
00903     if (!prjdlg.projectSet() || prjdlg.projectSet()->error()) {
00904         KexiGUIMessageHandler msgh;
00905         if (prjdlg.projectSet())
00906             msgh.showErrorMessage(prjdlg.projectSet(), 
00907                 i18n("Could not load list of available projects for <b>%1</b> database server.")
00908                 .arg(cdata->serverInfoString(true)));
00909         else
00910             msgh.showErrorMessage(
00911                 i18n("Could not load list of available projects for <b>%1</b> database server.")
00912                 .arg(cdata->serverInfoString(true)));
00913 //      setStatus(i18n("Could not load list of available projects for database server \"%1\"")
00914 //      .arg(cdata->serverInfoString(true)), prjdlg.projectSet()->errorMsg());
00915         return 0;
00916     }
00917     if (prjdlg.exec()!=QDialog::Accepted) {
00918         cancelled = true;
00919         return 0;
00920     }
00921     if (prjdlg.selectedProjectData()) {
00922         //deep copy
00923         projectData = new KexiProjectData(*prjdlg.selectedProjectData());
00924     }
00925     return projectData;
00926 }
00927 
00928 void KexiStartupHandler::slotSaveShortcutFileChanges()
00929 {
00930     bool ok = true;
00931     if (d->shortcutFile)
00932         ok = d->shortcutFile->saveProjectData(d->connDialog->currentProjectData(), 
00933             d->connDialog->savePasswordOptionSelected(), 
00934             &d->shortcutFileGroupKey );
00935     else if (d->connShortcutFile)
00936         ok = d->connShortcutFile->saveConnectionData(
00937             *d->connDialog->currentProjectData().connectionData(), 
00938             d->connDialog->savePasswordOptionSelected(), 
00939             &d->shortcutFileGroupKey );
00940 
00941     if (!ok) {
00942         KMessageBox::sorry(0, i18n("Failed saving connection data to\n\"%1\" file.")
00943             .arg(QDir::convertSeparators(d->shortcutFile->fileName())));
00944     }
00945 }
00946 
00947 /*void KexiStartupHandler::slotShowConnectionDetails()
00948 {
00949     d->passwordDialog->close();
00950     d->showConnectionDetailsExecuted = true;
00951 }*/
00952 
00953 #include "KexiStartup.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys