/* This file is part of the KDE project
Copyright ( C ) 2004 - 2007 Jaroslaw Staniek < js @ iidea . pl >
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation ; either
version 2 of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Library General Public License for more details .
You should have received a copy of the GNU Library General Public License
along with this program ; see the file COPYING . If not , write to
the Free Software Foundation , Inc . , 51 Franklin Street , Fifth Floor ,
* Boston , MA 02110 - 1301 , USA .
*/
# include "kexitabledesignerview.h"
# include "kexitabledesignerview_p.h"
# include "kexilookupcolumnpage.h"
# include "kexitabledesignercommands.h"
# include <tqlayout.h>
# include <tqlabel.h>
# include <tqsplitter.h>
# include <kiconloader.h>
# include <kdebug.h>
# include <tdelocale.h>
# include <tdeaction.h>
# include <tdepopupmenu.h>
# include <tdemessagebox.h>
# include <kiconeffect.h>
# include <koproperty/set.h>
# include <koproperty/utils.h>
# include <kexidb/cursor.h>
# include <kexidb/tableschema.h>
# include <kexidb/connection.h>
# include <kexidb/utils.h>
# include <kexidb/roweditbuffer.h>
# include <kexidb/error.h>
# include <kexidb/lookupfieldschema.h>
# include <kexiutils/identifier.h>
# include <kexiproject.h>
# include <keximainwindow.h>
# include <widget/tableview/kexidataawarepropertyset.h>
# include <widget/kexicustompropertyfactory.h>
# include <kexiutils/utils.h>
# include <kexidialogbase.h>
# include <kexitableview.h>
//#define MAX_FIELDS 101 //nice prime number
//! used only for BLOBs
# define DEFAULT_OBJECT_TYPE_VALUE "image"
//#define KexiTableDesignerView_DEBUG
//! @todo remove this when BLOBs are implemented
//#define KEXI_NO_BLOB_FIELDS
using namespace KexiTableDesignerCommands ;
//! @internal Used in tryCastTQVariant() anf canCastTQVariant()
static bool isIntegerTQVariant ( TQVariant : : Type t )
{
return t = = TQVariant : : LongLong
| | t = = TQVariant : : ULongLong
| | t = = TQVariant : : Int
| | t = = TQVariant : : UInt ;
}
//! @internal Used in tryCastTQVariant()
static bool canCastTQVariant ( TQVariant : : Type fromType , TQVariant : : Type toType )
{
return ( fromType = = TQVariant : : Int & & toType = = TQVariant : : UInt )
| | ( fromType = = TQVariant : : CString & & toType = = TQVariant : : String )
| | ( fromType = = TQVariant : : LongLong & & toType = = TQVariant : : ULongLong )
| | ( ( fromType = = TQVariant : : String | | fromType = = TQVariant : : CString )
& & ( isIntegerTQVariant ( toType ) | | toType = = TQVariant : : Double ) ) ;
}
/*! @internal
\ return a variant value converted from \ a fromVal to \ a toType type .
Null TQVariant is returned if \ a fromVal ' s type and \ a toType type
are incompatible . */
static TQVariant tryCastTQVariant ( const TQVariant & fromVal , TQVariant : : Type toType )
{
const TQVariant : : Type fromType = fromVal . type ( ) ;
if ( fromType = = toType )
return fromVal ;
if ( canCastTQVariant ( fromType , toType ) | | canCastTQVariant ( toType , fromType )
| | ( isIntegerTQVariant ( fromType ) & & toType = = TQVariant : : Double ) )
{
TQVariant res ( fromVal ) ;
if ( res . cast ( toType ) )
return res ;
}
return TQVariant ( ) ;
}
KexiTableDesignerView : : KexiTableDesignerView ( KexiMainWindow * win , TQWidget * parent )
: KexiDataTable ( win , parent , " KexiTableDesignerView " , false /*not db-aware*/ )
, KexiTableDesignerInterface ( )
, d ( new KexiTableDesignerViewPrivate ( this ) )
{
//needed for custom "identifier" property editor widget
KexiCustomPropertyFactory : : init ( ) ;
KexiDB : : Connection * conn = mainWin ( ) - > project ( ) - > dbConnection ( ) ;
d - > view = dynamic_cast < KexiTableView * > ( mainWidget ( ) ) ;
d - > data = new KexiTableViewData ( ) ;
if ( conn - > isReadOnly ( ) )
d - > data - > setReadOnly ( true ) ;
d - > data - > setInsertingEnabled ( false ) ;
KexiTableViewColumn * col = new KexiTableViewColumn ( " pk " , KexiDB : : Field : : Text , TQString ( ) ,
i18n ( " Additional information about the field " ) ) ;
col - > setIcon ( KexiUtils : : colorizeIconToTextColor ( SmallIcon ( " application-vnd.tde.info " ) , d - > view - > palette ( ) ) ) ;
col - > setHeaderTextVisible ( false ) ;
col - > field ( ) - > setSubType ( " TDEIcon " ) ;
col - > setReadOnly ( true ) ;
d - > data - > addColumn ( col ) ;
// col = new KexiTableViewColumn("name", KexiDB::Field::Text, i18n("Field Name"),
col = new KexiTableViewColumn ( " caption " , KexiDB : : Field : : Text , i18n ( " Field Caption " ) ,
i18n ( " Describes caption for the field " ) ) ;
// KexiUtils::Validator *vd = new KexiUtils::IdentifierValidator();
// vd->setAcceptsEmptyValue(true);
// col->setValidator( vd );
d - > data - > addColumn ( col ) ;
col = new KexiTableViewColumn ( " type " , KexiDB : : Field : : Enum , i18n ( " Data Type " ) ,
i18n ( " Describes data type for the field " ) ) ;
d - > data - > addColumn ( col ) ;
# ifdef KEXI_NO_BLOB_FIELDS
//! @todo remove this later
TQValueVector < TQString > types ( KexiDB : : Field : : LastTypeGroup - 1 ) ; //don't show last type (BLOB)
# else
TQValueVector < TQString > types ( KexiDB : : Field : : LastTypeGroup ) ;
# endif
d - > maxTypeNameTextWidth = 0 ;
TQFontMetrics fm ( font ( ) ) ;
for ( uint i = 1 ; i < = types . count ( ) ; i + + ) {
types [ i - 1 ] = KexiDB : : Field : : typeGroupName ( i ) ;
d - > maxTypeNameTextWidth = TQMAX ( d - > maxTypeNameTextWidth , fm . width ( types [ i - 1 ] ) ) ;
}
col - > field ( ) - > setEnumHints ( types ) ;
d - > data - > addColumn ( col = new KexiTableViewColumn ( " comments " , KexiDB : : Field : : Text , i18n ( " Comments " ) ,
i18n ( " Describes additional comments for the field " ) ) ) ;
d - > view - > setSpreadSheetMode ( ) ;
connect ( d - > data , TQT_SIGNAL ( aboutToChangeCell ( KexiTableItem * , int , TQVariant & , KexiDB : : ResultInfo * ) ) ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotBeforeCellChanged ( KexiTableItem * , int , TQVariant & , KexiDB : : ResultInfo * ) ) ) ;
connect ( d - > data , TQT_SIGNAL ( rowUpdated ( KexiTableItem * ) ) ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotRowUpdated ( KexiTableItem * ) ) ) ;
//connect(d->data, TQT_SIGNAL(aboutToInsertRow(KexiTableItem*,KexiDB::ResultInfo*,bool)),
// TQT_TQOBJECT(this), TQT_SLOT(slotAboutToInsertRow(KexiTableItem*,KexiDB::ResultInfo*,bool)));
connect ( d - > data , TQT_SIGNAL ( aboutToDeleteRow ( KexiTableItem & , KexiDB : : ResultInfo * , bool ) ) ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotAboutToDeleteRow ( KexiTableItem & , KexiDB : : ResultInfo * , bool ) ) ) ;
setMinimumSize ( d - > view - > minimumSizeHint ( ) . width ( ) , d - > view - > minimumSizeHint ( ) . height ( ) ) ;
d - > view - > setFocus ( ) ;
d - > sets = new KexiDataAwarePropertySet ( this , d - > view ) ;
connect ( d - > sets , TQT_SIGNAL ( rowDeleted ( ) ) , TQT_TQOBJECT ( this ) , TQT_SLOT ( updateActions ( ) ) ) ;
connect ( d - > sets , TQT_SIGNAL ( rowInserted ( ) ) , TQT_TQOBJECT ( this ) , TQT_SLOT ( slotRowInserted ( ) ) ) ;
d - > contextMenuTitle = new TDEPopupTitle ( d - > view - > contextMenu ( ) ) ;
d - > view - > contextMenu ( ) - > insertItem ( d - > contextMenuTitle , - 1 , 0 ) ;
connect ( d - > view - > contextMenu ( ) , TQT_SIGNAL ( aboutToShow ( ) ) , TQT_TQOBJECT ( this ) , TQT_SLOT ( slotAboutToShowContextMenu ( ) ) ) ;
plugSharedAction ( " tablepart_toggle_pkey " , TQT_TQOBJECT ( this ) , TQT_SLOT ( slotTogglePrimaryKey ( ) ) ) ;
d - > action_toggle_pkey = static_cast < TDEToggleAction * > ( sharedAction ( " tablepart_toggle_pkey " ) ) ;
d - > action_toggle_pkey - > plug ( d - > view - > contextMenu ( ) , 1 ) ; //add at the beginning
d - > view - > contextMenu ( ) - > insertSeparator ( 2 ) ;
setAvailable ( " tablepart_toggle_pkey " , ! conn - > isReadOnly ( ) ) ;
# ifndef KEXI_NO_UNDOREDO_ALTERTABLE
plugSharedAction ( " edit_undo " , TQT_TQOBJECT ( this ) , TQT_SLOT ( slotUndo ( ) ) ) ;
plugSharedAction ( " edit_redo " , TQT_TQOBJECT ( this ) , TQT_SLOT ( slotRedo ( ) ) ) ;
setAvailable ( " edit_undo " , false ) ;
setAvailable ( " edit_redo " , false ) ;
connect ( d - > history , TQT_SIGNAL ( commandExecuted ( KCommand * ) ) , TQT_TQOBJECT ( this ) , TQT_SLOT ( slotCommandExecuted ( KCommand * ) ) ) ;
# endif
# ifdef KEXI_DEBUG_GUI
KexiUtils : : addAlterTableActionDebug ( TQString ( ) ) ; //to create the tab
KexiUtils : : connectPushButtonActionForDebugWindow (
" simulateAlterTableExecution " , TQT_TQOBJECT ( this ) , TQT_SLOT ( slotSimulateAlterTableExecution ( ) ) ) ;
KexiUtils : : connectPushButtonActionForDebugWindow (
" executeRealAlterTable " , TQT_TQOBJECT ( this ) , TQT_SLOT ( executeRealAlterTable ( ) ) ) ;
# endif
}
KexiTableDesignerView : : ~ KexiTableDesignerView ( )
{
// removeCurrentPropertySet();
delete d ;
}
void KexiTableDesignerView : : initData ( )
{
//add column data
// d->data->clear();
d - > data - > deleteAllRows ( ) ;
int tableFieldCount = 0 ;
d - > primaryKeyExists = false ;
if ( tempData ( ) - > table ) {
tableFieldCount = tempData ( ) - > table - > fieldCount ( ) ;
//not needed d->sets->clear(tableFieldCount);
//recreate table data rows
for ( int i = 0 ; i < tableFieldCount ; i + + ) {
KexiDB : : Field * field = tempData ( ) - > table - > field ( i ) ;
KexiTableItem * item = d - > data - > createItem ( ) ; //new KexiTableItem(0);
if ( field - > isPrimaryKey ( ) ) {
( * item ) [ COLUMN_ID_ICON ] = " key " ;
d - > primaryKeyExists = true ;
}
else {
KexiDB : : LookupFieldSchema * lookupFieldSchema
= field - > table ( ) ? field - > table ( ) - > lookupFieldSchema ( * field ) : 0 ;
if ( lookupFieldSchema & & lookupFieldSchema - > rowSource ( ) . type ( ) ! = KexiDB : : LookupFieldSchema : : RowSource : : NoType
& & ! lookupFieldSchema - > rowSource ( ) . name ( ) . isEmpty ( ) )
{
( * item ) [ COLUMN_ID_ICON ] = " combo " ;
}
}
( * item ) [ COLUMN_ID_CAPTION ] = field - > captionOrName ( ) ;
( * item ) [ COLUMN_ID_TYPE ] = field - > typeGroup ( ) - 1 ; //-1 because type groups are counted from 1
( * item ) [ COLUMN_ID_DESC ] = field - > description ( ) ;
d - > data - > append ( item ) ;
//later! createPropertySet( i, field );
}
}
// else {
// d->sets->clear();//default size
// }
//add empty space
// const int columnsCount = d->data->columnsCount();
for ( int i = tableFieldCount ; i < ( int ) d - > sets - > size ( ) ; i + + ) {
// KexiTableItem *item = new KexiTableItem(columnsCount);//3 empty fields
d - > data - > append ( d - > data - > createItem ( ) ) ;
}
//set data for our spreadsheet: this will clear our sets
d - > view - > setData ( d - > data ) ;
//now recreate property sets
if ( tempData ( ) - > table ) {
for ( int i = 0 ; i < tableFieldCount ; i + + ) {
KexiDB : : Field * field = tempData ( ) - > table - > field ( i ) ;
createPropertySet ( i , * field ) ;
}
}
//column widths
d - > view - > setColumnWidth ( COLUMN_ID_ICON , IconSize ( TDEIcon : : Small ) + 10 ) ;
d - > view - > adjustColumnWidthToContents ( COLUMN_ID_CAPTION ) ; //adjust column width
d - > view - > setColumnWidth ( COLUMN_ID_TYPE , d - > maxTypeNameTextWidth + 2 * d - > view - > rowHeight ( ) ) ;
d - > view - > setColumnStretchEnabled ( true , COLUMN_ID_DESC ) ; //last column occupies the rest of the area
const int minCaptionColumnWidth = d - > view - > fontMetrics ( ) . width ( " wwwwwwwwwww " ) ;
if ( minCaptionColumnWidth > d - > view - > columnWidth ( COLUMN_ID_CAPTION ) )
d - > view - > setColumnWidth ( COLUMN_ID_CAPTION , minCaptionColumnWidth ) ;
setDirty ( false ) ;
d - > view - > setCursorPosition ( 0 , COLUMN_ID_CAPTION ) ; //set @ name column
propertySetSwitched ( ) ;
}
//! Gets subtype strings and names for type \a fieldType
void
KexiTableDesignerView : : getSubTypeListData ( KexiDB : : Field : : TypeGroup fieldTypeGroup ,
TQStringList & stringsList , TQStringList & namesList )
{
/* disabled - "mime" is moved from subType to "objectType" custom property
if ( fieldTypeGroup = = KexiDB : : Field : : BLOBGroup ) {
// special case: BLOB type uses "mime-based" subtypes
//! @todo hardcoded!
stringsList < < " image " ;
namesList < < i18n ( " Image object type " , " Image " ) ;
}
else { */
stringsList = KexiDB : : typeStringsForGroup ( fieldTypeGroup ) ;
namesList = KexiDB : : typeNamesForGroup ( fieldTypeGroup ) ;
// }
kexipluginsdbg < < " KexiTableDesignerView::getSubTypeListData(): subType strings: " < <
stringsList . join ( " | " ) < < " \n names: " < < namesList . join ( " | " ) < < endl ;
}
KoProperty : : Set *
KexiTableDesignerView : : createPropertySet ( int row , const KexiDB : : Field & field , bool newOne )
{
TQString typeName = " KexiDB::Field:: " + field . typeGroupString ( ) ;
KoProperty : : Set * set = new KoProperty : : Set ( d - > sets , typeName ) ;
if ( mainWin ( ) - > project ( ) - > dbConnection ( ) - > isReadOnly ( ) )
set - > setReadOnly ( true ) ;
// connect(buff,TQT_SIGNAL(propertyChanged(KexiPropertyBuffer&,KexiProperty&)),
// TQT_TQOBJECT(this), TQT_SLOT(slotPropertyChanged(KexiPropertyBuffer&,KexiProperty&)));
KoProperty : : Property * prop ;
set - > addProperty ( prop = new KoProperty : : Property ( " uid " , d - > generateUniqueId ( ) , " " ) ) ;
prop - > setVisible ( false ) ;
//meta-info for property editor
set - > addProperty ( prop = new KoProperty : : Property ( " this:classString " , i18n ( " Table field " ) ) ) ;
prop - > setVisible ( false ) ;
set - > addProperty ( prop = new KoProperty : : Property ( " this:iconName " ,
//! \todo add table_field icon
" lineedit " //"table_field"
) ) ;
prop - > setVisible ( false ) ;
set - > addProperty ( prop = new KoProperty : : Property ( " this:useCaptionAsObjectName " ,
TQVariant ( true , 1 ) , TQString ( ) ) ) ; //we want "caption" to be displayed in the header, not name
prop - > setVisible ( false ) ;
//name
set - > addProperty ( prop
= new KoProperty : : Property ( " name " , TQVariant ( field . name ( ) ) , i18n ( " Name " ) ,
TQString ( ) , KexiCustomPropertyFactory : : Identifier ) ) ;
//type
set - > addProperty ( prop
= new KoProperty : : Property ( " type " , TQVariant ( field . type ( ) ) , i18n ( " Type " ) ) ) ;
# ifndef KexiTableDesignerView_DEBUG
prop - > setVisible ( false ) ; //always hidden
# endif
//subtype
TQStringList typeStringList , typeNameList ;
getSubTypeListData ( field . typeGroup ( ) , typeStringList , typeNameList ) ;
/* disabled - "mime" is moved from subType to "objectType" custom property
TQString subTypeValue ;
if ( field . typeGroup ( ) = = KexiDB : : Field : : BLOBGroup ) {
// special case: BLOB type uses "mime-based" subtypes
//! @todo this should be retrieved from KexiDB::Field when BLOB supports many different mimetypes
subTypeValue = slist . first ( ) ;
}
else { */
TQString subTypeValue = field . typeString ( ) ;
//}
set - > addProperty ( prop = new KoProperty : : Property ( " subType " ,
typeStringList , typeNameList , subTypeValue , i18n ( " Subtype " ) ) ) ;
// objectType
TQStringList objectTypeStringList , objectTypeNameList ;
//! @todo this should be retrieved from KexiDB::Field when BLOB supports many different mimetypes
objectTypeStringList < < " image " ;
objectTypeNameList < < i18n ( " Image object type " , " Image " ) ;
TQString objectTypeValue ( field . customProperty ( " objectType " ) . toString ( ) ) ;
if ( objectTypeValue . isEmpty ( ) )
objectTypeValue = DEFAULT_OBJECT_TYPE_VALUE ;
set - > addProperty ( prop = new KoProperty : : Property ( " objectType " ,
objectTypeStringList , objectTypeNameList , objectTypeValue , i18n ( " Subtype " ) /*todo other i18n string?*/ ) ) ;
set - > addProperty ( prop
= new KoProperty : : Property ( " caption " , TQVariant ( field . caption ( ) ) , i18n ( " Caption " ) ) ) ;
prop - > setVisible ( false ) ; //always hidden
set - > addProperty ( prop
= new KoProperty : : Property ( " description " , TQVariant ( field . description ( ) ) ) ) ;
prop - > setVisible ( false ) ; //always hidden
set - > addProperty ( prop
= new KoProperty : : Property ( " unsigned " , TQVariant ( field . isUnsigned ( ) , 4 ) , i18n ( " Unsigned Number " ) ) ) ;
set - > addProperty ( prop
= new KoProperty : : Property ( " length " , ( int ) field . length ( ) /*200?*/ , i18n ( " Length " ) ) ) ;
set - > addProperty ( prop
= new KoProperty : : Property ( " precision " , ( int ) field . precision ( ) /*200?*/ , i18n ( " Precision " ) ) ) ;
# ifdef KEXI_NO_UNFINISHED
prop - > setVisible ( false ) ;
# endif
set - > addProperty ( prop
= new KoProperty : : Property ( " visibleDecimalPlaces " , field . visibleDecimalPlaces ( ) , i18n ( " Visible Decimal Places " ) ) ) ;
prop - > setOption ( " min " , - 1 ) ;
prop - > setOption ( " minValueText " , i18n ( " Auto Decimal Places " , " Auto " ) ) ;
//! @todo set reasonable default for column width
set - > addProperty ( prop
= new KoProperty : : Property ( " width " , ( int ) field . width ( ) /*200?*/ , i18n ( " Column Width " ) ) ) ;
# ifdef KEXI_NO_UNFINISHED
prop - > setVisible ( false ) ;
# endif
set - > addProperty ( prop
= new KoProperty : : Property ( " defaultValue " , field . defaultValue ( ) , i18n ( " Default Value " ) ,
TQString ( ) ,
//! @todo use "Variant" type here when supported by KoProperty
( KoProperty : : PropertyType ) field . variantType ( ) ) ) ;
prop - > setOption ( " 3rdState " , i18n ( " None " ) ) ;
// prop->setVisible(false);
set - > addProperty ( prop
= new KoProperty : : Property ( " primaryKey " , TQVariant ( field . isPrimaryKey ( ) , 4 ) , i18n ( " Primary Key " ) ) ) ;
prop - > setIcon ( " key " ) ;
set - > addProperty ( prop
= new KoProperty : : Property ( " unique " , TQVariant ( field . isUniqueKey ( ) , 4 ) , i18n ( " Unique " ) ) ) ;
set - > addProperty ( prop
= new KoProperty : : Property ( " notNull " , TQVariant ( field . isNotNull ( ) , 4 ) , i18n ( " Required " ) ) ) ;
set - > addProperty ( prop
= new KoProperty : : Property ( " allowEmpty " , TQVariant ( ! field . isNotEmpty ( ) , 4 ) , i18n ( " Allow Zero \n Size " ) ) ) ;
set - > addProperty ( prop
= new KoProperty : : Property ( " autoIncrement " , TQVariant ( field . isAutoIncrement ( ) , 4 ) , i18n ( " Autonumber " ) ) ) ;
prop - > setIcon ( " autonumber " ) ;
set - > addProperty ( prop
= new KoProperty : : Property ( " indexed " , TQVariant ( field . isIndexed ( ) , 4 ) , i18n ( " Indexed " ) ) ) ;
//- properties related to lookup columns (used and set by the "lookup column" tab in the property pane)
KexiDB : : LookupFieldSchema * lookupFieldSchema = field . table ( ) ? field . table ( ) - > lookupFieldSchema ( field ) : 0 ;
set - > addProperty ( prop = new KoProperty : : Property ( " rowSource " ,
lookupFieldSchema ? lookupFieldSchema - > rowSource ( ) . name ( ) : TQString ( ) , i18n ( " Row Source " ) ) ) ;
prop - > setVisible ( false ) ;
set - > addProperty ( prop = new KoProperty : : Property ( " rowSourceType " ,
lookupFieldSchema ? lookupFieldSchema - > rowSource ( ) . typeName ( ) : TQString ( ) , i18n ( " Row Source \n Type " ) ) ) ;
prop - > setVisible ( false ) ;
set - > addProperty ( prop
= new KoProperty : : Property ( " boundColumn " ,
lookupFieldSchema ? lookupFieldSchema - > boundColumn ( ) : - 1 , i18n ( " Bound Column " ) ) ) ;
prop - > setVisible ( false ) ;
//! @todo this is backward-compatible code for "single visible column" implementation
//! for multiple columns, only the first is displayed, so there is a data loss is GUI is used
//! -- special koproperty editor needed
int visibleColumn = - 1 ;
if ( lookupFieldSchema & & ! lookupFieldSchema - > visibleColumns ( ) . isEmpty ( ) )
visibleColumn = lookupFieldSchema - > visibleColumns ( ) . first ( ) ;
set - > addProperty ( prop
= new KoProperty : : Property ( " visibleColumn " , visibleColumn , i18n ( " Visible Column " ) ) ) ;
prop - > setVisible ( false ) ;
//! @todo support columnWidths(), columnHeadersVisible(), maximumListRows(), limitToList(), displayWidget()
//----
d - > updatePropertiesVisibility ( field . type ( ) , * set ) ;
connect ( set , TQT_SIGNAL ( propertyChanged ( KoProperty : : Set & , KoProperty : : Property & ) ) ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotPropertyChanged ( KoProperty : : Set & , KoProperty : : Property & ) ) ) ;
d - > sets - > insert ( row , set , newOne ) ;
return set ;
}
void KexiTableDesignerView : : updateActions ( bool activated )
{
Q_UNUSED ( activated ) ;
/*! \todo check if we can set pkey for this column type (eg. BLOB?) */
setAvailable ( " tablepart_toggle_pkey " , propertySet ( ) ! = 0 & & ! mainWin ( ) - > project ( ) - > dbConnection ( ) - > isReadOnly ( ) ) ;
if ( ! propertySet ( ) )
return ;
KoProperty : : Set & set = * propertySet ( ) ;
d - > slotTogglePrimaryKeyCalled = true ;
d - > action_toggle_pkey - > setChecked ( set [ " primaryKey " ] . value ( ) . toBool ( ) ) ;
d - > slotTogglePrimaryKeyCalled = false ;
}
void KexiTableDesignerView : : slotUpdateRowActions ( int row )
{
KexiDataTable : : slotUpdateRowActions ( row ) ;
updateActions ( ) ;
}
void KexiTableDesignerView : : slotTogglePrimaryKey ( )
{
if ( d - > slotTogglePrimaryKeyCalled )
return ;
d - > slotTogglePrimaryKeyCalled = true ;
if ( ! propertySet ( ) )
return ;
KoProperty : : Set & set = * propertySet ( ) ;
bool isSet = ! set [ " primaryKey " ] . value ( ) . toBool ( ) ;
set . changeProperty ( " primaryKey " , TQVariant ( isSet , 1 ) ) ; //this will update all related properties as well
/* CommandGroup *setPrimaryKeyCommand;
if ( isSet ) {
setPrimaryKeyCommand = new CommandGroup ( i18n ( " Set primary key for field \" %1 \" " )
. arg ( set [ " name " ] . value ( ) . toString ( ) ) ) ;
}
else {
setPrimaryKeyCommand = new CommandGroup ( i18n ( " Unset primary key for field \" %1 \" " )
. arg ( set [ " name " ] . value ( ) . toString ( ) ) ) ;
}
switchPrimaryKey ( set , isSet , false , setPrimaryKeyCommand ) ; */
//addHistoryCommand( setPrimaryKeyCommand, false /* !execute */ );
d - > slotTogglePrimaryKeyCalled = false ;
}
void KexiTableDesignerView : : switchPrimaryKey ( KoProperty : : Set & propertySet ,
bool set , bool aWasPKey , CommandGroup * commandGroup )
{
const bool was_pkey = aWasPKey | | propertySet [ " primaryKey " ] . value ( ) . toBool ( ) ;
// propertySet["primaryKey"] = TQVariant(set, 1);
d - > setPropertyValueIfNeeded ( propertySet , " primaryKey " , TQVariant ( set , 1 ) , commandGroup ) ;
if ( & propertySet = = this - > propertySet ( ) ) {
//update action and icon @ column 0 (only if we're changing current property set)
d - > action_toggle_pkey - > setChecked ( set ) ;
if ( d - > view - > selectedItem ( ) ) {
//show key in the table
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > clearRowEditBuffer ( ) ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( d - > view - > selectedItem ( ) , COLUMN_ID_ICON ,
TQVariant ( set ? " key " : " " ) ) ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > saveRowChanges ( * d - > view - > selectedItem ( ) , true ) ;
}
if ( was_pkey | | set ) //change flag only if we're setting pk or really clearing it
d - > primaryKeyExists = set ;
}
if ( set ) {
//primary key is set, remove old pkey if exists
KoProperty : : Set * s = 0 ;
int i ;
const int count = ( int ) d - > sets - > size ( ) ;
for ( i = 0 ; i < count ; i + + ) {
s = d - > sets - > at ( i ) ;
if ( s & & s ! = & propertySet & & ( * s ) [ " primaryKey " ] . value ( ) . toBool ( ) & & i ! = d - > view - > currentRow ( ) )
break ;
}
if ( i < count ) { //remove
//(*s)["autoIncrement"] = TQVariant(false, 0);
d - > setPropertyValueIfNeeded ( * s , " autoIncrement " , TQVariant ( false , 0 ) , commandGroup ) ;
//(*s)["primaryKey"] = TQVariant(false, 0);
d - > setPropertyValueIfNeeded ( * s , " primaryKey " , TQVariant ( false , 0 ) , commandGroup ) ;
//remove key from table
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > clearRowEditBuffer ( ) ;
KexiTableItem * item = d - > view - > itemAt ( i ) ;
if ( item ) {
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_ICON , TQVariant ( ) ) ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > saveRowChanges ( * item , true ) ;
}
}
//set unsigned big-integer type
// d->view->KexiDataAwareObjectInterface::data()->saveRowChanges(*d->view->selectedItem());
d - > slotBeforeCellChanged_enabled = false ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > clearRowEditBuffer ( ) ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( d - > view - > selectedItem ( ) , COLUMN_ID_TYPE ,
TQVariant ( KexiDB : : Field : : IntegerGroup - 1 /*counting from 0*/ ) ) ;
// TQVariant(KexiDB::Field::typeGroupName(KexiDB::Field::IntegerGroup)));
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > saveRowChanges ( * d - > view - > selectedItem ( ) , true ) ;
//propertySet["subType"] = KexiDB::Field::typeString(KexiDB::Field::BigInteger);
d - > setPropertyValueIfNeeded ( propertySet , " subType " , KexiDB : : Field : : typeString ( KexiDB : : Field : : BigInteger ) ,
commandGroup ) ;
//propertySet["unsigned"] = TQVariant(true,4);
d - > setPropertyValueIfNeeded ( propertySet , " unsigned " , TQVariant ( true , 4 ) , commandGroup ) ;
/*todo*/
d - > slotBeforeCellChanged_enabled = true ;
}
updateActions ( ) ;
}
/*void KexiTableDesignerView::slotCellSelected(int, int row)
{
kdDebug ( ) < < " KexiTableDesignerView::slotCellSelected() " < < endl ;
if ( row = = m_row )
return ;
m_row = row ;
propertyBufferSwitched ( ) ;
} */
tristate KexiTableDesignerView : : beforeSwitchTo ( int mode , bool & dontStore )
{
if ( ! d - > view - > acceptRowEdit ( ) )
return false ;
/* if (mode==Kexi::DesignViewMode) {
initData ( ) ;
return true ;
}
else */
tristate res = true ;
if ( mode = = Kexi : : DataViewMode ) {
if ( ! dirty ( ) & & parentDialog ( ) - > neverSaved ( ) ) {
KMessageBox : : sorry ( this , i18n ( " Cannot switch to data view, because table design is empty. \n "
" First, please create your design. " ) ) ;
return cancelled ;
}
//<temporary>
else if ( dirty ( ) & & ! parentDialog ( ) - > neverSaved ( ) ) {
// cancelled = (KMessageBox::No == KMessageBox::questionYesNo(this, i18n("Saving changes for existing table design is not yet supported.\nDo you want to discard your changes now?")));
// KexiDB::Connection *conn = mainWin()->project()->dbConnection();
bool emptyTable ;
int r = KMessageBox : : warningYesNoCancel ( this ,
i18n ( " Saving changes for existing table design is now required. " )
+ " \n " + d - > messageForSavingChanges ( emptyTable , /* skip warning? */ ! isPhysicalAlteringNeeded ( ) ) ,
TQString ( ) ,
KStdGuiItem : : save ( ) , KStdGuiItem : : discard ( ) , TQString ( ) ,
KMessageBox : : Notify | KMessageBox : : Dangerous ) ;
if ( r = = KMessageBox : : Cancel )
res = cancelled ;
else
res = true ;
dontStore = ( r ! = KMessageBox : : Yes ) ;
if ( ! dontStore )
d - > dontAskOnStoreData = true ;
// if (dontStore)
// setDirty(false);
}
//</temporary>
//todo
return res ;
}
else if ( mode = = Kexi : : TextViewMode ) {
//todo
}
return res ;
}
tristate KexiTableDesignerView : : afterSwitchFrom ( int mode )
{
if ( mode = = Kexi : : NoViewMode | | mode = = Kexi : : DataViewMode ) {
initData ( ) ;
}
return true ;
}
KoProperty : : Set * KexiTableDesignerView : : propertySet ( )
{
return d - > sets ? d - > sets - > currentPropertySet ( ) : 0 ;
}
/*
void KexiTableDesignerView : : removeCurrentPropertySet ( )
{
const int r = d - > view - > currentRow ( ) ;
KoProperty : : Set * buf = d - > sets . at ( r ) ;
if ( ! buf )
return ;
buf - > debug ( ) ;
// m_currentBufferCleared = true;
d - > sets . remove ( r ) ;
propertysetswitched ( ) ;
// delete buf;
// m_currentBufferCleared = false;
}
*/
void KexiTableDesignerView : : slotBeforeCellChanged (
KexiTableItem * item , int colnum , TQVariant & newValue , KexiDB : : ResultInfo * /*result*/ )
{
if ( ! d - > slotBeforeCellChanged_enabled )
return ;
// kdDebug() << d->view->selectedItem() << " " << item
//<< " " << d->sets->at( d->view->currentRow() ) << " " << propertySet() << endl;
if ( colnum = = COLUMN_ID_CAPTION ) { //'caption'
// if (!item->at(1).toString().isEmpty() && item->at(1).isNull()) {
//if 'type' is not filled yet
if ( item - > at ( COLUMN_ID_TYPE ) . isNull ( ) ) {
//auto select 1st row of 'type' column
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_TYPE , TQVariant ( ( int ) 0 ) ) ;
}
KoProperty : : Set * propertySetForItem = d - > sets - > findPropertySetForItem ( * item ) ;
if ( propertySetForItem ) {
d - > addHistoryCommand_in_slotPropertyChanged_enabled = false ; //because we'll add the two changes as one KMacroCommand
TQString oldName ( propertySetForItem - > property ( " name " ) . value ( ) . toString ( ) ) ;
TQString oldCaption ( propertySetForItem - > property ( " caption " ) . value ( ) . toString ( ) ) ;
//we need to create the action now as set["name"] will be changed soon..
ChangeFieldPropertyCommand * changeCaptionCommand
= new ChangeFieldPropertyCommand ( this , * propertySetForItem , " caption " , oldCaption , newValue ) ;
//update field caption and name
propertySetForItem - > changeProperty ( " caption " , newValue ) ;
propertySetForItem - > changeProperty ( " name " , newValue ) ; // "name" prop. is of custom type Identifier, so this assignment
// will automatically convert newValue to an valid identifier
//remember this action containing 2 subactions
CommandGroup * changeCaptionAndNameCommand = new CommandGroup (
i18n ( " Change \" %1 \" field's name to \" %2 \" and caption from \" %3 \" to \" %4 \" " )
. arg ( oldName ) . arg ( propertySetForItem - > property ( " name " ) . value ( ) . toString ( ) )
. arg ( oldCaption ) . arg ( newValue . toString ( ) ) ) ;
changeCaptionAndNameCommand - > addCommand ( changeCaptionCommand ) ;
// new ChangeFieldPropertyCommand( this, *propertySetForItem,
// "caption", oldCaption, newValue)
// );
changeCaptionAndNameCommand - > addCommand (
new ChangeFieldPropertyCommand ( this , * propertySetForItem ,
" name " , oldName , propertySetForItem - > property ( " name " ) . value ( ) . toString ( ) )
) ;
addHistoryCommand ( changeCaptionAndNameCommand , false /* !execute */ ) ;
d - > addHistoryCommand_in_slotPropertyChanged_enabled = true ;
}
}
else if ( colnum = = COLUMN_ID_TYPE ) { //'type'
if ( newValue . isNull ( ) ) {
//'type' col will be cleared: clear all other columns as well
d - > slotBeforeCellChanged_enabled = false ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_ICON , TQVariant ( ) ) ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_CAPTION , TQVariant ( TQString ( ) ) ) ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_DESC , TQVariant ( ) ) ;
d - > slotBeforeCellChanged_enabled = true ;
return ;
}
KoProperty : : Set * propertySetForItem = d - > sets - > findPropertySetForItem ( * item ) ;
if ( ! propertySetForItem )
return ;
KoProperty : : Set & set = * propertySetForItem ; //propertySet();
//'type' col is changed (existed before)
//-get type group number
KexiDB : : Field : : TypeGroup fieldTypeGroup ;
int i_fieldTypeGroup = newValue . toInt ( ) + 1 /*counting from 1*/ ;
if ( i_fieldTypeGroup < 1 | | i_fieldTypeGroup >
# ifdef KEXI_NO_BLOB_FIELDS
//! @todo remove this later
( int ) KexiDB : : Field : : LastTypeGroup - 1 ) //don't show last (BLOB) type
# else
( int ) KexiDB : : Field : : LastTypeGroup )
# endif
return ;
fieldTypeGroup = static_cast < KexiDB : : Field : : TypeGroup > ( i_fieldTypeGroup ) ;
//-get 1st type from this group, and update 'type' property
KexiDB : : Field : : Type fieldType = KexiDB : : defaultTypeForGroup ( fieldTypeGroup ) ;
if ( fieldType = = KexiDB : : Field : : InvalidType )
fieldType = KexiDB : : Field : : Text ;
//moved down set["type"] = (int)fieldType;
// set["subType"] = KexiDB::Field::typeName(fieldType);
//-get subtypes for this type: keys (slist) and names (nlist)
TQStringList slist , nlist ;
getSubTypeListData ( fieldTypeGroup , slist , nlist ) ;
TQString subTypeValue ;
/* disabled - "mime" is moved from subType to "objectType" custom property
if ( fieldType = = KexiDB : : Field : : BLOB ) {
// special case: BLOB type uses "mime-based" subtypes
subTypeValue = slist . first ( ) ;
}
else { */
subTypeValue = KexiDB : : Field : : typeString ( fieldType ) ;
//}
KoProperty : : Property * subTypeProperty = & set [ " subType " ] ;
kexipluginsdbg < < subTypeProperty - > value ( ) < < endl ;
// *** this action contains subactions ***
CommandGroup * changeDataTypeCommand = new CommandGroup (
i18n ( " Change data type for field \" %1 \" to \" %2 \" " )
. arg ( set [ " name " ] . value ( ) . toString ( ) ) . arg ( KexiDB : : Field : : typeName ( fieldType ) ) ) ;
//kexipluginsdbg << "++++++++++" << slist << nlist << endl;
//update subtype list and value
const bool forcePropertySetReload
= KexiDB : : Field : : typeGroup ( KexiDB : : Field : : typeForString ( subTypeProperty - > value ( ) . toString ( ) ) )
! = fieldTypeGroup ; //<-- ?????
// const bool forcePropertySetReload = set["type"].value().toInt() != (int)fieldTypeGroup;
const bool useListData = slist . count ( ) > 1 ; //disabled-> || fieldType==KexiDB::Field::BLOB;
if ( ! useListData ) {
slist . clear ( ) ; //empty list will be passed
nlist . clear ( ) ;
}
d - > setPropertyValueIfNeeded ( set , " type " , ( int ) fieldType , changeDataTypeCommand ,
false /*!forceAddCommand*/ , true /*rememberOldValue*/ ) ;
// notNull and defaultValue=false is reasonable for boolean type
if ( fieldType = = KexiDB : : Field : : Boolean ) {
//! @todo maybe this is good for other data types as well?
d - > setPropertyValueIfNeeded ( set , " notNull " , TQVariant ( true , 1 ) , changeDataTypeCommand ,
false /*!forceAddCommand*/ , false /*!rememberOldValue*/ ) ;
d - > setPropertyValueIfNeeded ( set , " defaultValue " , TQVariant ( false , 1 ) , changeDataTypeCommand ,
false /*!forceAddCommand*/ , false /*!rememberOldValue*/ ) ;
}
/* if (useListData) {
{
subTypeProperty - > setListData ( slist , nlist ) ;
}
else {
subTypeProperty - > setListData ( 0 ) ;
} */
if ( set [ " primaryKey " ] . value ( ) . toBool ( ) = = true ) {
//primary keys require big int, so if selected type is not integer- remove PK
if ( fieldTypeGroup ! = KexiDB : : Field : : IntegerGroup ) {
/*not needed, line below will do the work
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_ICON , TQVariant ( ) ) ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > saveRowChanges ( * item ) ; */
//set["primaryKey"] = TQVariant(false, 1);
d - > setPropertyValueIfNeeded ( set , " primaryKey " , TQVariant ( false , 1 ) , changeDataTypeCommand ) ;
//! @todo should we display (passive?) dialog informing about cleared pkey?
}
}
// if (useListData)
// subTypeProperty->setValue( subTypeValue, false/*!rememberOldValue*/ );
d - > setPropertyValueIfNeeded ( set , " subType " , subTypeValue ,
changeDataTypeCommand , false , false /*!rememberOldValue*/ ,
& slist , & nlist ) ;
if ( d - > updatePropertiesVisibility ( fieldType , set , changeDataTypeCommand ) | | forcePropertySetReload ) {
//properties' visiblility changed: refresh prop. set
propertySetReloaded ( true ) ;
}
addHistoryCommand ( changeDataTypeCommand , false /* !execute */ ) ;
}
else if ( colnum = = COLUMN_ID_DESC ) { //'description'
KoProperty : : Set * propertySetForItem = d - > sets - > findPropertySetForItem ( * item ) ;
if ( ! propertySetForItem )
return ;
//update field desc.
TQVariant oldValue ( ( * propertySetForItem ) [ " description " ] . value ( ) ) ;
kexipluginsdbg < < oldValue < < endl ;
propertySetForItem - > changeProperty ( " description " , newValue ) ;
/*moved addHistoryCommand(
new ChangeFieldPropertyCommand ( this , * propertySetForItem ,
" description " , oldValue , newValue ) , false ) ; */
}
}
void KexiTableDesignerView : : slotRowUpdated ( KexiTableItem * item )
{
const int row = d - > view - > KexiDataAwareObjectInterface : : data ( ) - > findRef ( item ) ;
if ( row < 0 )
return ;
setDirty ( ) ;
//-check if the row was empty before updating
//if yes: we want to add a property set for this new row (field)
TQString fieldCaption ( item - > at ( COLUMN_ID_CAPTION ) . toString ( ) ) ;
const bool prop_set_allowed = ! item - > at ( COLUMN_ID_TYPE ) . isNull ( ) ;
if ( ! prop_set_allowed & & d - > sets - > at ( row ) /*propertySet()*/ ) {
//there is a property set, but it's not allowed - remove it:
d - > sets - > remove ( row ) ; //d->sets->removeCurrentPropertySet();
//clear 'type' column:
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > clearRowEditBuffer ( ) ;
// d->view->KexiDataAwareObjectInterface::data()->updateRowEditBuffer(d->view->selectedItem(), COLUMN_ID_TYPE, TQVariant());
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_TYPE , TQVariant ( ) ) ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > saveRowChanges ( * item ) ;
} else if ( prop_set_allowed & & ! d - > sets - > at ( row ) /*propertySet()*/ ) {
//-- create a new field:
KexiDB : : Field : : TypeGroup fieldTypeGroup = static_cast < KexiDB : : Field : : TypeGroup > (
item - > at ( COLUMN_ID_TYPE ) . toInt ( ) + 1 /*counting from 1*/ ) ;
int intFieldType = KexiDB : : defaultTypeForGroup ( fieldTypeGroup ) ;
if ( intFieldType = = 0 )
return ;
TQString description ( item - > at ( COLUMN_ID_DESC ) . toString ( ) ) ;
//todo: check uniqueness:
TQString fieldName ( KexiUtils : : string2Identifier ( fieldCaption ) ) ;
KexiDB : : Field : : Type fieldType = KexiDB : : intToFieldType ( intFieldType ) ;
KexiDB : : Field field ( //tmp
fieldName ,
fieldType ,
KexiDB : : Field : : NoConstraints ,
KexiDB : : Field : : NoOptions ,
/*length*/ 0 ,
/*precision*/ 0 ,
/*defaultValue*/ TQVariant ( ) ,
fieldCaption ,
description ,
/*width*/ 0 ) ;
// m_newTable->addField( field );
// reasonable case for boolean type: set notNull flag and "false" as default value
if ( fieldType = = KexiDB : : Field : : Boolean ) {
field . setNotNull ( true ) ;
field . setDefaultValue ( TQVariant ( false , 0 ) ) ;
}
kexipluginsdbg < < " KexiTableDesignerView::slotRowUpdated(): " < < field . debugString ( ) < < endl ;
//create a new property set:
KoProperty : : Set * newSet = createPropertySet ( row , field , true ) ;
//moved
//add a special property indicating that this is brand new buffer,
//not just changed
// KoProperty::Property* prop = new KoProperty::Property("newrow", TQVariant());
// prop->setVisible(false);
// newbuff->addProperty( prop );
//refresh property editor:
propertySetSwitched ( ) ;
if ( row > = 0 ) {
if ( d - > addHistoryCommand_in_slotRowUpdated_enabled ) {
addHistoryCommand ( new InsertFieldCommand ( this , row , * newSet /*propertySet()*/ ) , //, field /*will be copied*/
false /* !execute */ ) ;
}
}
else {
kexipluginswarn < < " KexiTableDesignerView::slotRowUpdated() row # not found ! " < < endl ;
}
}
}
void KexiTableDesignerView : : updateActions ( )
{
updateActions ( false ) ;
}
void KexiTableDesignerView : : slotPropertyChanged ( KoProperty : : Set & set , KoProperty : : Property & property )
{
// if (!d->slotPropertyChanged_enabled)
// return;
const TQCString pname = property . name ( ) ;
kexipluginsdbg < < " KexiTableDesignerView::slotPropertyChanged(): " < < pname < < " = " < < property . value ( )
< < " (oldvalue = " < < property . oldValue ( ) < < " ) " < < endl ;
// true is PK should be altered
bool changePrimaryKey = false ;
// true is PK should be set to true, otherwise unset
bool setPrimaryKey = false ;
if ( pname = = " primaryKey " & & d - > slotPropertyChanged_primaryKey_enabled ) {
changePrimaryKey = true ;
setPrimaryKey = property . value ( ) . toBool ( ) ;
}
// update "lookup column" icon
if ( pname = = " rowSource " | | pname = = " rowSourceType " ) {
//! @todo indicate invalid definitions of lookup columns as well using a special icon
//! (e.g. due to missing data source)
const int row = d - > sets - > findRowForPropertyValue ( " uid " , set [ " uid " ] . value ( ) . toInt ( ) ) ;
KexiTableItem * item = d - > view - > itemAt ( row ) ;
if ( item )
d - > updateIconForItem ( * item , set ) ;
}
//setting autonumber requires setting PK as well
CommandGroup * setAutonumberCommand = 0 ;
CommandGroup * toplevelCommand = 0 ;
if ( pname = = " autoIncrement " & & property . value ( ) . toBool ( ) = = true ) {
if ( set [ " primaryKey " ] . value ( ) . toBool ( ) = = false ) { //we need PKEY here!
TQString msg = TQString ( " <p> " )
+ i18n ( " Setting autonumber requires primary key to be set for current field. " ) + " </p> " ;
if ( d - > primaryKeyExists )
msg + = ( TQString ( " <p> " ) + i18n ( " Previous primary key will be removed. " ) + " </p> " ) ;
msg + = ( TQString ( " <p> " )
+ i18n ( " Do you want to create primary key for current field? "
" Click \" Cancel \" to cancel setting autonumber. " ) + " </p> " ) ;
if ( KMessageBox : : Yes = = KMessageBox : : questionYesNo ( this , msg ,
i18n ( " Setting Autonumber Field " ) ,
KGuiItem ( i18n ( " Create &Primary Key " ) , " key " ) , KStdGuiItem : : cancel ( ) ) )
{
changePrimaryKey = true ;
setPrimaryKey = true ;
//switchPrimaryKey(set, true);
// this will be toplevel command
setAutonumberCommand = new CommandGroup (
i18n ( " Assign autonumber for field \" %1 \" " ) . arg ( set [ " name " ] . value ( ) . toString ( ) ) ) ;
toplevelCommand = setAutonumberCommand ;
d - > setPropertyValueIfNeeded ( set , " autoIncrement " , TQVariant ( true , 1 ) , setAutonumberCommand ) ;
}
else {
setAutonumberCommand = new CommandGroup (
i18n ( " Remove autonumber from field \" %1 \" " ) . arg ( set [ " name " ] . value ( ) . toString ( ) ) ) ;
//d->slotPropertyChanged_enabled = false;
// set["autoIncrement"].setValue( TQVariant(false,1), false/*don't save old*/);
// d->slotPropertyChanged_enabled = true;
d - > setPropertyValueIfNeeded ( set , " autoIncrement " , TQVariant ( false , 1 ) , setAutonumberCommand ,
true /*forceAddCommand*/ , false /*rememberOldValue*/ ) ;
addHistoryCommand ( setAutonumberCommand , false /* !execute */ ) ;
return ;
}
}
}
//clear PK when these properties were set to false:
if ( ( pname = = " indexed " | | pname = = " unique " | | pname = = " notNull " )
& & set [ " primaryKey " ] . value ( ) . toBool ( ) & & property . value ( ) . toBool ( ) = = false )
{
//! @todo perhaps show a hint in help panel telling what happens?
changePrimaryKey = true ;
setPrimaryKey = false ;
// this will be toplevel command
CommandGroup * unsetIndexedOrUniquOrNotNullCommand = new CommandGroup (
i18n ( " Set \" %1 \" property for field \" %2 \" " ) . arg ( property . caption ( ) ) . arg ( set [ " name " ] . value ( ) . toString ( ) ) ) ;
toplevelCommand = unsetIndexedOrUniquOrNotNullCommand ;
d - > setPropertyValueIfNeeded ( set , pname , TQVariant ( false , 1 ) , unsetIndexedOrUniquOrNotNullCommand ) ;
if ( pname = = " notNull " ) {
//? d->setPropertyValueIfNeeded( set, "notNull", TQVariant(true,1), unsetIndexedOrUniquOrNotNullCommand );
d - > setPropertyValueIfNeeded ( set , " unique " , TQVariant ( false , 1 ) , unsetIndexedOrUniquOrNotNullCommand ) ;
}
}
if ( pname = = " defaultValue " ) {
KexiDB : : Field : : Type type = KexiDB : : intToFieldType ( set [ " type " ] . value ( ) . toInt ( ) ) ;
set [ " defaultValue " ] . setType ( ( KoProperty : : PropertyType ) KexiDB : : Field : : variantType ( type ) ) ;
}
if ( pname = = " subType " & & d - > slotPropertyChanged_subType_enabled ) {
d - > slotPropertyChanged_subType_enabled = false ;
if ( set [ " primaryKey " ] . value ( ) . toBool ( ) = = true
& & property . value ( ) . toString ( ) ! = KexiDB : : Field : : typeString ( KexiDB : : Field : : BigInteger ) )
{
kexipluginsdbg < < " INVALID " < < property . value ( ) . toString ( ) < < endl ;
// if (KMessageBox::Yes == KMessageBox::questionYesNo(this, msg,
// i18n("This field has promary key assigned. Setting autonumber field"),
// KGuiItem(i18n("Create &Primary Key"), "key"), KStdGuiItem::cancel() ))
}
KexiDB : : Field : : Type type = KexiDB : : intToFieldType ( set [ " type " ] . value ( ) . toInt ( ) ) ;
TQString typeName ;
/* disabled - "mime" is moved from subType to "objectType" custom property
if ( type = = KexiDB : : Field : : BLOB ) { //special case
//find i18n'd text
TQStringList stringsList , namesList ;
getSubTypeListData ( KexiDB : : Field : : BLOBGroup , stringsList , namesList ) ;
const int stringIndex = stringsList . findIndex ( property . value ( ) . toString ( ) ) ;
if ( - 1 = = stringIndex | | stringIndex > = ( int ) namesList . count ( ) )
typeName = property . value ( ) . toString ( ) ; //for sanity
else
typeName = namesList [ stringIndex ] ;
}
else { */
typeName = KexiDB : : Field : : typeName ( KexiDB : : Field : : typeForString ( property . value ( ) . toString ( ) ) ) ;
// }
// kdDebug() << property.value().toString() << endl;
// kdDebug() << set["type"].value() << endl;
// if (KexiDB::Field::typeGroup( set["type"].value().toInt() ) == (int)KexiDB::Field::TextGroup) {
CommandGroup * changeFieldTypeCommand = new CommandGroup (
i18n ( " Change type for field \" %1 \" to \" %2 \" " ) . arg ( set [ " name " ] . value ( ) . toString ( ) )
. arg ( typeName ) ) ;
d - > setPropertyValueIfNeeded ( set , " subType " , property . value ( ) , property . oldValue ( ) ,
changeFieldTypeCommand ) ;
kexipluginsdbg < < set [ " type " ] . value ( ) < < endl ;
const KexiDB : : Field : : Type newType = KexiDB : : Field : : typeForString ( property . value ( ) . toString ( ) ) ;
set [ " type " ] . setValue ( newType ) ;
// cast "defaultValue" property value to a new type
TQVariant oldDefVal ( set [ " defaultValue " ] . value ( ) ) ;
TQVariant newDefVal ( tryCastTQVariant ( oldDefVal , KexiDB : : Field : : variantType ( type ) ) ) ;
if ( oldDefVal . type ( ) ! = newDefVal . type ( ) )
set [ " defaultValue " ] . setType ( newDefVal . type ( ) ) ;
d - > setPropertyValueIfNeeded ( set , " defaultValue " , newDefVal , newDefVal ,
changeFieldTypeCommand ) ;
d - > updatePropertiesVisibility ( newType , set ) ;
//properties' visiblility changed: refresh prop. set
propertySetReloaded ( true ) ;
d - > slotPropertyChanged_subType_enabled = true ;
addHistoryCommand ( changeFieldTypeCommand , false /* !execute */ ) ;
return ;
// }
// d->slotPropertyChanged_subType_enabled = true;
// return;
}
if ( d - > addHistoryCommand_in_slotPropertyChanged_enabled & & ! changePrimaryKey /*we'll add multiple commands for PK*/ ) {
addHistoryCommand ( new ChangeFieldPropertyCommand ( this , set ,
property . name ( ) , property . oldValue ( ) /* ??? */ , property . value ( ) ) ,
false /* !execute */ ) ;
}
if ( changePrimaryKey ) {
d - > slotPropertyChanged_primaryKey_enabled = false ;
if ( setPrimaryKey ) {
//primary key implies some rules
//const bool prev_addHistoryCommand_in_slotPropertyChanged_enabled = d->addHistoryCommand_in_slotPropertyChanged_enabled;
// d->addHistoryCommand_in_slotPropertyChanged_enabled = false;
//this action contains subactions
CommandGroup * setPrimaryKeyCommand = new CommandGroup (
i18n ( " Set primary key for field \" %1 \" " )
. arg ( set [ " name " ] . value ( ) . toString ( ) ) ) ;
if ( toplevelCommand )
toplevelCommand - > addCommand ( setPrimaryKeyCommand ) ;
else
toplevelCommand = setPrimaryKeyCommand ;
d - > setPropertyValueIfNeeded ( set , " primaryKey " , TQVariant ( true , 1 ) , setPrimaryKeyCommand , true /*forceAddCommand*/ ) ;
d - > setPropertyValueIfNeeded ( set , " unique " , TQVariant ( true , 1 ) , setPrimaryKeyCommand ) ;
d - > setPropertyValueIfNeeded ( set , " notNull " , TQVariant ( true , 1 ) , setPrimaryKeyCommand ) ;
d - > setPropertyValueIfNeeded ( set , " allowEmpty " , TQVariant ( false , 1 ) , setPrimaryKeyCommand ) ;
d - > setPropertyValueIfNeeded ( set , " indexed " , TQVariant ( true , 1 ) , setPrimaryKeyCommand ) ;
//! \todo: add setting for this: "Integer PKeys have autonumber set by default"
d - > setPropertyValueIfNeeded ( set , " autoIncrement " , TQVariant ( true , 1 ) , setPrimaryKeyCommand ) ;
/* set["unique"] = TQVariant(true,1);
set [ " notNull " ] = TQVariant ( true , 1 ) ;
set [ " allowEmpty " ] = TQVariant ( false , 1 ) ;
set [ " indexed " ] = TQVariant ( true , 1 ) ;
set [ " autoIncrement " ] = TQVariant ( true , 1 ) ; */
// d->addHistoryCommand_in_slotPropertyChanged_enabled = prev_addHistoryCommand_in_slotPropertyChanged_enabled;
//down addHistoryCommand( toplevelCommand, false /* !execute */ );
}
else { //! set PK to false
//remember this action containing 2 subactions
CommandGroup * setPrimaryKeyCommand = new CommandGroup (
i18n ( " Unset primary key for field \" %1 \" " )
. arg ( set [ " name " ] . value ( ) . toString ( ) ) ) ;
if ( toplevelCommand )
toplevelCommand - > addCommand ( setPrimaryKeyCommand ) ;
else
toplevelCommand = setPrimaryKeyCommand ;
d - > setPropertyValueIfNeeded ( set , " primaryKey " , TQVariant ( false , 1 ) , setPrimaryKeyCommand , true /*forceAddCommand*/ ) ;
d - > setPropertyValueIfNeeded ( set , " autoIncrement " , TQVariant ( false , 1 ) , setPrimaryKeyCommand ) ;
// set["autoIncrement"] = TQVariant(false,1);
//down addHistoryCommand( toplevelCommand, false /* !execute */ );
}
switchPrimaryKey ( set , setPrimaryKey , true /*wasPKey*/ , toplevelCommand ) ;
d - > updatePropertiesVisibility (
KexiDB : : Field : : typeForString ( set [ " subType " ] . value ( ) . toString ( ) ) , set , toplevelCommand ) ;
addHistoryCommand ( toplevelCommand , false /* !execute */ ) ;
//properties' visiblility changed: refresh prop. set
propertySetReloaded ( true /*preservePrevSelection*/ ) ;
d - > slotPropertyChanged_primaryKey_enabled = true ;
}
}
void KexiTableDesignerView : : slotRowInserted ( )
{
updateActions ( ) ;
if ( d - > addHistoryCommand_in_slotRowInserted_enabled ) {
const int row = d - > view - > currentRow ( ) ;
if ( row > = 0 ) {
addHistoryCommand ( new InsertEmptyRowCommand ( this , row ) , false /* !execute */ ) ;
}
}
//TODO?
}
void KexiTableDesignerView : : slotAboutToDeleteRow (
KexiTableItem & item , KexiDB : : ResultInfo * result , bool repaint )
{
Q_UNUSED ( result )
Q_UNUSED ( repaint )
if ( item [ COLUMN_ID_ICON ] . toString ( ) = = " key " )
d - > primaryKeyExists = false ;
if ( d - > addHistoryCommand_in_slotAboutToDeleteRow_enabled ) {
const int row = d - > view - > KexiDataAwareObjectInterface : : data ( ) - > findRef ( & item ) ;
KoProperty : : Set * set = row > = 0 ? d - > sets - > at ( row ) : 0 ;
//set can be 0 here, what means "removing empty row"
addHistoryCommand (
new RemoveFieldCommand ( this , row , set ) ,
false /* !execute */
) ;
}
}
KexiDB : : Field * KexiTableDesignerView : : buildField ( const KoProperty : : Set & set ) const
{
//create a map of property values
kexipluginsdbg < < set [ " type " ] . value ( ) < < endl ;
TQMap < TQCString , TQVariant > values = KoProperty : : propertyValues ( set ) ;
//remove internal values, to avoid creating custom field's properties
TQMap < TQCString , TQVariant > : : Iterator it = values . begin ( ) ;
KexiDB : : Field * field = new KexiDB : : Field ( ) ;
while ( it ! = values . end ( ) ) {
const TQString propName ( it . key ( ) ) ;
if ( d - > internalPropertyNames . find ( propName . latin1 ( ) ) | | propName . startsWith ( " this: " )
| | ( /*sanity*/ propName = = " objectType " & & KexiDB : : Field : : BLOB ! = KexiDB : : intToFieldType ( set [ " type " ] . value ( ) . toInt ( ) ) ) )
{
TQMap < TQCString , TQVariant > : : Iterator it_tmp = it ;
+ + it ;
values . remove ( it_tmp ) ;
}
else
+ + it ;
}
//assign properties to the field
// (note that "objectType" property will be saved as custom property)
if ( ! KexiDB : : setFieldProperties ( * field , values ) ) {
delete field ;
return 0 ;
}
return field ;
}
tristate KexiTableDesignerView : : buildSchema ( KexiDB : : TableSchema & schema , bool beSilent )
{
if ( ! d - > view - > acceptRowEdit ( ) )
return cancelled ;
tristate res = true ;
//check for pkey; automatically add a pkey if user wanted
if ( ! d - > primaryKeyExists ) {
if ( beSilent ) {
kexipluginsdbg < < " KexiTableDesignerView::buildSchema(): no primay key defined... " < < endl ;
}
else {
const int questionRes = KMessageBox : : questionYesNoCancel ( this ,
i18n ( " <p>Table \" %1 \" has no <b>primary key</b> defined.</p> "
" <p>Although a primary key is not required, it is needed "
" for creating relations between database tables. "
" Do you want to add primary key automatically now?</p> "
" <p>If you want to add a primary key by hand, press \" Cancel \" "
" to cancel saving table design.</p> " ) . arg ( schema . name ( ) ) ,
TQString ( ) , KGuiItem ( i18n ( " &Add Primary Key " ) , " key " ) , KStdGuiItem : : no ( ) ,
" autogeneratePrimaryKeysOnTableDesignSaving " ) ;
if ( questionRes = = KMessageBox : : Cancel ) {
return cancelled ;
}
else if ( questionRes = = KMessageBox : : Yes ) {
//-find unique name, starting with, "id", "id2", ....
int i = 0 ;
int idIndex = 1 ; //means "id"
TQString pkFieldName ( " id%1 " ) ;
TQString pkFieldCaption ( i18n ( " Identifier%1 " , " Id%1 " ) ) ;
while ( i < ( int ) d - > sets - > size ( ) ) {
KoProperty : : Set * set = d - > sets - > at ( i ) ;
if ( set ) {
if ( ( * set ) [ " name " ] . value ( ) . toString ( )
= = pkFieldName . arg ( idIndex = = 1 ? TQString ( ) : TQString : : number ( idIndex ) )
| | ( * set ) [ " caption " ] . value ( ) . toString ( )
= = pkFieldCaption . arg ( idIndex = = 1 ? TQString ( ) : TQString : : number ( idIndex ) ) )
{
//try next id index
i = 0 ;
idIndex + + ;
continue ;
}
}
i + + ;
}
pkFieldName = pkFieldName . arg ( idIndex = = 1 ? TQString ( ) : TQString : : number ( idIndex ) ) ;
pkFieldCaption = pkFieldCaption . arg ( idIndex = = 1 ? TQString ( ) : TQString : : number ( idIndex ) ) ;
//ok, add PK with such unique name
d - > view - > insertEmptyRow ( 0 ) ;
d - > view - > setCursorPosition ( 0 , COLUMN_ID_CAPTION ) ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( d - > view - > selectedItem ( ) , COLUMN_ID_CAPTION ,
TQVariant ( pkFieldCaption ) ) ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( d - > view - > selectedItem ( ) , COLUMN_ID_TYPE ,
TQVariant ( KexiDB : : Field : : IntegerGroup - 1 /*counting from 0*/ ) ) ;
if ( ! d - > view - > KexiDataAwareObjectInterface : : data ( ) - > saveRowChanges ( * d - > view - > selectedItem ( ) , true ) ) {
return cancelled ;
}
slotTogglePrimaryKey ( ) ;
}
}
}
//check for duplicates
KoProperty : : Set * b = 0 ;
bool no_fields = true ;
int i ;
TQDict < char > names ( 1009 , false ) ;
char dummy ;
for ( i = 0 ; i < ( int ) d - > sets - > size ( ) ; i + + ) {
b = d - > sets - > at ( i ) ;
if ( b ) {
no_fields = false ;
const TQString name = ( * b ) [ " name " ] . value ( ) . toString ( ) ;
if ( name . isEmpty ( ) ) {
if ( beSilent ) {
kexipluginswarn < <
TQString ( " KexiTableDesignerView::buildSchema(): no field caption entered at row %1... " )
. arg ( i + 1 ) < < endl ;
}
else {
d - > view - > setCursorPosition ( i , COLUMN_ID_CAPTION ) ;
d - > view - > startEditCurrentCell ( ) ;
KMessageBox : : information ( this , i18n ( " You should enter field caption. " ) ) ;
}
res = cancelled ;
break ;
}
if ( names [ name ] ) {
break ;
}
names . insert ( name , & dummy ) ; //remember
}
}
if ( res = = true & & no_fields ) { //no fields added
if ( beSilent ) {
kexipluginswarn < <
" KexiTableDesignerView::buildSchema(): no field defined... " < < endl ;
}
else {
KMessageBox : : sorry ( this ,
i18n ( " You have added no fields. \n Every table should have at least one field. " ) ) ;
}
res = cancelled ;
}
if ( res = = true & & b & & i < ( int ) d - > sets - > size ( ) ) { //found a duplicate
if ( beSilent ) {
kexipluginswarn < <
TQString ( " KexiTableDesignerView::buildSchema(): duplicated field name '%1' " )
. arg ( ( * b ) [ " name " ] . value ( ) . toString ( ) ) < < endl ;
}
else {
d - > view - > setCursorPosition ( i , COLUMN_ID_CAPTION ) ;
d - > view - > startEditCurrentCell ( ) ;
//! @todo for "names hidden" mode we won't get this error because user is unable to change names
KMessageBox : : sorry ( this ,
i18n ( " You have added \" %1 \" field name twice. \n Field names cannot be repeated. "
" Correct name of the field. " )
. arg ( ( * b ) [ " name " ] . value ( ) . toString ( ) ) ) ;
}
res = cancelled ;
}
if ( res = = true ) {
//for every field, create KexiDB::Field definition
for ( i = 0 ; i < ( int ) d - > sets - > size ( ) ; i + + ) {
KoProperty : : Set * s = d - > sets - > at ( i ) ;
if ( ! s )
continue ;
KexiDB : : Field * f = buildField ( * s ) ;
if ( ! f )
continue ; //hmm?
schema . addField ( f ) ;
if ( ! ( * s ) [ " rowSource " ] . value ( ) . toString ( ) . isEmpty ( ) & & ! ( * s ) [ " rowSourceType " ] . value ( ) . toString ( ) . isEmpty ( ) ) {
//add lookup column
KexiDB : : LookupFieldSchema * lookupFieldSchema = new KexiDB : : LookupFieldSchema ( ) ;
lookupFieldSchema - > rowSource ( ) . setTypeByName ( ( * s ) [ " rowSourceType " ] . value ( ) . toString ( ) ) ;
lookupFieldSchema - > rowSource ( ) . setName ( ( * s ) [ " rowSource " ] . value ( ) . toString ( ) ) ;
lookupFieldSchema - > setBoundColumn ( ( * s ) [ " boundColumn " ] . value ( ) . toInt ( ) ) ;
//! @todo this is backward-compatible code for "single visible column" implementation
//! for multiple columns, only the first is displayed, so there is a data loss is GUI is used
//! -- special koproperty editor needed
TQValueList < uint > visibleColumns ;
const int visibleColumn = ( * s ) [ " visibleColumn " ] . value ( ) . toInt ( ) ;
if ( visibleColumn > = 0 )
visibleColumns . append ( ( uint ) visibleColumn ) ;
lookupFieldSchema - > setVisibleColumns ( visibleColumns ) ;
//! @todo support columnWidths(), columnHeadersVisible(), maximumListRows(), limitToList(), displayWidget()
if ( ! schema . setLookupFieldSchema ( f - > name ( ) , lookupFieldSchema ) ) {
kexipluginswarn < <
" KexiTableDesignerView::buildSchema(): !schema.setLookupFieldSchema() " < < endl ;
delete lookupFieldSchema ;
return false ;
}
}
}
}
return res ;
}
//! @internal
//! A recursive function for copying alter table actions from undo/redo commands.
static void copyAlterTableActions ( KCommand * command , KexiDB : : AlterTableHandler : : ActionList & actions )
{
CommandGroup * cmdGroup = dynamic_cast < CommandGroup * > ( command ) ;
if ( cmdGroup ) { //command group: flatten it
for ( TQPtrListIterator < KCommand > it ( cmdGroup - > commands ( ) ) ; it . current ( ) ; + + it )
copyAlterTableActions ( it . current ( ) , actions ) ;
return ;
}
Command * cmd = dynamic_cast < Command * > ( command ) ;
if ( ! cmd ) {
kexipluginswarn < < " KexiTableDesignerView::copyAlterTableActions(): cmd is not of type 'Command'! " < < endl ;
return ;
}
KexiDB : : AlterTableHandler : : ActionBase * action = cmd - > createAction ( ) ;
//some commands can contain null actions, e.g. "set visibility" command
if ( action )
actions . append ( action ) ;
}
tristate KexiTableDesignerView : : buildAlterTableActions ( KexiDB : : AlterTableHandler : : ActionList & actions )
{
actions . clear ( ) ;
kexipluginsdbg < < " KexiTableDesignerView::buildAlterTableActions(): " < < d - > history - > commands ( ) . count ( )
< < " top-level command(s) to process... " < < endl ;
for ( TQPtrListIterator < KCommand > it ( d - > history - > commands ( ) ) ; it . current ( ) ; + + it ) {
copyAlterTableActions ( it . current ( ) , actions ) ;
}
return true ;
}
KexiDB : : SchemaData * KexiTableDesignerView : : storeNewData ( const KexiDB : : SchemaData & sdata , bool & cancel )
{
if ( tempData ( ) - > table | | m_dialog - > schemaData ( ) ) //must not be
return 0 ;
//create table schema definition
tempData ( ) - > table = new KexiDB : : TableSchema ( sdata . name ( ) ) ;
tempData ( ) - > table - > setName ( sdata . name ( ) ) ;
tempData ( ) - > table - > setCaption ( sdata . caption ( ) ) ;
tempData ( ) - > table - > setDescription ( sdata . description ( ) ) ;
tristate res = buildSchema ( * tempData ( ) - > table ) ;
cancel = ~ res ;
//FINALLY: create table:
if ( res = = true ) {
//todo
KexiDB : : Connection * conn = mainWin ( ) - > project ( ) - > dbConnection ( ) ;
res = conn - > createTable ( tempData ( ) - > table ) ;
if ( res ! = true )
parentDialog ( ) - > setStatus ( conn , " " ) ;
}
if ( res = = true ) {
//we've current schema
tempData ( ) - > tableSchemaChangedInPreviousView = true ;
//not needed; KexiProject emits newItemStored signal //let project know the table is created
// mainWin()->project()->emitTableCreated(*tempData()->table);
}
else {
delete tempData ( ) - > table ;
tempData ( ) - > table = 0 ;
}
return tempData ( ) - > table ;
}
tristate KexiTableDesignerView : : storeData ( bool dontAsk )
{
if ( ! tempData ( ) - > table | | ! m_dialog - > schemaData ( ) ) {
d - > recentResultOfStoreData = false ;
return false ;
}
KexiDB : : Connection * conn = mainWin ( ) - > project ( ) - > dbConnection ( ) ;
KexiDB : : AlterTableHandler * alterTableHandler = 0 ;
KexiDB : : TableSchema * newTable = 0 ;
//- create action list for the alter table handler
KexiDB : : AlterTableHandler : : ActionList actions ;
tristate res = buildAlterTableActions ( actions ) ;
bool realAlterTableCanBeUsed = false ; //!< @todo this is temporary flag before we switch entirely to real alter table
if ( res = = true ) {
alterTableHandler = new KexiDB : : AlterTableHandler ( * conn ) ;
alterTableHandler - > setActions ( actions ) ;
if ( ! d - > tempStoreDataUsingRealAlterTable ) {
//only compute requirements
KexiDB : : AlterTableHandler : : ExecutionArguments args ;
args . onlyComputeRequirements = true ;
( void ) alterTableHandler - > execute ( tempData ( ) - > table - > name ( ) , args ) ;
res = args . result ;
if ( res = = true & & 0 = = ( args . requirements & ( 0xffff ^ KexiDB : : AlterTableHandler : : SchemaAlteringRequired ) ) )
realAlterTableCanBeUsed = true ;
}
}
if ( res = = true ) {
res = KexiTablePart : : askForClosingObjectsUsingTableSchema (
this , * conn , * tempData ( ) - > table ,
i18n ( " You are about to change the design of table \" %1 \" "
" but following objects using this table are opened: " )
. arg ( tempData ( ) - > table - > name ( ) ) ) ;
}
if ( res = = true ) {
if ( ! d - > tempStoreDataUsingRealAlterTable & & ! realAlterTableCanBeUsed ) {
//! @todo temp; remove this case:
delete alterTableHandler ;
alterTableHandler = 0 ;
// - inform about removing the current table and ask for confirmation
if ( ! d - > dontAskOnStoreData & & ! dontAsk ) {
bool emptyTable ;
const TQString msg = d - > messageForSavingChanges ( emptyTable ) ;
if ( ! emptyTable ) {
if ( KMessageBox : : No = = KMessageBox : : questionYesNo ( this , msg ) )
res = cancelled ;
}
}
d - > dontAskOnStoreData = false ; //one-time use
if ( ~ res ) {
d - > recentResultOfStoreData = res ;
return res ;
}
// keep old behaviour:
newTable = new KexiDB : : TableSchema ( ) ;
// copy the schema data
static_cast < KexiDB : : SchemaData & > ( * newTable ) = static_cast < KexiDB : : SchemaData & > ( * tempData ( ) - > table ) ;
res = buildSchema ( * newTable ) ;
kexipluginsdbg < < " KexiTableDesignerView::storeData() : BUILD SCHEMA: " < < endl ;
newTable - > debug ( ) ;
res = conn - > alterTable ( * tempData ( ) - > table , * newTable ) ;
if ( res ! = true )
parentDialog ( ) - > setStatus ( conn , " " ) ;
}
else {
KexiDB : : AlterTableHandler : : ExecutionArguments args ;
newTable = alterTableHandler - > execute ( tempData ( ) - > table - > name ( ) , args ) ;
res = args . result ;
kexipluginsdbg < < " KexiTableDesignerView::storeData() : ALTER TABLE EXECUTE: "
< < res . toString ( ) < < endl ;
if ( true ! = res ) {
alterTableHandler - > debugError ( ) ;
parentDialog ( ) - > setStatus ( alterTableHandler , " " ) ;
}
}
}
if ( res = = true ) {
//change current schema
tempData ( ) - > table = newTable ;
tempData ( ) - > tableSchemaChangedInPreviousView = true ;
d - > history - > clear ( ) ;
}
else {
delete newTable ;
}
delete alterTableHandler ;
d - > recentResultOfStoreData = res ;
return res ;
}
tristate KexiTableDesignerView : : simulateAlterTableExecution ( TQString * debugTarget )
{
# ifndef KEXI_NO_UNDOREDO_ALTERTABLE
# ifdef KEXI_DEBUG_GUI
if ( mainWin ( ) - > activeWindow ( ) ! = parentDialog ( ) ) //to avoid executing for multiple alter table views
return false ;
if ( ! tempData ( ) - > table | | ! m_dialog - > schemaData ( ) )
return false ;
KexiDB : : Connection * conn = mainWin ( ) - > project ( ) - > dbConnection ( ) ;
KexiDB : : AlterTableHandler : : ActionList actions ;
tristate res = buildAlterTableActions ( actions ) ;
//todo: result?
KexiDB : : AlterTableHandler alterTableHandler ( * conn ) ;
alterTableHandler . setActions ( actions ) ;
KexiDB : : AlterTableHandler : : ExecutionArguments args ;
if ( debugTarget ) {
args . debugString = debugTarget ;
}
else {
args . simulate = true ;
}
( void ) alterTableHandler . execute ( tempData ( ) - > table - > name ( ) , args ) ;
return args . result ;
# else
return false ;
# endif
# else
return false ;
# endif
}
void KexiTableDesignerView : : slotSimulateAlterTableExecution ( )
{
( void ) simulateAlterTableExecution ( 0 ) ;
}
tristate KexiTableDesignerView : : executeRealAlterTable ( )
{
TQSignal signal ;
signal . connect ( mainWin ( ) , TQT_SLOT ( slotProjectSave ( ) ) ) ;
d - > tempStoreDataUsingRealAlterTable = true ;
d - > recentResultOfStoreData = false ;
signal . activate ( ) ; //will call KexiMainWindowImpl::slotProjectSaveAs() and thus storeData()
d - > tempStoreDataUsingRealAlterTable = false ;
return d - > recentResultOfStoreData ;
}
KexiTablePart : : TempData * KexiTableDesignerView : : tempData ( ) const
{
return static_cast < KexiTablePart : : TempData * > ( parentDialog ( ) - > tempData ( ) ) ;
}
/*void KexiTableDesignerView::slotAboutToUpdateRow(
KexiTableItem * item , KexiDB : : RowEditBuffer * buffer , KexiDB : : ResultInfo * result )
{
KexiDB : : RowEditBuffer : : SimpleMap map = buffer - > simpleBuffer ( ) ;
buffer - > debug ( ) ;
TQVariant old_type = item - > at ( 1 ) ;
TQVariant * buf_type = buffer - > at ( d - > view - > field ( 1 ) - > name ( ) ) ;
//check if there is a type specified
// if ((old_type.isNull() && !buf_type) || (buf_type && buf_type->isNull())) {
//kdDebug() << "err" << endl;
//}
// allow = true;
// m_dirty = m_dirty | result->success;
} */
# ifdef KEXI_DEBUG_GUI
void KexiTableDesignerView : : debugCommand ( KCommand * command , int nestingLevel )
{
if ( dynamic_cast < Command * > ( command ) )
KexiUtils : : addAlterTableActionDebug ( dynamic_cast < Command * > ( command ) - > debugString ( ) , nestingLevel ) ;
else
KexiUtils : : addAlterTableActionDebug ( command - > name ( ) , nestingLevel ) ;
//show subcommands
if ( dynamic_cast < CommandGroup * > ( command ) ) {
for ( TQPtrListIterator < KCommand > it ( dynamic_cast < CommandGroup * > ( command ) - > commands ( ) ) ; it . current ( ) ; + + it ) {
debugCommand ( it . current ( ) , nestingLevel + 1 ) ;
}
}
}
# endif
void KexiTableDesignerView : : addHistoryCommand ( KCommand * command , bool execute )
{
# ifndef KEXI_NO_UNDOREDO_ALTERTABLE
# ifdef KEXI_DEBUG_GUI
debugCommand ( command , 0 ) ;
# endif
d - > history - > addCommand ( command , execute ) ;
updateUndoRedoActions ( ) ;
# endif
}
void KexiTableDesignerView : : updateUndoRedoActions ( )
{
# ifndef KEXI_NO_UNDOREDO_ALTERTABLE
setAvailable ( " edit_undo " , d - > historyActionCollection - > action ( " edit_undo " ) - > isEnabled ( ) ) ;
setAvailable ( " edit_redo " , d - > historyActionCollection - > action ( " edit_redo " ) - > isEnabled ( ) ) ;
# endif
}
void KexiTableDesignerView : : slotUndo ( )
{
# ifndef KEXI_NO_UNDOREDO_ALTERTABLE
# ifdef KEXI_DEBUG_GUI
KexiUtils : : addAlterTableActionDebug ( TQString ( " UNDO: " ) ) ;
# endif
d - > history - > undo ( ) ;
updateUndoRedoActions ( ) ;
# endif
}
void KexiTableDesignerView : : slotRedo ( )
{
# ifndef KEXI_NO_UNDOREDO_ALTERTABLE
# ifdef KEXI_DEBUG_GUI
KexiUtils : : addAlterTableActionDebug ( TQString ( " REDO: " ) ) ;
# endif
d - > history - > redo ( ) ;
updateUndoRedoActions ( ) ;
# endif
}
void KexiTableDesignerView : : slotCommandExecuted ( KCommand * command )
{
# ifdef KEXI_DEBUG_GUI
debugCommand ( command , 1 ) ;
# endif
}
void KexiTableDesignerView : : slotAboutToShowContextMenu ( )
{
//update title
if ( propertySet ( ) ) {
const KoProperty : : Set & set = * propertySet ( ) ;
TQString captionOrName ( set [ " caption " ] . value ( ) . toString ( ) ) ;
if ( captionOrName . isEmpty ( ) )
captionOrName = set [ " name " ] . value ( ) . toString ( ) ;
//! @todo show "field" icon
d - > contextMenuTitle - > setTitle ( i18n ( " Table field \" %1 \" " ) . arg ( captionOrName ) ) ;
}
else {
d - > contextMenuTitle - > setTitle ( i18n ( " Empty table row " , " Empty Row " ) ) ;
}
}
TQString KexiTableDesignerView : : debugStringForCurrentTableSchema ( tristate & result )
{
KexiDB : : TableSchema tempTable ;
//copy schema data
static_cast < KexiDB : : SchemaData & > ( tempTable ) = static_cast < KexiDB : : SchemaData & > ( * tempData ( ) - > table ) ;
result = buildSchema ( tempTable , true /*beSilent*/ ) ;
if ( true ! = result )
return TQString ( ) ;
return tempTable . debugString ( false /*without name*/ ) ;
}
// -- low-level actions used by undo/redo framework
void KexiTableDesignerView : : clearRow ( int row , bool addCommand )
{
if ( ! d - > view - > acceptRowEdit ( ) )
return ;
KexiTableItem * item = d - > view - > itemAt ( row ) ;
if ( ! item )
return ;
//remove from prop. set
d - > sets - > remove ( row ) ;
//clear row in table view (just clear value in COLUMN_ID_TYPE column)
// for (int i=0; i < (int)d->view->KexiDataAwareObjectInterface::data()->columnsCount(); i++) {
if ( ! addCommand ) {
d - > addHistoryCommand_in_slotRowUpdated_enabled = false ;
d - > addHistoryCommand_in_slotPropertyChanged_enabled = false ;
d - > slotBeforeCellChanged_enabled = false ;
}
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_TYPE , TQVariant ( ) ) ;
if ( ! addCommand ) {
d - > addHistoryCommand_in_slotRowUpdated_enabled = true ;
d - > addHistoryCommand_in_slotPropertyChanged_enabled = true ;
d - > slotBeforeCellChanged_enabled = true ;
}
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > saveRowChanges ( * item , true ) ;
}
void KexiTableDesignerView : : insertField ( int row , const TQString & caption , bool addCommand )
{
insertFieldInternal ( row , 0 , caption , addCommand ) ;
}
void KexiTableDesignerView : : insertField ( int row , KoProperty : : Set & set , bool addCommand )
{
insertFieldInternal ( row , & set , TQString ( ) , addCommand ) ;
}
void KexiTableDesignerView : : insertFieldInternal ( int row , KoProperty : : Set * set , //const KexiDB::Field& field,
const TQString & caption , bool addCommand )
{
if ( set & & ( ! set - > contains ( " type " ) | | ! set - > contains ( " caption " ) ) ) {
kexipluginswarn < < " KexiTableDesignerView::insertField(): no 'type' or 'caption' property in set! " < < endl ;
return ;
}
if ( ! d - > view - > acceptRowEdit ( ) )
return ;
KexiTableItem * item = d - > view - > itemAt ( row ) ;
if ( ! item )
return ;
if ( ! addCommand ) {
d - > addHistoryCommand_in_slotRowUpdated_enabled = false ;
d - > addHistoryCommand_in_slotPropertyChanged_enabled = false ;
d - > slotBeforeCellChanged_enabled = false ;
}
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_CAPTION ,
set ? ( * set ) [ " caption " ] . value ( ) : TQVariant ( caption ) ) ; //field.caption());
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_TYPE ,
set ? ( int ) KexiDB : : Field : : typeGroup ( ( * set ) [ " type " ] . value ( ) . toInt ( ) ) - 1 /*counting from 0*/
: ( ( ( int ) KexiDB : : Field : : TextGroup ) - 1 ) /*default type, counting from 0*/
) ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_DESC ,
set ? ( * set ) [ " description " ] . value ( ) : TQVariant ( ) ) ; //field.description());
if ( ! addCommand ) {
d - > slotBeforeCellChanged_enabled = true ;
}
//this will create a new property set:
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > saveRowChanges ( * item ) ;
if ( set ) {
KoProperty : : Set * newSet = d - > sets - > at ( row ) ;
if ( newSet ) {
* newSet = * set ; //deep copy
}
else {
kexipluginswarn < < " KexiTableDesignerView::insertField() !newSet, row== " < < row < < endl ;
}
}
if ( ! addCommand ) {
d - > addHistoryCommand_in_slotPropertyChanged_enabled = true ;
d - > addHistoryCommand_in_slotRowUpdated_enabled = true ;
}
d - > view - > updateRow ( row ) ;
propertySetReloaded ( true ) ;
}
void KexiTableDesignerView : : insertEmptyRow ( int row , bool addCommand )
{
if ( ! addCommand ) {
d - > addHistoryCommand_in_slotRowInserted_enabled = false ;
}
d - > view - > insertEmptyRow ( row ) ;
if ( ! addCommand ) {
d - > addHistoryCommand_in_slotRowInserted_enabled = true ;
}
}
/*void KexiTableDesignerView::deleteRow( int row )
{
d - > addHistoryCommand_in_slotAboutToDeleteRow_enabled = false ;
d - > view - > deleteItem ( d - > view - > KexiDataAwareObjectInterface : : data ( ) - > at ( row ) ) ;
d - > addHistoryCommand_in_slotAboutToDeleteRow_enabled = true ;
} */
void KexiTableDesignerView : : deleteRow ( int row , bool addCommand )
{
KexiTableItem * item = d - > view - > itemAt ( row ) ;
if ( ! item )
return ;
if ( ! addCommand ) {
d - > addHistoryCommand_in_slotAboutToDeleteRow_enabled = false ;
}
const bool res = d - > view - > deleteItem ( item ) ;
if ( ! addCommand ) {
d - > addHistoryCommand_in_slotAboutToDeleteRow_enabled = true ;
}
if ( ! res )
return ;
}
void KexiTableDesignerView : : changeFieldPropertyForRow ( int row ,
const TQCString & propertyName , const TQVariant & newValue ,
KoProperty : : Property : : ListData * const listData , bool addCommand )
{
# ifdef KEXI_DEBUG_GUI
KexiUtils : : addAlterTableActionDebug ( TQString ( " ** changeFieldProperty: \" " )
+ TQString ( propertyName ) + " \" to \" " + newValue . toString ( ) + " \" " , 2 /*nestingLevel*/ ) ;
# endif
if ( ! d - > view - > acceptRowEdit ( ) )
return ;
KoProperty : : Set * set = d - > sets - > at ( row ) ;
if ( ! set | | ! set - > contains ( propertyName ) )
return ;
KoProperty : : Property & property = set - > property ( propertyName ) ;
if ( listData ) {
if ( listData - > keys . isEmpty ( ) )
property . setListData ( 0 ) ;
else
property . setListData ( new KoProperty : : Property : : ListData ( * listData ) ) ;
}
if ( propertyName ! = " type " ) //delayed type update (we need to have subtype set properly)
property . setValue ( newValue ) ;
KexiTableItem * item = d - > view - > itemAt ( row ) ;
Q_ASSERT ( item ) ;
if ( propertyName = = " type " ) {
// d->addHistoryCommand_in_slotRowUpdated_enabled = false;
// d->addHistoryCommand_in_slotPropertyChanged_enabled = false;
d - > slotPropertyChanged_subType_enabled = false ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_TYPE ,
int ( KexiDB : : Field : : typeGroup ( newValue . toInt ( ) ) ) - 1 ) ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > saveRowChanges ( * item ) ;
d - > addHistoryCommand_in_slotRowUpdated_enabled = true ;
// d->addHistoryCommand_in_slotPropertyChanged_enabled = true;
// d->slotPropertyChanged_subType_enabled = true;
property . setValue ( newValue ) ; //delayed type update (we needed to have subtype set properly)
}
if ( ! addCommand ) {
d - > addHistoryCommand_in_slotRowUpdated_enabled = false ;
d - > addHistoryCommand_in_slotPropertyChanged_enabled = false ;
d - > slotPropertyChanged_subType_enabled = false ;
}
//special cases: properties displayed within the data grid:
if ( propertyName = = " caption " ) {
if ( ! addCommand ) {
d - > slotBeforeCellChanged_enabled = false ;
}
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_CAPTION , newValue ) ;
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > saveRowChanges ( * item ) ;
if ( ! addCommand ) {
d - > slotBeforeCellChanged_enabled = true ;
}
}
else if ( propertyName = = " description " ) {
if ( ! addCommand ) {
d - > slotBeforeCellChanged_enabled = false ;
}
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > updateRowEditBuffer ( item , COLUMN_ID_DESC , newValue ) ;
if ( ! addCommand ) {
d - > slotBeforeCellChanged_enabled = true ;
}
d - > view - > KexiDataAwareObjectInterface : : data ( ) - > saveRowChanges ( * item ) ;
}
if ( ! addCommand ) {
d - > addHistoryCommand_in_slotPropertyChanged_enabled = true ;
d - > addHistoryCommand_in_slotRowUpdated_enabled = true ;
d - > slotPropertyChanged_subType_enabled = true ;
}
d - > view - > updateRow ( row ) ;
}
void KexiTableDesignerView : : changeFieldProperty ( int fieldUID ,
const TQCString & propertyName , const TQVariant & newValue ,
KoProperty : : Property : : ListData * const listData , bool addCommand )
{
//find a property by UID
const int row = d - > sets - > findRowForPropertyValue ( " uid " , fieldUID ) ;
if ( row < 0 ) {
kexipluginswarn < < " KexiTableDesignerView::changeFieldProperty(): field with uid= " < < fieldUID < < " not found! " < < endl ;
return ;
}
changeFieldPropertyForRow ( row , propertyName , newValue , listData , addCommand ) ;
}
void KexiTableDesignerView : : changePropertyVisibility (
int fieldUID , const TQCString & propertyName , bool visible )
{
# ifdef KEXI_DEBUG_GUI
KexiUtils : : addAlterTableActionDebug ( TQString ( " ** changePropertyVisibility: \" " )
+ TQString ( propertyName ) + " \" to \" " + ( visible ? " true " : " false " ) + " \" " , 2 /*nestingLevel*/ ) ;
# endif
if ( ! d - > view - > acceptRowEdit ( ) )
return ;
//find a property by name
const int row = d - > sets - > findRowForPropertyValue ( " uid " , fieldUID ) ;
if ( row < 0 )
return ;
KoProperty : : Set * set = d - > sets - > at ( row ) ;
if ( ! set | | ! set - > contains ( propertyName ) )
return ;
KoProperty : : Property & property = set - > property ( propertyName ) ;
if ( property . isVisible ( ) ! = visible ) {
property . setVisible ( visible ) ;
propertySetReloaded ( true ) ;
}
}
void KexiTableDesignerView : : propertySetSwitched ( )
{
KexiDataTable : : propertySetSwitched ( ) ;
//if (parentDialog()!=parentDialog()->mainWin()->currentDialog())
// return; //this is not the current dialog's view
static_cast < KexiTablePart * > ( parentDialog ( ) - > part ( ) ) - > lookupColumnPage ( )
- > assignPropertySet ( propertySet ( ) ) ;
}
bool KexiTableDesignerView : : isPhysicalAlteringNeeded ( )
{
//- create action list for the alter table handler
KexiDB : : AlterTableHandler : : ActionList actions ;
tristate res = buildAlterTableActions ( actions ) ;
if ( res ! = true )
return true ;
KexiDB : : Connection * conn = mainWin ( ) - > project ( ) - > dbConnection ( ) ;
KexiDB : : AlterTableHandler * alterTableHandler = new KexiDB : : AlterTableHandler ( * conn ) ;
alterTableHandler - > setActions ( actions ) ;
//only compute requirements
KexiDB : : AlterTableHandler : : ExecutionArguments args ;
args . onlyComputeRequirements = true ;
( void ) alterTableHandler - > execute ( tempData ( ) - > table - > name ( ) , args ) ;
res = args . result ;
delete alterTableHandler ;
if ( res = = true & & 0 = = ( args . requirements & ( 0xffff ^ KexiDB : : AlterTableHandler : : SchemaAlteringRequired ) ) )
return false ;
return true ;
}
# include "kexitabledesignerview.moc"