00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kexialtertabledialog.h"
00021
00022 #include <qlayout.h>
00023 #include <qlabel.h>
00024 #include <qsplitter.h>
00025
00026 #include <kiconloader.h>
00027 #include <kdebug.h>
00028 #include <klocale.h>
00029 #include <kaction.h>
00030 #include <kpopupmenu.h>
00031 #include <kmessagebox.h>
00032
00033 #include <koproperty/set.h>
00034 #include <koproperty/property.h>
00035
00036 #include <kexidb/cursor.h>
00037 #include <kexidb/tableschema.h>
00038 #include <kexidb/connection.h>
00039 #include <kexidb/utils.h>
00040 #include <kexidb/roweditbuffer.h>
00041 #include <kexidb/error.h>
00042 #include <kexiutils/identifier.h>
00043 #include <kexiproject.h>
00044 #include <keximainwindow.h>
00045 #include <widget/tableview/kexidataawarepropertyset.h>
00046 #include <widget/kexicustompropertyfactory.h>
00047 #include <kexidialogbase.h>
00048 #include <kexitableview.h>
00049
00050
00051
00053 #define COLUMN_ID_PK 0
00054 #define COLUMN_ID_CAPTION 1
00055 #define COLUMN_ID_TYPE 2
00056 #define COLUMN_ID_DESC 3
00057
00058
00059
00061 #define KEXI_NO_BLOB_FIELDS
00062
00064 class KexiAlterTableDialogPrivate
00065 {
00066 public:
00067 KexiAlterTableDialogPrivate()
00068 : sets(0)
00069 , dontAskOnStoreData(false)
00070 , slotTogglePrimaryKeyCalled(false)
00071 , primaryKeyExists(false)
00072 , slotPropertyChanged_primaryKey_enabled(true)
00073 , slotPropertyChanged_subType_enabled(true)
00074 {
00075 }
00076
00077 ~KexiAlterTableDialogPrivate() {
00078 delete sets;
00079 }
00080
00081 KexiTableView *view;
00082
00083 KexiTableViewData *data;
00084
00085 KexiDataAwarePropertySet *sets;
00086
00087 int row;
00088
00089 KToggleAction *action_toggle_pkey;
00090
00092 int maxTypeNameTextWidth;
00094 bool dontAskOnStoreData : 1;
00095
00096 bool slotTogglePrimaryKeyCalled : 1;
00097
00098 bool primaryKeyExists : 1;
00100 bool slotPropertyChanged_primaryKey_enabled : 1;
00102 bool slotPropertyChanged_subType_enabled : 1;
00103 };
00104
00105
00106
00107 KexiAlterTableDialog::KexiAlterTableDialog(KexiMainWindow *win, QWidget *parent,
00108 const char *name)
00109 : KexiDataTable(win, parent, name, false)
00110 , d( new KexiAlterTableDialogPrivate() )
00111 {
00112
00113 KexiCustomPropertyFactory::init();
00114
00115 KexiDB::Connection *conn = mainWin()->project()->dbConnection();
00116
00117 d->data = new KexiTableViewData();
00118 if (conn->isReadOnly())
00119 d->data->setReadOnly(true);
00120 d->data->setInsertingEnabled( false );
00121
00122 KexiTableViewColumn *col = new KexiTableViewColumn("pk", KexiDB::Field::Text, i18n("Primary Key", "PK"),
00123 i18n("Describes primary key for the field."));
00124 col->field()->setSubType("KIcon");
00125 col->setReadOnly(true);
00126 d->data->addColumn( col );
00127
00128
00129 col = new KexiTableViewColumn("caption", KexiDB::Field::Text, i18n("Field Caption"),
00130 i18n("Describes name for the field."));
00131
00132
00133
00134 d->data->addColumn( col );
00135
00136 col = new KexiTableViewColumn("type", KexiDB::Field::Enum, i18n("Data Type"),
00137 i18n("Describes data type for the field."));
00138 d->data->addColumn( col );
00139
00140 #ifdef KEXI_NO_BLOB_FIELDS
00142 QValueVector<QString> types(KexiDB::Field::LastTypeGroup-1); //don't show last type (BLOB)
00143 #else
00144 QValueVector<QString> types(KexiDB::Field::LastTypeGroup);
00145 #endif
00146 d->maxTypeNameTextWidth = 0;
00147 QFontMetrics fm(font());
00148 for (uint i=1; i<=types.count(); i++) {
00149 types[i-1] = KexiDB::Field::typeGroupName(i);
00150 d->maxTypeNameTextWidth = QMAX(d->maxTypeNameTextWidth, fm.width(types[i-1]));
00151 }
00152 col->field()->setEnumHints(types);
00153
00154 d->data->addColumn( col = new KexiTableViewColumn("comments", KexiDB::Field::Text, i18n("Comments"),
00155 i18n("Describes additional comments for the field.")) );
00156
00157 d->view = dynamic_cast<KexiTableView*>(mainWidget());
00158
00159 d->view->setSpreadSheetMode();
00160
00161
00162 connect(d->data, SIGNAL(aboutToChangeCell(KexiTableItem*,int,QVariant&,KexiDB::ResultInfo*)),
00163 this, SLOT(slotBeforeCellChanged(KexiTableItem*,int,QVariant&,KexiDB::ResultInfo*)));
00164 connect(d->data, SIGNAL(rowUpdated(KexiTableItem*)),
00165 this, SLOT(slotRowUpdated(KexiTableItem*)));
00166 connect(d->data, SIGNAL(aboutToInsertRow(KexiTableItem*,KexiDB::ResultInfo*,bool)),
00167 this, SLOT(slotAboutToInsertRow(KexiTableItem*,KexiDB::ResultInfo*,bool)));
00168 connect(d->data, SIGNAL(aboutToDeleteRow(KexiTableItem&,KexiDB::ResultInfo*,bool)),
00169 this, SLOT(slotAboutToDeleteRow(KexiTableItem&,KexiDB::ResultInfo*,bool)));
00170
00171 setMinimumSize(d->view->minimumSizeHint().width(), d->view->minimumSizeHint().height());
00172 d->view->setFocus();
00173
00174 d->sets = new KexiDataAwarePropertySet( this, d->view );
00175 connect(d->sets, SIGNAL(rowDeleted()), this, SLOT(updateActions()));
00176 connect(d->sets, SIGNAL(rowInserted()), this, SLOT(updateActions()));
00177
00178 plugSharedAction("tablepart_toggle_pkey", this, SLOT(slotTogglePrimaryKey()));
00179 d->action_toggle_pkey = static_cast<KToggleAction*>( sharedAction("tablepart_toggle_pkey") );
00180 d->action_toggle_pkey->plug(d->view->contextMenu(), 0);
00181 setAvailable("tablepart_toggle_pkey", !conn->isReadOnly());
00182 }
00183
00184 KexiAlterTableDialog::~KexiAlterTableDialog()
00185 {
00186
00187 delete d;
00188 }
00189
00190 void KexiAlterTableDialog::initData()
00191 {
00192
00193
00194 d->data->deleteAllRows();
00195 int tableFieldCount = 0;
00196 d->primaryKeyExists = false;
00197
00198 if (tempData()->table) {
00199 tableFieldCount = tempData()->table->fieldCount();
00200
00201
00202
00203 for(int i=0; i < tableFieldCount; i++) {
00204 KexiDB::Field *field = tempData()->table->field(i);
00205 KexiTableItem *item = d->data->createItem();
00206 (*item)[0] = field->isPrimaryKey() ? "key" : "";
00207 if (field->isPrimaryKey())
00208 d->primaryKeyExists = true;
00209 (*item)[1] = field->captionOrName();
00210 (*item)[2] = field->typeGroup()-1;
00211 (*item)[3] = field->description();
00212 d->data->append(item);
00213
00214
00215 }
00216 }
00217
00218
00219
00220
00221
00222
00223 for (int i=tableFieldCount; i<(int)d->sets->size(); i++) {
00224
00225 d->data->append(d->data->createItem());
00226 }
00227
00228
00229 d->view->setData(d->data);
00230
00231
00232 if (tempData()->table) {
00233 for(int i=0; i < tableFieldCount; i++) {
00234 KexiDB::Field *field = tempData()->table->field(i);
00235 createPropertySet( i, field );
00236 }
00237 }
00238
00239
00240 d->view->setColumnWidth(COLUMN_ID_PK, IconSize( KIcon::Small ) + 10);
00241 d->view->adjustColumnWidthToContents(COLUMN_ID_CAPTION);
00242 d->view->setColumnWidth(COLUMN_ID_TYPE, d->maxTypeNameTextWidth + 2 * d->view->rowHeight());
00243 d->view->setColumnStretchEnabled( true, COLUMN_ID_DESC );
00244
00245 setDirty(false);
00246 d->view->setCursorPosition(0, COLUMN_ID_CAPTION);
00247 }
00248
00249 static bool updatePropertiesVisibility(KexiDB::Field::Type fieldType, KoProperty::Set &set)
00250 {
00251 bool changed = false;
00252 KoProperty::Property *prop;
00253 bool visible;
00254
00255 prop = &set["subType"];
00256 const bool isObjectTypeGroup = set["type"].value().toInt() == (int)KexiDB::Field::BLOB;
00257 kdDebug() << prop->value().toInt() << set["type"].value().toInt()<< endl;
00258
00259
00260 visible = (prop->listData() && prop->listData()->keys.count() > 1 || isObjectTypeGroup)
00261 && set["primaryKey"].value().toBool()==false;
00262 if (prop->isVisible()!=visible) {
00263 prop->setVisible( visible );
00264 changed = true;
00265 }
00266 prop = &set["unsigned"];
00267 visible = KexiDB::Field::isNumericType(fieldType);
00268 if (prop->isVisible()!=visible) {
00269 prop->setVisible( visible );
00270 changed = true;
00271 }
00272 prop = &set["length"];
00273 visible = (fieldType == KexiDB::Field::Text);
00274 if (prop->isVisible()!=visible) {
00275 prop->setVisible( visible );
00276 prop->setValue( visible ? KexiDB::Field::defaultTextLength() : 0, false );
00277 changed = true;
00278 }
00279 #ifndef KEXI_NO_UNFINISHED
00280 prop = &set["precision"];
00281 visible = KexiDB::Field::isFPNumericType(fieldType);
00282 if (prop->isVisible()!=visible) {
00283 prop->setVisible( visible );
00284 changed = true;
00285 }
00286 #endif
00287 prop = &set["unique"];
00288 visible = fieldType != KexiDB::Field::BLOB;
00289 if (prop->isVisible()!=visible) {
00290 prop->setVisible( visible );
00291 changed = true;
00292 }
00293 prop = &set["indexed"];
00294 visible = fieldType != KexiDB::Field::BLOB;
00295 if (prop->isVisible()!=visible) {
00296 prop->setVisible( visible );
00297 changed = true;
00298 }
00299 prop = &set["allowEmpty"];
00300 visible = KexiDB::Field::hasEmptyProperty(fieldType);
00301 if (prop->isVisible()!=visible) {
00302 prop->setVisible( visible );
00303 changed = true;
00304 }
00305 prop = &set["autoIncrement"];
00306 visible = KexiDB::Field::isAutoIncrementAllowed(fieldType);
00307 if (prop->isVisible()!=visible) {
00308 prop->setVisible( visible );
00309 changed = true;
00310 }
00311 return changed;
00312 }
00313
00315 void
00316 KexiAlterTableDialog::getSubTypeListData(KexiDB::Field::TypeGroup fieldTypeGroup,
00317 QStringList& stringsList, QStringList& namesList)
00318 {
00319 if (fieldTypeGroup==KexiDB::Field::BLOBGroup) {
00320
00322 stringsList << "image";
00323 namesList << i18n("Image object type", "Image");
00324 }
00325 else {
00326 stringsList = KexiDB::typeStringsForGroup(fieldTypeGroup);
00327 namesList = KexiDB::typeNamesForGroup(fieldTypeGroup);
00328 }
00329 kdDebug() << "KexiAlterTableDialog::getSubTypeListData(): subType strings: " <<
00330 stringsList.join("|") << "\nnames: " << namesList.join("|") << endl;
00331 }
00332
00333 KoProperty::Set *
00334 KexiAlterTableDialog::createPropertySet( int row, KexiDB::Field *field, bool newOne )
00335 {
00336 QString typeName = "KexiDB::Field::" + field->typeGroupString();
00337 KoProperty::Set *set = new KoProperty::Set(d->sets, typeName);
00338 if (mainWin()->project()->dbConnection()->isReadOnly())
00339 set->setReadOnly( true );
00340
00341
00342
00343 KoProperty::Property *prop;
00344
00345
00346 set->addProperty(prop = new KoProperty::Property("this:classString", i18n("Table field")) );
00347 prop->setVisible(false);
00349
00350
00351
00352 set->addProperty(prop
00353 = new KoProperty::Property("name", QVariant(field->name()), i18n("Name"),
00354 QString::null, KexiCustomPropertyFactory::Identifier) );
00355
00356
00357 set->addProperty( prop
00358 = new KoProperty::Property("type", QVariant(field->type()), i18n("Type")) );
00359 #ifndef KexiAlterTableDialog_DEBUG
00360 prop->setVisible(false);
00361 #endif
00362
00363
00364 QStringList slist, nlist;
00365 getSubTypeListData(field->typeGroup(), slist, nlist);
00366 QString subTypeValue;
00367 if (field->typeGroup()==KexiDB::Field::BLOBGroup) {
00368
00370 subTypeValue = slist.first();
00371 }
00372 else {
00373 subTypeValue = field->typeString();
00374 }
00375 set->addProperty(prop
00376 = new KoProperty::Property("subType", slist, nlist, subTypeValue, i18n("Subtype")));
00377
00378 set->addProperty( prop
00379 = new KoProperty::Property("caption", QVariant(field->caption()), i18n("Caption") ) );
00380 prop->setVisible(false);
00381
00382 set->addProperty( prop
00383 = new KoProperty::Property("description", QVariant(field->description())) );
00384 prop->setVisible(false);
00385
00386 set->addProperty(prop
00387 = new KoProperty::Property("unsigned", QVariant(field->isUnsigned(), 4), i18n("Unsigned Number")));
00388
00389 set->addProperty( prop
00390 = new KoProperty::Property("length", (int)field->length(), i18n("Length")));
00391
00392 set->addProperty( prop
00393 = new KoProperty::Property("precision", (int)field->precision(), i18n("Precision")));
00394 #ifdef KEXI_NO_UNFINISHED
00395 prop->setVisible(false);
00396 #endif
00397
00399 set->addProperty( prop
00400 = new KoProperty::Property("width", (int)field->width(), i18n("Column Width")));
00401 #ifdef KEXI_NO_UNFINISHED
00402 prop->setVisible(false);
00403 #endif
00404
00405 set->addProperty( prop
00406 = new KoProperty::Property("defaultValue", field->defaultValue(), i18n("Default Value")));
00408 prop->setVisible(false);
00409
00410 set->addProperty(prop
00411 = new KoProperty::Property("primaryKey", QVariant(field->isPrimaryKey(), 4), i18n("Primary Key")));
00412 prop->setIcon("key");
00413
00414 set->addProperty(
00415 new KoProperty::Property("unique", QVariant(field->isUniqueKey(), 4), i18n("Unique")));
00416
00417 set->addProperty(
00418 new KoProperty::Property("notNull", QVariant(field->isNotNull(), 4), i18n("Required")));
00419
00420 set->addProperty(
00421 new KoProperty::Property("allowEmpty", QVariant(!field->isNotEmpty(), 4), i18n("Allow Zero\nSize")));
00422
00423 set->addProperty(prop
00424 = new KoProperty::Property("autoIncrement", QVariant(field->isAutoIncrement(), 4), i18n("Autonumber")));
00425 prop->setIcon("autonumber");
00426
00427 set->addProperty(
00428 new KoProperty::Property("indexed", QVariant(field->isIndexed(), 4), i18n("Indexed")));
00429
00430 updatePropertiesVisibility(field->type(), *set);
00431
00432 connect(set, SIGNAL(propertyChanged(KoProperty::Set&, KoProperty::Property&)),
00433 this, SLOT(slotPropertyChanged(KoProperty::Set&, KoProperty::Property&)));
00434
00435 d->sets->insert(row, set, newOne);
00436 return set;
00437 }
00438
00439 void KexiAlterTableDialog::updateActions(bool activated)
00440 {
00441 Q_UNUSED(activated);
00443 setAvailable("tablepart_toggle_pkey", propertySet()!=0 && !mainWin()->project()->dbConnection()->isReadOnly());
00444 if (!propertySet())
00445 return;
00446 KoProperty::Set &set = *propertySet();
00447 d->slotTogglePrimaryKeyCalled = true;
00448 d->action_toggle_pkey->setChecked(set["primaryKey"].value().toBool());
00449 d->slotTogglePrimaryKeyCalled = false;
00450 }
00451
00452 void KexiAlterTableDialog::slotUpdateRowActions(int row)
00453 {
00454 KexiDataTable::slotUpdateRowActions(row);
00455 updateActions();
00456 }
00457
00458 void KexiAlterTableDialog::slotTogglePrimaryKey()
00459 {
00460 if (d->slotTogglePrimaryKeyCalled)
00461 return;
00462 d->slotTogglePrimaryKeyCalled = true;
00463 if (!propertySet())
00464 return;
00465 KoProperty::Set &set = *propertySet();
00466 bool isSet = !set["primaryKey"].value().toBool();
00467 setPrimaryKey(set, isSet);
00468 d->slotTogglePrimaryKeyCalled = false;
00469 }
00470
00471 void KexiAlterTableDialog::setPrimaryKey(KoProperty::Set &propertySet, bool set, bool aWasPKey)
00472 {
00473 const bool was_pkey = aWasPKey || propertySet["primaryKey"].value().toBool();
00474 propertySet["primaryKey"] = QVariant(set, 1);
00475 if (&propertySet==this->propertySet()) {
00476
00477 d->action_toggle_pkey->setChecked(set);
00478 if (d->view->selectedItem()) {
00479
00480 d->view->data()->clearRowEditBuffer();
00481 d->view->data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_PK,
00482 QVariant(set ? "key" : ""));
00483 d->view->data()->saveRowChanges(*d->view->selectedItem(), true);
00484 }
00485 if (was_pkey || set)
00486 d->primaryKeyExists = set;
00487 }
00488
00489 if (set) {
00490
00491 KoProperty::Set *s = 0;
00492 int i;
00493 const int count = (int)d->sets->size();
00494 for (i=0; i<count; i++) {
00495 s = d->sets->at(i);
00496 if (s && s!=&propertySet && (*s)["primaryKey"].value().toBool() && i!=d->view->currentRow())
00497 break;
00498 }
00499 if (i<count) {
00500 (*s)["autoIncrement"] = QVariant(false, 0);
00501 (*s)["primaryKey"] = QVariant(false, 0);
00502
00503 d->view->data()->clearRowEditBuffer();
00504 KexiTableItem *item = d->view->itemAt(i);
00505 if (item) {
00506 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_PK, QVariant());
00507 d->view->data()->saveRowChanges(*item, true);
00508 }
00509 }
00510
00511
00512 d->view->data()->clearRowEditBuffer();
00513 d->view->data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_TYPE,
00514 QVariant(KexiDB::Field::IntegerGroup-1));
00515
00516 d->view->data()->saveRowChanges(*d->view->selectedItem(), true);
00517
00518
00519 propertySet["subType"] = KexiDB::Field::typeString(KexiDB::Field::BigInteger);
00520 propertySet["unsigned"] = QVariant(true,4);
00521 }
00522 updateActions();
00523 }
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534 QString KexiAlterTableDialog::messageForSavingChanges(bool &emptyTable)
00535 {
00536 KexiDB::Connection *conn = mainWin()->project()->dbConnection();
00537 bool ok;
00538 emptyTable = conn->isEmpty( *tempData()->table, ok ) && ok;
00539 return i18n("Do you want to save the design now?")
00540 + ( emptyTable ? QString::null :
00541 (QString("\n\n") + part()->i18nMessage(":additional message before saving design", parentDialog())) );
00542
00543 }
00544
00545 tristate KexiAlterTableDialog::beforeSwitchTo(int mode, bool &dontStore)
00546 {
00547 if (!d->view->acceptRowEdit())
00548 return false;
00549
00550
00551
00552
00553
00554 tristate res = true;
00555 if (mode==Kexi::DataViewMode) {
00556 if (!dirty() && parentDialog()->neverSaved()) {
00557 KMessageBox::sorry(this, i18n("Cannot switch to data view, because table design is empty.\n"
00558 "First, please create your design.") );
00559 return cancelled;
00560 }
00561
00562 else if (dirty() && !parentDialog()->neverSaved()) {
00563
00564
00565
00566 bool emptyTable;
00567 int r = KMessageBox::warningYesNoCancel(this,
00568 i18n("Saving changes for existing table design is now required.")
00569 +"\n"+messageForSavingChanges(emptyTable), QString::null,
00570 KStdGuiItem::save(), KStdGuiItem::discard(), QString::null,
00571 KMessageBox::Notify|KMessageBox::Dangerous);
00572 if (r == KMessageBox::Cancel)
00573 res = cancelled;
00574 else
00575 res = true;
00576 dontStore = (r!=KMessageBox::Yes);
00577 if (!dontStore)
00578 d->dontAskOnStoreData = true;
00579
00580
00581 }
00582
00583
00584 return res;
00585 }
00586 else if (mode==Kexi::TextViewMode) {
00587
00588 }
00589 return res;
00590 }
00591
00592 tristate KexiAlterTableDialog::afterSwitchFrom(int mode)
00593 {
00594 if (mode==Kexi::NoViewMode || mode==Kexi::DataViewMode) {
00595 initData();
00596 }
00597 return true;
00598 }
00599
00600 KoProperty::Set *KexiAlterTableDialog::propertySet()
00601 {
00602 return d->sets ? d->sets->currentPropertySet() : 0;
00603 }
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621 void KexiAlterTableDialog::slotBeforeCellChanged(
00622 KexiTableItem *item, int colnum, QVariant& newValue, KexiDB::ResultInfo* )
00623 {
00624
00625
00626 if (colnum==COLUMN_ID_CAPTION) {
00627
00628
00629 if (item->at(COLUMN_ID_TYPE).isNull()) {
00630
00631 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_TYPE, QVariant((int)0));
00632 }
00633
00634 if (propertySet()) {
00635 KoProperty::Set &set = *propertySet();
00636
00637 set["caption"] = newValue;
00638 set["name"] = newValue;
00639
00640 }
00641 }
00642 else if (colnum==COLUMN_ID_TYPE) {
00643 if (newValue.isNull()) {
00644
00645 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_PK, QVariant());
00646 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_CAPTION, QVariant(QString::null));
00647 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_DESC, QVariant());
00648 return;
00649 }
00650
00651 if (!propertySet())
00652 return;
00653
00654 KoProperty::Set &set = *propertySet();
00655
00656
00657 KexiDB::Field::TypeGroup fieldTypeGroup;
00658 int i_fieldTypeGroup = newValue.toInt()+1;
00659 if (i_fieldTypeGroup < 1 || i_fieldTypeGroup >
00660 #ifdef KEXI_NO_BLOB_FIELDS
00662 (int)KexiDB::Field::LastTypeGroup-1)
00663 #else
00664 (int)KexiDB::Field::LastTypeGroup)
00665 #endif
00666 return;
00667 fieldTypeGroup = static_cast<KexiDB::Field::TypeGroup>(i_fieldTypeGroup);
00668
00669
00670 KexiDB::Field::Type fieldType = KexiDB::defaultTypeForGroup( fieldTypeGroup );
00671 if (fieldType==KexiDB::Field::InvalidType)
00672 fieldType = KexiDB::Field::Text;
00673 set["type"] = (int)fieldType;
00674
00675
00676
00677 QStringList slist, nlist;
00678 getSubTypeListData(fieldTypeGroup, slist, nlist);
00679
00680 QString subTypeValue;
00681 if (fieldType==KexiDB::Field::BLOB) {
00682
00683 subTypeValue = slist.first();
00684 }
00685 else {
00686 subTypeValue = KexiDB::Field::typeString(fieldType);
00687 }
00688 KoProperty::Property *subTypeProperty = &set["subType"];
00689 kdDebug() << "++++++++++" << slist << nlist << endl;
00690
00691
00692 const bool forcePropertySetReload = set["type"].value().toInt() != (int)fieldTypeGroup;
00693 const bool useListData = slist.count() > 1 || fieldType==KexiDB::Field::BLOB;
00694 if (useListData) {
00695 subTypeProperty->setListData( slist, nlist );
00696 }
00697 else {
00698 subTypeProperty->setListData( 0 );
00699 }
00700 if (set["primaryKey"].value().toBool()==true) {
00701
00702 if (fieldTypeGroup != KexiDB::Field::IntegerGroup) {
00703 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_PK, QVariant());
00704 set["primaryKey"] = QVariant(false, 1);
00706 }
00707 }
00708
00709 subTypeProperty->setValue( subTypeValue, false );
00710 if (updatePropertiesVisibility(fieldType, set) || forcePropertySetReload) {
00711
00712 propertySetReloaded(true);
00713 }
00714 }
00715 else if (colnum==COLUMN_ID_DESC) {
00716 if (!propertySet())
00717 return;
00718
00719
00720 KoProperty::Set &set = *propertySet();
00721 set["description"] = newValue;
00722 }
00723 }
00724
00725 void KexiAlterTableDialog::slotRowUpdated(KexiTableItem *item)
00726 {
00727 const int row = d->view->data()->findRef(item);
00728 if (row < 0)
00729 return;
00730
00731 setDirty();
00732
00733
00734
00735 QString fieldCaption( item->at(COLUMN_ID_CAPTION).toString() );
00736 const bool prop_set_allowed = !item->at(COLUMN_ID_TYPE).isNull();
00737
00738 if (!prop_set_allowed && propertySet()) {
00739
00740 d->sets->remove( row );
00741
00742
00743 d->view->data()->clearRowEditBuffer();
00744 d->view->data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_TYPE, QVariant());
00745 d->view->data()->saveRowChanges(*d->view->selectedItem());
00746
00747 } else if (prop_set_allowed && !propertySet()) {
00748
00749 KexiDB::Field::TypeGroup fieldTypeGroup = static_cast<KexiDB::Field::TypeGroup>(
00750 item->at(COLUMN_ID_TYPE).toInt()+1 );
00751 int fieldType = KexiDB::defaultTypeForGroup( fieldTypeGroup );
00752 if (fieldType==0)
00753 return;
00754
00755 QString description( item->at(COLUMN_ID_DESC).toString() );
00756
00757
00758 QString fieldName( KexiUtils::string2Identifier(fieldCaption) );
00759
00760 KexiDB::Field field(
00761 fieldName,
00762 (KexiDB::Field::Type)fieldType,
00763 KexiDB::Field::NoConstraints,
00764 KexiDB::Field::NoOptions,
00765 0,
00766 0,
00767 QVariant(),
00768 fieldCaption,
00769 description,
00770 0);
00771
00772
00773 kexipluginsdbg << "KexiAlterTableDialog::slotRowUpdated(): " << field.debugString() << endl;
00774
00775
00776 createPropertySet( row, &field, true );
00777
00778
00779
00780
00781
00782
00783
00784
00785 propertySetSwitched();
00786 }
00787 }
00788
00789 void KexiAlterTableDialog::updateActions()
00790 {
00791 updateActions(false);
00792 }
00793
00794 void KexiAlterTableDialog::slotPropertyChanged(KoProperty::Set& set, KoProperty::Property& property)
00795 {
00796 const QCString pname = property.name();
00797 kexipluginsdbg << "KexiAlterTableDialog::slotPropertyChanged(): " << pname << " = " << property.value() << endl;
00798 if (pname=="primaryKey" && d->slotPropertyChanged_primaryKey_enabled) {
00799 d->slotPropertyChanged_primaryKey_enabled = false;
00800 if (property.value().toBool()) {
00801
00802 set["unique"] = QVariant(true,1);
00803 set["notNull"] = QVariant(true,1);
00804 set["allowEmpty"] = QVariant(false,1);
00805 set["indexed"] = QVariant(true,1);
00807 set["autoIncrement"] = QVariant(true,1);
00808 }
00809 else {
00810 set["autoIncrement"] = QVariant(false,1);
00811 }
00812 setPrimaryKey(set, property.value().toBool(), true);
00813 updatePropertiesVisibility(
00814 KexiDB::Field::typeForString( set["subType"].value().toString() ), set);
00815
00816 propertySetReloaded(true);
00817 d->slotPropertyChanged_primaryKey_enabled = true;
00818 }
00819
00820 else if (property.value().toBool()==false
00821 && (pname=="indexed" || pname=="unique" || pname=="notNull"))
00822 {
00823
00824 setPrimaryKey(set, false);
00825 if (pname=="notNull")
00826 set["allowEmpty"] = QVariant(true,1);
00827 }
00828 else if (pname=="subType" && d->slotPropertyChanged_subType_enabled) {
00829 d->slotPropertyChanged_subType_enabled = false;
00830 if (set["primaryKey"].value().toBool()==true && property.value().toString()!=KexiDB::Field::typeString(KexiDB::Field::BigInteger)) {
00831 kdDebug() << "INVALID " << property.value().toString() << endl;
00832
00833
00834
00835
00836 }
00837
00838
00839 if (KexiDB::Field::typeGroup( set["type"].value().toInt() ) == (int)KexiDB::Field::TextGroup) {
00840 updatePropertiesVisibility(KexiDB::Field::typeForString(property.value().toString()), set);
00841
00842 propertySetReloaded(true);
00843 }
00844 d->slotPropertyChanged_subType_enabled = true;
00845 }
00846 else {
00847 if (property.value().toBool()==true && pname=="autoIncrement") {
00848 if (set["primaryKey"].value().toBool()==false) {
00849 QString msg = QString("<p>")
00850 +i18n("Setting autonumber requires primary key to be set for current field.")+"</p>";
00851 if (d->primaryKeyExists)
00852 msg += (QString("<p>")+ i18n("Previous primary key will be removed.")+"</p>");
00853 msg += (QString("<p>")
00854 +i18n("Do you want to create primary key for current field? "
00855 "Click \"Cancel\" to cancel setting autonumber.")+"</p>");
00856
00857 if (KMessageBox::Yes == KMessageBox::questionYesNo(this, msg,
00858 i18n("Setting autonumber field"),
00859 KGuiItem(i18n("Create &Primary Key"), "key"), KStdGuiItem::cancel() ))
00860 {
00861 setPrimaryKey(set, true);
00862 }
00863 else {
00864 set["autoIncrement"].setValue( QVariant(false,1), false);
00865 }
00866 }
00867 }
00868 }
00869 }
00870
00871 void KexiAlterTableDialog::slotAboutToInsertRow(KexiTableItem* ,
00872 KexiDB::ResultInfo* , bool )
00873 {
00874 setDirty();
00875
00876 }
00877
00878 void KexiAlterTableDialog::slotAboutToDeleteRow(
00879 KexiTableItem& item, KexiDB::ResultInfo* result, bool repaint)
00880 {
00881 Q_UNUSED(result)
00882 Q_UNUSED(repaint)
00883 if (item[COLUMN_ID_PK].toString()=="key")
00884 d->primaryKeyExists = false;
00885 }
00886
00887 tristate KexiAlterTableDialog::buildSchema(KexiDB::TableSchema &schema)
00888 {
00889 if (!d->view->acceptRowEdit())
00890 return cancelled;
00891
00892 tristate res = true;
00893
00894 if (!d->primaryKeyExists) {
00895 const int questionRes = KMessageBox::questionYesNoCancel(this,
00896 i18n("<p>Table \"%1\" has no <b>primary key</b> defined.</p>"
00897 "<p>Although a primary key is not required, it is needed "
00898 "for creating relations between database tables. "
00899 "Do you want to add primary key automatically now?</p>"
00900 "<p>If you want to add a primary key by hand, press \"Cancel\" "
00901 "to cancel saving table design.</p>").arg(schema.name()),
00902 QString::null, KGuiItem(i18n("&Add Primary Key"), "key"), KStdGuiItem::no(),
00903 "autogeneratePrimaryKeysOnTableDesignSaving");
00904 if (questionRes==KMessageBox::Cancel) {
00905 return cancelled;
00906 }
00907 else if (questionRes==KMessageBox::Yes) {
00908
00909 int i=0;
00910 int idIndex = 1;
00911 QString pkFieldName("id%1");
00912 QString pkFieldCaption(i18n("Identifier%1", "Id%1"));
00913 while (i<(int)d->sets->size()) {
00914 KoProperty::Set *set = d->sets->at(i);
00915 if (set) {
00916 if ((*set)["name"].value().toString()
00917 == pkFieldName.arg(idIndex==1?QString::null : QString::number(idIndex))
00918 || (*set)["caption"].value().toString()
00919 == pkFieldCaption.arg(idIndex==1?QString::null : QString::number(idIndex)))
00920 {
00921
00922 i = 0;
00923 idIndex++;
00924 continue;
00925 }
00926 }
00927 i++;
00928 }
00929 pkFieldName = pkFieldName.arg(idIndex==1?QString::null : QString::number(idIndex));
00930 pkFieldCaption = pkFieldCaption.arg(idIndex==1?QString::null : QString::number(idIndex));
00931
00932 d->view->insertEmptyRow(0);
00933 d->view->setCursorPosition(0, COLUMN_ID_CAPTION);
00934 d->view->data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_CAPTION,
00935 QVariant(pkFieldCaption));
00936 d->view->data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_TYPE,
00937 QVariant(KexiDB::Field::IntegerGroup-1));
00938 if (!d->view->data()->saveRowChanges(*d->view->selectedItem(), true)) {
00939 return cancelled;
00940 }
00941 slotTogglePrimaryKey();
00942 }
00943 }
00944
00945
00946 KoProperty::Set *b = 0;
00947 bool no_fields = true;
00948 int i;
00949 QDict<char> names(101, false);
00950 char dummy;
00951 for (i=0;i<(int)d->sets->size();i++) {
00952 b = d->sets->at(i);
00953 if (b) {
00954 no_fields = false;
00955 const QString name = (*b)["name"].value().toString();
00956 if (name.isEmpty()) {
00957 d->view->setCursorPosition(i, COLUMN_ID_CAPTION);
00958 d->view->startEditCurrentCell();
00959 KMessageBox::information(this, i18n("You should enter field caption.") );
00960 res = cancelled;
00961 break;
00962 }
00963 if (names[name]) {
00964 break;
00965 }
00966 names.insert( name, &dummy );
00967 }
00968 }
00969 if (res && no_fields) {
00970 KMessageBox::sorry(this,
00971 i18n("You have added no fields.\nEvery table should have at least one field.") );
00972 res = cancelled;
00973 }
00974 if (res && b && i<(int)d->sets->size()) {
00975 d->view->setCursorPosition(i, COLUMN_ID_CAPTION);
00976 d->view->startEditCurrentCell();
00978 KMessageBox::sorry(this,
00979 i18n("You have added \"%1\" field name twice.\nField names cannot be repeated. "
00980 "Correct name of the field.")
00981 .arg((*b)["name"].value().toString()) );
00982 res = cancelled;
00983 }
00984 if (res) {
00985
00986 for (i=0;i<(int)d->sets->size();i++) {
00987 KoProperty::Set *s = d->sets->at(i);
00988 if (!s)
00989 continue;
00990 KoProperty::Set &set = *s;
00991
00992 kexipluginsdbg << set["subType"].value().toString() << endl;
00993
00994 QString subTypeString( set["subType"].value().toString() );
00995
00997
00998
00999
01000
01001
01002 KexiDB::Field::Type type = KexiDB::Field::typeForString(subTypeString);
01003
01004 if (type <= (int)KexiDB::Field::InvalidType || type > (int)KexiDB::Field::LastType) {
01005 type = KexiDB::Field::Text;
01006 kexipluginswarn << "KexiAlterTableDialog::buildSchema(): invalid type " << type
01007 << ", moving back to Text type" << endl;
01008 }
01009
01010
01011
01012 uint constraints = 0;
01013 uint options = 0;
01014 if (set["primaryKey"].value().toBool())
01015 constraints |= KexiDB::Field::PrimaryKey;
01016 if (set["autoIncrement"].value().toBool() && KexiDB::Field::isAutoIncrementAllowed(type))
01017 constraints |= KexiDB::Field::AutoInc;
01018 if (set["unique"].value().toBool())
01019 constraints |= KexiDB::Field::Unique;
01020 if (set["notnull"].value().toBool())
01021 constraints |= KexiDB::Field::NotNull;
01022 if (!set["allowEmpty"].value().toBool())
01023 constraints |= KexiDB::Field::NotEmpty;
01024
01025 if (set["unsigned"].value().toBool())
01026 options |= KexiDB::Field::Unsigned;
01027
01028
01029
01030
01031
01032 KexiDB::Field *f = new KexiDB::Field(
01033 set["name"].value().toString(),
01034 type,
01035 constraints,
01036 options,
01037 set["length"].value().toInt(),
01038 set["precision"].value().toInt(),
01039 set["defaultValue"].value(),
01040 set["caption"].value().toString(),
01041 set["description"].value().toString(),
01042 set["width"].value().toInt()
01043 );
01044 schema.addField(f);
01045 }
01046 }
01047 return res;
01048 }
01049
01050 KexiDB::SchemaData* KexiAlterTableDialog::storeNewData(const KexiDB::SchemaData& sdata, bool &cancel)
01051 {
01052 if (tempData()->table || m_dialog->schemaData())
01053 return 0;
01054
01055
01056 tempData()->table = new KexiDB::TableSchema(sdata.name());
01057 tempData()->table->setName( sdata.name() );
01058 tempData()->table->setCaption( sdata.caption() );
01059 tempData()->table->setDescription( sdata.description() );
01060
01061 tristate res = buildSchema(*tempData()->table);
01062 cancel = ~res;
01063
01064
01065 if (res) {
01066
01067 KexiDB::Connection *conn = mainWin()->project()->dbConnection();
01068 res = conn->createTable(tempData()->table);
01069 if (res!=true)
01070 parentDialog()->setStatus(conn, "");
01071 }
01072
01073 if (res) {
01074
01075 tempData()->tableSchemaChangedInPreviousView = true;
01076
01077
01078 }
01079 else {
01080 delete tempData()->table;
01081 tempData()->table = 0;
01082 }
01083 return tempData()->table;
01084 }
01085
01086 tristate KexiAlterTableDialog::storeData(bool dontAsk)
01087 {
01088 if (!tempData()->table || !m_dialog->schemaData())
01089 return 0;
01090
01091 tristate res = true;
01092 if (!d->dontAskOnStoreData && !dontAsk) {
01093 bool emptyTable;
01094 const QString msg = messageForSavingChanges(emptyTable);
01095 if (!emptyTable) {
01096 if (KMessageBox::No == KMessageBox::questionYesNo(this, msg))
01097 res = cancelled;
01098 }
01099 }
01100 d->dontAskOnStoreData = false;
01101 if (~res)
01102 return res;
01103
01104
01105
01106 KexiDB::TableSchema *newTable = new KexiDB::TableSchema();
01107
01108 static_cast<KexiDB::SchemaData&>(*newTable) = static_cast<KexiDB::SchemaData&>(*tempData()->table);
01109 res = buildSchema(*newTable);
01110
01111
01112 kexipluginsdbg << "KexiAlterTableDialog::storeData() : BUILD SCHEMA:" << endl;
01113 newTable->debug();
01114
01115 KexiDB::Connection *conn = mainWin()->project()->dbConnection();
01116 if (res) {
01117 res = KexiTablePart::askForClosingObjectsUsingTableSchema(
01118 this, *conn, *tempData()->table,
01119 i18n("You are about to change the design of table \"%1\" "
01120 "but following objects using this table are opened:")
01121 .arg(tempData()->table->name()));
01122 }
01123 if (res) {
01124 res = conn->alterTable(*tempData()->table, *newTable);
01125 if (!res)
01126 parentDialog()->setStatus(conn, "");
01127 }
01128 if (res) {
01129
01130 tempData()->table = newTable;
01131 tempData()->tableSchemaChangedInPreviousView = true;
01132 }
01133 else {
01134 delete newTable;
01135 }
01136 return res;
01137 }
01138
01139 KexiTablePart::TempData* KexiAlterTableDialog::tempData() const
01140 {
01141 return static_cast<KexiTablePart::TempData*>(parentDialog()->tempData());
01142 }
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163 #include "kexialtertabledialog.moc"
01164