kexi

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