00001 #include <QtCore/QString>
00002 #include <QtCore/QStringList>
00003 #include <QtCore/QPair>
00004 #include <QtCore/QtDebug>
00005 #include <QtCore/QSettings>
00006 #include <QtCore/QRegExp>
00007 #include <QtGui/QColor>
00008 #include <QtGui/QValidator>
00009 #include <QtGui/QRegExpValidator>
00010 #include <QtGui/QIntValidator>
00011 #include <QtGui/QDoubleValidator>
00012
00013 #include "ACE/foldertablemodel.h"
00014 #include "ACE/ACE_Errors.h"
00015
00016
00017 FolderTableModel::FolderTableModel( cool::IFolderPtr folderPtr, cool::ValidityKey start, cool::ValidityKey end, cool::ChannelSelection channels, QString tag, QObject* parent )
00018 try :
00019 QAbstractTableModel( parent ),
00020 coolFolderPtr( folderPtr ),
00021 payloadSpec( coolFolderPtr->payloadSpecification() ),
00022 filtered( false )
00023 {
00024 QSettings settings;
00025 setupFolderTableModelData( start, end, channels, tag );
00026 defaultCopyRow = rowCount() - 1;
00027 settings.beginGroup( "Preferences/FolderTables" );
00028 newRowColour = settings.value( "NewRowBGColour", QString( "#00FFFF" ) ).toString();
00029 modifiedColour = settings.value( "ModifiedBGColour", QString( "#DDFFFF" ) ).toString();
00030 filteredColour = settings.value( "FilteredBGColour", QString( "#DDEEFF" ) ).toString();
00031 settings.beginGroup( "Mask" );
00032 if ( settings.value( "ChannelId_Hex", true ).toBool() )
00033 {
00034 displayAsMaskHash[ 0 ] = hexMask;
00035 }
00036 displayAsMaskHash[ 1 ] = datetimeMask;
00037 displayAsMaskHash[ 2 ] = datetimeMask;
00038 maskColour = settings.value( "MaskColour", QString( "#000080" ) ).toString();
00039 settings.endGroup();
00040 settings.endGroup();
00041 columnResponseHash[ 0 ] = confirmResponse;
00042 columnResponseHash[ 1 ] = readonlyResponse;
00043 columnResponseHash[ 2 ] = readonlyResponse;
00044 }
00045 catch ( ace_errors::EmptyFolder &e )
00046 {
00047 qCritical() << "Could not construct FolderTableModel from empty folder!";
00048 throw;
00049 }
00050 catch ( ... )
00051 {
00052 qCritical() << "Unknown error! Could not construct FolderTableModel!";
00053 throw;
00054 }
00055
00056 FolderTableModel::~FolderTableModel()
00057 {
00058 delete rootTableItem;
00059 }
00060
00061 Qt::ItemFlags FolderTableModel::flags( const QModelIndex& index ) const
00062 {
00063 if ( !index.isValid() )
00064 return 0;
00065 else if ( columnResponseHash.value( index.column(), noResponse ) == readonlyResponse )
00066 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
00067 else
00068 return QAbstractTableModel::flags( index ) | Qt::ItemIsEditable;
00069 }
00070
00071 int FolderTableModel::rowCount( const QModelIndex& parent ) const
00072 {
00073 if ( parent.column() > 0 )
00074 return 0;
00075
00076 if ( !parent.isValid() )
00077 return rootTableItem->childCount();
00078 else
00079 return 0;
00080 }
00081
00082 int FolderTableModel::columnCount( const QModelIndex& parent ) const
00083 {
00084 if ( parent.isValid() )
00085 return static_cast<FolderTableItem*>( parent.internalPointer() )->columnCount();
00086 else
00087 return rootTableItem->columnCount();
00088 }
00089
00090 QVariant FolderTableModel::headerData( int section, Qt::Orientation orientation, int role ) const
00091 {
00092 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole )
00093 return QVariant( rootTableItem->header( section ) );
00094
00095 return QVariant();
00096 }
00097
00098 QModelIndex FolderTableModel::index( int row, int column, const QModelIndex& parent) const
00099 {
00100 if ( !hasIndex( row, column, parent ) )
00101 return QModelIndex();
00102
00103 if ( !parent.isValid() )
00104 {
00105 FolderTableItem* childItem = rootTableItem->child( row );
00106 if ( childItem )
00107 return createIndex( row, column, childItem );
00108 else
00109 return QModelIndex();
00110 }
00111 else
00112 {
00113 qCritical() << "FolderTableItems should not have children!";
00114 return QModelIndex();
00115 }
00116 }
00117
00118 QModelIndex FolderTableModel::parent( const QModelIndex& ) const
00119 {
00120
00121 return QModelIndex();
00122 }
00123
00124 void FolderTableModel::setupFolderTableModelData( cool::ValidityKey start, cool::ValidityKey end, cool::ChannelSelection channels, QString tag )
00125 {
00126 cool::IObjectIteratorPtr ic;
00127 bool ok( false );
00128
00129 if ( start == cool::ValidityKeyMax )
00130 {
00131 ic = coolFolderPtr->findObjects( start - 1, channels, tag.toStdString() );
00132 }
00133 else
00134 {
00135 ic = coolFolderPtr->browseObjects( start, end, channels, tag.toStdString() );
00136 }
00137
00138
00139
00140 if ( ic->isEmpty() )
00141 {
00142 throw ace_errors::EmptyFolder();
00143 }
00144
00145
00146 QList< QPair< QString, QVariant > > hTypeList;
00147 QList<QString> hNames;
00148 QString typeName;
00149 hNames << "ChannelId" << "Since" << "Until";
00150 hTypeList.append( qMakePair( QString( "UInt32" ), QVariant( getQVariantType( std::string( "UInt32" ) ) ) ) );
00151 hTypeList.append( qMakePair( QString::fromStdString( "UInt63" ), QVariant( getQVariantType( std::string( "UInt63" ) ) ) ) );
00152 hTypeList.append( qMakePair( QString::fromStdString( "UInt63" ), QVariant( getQVariantType( std::string( "UInt63" ) ) ) ) );
00153 for ( unsigned int i=0; i<payloadSpec.size(); i++ )
00154 {
00155 const cool::IFieldSpecification& fSpec = payloadSpec[ i ];
00156 const cool::StorageType& st = fSpec.storageType();
00157
00158 hNames.append( QString::fromStdString( fSpec.name() ) );
00159
00160
00161 typeName = QString::fromStdString( st.name() );
00162 hTypeList.append( qMakePair( typeName, QVariant( getQVariantType( st.name() ) ) ) );
00163 if ( ( typeName == "Blob64k" ) || ( typeName == "Blob16M" ) )
00164 {
00165 displayAsMaskHash[ i + 3 ] = blobMask;
00166 }
00167 else if ( ( typeName == "String4k" ) || ( typeName == "String64k" ) || ( typeName == "String16M") )
00168 {
00169 displayAsMaskHash[ i + 3 ] = clobMask;
00170 }
00171 else if ( typeName == "UChar" )
00172 {
00173 displayAsMaskHash[ i + 3 ] = decMask;
00174 }
00175 }
00176
00177 rootTableItem = new RootFolderTableItem( hNames, hTypeList );
00178
00179
00180
00181 while ( ic->goToNext() )
00182 {
00183 const cool::IObject& o = ic->currentRef();
00184 const cool::IRecord& r = o.payload();
00185 const cool::IRecordSpecification& recordSpec = r.specification();
00186 QList<QVariant> entryData;
00187 entryData << QVariant( o.channelId() ) << QVariant( o.since() ) << QVariant( o.until() );
00188 for ( unsigned int i=0; i<recordSpec.size(); i++ )
00189 {
00190 const cool::IField& f = r[ i ];
00191 DisplayAsMask currentMask = getDisplayAsMask( i + 3 );
00192 if ( currentMask == blobMask )
00193 {
00194 const coral::Blob& tempBlob = o.payloadValue< coral::Blob >( f.name() );
00195 entryData.append( QVariant( QByteArray( static_cast<const char*>( tempBlob.startingAddress() ), ( int ) tempBlob.size() ) ) );
00196 }
00197 else
00198 {
00199 entryData.append( qStringToQVariant( QString::fromStdString( o.payloadValue( f.name() ) ), &ok, i+3 ) );
00200 }
00201 }
00202 FolderTableItem* newTableItem = new FolderTableItem( entryData, rootTableItem, false );
00203 rootTableItem->appendChild( newTableItem );
00204 }
00205 }
00206
00207 bool FolderTableModel::setHeaderData( int , Qt::Orientation , const QVariant& , int )
00208 {
00209
00210
00211
00212
00213 return false;
00214 }
00215
00216 bool FolderTableModel::removeRows( int row, int count, const QModelIndex& parent )
00217 {
00218 if ( count < 1 || row < 0 )
00219 {
00220 qWarning() << "Either count < 1 or row < 0";
00221 return false;
00222 }
00223
00224 if ( parent.isValid() )
00225 {
00226 qCritical() << "Parent index provided does not refer to the rootTableItem!";
00227 return false;
00228 }
00229
00230 beginRemoveRows( QModelIndex(), row, row + count - 1 );
00231 while ( count-- )
00232 {
00233 delete rootTableItem->child( row );
00234 rootTableItem->removeChildAt( row );
00235 }
00236 endRemoveRows();
00237 if ( !rootTableItem->anyNew() )
00238 {
00239 emit modelChanged( this, false );
00240 }
00241 return true;
00242 }
00243
00244
00245 bool FolderTableModel::insertRows( int row, int count, const QModelIndex& parent )
00246 {
00247 if ( count < 1 || row < 0 )
00248 {
00249 qWarning() << "Either count < 1 or row < 0";
00250 return false;
00251 }
00252 if ( parent.isValid() )
00253 {
00254 qCritical() << "Parent index provided does not refer to the rootTableItem!";
00255 return false;
00256 }
00257 beginInsertRows( QModelIndex(), row, row + count - 1 );
00258 while ( count-- )
00259 {
00260 FolderTableItem* cloneSourceTableItem = rootTableItem->child( defaultCopyRow );
00261 FolderTableItem* newTableItem = new FolderTableItem( cloneSourceTableItem->data(), rootTableItem, true );
00262 newTableItem->setData( QVariant( (qulonglong)( QDateTime::currentDateTime().toTime_t() ) * (qulonglong)( 1000000000 ) ), 1 );
00263 newTableItem->setData( QVariant( cool::ValidityKeyMax ), 2 );
00264 newTableItem->setClonedSourceItem( cloneSourceTableItem );
00265 rootTableItem->insertChild( newTableItem, row );
00266 }
00267 endInsertRows();
00268 emit modelChanged( this, true );
00269 return true;
00270 }
00271
00272 QVariant::Type FolderTableModel::getQVariantType( const std::string& coolType ) const
00273 {
00274 if ( coolType == "Bool" )
00275 return QVariant::Bool;
00276 else if ( coolType == "UChar" )
00277 return QVariant::Char;
00278 else if ( coolType == "Int16" )
00279 return QVariant::Int;
00280 else if ( coolType == "UInt16" )
00281 return QVariant::UInt;
00282 else if ( coolType == "Int32" )
00283 return QVariant::Int;
00284 else if ( coolType == "UInt32" )
00285 return QVariant::UInt;
00286 else if ( coolType == "UInt63" )
00287 return QVariant::ULongLong;
00288 else if ( coolType == "Int64" )
00289 return QVariant::LongLong;
00290 else if ( coolType == "Float" )
00291 return QVariant::Double;
00292 else if ( coolType == "Double" )
00293 return QVariant::Double;
00294 else if ( coolType == "String255" )
00295 return QVariant::String;
00296 else if ( coolType == "String4k" )
00297 return QVariant::String;
00298 else if ( coolType == "String64k" )
00299 return QVariant::String;
00300 else if ( coolType == "String16M" )
00301 return QVariant::String;
00302 else if ( coolType == "Blob64k" )
00303 return QVariant::ByteArray;
00304 else if ( coolType == "Blob16M" )
00305 return QVariant::ByteArray;
00306 else
00307 {
00308 qWarning() << "[getQVariantType()] Unrecognised COOL type (" << QString::fromStdString( coolType ) << ") provided!";
00309 return QVariant::Invalid;
00310 }
00311 }
00312
00313 QVariant::Type FolderTableModel::getQVariantType( const QModelIndex& index ) const
00314 {
00315 if ( index.isValid() )
00316 return rootTableItem->headerType( index.column() ).second.type();
00317 qWarning() << "[getQVariantType()]: Invalid index provided!";
00318 return QVariant::Invalid;
00319 }
00320
00321 QVariant::Type FolderTableModel::getQVariantType( const QString& field ) const
00322 {
00323 int column = rootTableItem->headerPos( field );
00324 if ( column == -1 )
00325 {
00326 qWarning() << "[getQVariantType()]: " << field << " not found!";
00327 return QVariant::Invalid;
00328 }
00329 return rootTableItem->headerType( column ).second.type();
00330 }
00331
00332 QVariant::Type FolderTableModel::getQVariantType( int column ) const
00333 {
00334 if ( column <= columnCount() )
00335 return rootTableItem->headerType( column ).second.type();
00336 qWarning() << "[getQVariantType()]: No such column!";
00337 return QVariant::Invalid;
00338 }
00339
00340 QString FolderTableModel::getCoolTypeString( const QModelIndex& index ) const
00341 {
00342 if ( index.isValid() )
00343 return rootTableItem->headerType( index.column() ).first;
00344 qWarning() << "[getCoolTypeString()]: Invalid index provided!";
00345 return QString( "Unknown type" );
00346 }
00347
00348 RootFolderTableItem* FolderTableModel::getRootTableItem() const
00349 {
00350 return rootTableItem;
00351 }
00352
00353 void FolderTableModel::setDefaultCopyRow( int row )
00354 {
00355 if ( row < rowCount() )
00356 defaultCopyRow = row;
00357 else
00358 qWarning() << "Trying to set a non-existent row as the defaultCopyRow!";
00359 }
00360
00361
00362 QList< int > FolderTableModel::filter( FilterFunction0 f, bool inverse, bool allChannels, int rowStartPos, int rowEndPos )
00363 {
00364 QList< int > selectedRows;
00365 int startRow = 0, maxRow = rowCount() - 1;
00366 unsigned int channelId = 0;
00367
00368 if ( rowStartPos != -1 )
00369 {
00370 startRow = rowStartPos;
00371 if ( rowEndPos != -1 )
00372 maxRow = rowEndPos;
00373 }
00374
00375
00376
00377 if ( !allChannels )
00378 {
00379 channelId = getRootTableItem()->child( startRow )->getChannelId();
00380 }
00381
00382
00383 for ( int r = startRow; r <= maxRow; r++ )
00384 {
00385
00386
00387 if ( !allChannels && ( getRootTableItem()->child( r )->getChannelId() != channelId ) )
00388 {
00389 continue;
00390 }
00391
00392 if ( inverse )
00393 {
00394 if ( !( this->*f )( r ) )
00395 {
00396 selectedRows.append( r );
00397 }
00398 }
00399 else
00400 {
00401 if ( ( this->*f )( r ) )
00402 {
00403 selectedRows.append( r );
00404 }
00405 }
00406 }
00407 return selectedRows;
00408 }
00409
00410
00411 QList< int > FolderTableModel::filter_mres( bool inverse )
00412 {
00413 return filter( &FolderTableModel::filter_mre, inverse );
00414 }
00415
00416
00417 bool FolderTableModel::filter_mre( int row )
00418 {
00419 return cool::ValidityKeyMax - getRootTableItem()->child( row )->data( 2 ).toLongLong() == 0;
00420 }
00421
00422
00423 int FolderTableModel::filter_mre_singleChannel( int row )
00424 {
00425 QList< int > filterResult( filter( &FolderTableModel::filter_mre, false, false, row ) ) ;
00426 if ( filterResult.count() > 1 )
00427 {
00428
00429 if ( getRootTableItem()->child( filterResult.at( 0 ) )->data( 1 ).toLongLong() > getRootTableItem()->child( filterResult.at( 1 ) )->data( 1 ).toLongLong() )
00430 return filterResult.at( 1 );
00431 else
00432 return filterResult.at( 0 );
00433 }
00434 else
00435 return filterResult.at( 0 );
00436 }
00437
00438
00439
00440
00441
00442 QList< FolderTableItem* > FolderTableModel::_updateValidityKeys( QList< FolderTableItem* > newTableItems )
00443 {
00444 foreach ( FolderTableItem* tableItem, newTableItems )
00445 {
00446 FolderTableItem* sourceItem( tableItem->getClonedSourceItem() );
00447 if ( !sourceItem )
00448 continue;
00449
00450 if ( sourceItem->getChannelId() == tableItem->getChannelId() )
00451 {
00452
00453
00454 if ( cool::ValidityKeyMax - sourceItem->data( 2 ).toLongLong() == 0 )
00455 {
00456 setData( index( sourceItem->row(), 2 ), tableItem->data( 1 ) );
00457 }
00458 else
00459 {
00460 setData( index( filter_mre_singleChannel( sourceItem->row() ), 2 ), tableItem->data( 1 ) );
00461 }
00462 }
00463 else
00464 {
00465 int modifiedChannelRow = getRootTableItem()->find( tableItem->getChannelId() );
00466 if ( modifiedChannelRow != tableItem->row() )
00467 {
00468 setData( index( filter_mre_singleChannel( modifiedChannelRow ), 2 ), tableItem->data( 1 ) );
00469 }
00470 }
00471 }
00472 return newTableItems;
00473 }
00474
00475 bool FolderTableModel::commit()
00476 {
00477 int totalColumns( rootTableItem->columnCount() );
00478 QVariant commitTime = QVariant( (qulonglong)( QDateTime::currentDateTime().toTime_t() ) * (qulonglong)( 1000000000 ) );
00479 QList< FolderTableItem* > newItems = rootTableItem->newItems();
00480 try
00481 {
00482 coolFolderPtr->setupStorageBuffer( true );
00483 foreach ( FolderTableItem* newItem, newItems )
00484 {
00485 cool::Record payload = cool::Record( payloadSpec );
00486 cool::ChannelId cId( newItem->getChannelId() );
00487 for ( int i = 3; i < totalColumns; i++ )
00488 {
00489 QPair< QString, QVariant > valueTypePair = rootTableItem->headerType( i );
00490 std::string coolType = valueTypePair.first.toStdString();
00491 std::string headerName = rootTableItem->header( i ).toStdString();
00492 if ( coolType == "Bool" )
00493 {
00494 payload[ headerName ].setValue<cool::Bool>( newItem->data( i ).value<bool>() );
00495 continue;
00496 }
00497 else if ( coolType == "UChar" )
00498 {
00499 payload[ headerName ].setValue<cool::UChar>( newItem->data( i ).toInt() );
00500 continue;
00501 }
00502 else if ( coolType == "Int16" )
00503 {
00504 payload[ headerName ].setValue<cool::Int16>( newItem->data( i ).value<short>() );
00505 continue;
00506 }
00507 else if ( coolType == "UInt16" )
00508 {
00509 payload[ headerName ].setValue<cool::UInt16>( newItem->data( i ).value<unsigned short>() );
00510 continue;
00511 }
00512 else if ( coolType == "Int32" )
00513 {
00514 payload[ headerName ].setValue<cool::Int32>( newItem->data( i ).value<int>() );
00515 continue;
00516 }
00517 else if ( coolType == "UInt32" )
00518 {
00519 payload[ headerName ].setValue<cool::UInt32>( newItem->data( i ).value<unsigned int>() );
00520 continue;
00521 }
00522 else if ( coolType == "UInt63" )
00523 {
00524 payload[ headerName ].setValue<cool::UInt63>( newItem->data( i ).value<unsigned long long>() );
00525 continue;
00526 }
00527 else if ( coolType == "Int64" )
00528 {
00529 payload[ headerName ].setValue<cool::Int64>( newItem->data( i ).value<long long>() );
00530 continue;
00531 }
00532 else if ( coolType == "Float" )
00533 {
00534 payload[ headerName ].setValue<cool::Float>( newItem->data( i ).value<float>() );
00535 continue;
00536 }
00537 else if ( coolType == "Double" )
00538 {
00539 payload[ headerName ].setValue<cool::Double>( newItem->data( i ).value<double>() );
00540 continue;
00541 }
00542 else if ( coolType == "String255" )
00543 {
00544 payload[ headerName ].setValue<cool::String255>( newItem->data( i ).toString().toStdString() );
00545 continue;
00546 }
00547 else if ( coolType == "String4k" )
00548 {
00549 payload[ headerName ].setValue<cool::String4k>( newItem->data( i ).toString().toStdString() );
00550 continue;
00551 }
00552 else if ( coolType == "String64k" )
00553 {
00554 payload[ headerName ].setValue<cool::String64k>( newItem->data( i ).toString().toStdString() );
00555 continue;
00556 }
00557 else if ( coolType == "String16M" )
00558 {
00559 payload[ headerName ].setValue<cool::String16M>( newItem->data( i ).toString().toStdString() );
00560 continue;
00561 }
00562 else if ( coolType == "Blob64k" )
00563 {
00564 QByteArray ba = newItem->data( i ).value<QByteArray>();
00565 int blobSize = ( int ) ba.size();
00566 const char* rawdata = ba.constData();
00567 cool::Blob64k blob;
00568 blob.resize( blobSize );
00569 char* p = static_cast<char*>( blob.startingAddress() );
00570 for ( int j = 0; j < blobSize; ++j, ++p, ++rawdata ) *p = *rawdata;
00571 payload[ headerName ].setValue<cool::Blob64k>( blob );
00572 continue;
00573 }
00574 else if ( coolType == "Blob16M" )
00575 {
00576 QByteArray ba = newItem->data( i ).value<QByteArray>();
00577 int blobSize = ( int ) ba.size();
00578 const char* rawdata = ba.constData();
00579 cool::Blob16M blob;
00580 blob.resize( blobSize );
00581 char* p = static_cast<char*>( blob.startingAddress() );
00582 for ( int j = 0; j < blobSize; ++j, ++p, ++rawdata ) *p = *rawdata;
00583 payload[ headerName ].setValue<cool::Blob16M>( blob );
00584 continue;
00585 }
00586 else
00587 qWarning() << "COOL type" << valueTypePair.first << "not recognised. Skipping.";
00588 }
00589 newItem->setData( commitTime, 1 );
00590 coolFolderPtr->storeObject( cool::ValidityKey( newItem->data( 1 ).toLongLong() ), cool::ValidityKey( newItem->data( 2 ).toLongLong() ), payload, cId );
00591 }
00592 coolFolderPtr->flushStorageBuffer();
00593
00594
00595
00596
00597 foreach ( FolderTableItem* newItem, _updateValidityKeys( newItems ) )
00598 {
00599 newItem->setOld();
00600 }
00601 }
00602 catch ( cool::Exception& e )
00603 {
00604 qCritical() << "COOL Exception: Error storing object. " << e.what();
00605 return false;
00606 }
00607 catch ( coral::Exception& e )
00608 {
00609 qCritical() << "CORAL Exception: Error storing object. " << e.what();
00610 return false;
00611 }
00612 reset();
00613 emit modelChanged( this, false );
00614
00615 return true;
00616 }
00617
00618 bool FolderTableModel::isNewRow( int row ) const
00619 {
00620 FolderTableItem* item = rootTableItem->child( row );
00621 if ( item )
00622 return item->isNew();
00623 else
00624 return false;
00625 }
00626
00627 QSet< unsigned int > FolderTableModel::newRowChannelIds( QList< FolderTableItem* > newTableItems ) const
00628 {
00629 QSet< unsigned int > channelIds;
00630 if ( newTableItems.isEmpty() )
00631 {
00632 newTableItems = rootTableItem->newItems();
00633 }
00634 foreach ( FolderTableItem* item, newTableItems )
00635 {
00636 channelIds.insert( item->getChannelId() );
00637 }
00638 return channelIds;
00639 }
00640
00641 void FolderTableModel::setData( const QModelIndexList& indexList, const QVariant& value, int role )
00642 {
00643 QModelIndex index;
00644 foreach ( index, indexList )
00645 {
00646 if ( flags( index ) & Qt::ItemIsEditable )
00647 {
00648 setData( index, value, role );
00649 }
00650 }
00651 }
00652
00653 bool FolderTableModel::setData( const QModelIndex& index, const QVariant& value, int role )
00654 {
00655 bool ok( false );
00656 if ( index.isValid() && role == Qt::EditRole )
00657 {
00658
00659
00660
00661 FolderTableItem* currentItem = static_cast<FolderTableItem*>( index.internalPointer() );
00662 int column = index.column();
00663 DisplayAsMask currentMask = getDisplayAsMask( column );
00664 QVariant newQVariant;
00665
00666 switch ( currentMask )
00667 {
00668 case octMask:
00669 if ( value.canConvert( QVariant::String ) )
00670 {
00671 newQVariant = qStringToQVariant( value.toString(), &ok, column, 8 );
00672 }
00673 if ( ok )
00674 {
00675 currentItem->setData( newQVariant, column );
00676 }
00677 else
00678 {
00679 qWarning() << "Error storing octal value: " << value;
00680 return false;
00681 }
00682 break;
00683
00684 case decMask:
00685 if ( value.canConvert( QVariant::String ) )
00686 {
00687 newQVariant = qStringToQVariant( value.toString(), &ok, column, 10 );
00688 }
00689 if ( ok )
00690 {
00691 currentItem->setData( newQVariant, column );
00692 }
00693 else
00694 {
00695 qWarning() << "Error storing decimal value:" << value;
00696 return false;
00697 }
00698 break;
00699
00700 case hexMask:
00701 if ( value.canConvert( QVariant::String ) )
00702 {
00703 newQVariant = qStringToQVariant( value.toString(), &ok, column, 16 );
00704 }
00705 if ( ok )
00706 {
00707 currentItem->setData( newQVariant, column );
00708 }
00709 else
00710 {
00711 qWarning() << "Error storing hexadecimal value: " << value;
00712 return false;
00713 }
00714 break;
00715
00716 case blobMask:
00717 if ( value.canConvert( QVariant::ByteArray ) )
00718 {
00719 currentItem->setData( value, column );
00720 }
00721 else
00722 {
00723 qWarning() << "Error storing blob.";
00724 return false;
00725 }
00726 break;
00727
00728 case clobMask:
00729 if ( value.canConvert( QVariant::String ) )
00730 {
00731 currentItem->setData( value, column );
00732 }
00733 else
00734 {
00735 qWarning() << "Error storing clob.";
00736 return false;
00737 }
00738 break;
00739
00740 case datetimeMask:
00741
00742 case noMask:
00743 if ( value.canConvert( QVariant::String ) )
00744 {
00745 newQVariant = qStringToQVariant( value.toString(), &ok, column, 10 );
00746 }
00747 if ( ok )
00748 {
00749 currentItem->setData( newQVariant, column );
00750 }
00751 else
00752 {
00753 qWarning() << "Invalid value detected: " << value;
00754 return false;
00755 }
00756 break;
00757 }
00758 if ( ok )
00759 {
00760 emit dataChanged( index, index );
00761 }
00762 }
00763 return ok;
00764 }
00765
00766 QVariant FolderTableModel::getMaskedData( FolderTableItem*& item, int column ) const
00767 {
00768 DisplayAsMask currentMask = getDisplayAsMask( column );
00769 QVariant currentValue( item->data( column ) );
00770 bool ok( false );
00771
00772 switch ( currentMask )
00773 {
00774 case octMask:
00775 currentValue = applyMaskToQVariant( QString( "%L1" ), currentValue, column, &ok, 0, 8 );
00776 break;
00777
00778 case decMask:
00779 currentValue = applyMaskToQVariant( QString( "%L1" ), currentValue, column, &ok, 0, 10 );
00780 break;
00781
00782 case hexMask:
00783 currentValue = applyMaskToQVariant( QString( "%L1" ), currentValue, column, &ok, 0, 16 );
00784 break;
00785
00786 case datetimeMask:
00787 if ( currentValue.canConvert( QVariant::ULongLong ) )
00788 {
00789 if ( cool::ValidityKeyMax-currentValue.toLongLong() == 0 )
00790 {
00791 currentValue = QVariant( "ValidityKeyMax" );
00792 }
00793 else
00794 {
00795 currentValue = QVariant( QDateTime::fromTime_t( currentValue.toString().left(10).toUInt() ).toString( Qt::ISODate ) );
00796 }
00797 }
00798 break;
00799
00800 case blobMask:
00801 currentValue = QVariant( "Blob" );
00802 break;
00803
00804 case clobMask:
00805 currentValue = QVariant( "Clob" );
00806 break;
00807
00808 case noMask:
00809 break;
00810 }
00811 return currentValue;
00812 }
00813
00814
00815
00816
00817 QVariant FolderTableModel::data( const QModelIndex& index, int role ) const
00818 {
00819 if ( !index.isValid() )
00820 return QVariant();
00821 FolderTableItem* item = static_cast<FolderTableItem*>( index.internalPointer() );
00822
00823 if ( role == Qt::DisplayRole )
00824 {
00825 return getMaskedData( item, index.column() );
00826 }
00827 else if ( role == Qt::BackgroundRole )
00828 {
00829 if ( item->isNew() )
00830 {
00831 return QVariant( QColor( newRowColour ) );
00832 }
00833
00834 if ( isFiltered() )
00835 {
00836 return QVariant( QColor( filteredColour ) );
00837 }
00838 }
00839 else if ( role == Qt::ForegroundRole )
00840 {
00841 if ( hasMask( index.column() ) )
00842 {
00843 return QVariant( QColor( maskColour ) );
00844 }
00845 }
00846 else if ( role == Qt::ToolTipRole )
00847 {
00848 return QVariant( getCoolTypeString( index ) );
00849 }
00850 return QVariant();
00851 }
00852
00853 QVariant FolderTableModel::rawData( const QModelIndex& index ) const
00854 {
00855 FolderTableItem* item = static_cast<FolderTableItem*>( index.internalPointer() );
00856 return item->data( index.column() );
00857 }
00858
00859 DisplayAsMask FolderTableModel::getDisplayAsMask( int column ) const
00860 {
00861 return displayAsMaskHash.value( column, noMask );
00862 }
00863
00864 ColumnResponse FolderTableModel::getColumnResponse( int column ) const
00865 {
00866 return columnResponseHash.value( column, noResponse );
00867 }
00868
00869
00870 bool FolderTableModel::hasMask( int column ) const
00871 {
00872 return displayAsMaskHash.contains( column );
00873 }
00874
00875 void FolderTableModel::setDisplayAsMask( const QModelIndex& index, DisplayAsMask dMask )
00876 {
00877 if ( !index.isValid() )
00878 {
00879 return;
00880 }
00881 int column = index.column();
00882 if ( column < rootTableItem->columnCount() )
00883 {
00884 if ( dMask == noMask )
00885 {
00886 displayAsMaskHash.remove( column );
00887 }
00888 else
00889 {
00890 displayAsMaskHash[ column ] = dMask;
00891 }
00892 emit dataChanged( index.sibling( 0, column ), index.sibling( rootTableItem->childCount() - 1, column ) );
00893 }
00894 else
00895 {
00896 qWarning() << "Column" << column << "does not exist!";
00897 }
00898 }
00899
00900 bool FolderTableModel::canSetDisplayAsMask( const QModelIndex& index ) const
00901 {
00902
00903
00904 return index.isValid();
00905 }
00906
00907 bool FolderTableModel::canSetDisplayAsMask( const QModelIndexList& indexList ) const
00908 {
00909 foreach ( QModelIndex index, indexList )
00910 {
00911 if ( canSetDisplayAsMask( index ) )
00912 return true;
00913 }
00914 return false;
00915 }
00916
00917 QVariant FolderTableModel::qStringToQVariant( QString value, bool* ok, int column, int base )
00918 {
00919 QString testValue;
00920 switch ( getQVariantType( column ) )
00921 {
00922 case QVariant::Bool:
00923 *ok = true;
00924 testValue = value.simplified().toLower();
00925 if ( testValue == "false" || testValue == "0" || testValue.isEmpty() || testValue.isNull() )
00926 {
00927 return QVariant( false );
00928 }
00929 return QVariant( true );
00930 break;
00931 case QVariant::Char:
00932 return QVariant( QChar( value.toInt( ok, base ) ) );
00933 break;
00934 case QVariant::Int:
00935 return QVariant( value.toInt( ok, base ) );
00936 break;
00937 case QVariant::UInt:
00938 return QVariant( value.toUInt( ok, base ) );
00939 break;
00940 case QVariant::LongLong:
00941 return QVariant( value.toLongLong( ok, base ) );
00942 break;
00943 case QVariant::ULongLong:
00944 return QVariant( value.toULongLong( ok, base ) );
00945 break;
00946 case QVariant::Double:
00947 return QVariant( value.toDouble( ok ) );
00948 break;
00949 case QVariant::String:
00950 *ok = true;
00951 return QVariant( value );
00952 break;
00953 case QVariant::ByteArray:
00954 *ok = true;
00955 return QVariant( value.toAscii() );
00956 break;
00957 default:
00958 *ok = false;
00959 qDebug() << "Unknown type --- returning QVariant()";
00960 return QVariant();
00961 break;
00962 }
00963 }
00964
00965
00966 QVariant FolderTableModel::applyMaskToQVariant( QString format, QVariant currentValue, int column, bool* ok, int fieldWidth, int base, const QChar& fillChar ) const
00967 {
00968 switch ( getQVariantType( column ) )
00969 {
00970 case QVariant::Bool:
00971 *ok = true;
00972 return QVariant( currentValue.toBool() );
00973 break;
00974 case QVariant::Char:
00975 return QVariant( format.arg( currentValue.toInt( ok ), fieldWidth, base, fillChar ) );
00976 break;
00977 case QVariant::Int:
00978 return QVariant( format.arg( currentValue.toInt( ok ), fieldWidth, base, fillChar ).toUpper() );
00979 break;
00980 case QVariant::UInt:
00981 return QVariant( format.arg( currentValue.toUInt( ok ), fieldWidth, base, fillChar ).toUpper() );
00982 break;
00983 case QVariant::LongLong:
00984 return QVariant( format.arg( currentValue.toLongLong( ok ), fieldWidth, base, fillChar ).toUpper() );
00985 break;
00986 case QVariant::ULongLong:
00987 return QVariant( format.arg( currentValue.toULongLong( ok ), fieldWidth, base, fillChar ).toUpper() );
00988 break;
00989 case QVariant::Double:
00990 return QVariant( format.arg( currentValue.toDouble( ok ), fieldWidth, 'g', -1, fillChar ).toUpper() );
00991 break;
00992 case QVariant::String:
00993 default:
00994 *ok = true;
00995 return currentValue;
00996 break;
00997 }
00998 }
00999
01000 QString FolderTableModel::getInputMask( const QModelIndex& ) const
01001 {
01002 return "";
01003 }
01004
01005 QValidator* FolderTableModel::getValidator( const QModelIndex& index ) const
01006 {
01007 return getValidator( index.column() );
01008 }
01009
01010 QValidator* FolderTableModel::getValidator( unsigned int column ) const
01011 {
01012 DisplayAsMask currentMask = getDisplayAsMask( column );
01013 QRegExp rx;
01014 std::string cooltype;
01015
01016 switch ( currentMask )
01017 {
01018 case octMask:
01019 rx.setPattern( "[0-7]+" );
01020 return new QRegExpValidator( rx, 0 );
01021 break;
01022
01023 case decMask:
01024 if ( getQVariantType( column ) == QVariant::Char )
01025 {
01026 QIntValidator* iv = new QIntValidator( 0 );
01027 iv->setRange( 0, 255 );
01028 return iv;
01029 }
01030 else
01031 return new QIntValidator( 0 );
01032 break;
01033
01034 case hexMask:
01035 rx.setPattern( "[0-9a-fA-F]+" );
01036 return new QRegExpValidator( rx, 0 );
01037 break;
01038
01039 case datetimeMask:
01040
01041 return 0;
01042 break;
01043
01044 case blobMask:
01045 case clobMask:
01046 return 0;
01047 break;
01048
01049 case noMask:
01050
01051 switch ( getQVariantType( column ) )
01052 {
01053 case QVariant::Char:
01054 return new QIntValidator( 0, 255, 0 );
01055 break;
01056 case QVariant::Int:
01057 cooltype = rootTableItem->headerType( column ).first.toStdString();
01058 if ( cooltype == "Int16" )
01059 return new QIntValidator( cool::Int16Min, cool::Int16Max, 0 );
01060 else
01061 return new QIntValidator( cool::Int32Min, cool::Int32Max, 0 );
01062 break;
01063 case QVariant::UInt:
01064 cooltype = rootTableItem->headerType( column ).first.toStdString();
01065 if ( cooltype == "UInt16" )
01066 return new QIntValidator( cool::UInt16Min, cool::UInt16Max, 0 );
01067 else
01068 {
01069 QDoubleValidator* dValidator = new QDoubleValidator( cool::UInt32Min, cool::UInt32Max, 0, 0 );
01070 dValidator->setNotation( QDoubleValidator::StandardNotation );
01071 return dValidator;
01072 }
01073 break;
01074 case QVariant::Double:
01075 return new QDoubleValidator( 0 );
01076 break;
01077 case QVariant::LongLong:
01078 rx.setPattern( "-?\\d+" );
01079 return new QRegExpValidator( rx, 0 );
01080 break;
01081 case QVariant::ULongLong:
01082 rx.setPattern( "\\d+" );
01083 return new QRegExpValidator( rx, 0 );
01084 break;
01085 case QVariant::String:
01086 default:
01087 return 0;
01088 break;
01089 }
01090 break;
01091 }
01092 return 0;
01093 }
01094
01095 void FolderTableModel::sort( int column, Qt::SortOrder order = Qt::AscendingOrder )
01096 {
01097 emit layoutAboutToBeChanged();
01098 rootTableItem->sort( column, order );
01099 emit layoutChanged();
01100 }
01101
01102 int FolderTableModel::compare( const QModelIndex& index, QString value )
01103 {
01104 bool ok( true );
01105 int base;
01106 int column = index.column();
01107 QVariant valueAsQVariant( value );
01108 QVariant valueAtIndex;
01109 switch ( getDisplayAsMask( column ) )
01110 {
01111 case blobMask:
01112
01113 return 0;
01114 break;
01115
01116 case octMask:
01117 base = 8;
01118 break;
01119
01120 case hexMask:
01121 base = 16;
01122 break;
01123
01124 case clobMask:
01125 case decMask:
01126 default:
01127 base = 10;
01128 break;
01129 }
01130
01131 valueAsQVariant = qStringToQVariant( value, &ok, column, base );
01132
01133 valueAtIndex = rawData( index );
01134
01135
01136 if ( ok )
01137 {
01138 return compareQVariants( valueAtIndex, valueAsQVariant );
01139 }
01140 qDebug() << "Comparison failed. Could not convert "<< value << " to a QVariant.\nTreating as strings instead.";
01141 return QString::localeAwareCompare( valueAtIndex.toString(), value );
01142 }
01143
01144 int FolderTableModel::compareQVariants( QVariant a, QVariant b )
01145 {
01146 QVariant::Type typeA = a.type();
01147 double dTest = 0.0;
01148
01149 if ( typeA != b.type() )
01150 {
01151
01152 qDebug() << "Types do not match. Treating as strings instead.";
01153 typeA = QVariant::String;
01154 }
01155
01156 switch ( typeA )
01157 {
01158 case QVariant::Bool:
01159 return a.toBool() - b.toBool();
01160 break;
01161 case QVariant::Char:
01162 case QVariant::Int:
01163 return a.toInt() - b.toInt();
01164 break;
01165 case QVariant::LongLong:
01166 return a.toLongLong() - b.toLongLong();
01167 break;
01168 case QVariant::UInt:
01169 return a.toUInt() - b.toUInt();
01170 break;
01171 case QVariant::ULongLong:
01172 return a.toULongLong() - b.toULongLong();
01173 break;
01174 case QVariant::Double:
01175 dTest = a.toDouble() - b.toDouble();
01176 if ( dTest == 0.0 )
01177 return 0;
01178 else if ( dTest > 0.0 )
01179 return 1;
01180 else
01181 return -1;
01182 break;
01183 case QVariant::String:
01184 return QString::localeAwareCompare( a.toString(), b.toString() );
01185 break;
01186 case QVariant::ByteArray:
01187 default:
01188 return 0;
01189 break;
01190 }
01191 }
01192
01193 void FolderTableModel::setFiltered( bool enabled )
01194 {
01195 filtered = enabled;
01196 }
01197
01198 bool FolderTableModel::isFiltered() const
01199 {
01200 return filtered;
01201 }
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225