kexi

KexiStartup.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003-2007 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 #include <kuser.h>
00052 
00053 #include <unistd.h>
00054 
00055 #include <qcstring.h>
00056 #include <qapplication.h>
00057 #include <qlayout.h>
00058 
00059 namespace Kexi {
00060     static KStaticDeleter<KexiStartupHandler> Kexi_startupHandlerDeleter;
00061     KexiStartupHandler* _startupHandler = 0;
00062 
00063     KexiStartupHandler& startupHandler()
00064     {
00065         if (!_startupHandler)
00066             Kexi_startupHandlerDeleter.setObject( _startupHandler, new KexiStartupHandler() );
00067         return *_startupHandler; 
00068     }
00069 }
00070 
00071 //---------------------------------
00072 
00074 class KexiStartupHandlerPrivate
00075 {
00076     public:
00077         KexiStartupHandlerPrivate()
00078          : passwordDialog(0)//, showConnectionDetailsExecuted(false)
00079             , shortcutFile(0), connShortcutFile(0), connDialog(0), startupDialog(0)
00080         {
00081         }
00082 
00083         ~KexiStartupHandlerPrivate()
00084         {
00085             delete passwordDialog;
00086             delete connDialog;
00087             delete startupDialog;
00088         }
00089 
00090         KexiDBPasswordDialog* passwordDialog;
00091 //      bool showConnectionDetailsExecuted : 1;
00092         KexiDBShortcutFile *shortcutFile;
00093         KexiDBConnShortcutFile *connShortcutFile;
00094         KexiDBConnectionDialog *connDialog;
00095         QString shortcutFileGroupKey;
00096         KexiStartupDialog *startupDialog;
00097 };
00098 
00099 //---------------------------------
00100 
00101 static bool stripQuotes(const QString &item, QString &name)
00102 {
00103     if (item.left(1)=="\"" && item.right(1)=="\"") {
00104         name = item.mid(1, item.length()-2);
00105         return true;
00106     }
00107     name = item;
00108     return false;
00109 }
00110 
00111 void updateProgressBar(KProgressDialog *pd, char *buffer, int buflen)
00112 {
00113     char *p = buffer;
00114     QCString line(80);
00115     for (int i=0; i<buflen; i++, p++) {
00116         if ((i==0 || buffer[i-1]=='\n') && buffer[i]=='%') {
00117             bool ok;
00118             int j=0;
00119 //          char *q=++p;
00120             ++i;
00121             line="";
00122             for (;i<buflen && *p>='0' && *p<='9'; j++, i++, p++)
00123                 line+=QChar(*p);
00124             --i; --p;
00125             int percent = line.toInt(&ok);
00126             if (ok && percent>=0 && percent<=100 && pd->progressBar()->progress()<percent) {
00127 //              kdDebug() << percent << endl;
00128                 pd->progressBar()->setProgress(percent);
00129                 qApp->processEvents(100);
00130             }
00131         }
00132     }
00133 }
00134 
00135 //---------------------------------
00136 
00137 KexiDBPasswordDialog::KexiDBPasswordDialog(QWidget *parent, KexiDB::ConnectionData& cdata, bool showDetailsButton)
00138  : KPasswordDialog( KPasswordDialog::Password, false/*keep*/, 
00139     showDetailsButton ? (int)KDialogBase::User1 : 0, parent )
00140  , m_cdata(&cdata)
00141  , m_showConnectionDetailsRequested(false)
00142 {
00143     QString msg = "<H2>" + i18n("Opening database") + "</H2><p>"
00144      + i18n("Please enter the password.") + "</p>";
00145 /*      msg += cdata.userName.isEmpty() ?
00146             "<p>"+i18n("Please enter the password.")
00147             : "<p>"+i18n("Please enter the password for user.").arg("<b>"+cdata.userName+"</b>");*/
00148 
00149     QString srv = cdata.serverInfoString(false);
00150     if (srv.isEmpty() || srv.lower()=="localhost")
00151         srv = i18n("local database server");
00152 
00153     msg += ("</p><p>"+i18n("Database server: %1").arg(QString("<nobr>")+srv+"</nobr>")+"</p>");
00154         
00155     QString usr;
00156     if (cdata.userName.isEmpty())
00157         usr = i18n("unspecified user", "(unspecified)");
00158     else
00159         usr = cdata.userName;
00160     
00161     msg += ("<p>"+i18n("Username: %1").arg(usr)+"</p>");
00162 
00163     setPrompt( msg );
00164     if (showDetailsButton) {
00165         connect( this, SIGNAL(user1Clicked()), 
00166             this, SLOT(slotShowConnectionDetails()) );
00167         setButtonText(KDialogBase::User1, i18n("&Details")+ " >>");
00168     }
00169     setButtonOK(KGuiItem(i18n("&Open"), "fileopen"));
00170 }
00171 
00172 KexiDBPasswordDialog::~KexiDBPasswordDialog()
00173 {
00174 }
00175 
00176 void KexiDBPasswordDialog::done(int r)
00177 {
00178     if (r == QDialog::Accepted) {
00179         m_cdata->password = QString::fromLatin1(password());
00180     }
00181 //  if (d->showConnectionDetailsExecuted || ret == QDialog::Accepted) {
00182 /*          } else {
00183                 m_action = Exit;
00184                 return true;
00185             }
00186         }*/
00187     KPasswordDialog::done(r);
00188 }
00189 
00190 void KexiDBPasswordDialog::slotShowConnectionDetails()
00191 {
00192     m_showConnectionDetailsRequested = true;
00193     close();
00194 }
00195 
00196 //---------------------------------
00197 KexiStartupHandler::KexiStartupHandler()
00198  : QObject(0,"KexiStartupHandler")
00199  , KexiStartupData()
00200  , d( new KexiStartupHandlerPrivate() )
00201 {
00202 }
00203 
00204 KexiStartupHandler::~KexiStartupHandler()
00205 {
00206     delete d;
00207 }
00208 
00209 bool KexiStartupHandler::getAutoopenObjects(KCmdLineArgs *args, const QCString &action_name)
00210 {
00211     QCStringList list = args->getOptionList(action_name);
00212     QCStringList::ConstIterator it;
00213     bool atLeastOneFound = false;
00214     for ( it = list.constBegin(); it!=list.constEnd(); ++it) {
00215         QString type_name, obj_name, item=*it;
00216         int idx;
00217         bool name_required = true;
00218         if (action_name=="new") {
00219             obj_name = "";
00220             stripQuotes(item, type_name);
00221             name_required = false;
00222         }
00223         else {//open, design, text...
00224             QString defaultType;
00225             if (action_name=="execute")
00226                 defaultType = "macro";
00227             else
00228                 defaultType = "table";
00229 
00230             //option with " " (set default type)
00231             if (stripQuotes(item, obj_name)) {
00232                 type_name = defaultType;
00233             }
00234             else if ((idx = item.find(':'))!=-1) {
00235                 //option with type name specified:
00236                 type_name = item.left(idx).lower();
00237                 obj_name = item.mid(idx+1);
00238                 //optional: remove ""
00239                 if (obj_name.left(1)=="\"" && obj_name.right(1)=="\"")
00240                     obj_name = obj_name.mid(1, obj_name.length()-2);
00241             }
00242             else {
00243                 //just obj. name: set default type name
00244                 obj_name = item;
00245                 type_name = defaultType;
00246             }
00247         }
00248         if (type_name.isEmpty())
00249             continue;
00250         if (name_required && obj_name.isEmpty())
00251             continue;
00252 
00253         KexiProjectData::ObjectInfo info;
00254         info["name"]=obj_name;
00255         info["type"]=type_name;
00256         info["action"]=action_name;
00257         //ok, now add info for this object
00258         atLeastOneFound = true;
00259         if (projectData())
00260             projectData()->autoopenObjects.append( info );
00261         else
00262             return true; //no need to find more because we do not have projectData() anyway
00263     } //for
00264     return atLeastOneFound;
00265 }
00266 
00267 tristate KexiStartupHandler::init(int /*argc*/, char ** /*argv*/)
00268 {
00269     m_action = DoNothing;
00270 //  d->showConnectionDetailsExecuted = false;
00271     KCmdLineArgs *args = KCmdLineArgs::parsedArgs(0);
00272     if (!args)
00273         return true;
00274 
00275     KexiDB::ConnectionData cdata;
00276 
00277     const QString connectionShortcutFileName( args->getOption("connection") );
00278     if (!connectionShortcutFileName.isEmpty()) {
00279         KexiDBConnShortcutFile connectionShortcut( connectionShortcutFileName );
00280         if (!connectionShortcut.loadConnectionData(cdata)) {
00283             KMessageBox::sorry( 0, "<qt>"
00284                 +i18n("Could not read connection information from connection shortcut "
00285                 "file <nobr>\"%1\"</nobr>.<br><br>Check whether the file has valid contents.")
00286                 .arg(QDir::convertSeparators(connectionShortcut.fileName())));
00287             return false;
00288         }
00289     }
00290     
00291     if (!args->getOption("dbdriver").isEmpty())
00292         cdata.driverName = args->getOption("dbdriver");
00293 
00294     QString fileType( args->getOption("type").lower() );
00295     if (args->count()>0 && (!fileType.isEmpty() && fileType!="project" && fileType!="shortcut" && fileType!="connection")) {
00296         KMessageBox::sorry( 0, 
00297             i18n("You have specified invalid argument (\"%1\") for \"type\" command-line option.")
00298             .arg(fileType));
00299         return false;
00300     }
00301 
00302 //  if (cdata.driverName.isEmpty())
00303 //      cdata.driverName = KexiDB::Driver::defaultFileBasedDriverName();
00304     if (!args->getOption("host").isEmpty())
00305         cdata.hostName = args->getOption("host");
00306     if (!args->getOption("local-socket").isEmpty())
00307         cdata.localSocketFileName = args->getOption("local-socket");
00308     if (!args->getOption("user").isEmpty())
00309         cdata.userName = args->getOption("user");
00310 //  cdata.password = args->getOption("password");
00311     bool fileDriverSelected;
00312     if (cdata.driverName.isEmpty())
00313         fileDriverSelected = true;
00314     else {
00315         KexiDB::DriverManager dm;
00316         KexiDB::Driver::Info dinfo = dm.driverInfo(cdata.driverName);
00317         if (dinfo.name.isEmpty()) {
00318             //driver name provided explicitly, but not found
00319             KMessageBox::sorry(0, dm.errorMsg());
00320             return false;
00321         }
00322         fileDriverSelected = dinfo.fileBased;
00323     }
00324     bool projectFileExists = false;
00325 
00326     //obfuscate the password, if present
00327 //removed
00328 /*
00329     for (int i=1; i<(argc-1); i++) {
00330         if (qstrcmp("--password",argv[i])==0
00331             || qstrcmp("-password",argv[i])==0)
00332         {
00333             QCString pwd(argv[i+1]);
00334             if (!pwd.isEmpty()) {
00335                 pwd.fill(' ');
00336                 pwd[0]='x';
00337                 qstrcpy(argv[i+1], (const char*)pwd);
00338             }
00339             break;
00340         }
00341     }
00342     */
00343     
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 
00357     m_forcedUserMode = args->isSet("user-mode");
00358     m_forcedDesignMode = args->isSet("design-mode");
00359     m_isProjectNavigatorVisible = args->isSet("show-navigator");
00360     bool createDB = args->isSet("createdb");
00361     const bool alsoOpenDB = args->isSet("create-opendb");
00362     if (alsoOpenDB)
00363         createDB = true;
00364     const bool dropDB = args->isSet("dropdb");
00365     const bool openExisting = !createDB && !dropDB;
00366     const bool readOnly = args->isSet("readonly");
00367     const QString couldnotMsg = QString::fromLatin1("\n")
00368         +i18n("Could not start Kexi application this way.");
00369 
00370     if (createDB && dropDB) {
00371         KMessageBox::sorry( 0, i18n(
00372             "You have used both \"createdb\" and \"dropdb\" startup options.")+couldnotMsg);
00373         return false;
00374     };
00375 
00376     if (createDB || dropDB) {
00377         if (args->count()<1) {
00378             KMessageBox::sorry( 0, i18n("No project name specified.") );
00379             return false;
00380         }
00381         m_action = Exit;
00382     }
00383 
00384 //TODO: add option for non-gui; integrate with KWallet; 
00385 //      move to static KexiProject method
00386     if (!fileDriverSelected && !cdata.driverName.isEmpty() && cdata.password.isEmpty()) {
00387 
00388         if (cdata.password.isEmpty()) {
00389             delete d->passwordDialog;
00390             d->passwordDialog = new KexiDBPasswordDialog(0, cdata, true);
00391 //          connect( d->passwordDialog, SIGNAL(user1Clicked()), 
00392 //              this, SLOT(slotShowConnectionDetails()) );
00393             const int ret = d->passwordDialog->exec();
00394             if (d->passwordDialog->showConnectionDetailsRequested() || ret == QDialog::Accepted) {
00395 //              if ( ret == QDialog::Accepted ) {
00396         //      if (QDialog::Accepted == KPasswordDialog::getPassword(pwd, msg)) {
00397 //moved             cdata.password = QString(pwd);
00398 //              }
00399             } else {
00400                 m_action = Exit;
00401                 return true;
00402             }
00403         }
00404     }
00405 
00406 /*  kdDebug() << "ARGC==" << args->count() << endl;
00407     for (int i=0;i<args->count();i++) {
00408         kdDebug() << "ARG" <<i<< "= " << args->arg(i) <<endl;
00409     }*/
00410 
00411     if (m_forcedUserMode && m_forcedDesignMode) {
00412         KMessageBox::sorry( 0, i18n(
00413         "You have used both \"user-mode\" and \"design-mode\" startup options.")+couldnotMsg);
00414         return false;
00415     }
00416 
00417     //database filenames, shortcut filenames or db names on a server
00418     if (args->count()>=1) {
00419         QString prjName;
00420         QString fileName;
00421         if (fileDriverSelected) {
00422             fileName = QFile::decodeName(args->arg(0));
00423         }
00424         else {
00425             prjName = QString::fromLocal8Bit(args->arg(0));
00426         }
00427         
00428         if (fileDriverSelected) {
00429             QFileInfo finfo(fileName);
00430             prjName = finfo.fileName(); //filename only, to avoid messy names like when Kexi is started with "../../db" arg
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-conn-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, "execute")
00592         || getAutoopenObjects(args, "new")
00593         || getAutoopenObjects(args, "print")
00594         || getAutoopenObjects(args, "print-preview");
00595 
00596     if (atLeastOneAOOFound && !openExisting) {
00597         KMessageBox::information( 0, 
00598             i18n("You have specified a few database objects to be opened automatically, "
00599                 "using startup options.\n"
00600                 "These options will be ignored because it is not available while creating "
00601                 "or dropping projects."));
00602     }
00603 
00604     if (createDB) {
00605         bool creationNancelled;
00606         KexiGUIMessageHandler gui;
00607         KexiProject *prj = KexiProject::createBlankProject(creationNancelled, projectData(), &gui);
00608         bool ok = prj!=0;
00609         delete prj;
00610         if (creationNancelled)
00611             return cancelled;
00612         if (!alsoOpenDB) {
00613             if (ok) {
00614                 KMessageBox::information( 0, i18n("Project \"%1\" created successfully.")
00615                     .arg( QDir::convertSeparators(projectData()->databaseName()) ));
00616             }
00617             return ok;
00618         }
00619     }
00620     else if (dropDB) {
00621         KexiGUIMessageHandler gui;
00622         tristate res = KexiProject::dropProject(projectData(), &gui, false/*ask*/);
00623         if (res==true)
00624             KMessageBox::information( 0, i18n("Project \"%1\" dropped successfully.")
00625                 .arg( QDir::convertSeparators(projectData()->databaseName()) ));
00626         return res!=false;
00627     }
00628 
00629     //------
00630 
00631 /*  if (m_forcedFinalMode || (m_projectData && projectData->finalMode())) {
00632         //TODO: maybe also auto allow to open objects...
00633         KexiMainWindowImpl::initFinal(m_projectData);
00634         return;
00635     }*/
00636 
00637     if (!m_projectData) {
00638         cdata = KexiDB::ConnectionData(); //clear
00639 
00640         if (args->isSet("skip-startup-dialog") || !KexiStartupDialog::shouldBeShown())
00641             return true;
00642 
00643         if (!d->startupDialog) {
00644             //create d->startupDialog for reuse because it can be used again after conn err.
00645             d->startupDialog = new KexiStartupDialog(
00646                 KexiStartupDialog::Everything, KexiStartupDialog::CheckBoxDoNotShowAgain,
00647                 Kexi::connset(), Kexi::recentProjects(), 0, "KexiStartupDialog");
00648         }
00649         if (d->startupDialog->exec()!=QDialog::Accepted)
00650             return true;
00651 
00652         const int r = d->startupDialog->result();
00653         if (r == KexiStartupDialog::CreateBlankResult) {
00654             m_action = CreateBlankProject;
00655             return true;
00656         }
00657         else if (r == KexiStartupDialog::ImportResult) {
00658             m_action = ImportProject;
00659             return true;
00660         }
00661         else if (r == KexiStartupDialog::CreateFromTemplateResult) {
00662             const QString selFile( d->startupDialog->selectedFileName() );
00663             cdata.setFileName( selFile );
00664             QString detectedDriverName;
00665             const tristate res = detectActionForFile( m_importActionData, detectedDriverName, 
00666                 cdata.driverName, selFile );
00667             if (true != res)
00668                 return res;
00669             if (m_importActionData || detectedDriverName.isEmpty())
00670                 return false;
00671             cdata.driverName = detectedDriverName;
00672             m_projectData = new KexiProjectData(cdata, selFile);
00673             m_projectData->autoopenObjects = d->startupDialog->autoopenObjects();
00674             m_action = CreateFromTemplate;
00675             return true;
00676         }
00677         else if (r == KexiStartupDialog::OpenExistingResult) {
00678 //          kdDebug() << "Existing project --------" << endl;
00679             const QString selFile( d->startupDialog->selectedFileName() );
00680             if (!selFile.isEmpty()) {
00681                 //file-based project
00682 //              kdDebug() << "Project File: " << selFile << endl;
00683                 cdata.setFileName( selFile );
00684                 QString detectedDriverName;
00685                 const tristate res = detectActionForFile( m_importActionData, detectedDriverName, 
00686                     cdata.driverName, selFile );
00687                 if (true != res)
00688                     return res;
00689                 if (m_importActionData) { //importing action
00690                     m_action = ImportProject;
00691                     return true;
00692                 }
00693 
00694                 if (detectedDriverName.isEmpty())
00695                     return false;
00696                 cdata.driverName = detectedDriverName;
00697                 m_projectData = new KexiProjectData(cdata, selFile);
00698             }
00699             else if (d->startupDialog->selectedExistingConnection()) {
00700 //              kdDebug() << "Existing connection: " <<
00701 //                  d->startupDialog->selectedExistingConnection()->serverInfoString() << endl;
00702                 KexiDB::ConnectionData *cdata = d->startupDialog->selectedExistingConnection();
00703                 //ok, now we will try to show projects for this connection to the user
00704                 bool cancelled;
00705                 m_projectData = selectProject( cdata, cancelled );
00706                 if (!m_projectData && !cancelled || cancelled) {
00707                         //try again
00708                         return init(0, 0);
00709                 }
00710                 //not needed anymore
00711                 delete d->startupDialog;
00712                 d->startupDialog = 0;
00713             }
00714         }
00715         else if (r==KexiStartupDialog::OpenRecentResult) {
00716 //          kdDebug() << "Recent project --------" << endl;
00717             const KexiProjectData *data = d->startupDialog->selectedProjectData();
00718             if (data) {
00719 //              kdDebug() << "Selected project: database=" << data->databaseName()
00720 //                  << " connection=" << data->constConnectionData()->serverInfoString() << endl;
00721             }
00723             return data!=0;
00724         }
00725 
00726         if (!m_projectData)
00727             return true;
00728     }
00729     
00730     if (m_projectData && (openExisting || (createDB && alsoOpenDB))) {
00731         m_projectData->setReadOnly( readOnly );
00732         m_action = OpenProject;
00733     }
00734     //show if wasn't show yet
00735 //  importantInfo(true);
00736     
00737     return true;
00738 }
00739 
00740 tristate KexiStartupHandler::detectActionForFile( 
00741     KexiStartupData::Import& detectedImportAction, QString& detectedDriverName,
00742     const QString& _suggestedDriverName, const QString &dbFileName, QWidget *parent, int options )
00743 {
00744     detectedImportAction = KexiStartupData::Import(); //clear
00745     QString suggestedDriverName(_suggestedDriverName); //safe
00746     detectedDriverName = QString::null;
00747     QFileInfo finfo(dbFileName);
00748     if (dbFileName.isEmpty() || !finfo.isReadable()) {
00749         if (!(options & SkipMessages))
00750             KMessageBox::sorry(parent, i18n("<p>Could not open project.</p>")
00751                 +i18n("<p>The file <nobr>\"%1\"</nobr> does not exist or is not readable.</p>")
00752                 .arg(QDir::convertSeparators(dbFileName))
00753                 +i18n("Check the file's permissions and whether it is already opened "
00754                 "and locked by another application."));
00755         return false;
00756     }
00757 
00758     KMimeType::Ptr ptr;
00759     QString mimename;
00760 
00761     const bool thisIsShortcut = (options & ThisIsAShortcutToAProjectFile) 
00762         || (options & ThisIsAShortcutToAConnectionData);
00763 
00764     if ((options & ThisIsAProjectFile) || !thisIsShortcut) {
00765         //try this detection if "project file" mode is forced or no type is forced:
00766         ptr = KMimeType::findByFileContent(dbFileName);
00767         mimename = ptr.data()->name();
00768         kdDebug() << "KexiStartupHandler::detectActionForFile(): found mime is: " 
00769             << mimename << endl;
00770         if (mimename.isEmpty() || mimename=="application/octet-stream" || mimename=="text/plain") {
00771             //try by URL:
00772             ptr = KMimeType::findByURL(dbFileName);
00773             mimename = ptr.data()->name();
00774         }
00775     }
00776     if (mimename.isEmpty() || mimename=="application/octet-stream") {
00777         // perhaps the file is locked
00778         QFile f(dbFileName);
00779         if (!f.open(IO_ReadOnly)) {
00780             // BTW: similar error msg is provided in SQLiteConnection::drv_useDatabase()
00781             if (!(options & SkipMessages))
00782                 KMessageBox::sorry(parent, i18n("<p>Could not open project.</p>")
00783                     +i18n("<p>The file <nobr>\"%1\"</nobr> is not readable.</p>")
00784                     .arg(QDir::convertSeparators(dbFileName))
00785                     +i18n("Check the file's permissions and whether it is already opened "
00786                         "and locked by another application."));
00787             return false;
00788         }
00789     }
00790     if ((options & ThisIsAShortcutToAProjectFile) || mimename=="application/x-kexiproject-shortcut") {
00791         detectedDriverName = "shortcut";
00792         return true;
00793     }
00794 
00795     if ((options & ThisIsAShortcutToAConnectionData) || mimename=="application/x-kexi-connectiondata") {
00796         detectedDriverName = "connection";
00797         return true;
00798     }
00799 
00802     if (ptr.data()) {
00803         if (mimename=="application/x-msaccess") {
00804             if ((options & SkipMessages) || KMessageBox::Yes != KMessageBox::questionYesNo(
00805                 parent, i18n("\"%1\" is an external file of type:\n\"%2\".\n"
00806                 "Do you want to import the file as a Kexi project?")
00807                 .arg(QDir::convertSeparators(dbFileName)).arg(ptr.data()->comment()),
00808                 i18n("Open External File"), KGuiItem(i18n("Import...")), KStdGuiItem::cancel() ) )
00809             {
00810                 return cancelled;
00811             }
00812             detectedImportAction.mimeType = mimename;
00813             detectedImportAction.fileName = dbFileName;
00814             return true;
00815         }
00816     }
00817 
00818     if (!finfo.isWritable()) {
00820     }
00821 
00822     // "application/x-kexiproject-sqlite", etc.:
00823     QString tmpDriverName = Kexi::driverManager().lookupByMime(mimename).latin1();
00824 //@todo What about trying to reuse KOFFICE FILTER CHAINS here?
00825     bool useDetectedDriver = suggestedDriverName.isEmpty() || suggestedDriverName.lower()==detectedDriverName.lower();
00826     if (!useDetectedDriver) {
00827         int res = KMessageBox::Yes;
00828         if (!(options & SkipMessages))
00829             res = KMessageBox::warningYesNoCancel(parent, i18n(
00830              "The project file \"%1\" is recognized as compatible with \"%2\" database driver, "
00831              "while you have asked for \"%3\" database driver to be used.\n"
00832              "Do you want to use \"%4\" database driver?")
00833              .arg(QDir::convertSeparators(dbFileName))
00834              .arg(tmpDriverName).arg(suggestedDriverName).arg(tmpDriverName));
00835         if (KMessageBox::Yes == res)
00836             useDetectedDriver = true;
00837         else if (KMessageBox::Cancel == res)
00838             return cancelled;
00839     }
00840     if (useDetectedDriver) {
00841         detectedDriverName = tmpDriverName;
00842     }
00843     else {//use suggested driver
00844         detectedDriverName = suggestedDriverName;
00845     }
00846 //  kdDebug() << "KexiStartupHandler::detectActionForFile(): driver name: " << detectedDriverName << endl;
00847 //hardcoded for convenience:
00848     const QString newFileFormat = "SQLite3";
00849     if (!(options & DontConvert || options & SkipMessages) 
00850         && detectedDriverName.lower()=="sqlite2" && detectedDriverName.lower()!=suggestedDriverName.lower()
00851         && KMessageBox::Yes == KMessageBox::questionYesNo(parent, i18n(
00852             "Previous version of database file format (\"%1\") is detected in the \"%2\" "
00853             "project file.\nDo you want to convert the project to a new \"%3\" format (recommended)?")
00854             .arg(detectedDriverName).arg(QDir::convertSeparators(dbFileName)).arg(newFileFormat)) )
00855     {
00856 //      SQLite2ToSQLite3Migration *migr = new 
00857         SQLite2ToSQLite3Migration migr( finfo.absFilePath() );
00858         tristate res = migr.run();
00859 //      kdDebug() << "--- migr.run() END ---" <<endl;
00860         if (!res) {
00861             //TODO msg
00862             KMessageBox::sorry(parent, i18n(
00863                 "Failed to convert project file \"%1\" to a new \"%2\" format.\n"
00864                 "The file format remains unchanged.")
00865                 .arg(QDir::convertSeparators(dbFileName)).arg(newFileFormat) );
00866             //continue...
00867         }
00868         if (res==true)
00869             detectedDriverName = newFileFormat;
00870     }
00871 //  action.driverName = detectedDriverName;
00872     if (detectedDriverName.isEmpty()) {
00873         QString possibleProblemsInfoMsg( Kexi::driverManager().possibleProblemsInfoMsg() );
00874         if (!possibleProblemsInfoMsg.isEmpty()) {
00875             possibleProblemsInfoMsg.prepend(QString::fromLatin1("<p>")+i18n("Possible problems:"));
00876             possibleProblemsInfoMsg += QString::fromLatin1("</p>");
00877         }
00878         if (!(options & SkipMessages))
00879             KMessageBox::detailedSorry(parent, 
00880                 i18n( "The file \"%1\" is not recognized as being supported by Kexi.")
00881                     .arg(QDir::convertSeparators(dbFileName)),
00882                 QString::fromLatin1("<p>")
00883                 +i18n("Database driver for this file type not found.\nDetected MIME type: %1")
00884                     .arg(mimename)
00885                 +(ptr.data()->comment().isEmpty() 
00886                     ? QString::fromLatin1(".") : QString::fromLatin1(" (%1).").arg(ptr.data()->comment()))
00887                 +QString::fromLatin1("</p>")
00888                 +possibleProblemsInfoMsg);
00889         return false;
00890     }
00891     return true;
00892 }
00893 
00894 KexiProjectData*
00895 KexiStartupHandler::selectProject(KexiDB::ConnectionData *cdata, bool& cancelled, QWidget *parent)
00896 {
00897     clearStatus();
00898     cancelled = false;
00899     if (!cdata)
00900         return 0;
00901     if (!cdata->savePassword && cdata->password.isEmpty()) {
00902         if (!d->passwordDialog)
00903             d->passwordDialog = new KexiDBPasswordDialog(0, *cdata, false);
00904         const int ret = d->passwordDialog->exec();
00905         if (d->passwordDialog->showConnectionDetailsRequested() || ret == QDialog::Accepted) {
00906 
00907         } else {
00908             cancelled = true;
00909             return 0;
00910         }
00911     }
00912     KexiProjectData* projectData = 0;
00913     //dialog for selecting a project
00914     KexiProjectSelectorDialog prjdlg( parent, "prjdlg", cdata, true, false );
00915     if (!prjdlg.projectSet() || prjdlg.projectSet()->error()) {
00916         KexiGUIMessageHandler msgh;
00917         if (prjdlg.projectSet())
00918             msgh.showErrorMessage(prjdlg.projectSet(), 
00919                 i18n("Could not load list of available projects for <b>%1</b> database server.")
00920                 .arg(cdata->serverInfoString(true)));
00921         else
00922             msgh.showErrorMessage(
00923                 i18n("Could not load list of available projects for <b>%1</b> database server.")
00924                 .arg(cdata->serverInfoString(true)));
00925 //      setStatus(i18n("Could not load list of available projects for database server \"%1\"")
00926 //      .arg(cdata->serverInfoString(true)), prjdlg.projectSet()->errorMsg());
00927         return 0;
00928     }
00929     if (prjdlg.exec()!=QDialog::Accepted) {
00930         cancelled = true;
00931         return 0;
00932     }
00933     if (prjdlg.selectedProjectData()) {
00934         //deep copy
00935         projectData = new KexiProjectData(*prjdlg.selectedProjectData());
00936     }
00937     return projectData;
00938 }
00939 
00940 void KexiStartupHandler::slotSaveShortcutFileChanges()
00941 {
00942     bool ok = true;
00943     if (d->shortcutFile)
00944         ok = d->shortcutFile->saveProjectData(d->connDialog->currentProjectData(), 
00945             d->connDialog->savePasswordOptionSelected(), 
00946             &d->shortcutFileGroupKey );
00947     else if (d->connShortcutFile)
00948         ok = d->connShortcutFile->saveConnectionData(
00949             *d->connDialog->currentProjectData().connectionData(), 
00950             d->connDialog->savePasswordOptionSelected(), 
00951             &d->shortcutFileGroupKey );
00952 
00953     if (!ok) {
00954         KMessageBox::sorry(0, i18n("Failed saving connection data to\n\"%1\" file.")
00955             .arg(QDir::convertSeparators(d->shortcutFile->fileName())));
00956     }
00957 }
00958 
00959 /*void KexiStartupHandler::slotShowConnectionDetails()
00960 {
00961     d->passwordDialog->close();
00962     d->showConnectionDetailsExecuted = true;
00963 }*/
00964 
00965 #include "KexiStartup.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys