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
00443 set->addProperty( prop
00444 = new KoProperty::Property("visibleColumn",
00445 lookupFieldSchema ? lookupFieldSchema->visibleColumn() : -1, i18n("Visible Column")));
00446 prop->setVisible(false);
00447
00449
00450
00451 d->updatePropertiesVisibility(field.type(), *set);
00452
00453 connect(set, SIGNAL(propertyChanged(KoProperty::Set&, KoProperty::Property&)),
00454 this, SLOT(slotPropertyChanged(KoProperty::Set&, KoProperty::Property&)));
00455
00456 d->sets->insert(row, set, newOne);
00457 return set;
00458 }
00459
00460 void KexiTableDesignerView::updateActions(bool activated)
00461 {
00462 Q_UNUSED(activated);
00464 setAvailable("tablepart_toggle_pkey", propertySet()!=0 && !mainWin()->project()->dbConnection()->isReadOnly());
00465 if (!propertySet())
00466 return;
00467 KoProperty::Set &set = *propertySet();
00468 d->slotTogglePrimaryKeyCalled = true;
00469 d->action_toggle_pkey->setChecked(set["primaryKey"].value().toBool());
00470 d->slotTogglePrimaryKeyCalled = false;
00471 }
00472
00473 void KexiTableDesignerView::slotUpdateRowActions(int row)
00474 {
00475 KexiDataTable::slotUpdateRowActions(row);
00476 updateActions();
00477 }
00478
00479 void KexiTableDesignerView::slotTogglePrimaryKey()
00480 {
00481 if (d->slotTogglePrimaryKeyCalled)
00482 return;
00483 d->slotTogglePrimaryKeyCalled = true;
00484 if (!propertySet())
00485 return;
00486 KoProperty::Set &set = *propertySet();
00487 bool isSet = !set["primaryKey"].value().toBool();
00488 set.changeProperty("primaryKey", QVariant(isSet,1));
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500 d->slotTogglePrimaryKeyCalled = false;
00501 }
00502
00503 void KexiTableDesignerView::switchPrimaryKey(KoProperty::Set &propertySet,
00504 bool set, bool aWasPKey, CommandGroup* commandGroup)
00505 {
00506 const bool was_pkey = aWasPKey || propertySet["primaryKey"].value().toBool();
00507
00508 d->setPropertyValueIfNeeded( propertySet, "primaryKey", QVariant(set,1), commandGroup );
00509 if (&propertySet==this->propertySet()) {
00510
00511 d->action_toggle_pkey->setChecked(set);
00512 if (d->view->selectedItem()) {
00513
00514 d->view->data()->clearRowEditBuffer();
00515 d->view->data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_ICON,
00516 QVariant(set ? "key" : ""));
00517 d->view->data()->saveRowChanges(*d->view->selectedItem(), true);
00518 }
00519 if (was_pkey || set)
00520 d->primaryKeyExists = set;
00521 }
00522
00523 if (set) {
00524
00525 KoProperty::Set *s = 0;
00526 int i;
00527 const int count = (int)d->sets->size();
00528 for (i=0; i<count; i++) {
00529 s = d->sets->at(i);
00530 if (s && s!=&propertySet && (*s)["primaryKey"].value().toBool() && i!=d->view->currentRow())
00531 break;
00532 }
00533 if (i<count) {
00534
00535 d->setPropertyValueIfNeeded( *s, "autoIncrement", QVariant(false,0), commandGroup );
00536
00537 d->setPropertyValueIfNeeded( *s, "primaryKey", QVariant(false,0), commandGroup );
00538
00539 d->view->data()->clearRowEditBuffer();
00540 KexiTableItem *item = d->view->itemAt(i);
00541 if (item) {
00542 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_ICON, QVariant());
00543 d->view->data()->saveRowChanges(*item, true);
00544 }
00545 }
00546
00547
00548 d->slotBeforeCellChanged_enabled = false;
00549 d->view->data()->clearRowEditBuffer();
00550 d->view->data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_TYPE,
00551 QVariant(KexiDB::Field::IntegerGroup-1));
00552
00553 d->view->data()->saveRowChanges(*d->view->selectedItem(), true);
00554
00555 d->setPropertyValueIfNeeded( propertySet, "subType", KexiDB::Field::typeString(KexiDB::Field::BigInteger),
00556 commandGroup );
00557
00558 d->setPropertyValueIfNeeded( propertySet, "unsigned", QVariant(true,4), commandGroup );
00559
00560 d->slotBeforeCellChanged_enabled = true;
00561 }
00562 updateActions();
00563 }
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574 tristate KexiTableDesignerView::beforeSwitchTo(int mode, bool &dontStore)
00575 {
00576 if (!d->view->acceptRowEdit())
00577 return false;
00578
00579
00580
00581
00582
00583 tristate res = true;
00584 if (mode==Kexi::DataViewMode) {
00585 if (!dirty() && parentDialog()->neverSaved()) {
00586 KMessageBox::sorry(this, i18n("Cannot switch to data view, because table design is empty.\n"
00587 "First, please create your design.") );
00588 return cancelled;
00589 }
00590
00591 else if (dirty() && !parentDialog()->neverSaved()) {
00592
00593
00594
00595 bool emptyTable;
00596 int r = KMessageBox::warningYesNoCancel(this,
00597 i18n("Saving changes for existing table design is now required.")
00598 + "\n" + d->messageForSavingChanges(emptyTable), QString::null,
00599 KStdGuiItem::save(), KStdGuiItem::discard(), QString::null,
00600 KMessageBox::Notify|KMessageBox::Dangerous);
00601 if (r == KMessageBox::Cancel)
00602 res = cancelled;
00603 else
00604 res = true;
00605 dontStore = (r!=KMessageBox::Yes);
00606 if (!dontStore)
00607 d->dontAskOnStoreData = true;
00608
00609
00610 }
00611
00612
00613 return res;
00614 }
00615 else if (mode==Kexi::TextViewMode) {
00616
00617 }
00618 return res;
00619 }
00620
00621 tristate KexiTableDesignerView::afterSwitchFrom(int mode)
00622 {
00623 if (mode==Kexi::NoViewMode || mode==Kexi::DataViewMode) {
00624 initData();
00625 }
00626 return true;
00627 }
00628
00629 KoProperty::Set *KexiTableDesignerView::propertySet()
00630 {
00631 return d->sets ? d->sets->currentPropertySet() : 0;
00632 }
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650 void KexiTableDesignerView::slotBeforeCellChanged(
00651 KexiTableItem *item, int colnum, QVariant& newValue, KexiDB::ResultInfo* )
00652 {
00653 if (!d->slotBeforeCellChanged_enabled)
00654 return;
00655
00656
00657 if (colnum==COLUMN_ID_CAPTION) {
00658
00659
00660 if (item->at(COLUMN_ID_TYPE).isNull()) {
00661
00662 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_TYPE, QVariant((int)0));
00663 }
00664
00665 KoProperty::Set *propertySetForItem = d->sets->findPropertySetForItem(*item);
00666 if (propertySetForItem) {
00667 d->addHistoryCommand_in_slotPropertyChanged_enabled = false;
00668 QString oldName( propertySetForItem->property("name").value().toString() );
00669 QString oldCaption( propertySetForItem->property("caption").value().toString() );
00670
00671
00672 ChangeFieldPropertyCommand *changeCaptionCommand
00673 = new ChangeFieldPropertyCommand( this, *propertySetForItem, "caption", oldCaption, newValue);
00674
00675
00676 propertySetForItem->changeProperty("caption", newValue);
00677 propertySetForItem->changeProperty("name", newValue);
00678
00679
00680
00681 CommandGroup *changeCaptionAndNameCommand = new CommandGroup(
00682 i18n("Change \"%1\" field's name to \"%2\" and caption from \"%3\" to \"%4\"")
00683 .arg(oldName).arg(propertySetForItem->property("name").value().toString())
00684 .arg(oldCaption).arg(newValue.toString() ));
00685 changeCaptionAndNameCommand->addCommand( changeCaptionCommand );
00686
00687
00688
00689 changeCaptionAndNameCommand->addCommand(
00690 new ChangeFieldPropertyCommand( this, *propertySetForItem,
00691 "name", oldName, propertySetForItem->property("name").value().toString())
00692 );
00693 addHistoryCommand( changeCaptionAndNameCommand, false );
00694
00695 d->addHistoryCommand_in_slotPropertyChanged_enabled = true;
00696 }
00697 }
00698 else if (colnum==COLUMN_ID_TYPE) {
00699 if (newValue.isNull()) {
00700
00701 d->slotBeforeCellChanged_enabled = false;
00702 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_ICON, QVariant());
00703 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_CAPTION, QVariant(QString::null));
00704 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_DESC, QVariant());
00705 d->slotBeforeCellChanged_enabled = true;
00706 return;
00707 }
00708
00709 KoProperty::Set *propertySetForItem = d->sets->findPropertySetForItem(*item);
00710 if (!propertySetForItem)
00711 return;
00712
00713 KoProperty::Set &set = *propertySetForItem;
00714
00715
00716
00717 KexiDB::Field::TypeGroup fieldTypeGroup;
00718 int i_fieldTypeGroup = newValue.toInt()+1;
00719 if (i_fieldTypeGroup < 1 || i_fieldTypeGroup >
00720 #ifdef KEXI_NO_BLOB_FIELDS
00722 (int)KexiDB::Field::LastTypeGroup-1)
00723 #else
00724 (int)KexiDB::Field::LastTypeGroup)
00725 #endif
00726 return;
00727 fieldTypeGroup = static_cast<KexiDB::Field::TypeGroup>(i_fieldTypeGroup);
00728
00729
00730 KexiDB::Field::Type fieldType = KexiDB::defaultTypeForGroup( fieldTypeGroup );
00731 if (fieldType==KexiDB::Field::InvalidType)
00732 fieldType = KexiDB::Field::Text;
00733
00734
00735
00736
00737 QStringList slist, nlist;
00738 getSubTypeListData(fieldTypeGroup, slist, nlist);
00739
00740 QString subTypeValue;
00741
00742
00743
00744
00745
00746
00747 subTypeValue = KexiDB::Field::typeString(fieldType);
00748
00749 KoProperty::Property *subTypeProperty = &set["subType"];
00750 kexipluginsdbg << subTypeProperty->value() << endl;
00751
00752
00753 CommandGroup *changeDataTypeCommand = new CommandGroup(
00754 i18n("Change data type for field \"%1\" to \"%2\"")
00755 .arg(set["name"].value().toString()).arg( KexiDB::Field::typeName( fieldType ) ) );
00756
00757
00758
00759
00760 const bool forcePropertySetReload
00761 = KexiDB::Field::typeGroup( KexiDB::Field::typeForString(subTypeProperty->value().toString()) )
00762 != fieldTypeGroup;
00763
00764 const bool useListData = slist.count() > 1;
00765
00766 if (!useListData) {
00767 slist.clear();
00768 nlist.clear();
00769 }
00770 d->setPropertyValueIfNeeded( set, "type", (int)fieldType, changeDataTypeCommand,
00771 false , true );
00772
00773
00774 if (fieldType == KexiDB::Field::Boolean) {
00776 d->setPropertyValueIfNeeded( set, "notNull", QVariant(true, 1), changeDataTypeCommand,
00777 false , false );
00778 d->setPropertyValueIfNeeded( set, "defaultValue", QVariant(false, 1), changeDataTypeCommand,
00779 false , false );
00780 }
00781
00782
00783
00784
00785
00786
00787
00788
00789 if (set["primaryKey"].value().toBool()==true) {
00790
00791 if (fieldTypeGroup != KexiDB::Field::IntegerGroup) {
00792
00793
00794
00795
00796 d->setPropertyValueIfNeeded( set, "primaryKey", QVariant(false, 1), changeDataTypeCommand );
00798 }
00799 }
00800
00801
00802 d->setPropertyValueIfNeeded( set, "subType", subTypeValue,
00803 changeDataTypeCommand, false, false ,
00804 &slist, &nlist );
00805
00806 if (d->updatePropertiesVisibility(fieldType, set, changeDataTypeCommand) || forcePropertySetReload) {
00807
00808 propertySetReloaded(true);
00809 }
00810
00811 addHistoryCommand( changeDataTypeCommand, false );
00812 }
00813 else if (colnum==COLUMN_ID_DESC) {
00814 KoProperty::Set *propertySetForItem = d->sets->findPropertySetForItem(*item);
00815 if (!propertySetForItem)
00816 return;
00817
00818 QVariant oldValue((*propertySetForItem)["description"].value());
00819 kexipluginsdbg << oldValue << endl;
00820 propertySetForItem->changeProperty("description", newValue);
00821
00822
00823
00824 }
00825 }
00826
00827 void KexiTableDesignerView::slotRowUpdated(KexiTableItem *item)
00828 {
00829 const int row = d->view->data()->findRef(item);
00830 if (row < 0)
00831 return;
00832
00833 setDirty();
00834
00835
00836
00837 QString fieldCaption( item->at(COLUMN_ID_CAPTION).toString() );
00838 const bool prop_set_allowed = !item->at(COLUMN_ID_TYPE).isNull();
00839
00840 if (!prop_set_allowed && d->sets->at(row)) {
00841
00842 d->sets->remove( row );
00843
00844
00845 d->view->data()->clearRowEditBuffer();
00846
00847 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_TYPE, QVariant());
00848 d->view->data()->saveRowChanges(*item);
00849
00850 } else if (prop_set_allowed && !d->sets->at(row)) {
00851
00852 KexiDB::Field::TypeGroup fieldTypeGroup = static_cast<KexiDB::Field::TypeGroup>(
00853 item->at(COLUMN_ID_TYPE).toInt()+1 );
00854 int intFieldType = KexiDB::defaultTypeForGroup( fieldTypeGroup );
00855 if (intFieldType==0)
00856 return;
00857
00858 QString description( item->at(COLUMN_ID_DESC).toString() );
00859
00860
00861 QString fieldName( KexiUtils::string2Identifier(fieldCaption) );
00862
00863 KexiDB::Field::Type fieldType = KexiDB::intToFieldType( intFieldType );
00864 KexiDB::Field field(
00865 fieldName,
00866 fieldType,
00867 KexiDB::Field::NoConstraints,
00868 KexiDB::Field::NoOptions,
00869 0,
00870 0,
00871 QVariant(),
00872 fieldCaption,
00873 description,
00874 0);
00875
00876
00877
00878 if (fieldType == KexiDB::Field::Boolean) {
00879 field.setNotNull( true );
00880 field.setDefaultValue( QVariant(false, 0) );
00881 }
00882
00883 kexipluginsdbg << "KexiTableDesignerView::slotRowUpdated(): " << field.debugString() << endl;
00884
00885
00886 KoProperty::Set *newSet = createPropertySet( row, field, true );
00887
00888
00889
00890
00891
00892
00893
00894
00895 propertySetSwitched();
00896
00897 if (row>=0) {
00898 if (d->addHistoryCommand_in_slotRowUpdated_enabled) {
00899 addHistoryCommand( new InsertFieldCommand( this, row, *newSet ),
00900 false );
00901 }
00902 }
00903 else {
00904 kexipluginswarn << "KexiTableDesignerView::slotRowUpdated() row # not found !" << endl;
00905 }
00906 }
00907 }
00908
00909 void KexiTableDesignerView::updateActions()
00910 {
00911 updateActions(false);
00912 }
00913
00914 void KexiTableDesignerView::slotPropertyChanged(KoProperty::Set& set, KoProperty::Property& property)
00915 {
00916
00917
00918 const QCString pname = property.name();
00919 kexipluginsdbg << "KexiTableDesignerView::slotPropertyChanged(): " << pname << " = " << property.value()
00920 << " (oldvalue = " << property.oldValue() << ")" << endl;
00921
00922
00923 bool changePrimaryKey = false;
00924
00925 bool setPrimaryKey = false;
00926
00927 if (pname=="primaryKey" && d->slotPropertyChanged_primaryKey_enabled) {
00928 changePrimaryKey = true;
00929 setPrimaryKey = property.value().toBool();
00930 }
00931
00932
00933 if (pname=="rowSource" || pname=="rowSourceType") {
00936 const int row = d->sets->findRowForPropertyValue("uid", set["uid"].value().toInt());
00937 KexiTableItem *item = d->view->itemAt(row);
00938 if (item)
00939 d->updateIconForItem(*item, set);
00940 }
00941
00942
00943 CommandGroup *setAutonumberCommand = 0;
00944 CommandGroup *toplevelCommand = 0;
00945 if (pname=="autoIncrement" && property.value().toBool()==true) {
00946 if (set["primaryKey"].value().toBool()==false) {
00947 QString msg = QString("<p>")
00948 +i18n("Setting autonumber requires primary key to be set for current field.")+"</p>";
00949 if (d->primaryKeyExists)
00950 msg += (QString("<p>")+ i18n("Previous primary key will be removed.")+"</p>");
00951 msg += (QString("<p>")
00952 +i18n("Do you want to create primary key for current field? "
00953 "Click \"Cancel\" to cancel setting autonumber.")+"</p>");
00954
00955 if (KMessageBox::Yes == KMessageBox::questionYesNo(this, msg,
00956 i18n("Setting Autonumber Field"),
00957 KGuiItem(i18n("Create &Primary Key"), "key"), KStdGuiItem::cancel() ))
00958 {
00959 changePrimaryKey = true;
00960 setPrimaryKey = true;
00961
00962
00963 setAutonumberCommand = new CommandGroup(
00964 i18n("Assign autonumber for field \"%1\"").arg(set["name"].value().toString()) );
00965 toplevelCommand = setAutonumberCommand;
00966 d->setPropertyValueIfNeeded( set, "autoIncrement", QVariant(true,1), setAutonumberCommand );
00967 }
00968 else {
00969 setAutonumberCommand = new CommandGroup(
00970 i18n("Remove autonumber from field \"%1\"").arg(set["name"].value().toString()) );
00971
00972
00973
00974 d->setPropertyValueIfNeeded( set, "autoIncrement", QVariant(false,1), setAutonumberCommand,
00975 true , false );
00976 addHistoryCommand( setAutonumberCommand, false );
00977 return;
00978 }
00979 }
00980 }
00981
00982
00983 if ((pname=="indexed" || pname=="unique" || pname=="notNull")
00984 && set["primaryKey"].value().toBool() && property.value().toBool()==false)
00985 {
00987 changePrimaryKey = true;
00988 setPrimaryKey = false;
00989
00990 CommandGroup *unsetIndexedOrUniquOrNotNullCommand = new CommandGroup(
00991 i18n("Set \"%1\" property for field \"%2\"").arg(property.caption()).arg(set["name"].value().toString()) );
00992 toplevelCommand = unsetIndexedOrUniquOrNotNullCommand;
00993 d->setPropertyValueIfNeeded( set, pname, QVariant(false,1), unsetIndexedOrUniquOrNotNullCommand );
00994 if (pname=="notNull") {
00995
00996 d->setPropertyValueIfNeeded( set, "unique", QVariant(false,1), unsetIndexedOrUniquOrNotNullCommand );
00997 }
00998 }
00999
01000 if (pname=="defaultValue") {
01001 KexiDB::Field::Type type = KexiDB::intToFieldType( set["type"].value().toInt() );
01002 set["defaultValue"].setType((KoProperty::PropertyType)KexiDB::Field::variantType(type));
01003 }
01004
01005 if (pname=="subType" && d->slotPropertyChanged_subType_enabled) {
01006 d->slotPropertyChanged_subType_enabled = false;
01007 if (set["primaryKey"].value().toBool()==true
01008 && property.value().toString()!=KexiDB::Field::typeString(KexiDB::Field::BigInteger))
01009 {
01010 kexipluginsdbg << "INVALID " << property.value().toString() << endl;
01011
01012
01013
01014
01015 }
01016 KexiDB::Field::Type type = KexiDB::intToFieldType( set["type"].value().toInt() );
01017 QString typeName;
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030 typeName = KexiDB::Field::typeName( KexiDB::Field::typeForString(property.value().toString()) );
01031
01032
01033
01034
01035 CommandGroup* changeFieldTypeCommand = new CommandGroup(
01036 i18n("Change type for field \"%1\" to \"%2\"").arg(set["name"].value().toString())
01037 .arg(typeName) );
01038 d->setPropertyValueIfNeeded( set, "subType", property.value(), property.oldValue(),
01039 changeFieldTypeCommand );
01040
01041 kexipluginsdbg << set["type"].value() << endl;
01042 const KexiDB::Field::Type newType = KexiDB::Field::typeForString(property.value().toString());
01043 set["type"].setValue( newType );
01044
01045
01046 QVariant oldDefVal( set["defaultValue"].value() );
01047 QVariant newDefVal( tryCastQVariant(oldDefVal, KexiDB::Field::variantType(type)) );
01048 if (oldDefVal.type()!=newDefVal.type())
01049 set["defaultValue"].setType( newDefVal.type() );
01050 d->setPropertyValueIfNeeded( set, "defaultValue", newDefVal, newDefVal,
01051 changeFieldTypeCommand );
01052
01053 d->updatePropertiesVisibility(newType, set);
01054
01055 propertySetReloaded(true);
01056 d->slotPropertyChanged_subType_enabled = true;
01057
01058 addHistoryCommand( changeFieldTypeCommand, false );
01059 return;
01060
01061
01062
01063 }
01064
01065 if (d->addHistoryCommand_in_slotPropertyChanged_enabled && !changePrimaryKey) {
01066 addHistoryCommand( new ChangeFieldPropertyCommand(this, set,
01067 property.name(), property.oldValue() , property.value()),
01068 false );
01069 }
01070
01071 if (changePrimaryKey) {
01072 d->slotPropertyChanged_primaryKey_enabled = false;
01073 if (setPrimaryKey) {
01074
01075
01076
01077
01078
01079 CommandGroup *setPrimaryKeyCommand = new CommandGroup(
01080 i18n("Set primary key for field \"%1\"")
01081 .arg(set["name"].value().toString()) );
01082 if (toplevelCommand)
01083 toplevelCommand->addCommand( setPrimaryKeyCommand );
01084 else
01085 toplevelCommand = setPrimaryKeyCommand;
01086
01087 d->setPropertyValueIfNeeded( set, "primaryKey", QVariant(true,1), setPrimaryKeyCommand, true );
01088 d->setPropertyValueIfNeeded( set, "unique", QVariant(true,1), setPrimaryKeyCommand );
01089 d->setPropertyValueIfNeeded( set, "notNull", QVariant(true,1), setPrimaryKeyCommand );
01090 d->setPropertyValueIfNeeded( set, "allowEmpty", QVariant(false,1), setPrimaryKeyCommand );
01091 d->setPropertyValueIfNeeded( set, "indexed", QVariant(true,1), setPrimaryKeyCommand );
01093 d->setPropertyValueIfNeeded( set, "autoIncrement", QVariant(true,1), setPrimaryKeyCommand );
01094
01095
01096
01097
01098
01099
01100
01101
01102 }
01103 else {
01104
01105 CommandGroup *setPrimaryKeyCommand = new CommandGroup(
01106 i18n("Unset primary key for field \"%1\"")
01107 .arg(set["name"].value().toString()) );
01108 if (toplevelCommand)
01109 toplevelCommand->addCommand( setPrimaryKeyCommand );
01110 else
01111 toplevelCommand = setPrimaryKeyCommand;
01112
01113 d->setPropertyValueIfNeeded( set, "primaryKey", QVariant(false,1), setPrimaryKeyCommand, true );
01114 d->setPropertyValueIfNeeded( set, "autoIncrement", QVariant(false,1), setPrimaryKeyCommand );
01115
01116
01117
01118 }
01119 switchPrimaryKey(set, setPrimaryKey, true, toplevelCommand);
01120 d->updatePropertiesVisibility(
01121 KexiDB::Field::typeForString( set["subType"].value().toString() ), set, toplevelCommand);
01122 addHistoryCommand( toplevelCommand, false );
01123
01124 propertySetReloaded(true);
01125 d->slotPropertyChanged_primaryKey_enabled = true;
01126 }
01127 }
01128
01129 void KexiTableDesignerView::slotRowInserted()
01130 {
01131 updateActions();
01132
01133 if (d->addHistoryCommand_in_slotRowInserted_enabled) {
01134 const int row = d->view->currentRow();
01135 if (row>=0) {
01136 addHistoryCommand( new InsertEmptyRowCommand( this, row ), false );
01137 }
01138 }
01139
01140 }
01141
01142 void KexiTableDesignerView::slotAboutToDeleteRow(
01143 KexiTableItem& item, KexiDB::ResultInfo* result, bool repaint)
01144 {
01145 Q_UNUSED(result)
01146 Q_UNUSED(repaint)
01147 if (item[COLUMN_ID_ICON].toString()=="key")
01148 d->primaryKeyExists = false;
01149
01150 if (d->addHistoryCommand_in_slotAboutToDeleteRow_enabled) {
01151 const int row = d->view->data()->findRef(&item);
01152 KoProperty::Set *set = row >=0 ? d->sets->at(row) : 0;
01153
01154 addHistoryCommand(
01155 new RemoveFieldCommand( this, row, set ),
01156 false
01157 );
01158 }
01159 }
01160
01161 KexiDB::Field * KexiTableDesignerView::buildField( const KoProperty::Set &set ) const
01162 {
01163
01164 kexipluginsdbg << set["type"].value() << endl;
01165 QMap<QCString, QVariant> values = KoProperty::propertyValues(set);
01166
01167 QMap<QCString, QVariant>::Iterator it = values.begin();
01168 KexiDB::Field *field = new KexiDB::Field();
01169
01170 while (it!=values.end()) {
01171 const QString propName( it.key() );
01172 if (d->internalPropertyNames.find(propName.latin1()) || propName.startsWith("this:")
01173 || (propName=="objectType" && KexiDB::Field::BLOB != KexiDB::intToFieldType( set["type"].value().toInt() )))
01174 {
01175 QMap<QCString, QVariant>::Iterator it_tmp = it;
01176 ++it;
01177 values.remove(it_tmp);
01178 }
01179 else
01180 ++it;
01181 }
01182
01183
01184 if (!KexiDB::setFieldProperties( *field, values )) {
01185 delete field;
01186 return 0;
01187 }
01188 return field;
01189 }
01190
01191 tristate KexiTableDesignerView::buildSchema(KexiDB::TableSchema &schema, bool beSilent)
01192 {
01193 if (!d->view->acceptRowEdit())
01194 return cancelled;
01195
01196 tristate res = true;
01197
01198 if (!d->primaryKeyExists) {
01199 if (beSilent) {
01200 kexipluginsdbg << "KexiTableDesignerView::buildSchema(): no primay key defined..." << endl;
01201 }
01202 else {
01203 const int questionRes = KMessageBox::questionYesNoCancel(this,
01204 i18n("<p>Table \"%1\" has no <b>primary key</b> defined.</p>"
01205 "<p>Although a primary key is not required, it is needed "
01206 "for creating relations between database tables. "
01207 "Do you want to add primary key automatically now?</p>"
01208 "<p>If you want to add a primary key by hand, press \"Cancel\" "
01209 "to cancel saving table design.</p>").arg(schema.name()),
01210 QString::null, KGuiItem(i18n("&Add Primary Key"), "key"), KStdGuiItem::no(),
01211 "autogeneratePrimaryKeysOnTableDesignSaving");
01212 if (questionRes==KMessageBox::Cancel) {
01213 return cancelled;
01214 }
01215 else if (questionRes==KMessageBox::Yes) {
01216
01217 int i=0;
01218 int idIndex = 1;
01219 QString pkFieldName("id%1");
01220 QString pkFieldCaption(i18n("Identifier%1", "Id%1"));
01221 while (i<(int)d->sets->size()) {
01222 KoProperty::Set *set = d->sets->at(i);
01223 if (set) {
01224 if ((*set)["name"].value().toString()
01225 == pkFieldName.arg(idIndex==1?QString::null : QString::number(idIndex))
01226 || (*set)["caption"].value().toString()
01227 == pkFieldCaption.arg(idIndex==1?QString::null : QString::number(idIndex)))
01228 {
01229
01230 i = 0;
01231 idIndex++;
01232 continue;
01233 }
01234 }
01235 i++;
01236 }
01237 pkFieldName = pkFieldName.arg(idIndex==1?QString::null : QString::number(idIndex));
01238 pkFieldCaption = pkFieldCaption.arg(idIndex==1?QString::null : QString::number(idIndex));
01239
01240 d->view->insertEmptyRow(0);
01241 d->view->setCursorPosition(0, COLUMN_ID_CAPTION);
01242 d->view->data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_CAPTION,
01243 QVariant(pkFieldCaption));
01244 d->view->data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_TYPE,
01245 QVariant(KexiDB::Field::IntegerGroup-1));
01246 if (!d->view->data()->saveRowChanges(*d->view->selectedItem(), true)) {
01247 return cancelled;
01248 }
01249 slotTogglePrimaryKey();
01250 }
01251 }
01252 }
01253
01254
01255 KoProperty::Set *b = 0;
01256 bool no_fields = true;
01257 int i;
01258 QDict<char> names(101, false);
01259 char dummy;
01260 for (i=0;i<(int)d->sets->size();i++) {
01261 b = d->sets->at(i);
01262 if (b) {
01263 no_fields = false;
01264 const QString name = (*b)["name"].value().toString();
01265 if (name.isEmpty()) {
01266 if (beSilent) {
01267 kexipluginswarn <<
01268 QString("KexiTableDesignerView::buildSchema(): no field caption entered at row %1...")
01269 .arg(i+1) << endl;
01270 }
01271 else {
01272 d->view->setCursorPosition(i, COLUMN_ID_CAPTION);
01273 d->view->startEditCurrentCell();
01274 KMessageBox::information(this, i18n("You should enter field caption.") );
01275 }
01276 res = cancelled;
01277 break;
01278 }
01279 if (names[name]) {
01280 break;
01281 }
01282 names.insert( name, &dummy );
01283 }
01284 }
01285 if (res == true && no_fields) {
01286 if (beSilent) {
01287 kexipluginswarn <<
01288 "KexiTableDesignerView::buildSchema(): no field defined..." << endl;
01289 }
01290 else {
01291 KMessageBox::sorry(this,
01292 i18n("You have added no fields.\nEvery table should have at least one field.") );
01293 }
01294 res = cancelled;
01295 }
01296 if (res == true && b && i<(int)d->sets->size()) {
01297 if (beSilent) {
01298 kexipluginswarn <<
01299 QString("KexiTableDesignerView::buildSchema(): duplicated field name '%1'")
01300 .arg((*b)["name"].value().toString()) << endl;
01301 }
01302 else {
01303 d->view->setCursorPosition(i, COLUMN_ID_CAPTION);
01304 d->view->startEditCurrentCell();
01306 KMessageBox::sorry(this,
01307 i18n("You have added \"%1\" field name twice.\nField names cannot be repeated. "
01308 "Correct name of the field.")
01309 .arg((*b)["name"].value().toString()) );
01310 }
01311 res = cancelled;
01312 }
01313 if (res == true) {
01314
01315 for (i=0;i<(int)d->sets->size();i++) {
01316 KoProperty::Set *s = d->sets->at(i);
01317 if (!s)
01318 continue;
01319 KexiDB::Field * f = buildField( *s );
01320 if (!f)
01321 continue;
01322 schema.addField(f);
01323 if (!(*s)["rowSource"].value().toString().isEmpty() && !(*s)["rowSourceType"].value().toString().isEmpty()) {
01324
01325 KexiDB::LookupFieldSchema *lookupFieldSchema = new KexiDB::LookupFieldSchema();
01326 lookupFieldSchema->rowSource().setTypeByName( (*s)["rowSourceType"].value().toString() );
01327 lookupFieldSchema->rowSource().setName( (*s)["rowSource"].value().toString() );
01328 lookupFieldSchema->setBoundColumn( (*s)["boundColumn"].value().toInt() );
01329 lookupFieldSchema->setVisibleColumn( (*s)["visibleColumn"].value().toInt() );
01331 if (!schema.setLookupFieldSchema(f->name(), lookupFieldSchema)) {
01332 kexipluginswarn <<
01333 "KexiTableDesignerView::buildSchema(): !schema.setLookupFieldSchema()" << endl;
01334 delete lookupFieldSchema;
01335 return false;
01336 }
01337 }
01338 }
01339 }
01340 return res;
01341 }
01342
01345 static void copyAlterTableActions(KCommand* command, KexiDB::AlterTableHandler::ActionList &actions)
01346 {
01347 CommandGroup* cmdGroup = dynamic_cast<CommandGroup*>( command );
01348 if (cmdGroup) {
01349 for (QPtrListIterator<KCommand> it(cmdGroup->commands()); it.current(); ++it)
01350 copyAlterTableActions(it.current(), actions);
01351 return;
01352 }
01353 Command* cmd = dynamic_cast<Command*>( command );
01354 if (!cmd) {
01355 kexipluginswarn << "KexiTableDesignerView::copyAlterTableActions(): cmd is not of type 'Command'!" << endl;
01356 return;
01357 }
01358 KexiDB::AlterTableHandler::ActionBase* action = cmd->createAction();
01359
01360 if (action)
01361 actions.append( action );
01362 }
01363
01364 tristate KexiTableDesignerView::buildAlterTableActions(KexiDB::AlterTableHandler::ActionList &actions)
01365 {
01366 actions.clear();
01367 kexipluginsdbg << "KexiTableDesignerView::buildAlterTableActions(): " << d->history->commands().count()
01368 << " top-level command(s) to process..." << endl;
01369 for (QPtrListIterator<KCommand> it(d->history->commands()); it.current(); ++it) {
01370 copyAlterTableActions(it.current(), actions);
01371 }
01372 return true;
01373 }
01374
01375 KexiDB::SchemaData* KexiTableDesignerView::storeNewData(const KexiDB::SchemaData& sdata, bool &cancel)
01376 {
01377 if (tempData()->table || m_dialog->schemaData())
01378 return 0;
01379
01380
01381 tempData()->table = new KexiDB::TableSchema(sdata.name());
01382 tempData()->table->setName( sdata.name() );
01383 tempData()->table->setCaption( sdata.caption() );
01384 tempData()->table->setDescription( sdata.description() );
01385
01386 tristate res = buildSchema(*tempData()->table);
01387 cancel = ~res;
01388
01389
01390 if (res == true) {
01391
01392 KexiDB::Connection *conn = mainWin()->project()->dbConnection();
01393 res = conn->createTable(tempData()->table);
01394 if (res!=true)
01395 parentDialog()->setStatus(conn, "");
01396 }
01397
01398 if (res == true) {
01399
01400 tempData()->tableSchemaChangedInPreviousView = true;
01401
01402
01403 }
01404 else {
01405 delete tempData()->table;
01406 tempData()->table = 0;
01407 }
01408 return tempData()->table;
01409 }
01410
01411 tristate KexiTableDesignerView::storeData(bool dontAsk)
01412 {
01413 if (!tempData()->table || !m_dialog->schemaData()) {
01414 d->recentResultOfStoreData = false;
01415 return false;
01416 }
01417
01418 tristate res = true;
01419 if (!d->tempStoreDataUsingRealAlterTable && !d->dontAskOnStoreData && !dontAsk) {
01420 bool emptyTable;
01421 const QString msg = d->messageForSavingChanges(emptyTable);
01422 if (!emptyTable) {
01423 if (KMessageBox::No == KMessageBox::questionYesNo(this, msg))
01424 res = cancelled;
01425 }
01426 }
01427 d->dontAskOnStoreData = false;
01428 if (~res) {
01429 d->recentResultOfStoreData = res;
01430 return res;
01431 }
01432
01433
01434
01435 KexiDB::Connection *conn = mainWin()->project()->dbConnection();
01436
01437 KexiDB::AlterTableHandler *alterTableHandler = 0;
01438 KexiDB::TableSchema *newTable = 0;
01439 if (d->tempStoreDataUsingRealAlterTable) {
01440 KexiDB::AlterTableHandler::ActionList actions;
01441 res = buildAlterTableActions( actions );
01442
01443 alterTableHandler = new KexiDB::AlterTableHandler( *conn );
01444 alterTableHandler->setActions(actions);
01445 }
01446 else {
01448
01449 newTable = new KexiDB::TableSchema();
01450
01451 static_cast<KexiDB::SchemaData&>(*newTable) = static_cast<KexiDB::SchemaData&>(*tempData()->table);
01452 res = buildSchema(*newTable);
01453 kexipluginsdbg << "KexiTableDesignerView::storeData() : BUILD SCHEMA:" << endl;
01454 newTable->debug();
01455 }
01456
01457 if (res == true) {
01458 res = KexiTablePart::askForClosingObjectsUsingTableSchema(
01459 this, *conn, *tempData()->table,
01460 i18n("You are about to change the design of table \"%1\" "
01461 "but following objects using this table are opened:")
01462 .arg(tempData()->table->name()));
01463 }
01464 if (res == true) {
01465 if (d->tempStoreDataUsingRealAlterTable) {
01466 newTable = alterTableHandler->execute(tempData()->table->name(), res);
01467 kexipluginsdbg << "KexiTableDesignerView::storeData() : ALTER TABLE EXECUTE: "
01468 << res.toString() << endl;
01469 if (!res) {
01470 alterTableHandler->debugError();
01471 parentDialog()->setStatus(alterTableHandler, "");
01472 }
01474 }
01475 else {
01477
01478 res = conn->alterTable(*tempData()->table, *newTable);
01479 if (!res)
01480 parentDialog()->setStatus(conn, "");
01481 }
01482 if (res == true) {
01483
01484 tempData()->table = newTable;
01485 tempData()->tableSchemaChangedInPreviousView = true;
01486 }
01487 else {
01488 delete newTable;
01489 }
01490 }
01491 delete alterTableHandler;
01492 d->recentResultOfStoreData = res;
01493 return res;
01494 }
01495
01496 tristate KexiTableDesignerView::simulateAlterTableExecution(QString *debugTarget)
01497 {
01498 #ifndef KEXI_NO_UNDOREDO_ALTERTABLE
01499 # ifdef KEXI_DEBUG_GUI
01500 if (mainWin()->activeWindow() != parentDialog())
01501 return false;
01502 if (!tempData()->table || !m_dialog->schemaData())
01503 return false;
01504 KexiDB::Connection *conn = mainWin()->project()->dbConnection();
01505 KexiDB::AlterTableHandler::ActionList actions;
01506 tristate res = buildAlterTableActions( actions );
01507
01508 KexiDB::AlterTableHandler alterTableHandler( *conn );
01509 alterTableHandler.setActions(actions);
01510
01511 if (debugTarget)
01512 return alterTableHandler.simulateExecution(tempData()->table->name(), *debugTarget);
01513 else
01514 return alterTableHandler.execute(tempData()->table->name(), res, true);
01515 # else
01516 return false;
01517 # endif
01518 #else
01519 return false;
01520 #endif
01521 }
01522
01523 void KexiTableDesignerView::slotSimulateAlterTableExecution()
01524 {
01525 (void)simulateAlterTableExecution(0);
01526 }
01527
01528 tristate KexiTableDesignerView::executeRealAlterTable()
01529 {
01530 QSignal signal;
01531 signal.connect( mainWin(), SLOT(slotProjectSave()) );
01532 d->tempStoreDataUsingRealAlterTable = true;
01533 d->recentResultOfStoreData = false;
01534 signal.activate();
01535 d->tempStoreDataUsingRealAlterTable = false;
01536 return d->recentResultOfStoreData;
01537 }
01538
01539 KexiTablePart::TempData* KexiTableDesignerView::tempData() const
01540 {
01541 return static_cast<KexiTablePart::TempData*>(parentDialog()->tempData());
01542 }
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561 #ifdef KEXI_DEBUG_GUI
01562 void KexiTableDesignerView::debugCommand( KCommand* command, int nestingLevel )
01563 {
01564 if (dynamic_cast<Command*>(command))
01565 KexiUtils::addAlterTableActionDebug(dynamic_cast<Command*>(command)->debugString(), nestingLevel);
01566 else
01567 KexiUtils::addAlterTableActionDebug(command->name(), nestingLevel);
01568
01569 if (dynamic_cast<CommandGroup*>(command)) {
01570 for (QPtrListIterator<KCommand> it(dynamic_cast<CommandGroup*>(command)->commands()); it.current(); ++it) {
01571 debugCommand(it.current(), nestingLevel + 1);
01572 }
01573 }
01574 }
01575 #endif
01576
01577 void KexiTableDesignerView::addHistoryCommand( KCommand* command, bool execute )
01578 {
01579 #ifndef KEXI_NO_UNDOREDO_ALTERTABLE
01580 # ifdef KEXI_DEBUG_GUI
01581 debugCommand( command, 0 );
01582 # endif
01583 d->history->addCommand( command, execute );
01584 updateUndoRedoActions();
01585 #endif
01586 }
01587
01588 void KexiTableDesignerView::updateUndoRedoActions()
01589 {
01590 #ifndef KEXI_NO_UNDOREDO_ALTERTABLE
01591 setAvailable("edit_undo", d->historyActionCollection->action("edit_undo")->isEnabled());
01592 setAvailable("edit_redo", d->historyActionCollection->action("edit_redo")->isEnabled());
01593 #endif
01594 }
01595
01596 void KexiTableDesignerView::slotUndo()
01597 {
01598 #ifndef KEXI_NO_UNDOREDO_ALTERTABLE
01599 # ifdef KEXI_DEBUG_GUI
01600 KexiUtils::addAlterTableActionDebug(QString("UNDO:"));
01601 # endif
01602 d->history->undo();
01603 updateUndoRedoActions();
01604 #endif
01605 }
01606
01607 void KexiTableDesignerView::slotRedo()
01608 {
01609 #ifndef KEXI_NO_UNDOREDO_ALTERTABLE
01610 # ifdef KEXI_DEBUG_GUI
01611 KexiUtils::addAlterTableActionDebug(QString("REDO:"));
01612 # endif
01613 d->history->redo();
01614 updateUndoRedoActions();
01615 #endif
01616 }
01617
01618 void KexiTableDesignerView::slotCommandExecuted(KCommand *command)
01619 {
01620 #ifdef KEXI_DEBUG_GUI
01621 debugCommand( command, 1 );
01622 #endif
01623 }
01624
01625 void KexiTableDesignerView::slotAboutToShowContextMenu()
01626 {
01627
01628 if (propertySet()) {
01629 const KoProperty::Set &set = *propertySet();
01630 QString captionOrName(set["caption"].value().toString());
01631 if (captionOrName.isEmpty())
01632 captionOrName = set["name"].value().toString();
01634 d->contextMenuTitle->setTitle( i18n("Table field \"%1\"").arg(captionOrName) );
01635 }
01636 else {
01637 d->contextMenuTitle->setTitle( i18n("Empty table row", "Empty Row") );
01638 }
01639 }
01640
01641 QString KexiTableDesignerView::debugStringForCurrentTableSchema(tristate& result)
01642 {
01643 KexiDB::TableSchema tempTable;
01644
01645 static_cast<KexiDB::SchemaData&>(tempTable) = static_cast<KexiDB::SchemaData&>(*tempData()->table);
01646 result = buildSchema(tempTable, true );
01647 if (true!=result)
01648 return QString::null;
01649 return tempTable.debugString(false );
01650 }
01651
01652
01653
01654 void KexiTableDesignerView::clearRow(int row, bool addCommand)
01655 {
01656 if (!d->view->acceptRowEdit())
01657 return;
01658 KexiTableItem *item = d->view->itemAt(row);
01659 if (!item)
01660 return;
01661
01662 d->sets->remove( row );
01663
01664
01665 if (!addCommand) {
01666 d->addHistoryCommand_in_slotRowUpdated_enabled = false;
01667 d->addHistoryCommand_in_slotPropertyChanged_enabled = false;
01668 d->slotBeforeCellChanged_enabled = false;
01669 }
01670 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_TYPE, QVariant());
01671 if (!addCommand) {
01672 d->addHistoryCommand_in_slotRowUpdated_enabled = true;
01673 d->addHistoryCommand_in_slotPropertyChanged_enabled = true;
01674 d->slotBeforeCellChanged_enabled = true;
01675 }
01676 d->view->data()->saveRowChanges(*item, true);
01677 }
01678
01679 void KexiTableDesignerView::insertField(int row, const QString& caption, bool addCommand)
01680 {
01681 insertFieldInternal(row, 0, caption, addCommand);
01682 }
01683
01684 void KexiTableDesignerView::insertField(int row, KoProperty::Set& set, bool addCommand)
01685 {
01686 insertFieldInternal(row, &set, QString::null, addCommand);
01687 }
01688
01689 void KexiTableDesignerView::insertFieldInternal(int row, KoProperty::Set* set,
01690 const QString& caption, bool addCommand)
01691 {
01692 if (set && (!set->contains("type") || !set->contains("caption"))) {
01693 kexipluginswarn << "KexiTableDesignerView::insertField(): no 'type' or 'caption' property in set!" << endl;
01694 return;
01695 }
01696 if (!d->view->acceptRowEdit())
01697 return;
01698 KexiTableItem *item = d->view->itemAt(row);
01699 if (!item)
01700 return;
01701 if (!addCommand) {
01702 d->addHistoryCommand_in_slotRowUpdated_enabled = false;
01703 d->addHistoryCommand_in_slotPropertyChanged_enabled = false;
01704 d->slotBeforeCellChanged_enabled = false;
01705 }
01706 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_CAPTION,
01707 set ? (*set)["caption"].value() : QVariant(caption));
01708 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_TYPE,
01709 set ? (int)KexiDB::Field::typeGroup( (*set)["type"].value().toInt() )-1
01710 : (((int)KexiDB::Field::TextGroup)-1)
01711 );
01712 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_DESC,
01713 set ? (*set)["description"].value() : QVariant());
01714 if (!addCommand) {
01715 d->slotBeforeCellChanged_enabled = true;
01716 }
01717
01718 d->view->data()->saveRowChanges(*item);
01719 if (set) {
01720 KoProperty::Set *newSet = d->sets->at(row);
01721 if (newSet) {
01722 *newSet = *set;
01723 }
01724 else {
01725 kexipluginswarn << "KexiTableDesignerView::insertField() !newSet, row==" << row << endl;
01726 }
01727 }
01728 if (!addCommand) {
01729 d->addHistoryCommand_in_slotPropertyChanged_enabled = true;
01730 d->addHistoryCommand_in_slotRowUpdated_enabled = true;
01731 }
01732 d->view->updateRow( row );
01733 propertySetReloaded(true);
01734 }
01735
01736 void KexiTableDesignerView::insertEmptyRow( int row, bool addCommand )
01737 {
01738 if (!addCommand) {
01739 d->addHistoryCommand_in_slotRowInserted_enabled = false;
01740 }
01741 d->view->insertEmptyRow( row );
01742 if (!addCommand) {
01743 d->addHistoryCommand_in_slotRowInserted_enabled = true;
01744 }
01745 }
01746
01747
01748
01749
01750
01751
01752
01753
01754 void KexiTableDesignerView::deleteRow( int row, bool addCommand )
01755 {
01756 KexiTableItem *item = d->view->itemAt( row );
01757 if (!item)
01758 return;
01759 if (!addCommand) {
01760 d->addHistoryCommand_in_slotAboutToDeleteRow_enabled = false;
01761 }
01762 const bool res = d->view->deleteItem(item);
01763 if (!addCommand) {
01764 d->addHistoryCommand_in_slotAboutToDeleteRow_enabled = true;
01765 }
01766 if (!res)
01767 return;
01768 }
01769
01770 void KexiTableDesignerView::changeFieldPropertyForRow( int row,
01771 const QCString& propertyName, const QVariant& newValue,
01772 KoProperty::Property::ListData* const listData, bool addCommand )
01773 {
01774 #ifdef KEXI_DEBUG_GUI
01775 KexiUtils::addAlterTableActionDebug(QString("** changeFieldProperty: \"")
01776 + QString(propertyName) + "\" to \"" + newValue.toString() + "\"", 2);
01777 #endif
01778 if (!d->view->acceptRowEdit())
01779 return;
01780
01781 KoProperty::Set* set = d->sets->at( row );
01782 if (!set || !set->contains(propertyName))
01783 return;
01784 KoProperty::Property &property = set->property(propertyName);
01785 if (listData) {
01786 if (listData->keys.isEmpty())
01787 property.setListData( 0 );
01788 else
01789 property.setListData( new KoProperty::Property::ListData(*listData) );
01790 }
01791 if (propertyName != "type")
01792 property.setValue(newValue);
01793 KexiTableItem *item = d->view->itemAt(row);
01794 Q_ASSERT(item);
01795
01796 if (propertyName == "type") {
01797
01798
01799 d->slotPropertyChanged_subType_enabled = false;
01800 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_TYPE,
01801 int( KexiDB::Field::typeGroup( newValue.toInt() ) )-1);
01802 d->view->data()->saveRowChanges(*item);
01803 d->addHistoryCommand_in_slotRowUpdated_enabled = true;
01804
01805
01806 property.setValue(newValue);
01807 }
01808
01809 if (!addCommand) {
01810 d->addHistoryCommand_in_slotRowUpdated_enabled = false;
01811 d->addHistoryCommand_in_slotPropertyChanged_enabled = false;
01812 d->slotPropertyChanged_subType_enabled = false;
01813 }
01814
01815 if (propertyName == "caption") {
01816 if (!addCommand) {
01817 d->slotBeforeCellChanged_enabled = false;
01818 }
01819 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_CAPTION, newValue);
01820 d->view->data()->saveRowChanges(*item);
01821 if (!addCommand) {
01822 d->slotBeforeCellChanged_enabled = true;
01823 }
01824 }
01825 else if (propertyName == "description") {
01826 if (!addCommand) {
01827 d->slotBeforeCellChanged_enabled = false;
01828 }
01829 d->view->data()->updateRowEditBuffer(item, COLUMN_ID_DESC, newValue);
01830 if (!addCommand) {
01831 d->slotBeforeCellChanged_enabled = true;
01832 }
01833 d->view->data()->saveRowChanges(*item);
01834 }
01835 if (!addCommand) {
01836 d->addHistoryCommand_in_slotPropertyChanged_enabled = true;
01837 d->addHistoryCommand_in_slotRowUpdated_enabled = true;
01838 d->slotPropertyChanged_subType_enabled = true;
01839 }
01840 d->view->updateRow( row );
01841 }
01842
01843 void KexiTableDesignerView::changeFieldProperty( int fieldUID,
01844 const QCString& propertyName, const QVariant& newValue,
01845 KoProperty::Property::ListData* const listData, bool addCommand )
01846 {
01847
01848 const int row = d->sets->findRowForPropertyValue("uid", fieldUID);
01849 if (row<0) {
01850 kexipluginswarn << "KexiTableDesignerView::changeFieldProperty(): field with uid="<<fieldUID<<" not found!"<<endl;
01851 return;
01852 }
01853 changeFieldPropertyForRow(row, propertyName, newValue, listData, addCommand);
01854 }
01855
01856 void KexiTableDesignerView::changePropertyVisibility(
01857 int fieldUID, const QCString& propertyName, bool visible )
01858 {
01859 #ifdef KEXI_DEBUG_GUI
01860 KexiUtils::addAlterTableActionDebug(QString("** changePropertyVisibility: \"")
01861 + QString(propertyName) + "\" to \"" + (visible ? "true" : "false") + "\"", 2);
01862 #endif
01863 if (!d->view->acceptRowEdit())
01864 return;
01865
01866
01867 const int row = d->sets->findRowForPropertyValue("uid", fieldUID);
01868 if (row<0)
01869 return;
01870 KoProperty::Set* set = d->sets->at( row );
01871 if (!set || !set->contains(propertyName))
01872 return;
01873
01874 KoProperty::Property &property = set->property(propertyName);
01875 if (property.isVisible() != visible) {
01876 property.setVisible(visible);
01877 propertySetReloaded(true);
01878 }
01879 }
01880
01881 void KexiTableDesignerView::propertySetSwitched()
01882 {
01883 KexiDataTable::propertySetSwitched();
01884
01885
01886
01887
01888 static_cast<KexiTablePart*>(parentDialog()->part())->lookupColumnPage()
01889 ->assignPropertySet(propertySet());
01890 }
01891
01892 #include "kexitabledesignerview.moc"