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