00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <qfile.h>
00022 #include <qapplication.h>
00023 #include <qdom.h>
00024
00025 #include <kmimetype.h>
00026 #include <kdebug.h>
00027 #include <klocale.h>
00028
00029 #include <kexiutils/identifier.h>
00030
00031 #include <kexidb/connection.h>
00032 #include <kexidb/cursor.h>
00033 #include <kexidb/driver.h>
00034 #include <kexidb/drivermanager.h>
00035 #include <kexidb/utils.h>
00036 #include <kexidb/parser/parser.h>
00037 #include <kexidb/msghandler.h>
00038 #include <kexidb/dbproperties.h>
00039 #include <kexiutils/utils.h>
00040
00041 #include "kexiproject.h"
00042 #include "kexipartmanager.h"
00043 #include "kexipartitem.h"
00044 #include "kexipartinfo.h"
00045 #include "kexipart.h"
00046 #include "kexidialogbase.h"
00047 #include "kexi.h"
00048 #include "keximainwindow.h"
00049 #include "kexiblobbuffer.h"
00050 #include "kexiguimsghandler.h"
00051
00052 #include <assert.h>
00053
00054 class KexiProject::Private
00055 {
00056 public:
00057 Private()
00058 : data(0)
00059 , itemDictsCache(199)
00060 , unstoredItems(199)
00061 , tempPartItemID_Counter(-1)
00062 , sqlParser(0)
00063 , versionMajor(0)
00064 , versionMinor(0)
00065 , final(false)
00066 {
00067 itemDictsCache.setAutoDelete(true);
00068 unstoredItems.setAutoDelete(true);
00069 }
00070 ~Private() {
00071 delete data;
00072 data=0;
00073 delete sqlParser;
00074 }
00075
00076 QGuardedPtr<KexiDB::Connection> connection;
00077 QGuardedPtr<KexiProjectData> data;
00078
00079 QString error_title;
00080
00082 QIntDict<KexiPart::ItemDict> itemDictsCache;
00083
00084 QPtrDict<KexiPart::Item> unstoredItems;
00085 int tempPartItemID_Counter;
00086
00087 KexiDB::Parser* sqlParser;
00088
00089 int versionMajor;
00090 int versionMinor;
00091 bool final : 1;
00092 };
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 KexiProject::KexiProject(KexiProjectData *pdata, KexiDB::MessageHandler* handler)
00116 : QObject(), Object(handler)
00117 , d(new Private())
00118 {
00119 d->data = pdata;
00121 Kexi::partManager().lookup();
00122 }
00123
00124 KexiProject::KexiProject(KexiProjectData *pdata, KexiDB::MessageHandler* handler,
00125 KexiDB::Connection* conn)
00126 : QObject(), Object(handler)
00127 , d(new Private())
00128 {
00129 d->data = pdata;
00130 if (d->data->connectionData() == d->connection->data())
00131 d->connection = conn;
00132 else
00133 kdWarning() << "KexiProject::KexiProject(): passed connection's data ("
00134 << conn->data()->serverInfoString() << ") is not compatible with project's conn. data ("
00135 << d->data->connectionData()->serverInfoString() << ")" << endl;
00137 Kexi::partManager().lookup();
00138 }
00139
00140 KexiProject::~KexiProject()
00141 {
00142 closeConnection();
00143 delete d;
00144 }
00145
00146 KexiDB::Connection *KexiProject::dbConnection() const
00147 {
00148 return d->connection;
00149 }
00150
00151 KexiProjectData* KexiProject::data() const
00152 {
00153 return d->data;
00154 }
00155
00156 bool KexiProject::final() const
00157 {
00158 return d->final;
00159 }
00160
00161 void KexiProject::setFinal(bool set)
00162 {
00163 d->final = set;
00164 }
00165
00166 int KexiProject::versionMajor() const
00167 {
00168 return d->versionMajor;
00169 }
00170
00171 int KexiProject::versionMinor() const
00172 {
00173 return d->versionMinor;
00174 }
00175
00176 tristate
00177 KexiProject::open(bool &incompatibleWithKexi)
00178 {
00179 return openInternal(&incompatibleWithKexi);
00180 }
00181
00182 tristate
00183 KexiProject::open()
00184 {
00185 return openInternal(0);
00186 }
00187
00188 tristate
00189 KexiProject::openInternal(bool *incompatibleWithKexi)
00190 {
00191 if (incompatibleWithKexi)
00192 *incompatibleWithKexi = false;
00193 kdDebug() << "KexiProject::open(): " << d->data->databaseName() <<" "<< d->data->connectionData()->driverName << endl;
00194 KexiDB::MessageTitle et(this,
00195 i18n("Could not open project \"%1\".").arg(d->data->databaseName()));
00196
00197 if (!createConnection()) {
00198 kdDebug() << "KexiProject::open(): !createConnection()" << endl;
00199 return false;
00200 }
00201 bool cancel = false;
00202 KexiGUIMessageHandler msgHandler;
00203 if (!d->connection->useDatabase(d->data->databaseName(), true, &cancel, &msgHandler))
00204 {
00205 if (cancel) {
00206 return cancelled;
00207 }
00208 kdDebug() << "KexiProject::open(): !d->connection->useDatabase() "
00209 << d->data->databaseName() <<" "<< d->data->connectionData()->driverName << endl;
00210
00211 if (d->connection->errorNum() == ERR_NO_DB_PROPERTY) {
00212
00214 if ( !d->data->connectionData()->driverName.lower().startsWith("sqlite")) {
00215
00216 if (incompatibleWithKexi)
00217 *incompatibleWithKexi = true;
00218 }
00219 else
00220 setError(d->connection);
00221 closeConnection();
00222 return false;
00223 }
00224
00225 setError(d->connection);
00226 closeConnection();
00227 return false;
00228 }
00229
00230 if (!initProject())
00231 return false;
00232
00233 return createInternalStructures(true);
00234 }
00235
00236 tristate
00237 KexiProject::create(bool forceOverwrite)
00238 {
00239 KexiDB::MessageTitle et(this,
00240 i18n("Could not create project \"%1\".").arg(d->data->databaseName()));
00241
00242 if (!createConnection())
00243 return false;
00244 if (!checkWritable())
00245 return false;
00246 if (d->connection->databaseExists( d->data->databaseName() )) {
00247 if (!forceOverwrite)
00248 return cancelled;
00249 if (!d->connection->dropDatabase( d->data->databaseName() )) {
00250 setError(d->connection);
00251 closeConnection();
00252 return false;
00253 }
00254 kdDebug() << "--- DB '" << d->data->databaseName() << "' dropped ---"<< endl;
00255 }
00256 if (!d->connection->createDatabase( d->data->databaseName() )) {
00257 setError(d->connection);
00258 closeConnection();
00259 return false;
00260 }
00261 kdDebug() << "--- DB '" << d->data->databaseName() << "' created ---"<< endl;
00262
00263 if (!d->connection->useDatabase(d->data->databaseName()))
00264 {
00265 kdDebug() << "--- DB '" << d->data->databaseName() << "' USE ERROR ---"<< endl;
00266 setError(d->connection);
00267 closeConnection();
00268 return false;
00269 }
00270 kdDebug() << "--- DB '" << d->data->databaseName() << "' used ---"<< endl;
00271
00272
00273 KexiDB::Transaction trans = d->connection->beginTransaction();
00274 if (trans.isNull())
00275 return false;
00276
00277 if (!createInternalStructures(false))
00278 return false;
00279
00280
00282 KexiDB::DatabaseProperties &props = d->connection->databaseProperties();
00283 if (!props.setValue("kexiproject_major_ver", d->versionMajor)
00284 || !props.setCaption("kexiproject_major_ver", i18n("Project major version"))
00285 || !props.setValue("kexiproject_minor_ver", d->versionMinor)
00286 || !props.setCaption("kexiproject_minor_ver", i18n("Project minor version"))
00287 || !props.setValue("project_caption", d->data->caption())
00288 || !props.setCaption("project_caption", i18n("Project caption"))
00289 || !props.setValue("project_desc", d->data->description())
00290 || !props.setCaption("project_desc", i18n("Project description")) )
00291 return false;
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304 if (trans.active() && !d->connection->commitTransaction(trans))
00305 return false;
00306
00307
00308 return initProject();
00309 }
00310
00311 bool KexiProject::createInternalStructures(bool insideTransaction)
00312 {
00313 KexiDB::TransactionGuard tg;
00314 if (insideTransaction) {
00315 tg.setTransaction( d->connection->beginTransaction() );
00316 if (tg.transaction().isNull())
00317 return false;
00318 }
00319
00320
00321
00322 KexiDB::DatabaseProperties &props = d->connection->databaseProperties();
00323 bool ok;
00324 int storedMajorVersion = props.value("kexiproject_major_ver").toInt(&ok);
00325 if (!ok)
00326 storedMajorVersion = 0;
00327 int storedMinorVersion = props.value("kexiproject_minor_ver").toInt(&ok);
00328 if (!ok)
00329 storedMinorVersion = 1;
00330
00331 bool containsKexi__blobsTable = d->connection->drv_containsTable("kexi__blobs");
00332 int dummy;
00333 bool contains_o_folder_id = containsKexi__blobsTable && true == d->connection->querySingleNumber(
00334 "SELECT COUNT(o_folder_id) FROM kexi__blobs", dummy, 0, false);
00335 bool add_folder_id_column = false;
00336
00338 if (storedMajorVersion<=0) {
00339 d->versionMajor = KEXIPROJECT_VERSION_MAJOR;
00340 d->versionMinor = KEXIPROJECT_VERSION_MINOR;
00341
00342
00343 if (!d->connection->isReadOnly()) {
00344 if (!props.setValue("kexiproject_major_ver", d->versionMajor)
00345 || !props.setCaption("kexiproject_major_ver", i18n("Project major version"))
00346 || !props.setValue("kexiproject_minor_ver", d->versionMinor)
00347 || !props.setCaption("kexiproject_minor_ver", i18n("Project minor version")) ) {
00348 return false;
00349 }
00350 }
00351
00352 if (containsKexi__blobsTable) {
00354 if (!d->connection->isReadOnly()) {
00355 if (!contains_o_folder_id) {
00356 add_folder_id_column = true;
00357 }
00358 }
00359 }
00360 }
00361 if (storedMajorVersion!=d->versionMajor || storedMajorVersion!=d->versionMinor) {
00363 d->versionMajor = storedMajorVersion;
00364 d->versionMinor = storedMinorVersion;
00365 }
00366
00367 KexiDB::InternalTableSchema *t_blobs = new KexiDB::InternalTableSchema("kexi__blobs");
00368 t_blobs->addField( new KexiDB::Field("o_id", KexiDB::Field::Integer,
00369 KexiDB::Field::PrimaryKey | KexiDB::Field::AutoInc, KexiDB::Field::Unsigned) )
00370 .addField( new KexiDB::Field("o_data", KexiDB::Field::BLOB) )
00371 .addField( new KexiDB::Field("o_name", KexiDB::Field::Text ) )
00372 .addField( new KexiDB::Field("o_caption", KexiDB::Field::Text ) )
00373 .addField( new KexiDB::Field("o_mime", KexiDB::Field::Text, KexiDB::Field::NotNull) )
00374 .addField( new KexiDB::Field("o_folder_id",
00375 KexiDB::Field::Integer, 0, KexiDB::Field::Unsigned)
00376
00377
00378 );
00379
00380
00381 if (containsKexi__blobsTable) {
00383 d->connection->insertInternalTableSchema(t_blobs);
00384 if (add_folder_id_column && !d->connection->isReadOnly()) {
00385
00386
00387 KexiDB::TableSchema *kexi__blobsCopy = new KexiDB::TableSchema( *t_blobs );
00388 kexi__blobsCopy->setName("kexi__blobs__copy");
00389 if (!d->connection->drv_createTable( *kexi__blobsCopy )) {
00390 delete kexi__blobsCopy;
00391 delete t_blobs;
00392 return false;
00393 }
00394
00395 if (!d->connection->executeSQL(
00396 QString::fromLatin1("INSERT INTO kexi__blobs (o_data, o_name, o_caption, o_mime, o_folder_id) "
00397 "SELECT o_data, o_name, o_caption, o_mime, 0 FROM kexi__blobs") )
00398
00399 || !d->connection->executeSQL(QString::fromLatin1("DROP TABLE kexi__blobs"))
00400
00401 || !d->connection->drv_alterTableName(*kexi__blobsCopy, "kexi__blobs")
00402 )
00403 {
00404
00405 delete kexi__blobsCopy;
00406 delete t_blobs;
00407 return false;
00408 }
00409 delete kexi__blobsCopy;
00410 }
00411 }
00412 else {
00413
00414 if (!d->connection->isReadOnly()) {
00415 if (!d->connection->createTable( t_blobs, true )) {
00416 delete t_blobs;
00417 return false;
00418 }
00419 }
00420 }
00421
00422
00423
00424 KexiDB::InternalTableSchema *t_parts = new KexiDB::InternalTableSchema("kexi__parts");
00425 t_parts->addField(
00426 new KexiDB::Field("p_id", KexiDB::Field::Integer, KexiDB::Field::PrimaryKey | KexiDB::Field::AutoInc, KexiDB::Field::Unsigned)
00427 )
00428 .addField( new KexiDB::Field("p_name", KexiDB::Field::Text) )
00429 .addField( new KexiDB::Field("p_mime", KexiDB::Field::Text ) )
00430 .addField( new KexiDB::Field("p_url", KexiDB::Field::Text ) );
00431
00432 bool containsKexi__partsTable = d->connection->drv_containsTable("kexi__parts");
00433 bool partsTableOk = true;
00434 if (containsKexi__partsTable) {
00436 d->connection->insertInternalTableSchema(t_parts);
00437 }
00438 else {
00439 if (!d->connection->isReadOnly()) {
00440 partsTableOk = d->connection->createTable( t_parts, true );
00441
00442 KexiDB::FieldList *fl = t_parts->subList("p_id", "p_name", "p_mime", "p_url");
00443 if (partsTableOk)
00444 partsTableOk = d->connection->insertRecord(*fl, QVariant(1), QVariant("Tables"),
00445 QVariant("kexi/table"), QVariant("http://koffice.org/kexi/"));
00446
00447 if (partsTableOk)
00448 partsTableOk = d->connection->insertRecord(*fl, QVariant(2), QVariant("Queries"),
00449 QVariant("kexi/query"), QVariant("http://koffice.org/kexi/"));
00450 }
00451 }
00452
00453 if (!partsTableOk) {
00454 delete t_parts;
00455 return false;
00456 }
00457
00458 if (insideTransaction) {
00459 if (tg.transaction().active() && !tg.commit())
00460 return false;
00461 }
00462 return true;
00463 }
00464
00465 bool
00466 KexiProject::createConnection()
00467 {
00468 if (d->connection)
00469 return true;
00470
00471 clearError();
00472
00473 KexiDB::MessageTitle et(this);
00474
00475 KexiDB::Driver *driver = Kexi::driverManager().driver(d->data->connectionData()->driverName);
00476 if(!driver) {
00477 setError(&Kexi::driverManager());
00478 return false;
00479 }
00480
00481 int connectionOptions = 0;
00482 if (d->data->isReadOnly())
00483 connectionOptions |= KexiDB::Driver::ReadOnlyConnection;
00484 d->connection = driver->createConnection(*d->data->connectionData(), connectionOptions);
00485 if (!d->connection)
00486 {
00487 kdDebug() << "KexiProject::open(): uuups failed " << driver->errorMsg() << endl;
00488 setError(driver);
00489 return false;
00490 }
00491
00492 if (!d->connection->connect())
00493 {
00494 setError(d->connection);
00495 kdDebug() << "KexiProject::createConnection(): error connecting: " << (d->connection ? d->connection->errorMsg() : QString::null) << endl;
00496 closeConnection();
00497 return false;
00498 }
00499
00500
00502 KexiBLOBBuffer::setConnection(d->connection);
00503 return true;
00504 }
00505
00506
00507 bool
00508 KexiProject::closeConnection()
00509 {
00510 if (!d->connection)
00511 return true;
00512
00513 if (!d->connection->disconnect()) {
00514 setError(d->connection);
00515 return false;
00516 }
00517
00518 delete d->connection;
00519 d->connection = 0;
00520 return true;
00521 }
00522
00523 bool
00524 KexiProject::initProject()
00525 {
00526
00527 kdDebug() << "KexiProject::open(): checking project parts..." << endl;
00528
00529 if (!Kexi::partManager().checkProject(d->connection)) {
00530 setError(Kexi::partManager().error() ? (KexiDB::Object*)&Kexi::partManager() : (KexiDB::Connection*)d->connection);
00531 return false;
00532 }
00533
00534
00535 KexiDB::DatabaseProperties &props = d->connection->databaseProperties();
00536 QString str( props.value("project_caption").toString() );
00537 if (!str.isEmpty())
00538 d->data->setCaption( str );
00539 str = props.value("project_desc").toString();
00540 if (!str.isEmpty())
00541 d->data->setDescription( str );
00542
00543
00544
00545
00546
00547
00548
00549 return true;
00550 }
00551
00552 bool
00553 KexiProject::isConnected()
00554 {
00555 if(d->connection && d->connection->isDatabaseUsed())
00556 return true;
00557
00558 return false;
00559 }
00560
00561 KexiPart::ItemDict*
00562 KexiProject::items(KexiPart::Info *i)
00563 {
00564 kdDebug() << "KexiProject::items()" << endl;
00565 if(!i || !isConnected())
00566 return 0;
00567
00568
00569 KexiPart::ItemDict *dict = d->itemDictsCache[ i->projectPartID() ];
00570 if (dict)
00571 return dict;
00572
00573 KexiDB::Cursor *cursor = d->connection->executeQuery(
00574 "SELECT o_id, o_name, o_caption FROM kexi__objects WHERE o_type = "
00575 + QString::number(i->projectPartID()));
00576
00577 if(!cursor)
00578 return 0;
00579
00580 dict = new KexiPart::ItemDict(1009);
00581 dict->setAutoDelete(true);
00582
00583 for(cursor->moveFirst(); !cursor->eof(); cursor->moveNext())
00584 {
00585 KexiPart::Item *it = new KexiPart::Item();
00586 bool ok;
00587 int ident = cursor->value(0).toInt(&ok);
00588 QString objName( cursor->value(1).toString() );
00589
00590 if ( ok && (ident>0) && !d->connection->isInternalTableSchema(objName)
00591 && KexiUtils::isIdentifier(objName) )
00592 {
00593 it->setIdentifier(ident);
00594 it->setMimeType(i->mimeType());
00595 it->setName(objName);
00596 it->setCaption(cursor->value(2).toString());
00597 }
00598 dict->insert(it->identifier(), it);
00599
00600 }
00601
00602 d->connection->deleteCursor(cursor);
00603
00604 d->itemDictsCache.insert( i->projectPartID(), dict );
00605 return dict;
00606 }
00607
00608 KexiPart::ItemDict*
00609 KexiProject::itemsForMimeType(const QCString &mimeType)
00610 {
00611 KexiPart::Info *info = Kexi::partManager().infoForMimeType(mimeType);
00612 return items(info);
00613 }
00614
00615 void
00616 KexiProject::getSortedItems(KexiPart::ItemList& list, KexiPart::Info *i)
00617 {
00618 list.clear();
00619 KexiPart::ItemDict* dict = items(i);
00620 if (!dict)
00621 return;
00622 for (KexiPart::ItemDictIterator it(*dict); it.current(); ++it)
00623 list.append(it.current());
00624 }
00625
00626 void
00627 KexiProject::getSortedItemsForMimeType(KexiPart::ItemList& list, const QCString &mimeType)
00628 {
00629 KexiPart::Info *info = Kexi::partManager().infoForMimeType(mimeType);
00630 getSortedItems(list, info);
00631 }
00632
00633 void
00634 KexiProject::addStoredItem(KexiPart::Info *info, KexiPart::Item *item)
00635 {
00636 if (!info || !item)
00637 return;
00638 KexiPart::ItemDict *dict = items(info);
00639 item->setNeverSaved( false );
00640 d->unstoredItems.take(item);
00641 dict->insert( item->identifier(), item );
00642
00643 emit newItemStored(*item);
00644 }
00645
00646 KexiPart::Item*
00647 KexiProject::itemForMimeType(const QCString &mimeType, const QString &name)
00648 {
00649 KexiPart::ItemDict *dict = itemsForMimeType(mimeType);
00650 if (!dict)
00651 return 0;
00652 const QString l_name = name.lower();
00653 for (KexiPart::ItemDictIterator it( *dict ); it.current(); ++it) {
00654 if (it.current()->name().lower()==l_name)
00655 return it.current();
00656 }
00657 return 0;
00658 }
00659
00660 KexiPart::Item*
00661 KexiProject::item(KexiPart::Info *i, const QString &name)
00662 {
00663 KexiPart::ItemDict *dict = items(i);
00664 if (!dict)
00665 return 0;
00666 const QString l_name = name.lower();
00667 for (KexiPart::ItemDictIterator it( *dict ); it.current(); ++it) {
00668 if (it.current()->name().lower()==l_name)
00669 return it.current();
00670 }
00671 return 0;
00672 }
00673
00674 KexiPart::Item*
00675 KexiProject::item(int identifier)
00676 {
00677 KexiPart::ItemDict *dict;
00678 for (QIntDictIterator<KexiPart::ItemDict> it(d->itemDictsCache); (dict = it.current()); ++it) {
00679 KexiPart::Item *item = dict->find(identifier);
00680 if (item)
00681 return item;
00682 }
00683 return 0;
00684 }
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727 KexiPart::Part *KexiProject::findPartFor(KexiPart::Item& item)
00728 {
00729 clearError();
00730 KexiDB::MessageTitle et(this);
00731 KexiPart::Part *part = Kexi::partManager().partForMimeType(item.mimeType());
00732 if (!part)
00733 setError(&Kexi::partManager());
00734 return part;
00735 }
00736
00737 KexiDialogBase* KexiProject::openObject(KexiMainWindow *wnd, KexiPart::Item& item,
00738 int viewMode, QMap<QString,QString>* staticObjectArgs)
00739 {
00740 clearError();
00741 if (viewMode!=Kexi::DataViewMode && data()->userMode())
00742 return 0;
00743
00744 KexiDB::MessageTitle et(this);
00745 KexiPart::Part *part = findPartFor(item);
00746 if (!part)
00747 return 0;
00748 KexiDialogBase *dlg = part->openInstance(wnd, item, viewMode, staticObjectArgs);
00749 if (!dlg) {
00750 if (part->lastOperationStatus().error())
00751 setError(i18n("Opening object \"%1\" failed.").arg(item.name())+"<br>"
00752 +part->lastOperationStatus().message,
00753 part->lastOperationStatus().description);
00754 return 0;
00755 }
00756 return dlg;
00757 }
00758
00759 KexiDialogBase* KexiProject::openObject(KexiMainWindow *wnd, const QCString &mimeType,
00760 const QString& name, int viewMode)
00761 {
00762 KexiPart::Item *it = itemForMimeType(mimeType, name);
00763 return it ? openObject(wnd, *it, viewMode) : 0;
00764 }
00765
00766 bool KexiProject::checkWritable()
00767 {
00768 if (!d->connection->isReadOnly())
00769 return true;
00770 setError(i18n("This project is opened as read only."));
00771 return false;
00772 }
00773
00774 bool KexiProject::removeObject(KexiMainWindow *wnd, KexiPart::Item& item)
00775 {
00776 clearError();
00777 if (data()->userMode())
00778 return false;
00779
00780 KexiDB::MessageTitle et(this);
00781 if (!checkWritable())
00782 return false;
00783 KexiPart::Part *part = findPartFor(item);
00784 if (!part)
00785 return false;
00786 if (!item.neverSaved() && !part->remove(wnd, item)) {
00787
00788 return false;
00789 }
00790 if (!item.neverSaved()) {
00791 KexiDB::TransactionGuard tg( *d->connection );
00792 if (!tg.transaction().active()) {
00793 setError(d->connection);
00794 return false;
00795 }
00796 if (!d->connection->removeObject( item.identifier() )) {
00797 setError(d->connection);
00798 return false;
00799 }
00800 if (!tg.commit()) {
00801 setError(d->connection);
00802 return false;
00803 }
00804 }
00805 emit itemRemoved(item);
00806
00807
00808 if (part->info()) {
00809 KexiPart::ItemDict *dict = d->itemDictsCache[ part->info()->projectPartID() ];
00810 if (!(dict && dict->remove( item.identifier() )))
00811 d->unstoredItems.remove(&item);
00812 }
00813 return true;
00814 }
00815
00816 bool KexiProject::renameObject( KexiMainWindow *wnd, KexiPart::Item& item, const QString& _newName )
00817 {
00818 clearError();
00819 if (data()->userMode())
00820 return 0;
00821
00822 KexiUtils::WaitCursor wait;
00823 QString newName = _newName.stripWhiteSpace();
00824 {
00825 KexiDB::MessageTitle et(this);
00826 if (newName.isEmpty()) {
00827 setError( i18n("Could not set empty name for this object.") );
00828 return false;
00829 }
00830 if (this->itemForMimeType(item.mimeType(), newName)!=0) {
00831 setError( i18n("Could not use this name. Object with name \"%1\" already exists.")
00832 .arg(newName) );
00833 return false;
00834 }
00835 }
00836
00837 KexiDB::MessageTitle et(this,
00838 i18n("Could not rename object \"%1\".").arg(item.name()) );
00839 if (!checkWritable())
00840 return false;
00841 KexiPart::Part *part = findPartFor(item);
00842 if (!part)
00843 return false;
00844 KexiDB::TransactionGuard tg( *d->connection );
00845 if (!tg.transaction().active()) {
00846 setError(d->connection);
00847 return false;
00848 }
00849 if (!part->rename(wnd, item, newName)) {
00850 setError(part->lastOperationStatus().message, part->lastOperationStatus().description);
00851 return false;
00852 }
00853 if (!d->connection->executeSQL( "update kexi__objects set o_name="
00854 + d->connection->driver()->valueToSQL( KexiDB::Field::Text, newName )
00855 + " where o_id=" + QString::number(item.identifier()) )) {
00856 setError(d->connection);
00857 return false;
00858 }
00859 if (!tg.commit()) {
00860 setError(d->connection);
00861 return false;
00862 }
00863 QCString oldName( item.name().latin1() );
00864 item.setName( newName );
00865 emit itemRenamed(item, oldName);
00866 return true;
00867 }
00868
00869 KexiPart::Item* KexiProject::createPartItem(KexiPart::Info *info, const QString& suggestedCaption)
00870 {
00871 clearError();
00872 if (data()->userMode())
00873 return 0;
00874
00875 KexiDB::MessageTitle et(this);
00876 KexiPart::Part *part = Kexi::partManager().part(info);
00877 if (!part) {
00878 setError(&Kexi::partManager());
00879 return 0;
00880 }
00881
00882 KexiPart::ItemDict *dict = items(info);
00883
00884
00885 int n;
00886 QString new_name;
00887 QString base_name;
00888 if (suggestedCaption.isEmpty()) {
00889 n = 1;
00890 base_name = part->instanceName();
00891 }
00892 else {
00893 n = 0;
00894 base_name = KexiUtils::string2Identifier(suggestedCaption).lower();
00895 }
00896 base_name = KexiUtils::string2Identifier(base_name).lower();
00897 KexiPart::ItemDictIterator it(*dict);
00898 QPtrDictIterator<KexiPart::Item> itUnstored(d->unstoredItems);
00899 do {
00900 new_name = base_name;
00901 if (n>=1)
00902 new_name += QString::number(n);
00903 for (it.toFirst(); it.current(); ++it) {
00904 if (it.current()->name().lower()==new_name)
00905 break;
00906 }
00907 if ( it.current() ) {
00908 n++;
00909 continue;
00910 }
00911 for (itUnstored.toFirst(); itUnstored.current(); ++itUnstored) {
00912 if (itUnstored.current()->name().lower()==new_name)
00913 break;
00914 }
00915 if ( !itUnstored.current() )
00916 break;
00917 n++;
00918 } while (n<1000);
00919
00920 if (n>=1000)
00921 return 0;
00922
00923 QString new_caption( suggestedCaption.isEmpty() ? part->instanceCaption() : suggestedCaption);
00924 if (n>=1)
00925 new_caption += QString::number(n);
00926
00927 KexiPart::Item *item = new KexiPart::Item();
00928 item->setIdentifier( --d->tempPartItemID_Counter );
00929 item->setMimeType(info->mimeType());
00930 item->setName(new_name);
00931 item->setCaption(new_caption);
00932 item->setNeverSaved(true);
00933 d->unstoredItems.insert(item, item);
00934 return item;
00935 }
00936
00937 KexiPart::Item* KexiProject::createPartItem(KexiPart::Part *part, const QString& suggestedCaption)
00938 {
00939 return createPartItem(part->info(), suggestedCaption);
00940 }
00941
00942 void KexiProject::deleteUnstoredItem(KexiPart::Item *item)
00943 {
00944 if (!item)
00945 return;
00946 d->unstoredItems.remove(item);
00947 }
00948
00949 KexiDB::Parser* KexiProject::sqlParser()
00950 {
00951 if (!d->sqlParser) {
00952 if (!d->connection)
00953 return 0;
00954 d->sqlParser = new KexiDB::Parser(d->connection);
00955 }
00956 return d->sqlParser;
00957 }
00958
00959 static const QString warningNoUndo = i18n("Warning: entire project's data will be removed.");
00960
00961
00962 KexiProject*
00963 KexiProject::createBlankProject(bool &cancelled, KexiProjectData* data,
00964 KexiDB::MessageHandler* handler)
00965 {
00966 cancelled = false;
00967 KexiProject *prj = new KexiProject( new KexiProjectData(*data), handler );
00968
00969 tristate res = prj->create(false);
00970 if (~res) {
00972 if (KMessageBox::Yes != KMessageBox::warningYesNo(0, "<qt>"+i18n(
00973 "The project %1 already exists.\n"
00974 "Do you want to replace it with a new, blank one?")
00975 .arg(prj->data()->infoString())+"\n"+warningNoUndo+"</qt>",
00976 QString::null, KGuiItem(i18n("Replace")), KStdGuiItem::cancel() ))
00977
00978 {
00979 delete prj;
00980 cancelled = true;
00981 return 0;
00982 }
00983 res = prj->create(true);
00984 }
00985 if (res != true) {
00986 delete prj;
00987 return 0;
00988 }
00989 kdDebug() << "KexiProject::createBlankProject(): new project created --- " << endl;
00990
00991
00992 return prj;
00993 }
00994
00995
00996 tristate KexiProject::dropProject(KexiProjectData* data,
00997 KexiDB::MessageHandler* handler, bool dontAsk)
00998 {
00999 if (!dontAsk && KMessageBox::Yes != KMessageBox::warningYesNo(0,
01000 i18n("Do you want to drop the project \"%1\"?").arg(data->objectName())+"\n"+warningNoUndo ))
01001 return cancelled;
01002
01003 KexiProject prj( new KexiProjectData(*data), handler );
01004 if (!prj.open())
01005 return false;
01006
01007 if (prj.dbConnection()->isReadOnly()) {
01008 handler->showErrorMessage(
01009 i18n("Could not drop this project. Database connection for this project has been opened as read only."));
01010 return false;
01011 }
01012
01013 return prj.dbConnection()->dropDatabase();
01014 }
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035 #include "kexiproject.moc"