20#include "KexiStartup.h"
22# include "KexiStartup_p_win.h"
24# include "KexiStartup_p.h"
27#include "kexiproject.h"
28#include "kexiprojectdata.h"
29#include "kexiprojectset.h"
30#include "kexiguimsghandler.h"
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>
45#include <tdemessagebox.h>
46#include <tdecmdlineargs.h>
49#include <kstaticdeleter.h>
55#include <tqapplication.h>
59 static KStaticDeleter<KexiStartupHandler> Kexi_startupHandlerDeleter;
60 KexiStartupHandler* _startupHandler = 0;
66 return *_startupHandler;
73class KexiStartupHandlerPrivate
76 KexiStartupHandlerPrivate()
78 , shortcutFile(0), connShortcutFile(0), connDialog(0), startupDialog(0)
82 ~KexiStartupHandlerPrivate()
84 delete passwordDialog;
89 KexiDBPasswordDialog* passwordDialog;
91 KexiDBShortcutFile *shortcutFile;
92 KexiDBConnShortcutFile *connShortcutFile;
93 KexiDBConnectionDialog *connDialog;
94 TQString shortcutFileGroupKey;
95 KexiStartupDialog *startupDialog;
100static bool stripQuotes(
const TQString &item, TQString &name)
102 if (item.left(1)==
"\"" && item.right(1)==
"\"") {
103 name = item.mid(1, item.length()-2);
110void updateProgressBar(KProgressDialog *pd,
char *buffer,
int buflen)
114 for (
int i=0; i<buflen; i++, p++) {
115 if ((i==0 || buffer[i-1]==
'\n') && buffer[i]==
'%') {
121 for (;i<buflen && *p>=
'0' && *p<=
'9'; j++, i++, p++)
122 line+=TQChar(*p).latin1();
124 int percent = line.toInt(&ok);
125 if (ok && percent>=0 && percent<=100 && pd->progressBar()->progress()<percent) {
127 pd->progressBar()->setProgress(percent);
128 tqApp->processEvents(100);
136KexiDBPasswordDialog::KexiDBPasswordDialog(TQWidget *parent,
KexiDB::ConnectionData& cdata,
bool showDetailsButton)
137 : KPasswordDialog( KPasswordDialog::Password, false,
138 showDetailsButton ? (int)KDialogBase::User1 : 0, parent )
140 , m_showConnectionDetailsRequested(false)
142 TQString msg =
"<H2>" + i18n(
"Opening database") +
"</H2><p>"
143 + i18n(
"Please enter the password.") +
"</p>";
149 if (srv.isEmpty() || srv.lower()==
"localhost")
150 srv = i18n(
"local database server");
152 msg += (
"</p><p>"+i18n(
"Database server: %1").arg(TQString(
"<nobr>")+srv+
"</nobr>")+
"</p>");
156 usr = i18n(
"unspecified user",
"(unspecified)");
160 msg += (
"<p>"+i18n(
"Username: %1").arg(usr)+
"</p>");
163 if (showDetailsButton) {
164 connect(
this, TQ_SIGNAL(user1Clicked()),
165 this, TQ_SLOT(slotShowConnectionDetails()) );
166 setButtonText(KDialogBase::User1, i18n(
"&Details")+
" >>");
168 setButtonOK(KGuiItem(i18n(
"&Open"),
"document-open"));
171KexiDBPasswordDialog::~KexiDBPasswordDialog()
175void KexiDBPasswordDialog::done(
int r)
177 if (r == TQDialog::Accepted) {
178 m_cdata->password = password();
186 KPasswordDialog::done(r);
189void KexiDBPasswordDialog::slotShowConnectionDetails()
191 m_showConnectionDetailsRequested =
true;
196KexiStartupHandler::KexiStartupHandler()
197 : TQObject(0,
"KexiStartupHandler")
199 , d( new KexiStartupHandlerPrivate() )
203KexiStartupHandler::~KexiStartupHandler()
208bool KexiStartupHandler::getAutoopenObjects(TDECmdLineArgs *args,
const TQCString &action_name)
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;
216 bool name_required =
true;
217 if (action_name==
"new") {
219 stripQuotes(item, type_name);
220 name_required =
false;
223 TQString defaultType;
224 if (action_name==
"execute")
225 defaultType =
"macro";
227 defaultType =
"table";
230 if (stripQuotes(item, obj_name)) {
231 type_name = defaultType;
233 else if ((idx = item.find(
':'))!=-1) {
235 type_name = item.left(idx).lower();
236 obj_name = item.mid(idx+1);
238 if (obj_name.left(1)==
"\"" && obj_name.right(1)==
"\"")
239 obj_name = obj_name.mid(1, obj_name.length()-2);
244 type_name = defaultType;
247 if (type_name.isEmpty())
249 if (name_required && obj_name.isEmpty())
252 KexiProjectData::ObjectInfo info;
253 info[
"name"]=obj_name;
254 info[
"type"]=type_name;
255 info[
"action"]=action_name;
257 atLeastOneFound =
true;
263 return atLeastOneFound;
268 m_action = DoNothing;
270 TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs(0);
276 const TQString connectionShortcutFileName( args->getOption(
"connection") );
277 if (!connectionShortcutFileName.isEmpty()) {
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())));
290 if (!args->getOption(
"dbdriver").isEmpty())
291 cdata.
driverName = args->getOption(
"dbdriver");
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.")
303 if (!args->getOption(
"host").isEmpty())
304 cdata.
hostName = args->getOption(
"host");
305 if (!args->getOption(
"local-socket").isEmpty())
307 if (!args->getOption(
"user").isEmpty())
308 cdata.
userName = args->getOption(
"user");
310 bool fileDriverSelected;
312 fileDriverSelected =
true;
316 if (dinfo.name.isEmpty()) {
318 KMessageBox::sorry(0, dm.
errorMsg());
323 bool projectFileExists =
false;
343 const TQString portStr = args->getOption(
"port");
344 if (!portStr.isEmpty()) {
346 const int p = portStr.toInt(&ok);
350 KMessageBox::sorry( 0,
351 i18n(
"You have specified invalid port number \"%1\"."));
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");
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.");
369 if (createDB && dropDB) {
370 KMessageBox::sorry( 0, i18n(
371 "You have used both \"createdb\" and \"dropdb\" startup options.")+couldnotMsg);
375 if (createDB || dropDB) {
376 if (args->count()<1) {
377 KMessageBox::sorry( 0, i18n(
"No project name specified.") );
388 delete d->passwordDialog;
389 d->passwordDialog =
new KexiDBPasswordDialog(0, cdata,
true);
392 const int ret = d->passwordDialog->exec();
393 if (d->passwordDialog->showConnectionDetailsRequested() || ret == TQDialog::Accepted) {
410 if (m_forcedUserMode && m_forcedDesignMode) {
411 KMessageBox::sorry( 0, i18n(
412 "You have used both \"user-mode\" and \"design-mode\" startup options.")+couldnotMsg);
417 if (args->count()>=1) {
420 if (fileDriverSelected) {
421 fileName = TQFile::decodeName(args->arg(0));
424 prjName = TQString::fromLocal8Bit(args->arg(0));
427 if (fileDriverSelected) {
428 TQFileInfo finfo(fileName);
429 prjName = finfo.fileName();
431 projectFileExists = finfo.exists();
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())));
447 if (fileDriverSelected) {
448 int detectOptions = 0;
449 if (fileType==
"project")
451 else if (fileType==
"shortcut")
453 else if (fileType==
"connection")
459 TQString detectedDriverName;
465 if (m_importActionData) {
466 m_action = ImportProject;
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;
481 delete d->shortcutFile;
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) {
492 *m_projectData = d->connDialog->currentProjectData();
495 delete d->connDialog;
497 delete d->shortcutFile;
500 if (res == TQDialog::Rejected) {
501 delete m_projectData;
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;
517 const bool showConnectionDialog = !args->isSet(
"skip-conn-dialog");
519 if (showConnectionDialog) {
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()));
527 const int res = d->connDialog->exec();
528 if (res == TQDialog::Accepted) {
530 cdata = *d->connDialog->currentProjectData().constConnectionData();
538 if (m_projectData || cancel || !showConnectionDialog)
542 delete d->connShortcutFile;
543 d->connShortcutFile = 0;
544 delete d->connDialog;
560 if (args->count()>1) {
565 if (d->passwordDialog && d->passwordDialog->showConnectionDetailsRequested()) {
566 d->connDialog =
new KexiDBConnectionDialog(*m_projectData);
569 int res = d->connDialog->exec();
571 if (res == TQDialog::Accepted) {
573 *m_projectData = d->connDialog->currentProjectData();
576 delete d->connDialog;
579 if (res == TQDialog::Rejected) {
580 delete m_projectData;
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");
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."));
604 bool creationNancelled;
605 KexiGUIMessageHandler gui;
609 if (creationNancelled)
613 KMessageBox::information( 0, i18n(
"Project \"%1\" created successfully.")
614 .arg( TQDir::convertSeparators(
projectData()->databaseName()) ));
620 KexiGUIMessageHandler gui;
623 KMessageBox::information( 0, i18n(
"Project \"%1\" dropped successfully.")
624 .arg( TQDir::convertSeparators(
projectData()->databaseName()) ));
636 if (!m_projectData) {
642 if (!d->startupDialog) {
645 KexiStartupDialog::Everything, KexiStartupDialog::CheckBoxDoNotShowAgain,
648 if (d->startupDialog->exec()!=TQDialog::Accepted)
651 const int r = d->startupDialog->result();
653 m_action = CreateBlankProject;
657 m_action = ImportProject;
661 const TQString selFile( d->startupDialog->selectedFileName() );
663 TQString detectedDriverName;
668 if (m_importActionData || detectedDriverName.isEmpty())
672 m_projectData->autoopenObjects = d->startupDialog->autoopenObjects();
673 m_action = CreateFromTemplate;
678 const TQString selFile( d->startupDialog->selectedFileName() );
679 if (!selFile.isEmpty()) {
683 TQString detectedDriverName;
688 if (m_importActionData) {
689 m_action = ImportProject;
693 if (detectedDriverName.isEmpty())
698 else if (d->startupDialog->selectedExistingConnection()) {
705 if (!m_projectData && !cancelled || cancelled) {
710 delete d->startupDialog;
711 d->startupDialog = 0;
729 if (m_projectData && (openExisting || (createDB && alsoOpenDB))) {
730 m_projectData->setReadOnly( readOnly );
731 m_action = OpenProject;
741 const TQString& _suggestedDriverName,
const TQString &dbFileName, TQWidget *parent,
int options )
744 TQString suggestedDriverName(_suggestedDriverName);
745 detectedDriverName = TQString();
746 TQFileInfo finfo(dbFileName);
747 if (dbFileName.isEmpty() || !finfo.isReadable()) {
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."));
765 ptr = KMimeType::findByFileContent(dbFileName);
766 mimename = ptr.data()->name();
767 kdDebug() <<
"KexiStartupHandler::detectActionForFile(): found mime is: "
769 if (mimename.isEmpty() || mimename==
"application/octet-stream" || mimename==
"text/plain") {
771 ptr = KMimeType::findByURL(dbFileName);
772 mimename = ptr.data()->name();
775 if (mimename.isEmpty() || mimename==
"application/octet-stream") {
777 TQFile f(dbFileName);
778 if (!f.open(IO_ReadOnly)) {
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."));
790 detectedDriverName =
"shortcut";
795 detectedDriverName =
"connection";
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() ) )
811 detectedImportAction.mimeType = mimename;
812 detectedImportAction.fileName = dbFileName;
817 if (!finfo.isWritable()) {
824 bool useDetectedDriver = suggestedDriverName.isEmpty() || suggestedDriverName.lower()==detectedDriverName.lower();
825 if (!useDetectedDriver) {
826 int res = KMessageBox::Yes;
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)
839 if (useDetectedDriver) {
840 detectedDriverName = tmpDriverName;
843 detectedDriverName = suggestedDriverName;
847 const TQString newFileFormat =
"SQLite3";
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)) )
856 SQLite2ToSQLite3Migration migr( finfo.absFilePath() );
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) );
868 detectedDriverName = newFileFormat;
871 if (detectedDriverName.isEmpty()) {
873 if (!possibleProblemsInfoMsg.isEmpty()) {
874 possibleProblemsInfoMsg.prepend(TQString::fromLatin1(
"<p>")+i18n(
"Possible problems:"));
875 possibleProblemsInfoMsg += TQString::fromLatin1(
"</p>");
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")
884 +(ptr.data()->comment().isEmpty()
885 ? TQString::fromLatin1(
".") : TQString::fromLatin1(
" (%1).").arg(ptr.data()->comment()))
886 +TQString::fromLatin1(
"</p>")
887 +possibleProblemsInfoMsg);
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) {
915 KexiGUIMessageHandler msgh;
918 i18n(
"Could not load list of available projects for <b>%1</b> database server.")
921 msgh.showErrorMessage(
922 i18n(
"Could not load list of available projects for <b>%1</b> database server.")
928 if (prjdlg.exec()!=TQDialog::Accepted) {
939void KexiStartupHandler::slotSaveShortcutFileChanges()
943 ok = d->shortcutFile->
saveProjectData(d->connDialog->currentProjectData(),
944 d->connDialog->savePasswordOptionSelected(),
945 &d->shortcutFileGroupKey );
946 else if (d->connShortcutFile)
948 *d->connDialog->currentProjectData().connectionData(),
949 d->connDialog->savePasswordOptionSelected(),
950 &d->shortcutFileGroupKey );
953 KMessageBox::sorry(0, i18n(
"Failed saving connection data to\n\"%1\" file.")
954 .arg(TQDir::convertSeparators(d->shortcutFile->
fileName())));
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)
TQString fileName() const
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
static TQString defaultFileBasedDriverName()
const TQString & errorMsg() const
Kexi project core data member.
TQValueList< ObjectInfo > autoopenObjects
KexiProjectSet * projectSet()
KexiProjectData * selectedProjectData() const
A project's main controller.
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)
@ ThisIsAShortcutToAProjectFile
@ ThisIsAShortcutToAConnectionData
@ SkipMessages
do not display error or warning messages
@ ThisIsAProjectFile
a hint, forces detection of the file as a project file
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.
Namespace for general Kexi functions.
KexiStartupHandler & startupHandler()
KEXICORE_EXPORT KexiDB::DriverManager & driverManager()
shared driver manager
KEXICORE_EXPORT KexiDBConnectionSet & connset()
A set of known connections.
KEXICORE_EXPORT KexiProjectSet & recentProjects()
A set avaiulable of project infos.