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

datatableeditorfactory.cpp

/***************************************************************************
*   Copyright (C) 2005 by Adam Treat                                      *
*   treat@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 "datatableeditorfactory.h"

#include "project.h"
#include "datatable.h"
#include "dateedit.h"
#include "timeedit.h"
#include "databaseconnection.h"
#include "fieldeditordialogimpl.h"
#include "relationeditordialogimpl.h"

#include <qlabel.h>
#include <qtimer.h>
#include <qspinbox.h>
#include <qpopupmenu.h>
#include <qsimplerichtext.h>

#include <kdebug.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kcompletionbox.h>

DataTableEditorFactory::DataTableEditorFactory( DataTable *parent,
        const char *name ) :
        QSqlEditorFactory( parent, name ),
        m_dataTable( parent )
{}

DataTableEditorFactory::~DataTableEditorFactory()
{}

QWidget * DataTableEditorFactory::createVirtualEditor( QWidget *parent,
        const QString &name )
{
    DataField * f = m_dataTable->dataField( name );
    return new DataLineEdit( f, m_dataTable, parent );
}

QWidget * DataTableEditorFactory::createEditor( QWidget *parent,
        const QVariant &variant )
{
    return QSqlEditorFactory::createEditor( parent, variant );
}

QWidget * DataTableEditorFactory::createEditor( QWidget *parent,
                                                const QSqlField *field )
{
    if ( !field )
    {
        return 0;
    }

    DataField * f = m_dataTable->dataField( field->name() );
    return createEditor( parent, f );
}

QWidget * DataTableEditorFactory::createEditor( QWidget *parent,
                                                DataField *f )
{
    if ( f->relation() )
    {
        return new RelationCombo( f, m_dataTable, parent );
    }

    QWidget * w = 0;
    switch ( f->type() )
    {
    case QVariant::Invalid:
        w = 0;
        break;
    case QVariant::Bool:
        w = new DataComboBox( f, m_dataTable, parent );
        ( ( DataComboBox * ) w ) ->insertItem( "False" );
        ( ( DataComboBox * ) w ) ->insertItem( "True" );
        break;
    case QVariant::UInt:
        w = new DataLineEdit( f, m_dataTable, parent );
        ( ( DataLineEdit* ) w ) ->setFrame( false );
        break;
    case QVariant::Int:
        w = new DataLineEdit( f, m_dataTable, parent );
        ( ( DataLineEdit* ) w ) ->setFrame( false );
        break;
    case QVariant::LongLong:
    case QVariant::ULongLong:
    case QVariant::String:
    case QVariant::CString:
    case QVariant::Double:
        w = new DataLineEdit( f, m_dataTable, parent );
        ( ( DataLineEdit* ) w ) ->setFrame( false );
        break;
    case QVariant::Date:
        w = new DateEdit( f, m_dataTable, parent );
        break;
    case QVariant::Time:
        return new TimeEdit( f, m_dataTable, parent );
        break;
    case QVariant::DateTime:
        w = new DateTimeEdit( f, m_dataTable, parent );
        break;
    case QVariant::Pixmap:
        w = new QLabel( parent );
        break;
    case QVariant::Palette:
    case QVariant::ColorGroup:
    case QVariant::Color:
    case QVariant::Font:
    case QVariant::Brush:
    case QVariant::Bitmap:
    case QVariant::Cursor:
    case QVariant::Map:
    case QVariant::StringList:
    case QVariant::Rect:
    case QVariant::Size:
    case QVariant::IconSet:
    case QVariant::Point:
    case QVariant::PointArray:
    case QVariant::Region:
    case QVariant::SizePolicy:
    case QVariant::ByteArray:
    default:
        w = new QWidget( parent );
        break;
    }
    return w;
}

DataEditorBase::DataEditorBase( const QString &label, const QSqlField *field,
                                DataTableEditorFactory *factory,
                                QWidget *parent )
        : QVBox( parent ),
        m_label( new QLabel( "<nobr><b>" + label + ":</b></nobr>" , this ) ),
        m_field( field ),
        m_editor( factory->createEditor( this, m_field ) ),
        m_currentEdited( false )
{
    m_label->setBuddy( m_editor );

    if ( DataLineEdit *line = ::qt_cast<DataLineEdit*>( m_editor ) )
    {
        line ->setFrame( true );
        QObject::connect( m_editor, SIGNAL( textChanged( const QString & ) ),
                          this, SLOT( editorChanged( const QString & ) ) );

        if ( m_field->type() == QVariant::Double ||
             m_field->type() == QVariant::Int ||
             m_field->type() == QVariant::UInt
           )
        {
            line ->setAlignment( Qt::AlignRight );
        }
    }

    else if ( DateEdit *date = ::qt_cast<DateEdit*>( m_editor ) )
    {
        QObject::connect( date, SIGNAL( dateChanged( const QDate & ) ),
                          this, SLOT( editorChanged( const QDate & ) ) );
    }

    else if ( TimeEdit *time = ::qt_cast<TimeEdit*>( m_editor ) )
    {
        QObject::connect( time, SIGNAL( timeChanged( const QTime & ) ),
                          this, SLOT( editorChanged( const QTime & ) ) );
    }

    else if ( DateTimeEdit* datetime = ::qt_cast<DateTimeEdit*>( m_editor ) )
    {
        QObject::connect( datetime, SIGNAL( dateTimeChanged( const QDateTime & ) ),
                          this, SLOT( editorChanged( const QDateTime & ) ) );
    }

    else if ( RelationCombo * relation = ::qt_cast<RelationCombo*>( m_editor ) )
    {
        QObject::connect( relation, SIGNAL( comboChanged( const QString & ) ),
                          this, SLOT( editorChanged( const QString & ) ) );
        QObject::connect( relation, SIGNAL( addConstraint( const QString & ) ),
                          this, SLOT( slotAddConstraint( const QString & ) ) );
    }

    else if ( DataComboBox * combo = ::qt_cast<DataComboBox*>( m_editor ) )
    {
        QObject::connect( combo, SIGNAL( textChanged( const QString & ) ),
                          this, SLOT( editorChanged( const QString & ) ) );
    }
}

DataEditorBase::DataEditorBase( const QString &label, const QString &name,
                                DataTableEditorFactory *factory,
                                QWidget *parent )
        : QVBox( parent ),
        m_label( new QLabel( "<nobr><b>" + label + ":</b></nobr>" , this ) ),
        m_field( 0L ),
        m_editor( factory->createVirtualEditor( this, name ) ),
        m_currentEdited( false )
{
    m_label->setBuddy( m_editor );

    if ( DataLineEdit *line = ::qt_cast<DataLineEdit*>( m_editor ) )
    {
        line ->setFrame( true );
        line ->setReadOnly( true );
    }
}

DataEditorBase::DataEditorBase( const QString &label, DataField *field,
                                DataTableEditorFactory *factory,
                                QWidget *parent )
        : QVBox( parent ),
        m_label( new QLabel( "<nobr><b>" + label + ":</b></nobr>" , this ) ),
        m_field( 0L ),
        m_editor( factory->createEditor( this, field ) ),
        m_currentEdited( false )
{
    m_label->setBuddy( m_editor );

    if ( DataLineEdit *line = ::qt_cast<DataLineEdit*>( m_editor ) )
    {
        line ->setFrame( true );

        if ( field->type() == QVariant::Double ||
             field->type() == QVariant::Int ||
             field->type() == QVariant::UInt
           )
        {
            line ->setAlignment( Qt::AlignRight );
        }
    }

    else if ( RelationCombo * relation = ::qt_cast<RelationCombo*>( m_editor ) )
    {
        relation->setIgnoreConstraints( true );
        relation->initializeFields();
        resetEditBuffer( QVariant(), true );
    }
}

QWidget* DataEditorBase::getEditor() const
{
    return m_editor;
}

const QSqlField* DataEditorBase::getField() const
{
    return m_field;
}

QSize DataEditorBase::getRecommendedSize() const
{
    QSimpleRichText rich( m_label->text(), m_label->font() );
    QSize labelSize = QSize( rich.widthUsed(), 0 );

    if ( !::qt_cast<DataLineEdit*>( m_editor ) )
        return labelSize.expandedTo( m_editor->minimumSize() );

    QFontMetrics fm = m_editor->fontMetrics();

    QString str;
    if ( m_field )
        str = " " + m_field->value().toString() + " ";

    return labelSize.expandedTo( QSize( fm.width( str ), 0 ) );
}

bool DataEditorBase::currentEdited() const
{
    return m_currentEdited;
}

void DataEditorBase::setNullValue( const QString txt )
{
    if ( DataLineEdit *line = ::qt_cast<DataLineEdit*>( m_editor ) )
    {
        line ->setText( txt );
    }
    else if ( RelationCombo *relation = ::qt_cast<RelationCombo*>( m_editor ) )
    {
        relation ->setNullValue( txt );
    }
}

bool DataEditorBase::calculateEditor()
{
    if ( DataLineEdit * line = ::qt_cast<DataLineEdit*>( m_editor ) )
    {
        return line->calculateEditor();
    }
    return false;
}

void DataEditorBase::setFocus()
{
    m_editor->setFocus();
}

void DataEditorBase::resetEditBuffer( QVariant, bool currentEdited )
{
    if ( RelationCombo * relation = ::qt_cast<RelationCombo*>( m_editor ) )
    {
        if ( getField() )
        {
            relation->setRelationId( getField()->value().toString() );
            if ( currentEdited || getField()->isNull() )
                relation->setNullValue( "" );
        }
        else
        {
            relation->setRelationId( relation->relationId() );
            if ( currentEdited )
                relation->setNullValue( "" );
        }
    }
}

void DataEditorBase::editorChanged( const QString &txt )
{
    m_currentEdited = ( txt != m_field->value().toString() );
    emit editBufferChanged( QVariant( txt ), m_currentEdited );
}

void DataEditorBase::editorChanged( const QDate &date )
{
    m_currentEdited = ( date.toString( Qt::ISODate )
                        != m_field->value().toString() );
    emit editBufferChanged( QVariant( date ), m_currentEdited );
}

void DataEditorBase::editorChanged( const QTime &time )
{
    m_currentEdited = ( time.toString( Qt::ISODate )
                        != m_field->value().toString() );
    emit editBufferChanged( QVariant( time ), m_currentEdited );
}

void DataEditorBase::editorChanged( const QDateTime &datetime )
{
    m_currentEdited = ( datetime.toString( Qt::ISODate )
                        != m_field->value().toString() );
    emit editBufferChanged( QVariant( datetime ), m_currentEdited );
}

void DataEditorBase::slotAddConstraint( const QString &field )
{
    emit addConstraint( this, field );
}

DataLineEdit::DataLineEdit( DataField* field, DataTable* dataTable,
                            QWidget *parent, const char *name )
        : KLineEdit( parent, name ),
        m_field( field ),
        m_dataTable( dataTable )
{
    connect( this, SIGNAL( aboutToShowContextMenu( QPopupMenu * ) ),
             SLOT( configureContextMenu( QPopupMenu * ) ) );
}

QString DataLineEdit::value() const
{
    QString txt = text();

    if ( txt == "" && m_field->type() != QVariant::String )
        return "NULL";
    else if ( txt == "" )
        return QString::null;

    return txt;
}

void DataLineEdit::setValue( const QString &value )
{
    setText( value );
}

void DataLineEdit::setReadOnly( bool readOnly )
{
    // Do not do anything if nothing changed...
    if ( readOnly == isReadOnly() )
        return ;

    Qt::BackgroundMode background = backgroundMode();
    KLineEdit::setReadOnly( readOnly );
    setBackgroundMode( background );

    if ( readOnly )
    {
        QPalette p = palette();
        p.setColor(QColorGroup::Text, Qt::blue );
        setPalette(p);
        setFocusPolicy( QWidget::ClickFocus );
    }
}

void DataLineEdit::configureContextMenu( QPopupMenu *p )
{
    if ( isReadOnly() )
        p->insertItem( SmallIcon( "fileclose" ),
                i18n( "Delete Data Field" ), this,
                SLOT( deleteDataField() ), 0, -1, 0 );

    p->insertItem( UserIcon( "visible" ),
                   i18n( "Configure Data Field..." ), this,
                   SLOT( configureDataField() ), 0, -1, 0 );
}

void DataLineEdit::configureDataField()
{
    m_dataTable->configureDataField( m_field );
}

void DataLineEdit::deleteDataField()
{
    m_dataTable->removeDataField( m_field );
}

bool DataLineEdit::calculateEditor()
{
    if ( !m_field )
        return false;
    QVariant result = m_field->calculateField( m_dataTable->recordsInTree() );
    if ( result.isValid() )
        setText( result.toString() );
    else
        setText( i18n( "-- Invalid Equation --" ) );

    return result.isValid();
}

DataComboBox::DataComboBox( DataField* field, DataTable* dataTable,
                            QWidget *parent, const char *name )
        : KComboBox( parent, name ),
        m_field( field ),
        m_dataTable( dataTable )
{
    connect( this, SIGNAL( aboutToShowContextMenu( QPopupMenu * ) ),
             SLOT( configureContextMenu( QPopupMenu * ) ) );
}

DataComboBox::DataComboBox( DataField* field, DataTable* dataTable,
                            bool rw, QWidget *parent, const char *name )
        : KComboBox( rw, parent, name ),
        m_field( field ),
        m_dataTable( dataTable )
{
    connect( this, SIGNAL( aboutToShowContextMenu( QPopupMenu * ) ),
             SLOT( configureContextMenu( QPopupMenu * ) ) );
}

void DataComboBox::configureContextMenu( QPopupMenu *p )
{
    p->insertItem( UserIcon( "visible" ),
                   i18n( "Configure Data Field..." ), this,
                   SLOT( configureDataField() ), 0, -1, 0 );
}

void DataComboBox::configureDataField()
{
    m_dataTable->configureDataField( m_field );
}

DateTimeEdit::DateTimeEdit( DataField* field, DataTable* dataTable,
                            QWidget *parent, const char *name ) :
        QHBox( parent, name )
{
    setSpacing( 5 );
    m_dateEdit = new DateEdit( field, dataTable, this );
    m_timeEdit = new TimeEdit( field, dataTable, this );
    setStretchFactor( m_dateEdit, 1 );

    int width = m_dateEdit->width() + 5 + m_timeEdit->width();
    setMinimumSize( QSize( width, m_dateEdit->height() ) );
}

QDateTime DateTimeEdit::dateTime() const
{
    return QDateTime( m_dateEdit->date(), m_timeEdit->getTime() );
}

void DateTimeEdit::setDateTime( QDateTime dateTime )
{
    m_dateEdit->setDate( dateTime.date() );
    m_timeEdit->setTime( dateTime.time() );

    QObject::connect( m_dateEdit, SIGNAL( dateChanged( const QDate & ) ),
                      this, SLOT( slotDateTimeChanged() ) );
    QObject::connect( m_timeEdit, SIGNAL( timeChanged( const QTime & ) ),
                      this, SLOT( slotDateTimeChanged() ) );
}

void DateTimeEdit::slotDateTimeChanged()
{
    emit dateTimeChanged( dateTime() );
}

RelationCombo::RelationCombo( DataField* field, DataTable* dataTable,
                              QWidget *parent,
                              const char *name )
        : KComboTable( parent, name ),
        m_relationId( -1 ),
        m_field( field ),
        m_dataTable( dataTable ),
        m_constraints( QStringList() ),
        m_ignoreConstraints( false )
{
    connect( this, SIGNAL( activated ( int ) ),
             SLOT( setCurrentIndex( int ) ) );
    connect( completionBox(), SIGNAL( highlighted( const QString& ) ),
             SLOT( setCurrentTextId( const QString& ) ) );
    connect( lineEdit(), SIGNAL( trueTextChanged( const QString & ) ),
             SLOT( completionMatch( const QString & ) ) );
    connect( this, SIGNAL( aboutToShowContextMenu( QPopupMenu * ) ),
             SLOT( configureContextMenu( QPopupMenu * ) ) );

    if ( m_field->relation()->editorWidth() != 0 )
    {
        initializeFields();
    }
    else
    {
        initializeFields( true );
        setWidths();
    }
}

void RelationCombo::initializeFields( bool calculateWidths )
{
    if ( calculateWidths )
        QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );

    lineEdit() ->blockSignals( true );

    int cache = m_relationId; //save the current relation

    clearAll();
    index2id.clear();

    QStringList select;
    QStringList from;
    QStringList where;

    QValueList<int> colWidths;

    select.append( m_field->relation() ->fullKey() );
    select.append( ", " );

    int visibleFields = 0;
    DataFieldList fields = m_field->relation() ->fieldList();
    fieldSorter( fields.begin(), fields.end() );
    for ( DataFieldList::Iterator it = fields.begin(); it != fields.end(); ++it )
    {
        if ( ( *it ) ->relation() )
        {
            if ( ( *it ) ->hidden() &&
                    ( *it ) ->relation() ->constraint().isEmpty() )
                continue;

            if ( where.count() )
                where.append( " AND " );

            where.append( ( *it ) ->relation() ->table() );
            where.append( "." );
            where.append( ( *it ) ->relation() ->key() );
            where.append( "=" );
            where.append( ( *it ) ->table() );
            where.append( "." );
            where.append( ( *it ) ->name() );

            if ( !m_ignoreConstraints )
            {
                QString constraint = ( *it ) ->relation() ->constraint();
                if ( constraint != QString::null )
                {
                    if ( m_constraints.contains( constraint ) < 2 )
                    {
                        emit addConstraint( constraint );
                        m_constraints.append( constraint );
                    }
                    QString value = m_dataTable->dataTableEdit() ->currentValue( constraint ).toString();
                    if ( where.count() )
                        where.append( " AND " );

                    where.append( ( *it ) ->relation() ->table() );
                    where.append( "." );
                    where.append( ( *it ) ->relation() ->key() );
                    where.append( "='" );
                    where.append( value );
                    where.append( "'" );
                }
            }
        }

        QString field = ( *it ) ->relation() ?
                        ( *it ) ->relation() ->fullField() :
                        ( *it ) ->fullName();

        QString table = ( *it ) ->relation() ?
                        ( *it ) ->relation() ->table() :
                        m_field->relation() ->table();

        if ( !from.contains( table ) )
        {
            from.append( table );
            from.append( ", " );
        }

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

        ++visibleFields;

        select.append( field );
        select.append( ", " );

        if ( !calculateWidths )
            colWidths.append( ( *it ) ->editorWidth() );
    }

    select.pop_back();
    select.append( " " );
    from.pop_back();
    from.append( " " );

    if ( !calculateWidths )
        setColumnWidths( colWidths );

    QString fullquerystring = "SELECT " + select.join( "" ) +
                              "FROM " + from.join( "" );

    if ( where.count() )
        fullquerystring.append( "WHERE " + where.join( "" ) );

    DatabaseConnection * database =
        m_dataTable->project() ->databaseConnection( m_dataTable->connection() );

    QSqlQuery query( fullquerystring, database->connection() );

    //     kdDebug() << fullquerystring << endl;

    int greatestWidth = 0;
    QFontMetrics fm = fontMetrics();

    int i = 0;

    while ( query.next() )
    {
        QStringList row;
        for ( int j = 1; j < visibleFields + 1 ; ++j )
            row << query.value( j ).toString();

        insertRow( row, calculateWidths );

        index2id[ i ] = query.value( 0 ).toInt();

        int width = fm.width( " " + row[ 0 ] + " " );
        if ( width > greatestWidth )
            greatestWidth = width;

        i++;
    }

    lineEdit() ->blockSignals( false );

    if ( !m_constraints.count() || calculateWidths )
        setCurrentId( cache );

    setMinimumSize( QSize( greatestWidth, height() ) );

    if ( calculateWidths )
        QApplication::restoreOverrideCursor();
}

QString RelationCombo::relationId() const
{
    QString txt = lineEdit()->text();
    if ( txt.isEmpty() )
        return "NULL";
    else
        return QString::number( m_relationId );
}

void RelationCombo::setRelationId( const QString &id )
{
    if ( m_constraints.count() )
        initializeFields();

    setCurrentId( id.toInt() );
}

void RelationCombo::setNullValue( const QString &txt )
{
    setCurrentItem( -1 );
    setCurrentText( txt );
}

void RelationCombo::setIgnoreConstraints( bool ignore )
{
    m_ignoreConstraints = ignore;
}

void RelationCombo::setCurrentIndex( int index )
{
    int id = index2id[ index ];
    setCurrentId( id );
}

void RelationCombo::setCurrentId( int id )
{
    m_relationId = id;
    QMap<int, int>::Iterator it;
    for ( it = index2id.begin(); it != index2id.end(); ++it )
    {
        if ( it.data() == id )
        {
            setCurrentItem( it.key() );
            break;
        }
    }
}

void RelationCombo::setCurrentTextId( const QString &txt )
{
    setCurrentText( txt );
}

void RelationCombo::completionMatch( const QString &txt )
{
    int i = -1;
    for ( int j = 0; j < count(); j++ )
        if ( text( j ) == txt )
        {
            i = j;
            break;
        }

    m_relationId = index2id[ i ];
    emit comboChanged( QString::number( m_relationId ) );
}

void RelationCombo::configureContextMenu( QPopupMenu *p )
{
    p->insertItem( UserIcon( "foreignkey" ),
                   i18n( "Configure Relation Fields..." ), this,
                   SLOT( configureRelationField() ), 0, -1, 0 );
    p->insertItem( UserIcon( "visible" ),
                   i18n( "Configure Data Field..." ), this,
                   SLOT( configureDataField() ), 0, -1, 0 );
}

void RelationCombo::configureDataField()
{
    m_dataTable->configureDataField( m_field );
}

void RelationCombo::configureRelationField()
{
    RelationEditorDialog dialog( m_field, m_dataTable, false, this );
    if ( dialog.exec() )
    {
        m_constraints.clear();
        initializeFields( true );
        setWidths();
    }
}

void RelationCombo::setWidths()
{
    QValueList<int> widths = columnWidths();
    DataFieldList fields = m_field->relation() ->fieldList();
    fieldSorter( fields.begin(), fields.end() );
    int i = 0;
    for ( DataFieldList::Iterator it = fields.begin(); it != fields.end(); ++it )
    {
        if ( ( *it ) ->hidden() )
        {
            ( *it ) ->setEditorWidth( 0 );
            continue;
        }

        ( *it ) ->setEditorWidth( widths[ i ] );
        ++i;
    }
}

#include "datatableeditorfactory.moc"

Generated by  Doxygen 1.6.0   Back to index