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