diff -r 0ba996a9b75d -r 613943a21004 bluetoothengine/btui/btuimodel/btdevicemodel_p.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothengine/btui/btuimodel/btdevicemodel_p.cpp Tue Aug 31 15:25:10 2010 +0300 @@ -0,0 +1,478 @@ +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +#include "btdevicemodel_p.h" +#include +#include +#include +#include "btuiutil.h" +#include "btuidevtypemap.h" +#include "btqtconstants.h" + +/*! + Constructor. + */ +BtDeviceModelPrivate::BtDeviceModelPrivate( BtDeviceModel& model, QObject *parent ) + : QObject( parent ), mModel( model ), mDiscover( 0 ), mSeqNum( 0 ) +{ + mDeviceRepo = 0; + isSearchingDevice = false; + TRAP_IGNORE({ + mDeviceRepo = CBtDevRepository::NewL(); + }); + Q_CHECK_PTR( mDeviceRepo ); + TRAP_IGNORE( mDeviceRepo->AddObserverL( this ) ); + + if ( mDeviceRepo->IsInitialized() ) { + initializeDataStore(); + } +} + +/*! + Destructor. + */ +BtDeviceModelPrivate::~BtDeviceModelPrivate() +{ + delete mDeviceRepo; + delete mDiscover; +} + + +/*! + Tells whether the given column is in the range of the setting list. + + \param row the row number to be checked + \param col the column number to be checked + + \return true if the given row and column are valid; false otherwise. +*/ +bool BtDeviceModelPrivate::isValid( int row, int column) const +{ + return row >= 0 && row < mData.count() && column == 0; +} + +/*! + \return the total amount of rows. + +*/ +int BtDeviceModelPrivate::rowCount() const +{ + return mData.count(); +} + +/*! + \return the total amount of columns. + +*/ +int BtDeviceModelPrivate::columnCount() const +{ + return 1; +} + +/*! + Gets the value within a data item. + \param val contains the value at return. + \param row the row number which the value is from + \param col the column number which the value is from + \param role the role identifier of the value. + */ +void BtDeviceModelPrivate::data(QVariant& val, int row, int col, int role ) const +{ + if ( isValid( row, col ) ) { + val = mData.at( row ).value( role ); + } + else { + val = QVariant( QVariant::Invalid ); + } +} + +/*! + Gets the whole item data at the specified column + \param row the row number of the item data to be returned + \param col the column number of the item data to be returned + \return the item data + */ +BtuiModelDataItem BtDeviceModelPrivate::itemData( int row, int col ) const +{ + if ( isValid( row, col ) ) { + return mData.at( row ); + } + return BtuiModelDataItem(); +} + + +/*! + Requests the model to searching Bluetooth devices. + \return true if the request is accepted; false otherwise + */ +bool BtDeviceModelPrivate::searchDevice() +{ + int err ( 0 ); + removeTransientDevices(); + if ( !mDiscover ) { + TRAP(err, mDiscover = CAdvanceDevDiscoverer::NewL( *mDeviceRepo, *this) ); + } + if ( !err ) { + TRAP(err, mDiscover->DiscoverDeviceL() ); + } + isSearchingDevice = true; + return err == 0; +} + +/*! + Cancels a possible outstanding device search request. + */ +void BtDeviceModelPrivate::cancelSearchDevice() +{ + if ( mDiscover ) { + isSearchingDevice = false; + mDiscover->CancelDiscovery(); + } +} + +/*! + Removes transient (not-in-registry) devices + (added as the result of device search). + */ +void BtDeviceModelPrivate::removeTransientDevices() +{ + // clear in-range property for all device items in this model. + int cnt = mData.count(); + for ( int i = mData.count() - 1; i > -1; --i) + { + const BtuiModelDataItem& qtdev = mData.at(i); + if(isDeviceInRange(qtdev)) { + if(isDeviceInRegistry(qtdev)) { + // we cannot remove this device as it is in registry. + // remove it in-range property. + setMajorProperty(mData[i], BtuiDevProperty::InRange, false); + updateRssi(mData[i], RssiInvalid); + updateSeqNum(mData[i], -1); + emit deviceDataChanged(i, this); + } + else { + // this device is not in-registry. Delete it from local + // store. + emit beginRemoveDevices(i, i, this); + mData.removeAt( i ); + emit endRemoveDevices(); + } + } + } +} + +/*! + callback from repository. + re-initialize our store. + */ +void BtDeviceModelPrivate::RepositoryInitialized() +{ + initializeDataStore(); +} + +/*! + callback from repository. + update our store. + */ +void BtDeviceModelPrivate::DeletedFromRegistry( const TBTDevAddr& addr ) +{ + int i = indexOf( addr ); + if ( i > -1 ) { + if ( isSearchingDevice && isDeviceInRange( mData.at(i) ) ) { + // device searching is ongoing, and it is in-range. we can not + // remove it from model now. + // clear-registry related properties, so that + // we get a chance to clean it after device searching later. + setMajorProperty(mData[i], BtuiDevProperty::RegistryProperties, false); + emit deviceDataChanged(i, this); + } + else { + emit beginRemoveDevices(i, i, this); + mData.removeAt( i ); + emit endRemoveDevices(); + } + } +} + +/*! + callback from repository. + update our store. + */ +void BtDeviceModelPrivate::AddedToRegistry( const CBtDevExtension& dev ) +{ + ChangedInRegistry( dev, 0 ); +} + +/*! + callback from repository. + update our store. + */ +void BtDeviceModelPrivate::ChangedInRegistry( + const CBtDevExtension& dev, TUint similarity ) +{ + int i = indexOf( dev.Addr() ); + if ( i == -1 ) { + BtuiModelDataItem devData; + if ( !isSearchingDevice ) { + // Rssi is only available at device inquiry stage. + // We initialize this property to an invalid value + updateRssi(devData, RssiInvalid); + } + // add device-in-registry property: + setMajorProperty(devData, BtuiDevProperty::InRegistry, true); + updateDeviceProperty(devData, dev, 0 ); + emit beginInsertDevices( mData.count(), mData.count(), this ); + mData.append( devData ); + emit endInsertDevices(); + } + else { + updateDeviceProperty(mData[i], dev, similarity ); + setMajorProperty(mData[i], BtuiDevProperty::InRegistry, true); + emit deviceDataChanged( i, this ); + } +} + +/*! + callback from repository. + update our store. + */ +void BtDeviceModelPrivate::ServiceConnectionChanged( + const CBtDevExtension& dev, TBool connected ) +{ + int i = indexOf( dev.Addr() ); + if ( i > -1 ) { + int preconn = BtuiDevProperty::Connected + & mData[i][BtDeviceModel::MajorPropertyRole].toInt(); + // we only update and signal if connection status is really + // changed: + if ( ( preconn != 0 && !connected ) + || ( preconn == 0 && connected ) ) { + setMajorProperty(mData[i], BtuiDevProperty::Connected, connected ); + emit deviceDataChanged( i, this ); + } + } + // it is impossible that a device has connected but it is not in + // our local store according to current bteng services. + // need to take more care in future when this becomes possible. +} + +/*! + callback from device search. + update our store. + */ +void BtDeviceModelPrivate::HandleNextDiscoveryResultL( + const TInquirySockAddr& inqAddr, const TDesC& name ) +{ + int pos = indexOf( inqAddr.BTAddr() ); + const CBtDevExtension* dev = mDeviceRepo->Device( inqAddr.BTAddr() ); + + //RssiRole + int rssi( RssiInvalid ); // initialize to an invalid value. + if( inqAddr.ResultFlags() & TInquirySockAddr::ERssiValid ) { + rssi = inqAddr.Rssi(); + } + + if ( pos == -1 ) { + BtuiModelDataItem devData; + setMajorProperty(devData, BtuiDevProperty::InRange, true); + updateRssi(devData, rssi); + updateSeqNum( devData, mSeqNum++ ); + CBtDevExtension* devExt(NULL); + TRAP_IGNORE( { + devExt = CBtDevExtension::NewLC( inqAddr, name ); + CleanupStack::Pop(); }); + updateDeviceProperty(devData, *devExt, 0); + delete devExt; + emit beginInsertDevices( mData.count(), mData.count(), this ); + mData.append( devData ); + emit endInsertDevices(); + } + else { + setMajorProperty(mData[pos], BtuiDevProperty::InRange, true); + updateRssi(mData[pos], rssi); + updateSeqNum( mData[pos], mSeqNum++ ); + emit deviceDataChanged( pos, this ); + } +} + +/*! + callback from device search. + inform client. + */ +void BtDeviceModelPrivate::HandleDiscoveryCompleted( TInt error ) +{ + isSearchingDevice = false; + // Reset the sequence number for the next search + mSeqNum = 0; + emit deviceSearchCompleted( (int) error ); +} + +void BtDeviceModelPrivate::initializeDataStore() + { + + mSeqNum = 0; // reset when starting search again + + // it is possible that we are searching devices. + // We use a simple but not-so-efficient method to update the model. + + // If the device store is not empty, we clear + // registry property from these devices first. + for (int i = 0; i < mData.count(); ++i) { + setMajorProperty(mData[i], BtuiDevProperty::RegistryProperties, false); + } + if ( mData.count() ) { + // need to update view because we have changed device properties. + emit deviceDataChanged( 0, mData.count() - 1, this ); + } + + const RDevExtensionArray& devs = mDeviceRepo->AllDevices(); + for (int i = 0; i < devs.Count(); ++i) { + int pos = indexOf( devs[i]->Addr() ); + if ( pos > -1 ) { + // add device-in-registry property: + setMajorProperty(mData[pos], BtuiDevProperty::InRegistry, true); + updateDeviceProperty(mData[pos], *(devs[i]), 0); + updateSeqNum(mData[pos], -1); + emit deviceDataChanged( pos, this ); + } + else { + BtuiModelDataItem devData; + // add device-in-registry property: + setMajorProperty(devData, BtuiDevProperty::InRegistry, true); + updateDeviceProperty(devData, *( devs[i] ), 0 ); + updateSeqNum(devData, -1); + emit beginInsertDevices(mData.count(), mData.count(), this ); + mData.append( devData ); + emit endInsertDevices(); + } + } +} + +void BtDeviceModelPrivate::updateDeviceProperty(BtuiModelDataItem& qtdev, + const CBtDevExtension& dev, TUint similarity ) +{ + // similarity is not used currently. + // It is possible to gain better performance + // with this info to avoid re-manipulate + // unchanged properties. + Q_UNUSED(similarity); + + //DevDisplayNameRole + QString str = QString::fromUtf16( + dev.Alias().Ptr(), dev.Alias().Length() ); + qtdev[BtDeviceModel::NameAliasRole] = QVariant( str ); + + //DevAddrReadableRole + addrSymbianToReadbleString( str, dev.Addr() ); + qtdev[BtDeviceModel::ReadableBdaddrRole] = QVariant( str ); + + //LastUsedTimeRole + TDateTime symDt = dev.Device().Used().DateTime(); + QDate date( symDt.Year(), symDt.Month(), symDt.Day() ); + QTime time( symDt.Hour(), symDt.Minute(), symDt.MicroSecond() / 1000 ); + QDateTime qdt(date, time); + qtdev[BtDeviceModel::LastUsedTimeRole] = QVariant(qdt); + + // set paired status: + setMajorProperty(qtdev, BtuiDevProperty::Bonded, isBonded( dev.Device() )); + + // set blocked status: + setMajorProperty(qtdev, BtuiDevProperty::Blocked, + dev.Device().GlobalSecurity().Banned() ); + // set trusted status: + setMajorProperty(qtdev, BtuiDevProperty::Trusted, + dev.Device().GlobalSecurity().NoAuthorise() ); + // set connected status: + // EBTEngConnecting is an intermediate state between connected and not-connected, + // we do not treat it as connected: + setMajorProperty(qtdev, BtuiDevProperty::Connected, dev.ServiceConnectionStatus() == EBTEngConnected); + + // Check whether the device has services that are connectable in bteng scope. + CBTEngConnMan* connMan( 0 ); + TRAP_IGNORE( connMan = CBTEngConnMan::NewL(0)); + TBool connectable(EFalse); + if ( connMan ) { + (void) connMan->IsConnectable(dev.Addr(), dev.Device().DeviceClass(), connectable); + delete connMan; + } + setMajorProperty(qtdev, BtuiDevProperty::Connectable, connectable); + + int cod = static_cast( dev.Device().DeviceClass().DeviceClass() ); + qtdev[BtDeviceModel::CoDRole] = QVariant(cod); + + int majorDeviceType; + int minorDeviceType; + // device type is mapped according to CoD: + BtuiDevProperty::mapDeiveType(majorDeviceType, minorDeviceType, cod); + + + + + qtdev[BtDeviceModel::MajorPropertyRole] = + QVariant( qtdev[BtDeviceModel::MajorPropertyRole].toInt() | majorDeviceType ); + qtdev[BtDeviceModel::MinorPropertyRole] = QVariant( minorDeviceType ); +} + +int BtDeviceModelPrivate::indexOf( const TBTDevAddr& addr ) const +{ + QString addrStr; + addrSymbianToReadbleString( addrStr, addr ); + for (int i = 0; i < mData.count(); ++i ) { + if ( mData.at( i ).value( BtDeviceModel::ReadableBdaddrRole ) + == addrStr ) { + return i; + } + } + return -1; +} + +void BtDeviceModelPrivate::updateRssi(BtuiModelDataItem& qtdev, int rssi ) +{ + qtdev[BtDeviceModel::RssiRole] = QVariant( rssi ); +} + +void BtDeviceModelPrivate::updateSeqNum(BtuiModelDataItem& qtdev, int seqNum ) +{ + qtdev[BtDeviceModel::SeqNumRole] = QVariant( seqNum ); +} + +/*! + Add the specified major property to the device if addto is true. + Otherwise the property is removed from the device. + */ +void BtDeviceModelPrivate::setMajorProperty( + BtuiModelDataItem& qtdev, int prop, bool addto) +{ + if ( addto ) { + qtdev[BtDeviceModel::MajorPropertyRole] = + QVariant( qtdev[BtDeviceModel::MajorPropertyRole].toInt() | prop); + } + else { + qtdev[BtDeviceModel::MajorPropertyRole] = + QVariant( qtdev[BtDeviceModel::MajorPropertyRole].toInt() & ~prop); + } +} + +bool BtDeviceModelPrivate::isDeviceInRange( const BtuiModelDataItem& qtdev ) +{ + return BtuiDevProperty::InRange & qtdev[BtDeviceModel::MajorPropertyRole].toInt(); +} + +bool BtDeviceModelPrivate::isDeviceInRegistry( const BtuiModelDataItem& qtdev ) +{ + return BtuiDevProperty::InRegistry & qtdev[BtDeviceModel::MajorPropertyRole].toInt(); +}