kexi

kexiproject.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
3 Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include <tqfile.h>
22#include <tqapplication.h>
23#include <tqdom.h>
24
25#include <kmimetype.h>
26#include <kdebug.h>
27#include <tdelocale.h>
28
29#include <kexiutils/identifier.h>
30
31#include <kexidb/connection.h>
32#include <kexidb/cursor.h>
33#include <kexidb/driver.h>
34#include <kexidb/drivermanager.h>
35#include <kexidb/utils.h>
36#include <kexidb/parser/parser.h>
37#include <kexidb/msghandler.h>
38#include <kexidb/dbproperties.h>
39#include <kexiutils/utils.h>
40
41#include "kexiproject.h"
42#include "kexipartmanager.h"
43#include "kexipartitem.h"
44#include "kexipartinfo.h"
45#include "kexipart.h"
46#include "kexidialogbase.h"
47#include "kexi.h"
48#include "keximainwindow.h"
49#include "kexiblobbuffer.h"
50#include "kexiguimsghandler.h"
51
52#include <assert.h>
53
54class KexiProject::Private
55{
56 public:
57 Private()
58 : data(0)
59 , itemDictsCache(199)
60 , unstoredItems(199)
61 , tempPartItemID_Counter(-1)
62 , sqlParser(0)
63 , versionMajor(0)
64 , versionMinor(0)
65 {
66 itemDictsCache.setAutoDelete(true);
67 unstoredItems.setAutoDelete(true);
68 }
69 ~Private() {
70 delete data;
71 data=0;
72 delete sqlParser;
73 }
74
75 TQGuardedPtr<KexiDB::Connection> connection;
76 TQGuardedPtr<KexiProjectData> data;
77
78 TQString error_title;
79
81 TQIntDict<KexiPart::ItemDict> itemDictsCache;
82
83 TQPtrDict<KexiPart::Item> unstoredItems;
84 int tempPartItemID_Counter;
86 KexiDB::Parser* sqlParser;
87
88 int versionMajor;
89 int versionMinor;
90};
91
92//---------------------------
93
94/*
95 Helper for setting temporary error title.
96class KexiProject::ErrorTitle
97{
98 public:
99 ErrorTitle(KexiProject* p, const TQString& msg = TQString())
100 : prj(p)
101 , prev_err_title(p->m_error_title)
102 {
103 p->m_error_title = msg;
104 }
105 ~ErrorTitle()
106 {
107 prj->m_error_title = prev_err_title;
108 }
109 KexiProject* prj;
110 TQString prev_err_title;
111};*/
112
114 : TQObject(), Object(handler)
115 , d(new Private())
116{
117 d->data = pdata;
120}
121
123 KexiDB::Connection* conn)
124 : TQObject(), Object(handler)
125 , d(new Private())
126{
127 d->data = pdata;
128 if (d->data->connectionData() == d->connection->data())
129 d->connection = conn;
130 else
131 kdWarning() << "KexiProject::KexiProject(): passed connection's data ("
132 << conn->data()->serverInfoString() << ") is not compatible with project's conn. data ("
133 << d->data->connectionData()->serverInfoString() << ")" << endl;
136}
137
138KexiProject::~KexiProject()
139{
140 closeConnection();
141 delete d;
142}
143
145{
146 return d->connection;
147}
148
150{
151 return d->data;
152}
153
155{
156 return d->versionMajor;
157}
158
160{
161 return d->versionMinor;
162}
163
165KexiProject::open(bool &incompatibleWithKexi)
166{
167 return openInternal(&incompatibleWithKexi);
168}
169
172{
173 return openInternal(0);
174}
175
177KexiProject::openInternal(bool *incompatibleWithKexi)
178{
179 if (incompatibleWithKexi)
180 *incompatibleWithKexi = false;
181 kdDebug() << "KexiProject::open(): " << d->data->databaseName() <<" "<< d->data->connectionData()->driverName << endl;
182 KexiDB::MessageTitle et(this,
183 i18n("Could not open project \"%1\".").arg(d->data->databaseName()));
184
185 if (!createConnection()) {
186 kdDebug() << "KexiProject::open(): !createConnection()" << endl;
187 return false;
188 }
189 bool cancel = false;
190 KexiGUIMessageHandler msgHandler;
191 if (!d->connection->useDatabase(d->data->databaseName(), true, &cancel, &msgHandler))
192 {
193 if (cancel) {
194 return cancelled;
195 }
196 kdDebug() << "KexiProject::open(): !d->connection->useDatabase() "
197 << d->data->databaseName() <<" "<< d->data->connectionData()->driverName << endl;
198
199 if (d->connection->errorNum() == ERR_NO_DB_PROPERTY) {
200//<temp>
202 if (/*supported?*/ !d->data->connectionData()->driverName.lower().startsWith("sqlite")) {
203//</temp>
204 if (incompatibleWithKexi)
205 *incompatibleWithKexi = true;
206 }
207 else
208 setError(d->connection);
209 closeConnection();
210 return false;
211 }
212
213 setError(d->connection);
214 closeConnection();
215 return false;
216 }
217
218 if (!initProject())
219 return false;
220
221 return createInternalStructures(/*insideTransaction*/true);
222}
223
225KexiProject::create(bool forceOverwrite)
226{
227 KexiDB::MessageTitle et(this,
228 i18n("Could not create project \"%1\".").arg(d->data->databaseName()));
229
230 if (!createConnection())
231 return false;
232 if (!checkWritable())
233 return false;
234 if (d->connection->databaseExists( d->data->databaseName() )) {
235 if (!forceOverwrite)
236 return cancelled;
237 if (!d->connection->dropDatabase( d->data->databaseName() )) {
238 setError(d->connection);
239 closeConnection();
240 return false;
241 }
242 kdDebug() << "--- DB '" << d->data->databaseName() << "' dropped ---"<< endl;
243 }
244 if (!d->connection->createDatabase( d->data->databaseName() )) {
245 setError(d->connection);
246 closeConnection();
247 return false;
248 }
249 kdDebug() << "--- DB '" << d->data->databaseName() << "' created ---"<< endl;
250 // and now: open
251 if (!d->connection->useDatabase(d->data->databaseName()))
252 {
253 kdDebug() << "--- DB '" << d->data->databaseName() << "' USE ERROR ---"<< endl;
254 setError(d->connection);
255 closeConnection();
256 return false;
257 }
258 kdDebug() << "--- DB '" << d->data->databaseName() << "' used ---"<< endl;
259
260 //<add some data>
261 KexiDB::Transaction trans = d->connection->beginTransaction();
262 if (trans.isNull())
263 return false;
264
265 if (!createInternalStructures(false))
266 return false;
267
268 //add some metadata
270 KexiDB::DatabaseProperties &props = d->connection->databaseProperties();
271 if (!props.setValue("kexiproject_major_ver", d->versionMajor)
272 || !props.setCaption("kexiproject_major_ver", i18n("Project major version"))
273 || !props.setValue("kexiproject_minor_ver", d->versionMinor)
274 || !props.setCaption("kexiproject_minor_ver", i18n("Project minor version"))
275 || !props.setValue("project_caption", d->data->caption())
276 || !props.setCaption("project_caption", i18n("Project caption"))
277 || !props.setValue("project_desc", d->data->description())
278 || !props.setCaption("project_desc", i18n("Project description")) )
279 return false;
280
281/* KexiDB::TableSchema *t_db = d->connection->tableSchema("kexi__db");
282 //caption:
283 if (!t_db)
284 return false;
285
286 if (!KexiDB::replaceRow(*d->connection, t_db, "db_property", "project_caption",
287 "db_value", TQVariant( d->data->caption() ), KexiDB::Field::Text)
288 || !KexiDB::replaceRow(*d->connection, t_db, "db_property", "project_desc",
289 "db_value", TQVariant( d->data->description() ), KexiDB::Field::Text) )
290 return false;
291*/
292 if (trans.active() && !d->connection->commitTransaction(trans))
293 return false;
294 //</add some data>
295
296 return initProject();
297}
298
299bool KexiProject::createInternalStructures(bool insideTransaction)
300{
302 if (insideTransaction) {
303 tg.setTransaction( d->connection->beginTransaction() );
304 if (tg.transaction().isNull())
305 return false;
306 }
307
308 //Get information about kexiproject version.
309 //kexiproject version is a version of data layer above kexidb layer.
310 KexiDB::DatabaseProperties &props = d->connection->databaseProperties();
311 bool ok;
312 int storedMajorVersion = props.value("kexiproject_major_ver").toInt(&ok);
313 if (!ok)
314 storedMajorVersion = 0;
315 int storedMinorVersion = props.value("kexiproject_minor_ver").toInt(&ok);
316 if (!ok)
317 storedMinorVersion = 1;
318
319 bool containsKexi__blobsTable = d->connection->drv_containsTable("kexi__blobs");
320 int dummy;
321 bool contains_o_folder_id = containsKexi__blobsTable && true == d->connection->querySingleNumber(
322 "SELECT COUNT(o_folder_id) FROM kexi__blobs", dummy, 0, false/*addLimitTo1*/);
323 bool add_folder_id_column = false;
324
326 if (storedMajorVersion<=0) {
327 d->versionMajor = KEXIPROJECT_VERSION_MAJOR;
328 d->versionMinor = KEXIPROJECT_VERSION_MINOR;
329 //For compatibility for projects created before Kexi 1.0 beta 1:
330 //1. no kexiproject_major_ver and kexiproject_minor_ver -> add them
331 if (!d->connection->isReadOnly()) {
332 if (!props.setValue("kexiproject_major_ver", d->versionMajor)
333 || !props.setCaption("kexiproject_major_ver", i18n("Project major version"))
334 || !props.setValue("kexiproject_minor_ver", d->versionMinor)
335 || !props.setCaption("kexiproject_minor_ver", i18n("Project minor version")) ) {
336 return false;
337 }
338 }
339
340 if (containsKexi__blobsTable) {
342 if (!d->connection->isReadOnly()) {
343 if (!contains_o_folder_id) {
344 add_folder_id_column = true;
345 }
346 }
347 }
348 }
349 if (storedMajorVersion!=d->versionMajor || storedMajorVersion!=d->versionMinor) {
351 d->versionMajor = storedMajorVersion;
352 d->versionMinor = storedMinorVersion;
353 }
354
355 KexiDB::InternalTableSchema *t_blobs = new KexiDB::InternalTableSchema("kexi__blobs");
356 t_blobs->addField( new KexiDB::Field("o_id", KexiDB::Field::Integer,
357 KexiDB::Field::PrimaryKey | KexiDB::Field::AutoInc, KexiDB::Field::Unsigned) )
359 .addField( new KexiDB::Field("o_name", KexiDB::Field::Text ) )
360 .addField( new KexiDB::Field("o_caption", KexiDB::Field::Text ) )
361 .addField( new KexiDB::Field("o_mime", KexiDB::Field::Text, KexiDB::Field::NotNull) )
362 .addField( new KexiDB::Field("o_folder_id",
363 KexiDB::Field::Integer, 0, KexiDB::Field::Unsigned) //references kexi__gallery_folders.f_id
364 //If null, the BLOB only points to virtual "All" folder
365 //WILL BE USED in Kexi >=2.0
366 );
367
368 //*** create global BLOB container, if not present
369 if (containsKexi__blobsTable) {
371 d->connection->insertInternalTableSchema(t_blobs);
372 if (add_folder_id_column && !d->connection->isReadOnly()) {
373 // 2. "kexi__blobs" table contains no "o_folder_id" column -> add it
374 // (by copying table to avoid data loss)
375 KexiDB::TableSchema *kexi__blobsCopy = new KexiDB::TableSchema( *t_blobs );
376 kexi__blobsCopy->setName("kexi__blobs__copy");
377 if (!d->connection->drv_createTable( *kexi__blobsCopy )) {
378 delete kexi__blobsCopy;
379 delete t_blobs;
380 return false;
381 }
382 // 2.1 copy data (insert 0's into o_folder_id column)
383 if (!d->connection->executeSQL(
384 TQString::fromLatin1("INSERT INTO kexi__blobs (o_data, o_name, o_caption, o_mime, o_folder_id) "
385 "SELECT o_data, o_name, o_caption, o_mime, 0 FROM kexi__blobs") )
386 // 2.2 remove the original kexi__blobs
387 || !d->connection->executeSQL(TQString::fromLatin1("DROP TABLE kexi__blobs")) //lowlevel
388 // 2.3 rename the copy back into kexi__blobs
389 || !d->connection->drv_alterTableName(*kexi__blobsCopy, "kexi__blobs")
390 )
391 {
392 //(no need to drop the copy, ROLLBACK will drop it)
393 delete kexi__blobsCopy;
394 delete t_blobs;
395 return false;
396 }
397 delete kexi__blobsCopy; //not needed - physically renamed to kexi_blobs
398 }
399 }
400 else {
401// if (!d->connection->createTable( t_blobs, false/*!replaceExisting*/ )) {
402 if (!d->connection->isReadOnly()) {
403 if (!d->connection->createTable( t_blobs, true/*replaceExisting*/ )) {
404 delete t_blobs;
405 return false;
406 }
407 }
408 }
409
410 //Store default part infos.
411 //Infos for other parts (forms, reports...) are created on demand in KexiDialogBase::storeNewData()
412 KexiDB::InternalTableSchema *t_parts = new KexiDB::InternalTableSchema("kexi__parts"); //newKexiDBSystemTableSchema("kexi__parts");
413 t_parts->addField(
414 new KexiDB::Field("p_id", KexiDB::Field::Integer, KexiDB::Field::PrimaryKey | KexiDB::Field::AutoInc, KexiDB::Field::Unsigned)
415 )
417 .addField( new KexiDB::Field("p_mime", KexiDB::Field::Text ) )
418 .addField( new KexiDB::Field("p_url", KexiDB::Field::Text ) );
419
420 bool containsKexi__partsTable = d->connection->drv_containsTable("kexi__parts");
421 bool partsTableOk = true;
422 if (containsKexi__partsTable) {
424 d->connection->insertInternalTableSchema(t_parts);
425 }
426 else {
427 if (!d->connection->isReadOnly()) {
428 partsTableOk = d->connection->createTable( t_parts, true/*replaceExisting*/ );
429
430 KexiDB::FieldList *fl = t_parts->subList("p_id", "p_name", "p_mime", "p_url");
431 if (partsTableOk)
432 partsTableOk = d->connection->insertRecord(*fl, TQVariant(1), TQVariant("Tables"),
433 TQVariant("kexi/table"), TQVariant("http://koffice.org/kexi/"));
434
435 if (partsTableOk)
436 partsTableOk = d->connection->insertRecord(*fl, TQVariant(2), TQVariant("Queries"),
437 TQVariant("kexi/query"), TQVariant("http://koffice.org/kexi/"));
438 }
439 }
440
441 if (!partsTableOk) {
442 delete t_parts;
443 return false;
444 }
445
446 if (insideTransaction) {
447 if (tg.transaction().active() && !tg.commit())
448 return false;
449 }
450 return true;
451}
452
453bool
455{
456 if (d->connection)
457 return true;
458
459 clearError();
460// closeConnection();//for sanity
461 KexiDB::MessageTitle et(this);
462
463 KexiDB::Driver *driver = Kexi::driverManager().driver(d->data->connectionData()->driverName);
464 if(!driver) {
466 return false;
467 }
468
469 int connectionOptions = 0;
470 if (d->data->isReadOnly())
471 connectionOptions |= KexiDB::Driver::ReadOnlyConnection;
472 d->connection = driver->createConnection(*d->data->connectionData(), connectionOptions);
473 if (!d->connection)
474 {
475 kdDebug() << "KexiProject::open(): uuups failed " << driver->errorMsg() << endl;
476 setError(driver);
477 return false;
478 }
479
480 if (!d->connection->connect())
481 {
482 setError(d->connection);
483 kdDebug() << "KexiProject::createConnection(): error connecting: " << (d->connection ? d->connection->errorMsg() : TQString()) << endl;
484 closeConnection();
485 return false;
486 }
487
488 //re-init BLOB buffer
490 KexiBLOBBuffer::setConnection(d->connection);
491 return true;
492}
493
494
495bool
496KexiProject::closeConnection()
497{
498 if (!d->connection)
499 return true;
500
501 if (!d->connection->disconnect()) {
502 setError(d->connection);
503 return false;
504 }
505
506 delete d->connection; //this will also clear connection for BLOB buffer
507 d->connection = 0;
508 return true;
509}
510
511bool
512KexiProject::initProject()
513{
514// emit dbAvailable();
515 kdDebug() << "KexiProject::open(): checking project parts..." << endl;
516
517 if (!Kexi::partManager().checkProject(d->connection)) {
518 setError(Kexi::partManager().error() ? (KexiDB::Object*)&Kexi::partManager() : (KexiDB::Connection*)d->connection);
519 return false;
520 }
521
522// !@todo put more props. todo - creator, created date, etc. (also to KexiProjectData)
523 KexiDB::DatabaseProperties &props = d->connection->databaseProperties();
524 TQString str( props.value("project_caption").toString() );
525 if (!str.isEmpty())
526 d->data->setCaption( str );
527 str = props.value("project_desc").toString();
528 if (!str.isEmpty())
529 d->data->setDescription( str );
530/* KexiDB::RowData data;
531 TQString sql = "select db_value from kexi__db where db_property='%1'";
532 if (d->connection->querySingleRecord( sql.arg("project_caption"), data ) && !data[0].toString().isEmpty())
533 d->data->setCaption(data[0].toString());
534 if (d->connection->querySingleRecord( sql.arg("project_desc"), data) && !data[0].toString().isEmpty())
535 d->data->setDescription(data[0].toString());*/
536
537 return true;
538}
539
540bool
542{
543 if(d->connection && d->connection->isDatabaseUsed())
544 return true;
545
546 return false;
547}
548
549KexiPart::ItemDict*
551{
552 kdDebug() << "KexiProject::items()" << endl;
553 if(!i || !isConnected())
554 return 0;
555
556 //trying in cache...
557 KexiPart::ItemDict *dict = d->itemDictsCache[ i->projectPartID() ];
558 if (dict)
559 return dict;
560 //retrieve:
561 KexiDB::Cursor *cursor = d->connection->executeQuery(
562 "SELECT o_id, o_name, o_caption FROM kexi__objects WHERE o_type = "
563 + TQString::number(i->projectPartID()));//, KexiDB::Cursor::Buffered);
564// kdDebug() << "KexiProject::items(): cursor handle is:" << cursor << endl;
565 if(!cursor)
566 return 0;
567
568 dict = new KexiPart::ItemDict(1009);
569 dict->setAutoDelete(true);
570
571 for(cursor->moveFirst(); !cursor->eof(); cursor->moveNext())
572 {
573 KexiPart::Item *it = new KexiPart::Item();
574 bool ok;
575 int ident = cursor->value(0).toInt(&ok);
576 TQString objName( cursor->value(1).toString() );
577
578 if ( ok && (ident>0) && !d->connection->isInternalTableSchema(objName)
579 && KexiUtils::isIdentifier(objName) )
580 {
581 it->setIdentifier(ident);
582 it->setMimeType(i->mimeType()); //js: may be not null???
583 it->setName(objName);
584 it->setCaption(cursor->value(2).toString());
585 }
586 dict->insert(it->identifier(), it);
587// kdDebug() << "KexiProject::items(): ITEM ADDED == "<<objName <<" id="<<ident<<endl;
588 }
589
590 d->connection->deleteCursor(cursor);
591// kdDebug() << "KexiProject::items(): end with count " << dict->count() << endl;
592 d->itemDictsCache.insert( i->projectPartID(), dict );
593 return dict;
594}
595
596KexiPart::ItemDict*
597KexiProject::itemsForMimeType(const TQCString &mimeType)
598{
600 return items(info);
601}
602
603void
605{
606 list.clear();
607 KexiPart::ItemDict* dict = items(i);
608 if (!dict)
609 return;
610 for (KexiPart::ItemDictIterator it(*dict); it.current(); ++it)
611 list.append(it.current());
612}
613
614void
616{
618 getSortedItems(list, info);
619}
620
621void
623{
624 if (!info || !item)
625 return;
626 KexiPart::ItemDict *dict = items(info);
627 item->setNeverSaved( false );
628 d->unstoredItems.take(item); //no longer unstored
629 dict->insert( item->identifier(), item );
630 //let's update e.g. navigator
631 emit newItemStored(*item);
632}
633
635KexiProject::itemForMimeType(const TQCString &mimeType, const TQString &name)
636{
637 KexiPart::ItemDict *dict = itemsForMimeType(mimeType);
638 if (!dict)
639 return 0;
640 const TQString l_name = name.lower();
641 for (KexiPart::ItemDictIterator it( *dict ); it.current(); ++it) {
642 if (it.current()->name().lower()==l_name)
643 return it.current();
644 }
645 return 0;
646}
647
649KexiProject::item(KexiPart::Info *i, const TQString &name)
650{
651 KexiPart::ItemDict *dict = items(i);
652 if (!dict)
653 return 0;
654 const TQString l_name = name.lower();
655 for (KexiPart::ItemDictIterator it( *dict ); it.current(); ++it) {
656 if (it.current()->name().lower()==l_name)
657 return it.current();
658 }
659 return 0;
660}
661
663KexiProject::item(int identifier)
664{
665 KexiPart::ItemDict *dict;
666 for (TQIntDictIterator<KexiPart::ItemDict> it(d->itemDictsCache); (dict = it.current()); ++it) {
667 KexiPart::Item *item = dict->find(identifier);
668 if (item)
669 return item;
670 }
671 return 0;
672}
673
674/*void KexiProject::clearMsg()
675{
676 clearError();
677// d->error_title=TQString();
678}
679
680void KexiProject::setError(int code, const TQString &msg )
681{
682 Object::setError(code, msg);
683 if (Object::error())
684 ERRMSG(d->error_title, this);
685// emit error(d->error_title, this);
686}
687
688
689void KexiProject::setError( const TQString &msg )
690{
691 Object::setError(msg);
692 if (Object::error())
693 ERRMSG(d->error_title, this);
694// emit error(d->error_title, this);
695}
696
697void KexiProject::setError( KexiDB::Object *obj )
698{
699 if (!obj)
700 return;
701 Object::setError(obj);
702 if (Object::error())
703 ERRMSG(d->error_title, obj);
704// emit error(d->error_title, obj);
705}
706
707void KexiProject::setError(const TQString &msg, const TQString &desc)
708{
709 Object::setError(msg); //ok?
710 ERRMSG(msg, desc); //not KexiDB-related
711// emit error(msg, desc); //not KexiDB-related
712}
713*/
714
716{
717 clearError();
718 KexiDB::MessageTitle et(this);
720 if (!part)
722 return part;
723}
724
726 int viewMode, TQMap<TQString,TQString>* staticObjectArgs)
727{
728 clearError();
729 if (viewMode!=Kexi::DataViewMode && data()->userMode())
730 return 0;
731
732 KexiDB::MessageTitle et(this);
734 if (!part)
735 return 0;
736 KexiDialogBase *dlg = part->openInstance(wnd, item, viewMode, staticObjectArgs);
737 if (!dlg) {
738 if (part->lastOperationStatus().error())
739 setError(i18n("Opening object \"%1\" failed.").arg(item.name())+"<br>"
740 +part->lastOperationStatus().message,
741 part->lastOperationStatus().description);
742 return 0;
743 }
744 return dlg;
745}
746
747KexiDialogBase* KexiProject::openObject(KexiMainWindow *wnd, const TQCString &mimeType,
748 const TQString& name, int viewMode)
749{
750 KexiPart::Item *it = itemForMimeType(mimeType, name);
751 return it ? openObject(wnd, *it, viewMode) : 0;
752}
753
755{
756 if (!d->connection->isReadOnly())
757 return true;
758 setError(i18n("This project is opened as read only."));
759 return false;
760}
761
763{
764 clearError();
765 if (data()->userMode())
766 return false;
767
768 KexiDB::MessageTitle et(this);
769 if (!checkWritable())
770 return false;
772 if (!part)
773 return false;
774 if (!item.neverSaved() && !part->remove(wnd, item)) {
775 //js TODO check for errors
776 return false;
777 }
778 if (!item.neverSaved()) {
779 KexiDB::TransactionGuard tg( *d->connection );
780 if (!tg.transaction().active()) {
781 setError(d->connection);
782 return false;
783 }
784 if (!d->connection->removeObject( item.identifier() )) {
785 setError(d->connection);
786 return false;
787 }
788 if (!tg.commit()) {
789 setError(d->connection);
790 return false;
791 }
792 }
793 emit itemRemoved(item);
794
795 //now: remove this item from cache
796 if (part->info()) {
797 KexiPart::ItemDict *dict = d->itemDictsCache[ part->info()->projectPartID() ];
798 if (!(dict && dict->remove( item.identifier() )))
799 d->unstoredItems.remove(&item);//remove temp.
800 }
801 return true;
802}
803
804bool KexiProject::renameObject( KexiMainWindow *wnd, KexiPart::Item& item, const TQString& _newName )
805{
806 clearError();
807 if (data()->userMode())
808 return 0;
809
811 TQString newName = _newName.stripWhiteSpace();
812 {
813 KexiDB::MessageTitle et(this);
814 if (newName.isEmpty()) {
815 setError( i18n("Could not set empty name for this object.") );
816 return false;
817 }
818 if (this->itemForMimeType(item.mimeType(), newName)!=0) {
819 setError( i18n("Could not use this name. Object with name \"%1\" already exists.")
820 .arg(newName) );
821 return false;
822 }
823 }
824
825 KexiDB::MessageTitle et(this,
826 i18n("Could not rename object \"%1\".").arg(item.name()) );
827 if (!checkWritable())
828 return false;
830 if (!part)
831 return false;
832 KexiDB::TransactionGuard tg( *d->connection );
833 if (!tg.transaction().active()) {
834 setError(d->connection);
835 return false;
836 }
837 if (!part->rename(wnd, item, newName)) {
838 setError(part->lastOperationStatus().message, part->lastOperationStatus().description);
839 return false;
840 }
841 if (!d->connection->executeSQL( "update kexi__objects set o_name="
842 + d->connection->driver()->valueToSQL( KexiDB::Field::Text, newName )
843 + " where o_id=" + TQString::number(item.identifier()) )) {
844 setError(d->connection);
845 return false;
846 }
847 if (!tg.commit()) {
848 setError(d->connection);
849 return false;
850 }
851 TQCString oldName( item.name().latin1() );
852 item.setName( newName );
853 emit itemRenamed(item, oldName);
854 return true;
855}
856
857KexiPart::Item* KexiProject::createPartItem(KexiPart::Info *info, const TQString& suggestedCaption)
858{
859 clearError();
860 if (data()->userMode())
861 return 0;
862
863 KexiDB::MessageTitle et(this);
864 KexiPart::Part *part = Kexi::partManager().part(info);
865 if (!part) {
867 return 0;
868 }
869
870 KexiPart::ItemDict *dict = items(info);
871
872 //find new, unique default name for this item
873 int n;
874 TQString new_name;
875 TQString base_name;
876 if (suggestedCaption.isEmpty()) {
877 n = 1;
878 base_name = part->instanceName();
879 }
880 else {
881 n = 0; //means: try not to add 'n'
882 base_name = KexiUtils::string2Identifier(suggestedCaption).lower();
883 }
884 base_name = KexiUtils::string2Identifier(base_name).lower();
885 KexiPart::ItemDictIterator it(*dict);
886 TQPtrDictIterator<KexiPart::Item> itUnstored(d->unstoredItems);
887 do {
888 new_name = base_name;
889 if (n>=1)
890 new_name += TQString::number(n);
891 for (it.toFirst(); it.current(); ++it) {
892 if (it.current()->name().lower()==new_name)
893 break;
894 }
895 if ( it.current() ) {
896 n++;
897 continue; //stored exists!
898 }
899 for (itUnstored.toFirst(); itUnstored.current(); ++itUnstored) {
900 if (itUnstored.current()->name().lower()==new_name)
901 break;
902 }
903 if ( !itUnstored.current() )
904 break; //unstored doesn't exist
905 n++;
906 } while (n<1000/*sanity*/);
907
908 if (n>=1000)
909 return 0;
910
911 TQString new_caption( suggestedCaption.isEmpty() ? part->instanceCaption() : suggestedCaption);
912 if (n>=1)
913 new_caption += TQString::number(n);
914
916 item->setIdentifier( --d->tempPartItemID_Counter );//temporary
917 item->setMimeType(info->mimeType());
918 item->setName(new_name);
919 item->setCaption(new_caption);
920 item->setNeverSaved(true);
921 d->unstoredItems.insert(item, item);
922 return item;
923}
924
925KexiPart::Item* KexiProject::createPartItem(KexiPart::Part *part, const TQString& suggestedCaption)
926{
927 return createPartItem(part->info(), suggestedCaption);
928}
929
931{
932 if (!item)
933 return;
934 d->unstoredItems.remove(item);
935}
936
937KexiDB::Parser* KexiProject::sqlParser()
938{
939 if (!d->sqlParser) {
940 if (!d->connection)
941 return 0;
942 d->sqlParser = new KexiDB::Parser(d->connection);
943 }
944 return d->sqlParser;
945}
946
947static const TQString warningNoUndo = i18n("Warning: entire project's data will be removed.");
948
949/*static*/
952 KexiDB::MessageHandler* handler)
953{
954 cancelled = false;
955 KexiProject *prj = new KexiProject( new KexiProjectData(*data), handler );
956
957 tristate res = prj->create(false);
958 if (~res) {
960 if (KMessageBox::Yes != KMessageBox::warningYesNo(0, "<qt>"+i18n(
961 "The project %1 already exists.\n"
962 "Do you want to replace it with a new, blank one?")
963 .arg(prj->data()->infoString())+"\n"+warningNoUndo+"</qt>",
964 TQString(), KGuiItem(i18n("Replace")), KStdGuiItem::cancel() ))
965//todo add serverInfoString() for server-based prj
966 {
967 delete prj;
968 cancelled = true;
969 return 0;
970 }
971 res = prj->create(true/*overwrite*/);
972 }
973 if (res != true) {
974 delete prj;
975 return 0;
976 }
977 kdDebug() << "KexiProject::createBlankProject(): new project created --- " << endl;
978//todo? Kexi::recentProjects().addProjectData( data );
979
980 return prj;
981}
982
983/*static*/
985 KexiDB::MessageHandler* handler, bool dontAsk)
986{
987 if (!dontAsk && KMessageBox::Yes != KMessageBox::warningYesNo(0,
988 i18n("Do you want to drop the project \"%1\"?").arg(data->KexiDB::SchemaData::objectName())+"\n"+warningNoUndo ))
989 return cancelled;
990
991 KexiProject prj( new KexiProjectData(*data), handler );
992 if (!prj.open())
993 return false;
994
995 if (prj.dbConnection()->isReadOnly()) {
996 handler->showErrorMessage(
997 i18n("Could not drop this project. Database connection for this project has been opened as read only."));
998 return false;
999 }
1000
1001 return prj.dbConnection()->dropDatabase();
1002}
1003
1004/*void KexiProject::reloadPartItem( KexiDialogBase* dialog )
1005{
1006 if (!dialog)
1007 return;
1008
1009 KexiPart::Item* item = dialog->partItem();
1010
1011 if (dialog || !d->connection->setQuerySchemaObsolete( queryName ))
1012 return;
1013 KexiPart::Info *partInfo = Kexi::partManager().infoForMimeType("kexi/query");
1014 if (!partInfo)
1015 return; //err?
1016 item(partInfo, queryName);
1017 if (!item)
1018 return; //err?
1019 emit itemSetO
1020
1021}*/
1022
1023#include "kexiproject.moc"
TQString serverInfoString(bool addUser=true) const
A user-friendly string for the server.
Provides database connection, allowing queries and data modification.
Definition connection.h:62
virtual bool isReadOnly() const
bool dropDatabase(const TQString &dbName=TQString())
Drops database with name dbName.
ConnectionData * data() const
Provides database cursor functionality.
Definition cursor.h:67
virtual bool moveNext()
Definition cursor.cpp:292
virtual TQVariant value(uint i)=0
bool eof() const
Definition cursor.cpp:339
bool moveFirst()
Definition cursor.cpp:205
A set of storable database properties.
bool setValue(const TQString &name, const TQVariant &value)
TQVariant value(const TQString &name)
bool setCaption(const TQString &name, const TQString &caption)
Driver * driver(const TQString &name)
Generic database abstraction.
Definition driver.h:67
Connection * createConnection(ConnectionData &conn_data, int options=0)
Definition driver.cpp:178
@ ReadOnlyConnection
set to perform read only connection
Definition driver.h:116
FieldList * subList(const TQString &n1, const TQString &n2=TQString(), const TQString &n3=TQString(), const TQString &n4=TQString(), const TQString &n5=TQString(), const TQString &n6=TQString(), const TQString &n7=TQString(), const TQString &n8=TQString(), const TQString &n9=TQString(), const TQString &n10=TQString(), const TQString &n11=TQString(), const TQString &n12=TQString(), const TQString &n13=TQString(), const TQString &n14=TQString(), const TQString &n15=TQString(), const TQString &n16=TQString(), const TQString &n17=TQString(), const TQString &n18=TQString())
FieldList & addField(Field *field)
Meta-data for a field.
Definition field.h:73
virtual void showErrorMessage(const TQString &title, const TQString &details=TQString())=0
virtual void clearError()
Definition object.cpp:131
virtual void setError(int code=ERR_OTHER, const TQString &msg=TQString())
Definition object.cpp:53
const TQString & errorMsg() const
Definition object.h:42
Parser for SQL statements.
Definition parser.h:113
Helper class for using inside methods for given connection.
const Transaction transaction() const
void setTransaction(const Transaction &trans)
This class encapsulates transaction handle.
Definition transaction.h:60
Base class for child window of Kexi's main application window.
Kexi's main window interface This interface is implemented by KexiMainWindowImpl class.
Information about a Kexi Part (plugin).
int projectPartID() const
TQCString mimeType() const
Part item list with reimplemented compareItems() method.
Information about a single object that can be instantiated using Kexi Part.
bool neverSaved() const
void setNeverSaved(bool set)
Part * partForMimeType(const TQString &mimeTypt)
Info * infoForMimeType(const TQString &mimeType)
void lookup()
queries ktrader and creates a list of available parts
The main class for kexi frontend parts like tables, queries, forms and reports.
Definition kexipart.h:66
KexiDialogBase * openInstance(KexiMainWindow *win, KexiPart::Item &item, int viewMode=Kexi::DataViewMode, TQMap< TQString, TQString > *staticObjectArgs=0)
Definition kexipart.cpp:236
TQString instanceCaption() const
Definition kexipart.cpp:415
virtual bool remove(KexiMainWindow *win, KexiPart::Item &item)
Definition kexipart.cpp:385
virtual tristate rename(KexiMainWindow *win, KexiPart::Item &item, const TQString &newName)
Definition kexipart.cpp:420
TQCString instanceName() const
Definition kexipart.cpp:408
Kexi project core data member.
TQString infoString(bool nobr=true) const
A project's main controller.
Definition kexiproject.h:68
KexiPart::ItemDict * items(KexiPart::Info *i)
tristate openInternal(bool *incompatibleWithKexi)
Used in open() and open(bool&).
bool error() const
KexiDialogBase * openObject(KexiMainWindow *wnd, KexiPart::Item &item, int viewMode=Kexi::DataViewMode, TQMap< TQString, TQString > *staticObjectArgs=0)
bool isConnected()
KexiPart::Part * findPartFor(KexiPart::Item &item)
KexiProjectData * data() const
bool createConnection()
bool removeObject(KexiMainWindow *wnd, KexiPart::Item &item)
KexiPart::Item * itemForMimeType(const TQCString &mimeType, const TQString &name)
KexiPart::Item * item(KexiPart::Info *i, const TQString &name)
KexiPart::ItemDict * itemsForMimeType(const TQCString &mimeType)
static tristate dropProject(KexiProjectData *data, KexiDB::MessageHandler *handler, bool dontAsk=false)
void getSortedItems(KexiPart::ItemList &list, KexiPart::Info *i)
Puts a list of items of a type i in this project into list.
bool createInternalStructures(bool insideTransaction)
bool renameObject(KexiMainWindow *wnd, KexiPart::Item &item, const TQString &newName)
int versionMinor() const
KexiProject(KexiProjectData *pdata, KexiDB::MessageHandler *handler=0)
void addStoredItem(KexiPart::Info *info, KexiPart::Item *item)
tristate open()
void itemRemoved(const KexiPart::Item &item)
instance pointed by item is removed
void deleteUnstoredItem(KexiPart::Item *item)
void newItemStored(KexiPart::Item &item)
New item has been stored.
KexiDB::Connection * dbConnection() const
void getSortedItemsForMimeType(KexiPart::ItemList &list, const TQCString &mimeType)
Puts a sorted list of items of a type mimeType in this project into list.
static KexiProject * createBlankProject(bool &cancelled, KexiProjectData *data, KexiDB::MessageHandler *handler=0)
KexiPart::Item * createPartItem(KexiPart::Info *info, const TQString &suggestedCaption=TQString())
int versionMajor() const
void itemRenamed(const KexiPart::Item &item, const TQCString &oldName)
instance pointed by item is renamed
tristate create(bool forceOverwrite=false)
bool checkWritable()
3-state logical type with three values: true, false and cancelled and convenient operators.
Definition tristate.h:100
High-level database connectivity library with database backend drivers.
KEXIUTILS_EXPORT TQString string2Identifier(const TQString &s)
KEXIUTILS_EXPORT bool isIdentifier(const TQString &s)
KEXICORE_EXPORT KexiPart::Manager & partManager()
shared part manager
Definition kexi.cpp:97
KEXICORE_EXPORT KexiDB::DriverManager & driverManager()
shared driver manager
Definition kexi.cpp:91