1
/***************************************************************************
2
* Copyright (C) 2005 by Adam Treat *
5
* Copyright (C) 2004 by Scott Wheeler *
8
* This program is free software; you can redistribute it and/or modify *
9
* it under the terms of the GNU General Public License as published by *
10
* the Free Software Foundation; either version 2 of the License, or *
11
* (at your option) any later version. *
13
***************************************************************************/
16
#include <kmessagebox.h>
18
#include <kiconloader.h>
19
#include <klineedit.h>
21
#include <kpopupmenu.h>
24
#include <kinputdialog.h>
25
#include <kapplication.h>
33
#include <qeventloop.h>
35
#include <qwidgetstack.h>
36
#include <qsqldatabase.h>
38
#include <qsqlpropertymap.h>
44
#include "datatable.h"
46
#include "datatablesearch.h"
47
#include "actioncollection.h"
48
#include "datakiosk.h"
49
#include "databaseconnection.h"
50
#include "fieldeditordialogimpl.h"
51
#include "connectioneditordialogimpl.h"
52
#include "formlayout.h"
54
using namespace ActionCollection;
56
bool DataTable::m_visibleChanged = false;
58
DataTable::DataTable( Project *project ) :
59
QTabWidget( project->dataTableStack() ),
60
m_tableView( new DataTableView( this ) ),
61
m_tableEdit( new DataTableEdit( this ) ),
63
m_factory( new DataTableEditorFactory( this ) ),
64
m_propMap( new QSqlPropertyMap() ),
65
m_updatesAllowed( false )
68
setIconName( "table" );
69
m_project->setupDataTable( this, iconName() );
72
DataTable::DataTable( Project *project, DataTable* parent ) :
73
QTabWidget( project->dataTableStack() ),
74
m_tableView( new DataTableView( this ) ),
75
m_tableEdit( new DataTableEdit( this ) ),
77
m_factory( new DataTableEditorFactory( this ) ),
78
m_propMap( new QSqlPropertyMap() ),
79
m_updatesAllowed( false )
82
setIconName( "child" );
83
m_project->setupDataTable( this, iconName(), parent );
86
DataTable::~DataTable()
88
DataFieldList::iterator it = m_fieldList.begin();
89
for ( ; it != m_fieldList.end(); ++it )
92
delete m_tableView->sqlCursor();
95
bool DataTable::initialize()
97
if ( tableName().isEmpty() || connection().isEmpty() )
100
DatabaseConnection * database = m_project->databaseConnection( connection() );
105
if ( !database->isOpen() )
106
if ( !database->open() )
108
ConnectionEditorDialog dialog( this );
110
database = m_project->databaseConnection( connection() );
113
m_tableView->setSqlCursor( new QSqlCursor( tableName(), true, database->connection() ), false );
114
m_tableEdit->setSqlCursor( m_tableView->sqlCursor() );
116
initializeFields( parentName().isEmpty() );
118
m_updatesAllowed = true;
120
if ( parentName().isEmpty() )
121
slotSelectFirstRow();
123
emit requestParentSelect();
125
initializeEditorFields();
130
void DataTable::initializeFields( bool refresh )
132
fieldSorter( m_fieldList.begin(), m_fieldList.end() );
133
QStringList visible = visibleColumns();
134
int diff = m_tableView->numCols() - visible.count();
138
for ( int i = 0; i < diff; ++i )
140
m_tableView->removeColumn( i );
145
for ( int i = 0; i > diff; --i )
147
m_tableView->addColumn( "temp" );
151
for ( DataFieldList::Iterator it = m_fieldList.begin(); it != m_fieldList.end(); ++it )
153
if ( ( *it ) ->isVirtual() )
156
QSqlField* field = m_tableView->sqlCursor() ->field( ( *it ) ->name().latin1() );
161
if ( ( *it ) ->hidden() )
164
QString labelName = ( *it ) ->label() != QString::null ? ( *it ) ->label() : field->name();
165
m_tableView->setColumn( ( *it ) ->number(), field->name(), labelName, ( *it ) ->width() );
170
QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
171
tableRefresh( QDataTable::RefreshAll );
172
QApplication::restoreOverrideCursor();
176
void DataTable::initializeEditorFields()
178
DataEditorBase *base;
179
m_tableEdit->removeEditors();
180
for ( DataFieldList::Iterator it = m_fieldList.begin(); it != m_fieldList.end(); ++it )
182
QSqlField* field = 0;
183
if ( !( *it ) ->isVirtual() )
185
field = m_tableView->sqlCursor() ->field( ( *it ) ->name().latin1() );
190
if ( ( *it ) ->hidden() )
193
QString labelName = ( *it ) ->label() != QString::null ? ( *it ) ->label() : field->name();
195
if ( ( *it ) ->isVirtual() )
196
base = new DataEditorBase( labelName, ( *it ) ->name(), m_factory, m_tableEdit->getFormBox() );
198
base = new DataEditorBase( labelName, field, m_factory, m_tableEdit->getFormBox() );
199
m_tableEdit->addEditorBase( base, ( *it ) ->isVirtual() );
201
m_tableEdit->getFormLayout()->invalidate();
202
m_tableEdit->getFormLayout()->activate();
203
m_tableEdit->seek( m_tableView->currentRow() );
206
QStringList DataTable::visibleColumns()
209
for ( DataFieldList::Iterator it = m_fieldList.begin(); it != m_fieldList.end(); ++it )
211
if ( ( *it ) ->isVirtual() )
214
QSqlField* field = dataTableView() ->sqlCursor() ->field( ( *it ) ->name().latin1() );
218
if ( ( *it ) ->hidden() )
221
lst.append( ( *it ) ->name() );
226
QString DataTable::name() const
228
if ( !m_dataTableName.isEmpty() )
229
return m_dataTableName;
234
void DataTable::setName( const QString &n )
236
m_project->addName( n );
237
m_project->removeName( m_dataTableName );
240
emit signalNameChanged( m_dataTableName );
243
QString DataTable::alias() const
245
return DataTable::sanitize( name() );
248
QString DataTable::sanitize( const QString &str )
250
QRegExp rx( "(?:[a-z]|[A-Z]|[0-9]|\\.|_|-)+" );
254
pos = rx.search( str, pos );
257
pos += rx.matchedLength();
260
return list.join("");
263
QString DataTable::iconName() const
265
return m_dataTableIconName;
268
void DataTable::setIconName( const QString &n )
270
m_dataTableIconName = n;
271
setTabIconSet( m_tableView, SmallIconSet( n ) );
272
m_project->setIconName( this, n );
275
QString DataTable::connection() const
280
void DataTable::setConnection( const QString &name )
285
QString DataTable::tableName() const
290
void DataTable::setTableName( const QString &name )
295
int DataTable::number() const
300
void DataTable::setNumber( int number )
305
QString DataTable::parentName() const
310
void DataTable::setParentName( const QString &name )
315
DataTable::RelationToParent DataTable::relationToParent() const
317
return m_relationToParent;
320
void DataTable::setRelationToParent( DataTable::RelationToParent relation )
322
m_relationToParent = relation;
325
QString DataTable::parentKey() const
330
void DataTable::setParentKey( const QString &name )
335
QString DataTable::foreignKey() const
340
void DataTable::setForeignKey( const QString &name )
345
QString DataTable::foreignValue() const
347
return m_foreignValue;
350
void DataTable::setForeignValue( const QString &name )
352
m_foreignValue = name;
355
QString DataTable::defaultFilter() const
357
return m_defaultFilter;
360
void DataTable::setDefaultFilter( const QString &filter )
362
m_defaultFilter = filter;
365
QString DataTable::searchFilter() const
367
return m_searchFilter;
370
void DataTable::setSearchFilter( const QString &filter )
372
m_searchFilter = filter;
375
QStringList DataTable::sort() const
380
void DataTable::setSort( const QStringList &sort )
382
//Hold our own value to always reflect the default sort
383
//not the current sort.
385
m_tableView->setSort( m_sort );
386
m_tableEdit->setSort( m_sort );
389
bool DataTable::updatesAllowed() const
391
return m_updatesAllowed;
394
void DataTable::setUpdatesAllowed( bool allowed )
396
m_updatesAllowed = allowed;
399
QStringList DataTable::inheritanceTree() const
401
return m_inheritanceTree;
404
void DataTable::setInheritanceTree( const QStringList &inheritanceTree )
406
m_inheritanceTree = inheritanceTree;
409
DataRelation* DataTable::dataRelation( const QString &key )
411
DataFieldList::iterator it;
412
for ( it = m_fieldList.begin(); it != m_fieldList.end(); ++it )
413
if ( ( *it ) ->name() == key )
414
return ( *it ) ->relation();
419
void DataTable::addDataRelation( const QString &name, const QString &targetTable,
420
const QString &targetKey, const QString &targetField,
421
const QString &targetConstraint,
422
const QVariant::Type targetType, int number,
425
DataField * f = dataField( name );
426
DataRelation *r = new DataRelation();
427
r->setTable( targetTable );
428
r->setKey( targetKey );
429
r->setConstraint( targetConstraint );
430
r->addDataField( targetField, targetType, number, editorWidth, false, true, false, false );
435
DataFieldList DataTable::fieldList()
440
DataField* DataTable::dataField( const QString &key )
442
DataFieldList::iterator it;
443
for ( it = m_fieldList.begin(); it != m_fieldList.end(); ++it )
444
if ( ( *it ) ->name() == key )
450
DataField* DataTable::dataField( int col )
452
DataFieldList::iterator it;
453
for ( it = m_fieldList.begin(); it != m_fieldList.end(); ++it )
454
if ( ( *it ) ->number() == col )
460
void DataTable::addDataField( const QString &name, const QVariant::Type type,
461
int isRequired, bool calculated, bool isVirtual,
462
const QString &equation, const QString &label,
463
int number, int width,
464
bool foreign, bool primary, bool hidden,
465
bool resizable, bool sortable )
467
DataField * f = new DataField();
469
f->setTable( m_tableName );
471
f->setRequired( isRequired );
472
f->setCalculated( calculated );
473
f->setVirtual( isVirtual );
474
f->setEquation( equation );
475
f->setLabel( label );
476
f->setNumber( number == -1 ? m_fieldList.count() : number );
477
f->setWidth( width == 0 ? -1 : width );
478
f->setForeign( foreign );
479
f->setPrimary( primary );
480
f->setHidden( hidden );
481
f->setResizable( resizable );
482
f->setSortable( sortable );
483
m_fieldList.append( f );
486
void DataTable::removeDataField( DataField *field )
488
bool isVirtual = field->isVirtual();
490
m_fieldList.remove( field );
495
initializeEditorFields();
498
KActionMenu *DataTable::columnVisibleAction() const
500
return m_columnVisibleAction;
503
DataTableSearch DataTable::search() const
508
void DataTable::setSearch( const DataTableSearch &search )
513
void DataTable::tableRefresh( QDataTable::Refresh mode )
515
if ( !m_tableView->sqlCursor() )
517
m_tableView->setSort( sort() );
518
m_tableView->horizontalHeader()->setSortIndicator( -1, Qt::Ascending );
519
m_tableView->refresh( mode );
520
emit tableRefreshed();
523
bool DataTable::isRootTable()
525
return parentName().isEmpty();
528
void DataTable::slotUpdate()
530
if ( !m_updatesAllowed )
533
if ( m_tableView->currentSelection() == -1 && m_tableView->numRows() < 1 )
535
m_tableEdit->setCurrentRow( -1 );
536
emit myCurrentChanged( 0L );
538
else if ( m_tableView->currentSelection() != -1 )
540
m_tableEdit->setCurrentRow( m_tableView->currentRow() );
541
if ( m_tableView->sqlCursor()->isValid() )
542
emit myCurrentChanged( m_tableView->sqlCursor() );
544
emit myCurrentChanged( 0L );
545
calculateFieldsInTree();
549
void DataTable::slotSelectFirstRow()
551
m_tableView->slotSelectFirstRow();
554
void DataTable::slotDetailFromMaster( QSqlRecord * record )
556
m_updatesAllowed = false;
558
QString fk = foreignKey();
560
setForeignValue( "-1" );
562
setForeignValue( record->value( parentKey() ).toString() );
563
setDefaultFilter( foreignKey().append( "='" ).append( foreignValue() ).append( "'" ) );
564
m_tableView->setFilter( defaultFilter().append( searchFilter() ) );
565
m_tableEdit->setFilter( m_tableView->filter() );
569
m_updatesAllowed = true;
571
slotSelectFirstRow();
574
void DataTable::slotFilterToBuffer( QSqlRecord * record )
576
if ( parentName().isEmpty() )
579
record->field( foreignKey() )->setValue( foreignValue() );
582
int DataTable::scrollTabLeft( int i )
584
//hehe, easy since we only have two pages ;)
586
setCurrentPage( !currentPageIndex() );
589
return currentPageIndex();
592
int DataTable::scrollTabRight( int i )
595
setCurrentPage( !currentPageIndex() );
598
return currentPageIndex();
601
void DataTable::firstRecord()
603
if ( relationToParent() == DataTable::ManyToOne ||
604
relationToParent() == DataTable::OneToOne )
605
m_project->dataTableByName( parentName() )->firstRecord();
607
m_tableEdit->first();
610
void DataTable::previousRecord()
612
if ( relationToParent() == DataTable::ManyToOne ||
613
relationToParent() == DataTable::OneToOne )
614
m_project->dataTableByName( parentName() )->previousRecord();
619
void DataTable::nextRecord()
621
if ( relationToParent() == DataTable::ManyToOne ||
622
relationToParent() == DataTable::OneToOne )
623
m_project->dataTableByName( parentName() )->nextRecord();
628
void DataTable::lastRecord()
630
if ( relationToParent() == DataTable::ManyToOne ||
631
relationToParent() == DataTable::OneToOne )
632
m_project->dataTableByName( parentName() )->lastRecord();
637
void DataTable::commit()
639
m_tableEdit->update();
642
void DataTable::insertRecord()
644
if ( !m_tableEdit->insertRecord() )
647
m_tableView->insertRows( m_tableView->numRows() );
648
m_tableView->slotSelectRow( m_tableView->numRows() - 1, false );
650
emit tableRefreshed(); //Perhaps a new signal eventually
653
void DataTable::changeRecord()
655
m_tableView->setFilter( "" );
656
m_tableEdit->setFilter( m_tableView->filter() );
657
m_tableView->setSelectionColor( Qt::yellow );
658
m_tableView->setSelectionMode( DataTableView::MouseOver );
662
void DataTable::associateRecord()
664
m_tableView->setSelectionColor( Qt::green );
665
m_tableView->setSelectionMode( DataTableView::Default );
666
emit childValueChanged( parentKey(), m_tableView->sqlCursor()->value( foreignKey() ) );
669
void DataTable::slotValueFromChild( const QString &key, const QVariant &value )
671
m_tableEdit->sqlCursor()->editBuffer()->setValue( key, value );
672
m_tableEdit->sqlCursor()->update();
674
m_tableView->slotSelectRow( m_tableView->currentRow() );
677
void DataTable::deleteRecord()
679
if ( !m_tableEdit->deleteRecord() )
681
//The cursor is invalidated during the attempt to delete
686
m_tableView->removeRow( m_tableView->currentRow() );
687
m_tableView->slotSelectRow( m_tableView->currentRow() );
688
emit tableRefreshed(); //Perhaps a new signal eventually
691
void DataTable::deleteAbortedInsert()
693
m_tableView->removeRow( m_tableView->numRows() - 1 );
694
emit tableRefreshed(); //Perhaps a new signal eventually
697
void DataTable::configureDataField( DataField *field )
699
FieldEditorDialog dialog( field, this, true, this );
703
QString DataTable::uniqueDataFieldName( const QString &suggest )
705
if ( suggest.isEmpty() )
706
return uniqueDataFieldName();
708
if ( !dataField( suggest ) )
711
QString base = suggest;
712
base.remove( QRegExp( "\\s\\([0-9]+\\)$" ) );
715
QString s = QString( "%1 (%2)" ).arg( base ).arg( count );
717
while ( dataField( s ) )
720
s = QString( "%1 (%2)" ).arg( base ).arg( count );
726
DataFieldList DataTable::calculatedFields()
729
DataFieldList::iterator it = m_fieldList.begin();
730
for ( ; it != m_fieldList.end(); ++it )
731
if ( ( *it )->isVirtual() )
732
list.append( ( *it ) );
736
DataRecordList DataTable::recordsInTree()
738
DataRecordList records;
739
DataTableList tables = m_project->dataTablesInDataTableTree( this );
740
for ( DataTableList::Iterator it = tables.begin(); it != tables.end(); ++it )
741
records[ ( *it )->alias() ] = ( *it )->dataTableEdit()->sqlCursor()->editBuffer();
745
void DataTable::calculateFieldsInTree()
747
DataTableList tables = m_project->childrenOfDataTable( this );
748
for ( DataTableList::Iterator it = tables.begin(); it != tables.end(); ++it )
749
( *it )->dataTableEdit()->calculateFields();
752
void DataTable::addVirtualField()
754
QString name = uniqueDataFieldName( i18n("Virtual Field") );
757
QVariant::Invalid, //type
761
QString::null, //equation
772
FieldEditorDialog dialog( dataField(name), this, false, this );
776
void DataTable::setup()
778
setFocusPolicy( QWidget::ClickFocus );
779
addTab( m_tableView, i18n( "View Table" ) );
780
addTab( m_tableEdit, SmallIconSet( "edit" ), i18n( "Edit Record" ) );
781
QObject::connect( m_tableView, SIGNAL( selectionChanged() ),
782
this, SLOT( slotUpdate() ) );
783
QObject::connect( m_tableEdit, SIGNAL( primeInsert( QSqlRecord * ) ),
784
this, SLOT( slotFilterToBuffer( QSqlRecord * ) ) );
785
QObject::connect( m_tableEdit, SIGNAL( insertAborted() ),
786
this, SLOT( deleteAbortedInsert() ) );
787
QObject::connect( m_tableEdit, SIGNAL( selectedFirst( bool ) ),
788
m_tableView, SLOT( slotSelectFirstRow( bool ) ) );
789
QObject::connect( m_tableEdit, SIGNAL( selectedPrev( bool ) ),
790
m_tableView, SLOT( slotSelectPrevRow( bool ) ) );
791
QObject::connect( m_tableEdit, SIGNAL( selectedNext( bool ) ),
792
m_tableView, SLOT( slotSelectNextRow( bool ) ) );
793
QObject::connect( m_tableEdit, SIGNAL( selectedLast( bool ) ),
794
m_tableView, SLOT( slotSelectLastRow( bool ) ) );
795
QObject::connect( m_tableEdit, SIGNAL( selectedRow( int, bool ) ),
796
m_tableView, SLOT( slotSelectRow( int, bool ) ) );
797
QObject::connect( m_tableEdit, SIGNAL( colorBoxChanged( const QColor & ) ),
798
m_tableView, SLOT( setSelectionColor( const QColor & ) ) );
799
m_propMap->insert( "DataLineEdit", "value" );
800
m_propMap->insert( "RelationCombo", "relationid" );
801
m_propMap->insert( "DateEdit", "date" );
802
m_propMap->insert( "TimeEdit", "time" );
803
m_propMap->insert( "DateTimeEdit", "datetime" );
804
m_tableView->installPropertyMap( m_propMap );
805
m_tableEdit->installPropertyMap( m_propMap );
806
m_tableView->installEditorFactory( m_factory );
811
static QTime time = QTime::currentTime();
813
if ( time.elapsed() > 200 )
816
kapp->processEvents();
822
#include "datatable.moc"