KexiStartup.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "KexiStartup.h"
21#ifdef TQ_WS_WIN
22# include "KexiStartup_p_win.h"
23#else
24# include "KexiStartup_p.h"
25#endif
26
27#include "kexiproject.h"
28#include "kexiprojectdata.h"
29#include "kexiprojectset.h"
30#include "kexiguimsghandler.h"
31
32#include <kexidb/driver.h>
33#include <kexidb/drivermanager.h>
34#include "KexiStartupDialog.h"
35#include "KexiConnSelector.h"
36#include "KexiProjectSelectorBase.h"
37#include "KexiProjectSelector.h"
38#include "KexiNewProjectWizard.h"
39#include <kexidbconnectionwidget.h>
40#include <kexidbshortcutfile.h>
41
42#include <kdebug.h>
43#include <tdelocale.h>
44#include <kmimetype.h>
45#include <tdemessagebox.h>
46#include <tdecmdlineargs.h>
47#include <tdeversion.h>
48#include <kprogress.h>
49#include <ktextedit.h>
50#include <kstaticdeleter.h>
51#include <kuser.h>
52
53#include <unistd.h>
54
55#include <tqcstring.h>
56#include <tqapplication.h>
57#include <tqlayout.h>
58
59namespace Kexi {
60 static KStaticDeleter<KexiStartupHandler> Kexi_startupHandlerDeleter;
61 KexiStartupHandler* _startupHandler = 0;
62
64 {
65 if (!_startupHandler)
66 Kexi_startupHandlerDeleter.setObject( _startupHandler, new KexiStartupHandler() );
67 return *_startupHandler;
68 }
69}
70
71//---------------------------------
72
74class KexiStartupHandlerPrivate
75{
76 public:
77 KexiStartupHandlerPrivate()
78 : passwordDialog(0)//, showConnectionDetailsExecuted(false)
79 , shortcutFile(0), connShortcutFile(0), connDialog(0), startupDialog(0)
80 {
81 }
82
83 ~KexiStartupHandlerPrivate()
84 {
85 delete passwordDialog;
86 delete connDialog;
87 delete startupDialog;
88 }
89
90 KexiDBPasswordDialog* passwordDialog;
91// bool showConnectionDetailsExecuted : 1;
92 KexiDBShortcutFile *shortcutFile;
93 KexiDBConnShortcutFile *connShortcutFile;
94 KexiDBConnectionDialog *connDialog;
95 TQString shortcutFileGroupKey;
96 KexiStartupDialog *startupDialog;
97};
98
99//---------------------------------
100
101static bool stripQuotes(const TQString &item, TQString &name)
102{
103 if (item.left(1)=="\"" && item.right(1)=="\"") {
104 name = item.mid(1, item.length()-2);
105 return true;
106 }
107 name = item;
108 return false;
109}
110
111void updateProgressBar(KProgressDialog *pd, char *buffer, int buflen)
112{
113 char *p = buffer;
114 TQCString line(80);
115 for (int i=0; i<buflen; i++, p++) {
116 if ((i==0 || buffer[i-1]=='\n') && buffer[i]=='%') {
117 bool ok;
118 int j=0;
119// char *q=++p;
120 ++i;
121 line="";
122 for (;i<buflen && *p>='0' && *p<='9'; j++, i++, p++)
123 line+=TQChar(*p).latin1();
124 --i; --p;
125 int percent = line.toInt(&ok);
126 if (ok && percent>=0 && percent<=100 && pd->progressBar()->progress()<percent) {
127// kdDebug() << percent << endl;
128 pd->progressBar()->setProgress(percent);
129 tqApp->processEvents(100);
130 }
131 }
132 }
133}
134
135//---------------------------------
136
137KexiDBPasswordDialog::KexiDBPasswordDialog(TQWidget *parent, KexiDB::ConnectionData& cdata, bool showDetailsButton)
138 : KPasswordDialog( KPasswordDialog::Password, false/*keep*/,
139 showDetailsButton ? (int)KDialogBase::User1 : 0, parent )
140 , m_cdata(&cdata)
141 , m_showConnectionDetailsRequested(false)
142{
143 TQString msg = "<H2>" + i18n("Opening database") + "</H2><p>"
144 + i18n("Please enter the password.") + "</p>";
145/* msg += cdata.userName.isEmpty() ?
146 "<p>"+i18n("Please enter the password.")
147 : "<p>"+i18n("Please enter the password for user.").arg("<b>"+cdata.userName+"</b>");*/
148
149 TQString srv = cdata.serverInfoString(false);
150 if (srv.isEmpty() || srv.lower()=="localhost")
151 srv = i18n("local database server");
152
153 msg += ("</p><p>"+i18n("Database server: %1").arg(TQString("<nobr>")+srv+"</nobr>")+"</p>");
154
155 TQString usr;
156 if (cdata.userName.isEmpty())
157 usr = i18n("unspecified user", "(unspecified)");
158 else
159 usr = cdata.userName;
160
161 msg += ("<p>"+i18n("Username: %1").arg(usr)+"</p>");
162
163 setPrompt( msg );
164 if (showDetailsButton) {
165 connect( this, TQ_SIGNAL(user1Clicked()),
166 this, TQ_SLOT(slotShowConnectionDetails()) );
167 setButtonText(KDialogBase::User1, i18n("&Details")+ " >>");
168 }
169 setButtonOK(KGuiItem(i18n("&Open"), "document-open"));
170}
171
172KexiDBPasswordDialog::~KexiDBPasswordDialog()
173{
174}
175
176void KexiDBPasswordDialog::done(int r)
177{
178 if (r == TQDialog::Accepted) {
179 m_cdata->password = password();
180 }
181// if (d->showConnectionDetailsExecuted || ret == TQDialog::Accepted) {
182/* } else {
183 m_action = Exit;
184 return true;
185 }
186 }*/
187 KPasswordDialog::done(r);
188}
189
190void KexiDBPasswordDialog::slotShowConnectionDetails()
191{
192 m_showConnectionDetailsRequested = true;
193 close();
194}
195
196//---------------------------------
197KexiStartupHandler::KexiStartupHandler()
198 : TQObject(0,"KexiStartupHandler")
200 , d( new KexiStartupHandlerPrivate() )
201{
202}
203
204KexiStartupHandler::~KexiStartupHandler()
205{
206 delete d;
207}
208
209bool KexiStartupHandler::getAutoopenObjects(TDECmdLineArgs *args, const TQCString &action_name)
210{
211 QCStringList list = args->getOptionList(action_name);
212 QCStringList::ConstIterator it;
213 bool atLeastOneFound = false;
214 for ( it = list.constBegin(); it!=list.constEnd(); ++it) {
215 TQString type_name, obj_name, item=*it;
216 int idx;
217 bool name_required = true;
218 if (action_name=="new") {
219 obj_name = "";
220 stripQuotes(item, type_name);
221 name_required = false;
222 }
223 else {//open, design, text...
224 TQString defaultType;
225 if (action_name=="execute")
226 defaultType = "macro";
227 else
228 defaultType = "table";
229
230 //option with " " (set default type)
231 if (stripQuotes(item, obj_name)) {
232 type_name = defaultType;
233 }
234 else if ((idx = item.find(':'))!=-1) {
235 //option with type name specified:
236 type_name = item.left(idx).lower();
237 obj_name = item.mid(idx+1);
238 //optional: remove ""
239 if (obj_name.left(1)=="\"" && obj_name.right(1)=="\"")
240 obj_name = obj_name.mid(1, obj_name.length()-2);
241 }
242 else {
243 //just obj. name: set default type name
244 obj_name = item;
245 type_name = defaultType;
246 }
247 }
248 if (type_name.isEmpty())
249 continue;
250 if (name_required && obj_name.isEmpty())
251 continue;
252
253 KexiProjectData::ObjectInfo info;
254 info["name"]=obj_name;
255 info["type"]=type_name;
256 info["action"]=action_name;
257 //ok, now add info for this object
258 atLeastOneFound = true;
259 if (projectData())
260 projectData()->autoopenObjects.append( info );
261 else
262 return true; //no need to find more because we do not have projectData() anyway
263 } //for
264 return atLeastOneFound;
265}
266
267tristate KexiStartupHandler::init(int /*argc*/, char ** /*argv*/)
268{
269 m_action = DoNothing;
270// d->showConnectionDetailsExecuted = false;
271 TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs(0);
272 if (!args)
273 return true;
274
276
277 const TQString connectionShortcutFileName( args->getOption("connection") );
278 if (!connectionShortcutFileName.isEmpty()) {
279 KexiDBConnShortcutFile connectionShortcut( connectionShortcutFileName );
280 if (!connectionShortcut.loadConnectionData(cdata)) {
283 KMessageBox::sorry( 0, "<qt>"
284 +i18n("Could not read connection information from connection shortcut "
285 "file <nobr>\"%1\"</nobr>.<br><br>Check whether the file has valid contents.")
286 .arg(TQDir::convertSeparators(connectionShortcut.fileName())));
287 return false;
288 }
289 }
290
291 if (!args->getOption("dbdriver").isEmpty())
292 cdata.driverName = args->getOption("dbdriver");
293
294 TQString fileType( args->getOption("type").lower() );
295 if (args->count()>0 && (!fileType.isEmpty() && fileType!="project" && fileType!="shortcut" && fileType!="connection")) {
296 KMessageBox::sorry( 0,
297 i18n("You have specified invalid argument (\"%1\") for \"type\" command-line option.")
298 .arg(fileType));
299 return false;
300 }
301
302// if (cdata.driverName.isEmpty())
303// cdata.driverName = KexiDB::Driver::defaultFileBasedDriverName();
304 if (!args->getOption("host").isEmpty())
305 cdata.hostName = args->getOption("host");
306 if (!args->getOption("local-socket").isEmpty())
307 cdata.localSocketFileName = args->getOption("local-socket");
308 if (!args->getOption("user").isEmpty())
309 cdata.userName = args->getOption("user");
310// cdata.password = args->getOption("password");
311 bool fileDriverSelected;
312 if (cdata.driverName.isEmpty())
313 fileDriverSelected = true;
314 else {
317 if (dinfo.name.isEmpty()) {
318 //driver name provided explicitly, but not found
319 KMessageBox::sorry(0, dm.errorMsg());
320 return false;
321 }
322 fileDriverSelected = dinfo.fileBased;
323 }
324 bool projectFileExists = false;
325
326 //obfuscate the password, if present
327//removed
328/*
329 for (int i=1; i<(argc-1); i++) {
330 if (qstrcmp("--password",argv[i])==0
331 || qstrcmp("-password",argv[i])==0)
332 {
333 TQString pwd(argv[i+1]);
334 if (!pwd.isEmpty()) {
335 pwd.fill(' ');
336 pwd[0]='x';
337 qstrcpy(argv[i+1], (const char*)pwd.utf8().data());
338 }
339 break;
340 }
341 }
342 */
343
344 const TQString portStr = args->getOption("port");
345 if (!portStr.isEmpty()) {
346 bool ok;
347 const int p = portStr.toInt(&ok);
348 if (ok && p > 0)
349 cdata.port = p;
350 else {
351 KMessageBox::sorry( 0,
352 i18n("You have specified invalid port number \"%1\"."));
353 return false;
354 }
355 }
356
357 m_forcedUserMode = args->isSet("user-mode");
358 m_forcedDesignMode = args->isSet("design-mode");
359 m_isProjectNavigatorVisible = args->isSet("show-navigator");
360 bool createDB = args->isSet("createdb");
361 const bool alsoOpenDB = args->isSet("create-opendb");
362 if (alsoOpenDB)
363 createDB = true;
364 const bool dropDB = args->isSet("dropdb");
365 const bool openExisting = !createDB && !dropDB;
366 const bool readOnly = args->isSet("readonly");
367 const TQString couldnotMsg = TQString::fromLatin1("\n")
368 +i18n("Could not start Kexi application this way.");
369
370 if (createDB && dropDB) {
371 KMessageBox::sorry( 0, i18n(
372 "You have used both \"createdb\" and \"dropdb\" startup options.")+couldnotMsg);
373 return false;
374 };
375
376 if (createDB || dropDB) {
377 if (args->count()<1) {
378 KMessageBox::sorry( 0, i18n("No project name specified.") );
379 return false;
380 }
381 m_action = Exit;
382 }
383
384//TODO: add option for non-gui; integrate with TDEWallet;
385// move to static KexiProject method
386 if (!fileDriverSelected && !cdata.driverName.isEmpty() && cdata.password.isEmpty()) {
387
388 if (cdata.password.isEmpty()) {
389 delete d->passwordDialog;
390 d->passwordDialog = new KexiDBPasswordDialog(0, cdata, true);
391// connect( d->passwordDialog, TQ_SIGNAL(user1Clicked()),
392// this, TQ_SLOT(slotShowConnectionDetails()) );
393 const int ret = d->passwordDialog->exec();
394 if (d->passwordDialog->showConnectionDetailsRequested() || ret == TQDialog::Accepted) {
395// if ( ret == TQDialog::Accepted ) {
396 // if (TQDialog::Accepted == KPasswordDialog::getPassword(pwd, msg)) {
397//moved cdata.password = pwd;
398// }
399 } else {
400 m_action = Exit;
401 return true;
402 }
403 }
404 }
405
406/* kdDebug() << "ARGC==" << args->count() << endl;
407 for (int i=0;i<args->count();i++) {
408 kdDebug() << "ARG" <<i<< "= " << args->arg(i) <<endl;
409 }*/
410
411 if (m_forcedUserMode && m_forcedDesignMode) {
412 KMessageBox::sorry( 0, i18n(
413 "You have used both \"user-mode\" and \"design-mode\" startup options.")+couldnotMsg);
414 return false;
415 }
416
417 //database filenames, shortcut filenames or db names on a server
418 if (args->count()>=1) {
419 TQString prjName;
420 TQString fileName;
421 if (fileDriverSelected) {
422 fileName = TQFile::decodeName(args->arg(0));
423 }
424 else {
425 prjName = TQString::fromLocal8Bit(args->arg(0));
426 }
427
428 if (fileDriverSelected) {
429 TQFileInfo finfo(fileName);
430 prjName = finfo.fileName(); //filename only, to avoid messy names like when Kexi is started with "../../db" arg
431 cdata.setFileName( finfo.absFilePath() );
432 projectFileExists = finfo.exists();
433
434 if (dropDB && !projectFileExists) {
435 KMessageBox::sorry(0,
436 i18n("Could not remove project.\nThe file \"%1\" does not exist.")
437 .arg(TQDir::convertSeparators(cdata.dbFileName())));
438 return 0;
439 }
440 }
441
442 if (createDB) {
443 if (cdata.driverName.isEmpty())
445 m_projectData = new KexiProjectData(cdata, prjName); //dummy
446 }
447 else {
448 if (fileDriverSelected) {
449 int detectOptions = 0;
450 if (fileType=="project")
451 detectOptions |= ThisIsAProjectFile;
452 else if (fileType=="shortcut")
453 detectOptions |= ThisIsAShortcutToAProjectFile;
454 else if (fileType=="connection")
455 detectOptions |= ThisIsAShortcutToAConnectionData;
456
457 if (dropDB)
458 detectOptions |= DontConvert;
459
460 TQString detectedDriverName;
461 const tristate res = detectActionForFile( m_importActionData, detectedDriverName,
462 cdata.driverName, cdata.fileName(), 0, detectOptions );
463 if (true != res)
464 return res;
465
466 if (m_importActionData) { //importing action
467 m_action = ImportProject;
468 return true;
469 }
470
471 //opening action
472 cdata.driverName = detectedDriverName;
473 if (cdata.driverName=="shortcut") {
474 //get information for a shortcut file
475 d->shortcutFile = new KexiDBShortcutFile(cdata.fileName());
476 m_projectData = new KexiProjectData();
477 if (!d->shortcutFile->loadProjectData(*m_projectData, &d->shortcutFileGroupKey)) {
478 KMessageBox::sorry(0, i18n("Could not open shortcut file\n\"%1\".")
479 .arg(TQDir::convertSeparators(cdata.fileName())));
480 delete m_projectData;
481 m_projectData = 0;
482 delete d->shortcutFile;
483 d->shortcutFile = 0;
484 return false;
485 }
486 d->connDialog = new KexiDBConnectionDialog(
487 *m_projectData, d->shortcutFile->fileName());
488 connect(d->connDialog, TQ_SIGNAL(saveChanges()),
489 this, TQ_SLOT(slotSaveShortcutFileChanges()));
490 int res = d->connDialog->exec();
491 if (res == TQDialog::Accepted) {
492 //get (possibly changed) prj data
493 *m_projectData = d->connDialog->currentProjectData();
494 }
495
496 delete d->connDialog;
497 d->connDialog = 0;
498 delete d->shortcutFile;
499 d->shortcutFile = 0;
500
501 if (res == TQDialog::Rejected) {
502 delete m_projectData;
503 m_projectData = 0;
504 return cancelled;
505 }
506 }
507 else if (cdata.driverName=="connection") {
508 //get information for a connection file
509 d->connShortcutFile = new KexiDBConnShortcutFile(cdata.fileName());
510 if (!d->connShortcutFile->loadConnectionData(cdata, &d->shortcutFileGroupKey)) {
511 KMessageBox::sorry(0, i18n("Could not open connection data file\n\"%1\".")
512 .arg(TQDir::convertSeparators(cdata.fileName())));
513 delete d->connShortcutFile;
514 d->connShortcutFile = 0;
515 return false;
516 }
517 bool cancel = false;
518 const bool showConnectionDialog = !args->isSet("skip-conn-dialog");
519 while (true) {
520 if (showConnectionDialog) {
521 //show connection dialog, so user can change parameters
522 if (!d->connDialog) {
523 d->connDialog = new KexiDBConnectionDialog(
524 cdata, d->connShortcutFile->fileName());
525 connect(d->connDialog, TQ_SIGNAL(saveChanges()),
526 this, TQ_SLOT(slotSaveShortcutFileChanges()));
527 }
528 const int res = d->connDialog->exec();
529 if (res == TQDialog::Accepted) {
530 //get (possibly changed) prj data
531 cdata = *d->connDialog->currentProjectData().constConnectionData();
532 }
533 else {
534 cancel = true;
535 break;
536 }
537 }
538 m_projectData = selectProject(&cdata, cancel);
539 if (m_projectData || cancel || !showConnectionDialog)
540 break;
541 }
542
543 delete d->connShortcutFile;
544 d->connShortcutFile = 0;
545 delete d->connDialog;
546 d->connDialog = 0;
547
548 if (cancel)
549 return cancelled;
550 }
551 else
552 m_projectData = new KexiProjectData(cdata, prjName);
553 }
554 else
555 m_projectData = new KexiProjectData(cdata, prjName);
556
557 }
558// if (!m_projectData)
559// return false;
560 }
561 if (args->count()>1) {
562 //TODO: KRun another Kexi instances
563 }
564
565 //let's show connection details, user asked for that in the "password dialog"
566 if (d->passwordDialog && d->passwordDialog->showConnectionDetailsRequested()) {
567 d->connDialog = new KexiDBConnectionDialog(*m_projectData);
568// connect(d->connDialog->tabWidget->mainWidget, TQ_SIGNAL(saveChanges()),
569// this, TQ_SLOT(slotSaveShortcutFileChanges()));
570 int res = d->connDialog->exec();
571
572 if (res == TQDialog::Accepted) {
573 //get (possibly changed) prj data
574 *m_projectData = d->connDialog->currentProjectData();
575 }
576
577 delete d->connDialog;
578 d->connDialog = 0;
579
580 if (res == TQDialog::Rejected) {
581 delete m_projectData;
582 m_projectData = 0;
583 return cancelled;
584 }
585 }
586
587 //---autoopen objects:
588 const bool atLeastOneAOOFound = getAutoopenObjects(args, "open")
589 || getAutoopenObjects(args, "design")
590 || getAutoopenObjects(args, "edittext")
591 || getAutoopenObjects(args, "execute")
592 || getAutoopenObjects(args, "new")
593 || getAutoopenObjects(args, "print")
594 || getAutoopenObjects(args, "print-preview");
595
596 if (atLeastOneAOOFound && !openExisting) {
597 KMessageBox::information( 0,
598 i18n("You have specified a few database objects to be opened automatically, "
599 "using startup options.\n"
600 "These options will be ignored because it is not available while creating "
601 "or dropping projects."));
602 }
603
604 if (createDB) {
605 bool creationNancelled;
606 KexiGUIMessageHandler gui;
607 KexiProject *prj = KexiProject::createBlankProject(creationNancelled, projectData(), &gui);
608 bool ok = prj!=0;
609 delete prj;
610 if (creationNancelled)
611 return cancelled;
612 if (!alsoOpenDB) {
613 if (ok) {
614 KMessageBox::information( 0, i18n("Project \"%1\" created successfully.")
615 .arg( TQDir::convertSeparators(projectData()->databaseName()) ));
616 }
617 return ok;
618 }
619 }
620 else if (dropDB) {
621 KexiGUIMessageHandler gui;
622 tristate res = KexiProject::dropProject(projectData(), &gui, false/*ask*/);
623 if (res==true)
624 KMessageBox::information( 0, i18n("Project \"%1\" dropped successfully.")
625 .arg( TQDir::convertSeparators(projectData()->databaseName()) ));
626 return res!=false;
627 }
628
629 //------
630
631/* if (m_forcedFinalMode || (m_projectData && projectData->finalMode())) {
632 //TODO: maybe also auto allow to open objects...
633 KexiMainWindowImpl::initFinal(m_projectData);
634 return;
635 }*/
636
637 if (!m_projectData) {
638 cdata = KexiDB::ConnectionData(); //clear
639
640 if (args->isSet("skip-startup-dialog") || !KexiStartupDialog::shouldBeShown())
641 return true;
642
643 if (!d->startupDialog) {
644 //create d->startupDialog for reuse because it can be used again after conn err.
645 d->startupDialog = new KexiStartupDialog(
646 KexiStartupDialog::Everything, KexiStartupDialog::CheckBoxDoNotShowAgain,
647 Kexi::connset(), Kexi::recentProjects(), 0, "KexiStartupDialog");
648 }
649 if (d->startupDialog->exec()!=TQDialog::Accepted)
650 return true;
651
652 const int r = d->startupDialog->result();
654 m_action = CreateBlankProject;
655 return true;
656 }
657 else if (r == KexiStartupDialog::ImportResult) {
658 m_action = ImportProject;
659 return true;
660 }
662 const TQString selFile( d->startupDialog->selectedFileName() );
663 cdata.setFileName( selFile );
664 TQString detectedDriverName;
665 const tristate res = detectActionForFile( m_importActionData, detectedDriverName,
666 cdata.driverName, selFile );
667 if (true != res)
668 return res;
669 if (m_importActionData || detectedDriverName.isEmpty())
670 return false;
671 cdata.driverName = detectedDriverName;
672 m_projectData = new KexiProjectData(cdata, selFile);
673 m_projectData->autoopenObjects = d->startupDialog->autoopenObjects();
674 m_action = CreateFromTemplate;
675 return true;
676 }
678// kdDebug() << "Existing project --------" << endl;
679 const TQString selFile( d->startupDialog->selectedFileName() );
680 if (!selFile.isEmpty()) {
681 //file-based project
682// kdDebug() << "Project File: " << selFile << endl;
683 cdata.setFileName( selFile );
684 TQString detectedDriverName;
685 const tristate res = detectActionForFile( m_importActionData, detectedDriverName,
686 cdata.driverName, selFile );
687 if (true != res)
688 return res;
689 if (m_importActionData) { //importing action
690 m_action = ImportProject;
691 return true;
692 }
693
694 if (detectedDriverName.isEmpty())
695 return false;
696 cdata.driverName = detectedDriverName;
697 m_projectData = new KexiProjectData(cdata, selFile);
698 }
699 else if (d->startupDialog->selectedExistingConnection()) {
700// kdDebug() << "Existing connection: " <<
701// d->startupDialog->selectedExistingConnection()->serverInfoString() << endl;
702 KexiDB::ConnectionData *cdata = d->startupDialog->selectedExistingConnection();
703 //ok, now we will try to show projects for this connection to the user
704 bool cancelled;
705 m_projectData = selectProject( cdata, cancelled );
706 if (!m_projectData && !cancelled || cancelled) {
707 //try again
708 return init(0, 0);
709 }
710 //not needed anymore
711 delete d->startupDialog;
712 d->startupDialog = 0;
713 }
714 }
716// kdDebug() << "Recent project --------" << endl;
717 const KexiProjectData *data = d->startupDialog->selectedProjectData();
718 if (data) {
719// kdDebug() << "Selected project: database=" << data->databaseName()
720// << " connection=" << data->constConnectionData()->serverInfoString() << endl;
721 }
723 return data!=0;
724 }
725
726 if (!m_projectData)
727 return true;
728 }
729
730 if (m_projectData && (openExisting || (createDB && alsoOpenDB))) {
731 m_projectData->setReadOnly( readOnly );
732 m_action = OpenProject;
733 }
734 //show if wasn't show yet
735// importantInfo(true);
736
737 return true;
738}
739
741 KexiStartupData::Import& detectedImportAction, TQString& detectedDriverName,
742 const TQString& _suggestedDriverName, const TQString &dbFileName, TQWidget *parent, int options )
743{
744 detectedImportAction = KexiStartupData::Import(); //clear
745 TQString suggestedDriverName(_suggestedDriverName); //safe
746 detectedDriverName = TQString();
747 TQFileInfo finfo(dbFileName);
748 if (dbFileName.isEmpty() || !finfo.isReadable()) {
749 if (!(options & SkipMessages))
750 KMessageBox::sorry(parent, i18n("<p>Could not open project.</p>")
751 +i18n("<p>The file <nobr>\"%1\"</nobr> does not exist or is not readable.</p>")
752 .arg(TQDir::convertSeparators(dbFileName))
753 +i18n("Check the file's permissions and whether it is already opened "
754 "and locked by another application."));
755 return false;
756 }
757
758 KMimeType::Ptr ptr;
759 TQString mimename;
760
761 const bool thisIsShortcut = (options & ThisIsAShortcutToAProjectFile)
763
764 if ((options & ThisIsAProjectFile) || !thisIsShortcut) {
765 //try this detection if "project file" mode is forced or no type is forced:
766 ptr = KMimeType::findByFileContent(dbFileName);
767 mimename = ptr.data()->name();
768 kdDebug() << "KexiStartupHandler::detectActionForFile(): found mime is: "
769 << mimename << endl;
770 if (mimename.isEmpty() || mimename=="application/octet-stream" || mimename=="text/plain") {
771 //try by URL:
772 ptr = KMimeType::findByURL(dbFileName);
773 mimename = ptr.data()->name();
774 }
775 }
776 if (mimename.isEmpty() || mimename=="application/octet-stream") {
777 // perhaps the file is locked
778 TQFile f(dbFileName);
779 if (!f.open(IO_ReadOnly)) {
780 // BTW: similar error msg is provided in SQLiteConnection::drv_useDatabase()
781 if (!(options & SkipMessages))
782 KMessageBox::sorry(parent, i18n("<p>Could not open project.</p>")
783 +i18n("<p>The file <nobr>\"%1\"</nobr> is not readable.</p>")
784 .arg(TQDir::convertSeparators(dbFileName))
785 +i18n("Check the file's permissions and whether it is already opened "
786 "and locked by another application."));
787 return false;
788 }
789 }
790 if ((options & ThisIsAShortcutToAProjectFile) || mimename=="application/x-kexiproject-shortcut") {
791 detectedDriverName = "shortcut";
792 return true;
793 }
794
795 if ((options & ThisIsAShortcutToAConnectionData) || mimename=="application/x-kexi-connectiondata") {
796 detectedDriverName = "connection";
797 return true;
798 }
799
802 if (ptr.data()) {
803 if (mimename=="application/x-msaccess") {
804 if ((options & SkipMessages) || KMessageBox::Yes != KMessageBox::questionYesNo(
805 parent, i18n("\"%1\" is an external file of type:\n\"%2\".\n"
806 "Do you want to import the file as a Kexi project?")
807 .arg(TQDir::convertSeparators(dbFileName)).arg(ptr.data()->comment()),
808 i18n("Open External File"), KGuiItem(i18n("Import...")), KStdGuiItem::cancel() ) )
809 {
810 return cancelled;
811 }
812 detectedImportAction.mimeType = mimename;
813 detectedImportAction.fileName = dbFileName;
814 return true;
815 }
816 }
817
818 if (!finfo.isWritable()) {
820 }
821
822 // "application/x-kexiproject-sqlite", etc.:
823 TQString tmpDriverName = Kexi::driverManager().lookupByMime(mimename).latin1();
824//@todo What about trying to reuse KOFFICE FILTER CHAINS here?
825 bool useDetectedDriver = suggestedDriverName.isEmpty() || suggestedDriverName.lower()==detectedDriverName.lower();
826 if (!useDetectedDriver) {
827 int res = KMessageBox::Yes;
828 if (!(options & SkipMessages))
829 res = KMessageBox::warningYesNoCancel(parent, i18n(
830 "The project file \"%1\" is recognized as compatible with \"%2\" database driver, "
831 "while you have asked for \"%3\" database driver to be used.\n"
832 "Do you want to use \"%4\" database driver?")
833 .arg(TQDir::convertSeparators(dbFileName))
834 .arg(tmpDriverName).arg(suggestedDriverName).arg(tmpDriverName));
835 if (KMessageBox::Yes == res)
836 useDetectedDriver = true;
837 else if (KMessageBox::Cancel == res)
838 return cancelled;
839 }
840 if (useDetectedDriver) {
841 detectedDriverName = tmpDriverName;
842 }
843 else {//use suggested driver
844 detectedDriverName = suggestedDriverName;
845 }
846// kdDebug() << "KexiStartupHandler::detectActionForFile(): driver name: " << detectedDriverName << endl;
847//hardcoded for convenience:
848 const TQString newFileFormat = "SQLite3";
849 if (!(options & DontConvert || options & SkipMessages)
850 && detectedDriverName.lower()=="sqlite2" && detectedDriverName.lower()!=suggestedDriverName.lower()
851 && KMessageBox::Yes == KMessageBox::questionYesNo(parent, i18n(
852 "Previous version of database file format (\"%1\") is detected in the \"%2\" "
853 "project file.\nDo you want to convert the project to a new \"%3\" format (recommended)?")
854 .arg(detectedDriverName).arg(TQDir::convertSeparators(dbFileName)).arg(newFileFormat)) )
855 {
856// SQLite2ToSQLite3Migration *migr = new
857 SQLite2ToSQLite3Migration migr( finfo.absFilePath() );
858 tristate res = migr.run();
859// kdDebug() << "--- migr.run() END ---" <<endl;
860 if (!res) {
861 //TODO msg
862 KMessageBox::sorry(parent, i18n(
863 "Failed to convert project file \"%1\" to a new \"%2\" format.\n"
864 "The file format remains unchanged.")
865 .arg(TQDir::convertSeparators(dbFileName)).arg(newFileFormat) );
866 //continue...
867 }
868 if (res==true)
869 detectedDriverName = newFileFormat;
870 }
871// action.driverName = detectedDriverName;
872 if (detectedDriverName.isEmpty()) {
873 TQString possibleProblemsInfoMsg( Kexi::driverManager().possibleProblemsInfoMsg() );
874 if (!possibleProblemsInfoMsg.isEmpty()) {
875 possibleProblemsInfoMsg.prepend(TQString::fromLatin1("<p>")+i18n("Possible problems:"));
876 possibleProblemsInfoMsg += TQString::fromLatin1("</p>");
877 }
878 if (!(options & SkipMessages))
879 KMessageBox::detailedSorry(parent,
880 i18n( "The file \"%1\" is not recognized as being supported by Kexi.")
881 .arg(TQDir::convertSeparators(dbFileName)),
882 TQString::fromLatin1("<p>")
883 +i18n("Database driver for this file type not found.\nDetected MIME type: %1")
884 .arg(mimename)
885 +(ptr.data()->comment().isEmpty()
886 ? TQString::fromLatin1(".") : TQString::fromLatin1(" (%1).").arg(ptr.data()->comment()))
887 +TQString::fromLatin1("</p>")
888 +possibleProblemsInfoMsg);
889 return false;
890 }
891 return true;
892}
893
895KexiStartupHandler::selectProject(KexiDB::ConnectionData *cdata, bool& cancelled, TQWidget *parent)
896{
897 clearStatus();
898 cancelled = false;
899 if (!cdata)
900 return 0;
901 if (!cdata->savePassword && cdata->password.isEmpty()) {
902 if (!d->passwordDialog)
903 d->passwordDialog = new KexiDBPasswordDialog(0, *cdata, false);
904 const int ret = d->passwordDialog->exec();
905 if (d->passwordDialog->showConnectionDetailsRequested() || ret == TQDialog::Accepted) {
906
907 } else {
908 cancelled = true;
909 return 0;
910 }
911 }
913 //dialog for selecting a project
914 KexiProjectSelectorDialog prjdlg( parent, "prjdlg", cdata, true, false );
915 if (!prjdlg.projectSet() || prjdlg.projectSet()->error()) {
916 KexiGUIMessageHandler msgh;
917 if (prjdlg.projectSet())
918 msgh.showErrorMessage(prjdlg.projectSet(),
919 i18n("Could not load list of available projects for <b>%1</b> database server.")
920 .arg(cdata->serverInfoString(true)));
921 else
922 msgh.showErrorMessage(
923 i18n("Could not load list of available projects for <b>%1</b> database server.")
924 .arg(cdata->serverInfoString(true)));
925// setStatus(i18n("Could not load list of available projects for database server \"%1\"")
926// .arg(cdata->serverInfoString(true)), prjdlg.projectSet()->errorMsg());
927 return 0;
928 }
929 if (prjdlg.exec()!=TQDialog::Accepted) {
930 cancelled = true;
931 return 0;
932 }
933 if (prjdlg.selectedProjectData()) {
934 //deep copy
936 }
937 return projectData;
938}
939
940void KexiStartupHandler::slotSaveShortcutFileChanges()
941{
942 bool ok = true;
943 if (d->shortcutFile)
944 ok = d->shortcutFile->saveProjectData(d->connDialog->currentProjectData(),
945 d->connDialog->savePasswordOptionSelected(),
946 &d->shortcutFileGroupKey );
947 else if (d->connShortcutFile)
948 ok = d->connShortcutFile->saveConnectionData(
949 *d->connDialog->currentProjectData().connectionData(),
950 d->connDialog->savePasswordOptionSelected(),
951 &d->shortcutFileGroupKey );
952
953 if (!ok) {
954 KMessageBox::sorry(0, i18n("Failed saving connection data to\n\"%1\" file.")
955 .arg(TQDir::convertSeparators(d->shortcutFile->fileName())));
956 }
957}
958
959/*void KexiStartupHandler::slotShowConnectionDetails()
960{
961 d->passwordDialog->close();
962 d->showConnectionDetailsExecuted = true;
963}*/
964
965#include "KexiStartup.moc"
bool loadConnectionData(KexiDB::ConnectionData &data, TQString *groupKey=0)
bool savePassword
True if password should be saved to a file for the connection.
TQString localSocketFileName
Name of local (named) socket file.
TQString userName
Username used for the connection.
TQString password
Password used for the connection.
TQString driverName
the name of the driver that should be used to create a connection
unsigned short int port
Port used for the remote connection.
TQString hostName
Host name used for the remote connection.
Database specific connection data, e.g. host, port.
void setFileName(const TQString &fn)
Set the filename used by the connection.
TQString serverInfoString(bool addUser=true) const
A user-friendly string for the server.
TQString fileName() const
Get the filename used by the connection.
TQString dbFileName() const
The file name (without path) of the database file.
Database driver management, e.g. finding and loading drivers.
KexiDB::Driver::Info driverInfo(const TQString &name)
TQString lookupByMime(const TQString &mimeType)
bool fileBased
true is the driver is for file-based database backend
Definition driver.h:78
static TQString defaultFileBasedDriverName()
Definition driver.cpp:140
bool error() const
Definition object.h:38
const TQString & errorMsg() const
Definition object.h:42
Kexi project core data member.
TQValueList< ObjectInfo > autoopenObjects
void setReadOnly(bool set)
KexiProjectData * selectedProjectData() const
A project's main controller.
Definition kexiproject.h:68
static tristate dropProject(KexiProjectData *data, KexiDB::MessageHandler *handler, bool dontAsk=false)
static KexiProject * createBlankProject(bool &cancelled, KexiProjectData *data, KexiDB::MessageHandler *handler=0)
Startup data used for storing results of startup operations in Kexi.
KexiProjectData * projectData() const
static bool shouldBeShown()
@ OpenExistingResult
The user has chosen an existing connection or db file.
@ OpenRecentResult
The user has selected one of recently used databases.
@ ImportResult
The user has chosen to import db.
@ CreateFromTemplateResult
The user has selected a template to be used for creating a new db.
@ CreateBlankResult
The user has selected a template.
@ DontConvert
skip asking for conversion (used e.g. when dropdb is called)
Definition KexiStartup.h:86
@ ThisIsAShortcutToAProjectFile
a hint, forces detection of the file as a shortcut to a project file
Definition KexiStartup.h:88
@ ThisIsAShortcutToAConnectionData
a hint, forces detection of the file as a shortcut to a connection data
Definition KexiStartup.h:90
@ SkipMessages
do not display error or warning messages
Definition KexiStartup.h:92
@ ThisIsAProjectFile
a hint, forces detection of the file as a project file
Definition KexiStartup.h:87
static tristate detectActionForFile(KexiStartupData::Import &detectedImportAction, TQString &detectedDriverName, const TQString &_suggestedDriverName, const TQString &dbFileName, TQWidget *parent=0, int options=0)
KexiProjectData * selectProject(KexiDB::ConnectionData *cdata, bool &cancelled, TQWidget *parent=0)
virtual tristate init(int argc, char **argv)
3-state logical type with three values: true, false and cancelled and convenient operators.
Definition tristate.h:100
Namespace for general Kexi functions.
Definition kexi.h:38
KexiStartupHandler & startupHandler()
KEXICORE_EXPORT KexiDB::DriverManager & driverManager()
shared driver manager
Definition kexi.cpp:91
KEXICORE_EXPORT KexiDBConnectionSet & connset()
A set of known connections.
Definition kexi.cpp:74
KEXICORE_EXPORT KexiProjectSet & recentProjects()
A set avaiulable of project infos.
Definition kexi.cpp:86