00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kexitabledesignerview.h"
00021 #include "kexitabledesignerview_p.h"
00022 #include "kexilookupcolumnpage.h"
00023 #include "kexitabledesignercommands.h"
00024
00025 #include <qlayout.h>
00026 #include <qlabel.h>
00027 #include <qsplitter.h>
00028
00029 #include <kiconloader.h>
00030 #include <kdebug.h>
00031 #include <klocale.h>
00032 #include <kaction.h>
00033 #include <kpopupmenu.h>
00034 #include <kmessagebox.h>
00035 #include <kiconeffect.h>
00036
00037 #include <koproperty/set.h>
00038 #include <koproperty/utils.h>
00039
00040 #include <kexidb/cursor.h>
00041 #include <kexidb/tableschema.h>
00042 #include <kexidb/connection.h>
00043 #include <kexidb/utils.h>
00044 #include <kexidb/roweditbuffer.h>
00045 #include <kexidb/error.h>
00046 #include <kexidb/lookupfieldschema.h>
00047 #include <kexiutils/identifier.h>
00048 #include <kexiproject.h>
00049 #include <keximainwindow.h>
00050 #include <widget/tableview/kexidataawarepropertyset.h>
00051 #include <widget/kexicustompropertyfactory.h>
00052 #include <kexiutils/utils.h>
00053 #include <kexidialogbase.h>
00054 #include <kexitableview.h>
00055
00056
00057
00059 #define DEFAULT_OBJECT_TYPE_VALUE "image"
00060
00061
00062
00064
00065
00066 using namespace KexiTableDesignerCommands;
00067
00069 static bool isIntegerQVariant(QVariant::Type t)
00070 {
00071 return t==QVariant::LongLong
00072 || t==QVariant::ULongLong
00073 || t==QVariant::Int
00074 || t==QVariant::UInt;
00075 }
00076
00078 static bool canCastQVariant(QVariant::Type fromType, QVariant::Type toType)
00079 {
00080 return (fromType==QVariant::Int && toType==QVariant::UInt)
00081 || (fromType==QVariant::CString && toType==QVariant::String)
00082 || (fromType==QVariant::LongLong && toType==QVariant::ULongLong)
00083 || ((fromType==QVariant::String || fromType==QVariant::CString)
00084 && (isIntegerQVariant(toType) || toType==QVariant::Double));
00085 }
00086
00091 static QVariant tryCastQVariant( const QVariant& fromVal, QVariant::Type toType )
00092 {
00093 const QVariant::Type fromType = fromVal.type();
00094 if (fromType == toType)
00095 return fromVal;
00096 if (canCastQVariant(fromType, toType) || canCastQVariant(toType, fromType)
00097 || (isIntegerQVariant(fromType) && toType==QVariant::Double))
00098 {
00099 QVariant res( fromVal );
00100 if (res.cast(toType))
00101 return res;
00102 }
00103 return QVariant();
00104 }
00105
00106
00107 KexiTableDesignerView::KexiTableDesignerView(KexiMainWindow *win, QWidget *parent)
00108 : KexiDataTable(win, parent, "KexiTableDesignerView", false)
00109 , KexiTableDesignerInterface()
00110 , d( new KexiTableDesignerViewPrivate(this) )
00111 {
00112
00113 KexiCustomPropertyFactory::init();
00114
00115 KexiDB::Connection *conn = mainWin()->project()->dbConnection();
00116 d->view = dynamic_cast<KexiTableView*>(mainWidget());
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, QString::null,
00124 i18n("Additional information about the field"));
00125 col->setIcon( KexiUtils::colorizeIconToTextColor( SmallIcon("info"), d->view->palette() ) );
00126 col->setHeaderTextVisible(false);
00127 col->field()->setSubType("KIcon");
00128 col->setReadOnly(true);
00129 d->data->addColumn( col );
00130
00131
00132 col = new KexiTableViewColumn("caption", KexiDB::Field::Text, i18n("Field Caption"),
00133 i18n("Describes caption for the field"));
00134
00135
00136
00137 d->data->addColumn( col );
00138
00139 col = new KexiTableViewColumn("type", KexiDB::Field::Enum, i18n("Data Type"),
00140 i18n("Describes data type for the field"));
00141 d->data->addColumn( col );
00142
00143 #ifdef KEXI_NO_BLOB_FIELDS
00145 QValueVector<QString> types(KexiDB::Field::LastTypeGroup-1); //don't show last type (BLOB)
00146 #else
00147 QValueVector<QString> types(KexiDB::Field::LastTypeGroup);
00148 #endif
00149 d->maxTypeNameTextWidth = 0;
00150 QFontMetrics fm(font());
00151 for (uint i=1; i<=types.count(); i++) {
00152 types[i-1] = KexiDB::Field::typeGroupName(i);
00153 d->maxTypeNameTextWidth = QMAX(d->maxTypeNameTextWidth, fm.width(types[i-1]));
00154 }
00155 col->field()->setEnumHints(types);
00156
00157 d->data->addColumn( col = new KexiTableViewColumn("comments", KexiDB::Field::Text, i18n("Comments"),
00158 i18n("Describes additional comments for the field")) );
00159
00160 d->view->setSpreadSheetMode();
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
00167
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(slotRowInserted()));
00177
00178 d->contextMenuTitle = new KPopupTitle(d->view->contextMenu());
00179 d->view->contextMenu()->insertItem(d->contextMenuTitle, -1, 0);
00180 connect(d->view->contextMenu(), SIGNAL(aboutToShow()), this, SLOT(slotAboutToShowContextMenu()));
00181
00182 plugSharedAction("tablepart_toggle_pkey", this, SLOT(slotTogglePrimaryKey()));
00183 d->action_toggle_pkey = static_cast<KToggleAction*>( sharedAction("tablepart_toggle_pkey") );
00184 d->action_toggle_pkey->plug(d->view->contextMenu(), 1);
00185 setAvailable("tablepart_toggle_pkey", !conn->isReadOnly());
00186
00187 #ifndef KEXI_NO_UNDOREDO_ALTERTABLE
00188 plugSharedAction("edit_undo", this, SLOT(slotUndo()));
00189 plugSharedAction("edit_redo", this, SLOT(slotRedo()));
00190 setAvailable("edit_undo", false);
00191 setAvailable("edit_redo", false);
00192 connect(d->history, SIGNAL(commandExecuted(KCommand*)), this, SLOT(slotCommandExecuted(KCommand*)));
00193 #endif
00194
00195 #ifdef KEXI_DEBUG_GUI
00196 KexiUtils::addAlterTableActionDebug(QString::null);
00197 KexiUtils::connectPushButtonActionForDebugWindow(
00198 "simulateAlterTableExecution", this, SLOT(slotSimulateAlterTableExecution()));
00199 KexiUtils::connectPushButtonActionForDebugWindow(
00200 "executeRealAlterTable", this, SLOT(executeRealAlterTable()));
00201 #endif
00202 }
00203
00204 KexiTableDesignerView::~KexiTableDesignerView()
00205 {
00206
00207 delete d;
00208 }
00209
00210 void KexiTableDesignerView::initData()
00211 {
00212
00213
00214 d->data->deleteAllRows();
00215 int tableFieldCount = 0;
00216 d->primaryKeyExists = false;
00217
00218 if (tempData()->table) {
00219 tableFieldCount = tempData()->table->fieldCount();
00220
00221
00222
00223 for(int i=0; i < tableFieldCount; i++) {
00224 KexiDB::Field *field = tempData()->table->field(i);
00225 KexiTableItem *item = d->data->createItem();
00226 if (field->isPrimaryKey()) {
00227 (*item)[COLUMN_ID_ICON] = "key";
00228 d->primaryKeyExists = true;
00229 }
00230 else {
00231 KexiDB::LookupFieldSchema *lookupFieldSchema
00232 = field->table() ? field->table()->lookupFieldSchema(*field) : 0;
00233 if (lookupFieldSchema && lookupFieldSchema->rowSource().type()!=KexiDB::LookupFieldSchema::RowSource::NoType
00234 && !lookupFieldSchema->rowSource().name().isEmpty())
00235 {
00236 (*item)[COLUMN_ID_ICON] = "combo";
00237 }
00238 }
00239 (*item)[COLUMN_ID_CAPTION] = field->captionOrName();
00240 (*item)[COLUMN_ID_TYPE] = field->typeGroup()-1;
00241 (*item)[COLUMN_ID_DESC] = field->description();
00242 d->data->append(item);
00243
00244
00245 }
00246 }
00247
00248
00249
00250
00251
00252
00253 for (int i=tableFieldCount; i<(int)d->sets->size(); i++) {
00254
00255 d->data->append(d->data->createItem());
00256 }
00257
00258
00259 d->view->setData(d->data);
00260
00261
00262 if (tempData()->table) {
00263 for(int i=0; i < tableFieldCount; i++) {
00264 KexiDB::Field *field = tempData()->table->field(i);
00265 createPropertySet( i, *field );
00266 }
00267 }
00268
00269
00270 d->view->setColumnWidth(COLUMN_ID_ICON, IconSize( KIcon::Small ) + 10);
00271 d->view->adjustColumnWidthToContents(COLUMN_ID_CAPTION);
00272 d->view->setColumnWidth(COLUMN_ID_TYPE, d->maxTypeNameTextWidth + 2 * d->view->rowHeight());
00273 d->view->setColumnStretchEnabled( true, COLUMN_ID_DESC );
00274 const int minCaptionColumnWidth = d->view->fontMetrics().width("wwwwwwwwwww");
00275 if (minCaptionColumnWidth > d->view->columnWidth(COLUMN_ID_CAPTION))
00276 d->view->setColumnWidth(COLUMN_ID_CAPTION, minCaptionColumnWidth);
00277
00278 setDirty(false);
00279 d->view->setCursorPosition(0, COLUMN_ID_CAPTION);
00280 propertySetSwitched();
00281 }
00282
00284 void
00285 KexiTableDesignerView::getSubTypeListData(KexiDB::Field::TypeGroup fieldTypeGroup,
00286 QStringList& stringsList, QStringList& namesList)
00287 {
00288
00289
00290
00292
00293
00294
00295
00296 stringsList = KexiDB::typeStringsForGroup(fieldTypeGroup);
00297 namesList = KexiDB::typeNamesForGroup(fieldTypeGroup);
00298
00299 kexipluginsdbg << "KexiTableDesignerView::getSubTypeListData(): subType strings: " <<
00300 stringsList.join("|") << "\nnames: " << namesList.join("|") << endl;
00301 }
00302
00303 KoProperty::Set *
00304 KexiTableDesignerView::createPropertySet( int row, const KexiDB::Field& field, bool newOne )
00305 {
00306 QString typeName = "KexiDB::Field::" + field.typeGroupString();
00307 KoProperty::Set *set = new KoProperty::Set(d->sets, typeName);
00308 if (mainWin()->project()->dbConnection()->isReadOnly())
00309 set->setReadOnly( true );
00310
00311
00312
00313 KoProperty::Property *prop;
00314
00315 set->addProperty(prop = new KoProperty::Property("uid", d->generateUniqueId(), ""));
00316 prop->setVisible(false);
00317
00318
00319 set->addProperty(prop = new KoProperty::Property("this:classString", i18n("Table field")) );
00320 prop->setVisible(false);
00321 set->addProperty(prop = new KoProperty::Property("this:iconName",
00323 "lineedit"
00324 ));
00325 prop->setVisible(false);
00326 set->addProperty(prop = new KoProperty::Property("this:useCaptionAsObjectName",
00327 QVariant(true, 1), QString::null));
00328 prop->setVisible(false);
00329
00330
00331 set->addProperty(prop
00332 = new KoProperty::Property("name", QVariant(field.name()), i18n("Name"),
00333 QString::null, KexiCustomPropertyFactory::Identifier) );
00334
00335
00336 set->addProperty( prop
00337 = new KoProperty::Property("type", QVariant(field.type()), i18n("Type")) );
00338 #ifndef KexiTableDesignerView_DEBUG
00339 prop->setVisible(false);
00340 #endif
00341
00342
00343 QStringList typeStringList, typeNameList;
00344 getSubTypeListData(field.typeGroup(), typeStringList, typeNameList);
00345
00346
00347
00348
00350
00351
00352
00353 QString subTypeValue = field.typeString();
00354
00355 set->addProperty(prop = new KoProperty::Property("subType",
00356 typeStringList, typeNameList, subTypeValue, i18n("Subtype")));
00357
00358
00359 QStringList objectTypeStringList, objectTypeNameList;
00361 objectTypeStringList << "image";
00362 objectTypeNameList << i18n("Image object type", "Image");
00363 QString objectTypeValue( field.customProperty("objectType").toString() );
00364 if (objectTypeValue.isEmpty())
00365 objectTypeValue = DEFAULT_OBJECT_TYPE_VALUE;
00366 set->addProperty(prop = new KoProperty::Property("objectType",
00367 objectTypeStringList, objectTypeNameList, objectTypeValue, i18n("Subtype")));
00368
00369 set->addProperty( prop
00370 = new KoProperty::Property("caption", QVariant(field.caption()), i18n("Caption") ) );
00371 prop->setVisible(false);
00372
00373 set->addProperty( prop
00374 = new KoProperty::Property("description", QVariant(field.description())) );
00375 prop->setVisible(false);
00376
00377 set->addProperty(prop
00378 = new KoProperty::Property("unsigned", QVariant(field.isUnsigned(), 4), i18n("Unsigned Number")));
00379
00380 set->addProperty( prop
00381 = new KoProperty::Property("length", (int)field.length(), i18n("Length")));
00382
00383 set->addProperty( prop
00384 = new KoProperty::Property("precision", (int)field.precision(), i18n("Precision")));
00385 #ifdef KEXI_NO_UNFINISHED
00386 prop->setVisible(false);
00387 #endif
00388 set->addProperty( prop
00389 = new KoProperty::Property("visibleDecimalPlaces", field.visibleDecimalPlaces(), i18n("Visible Decimal Places")));
00390 prop->setOption("min", -1);
00391 prop->setOption("minValueText", i18n("Auto Decimal Places","Auto"));
00392
00394 set->addProperty( prop
00395 = new KoProperty::Property("width", (int)field.width(), i18n("Column Width")));
00396 #ifdef KEXI_NO_UNFINISHED
00397 prop->setVisible(false);
00398 #endif
00399
00400 set->addProperty( prop
00401 = new KoProperty::Property("defaultValue", field.defaultValue(), i18n("Default Value"),
00402 QString::null,
00404 (KoProperty::PropertyType)field.variantType()) );
00405 prop->setOption("3rdState", i18n("None"));
00406
00407
00408 set->addProperty( prop
00409 = new KoProperty::Property("primaryKey", QVariant(field.isPrimaryKey(), 4), i18n("Primary Key")));
00410 prop->setIcon("key");
00411
00412 set->addProperty( prop
00413 = new KoProperty::Property("unique", QVariant(field.isUniqueKey(), 4), i18n("Unique")));
00414
00415 set->addProperty( prop
00416 = new KoProperty::Property("notNull", QVariant(field.isNotNull(), 4), i18n("Required")));
00417
00418 set->addProperty( prop
00419 = new KoProperty::Property("allowEmpty", QVariant(!field.isNotEmpty(), 4), i18n("Allow Zero\nSize")));
00420
00421 set->addProperty( prop
00422 = new KoProperty::Property("autoIncrement", QVariant(field.isAutoIncrement(), 4), i18n("Autonumber")));
00423 prop->setIcon("autonumber");
00424
00425 set->addProperty( prop
00426 = new KoProperty::Property("indexed", QVariant(field.isIndexed(), 4), i18n("Indexed")));
00427
00428
00429 KexiDB::LookupFieldSchema *lookupFieldSchema = field.table() ? field.table()->lookupFieldSchema(field) : 0;
00430 set->addProperty( prop = new KoProperty::Property("rowSource",
00431 lookupFieldSchema ? lookupFieldSchema->rowSource().name() : QString::null, i18n("Row Source")));
00432 prop->setVisible(false);
00433
00434 set->addProperty( prop = new KoProperty::Property("rowSourceType",
00435 lookupFieldSchema ? lookupFieldSchema->rowSource().typeName() : QString::null, i18n("Row Source\nType")));
00436 prop->setVisible(false);
00437
00438 set->addProperty( prop
00439 = new KoProperty::Property("boundColumn",
00440 lookupFieldSchema ? lookupFieldSchema->boundColumn() : -1, i18n("Bound Column")));
00441 prop->setVisible(false);
00442
00446 int visibleColumn = -1;
00447 if (lookupFieldSchema && !lookupFieldSchema->visibleColumns().isEmpty())
00448 visibleColumn = lookupFieldSchema->visibleColumns().first();
00449 set->addProperty( prop
00450 = new KoProperty::Property("visibleColumn", visibleColumn, i18n("Visible Column")));
00451 prop->setVisible(false);
00452
00454
00455
00456 d->updatePropertiesVisibility(field.type(), *set);
00457
00458 connect(set, SIGNAL(propertyChanged(KoProperty::Set&, KoProperty::Property&)),
00459 this, SLOT(slotPropertyChanged(KoProperty::Set&, KoProperty::Property&)));
00460
00461 d->sets->insert(row, set, newOne);
00462 return set;
00463 }
00464
00465 void KexiTableDesignerView::updateActions(bool activated)
00466 {
00467 Q_UNUSED(activated);
00469 setAvailable("tablepart_toggle_pkey", propertySet()!=0 && !mainWin()->project()->dbConnection()->isReadOnly());
00470 if (!propertySet())
00471 return;
00472 KoProperty::Set &set = *propertySet();
00473 d->slotTogglePrimaryKeyCalled = true;
00474 d->action_toggle_pkey->setChecked(set["primaryKey"].value().toBool());
00475 d->slotTogglePrimaryKeyCalled = false;
00476 }
00477
00478 void KexiTableDesignerView::slotUpdateRowActions(int row)
00479 {
00480 KexiDataTable::slotUpdateRowActions(row);
00481 updateActions();
00482 }
00483
00484 void KexiTableDesignerView::slotTogglePrimaryKey()
00485 {
00486 if (d->slotTogglePrimaryKeyCalled)
00487 return;
00488 d->slotTogglePrimaryKeyCalled = true;
00489 if (!propertySet())
00490 return;
00491 KoProperty::Set &set = *propertySet();
00492 bool isSet = !set["primaryKey"].value().toBool();
00493 set.changeProperty("primaryKey", QVariant(isSet,1));
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 d->slotTogglePrimaryKeyCalled = false;
00506 }
00507
00508 void KexiTableDesignerView::switchPrimaryKey(KoProperty::Set &propertySet,
00509 bool set, bool aWasPKey, CommandGroup* commandGroup)
00510 {
00511 const bool was_pkey = aWasPKey || propertySet["primaryKey"].value().toBool();
00512
00513 d->setPropertyValueIfNeeded( propertySet, "primaryKey", QVariant(set,1), commandGroup );
00514 if (&propertySet==this->propertySet()) {
00515
00516 d->action_toggle_pkey->setChecked(set);
00517 if (d->view->selectedItem()) {
00518
00519 d->view->data()->clearRowEditBuffer();
00520 d->view->data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_ICON,
00521 QVariant(set ? "key" : ""));
00522 d->view->data()->saveRowChanges(*d->view->selectedItem(), true);
00523 }
00524 if (was_pkey || set)
00525 d->primaryKeyExists = set;
00526 }
00527
00528 if (set) {
00529
00530 KoProperty::Set *s = 0;
00531 int i;
00532 const int count = (int)d->sets->size();
00533 for (i=0; i<count; i++) {
00534 s = d->sets->at(i);
00535 if (s && s!=&propertySet && (*s)["primaryKey"].value().toBool() && i!=d->view->currentRow())
00536 break;
00537 }
00538 if (i<count) {
00539
00540 d->setPropertyValueIfNeeded( *s, "autoIncrement", QVariant(false,0), commandGroup );
00541
00542 d->setPropertyValueIfNeeded( *s, "primaryKey", QVariant(false,0), commandGroup );
00543
00544 d->view->data()->clearRowEditBuffer();
00545 KexiTableItem *item = d->view->itemAt(i);
00546 if (item) {
00547 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_ICON, QVariant());
00548 d->view->data()->saveRowChanges(*item, true);
00549 }
00550 }
00551
00552
00553 d->slotBeforeCellChanged_enabled = false;
00554 d->view->data()->clearRowEditBuffer();
00555 d->view->data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_TYPE,
00556 QVariant(KexiDB::Field::IntegerGroup-1));
00557
00558 d->view->data()->saveRowChanges(*d->view->selectedItem(), true);
00559
00560 d->setPropertyValueIfNeeded( propertySet, "subType", KexiDB::Field::typeString(KexiDB::Field::BigInteger),
00561 commandGroup );
00562
00563 d->setPropertyValueIfNeeded( propertySet, "unsigned", QVariant(true,4), commandGroup );
00564
00565 d->slotBeforeCellChanged_enabled = true;
00566 }
00567 updateActions();
00568 }
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579 tristate KexiTableDesignerView::beforeSwitchTo(int mode, bool &dontStore)
00580 {
00581 if (!d->view->acceptRowEdit())
00582 return false;
00583
00584
00585
00586
00587
00588 tristate res = true;
00589 if (mode==Kexi::DataViewMode) {
00590 if (!dirty() && parentDialog()->neverSaved()) {
00591 KMessageBox::sorry(this, i18n("Cannot switch to data view, because table design is empty.\n"
00592 "First, please create your design.") );
00593 return cancelled;
00594 }
00595
00596 else if (dirty() && !parentDialog()->neverSaved()) {
00597
00598
00599
00600 bool emptyTable;
00601 int r = KMessageBox::warningYesNoCancel(this,
00602 i18n("Saving changes for existing table design is now required.")
00603 + "\n" + d->messageForSavingChanges(emptyTable), QString::null,
00604 KStdGuiItem::save(), KStdGuiItem::discard(), QString::null,
00605 KMessageBox::Notify|KMessageBox::Dangerous);
00606 if (r == KMessageBox::Cancel)
00607 res = cancelled;
00608 else
00609 res = true;
00610 dontStore = (r!=KMessageBox::Yes);
00611 if (!dontStore)
00612 d->dontAskOnStoreData = true;
00613
00614
00615 }
00616
00617
00618 return res;
00619 }
00620 else if (mode==Kexi::TextViewMode) {
00621
00622 }
00623 return res;
00624 }
00625
00626 tristate KexiTableDesignerView::afterSwitchFrom(int mode)
00627 {
00628 if (mode==Kexi::NoViewMode || mode==Kexi::DataViewMode) {
00629 initData();
00630 }
00631 return true;
00632 }
00633
00634 KoProperty::Set *KexiTableDesignerView::propertySet()
00635 {
00636 return d->sets ? d->sets->currentPropertySet() : 0;
00637 }
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655 void KexiTableDesignerView::slotBeforeCellChanged(
00656 KexiTableItem *item, int colnum, QVariant& newValue, KexiDB::ResultInfo* )
00657 {
00658 if (!d->slotBeforeCellChanged_enabled)
00659 return;
00660
00661
00662 if (colnum==COLUMN_ID_CAPTION) {
00663
00664
00665 if (item->at(COLUMN_ID_TYPE).isNull()) {
00666
00667 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_TYPE, QVariant((int)0));
00668 }
00669
00670 KoProperty::Set *propertySetForItem = d->sets->findPropertySetForItem(*item);
00671 if (propertySetForItem) {
00672 d->addHistoryCommand_in_slotPropertyChanged_enabled = false;
00673 QString oldName( propertySetForItem->property("name").value().toString() );
00674 QString oldCaption( propertySetForItem->property("caption").value().toString() );
00675
00676
00677 ChangeFieldPropertyCommand *changeCaptionCommand
00678 = new ChangeFieldPropertyCommand( this, *propertySetForItem, "caption", oldCaption, newValue);
00679
00680
00681 propertySetForItem->changeProperty("caption", newValue);
00682 propertySetForItem->changeProperty("name", newValue);
00683
00684
00685
00686 CommandGroup *changeCaptionAndNameCommand = new CommandGroup(
00687 i18n("Change \"%1\" field's name to \"%2\" and caption from \"%3\" to \"%4\"")
00688 .arg(oldName).arg(propertySetForItem->property("name").value().toString())
00689 .arg(oldCaption).arg(newValue.toString() ));
00690 changeCaptionAndNameCommand->addCommand( changeCaptionCommand );
00691
00692
00693
00694 changeCaptionAndNameCommand->addCommand(
00695 new ChangeFieldPropertyCommand( this, *propertySetForItem,
00696 "name", oldName, propertySetForItem->property("name").value().toString())
00697 );
00698 addHistoryCommand( changeCaptionAndNameCommand, false );
00699
00700 d->addHistoryCommand_in_slotPropertyChanged_enabled = true;
00701 }
00702 }
00703 else if (colnum==COLUMN_ID_TYPE) {
00704 if (newValue.isNull()) {
00705
00706 d->slotBeforeCellChanged_enabled = false;
00707 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_ICON, QVariant());
00708 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_CAPTION, QVariant(QString::null));
00709 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_DESC, QVariant());
00710 d->slotBeforeCellChanged_enabled = true;
00711 return;
00712 }
00713
00714 KoProperty::Set *propertySetForItem = d->sets->findPropertySetForItem(*item);
00715 if (!propertySetForItem)
00716 return;
00717
00718 KoProperty::Set &set = *propertySetForItem;
00719
00720
00721
00722 KexiDB::Field::TypeGroup fieldTypeGroup;
00723 int i_fieldTypeGroup = newValue.toInt()+1;
00724 if (i_fieldTypeGroup < 1 || i_fieldTypeGroup >
00725 #ifdef KEXI_NO_BLOB_FIELDS
00727 (int)KexiDB::Field::LastTypeGroup-1)
00728 #else
00729 (int)KexiDB::Field::LastTypeGroup)
00730 #endif
00731 return;
00732 fieldTypeGroup = static_cast<KexiDB::Field::TypeGroup>(i_fieldTypeGroup);
00733
00734
00735 KexiDB::Field::Type fieldType = KexiDB::defaultTypeForGroup( fieldTypeGroup );
00736 if (fieldType==KexiDB::Field::InvalidType)
00737 fieldType = KexiDB::Field::Text;
00738
00739
00740
00741
00742 QStringList slist, nlist;
00743 getSubTypeListData(fieldTypeGroup, slist, nlist);
00744
00745 QString subTypeValue;
00746
00747
00748
00749
00750
00751
00752 subTypeValue = KexiDB::Field::typeString(fieldType);
00753
00754 KoProperty::Property *subTypeProperty = &set["subType"];
00755 kexipluginsdbg << subTypeProperty->value() << endl;
00756
00757
00758 CommandGroup *changeDataTypeCommand = new CommandGroup(
00759 i18n("Change data type for field \"%1\" to \"%2\"")
00760 .arg(set["name"].value().toString()).arg( KexiDB::Field::typeName( fieldType ) ) );
00761
00762
00763
00764
00765 const bool forcePropertySetReload
00766 = KexiDB::Field::typeGroup( KexiDB::Field::typeForString(subTypeProperty->value().toString()) )
00767 != fieldTypeGroup;
00768
00769 const bool useListData = slist.count() > 1;
00770
00771 if (!useListData) {
00772 slist.clear();
00773 nlist.clear();
00774 }
00775 d->setPropertyValueIfNeeded( set, "type", (int)fieldType, changeDataTypeCommand,
00776 false , true );
00777
00778
00779 if (fieldType == KexiDB::Field::Boolean) {
00781 d->setPropertyValueIfNeeded( set, "notNull", QVariant(true, 1), changeDataTypeCommand,
00782 false , false );
00783 d->setPropertyValueIfNeeded( set, "defaultValue", QVariant(false, 1), changeDataTypeCommand,
00784 false , false );
00785 }
00786
00787
00788
00789
00790
00791
00792
00793
00794 if (set["primaryKey"].value().toBool()==true) {
00795
00796 if (fieldTypeGroup != KexiDB::Field::IntegerGroup) {
00797
00798
00799
00800
00801 d->setPropertyValueIfNeeded( set, "primaryKey", QVariant(false, 1), changeDataTypeCommand );
00803 }
00804 }
00805
00806
00807 d->setPropertyValueIfNeeded( set, "subType", subTypeValue,
00808 changeDataTypeCommand, false, false ,
00809 &slist, &nlist );
00810
00811 if (d->updatePropertiesVisibility(fieldType, set, changeDataTypeCommand) || forcePropertySetReload) {
00812
00813 propertySetReloaded(true);
00814 }
00815
00816 addHistoryCommand( changeDataTypeCommand, false );
00817 }
00818 else if (colnum==COLUMN_ID_DESC) {
00819 KoProperty::Set *propertySetForItem = d->sets->findPropertySetForItem(*item);
00820 if (!propertySetForItem)
00821 return;
00822
00823 QVariant oldValue((*propertySetForItem)["description"].value());
00824 kexipluginsdbg << oldValue << endl;
00825 propertySetForItem->changeProperty("description", newValue);
00826
00827
00828
00829 }
00830 }
00831
00832 void KexiTableDesignerView::slotRowUpdated(KexiTableItem *item)
00833 {
00834 const int row = d->view->data()->findRef(item);
00835 if (row < 0)
00836 return;
00837
00838 setDirty();
00839
00840
00841
00842 QString fieldCaption( item->at(COLUMN_ID_CAPTION).toString() );
00843 const bool prop_set_allowed = !item->at(COLUMN_ID_TYPE).isNull();
00844
00845 if (!prop_set_allowed && d->sets->at(row)) {
00846
00847 d->sets->remove( row );
00848
00849
00850 d->view->data()->clearRowEditBuffer();
00851
00852 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_TYPE, QVariant());
00853 d->view->data()->saveRowChanges(*item);
00854
00855 } else if (prop_set_allowed && !d->sets->at(row)) {
00856
00857 KexiDB::Field::TypeGroup fieldTypeGroup = static_cast<KexiDB::Field::TypeGroup>(
00858 item->at(COLUMN_ID_TYPE).toInt()+1 );
00859 int intFieldType = KexiDB::defaultTypeForGroup( fieldTypeGroup );
00860 if (intFieldType==0)
00861 return;
00862
00863 QString description( item->at(COLUMN_ID_DESC).toString() );
00864
00865
00866 QString fieldName( KexiUtils::string2Identifier(fieldCaption) );
00867
00868 KexiDB::Field::Type fieldType = KexiDB::intToFieldType( intFieldType );
00869 KexiDB::Field field(
00870 fieldName,
00871 fieldType,
00872 KexiDB::Field::NoConstraints,
00873 KexiDB::Field::NoOptions,
00874 0,
00875 0,
00876 QVariant(),
00877 fieldCaption,
00878 description,
00879 0);
00880
00881
00882
00883 if (fieldType == KexiDB::Field::Boolean) {
00884 field.setNotNull( true );
00885 field.setDefaultValue( QVariant(false, 0) );
00886 }
00887
00888 kexipluginsdbg << "KexiTableDesignerView::slotRowUpdated(): " << field.debugString() << endl;
00889
00890
00891 KoProperty::Set *newSet = createPropertySet( row, field, true );
00892
00893
00894
00895
00896
00897
00898
00899
00900 propertySetSwitched();
00901
00902 if (row>=0) {
00903 if (d->addHistoryCommand_in_slotRowUpdated_enabled) {
00904 addHistoryCommand( new InsertFieldCommand( this, row, *newSet ),
00905 false );
00906 }
00907 }
00908 else {
00909 kexipluginswarn << "KexiTableDesignerView::slotRowUpdated() row # not found !" << endl;
00910 }
00911 }
00912 }
00913
00914 void KexiTableDesignerView::updateActions()
00915 {
00916 updateActions(false);
00917 }
00918
00919 void KexiTableDesignerView::slotPropertyChanged(KoProperty::Set& set, KoProperty::Property& property)
00920 {
00921
00922
00923 const QCString pname = property.name();
00924 kexipluginsdbg << "KexiTableDesignerView::slotPropertyChanged(): " << pname << " = " << property.value()
00925 << " (oldvalue = " << property.oldValue() << ")" << endl;
00926
00927
00928 bool changePrimaryKey = false;
00929
00930 bool setPrimaryKey = false;
00931
00932 if (pname=="primaryKey" && d->slotPropertyChanged_primaryKey_enabled) {
00933 changePrimaryKey = true;
00934 setPrimaryKey = property.value().toBool();
00935 }
00936
00937
00938 if (pname=="rowSource" || pname=="rowSourceType") {
00941 const int row = d->sets->findRowForPropertyValue("uid", set["uid"].value().toInt());
00942 KexiTableItem *item = d->view->itemAt(row);
00943 if (item)
00944 d->updateIconForItem(*item, set);
00945 }
00946
00947
00948 CommandGroup *setAutonumberCommand = 0;
00949 CommandGroup *toplevelCommand = 0;
00950 if (pname=="autoIncrement" && property.value().toBool()==true) {
00951 if (set["primaryKey"].value().toBool()==false) {
00952 QString msg = QString("<p>")
00953 +i18n("Setting autonumber requires primary key to be set for current field.")+"</p>";
00954 if (d->primaryKeyExists)
00955 msg += (QString("<p>")+ i18n("Previous primary key will be removed.")+"</p>");
00956 msg += (QString("<p>")
00957 +i18n("Do you want to create primary key for current field? "
00958 "Click \"Cancel\" to cancel setting autonumber.")+"</p>");
00959
00960 if (KMessageBox::Yes == KMessageBox::questionYesNo(this, msg,
00961 i18n("Setting Autonumber Field"),
00962 KGuiItem(i18n("Create &Primary Key"), "key"), KStdGuiItem::cancel() ))
00963 {
00964 changePrimaryKey = true;
00965 setPrimaryKey = true;
00966
00967
00968 setAutonumberCommand = new CommandGroup(
00969 i18n("Assign autonumber for field \"%1\"").arg(set["name"].value().toString()) );
00970 toplevelCommand = setAutonumberCommand;
00971 d->setPropertyValueIfNeeded( set, "autoIncrement", QVariant(true,1), setAutonumberCommand );
00972 }
00973 else {
00974 setAutonumberCommand = new CommandGroup(
00975 i18n("Remove autonumber from field \"%1\"").arg(set["name"].value().toString()) );
00976
00977
00978
00979 d->setPropertyValueIfNeeded( set, "autoIncrement", QVariant(false,1), setAutonumberCommand,
00980 true , false );
00981 addHistoryCommand( setAutonumberCommand, false );
00982 return;
00983 }
00984 }
00985 }
00986
00987
00988 if ((pname=="indexed" || pname=="unique" || pname=="notNull")
00989 && set["primaryKey"].value().toBool() && property.value().toBool()==false)
00990 {
00992 changePrimaryKey = true;
00993 setPrimaryKey = false;
00994
00995 CommandGroup *unsetIndexedOrUniquOrNotNullCommand = new CommandGroup(
00996 i18n("Set \"%1\" property for field \"%2\"").arg(property.caption()).arg(set["name"].value().toString()) );
00997 toplevelCommand = unsetIndexedOrUniquOrNotNullCommand;
00998 d->setPropertyValueIfNeeded( set, pname, QVariant(false,1), unsetIndexedOrUniquOrNotNullCommand );
00999 if (pname=="notNull") {
01000
01001 d->setPropertyValueIfNeeded( set, "unique", QVariant(false,1), unsetIndexedOrUniquOrNotNullCommand );
01002 }
01003 }
01004
01005 if (pname=="defaultValue") {
01006 KexiDB::Field::Type type = KexiDB::intToFieldType( set["type"].value().toInt() );
01007 set["defaultValue"].setType((KoProperty::PropertyType)KexiDB::Field::variantType(type));
01008 }
01009
01010 if (pname=="subType" && d->slotPropertyChanged_subType_enabled) {
01011 d->slotPropertyChanged_subType_enabled = false;
01012 if (set["primaryKey"].value().toBool()==true
01013 && property.value().toString()!=KexiDB::Field::typeString(KexiDB::Field::BigInteger))
01014 {
01015 kexipluginsdbg << "INVALID " << property.value().toString() << endl;
01016
01017
01018
01019
01020 }
01021 KexiDB::Field::Type type = KexiDB::intToFieldType( set["type"].value().toInt() );
01022 QString typeName;
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035 typeName = KexiDB::Field::typeName( KexiDB::Field::typeForString(property.value().toString()) );
01036
01037
01038
01039
01040 CommandGroup* changeFieldTypeCommand = new CommandGroup(
01041 i18n("Change type for field \"%1\" to \"%2\"").arg(set["name"].value().toString())
01042 .arg(typeName) );
01043 d->setPropertyValueIfNeeded( set, "subType", property.value(), property.oldValue(),
01044 changeFieldTypeCommand );
01045
01046 kexipluginsdbg << set["type"].value() << endl;
01047 const KexiDB::Field::Type newType = KexiDB::Field::typeForString(property.value().toString());
01048 set["type"].setValue( newType );
01049
01050
01051 QVariant oldDefVal( set["defaultValue"].value() );
01052 QVariant newDefVal( tryCastQVariant(oldDefVal, KexiDB::Field::variantType(type)) );
01053 if (oldDefVal.type()!=newDefVal.type())
01054 set["defaultValue"].setType( newDefVal.type() );
01055 d->setPropertyValueIfNeeded( set, "defaultValue", newDefVal, newDefVal,
01056 changeFieldTypeCommand );
01057
01058 d->updatePropertiesVisibility(newType, set);
01059
01060 propertySetReloaded(true);
01061 d->slotPropertyChanged_subType_enabled = true;
01062
01063 addHistoryCommand( changeFieldTypeCommand, false );
01064 return;
01065
01066
01067
01068 }
01069
01070 if (d->addHistoryCommand_in_slotPropertyChanged_enabled && !changePrimaryKey) {
01071 addHistoryCommand( new ChangeFieldPropertyCommand(this, set,
01072 property.name(), property.oldValue() , property.value()),
01073 false );
01074 }
01075
01076 if (changePrimaryKey) {
01077 d->slotPropertyChanged_primaryKey_enabled = false;
01078 if (setPrimaryKey) {
01079
01080
01081
01082
01083
01084 CommandGroup *setPrimaryKeyCommand = new CommandGroup(
01085 i18n("Set primary key for field \"%1\"")
01086 .arg(set["name"].value().toString()) );
01087 if (toplevelCommand)
01088 toplevelCommand->addCommand( setPrimaryKeyCommand );
01089 else
01090 toplevelCommand = setPrimaryKeyCommand;
01091
01092 d->setPropertyValueIfNeeded( set, "primaryKey", QVariant(true,1), setPrimaryKeyCommand, true );
01093 d->setPropertyValueIfNeeded( set, "unique", QVariant(true,1), setPrimaryKeyCommand );
01094 d->setPropertyValueIfNeeded( set, "notNull", QVariant(true,1), setPrimaryKeyCommand );
01095 d->setPropertyValueIfNeeded( set, "allowEmpty", QVariant(false,1), setPrimaryKeyCommand );
01096 d->setPropertyValueIfNeeded( set, "indexed", QVariant(true,1), setPrimaryKeyCommand );
01098 d->setPropertyValueIfNeeded( set, "autoIncrement", QVariant(true,1), setPrimaryKeyCommand );
01099
01100
01101
01102
01103
01104
01105
01106
01107 }
01108 else {
01109
01110 CommandGroup *setPrimaryKeyCommand = new CommandGroup(
01111 i18n("Unset primary key for field \"%1\"")
01112 .arg(set["name"].value().toString()) );
01113 if (toplevelCommand)
01114 toplevelCommand->addCommand( setPrimaryKeyCommand );
01115 else
01116 toplevelCommand = setPrimaryKeyCommand;
01117
01118 d->setPropertyValueIfNeeded( set, "primaryKey", QVariant(false,1), setPrimaryKeyCommand, true );
01119 d->setPropertyValueIfNeeded( set, "autoIncrement", QVariant(false,1), setPrimaryKeyCommand );
01120
01121
01122
01123 }
01124 switchPrimaryKey(set, setPrimaryKey, true, toplevelCommand);
01125 d->updatePropertiesVisibility(
01126 KexiDB::Field::typeForString( set["subType"].value().toString() ), set, toplevelCommand);
01127 addHistoryCommand( toplevelCommand, false );
01128
01129 propertySetReloaded(true);
01130 d->slotPropertyChanged_primaryKey_enabled = true;
01131 }
01132 }
01133
01134 void KexiTableDesignerView::slotRowInserted()
01135 {
01136 updateActions();
01137
01138 if (d->addHistoryCommand_in_slotRowInserted_enabled) {
01139 const int row = d->view->currentRow();
01140 if (row>=0) {
01141 addHistoryCommand( new InsertEmptyRowCommand( this, row ), false );
01142 }
01143 }
01144
01145 }
01146
01147 void KexiTableDesignerView::slotAboutToDeleteRow(
01148 KexiTableItem& item, KexiDB::ResultInfo* result, bool repaint)
01149 {
01150 Q_UNUSED(result)
01151 Q_UNUSED(repaint)
01152 if (item[COLUMN_ID_ICON].toString()=="key")
01153 d->primaryKeyExists = false;
01154
01155 if (d->addHistoryCommand_in_slotAboutToDeleteRow_enabled) {
01156 const int row = d->view->data()->findRef(&item);
01157 KoProperty::Set *set = row >=0 ? d->sets->at(row) : 0;
01158
01159 addHistoryCommand(
01160 new RemoveFieldCommand( this, row, set ),
01161 false
01162 );
01163 }
01164 }
01165
01166 KexiDB::Field * KexiTableDesignerView::buildField( const KoProperty::Set &set ) const
01167 {
01168
01169 kexipluginsdbg << set["type"].value() << endl;
01170 QMap<QCString, QVariant> values = KoProperty::propertyValues(set);
01171
01172 QMap<QCString, QVariant>::Iterator it = values.begin();
01173 KexiDB::Field *field = new KexiDB::Field();
01174
01175 while (it!=values.end()) {
01176 const QString propName( it.key() );
01177 if (d->internalPropertyNames.find(propName.latin1()) || propName.startsWith("this:")
01178 || (propName=="objectType" && KexiDB::Field::BLOB != KexiDB::intToFieldType( set["type"].value().toInt() )))
01179 {
01180 QMap<QCString, QVariant>::Iterator it_tmp = it;
01181 ++it;
01182 values.remove(it_tmp);
01183 }
01184 else
01185 ++it;
01186 }
01187
01188
01189 if (!KexiDB::setFieldProperties( *field, values )) {
01190 delete field;
01191 return 0;
01192 }
01193 return field;
01194 }
01195
01196 tristate KexiTableDesignerView::buildSchema(KexiDB::TableSchema &schema, bool beSilent)
01197 {
01198 if (!d->view->acceptRowEdit())
01199 return cancelled;
01200
01201 tristate res = true;
01202
01203 if (!d->primaryKeyExists) {
01204 if (beSilent) {
01205 kexipluginsdbg << "KexiTableDesignerView::buildSchema(): no primay key defined..." << endl;
01206 }
01207 else {
01208 const int questionRes = KMessageBox::questionYesNoCancel(this,
01209 i18n("<p>Table \"%1\" has no <b>primary key</b> defined.</p>"
01210 "<p>Although a primary key is not required, it is needed "
01211 "for creating relations between database tables. "
01212 "Do you want to add primary key automatically now?</p>"
01213 "<p>If you want to add a primary key by hand, press \"Cancel\" "
01214 "to cancel saving table design.</p>").arg(schema.name()),
01215 QString::null, KGuiItem(i18n("&Add Primary Key"), "key"), KStdGuiItem::no(),
01216 "autogeneratePrimaryKeysOnTableDesignSaving");
01217 if (questionRes==KMessageBox::Cancel) {
01218 return cancelled;
01219 }
01220 else if (questionRes==KMessageBox::Yes) {
01221
01222 int i=0;
01223 int idIndex = 1;
01224 QString pkFieldName("id%1");
01225 QString pkFieldCaption(i18n("Identifier%1", "Id%1"));
01226 while (i<(int)d->sets->size()) {
01227 KoProperty::Set *set = d->sets->at(i);
01228 if (set) {
01229 if ((*set)["name"].value().toString()
01230 == pkFieldName.arg(idIndex==1?QString::null : QString::number(idIndex))
01231 || (*set)["caption"].value().toString()
01232 == pkFieldCaption.arg(idIndex==1?QString::null : QString::number(idIndex)))
01233 {
01234
01235 i = 0;
01236 idIndex++;
01237 continue;
01238 }
01239 }
01240 i++;
01241 }
01242 pkFieldName = pkFieldName.arg(idIndex==1?QString::null : QString::number(idIndex));
01243 pkFieldCaption = pkFieldCaption.arg(idIndex==1?QString::null : QString::number(idIndex));
01244
01245 d->view->insertEmptyRow(0);
01246 d->view->setCursorPosition(0, COLUMN_ID_CAPTION);
01247 d->view->data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_CAPTION,
01248 QVariant(pkFieldCaption));
01249 d->view->data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_TYPE,
01250 QVariant(KexiDB::Field::IntegerGroup-1));
01251 if (!d->view->data()->saveRowChanges(*d->view->selectedItem(), true)) {
01252 return cancelled;
01253 }
01254 slotTogglePrimaryKey();
01255 }
01256 }
01257 }
01258
01259
01260 KoProperty::Set *b = 0;
01261 bool no_fields = true;
01262 int i;
01263 QDict<char> names(101, false);
01264 char dummy;
01265 for (i=0;i<(int)d->sets->size();i++) {
01266 b = d->sets->at(i);
01267 if (b) {
01268 no_fields = false;
01269 const QString name = (*b)["name"].value().toString();
01270 if (name.isEmpty()) {
01271 if (beSilent) {
01272 kexipluginswarn <<
01273 QString("KexiTableDesignerView::buildSchema(): no field caption entered at row %1...")
01274 .arg(i+1) << endl;
01275 }
01276 else {
01277 d->view->setCursorPosition(i, COLUMN_ID_CAPTION);
01278 d->view->startEditCurrentCell();
01279 KMessageBox::information(this, i18n("You should enter field caption.") );
01280 }
01281 res = cancelled;
01282 break;
01283 }
01284 if (names[name]) {
01285 break;
01286 }
01287 names.insert( name, &dummy );
01288 }
01289 }
01290 if (res == true && no_fields) {
01291 if (beSilent) {
01292 kexipluginswarn <<
01293 "KexiTableDesignerView::buildSchema(): no field defined..." << endl;
01294 }
01295 else {
01296 KMessageBox::sorry(this,
01297 i18n("You have added no fields.\nEvery table should have at least one field.") );
01298 }
01299 res = cancelled;
01300 }
01301 if (res == true && b && i<(int)d->sets->size()) {
01302 if (beSilent) {
01303 kexipluginswarn <<
01304 QString("KexiTableDesignerView::buildSchema(): duplicated field name '%1'")
01305 .arg((*b)["name"].value().toString()) << endl;
01306 }
01307 else {
01308 d->view->setCursorPosition(i, COLUMN_ID_CAPTION);
01309 d->view->startEditCurrentCell();
01311 KMessageBox::sorry(this,
01312 i18n("You have added \"%1\" field name twice.\nField names cannot be repeated. "
01313 "Correct name of the field.")
01314 .arg((*b)["name"].value().toString()) );
01315 }
01316 res = cancelled;
01317 }
01318 if (res == true) {
01319
01320 for (i=0;i<(int)d->sets->size();i++) {
01321 KoProperty::Set *s = d->sets->at(i);
01322 if (!s)
01323 continue;
01324 KexiDB::Field * f = buildField( *s );
01325 if (!f)
01326 continue;
01327 schema.addField(f);
01328 if (!(*s)["rowSource"].value().toString().isEmpty() && !(*s)["rowSourceType"].value().toString().isEmpty()) {
01329
01330 KexiDB::LookupFieldSchema *lookupFieldSchema = new KexiDB::LookupFieldSchema();
01331 lookupFieldSchema->rowSource().setTypeByName( (*s)["rowSourceType"].value().toString() );
01332 lookupFieldSchema->rowSource().setName( (*s)["rowSource"].value().toString() );
01333 lookupFieldSchema->setBoundColumn( (*s)["boundColumn"].value().toInt() );
01337 QValueList<uint> visibleColumns;
01338 const int visibleColumn = (*s)["visibleColumn"].value().toInt();
01339 if (visibleColumn >= 0)
01340 visibleColumns.append( (uint)visibleColumn );
01341 lookupFieldSchema->setVisibleColumns( visibleColumns );
01343 if (!schema.setLookupFieldSchema(f->name(), lookupFieldSchema)) {
01344 kexipluginswarn <<
01345 "KexiTableDesignerView::buildSchema(): !schema.setLookupFieldSchema()" << endl;
01346 delete lookupFieldSchema;
01347 return false;
01348 }
01349 }
01350 }
01351 }
01352 return res;
01353 }
01354
01357 static void copyAlterTableActions(KCommand* command, KexiDB::AlterTableHandler::ActionList &actions)
01358 {
01359 CommandGroup* cmdGroup = dynamic_cast<CommandGroup*>( command );
01360 if (cmdGroup) {
01361 for (QPtrListIterator<KCommand> it(cmdGroup->commands()); it.current(); ++it)
01362 copyAlterTableActions(it.current(), actions);
01363 return;
01364 }
01365 Command* cmd = dynamic_cast<Command*>( command );
01366 if (!cmd) {
01367 kexipluginswarn << "KexiTableDesignerView::copyAlterTableActions(): cmd is not of type 'Command'!" << endl;
01368 return;
01369 }
01370 KexiDB::AlterTableHandler::ActionBase* action = cmd->createAction();
01371
01372 if (action)
01373 actions.append( action );
01374 }
01375
01376 tristate KexiTableDesignerView::buildAlterTableActions(KexiDB::AlterTableHandler::ActionList &actions)
01377 {
01378 actions.clear();
01379 kexipluginsdbg << "KexiTableDesignerView::buildAlterTableActions(): " << d->history->commands().count()
01380 << " top-level command(s) to process..." << endl;
01381 for (QPtrListIterator<KCommand> it(d->history->commands()); it.current(); ++it) {
01382 copyAlterTableActions(it.current(), actions);
01383 }
01384 return true;
01385 }
01386
01387 KexiDB::SchemaData* KexiTableDesignerView::storeNewData(const KexiDB::SchemaData& sdata, bool &cancel)
01388 {
01389 if (tempData()->table || m_dialog->schemaData())
01390 return 0;
01391
01392
01393 tempData()->table = new KexiDB::TableSchema(sdata.name());
01394 tempData()->table->setName( sdata.name() );
01395 tempData()->table->setCaption( sdata.caption() );
01396 tempData()->table->setDescription( sdata.description() );
01397
01398 tristate res = buildSchema(*tempData()->table);
01399 cancel = ~res;
01400
01401
01402 if (res == true) {
01403
01404 KexiDB::Connection *conn = mainWin()->project()->dbConnection();
01405 res = conn->createTable(tempData()->table);
01406 if (res!=true)
01407 parentDialog()->setStatus(conn, "");
01408 }
01409
01410 if (res == true) {
01411
01412 tempData()->tableSchemaChangedInPreviousView = true;
01413
01414
01415 }
01416 else {
01417 delete tempData()->table;
01418 tempData()->table = 0;
01419 }
01420 return tempData()->table;
01421 }
01422
01423 tristate KexiTableDesignerView::storeData(bool dontAsk)
01424 {
01425 if (!tempData()->table || !m_dialog->schemaData()) {
01426 d->recentResultOfStoreData = false;
01427 return false;
01428 }
01429
01430 KexiDB::Connection *conn = mainWin()->project()->dbConnection();
01431 KexiDB::AlterTableHandler *alterTableHandler = 0;
01432 KexiDB::TableSchema *newTable = 0;
01433
01434
01435 KexiDB::AlterTableHandler::ActionList actions;
01436 tristate res = buildAlterTableActions( actions );
01437 bool realAlterTableCanBeUsed = false;
01438 if (res == true) {
01439 alterTableHandler = new KexiDB::AlterTableHandler( *conn );
01440 alterTableHandler->setActions(actions);
01441
01442 if (!d->tempStoreDataUsingRealAlterTable) {
01443
01444 KexiDB::AlterTableHandler::ExecutionArguments args;
01445 args.onlyComputeRequirements = true;
01446 (void)alterTableHandler->execute(tempData()->table->name(), args);
01447 res = args.result;
01448 if (res == true && 0 == (args.requirements & (0xffff ^ KexiDB::AlterTableHandler::SchemaAlteringRequired)))
01449 realAlterTableCanBeUsed = true;
01450 }
01451 }
01452
01453 if (res == true) {
01454 res = KexiTablePart::askForClosingObjectsUsingTableSchema(
01455 this, *conn, *tempData()->table,
01456 i18n("You are about to change the design of table \"%1\" "
01457 "but following objects using this table are opened:")
01458 .arg(tempData()->table->name()));
01459 }
01460
01461 if (res == true) {
01462 if (!d->tempStoreDataUsingRealAlterTable && !realAlterTableCanBeUsed) {
01464 delete alterTableHandler;
01465 alterTableHandler = 0;
01466
01467 if (!d->dontAskOnStoreData && !dontAsk) {
01468 bool emptyTable;
01469 const QString msg = d->messageForSavingChanges(emptyTable);
01470 if (!emptyTable) {
01471 if (KMessageBox::No == KMessageBox::questionYesNo(this, msg))
01472 res = cancelled;
01473 }
01474 }
01475 d->dontAskOnStoreData = false;
01476 if (~res) {
01477 d->recentResultOfStoreData = res;
01478 return res;
01479 }
01480
01481 newTable = new KexiDB::TableSchema();
01482
01483 static_cast<KexiDB::SchemaData&>(*newTable) = static_cast<KexiDB::SchemaData&>(*tempData()->table);
01484 res = buildSchema(*newTable);
01485 kexipluginsdbg << "KexiTableDesignerView::storeData() : BUILD SCHEMA:" << endl;
01486 newTable->debug();
01487
01488 res = conn->alterTable(*tempData()->table, *newTable);
01489 if (res != true)
01490 parentDialog()->setStatus(conn, "");
01491 }
01492 else {
01493 KexiDB::AlterTableHandler::ExecutionArguments args;
01494 newTable = alterTableHandler->execute(tempData()->table->name(), args);
01495 res = args.result;
01496 kexipluginsdbg << "KexiTableDesignerView::storeData() : ALTER TABLE EXECUTE: "
01497 << res.toString() << endl;
01498 if (true != res) {
01499 alterTableHandler->debugError();
01500 parentDialog()->setStatus(alterTableHandler, "");
01501 }
01502 }
01503 }
01504 if (res == true) {
01505
01506 tempData()->table = newTable;
01507 tempData()->tableSchemaChangedInPreviousView = true;
01508 }
01509 else {
01510 delete newTable;
01511 }
01512 delete alterTableHandler;
01513 d->recentResultOfStoreData = res;
01514 return res;
01515 }
01516
01517 tristate KexiTableDesignerView::simulateAlterTableExecution(QString *debugTarget)
01518 {
01519 #ifndef KEXI_NO_UNDOREDO_ALTERTABLE
01520 # ifdef KEXI_DEBUG_GUI
01521 if (mainWin()->activeWindow() != parentDialog())
01522 return false;
01523 if (!tempData()->table || !m_dialog->schemaData())
01524 return false;
01525 KexiDB::Connection *conn = mainWin()->project()->dbConnection();
01526 KexiDB::AlterTableHandler::ActionList actions;
01527 tristate res = buildAlterTableActions( actions );
01528
01529 KexiDB::AlterTableHandler alterTableHandler( *conn );
01530 alterTableHandler.setActions(actions);
01531 KexiDB::AlterTableHandler::ExecutionArguments args;
01532 if (debugTarget) {
01533 args.debugString = debugTarget;
01534 }
01535 else {
01536 args.simulate = true;
01537 }
01538 (void)alterTableHandler.execute(tempData()->table->name(), args);
01539 return args.result;
01540 # else
01541 return false;
01542 # endif
01543 #else
01544 return false;
01545 #endif
01546 }
01547
01548 void KexiTableDesignerView::slotSimulateAlterTableExecution()
01549 {
01550 (void)simulateAlterTableExecution(0);
01551 }
01552
01553 tristate KexiTableDesignerView::executeRealAlterTable()
01554 {
01555 QSignal signal;
01556 signal.connect( mainWin(), SLOT(slotProjectSave()) );
01557 d->tempStoreDataUsingRealAlterTable = true;
01558 d->recentResultOfStoreData = false;
01559 signal.activate();
01560 d->tempStoreDataUsingRealAlterTable = false;
01561 return d->recentResultOfStoreData;
01562 }
01563
01564 KexiTablePart::TempData* KexiTableDesignerView::tempData() const
01565 {
01566 return static_cast<KexiTablePart::TempData*>(parentDialog()->tempData());
01567 }
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586 #ifdef KEXI_DEBUG_GUI
01587 void KexiTableDesignerView::debugCommand( KCommand* command, int nestingLevel )
01588 {
01589 if (dynamic_cast<Command*>(command))
01590 KexiUtils::addAlterTableActionDebug(dynamic_cast<Command*>(command)->debugString(), nestingLevel);
01591 else
01592 KexiUtils::addAlterTableActionDebug(command->name(), nestingLevel);
01593
01594 if (dynamic_cast<CommandGroup*>(command)) {
01595 for (QPtrListIterator<KCommand> it(dynamic_cast<CommandGroup*>(command)->commands()); it.current(); ++it) {
01596 debugCommand(it.current(), nestingLevel + 1);
01597 }
01598 }
01599 }
01600 #endif
01601
01602 void KexiTableDesignerView::addHistoryCommand( KCommand* command, bool execute )
01603 {
01604 #ifndef KEXI_NO_UNDOREDO_ALTERTABLE
01605 # ifdef KEXI_DEBUG_GUI
01606 debugCommand( command, 0 );
01607 # endif
01608 d->history->addCommand( command, execute );
01609 updateUndoRedoActions();
01610 #endif
01611 }
01612
01613 void KexiTableDesignerView::updateUndoRedoActions()
01614 {
01615 #ifndef KEXI_NO_UNDOREDO_ALTERTABLE
01616 setAvailable("edit_undo", d->historyActionCollection->action("edit_undo")->isEnabled());
01617 setAvailable("edit_redo", d->historyActionCollection->action("edit_redo")->isEnabled());
01618 #endif
01619 }
01620
01621 void KexiTableDesignerView::slotUndo()
01622 {
01623 #ifndef KEXI_NO_UNDOREDO_ALTERTABLE
01624 # ifdef KEXI_DEBUG_GUI
01625 KexiUtils::addAlterTableActionDebug(QString("UNDO:"));
01626 # endif
01627 d->history->undo();
01628 updateUndoRedoActions();
01629 #endif
01630 }
01631
01632 void KexiTableDesignerView::slotRedo()
01633 {
01634 #ifndef KEXI_NO_UNDOREDO_ALTERTABLE
01635 # ifdef KEXI_DEBUG_GUI
01636 KexiUtils::addAlterTableActionDebug(QString("REDO:"));
01637 # endif
01638 d->history->redo();
01639 updateUndoRedoActions();
01640 #endif
01641 }
01642
01643 void KexiTableDesignerView::slotCommandExecuted(KCommand *command)
01644 {
01645 #ifdef KEXI_DEBUG_GUI
01646 debugCommand( command, 1 );
01647 #endif
01648 }
01649
01650 void KexiTableDesignerView::slotAboutToShowContextMenu()
01651 {
01652
01653 if (propertySet()) {
01654 const KoProperty::Set &set = *propertySet();
01655 QString captionOrName(set["caption"].value().toString());
01656 if (captionOrName.isEmpty())
01657 captionOrName = set["name"].value().toString();
01659 d->contextMenuTitle->setTitle( i18n("Table field \"%1\"").arg(captionOrName) );
01660 }
01661 else {
01662 d->contextMenuTitle->setTitle( i18n("Empty table row", "Empty Row") );
01663 }
01664 }
01665
01666 QString KexiTableDesignerView::debugStringForCurrentTableSchema(tristate& result)
01667 {
01668 KexiDB::TableSchema tempTable;
01669
01670 static_cast<KexiDB::SchemaData&>(tempTable) = static_cast<KexiDB::SchemaData&>(*tempData()->table);
01671 result = buildSchema(tempTable, true );
01672 if (true!=result)
01673 return QString::null;
01674 return tempTable.debugString(false );
01675 }
01676
01677
01678
01679 void KexiTableDesignerView::clearRow(int row, bool addCommand)
01680 {
01681 if (!d->view->acceptRowEdit())
01682 return;
01683 KexiTableItem *item = d->view->itemAt(row);
01684 if (!item)
01685 return;
01686
01687 d->sets->remove( row );
01688
01689
01690 if (!addCommand) {
01691 d->addHistoryCommand_in_slotRowUpdated_enabled = false;
01692 d->addHistoryCommand_in_slotPropertyChanged_enabled = false;
01693 d->slotBeforeCellChanged_enabled = false;
01694 }
01695 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_TYPE, QVariant());
01696 if (!addCommand) {
01697 d->addHistoryCommand_in_slotRowUpdated_enabled = true;
01698 d->addHistoryCommand_in_slotPropertyChanged_enabled = true;
01699 d->slotBeforeCellChanged_enabled = true;
01700 }
01701 d->view->data()->saveRowChanges(*item, true);
01702 }
01703
01704 void KexiTableDesignerView::insertField(int row, const QString& caption, bool addCommand)
01705 {
01706 insertFieldInternal(row, 0, caption, addCommand);
01707 }
01708
01709 void KexiTableDesignerView::insertField(int row, KoProperty::Set& set, bool addCommand)
01710 {
01711 insertFieldInternal(row, &set, QString::null, addCommand);
01712 }
01713
01714 void KexiTableDesignerView::insertFieldInternal(int row, KoProperty::Set* set,
01715 const QString& caption, bool addCommand)
01716 {
01717 if (set && (!set->contains("type") || !set->contains("caption"))) {
01718 kexipluginswarn << "KexiTableDesignerView::insertField(): no 'type' or 'caption' property in set!" << endl;
01719 return;
01720 }
01721 if (!d->view->acceptRowEdit())
01722 return;
01723 KexiTableItem *item = d->view->itemAt(row);
01724 if (!item)
01725 return;
01726 if (!addCommand) {
01727 d->addHistoryCommand_in_slotRowUpdated_enabled = false;
01728 d->addHistoryCommand_in_slotPropertyChanged_enabled = false;
01729 d->slotBeforeCellChanged_enabled = false;
01730 }
01731 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_CAPTION,
01732 set ? (*set)["caption"].value() : QVariant(caption));
01733 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_TYPE,
01734 set ? (int)KexiDB::Field::typeGroup( (*set)["type"].value().toInt() )-1
01735 : (((int)KexiDB::Field::TextGroup)-1)
01736 );
01737 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_DESC,
01738 set ? (*set)["description"].value() : QVariant());
01739 if (!addCommand) {
01740 d->slotBeforeCellChanged_enabled = true;
01741 }
01742
01743 d->view->data()->saveRowChanges(*item);
01744 if (set) {
01745 KoProperty::Set *newSet = d->sets->at(row);
01746 if (newSet) {
01747 *newSet = *set;
01748 }
01749 else {
01750 kexipluginswarn << "KexiTableDesignerView::insertField() !newSet, row==" << row << endl;
01751 }
01752 }
01753 if (!addCommand) {
01754 d->addHistoryCommand_in_slotPropertyChanged_enabled = true;
01755 d->addHistoryCommand_in_slotRowUpdated_enabled = true;
01756 }
01757 d->view->updateRow( row );
01758 propertySetReloaded(true);
01759 }
01760
01761 void KexiTableDesignerView::insertEmptyRow( int row, bool addCommand )
01762 {
01763 if (!addCommand) {
01764 d->addHistoryCommand_in_slotRowInserted_enabled = false;
01765 }
01766 d->view->insertEmptyRow( row );
01767 if (!addCommand) {
01768 d->addHistoryCommand_in_slotRowInserted_enabled = true;
01769 }
01770 }
01771
01772
01773
01774
01775
01776
01777
01778
01779 void KexiTableDesignerView::deleteRow( int row, bool addCommand )
01780 {
01781 KexiTableItem *item = d->view->itemAt( row );
01782 if (!item)
01783 return;
01784 if (!addCommand) {
01785 d->addHistoryCommand_in_slotAboutToDeleteRow_enabled = false;
01786 }
01787 const bool res = d->view->deleteItem(item);
01788 if (!addCommand) {
01789 d->addHistoryCommand_in_slotAboutToDeleteRow_enabled = true;
01790 }
01791 if (!res)
01792 return;
01793 }
01794
01795 void KexiTableDesignerView::changeFieldPropertyForRow( int row,
01796 const QCString& propertyName, const QVariant& newValue,
01797 KoProperty::Property::ListData* const listData, bool addCommand )
01798 {
01799 #ifdef KEXI_DEBUG_GUI
01800 KexiUtils::addAlterTableActionDebug(QString("** changeFieldProperty: \"")
01801 + QString(propertyName) + "\" to \"" + newValue.toString() + "\"", 2);
01802 #endif
01803 if (!d->view->acceptRowEdit())
01804 return;
01805
01806 KoProperty::Set* set = d->sets->at( row );
01807 if (!set || !set->contains(propertyName))
01808 return;
01809 KoProperty::Property &property = set->property(propertyName);
01810 if (listData) {
01811 if (listData->keys.isEmpty())
01812 property.setListData( 0 );
01813 else
01814 property.setListData( new KoProperty::Property::ListData(*listData) );
01815 }
01816 if (propertyName != "type")
01817 property.setValue(newValue);
01818 KexiTableItem *item = d->view->itemAt(row);
01819 Q_ASSERT(item);
01820
01821 if (propertyName == "type") {
01822
01823
01824 d->slotPropertyChanged_subType_enabled = false;
01825 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_TYPE,
01826 int( KexiDB::Field::typeGroup( newValue.toInt() ) )-1);
01827 d->view->data()->saveRowChanges(*item);
01828 d->addHistoryCommand_in_slotRowUpdated_enabled = true;
01829
01830
01831 property.setValue(newValue);
01832 }
01833
01834 if (!addCommand) {
01835 d->addHistoryCommand_in_slotRowUpdated_enabled = false;
01836 d->addHistoryCommand_in_slotPropertyChanged_enabled = false;
01837 d->slotPropertyChanged_subType_enabled = false;
01838 }
01839
01840 if (propertyName == "caption") {
01841 if (!addCommand) {
01842 d->slotBeforeCellChanged_enabled = false;
01843 }
01844 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_CAPTION, newValue);
01845 d->view->data()->saveRowChanges(*item);
01846 if (!addCommand) {
01847 d->slotBeforeCellChanged_enabled = true;
01848 }
01849 }
01850 else if (propertyName == "description") {
01851 if (!addCommand) {
01852 d->slotBeforeCellChanged_enabled = false;
01853 }
01854 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_DESC, newValue);
01855 if (!addCommand) {
01856 d->slotBeforeCellChanged_enabled = true;
01857 }
01858 d->view->data()->saveRowChanges(*item);
01859 }
01860 if (!addCommand) {
01861 d->addHistoryCommand_in_slotPropertyChanged_enabled = true;
01862 d->addHistoryCommand_in_slotRowUpdated_enabled = true;
01863 d->slotPropertyChanged_subType_enabled = true;
01864 }
01865 d->view->updateRow( row );
01866 }
01867
01868 void KexiTableDesignerView::changeFieldProperty( int fieldUID,
01869 const QCString& propertyName, const QVariant& newValue,
01870 KoProperty::Property::ListData* const listData, bool addCommand )
01871 {
01872
01873 const int row = d->sets->findRowForPropertyValue("uid", fieldUID);
01874 if (row<0) {
01875 kexipluginswarn << "KexiTableDesignerView::changeFieldProperty(): field with uid="<<fieldUID<<" not found!"<<endl;
01876 return;
01877 }
01878 changeFieldPropertyForRow(row, propertyName, newValue, listData, addCommand);
01879 }
01880
01881 void KexiTableDesignerView::changePropertyVisibility(
01882 int fieldUID, const QCString& propertyName, bool visible )
01883 {
01884 #ifdef KEXI_DEBUG_GUI
01885 KexiUtils::addAlterTableActionDebug(QString("** changePropertyVisibility: \"")
01886 + QString(propertyName) + "\" to \"" + (visible ? "true" : "false") + "\"", 2);
01887 #endif
01888 if (!d->view->acceptRowEdit())
01889 return;
01890
01891
01892 const int row = d->sets->findRowForPropertyValue("uid", fieldUID);
01893 if (row<0)
01894 return;
01895 KoProperty::Set* set = d->sets->at( row );
01896 if (!set || !set->contains(propertyName))
01897 return;
01898
01899 KoProperty::Property &property = set->property(propertyName);
01900 if (property.isVisible() != visible) {
01901 property.setVisible(visible);
01902 propertySetReloaded(true);
01903 }
01904 }
01905
01906 void KexiTableDesignerView::propertySetSwitched()
01907 {
01908 KexiDataTable::propertySetSwitched();
01909
01910
01911
01912
01913 static_cast<KexiTablePart*>(parentDialog()->part())->lookupColumnPage()
01914 ->assignPropertySet(propertySet());
01915 }
01916
01917 #include "kexitabledesignerview.moc"