Logo Search packages:      
Sourcecode: datakiosk version File versions  Download package

datatable.cpp

/***************************************************************************
*   Copyright (C) 2005 by Adam Treat                                      *
*   treat@kde.org                                                         *
*                                                                         *
*   Copyright (C) 2004 by Scott Wheeler                                   *
*   wheeler@kde.org                                                       *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/

#include <kconfig.h>
#include <kmessagebox.h>
#include <kurldrag.h>
#include <kiconloader.h>
#include <klineedit.h>
#include <kaction.h>
#include <kpopupmenu.h>
#include <klocale.h>
#include <kdebug.h>
#include <kinputdialog.h>
#include <kapplication.h>

#include <kdialog.h>

#include <qpainter.h>
#include <qheader.h>
#include <qcursor.h>
#include <qdir.h>
#include <qeventloop.h>
#include <qtooltip.h>
#include <qwidgetstack.h>
#include <qsqldatabase.h>
#include <qstyle.h>
#include <qsqlpropertymap.h>

#include <time.h>
#include <math.h>
#include <dirent.h>

#include "datatable.h"
#include "project.h"
#include "datatablesearch.h"
#include "actioncollection.h"
#include "datakiosk.h"
#include "databaseconnection.h"
#include "fieldeditordialogimpl.h"
#include "connectioneditordialogimpl.h"
#include "formlayout.h"

using namespace ActionCollection;

bool DataTable::m_visibleChanged = false;

DataTable::DataTable( Project *project ) :
        QTabWidget( project->dataTableStack() ),
        m_tableView( new DataTableView( this ) ),
        m_tableEdit( new DataTableEdit( this ) ),
        m_project( project ),
        m_factory( new DataTableEditorFactory( this ) ),
        m_propMap( new QSqlPropertyMap() ),
        m_updatesAllowed( false )
{
    setup();
    setIconName( "table" );
    m_project->setupDataTable( this, iconName() );
}

DataTable::DataTable( Project *project, DataTable* parent ) :
        QTabWidget( project->dataTableStack() ),
        m_tableView( new DataTableView( this ) ),
        m_tableEdit( new DataTableEdit( this ) ),
        m_project( project ),
        m_factory( new DataTableEditorFactory( this ) ),
        m_propMap( new QSqlPropertyMap() ),
        m_updatesAllowed( false )
{
    setup();
    setIconName( "child" );
    m_project->setupDataTable( this, iconName(), parent );
}

DataTable::~DataTable()
{
    DataFieldList::iterator it = m_fieldList.begin();
    for ( ; it != m_fieldList.end(); ++it )
        delete ( *it );

    delete m_tableView->sqlCursor();
}

bool DataTable::initialize()
{
    if ( tableName().isEmpty() || connection().isEmpty() )
        return false;

    DatabaseConnection * database = m_project->databaseConnection( connection() );

    if ( !database )
        return false;

    if ( !database->isOpen() )
        if ( !database->open() )
        {
            ConnectionEditorDialog dialog( this );
            dialog.exec();
            database = m_project->databaseConnection( connection() );
        }

    m_tableView->setSqlCursor( new QSqlCursor( tableName(), true, database->connection() ), false );
    m_tableEdit->setSqlCursor( m_tableView->sqlCursor() );

    initializeFields( parentName().isEmpty() );

    m_updatesAllowed = true;

    if ( parentName().isEmpty() )
        slotSelectFirstRow();
    else
        emit requestParentSelect();

    initializeEditorFields();

    return true;
}

void DataTable::initializeFields( bool refresh )
{
    fieldSorter( m_fieldList.begin(), m_fieldList.end() );
    QStringList visible = visibleColumns();
    int diff = m_tableView->numCols() - visible.count();

    if ( diff > 0 )
    {
        for ( int i = 0; i < diff; ++i )
        {
            m_tableView->removeColumn( i );
        }
    }
    else if ( diff < 0 )
    {
        for ( int i = 0; i > diff; --i )
        {
            m_tableView->addColumn( "temp" );
        }
    }

    for ( DataFieldList::Iterator it = m_fieldList.begin(); it != m_fieldList.end(); ++it )
    {
        if ( ( *it ) ->isVirtual() )
            continue;

        QSqlField* field = m_tableView->sqlCursor() ->field( ( *it ) ->name().latin1() );

        if ( !field )
            continue;

        if ( ( *it ) ->hidden() )
            continue;

        QString labelName = ( *it ) ->label() != QString::null ? ( *it ) ->label() : field->name();
        m_tableView->setColumn( ( *it ) ->number(), field->name(), labelName, ( *it ) ->width() );
    }

    if ( refresh )
    {
        QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
        tableRefresh( QDataTable::RefreshAll );
        QApplication::restoreOverrideCursor();
    }
}

void DataTable::initializeEditorFields()
{
    DataEditorBase *base;
    m_tableEdit->removeEditors();
    for ( DataFieldList::Iterator it = m_fieldList.begin(); it != m_fieldList.end(); ++it )
    {
        QSqlField* field = 0;
        if ( !( *it ) ->isVirtual() )
        {
            field = m_tableView->sqlCursor() ->field( ( *it ) ->name().latin1() );
            if ( !field )
                continue;
        }

        if ( ( *it ) ->hidden() )
            continue;

        QString labelName = ( *it ) ->label() != QString::null ? ( *it ) ->label() : field->name();

        if (  ( *it ) ->isVirtual()  )
            base = new DataEditorBase( labelName, ( *it ) ->name(), m_factory, m_tableEdit->getFormBox() );
        else
            base = new DataEditorBase( labelName, field, m_factory, m_tableEdit->getFormBox() );
        m_tableEdit->addEditorBase( base, ( *it ) ->isVirtual() );
    }
    m_tableEdit->getFormLayout()->invalidate();
    m_tableEdit->getFormLayout()->activate();
    m_tableEdit->seek( m_tableView->currentRow() );
}

QStringList DataTable::visibleColumns()
{
    QStringList lst;
    for ( DataFieldList::Iterator it = m_fieldList.begin(); it != m_fieldList.end(); ++it )
    {
        if ( ( *it ) ->isVirtual() )
            continue;

        QSqlField* field = dataTableView() ->sqlCursor() ->field( ( *it ) ->name().latin1() );
        if ( !field )
            continue;

        if ( ( *it ) ->hidden() )
            continue;

        lst.append( ( *it ) ->name() );
    }
    return lst;
}

QString DataTable::name() const
{
    if ( !m_dataTableName.isEmpty() )
        return m_dataTableName;
    else
        return m_tableName;
}

void DataTable::setName( const QString &n )
{
    m_project->addName( n );
    m_project->removeName( m_dataTableName );

    m_dataTableName = n;
    emit signalNameChanged( m_dataTableName );
}

QString DataTable::alias() const
{
    return DataTable::sanitize( name() );
}

QString DataTable::sanitize( const QString &str )
{
    QRegExp rx( "(?:[a-z]|[A-Z]|[0-9]|\\.|_|-)+" );
    QStringList list;
    int pos = 0;
    while ( pos >= 0 ) {
        pos = rx.search( str, pos );
        if ( pos > -1 ) {
            list += rx.cap();
            pos  += rx.matchedLength();
        }
    }
    return list.join("");
}

QString DataTable::iconName() const
{
    return m_dataTableIconName;
}

void DataTable::setIconName( const QString &n )
{
    m_dataTableIconName = n;
    setTabIconSet( m_tableView, SmallIconSet( n ) );
    m_project->setIconName( this, n );
}

QString DataTable::connection() const
{
    return m_connection;
}

void DataTable::setConnection( const QString &name )
{
    m_connection = name;
}

QString DataTable::tableName() const
{
    return m_tableName;
}

void DataTable::setTableName( const QString &name )
{
    m_tableName = name;
}

int DataTable::number() const
{
    return m_number;
}

void DataTable::setNumber( int number )
{
    m_number = number;
}

QString DataTable::parentName() const
{
    return m_parentName;
}

void DataTable::setParentName( const QString &name )
{
    m_parentName = name;
}

DataTable::RelationToParent DataTable::relationToParent() const
{
    return m_relationToParent;
}

void DataTable::setRelationToParent( DataTable::RelationToParent relation )
{
    m_relationToParent = relation;
}

QString DataTable::parentKey() const
{
    return m_parentKey;
}

void DataTable::setParentKey( const QString &name )
{
    m_parentKey = name;
}

QString DataTable::foreignKey() const
{
    return m_foreignKey;
}

void DataTable::setForeignKey( const QString &name )
{
    m_foreignKey = name;
}

QString DataTable::foreignValue() const
{
    return m_foreignValue;
}

void DataTable::setForeignValue( const QString &name )
{
    m_foreignValue = name;
}

QString DataTable::defaultFilter() const
{
    return m_defaultFilter;
}

void DataTable::setDefaultFilter( const QString &filter )
{
    m_defaultFilter = filter;
}

QString DataTable::searchFilter() const
{
    return m_searchFilter;
}

void DataTable::setSearchFilter( const QString &filter )
{
    m_searchFilter = filter;
}

QStringList DataTable::sort() const
{
    return m_sort;
}

void DataTable::setSort( const QStringList &sort )
{
    //Hold our own value to always reflect the default sort
    //not the current sort.
    m_sort = sort;
    m_tableView->setSort( m_sort );
    m_tableEdit->setSort( m_sort );
}

bool DataTable::updatesAllowed() const
{
    return m_updatesAllowed;
}

void DataTable::setUpdatesAllowed( bool allowed )
{
    m_updatesAllowed = allowed;
}

QStringList DataTable::inheritanceTree() const
{
    return m_inheritanceTree;
}

void DataTable::setInheritanceTree( const QStringList &inheritanceTree )
{
    m_inheritanceTree = inheritanceTree;
}

DataRelation* DataTable::dataRelation( const QString &key )
{
    DataFieldList::iterator it;
    for ( it = m_fieldList.begin(); it != m_fieldList.end(); ++it )
        if ( ( *it ) ->name() == key )
            return ( *it ) ->relation();

    return 0;
}

void DataTable::addDataRelation( const QString &name, const QString &targetTable,
                                 const QString &targetKey, const QString &targetField,
                                 const QString &targetConstraint,
                                 const QVariant::Type targetType, int number,
                                 int editorWidth )
{
    DataField * f = dataField( name );
    DataRelation *r = new DataRelation();
    r->setTable( targetTable );
    r->setKey( targetKey );
    r->setConstraint( targetConstraint );
    r->addDataField( targetField, targetType, number, editorWidth, false, true, false, false );

    f->setRelation( r );
}

DataFieldList DataTable::fieldList()
{
    return m_fieldList;
}

DataField* DataTable::dataField( const QString &key )
{
    DataFieldList::iterator it;
    for ( it = m_fieldList.begin(); it != m_fieldList.end(); ++it )
        if ( ( *it ) ->name() == key )
            return ( *it );

    return 0;
}

DataField* DataTable::dataField( int col )
{
    DataFieldList::iterator it;
    for ( it = m_fieldList.begin(); it != m_fieldList.end(); ++it )
        if ( ( *it ) ->number() == col )
            return ( *it );

    return 0;
}

void DataTable::addDataField( const QString &name, const QVariant::Type type,
                              int isRequired, bool calculated, bool isVirtual,
                              const QString &equation, const QString &label,
                              int number, int width,
                              bool foreign, bool primary, bool hidden,
                              bool resizable, bool sortable )
{
    DataField * f = new DataField();
    f->setName( name );
    f->setTable( m_tableName );
    f->setType( type );
    f->setRequired( isRequired );
    f->setCalculated( calculated );
    f->setVirtual( isVirtual );
    f->setEquation( equation );
    f->setLabel( label );
    f->setNumber( number == -1 ? m_fieldList.count() : number );
    f->setWidth( width == 0 ? -1 : width );
    f->setForeign( foreign );
    f->setPrimary( primary );
    f->setHidden( hidden );
    f->setResizable( resizable );
    f->setSortable( sortable );
    m_fieldList.append( f );
}

void DataTable::removeDataField( DataField *field )
{
    bool isVirtual = field->isVirtual();

    m_fieldList.remove( field );
    delete field;

    if ( !isVirtual )
        initializeFields();
    initializeEditorFields();
}

KActionMenu *DataTable::columnVisibleAction() const
{
    return m_columnVisibleAction;
}

DataTableSearch DataTable::search() const
{
    return m_search;
}

void DataTable::setSearch( const DataTableSearch &search )
{
    m_search = search;
}

void DataTable::tableRefresh( QDataTable::Refresh mode )
{
    if ( !m_tableView->sqlCursor() )
        return;
    m_tableView->setSort( sort() );
    m_tableView->horizontalHeader()->setSortIndicator( -1, Qt::Ascending );
    m_tableView->refresh( mode );
    emit tableRefreshed();
}

bool DataTable::isRootTable()
{
    return parentName().isEmpty();
}

void DataTable::slotUpdate()
{
    if ( !m_updatesAllowed )
        return;

    if ( m_tableView->currentSelection() == -1 && m_tableView->numRows() < 1 )
    {
        m_tableEdit->setCurrentRow( -1 );
        emit myCurrentChanged( 0L );
    }
    else if ( m_tableView->currentSelection() != -1 )
    {
        m_tableEdit->setCurrentRow( m_tableView->currentRow() );
        if ( m_tableView->sqlCursor()->isValid() )
            emit myCurrentChanged( m_tableView->sqlCursor() );
        else
            emit myCurrentChanged( 0L );
        calculateFieldsInTree();
    }
}

void DataTable::slotSelectFirstRow()
{
    m_tableView->slotSelectFirstRow();
}

void DataTable::slotDetailFromMaster( QSqlRecord * record )
{
    m_updatesAllowed = false;

    QString fk = foreignKey();
    if ( !record )
        setForeignValue( "-1" );
    else
        setForeignValue( record->value( parentKey() ).toString() );
    setDefaultFilter( foreignKey().append( "='" ).append( foreignValue() ).append( "'" ) );
    m_tableView->setFilter( defaultFilter().append( searchFilter() ) );
    m_tableEdit->setFilter( m_tableView->filter() );

    tableRefresh();

    m_updatesAllowed = true;

    slotSelectFirstRow();
}

void DataTable::slotFilterToBuffer( QSqlRecord * record )
{
    if ( parentName().isEmpty() )
        return;

    record->field( foreignKey() )->setValue( foreignValue() );
}

int DataTable::scrollTabLeft( int i )
{
    //hehe, easy since we only have two pages ;)
    if ( i == -1 )
        setCurrentPage( !currentPageIndex() );
    else
        setCurrentPage( i );
    return currentPageIndex();
}

int DataTable::scrollTabRight( int i )
{
    if ( i == -1 )
        setCurrentPage( !currentPageIndex() );
    else
        setCurrentPage( i );
    return currentPageIndex();
}

void DataTable::firstRecord()
{
    if ( relationToParent() == DataTable::ManyToOne ||
         relationToParent() == DataTable::OneToOne )
        m_project->dataTableByName( parentName() )->firstRecord();
    else
        m_tableEdit->first();
}

void DataTable::previousRecord()
{
    if ( relationToParent() == DataTable::ManyToOne ||
         relationToParent() == DataTable::OneToOne )
        m_project->dataTableByName( parentName() )->previousRecord();
    else
        m_tableEdit->prev();
}

void DataTable::nextRecord()
{
    if ( relationToParent() == DataTable::ManyToOne ||
         relationToParent() == DataTable::OneToOne )
        m_project->dataTableByName( parentName() )->nextRecord();
    else
        m_tableEdit->next();
}

void DataTable::lastRecord()
{
    if ( relationToParent() == DataTable::ManyToOne ||
         relationToParent() == DataTable::OneToOne )
        m_project->dataTableByName( parentName() )->lastRecord();
    else
        m_tableEdit->last();
}

void DataTable::commit()
{
    m_tableEdit->update();
}

void DataTable::insertRecord()
{
    if ( !m_tableEdit->insertRecord() )
        return;

    m_tableView->insertRows( m_tableView->numRows() );
    m_tableView->slotSelectRow( m_tableView->numRows() - 1, false );
    scrollTabRight();
    emit tableRefreshed(); //Perhaps a new signal eventually
}

void DataTable::changeRecord()
{
    m_tableView->setFilter( "" );
    m_tableEdit->setFilter( m_tableView->filter() );
    m_tableView->setSelectionColor( Qt::yellow );
    m_tableView->setSelectionMode( DataTableView::MouseOver );
    tableRefresh();
}

void DataTable::associateRecord()
{
    m_tableView->setSelectionColor( Qt::green );
    m_tableView->setSelectionMode( DataTableView::Default );
    emit childValueChanged( parentKey(), m_tableView->sqlCursor()->value( foreignKey() ) );
}

void DataTable::slotValueFromChild( const QString &key, const QVariant &value )
{
    m_tableEdit->sqlCursor()->editBuffer()->setValue( key, value );
    m_tableEdit->sqlCursor()->update();
    tableRefresh();
    m_tableView->slotSelectRow( m_tableView->currentRow() );
}

void DataTable::deleteRecord()
{
    if ( !m_tableEdit->deleteRecord() )
    {
        //The cursor is invalidated during the attempt to delete
        tableRefresh();
        return;
    }

    m_tableView->removeRow( m_tableView->currentRow() );
    m_tableView->slotSelectRow(  m_tableView->currentRow() );
    emit tableRefreshed(); //Perhaps a new signal eventually
}

void DataTable::deleteAbortedInsert()
{
    m_tableView->removeRow( m_tableView->numRows() - 1 );
    emit tableRefreshed(); //Perhaps a new signal eventually
}

void DataTable::configureDataField( DataField *field  )
{
    FieldEditorDialog dialog( field, this, true, this );
    dialog.exec();
}

QString DataTable::uniqueDataFieldName( const QString &suggest )
{
    if ( suggest.isEmpty() )
        return uniqueDataFieldName();

    if ( !dataField( suggest ) )
        return suggest;

    QString base = suggest;
    base.remove( QRegExp( "\\s\\([0-9]+\\)$" ) );

    int count = 1;
    QString s = QString( "%1 (%2)" ).arg( base ).arg( count );

    while ( dataField( s ) )
    {
        count++;
        s = QString( "%1 (%2)" ).arg( base ).arg( count );
    }

    return s;
}

DataFieldList DataTable::calculatedFields()
{
    DataFieldList list;
    DataFieldList::iterator it = m_fieldList.begin();
    for ( ; it != m_fieldList.end(); ++it )
        if ( ( *it )->isVirtual() )
            list.append( ( *it ) );
    return list;
}

DataRecordList DataTable::recordsInTree()
{
    DataRecordList records;
    DataTableList tables = m_project->dataTablesInDataTableTree( this );
    for ( DataTableList::Iterator it = tables.begin(); it != tables.end(); ++it )
        records[ ( *it )->alias() ] = ( *it )->dataTableEdit()->sqlCursor()->editBuffer();
    return records;
}

void DataTable::calculateFieldsInTree()
{
    DataTableList tables = m_project->childrenOfDataTable( this );
    for ( DataTableList::Iterator it = tables.begin(); it != tables.end(); ++it )
        ( *it )->dataTableEdit()->calculateFields();
}

void DataTable::addVirtualField()
{
    QString name = uniqueDataFieldName( i18n("Virtual Field") );
    addDataField(
        name,                           //name
        QVariant::Invalid,              //type
        false,                          //required
        true,                           //calculated
        true,                           //virtual
        QString::null,                  //equation
        name,                           //label
        -1,                             //number
        -1,                             //width
        false,                          //foreign
        false,                          //primary
        false,                          //hidden
        false,                          //resizable
        false                           //sortable
    );

    FieldEditorDialog dialog( dataField(name), this, false, this );
    dialog.exec();
}

void DataTable::setup()
{
    setFocusPolicy( QWidget::ClickFocus );
    addTab( m_tableView, i18n( "View Table" ) );
    addTab( m_tableEdit, SmallIconSet( "edit" ), i18n( "Edit Record" ) );
    QObject::connect( m_tableView, SIGNAL( selectionChanged() ),
                      this, SLOT( slotUpdate() ) );
    QObject::connect( m_tableEdit, SIGNAL( primeInsert( QSqlRecord * ) ),
                      this, SLOT( slotFilterToBuffer( QSqlRecord * ) ) );
    QObject::connect( m_tableEdit, SIGNAL( insertAborted() ),
                      this, SLOT( deleteAbortedInsert() ) );
    QObject::connect( m_tableEdit, SIGNAL( selectedFirst( bool ) ),
                      m_tableView, SLOT( slotSelectFirstRow( bool ) ) );
    QObject::connect( m_tableEdit, SIGNAL( selectedPrev( bool ) ),
                      m_tableView, SLOT( slotSelectPrevRow( bool ) ) );
    QObject::connect( m_tableEdit, SIGNAL( selectedNext( bool ) ),
                      m_tableView, SLOT( slotSelectNextRow( bool ) ) );
    QObject::connect( m_tableEdit, SIGNAL( selectedLast( bool ) ),
                      m_tableView, SLOT( slotSelectLastRow( bool ) ) );
    QObject::connect( m_tableEdit, SIGNAL( selectedRow( int, bool ) ),
                      m_tableView, SLOT( slotSelectRow( int, bool ) ) );
    QObject::connect( m_tableEdit, SIGNAL( colorBoxChanged( const QColor & ) ),
                      m_tableView, SLOT( setSelectionColor( const QColor & ) ) );
    m_propMap->insert( "DataLineEdit", "value" );
    m_propMap->insert( "RelationCombo", "relationid" );
    m_propMap->insert( "DateEdit", "date" );
    m_propMap->insert( "TimeEdit", "time" );
    m_propMap->insert( "DateTimeEdit", "datetime" );
    m_tableView->installPropertyMap( m_propMap );
    m_tableEdit->installPropertyMap( m_propMap );
    m_tableView->installEditorFactory( m_factory );
}

bool processEvents()
{
    static QTime time = QTime::currentTime();

    if ( time.elapsed() > 200 )
    {
        time.restart();
        kapp->processEvents();
        return true;
    }
    return false;
}

#include "datatable.moc"

Generated by  Doxygen 1.6.0   Back to index