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>
47#include <tdeversion.h>
50#include <kstaticdeleter.h>
56#include <tqapplication.h>
60 static KStaticDeleter<KexiStartupHandler> Kexi_startupHandlerDeleter;
67 return *_startupHandler;
74class KexiStartupHandlerPrivate
77 KexiStartupHandlerPrivate()
79 , shortcutFile(0), connShortcutFile(0), connDialog(0), startupDialog(0)
83 ~KexiStartupHandlerPrivate()
85 delete passwordDialog;
90 KexiDBPasswordDialog* passwordDialog;
94 KexiDBConnectionDialog *connDialog;
95 TQString shortcutFileGroupKey;
101static bool stripQuotes(
const TQString &item, TQString &name)
103 if (item.left(1)==
"\"" && item.right(1)==
"\"") {
104 name = item.mid(1, item.length()-2);
111void updateProgressBar(KProgressDialog *pd,
char *buffer,
int buflen)
115 for (
int i=0; i<buflen; i++, p++) {
116 if ((i==0 || buffer[i-1]==
'\n') && buffer[i]==
'%') {
122 for (;i<buflen && *p>=
'0' && *p<=
'9'; j++, i++, p++)
123 line+=TQChar(*p).latin1();
125 int percent = line.toInt(&ok);
126 if (ok && percent>=0 && percent<=100 && pd->progressBar()->progress()<percent) {
128 pd->progressBar()->setProgress(percent);
129 tqApp->processEvents(100);
137KexiDBPasswordDialog::KexiDBPasswordDialog(TQWidget *parent,
KexiDB::ConnectionData& cdata,
bool showDetailsButton)
138 : KPasswordDialog( KPasswordDialog::Password, false,
139 showDetailsButton ? (int)KDialogBase::User1 : 0, parent )
141 , m_showConnectionDetailsRequested(false)
143 TQString msg =
"<H2>" + i18n(
"Opening database") +
"</H2><p>"
144 + i18n(
"Please enter the password.") +
"</p>";
150 if (srv.isEmpty() || srv.lower()==
"localhost")
151 srv = i18n(
"local database server");
153 msg += (
"</p><p>"+i18n(
"Database server: %1").arg(TQString(
"<nobr>")+srv+
"</nobr>")+
"</p>");
157 usr = i18n(
"unspecified user",
"(unspecified)");
161 msg += (
"<p>"+i18n(
"Username: %1").arg(usr)+
"</p>");
164 if (showDetailsButton) {
165 connect(
this, TQ_SIGNAL(user1Clicked()),
166 this, TQ_SLOT(slotShowConnectionDetails()) );
167 setButtonText(KDialogBase::User1, i18n(
"&Details")+
" >>");
169 setButtonOK(KGuiItem(i18n(
"&Open"),
"document-open"));
172KexiDBPasswordDialog::~KexiDBPasswordDialog()
176void KexiDBPasswordDialog::done(
int r)
178 if (r == TQDialog::Accepted) {
179 m_cdata->password = password();
187 KPasswordDialog::done(r);
190void KexiDBPasswordDialog::slotShowConnectionDetails()
192 m_showConnectionDetailsRequested =
true;
197KexiStartupHandler::KexiStartupHandler()
198 : TQObject(0,
"KexiStartupHandler")
200 , d( new KexiStartupHandlerPrivate() )
204KexiStartupHandler::~KexiStartupHandler()
209bool KexiStartupHandler::getAutoopenObjects(TDECmdLineArgs *args,
const TQCString &action_name)
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;
217 bool name_required =
true;
218 if (action_name==
"new") {
220 stripQuotes(item, type_name);
221 name_required =
false;
224 TQString defaultType;
225 if (action_name==
"execute")
226 defaultType =
"macro";
228 defaultType =
"table";
231 if (stripQuotes(item, obj_name)) {
232 type_name = defaultType;
234 else if ((idx = item.find(
':'))!=-1) {
236 type_name = item.left(idx).lower();
237 obj_name = item.mid(idx+1);
239 if (obj_name.left(1)==
"\"" && obj_name.right(1)==
"\"")
240 obj_name = obj_name.mid(1, obj_name.length()-2);
245 type_name = defaultType;
248 if (type_name.isEmpty())
250 if (name_required && obj_name.isEmpty())
253 KexiProjectData::ObjectInfo info;
254 info[
"name"]=obj_name;
255 info[
"type"]=type_name;
256 info[
"action"]=action_name;
258 atLeastOneFound =
true;
264 return atLeastOneFound;
269 m_action = DoNothing;
271 TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs(0);
277 const TQString connectionShortcutFileName( args->getOption(
"connection") );
278 if (!connectionShortcutFileName.isEmpty()) {
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())));
291 if (!args->getOption(
"dbdriver").isEmpty())
292 cdata.
driverName = args->getOption(
"dbdriver");
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.")
304 if (!args->getOption(
"host").isEmpty())
305 cdata.
hostName = args->getOption(
"host");
306 if (!args->getOption(
"local-socket").isEmpty())
308 if (!args->getOption(
"user").isEmpty())
309 cdata.
userName = args->getOption(
"user");
311 bool fileDriverSelected;
313 fileDriverSelected =
true;
317 if (dinfo.name.isEmpty()) {
319 KMessageBox::sorry(0, dm.
errorMsg());
324 bool projectFileExists =
false;
344 const TQString portStr = args->getOption(
"port");
345 if (!portStr.isEmpty()) {
347 const int p = portStr.toInt(&ok);
351 KMessageBox::sorry( 0,
352 i18n(
"You have specified invalid port number \"%1\"."));
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");
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.");
370 if (createDB && dropDB) {
371 KMessageBox::sorry( 0, i18n(
372 "You have used both \"createdb\" and \"dropdb\" startup options.")+couldnotMsg);
376 if (createDB || dropDB) {
377 if (args->count()<1) {
378 KMessageBox::sorry( 0, i18n(
"No project name specified.") );
389 delete d->passwordDialog;
390 d->passwordDialog =
new KexiDBPasswordDialog(0, cdata,
true);
393 const int ret = d->passwordDialog->exec();
394 if (d->passwordDialog->showConnectionDetailsRequested() || ret == TQDialog::Accepted) {
411 if (m_forcedUserMode && m_forcedDesignMode) {
412 KMessageBox::sorry( 0, i18n(
413 "You have used both \"user-mode\" and \"design-mode\" startup options.")+couldnotMsg);
418 if (args->count()>=1) {
421 if (fileDriverSelected) {
422 fileName = TQFile::decodeName(args->arg(0));
425 prjName = TQString::fromLocal8Bit(args->arg(0));
428 if (fileDriverSelected) {
429 TQFileInfo finfo(fileName);
430 prjName = finfo.fileName();
432 projectFileExists = finfo.exists();
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())));
448 if (fileDriverSelected) {
449 int detectOptions = 0;
450 if (fileType==
"project")
452 else if (fileType==
"shortcut")
454 else if (fileType==
"connection")
460 TQString detectedDriverName;
466 if (m_importActionData) {
467 m_action = ImportProject;
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;
482 delete d->shortcutFile;
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) {
493 *m_projectData = d->connDialog->currentProjectData();
496 delete d->connDialog;
498 delete d->shortcutFile;
501 if (res == TQDialog::Rejected) {
502 delete m_projectData;
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;
518 const bool showConnectionDialog = !args->isSet(
"skip-conn-dialog");
520 if (showConnectionDialog) {
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()));
528 const int res = d->connDialog->exec();
529 if (res == TQDialog::Accepted) {
531 cdata = *d->connDialog->currentProjectData().constConnectionData();
539 if (m_projectData || cancel || !showConnectionDialog)
543 delete d->connShortcutFile;
544 d->connShortcutFile = 0;
545 delete d->connDialog;
561 if (args->count()>1) {
566 if (d->passwordDialog && d->passwordDialog->showConnectionDetailsRequested()) {
567 d->connDialog =
new KexiDBConnectionDialog(*m_projectData);
570 int res = d->connDialog->exec();
572 if (res == TQDialog::Accepted) {
574 *m_projectData = d->connDialog->currentProjectData();
577 delete d->connDialog;
580 if (res == TQDialog::Rejected) {
581 delete m_projectData;
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");
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."));
605 bool creationNancelled;
606 KexiGUIMessageHandler gui;
610 if (creationNancelled)
614 KMessageBox::information( 0, i18n(
"Project \"%1\" created successfully.")
615 .arg( TQDir::convertSeparators(
projectData()->databaseName()) ));
621 KexiGUIMessageHandler gui;
624 KMessageBox::information( 0, i18n(
"Project \"%1\" dropped successfully.")
625 .arg( TQDir::convertSeparators(
projectData()->databaseName()) ));
637 if (!m_projectData) {
643 if (!d->startupDialog) {
646 KexiStartupDialog::Everything, KexiStartupDialog::CheckBoxDoNotShowAgain,
649 if (d->startupDialog->exec()!=TQDialog::Accepted)
652 const int r = d->startupDialog->result();
654 m_action = CreateBlankProject;
658 m_action = ImportProject;
662 const TQString selFile( d->startupDialog->selectedFileName() );
664 TQString detectedDriverName;
669 if (m_importActionData || detectedDriverName.isEmpty())
674 m_action = CreateFromTemplate;
679 const TQString selFile( d->startupDialog->selectedFileName() );
680 if (!selFile.isEmpty()) {
684 TQString detectedDriverName;
689 if (m_importActionData) {
690 m_action = ImportProject;
694 if (detectedDriverName.isEmpty())
699 else if (d->startupDialog->selectedExistingConnection()) {
706 if (!m_projectData && !cancelled || cancelled) {
711 delete d->startupDialog;
712 d->startupDialog = 0;
730 if (m_projectData && (openExisting || (createDB && alsoOpenDB))) {
732 m_action = OpenProject;
742 const TQString& _suggestedDriverName,
const TQString &dbFileName, TQWidget *parent,
int options )
745 TQString suggestedDriverName(_suggestedDriverName);
746 detectedDriverName = TQString();
747 TQFileInfo finfo(dbFileName);
748 if (dbFileName.isEmpty() || !finfo.isReadable()) {
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."));
766 ptr = KMimeType::findByFileContent(dbFileName);
767 mimename = ptr.data()->name();
768 kdDebug() <<
"KexiStartupHandler::detectActionForFile(): found mime is: "
770 if (mimename.isEmpty() || mimename==
"application/octet-stream" || mimename==
"text/plain") {
772 ptr = KMimeType::findByURL(dbFileName);
773 mimename = ptr.data()->name();
776 if (mimename.isEmpty() || mimename==
"application/octet-stream") {
778 TQFile f(dbFileName);
779 if (!f.open(IO_ReadOnly)) {
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."));
791 detectedDriverName =
"shortcut";
796 detectedDriverName =
"connection";
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() ) )
812 detectedImportAction.mimeType = mimename;
813 detectedImportAction.fileName = dbFileName;
818 if (!finfo.isWritable()) {
825 bool useDetectedDriver = suggestedDriverName.isEmpty() || suggestedDriverName.lower()==detectedDriverName.lower();
826 if (!useDetectedDriver) {
827 int res = KMessageBox::Yes;
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)
840 if (useDetectedDriver) {
841 detectedDriverName = tmpDriverName;
844 detectedDriverName = suggestedDriverName;
848 const TQString newFileFormat =
"SQLite3";
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)) )
857 SQLite2ToSQLite3Migration migr( finfo.absFilePath() );
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) );
869 detectedDriverName = newFileFormat;
872 if (detectedDriverName.isEmpty()) {
874 if (!possibleProblemsInfoMsg.isEmpty()) {
875 possibleProblemsInfoMsg.prepend(TQString::fromLatin1(
"<p>")+i18n(
"Possible problems:"));
876 possibleProblemsInfoMsg += TQString::fromLatin1(
"</p>");
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")
885 +(ptr.data()->comment().isEmpty()
886 ? TQString::fromLatin1(
".") : TQString::fromLatin1(
" (%1).").arg(ptr.data()->comment()))
887 +TQString::fromLatin1(
"</p>")
888 +possibleProblemsInfoMsg);
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) {
916 KexiGUIMessageHandler msgh;
919 i18n(
"Could not load list of available projects for <b>%1</b> database server.")
922 msgh.showErrorMessage(
923 i18n(
"Could not load list of available projects for <b>%1</b> database server.")
929 if (prjdlg.exec()!=TQDialog::Accepted) {
940void KexiStartupHandler::slotSaveShortcutFileChanges()
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 );
954 KMessageBox::sorry(0, i18n(
"Failed saving connection data to\n\"%1\" file.")
955 .arg(TQDir::convertSeparators(d->shortcutFile->fileName())));
965#include "KexiStartup.moc"
bool loadConnectionData(KexiDB::ConnectionData &data, TQString *groupKey=0)
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
void setReadOnly(bool set)
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)
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)
@ ThisIsAShortcutToAProjectFile
a hint, forces detection of the file as a shortcut to a project file
@ ThisIsAShortcutToAConnectionData
a hint, forces detection of the file as a shortcut to a connection data
@ 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.