<commit_before>/************************************************************************/
/*!
    @author Original Code Sample from Erik Staats, NWG.
            FWCamAkiz was written by Adrian Daerr

    Copyright (c) 2002 Adrian Daer & Université Paris VII "Denis Diderot" (France).
    Copyright (c) 2004 Joel Falcou & Université Clermont-Ferrand II "Blaise Pascal" (France).
    All rights reserved.

    This file is part of the C+FOX Library.  This
    library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation; either version 2.1,
    or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General
    Public License along with this library; see the file COPYING.
    If not, send mail to the developers of C+FOX

    As a special exception, you may use this file as part of a free
    software library without restriction. Specifically, if other
    files instantiate templates or use macros or inline functions
    from this file, or you compile this file and link it with other
    files to produce an executable, this file does not by itself
    cause the resulting executable to be covered by the GNU Lesser
    General Public License.  This exception does not however
    invalidate any other reasons why the executable file might be
    covered by the GNU Lesser General Public License.
*/
/************************************************************************/

#include <iostream>
#include "constants.h"
#include "exception.h"
#include "FWController.h"

using namespace cfox;

/************************************************************************/
/*!
    @method    FWController
    @abstract   FWController base constructor
    @discussion FWController constructor uses
    a Device Dictionary to find out video device
    on the Firewire bus. From there, it builds an
    internal list of services attached to those
    devices.
*/
/************************************************************************/
FWController::FWController()
{
	// all user-level access of a device begins with a Mach port to
	// communicate with the I/O Kit.
	mach_port_t  masterPort;

	// attempt to get a Mach port and then check to see if there were
	// any problems getting it.
	if( kIOReturnSuccess == IOMasterPort( MACH_PORT_NULL, &masterPort ) )
	{
		findUnit(masterPort);
	}
	else
	{
		throw InvalidIOMasterPort();
	}
}

/************************************************************************/
/*!
    @method   ~FWController()
    @abstract   FWController base destructor
    @discussion Release all memory used by
    the Firewire object and channel. After
    being destroyed, FWController must have
    set all firewire device into a clean
    state for other applications to use them.
*/
/************************************************************************/
FWController::~FWController()
{
    if( mCFPlugInInterface ) IODestroyPlugInInterface(mCFPlugInInterface);
}

/************************************************************************/
/*!
    @method     acquireService
    @abstract   FWController main access onto services
    @discussion acquireService allows client to
    control a specific Firewire device found on the
    bus by referencing them by their service ID.
    acquireService performs all the needed initialisation
    of the base device service, letting the client the choice
    on how to hndle IRM and other device options.
*/
/************************************************************************/
FWDevice::device_ref_t FWController::acquireService( size_t idx, IOFireWireLibDCLCommandPoolRef& dcl, DCLCommandStruct**& udcl )
{
	message( "check that there are actually firewire devices attached to the computer" );
	if( mDevices.size() == 0 )
	{
		gen_fatal( "there are no firewire devices plugged into the computer" );
	}

	SInt32                  score;
	IOFireWireLibDeviceRef  resultInterface = 0;
	ComponentResult         result = noErr;

	// get the IOCFPlugInInterface
	result = IOCreatePlugInInterfaceForService( mDevices[idx].service, kIOFireWireLibTypeID,
			kIOCFPlugInInterfaceID, &mCFPlugInInterface, &score);

	message( "check if the plugin was created sucessfully" );
	if( result == kIOReturnSuccess )
	{
		// get the specific device interface that we want
		HRESULT err = (*mCFPlugInInterface)->QueryInterface(mCFPlugInInterface,
				CFUUIDGetUUIDBytes(kIOFireWireDeviceInterfaceID_v2),(void**) &resultInterface);

		// check if the interface was queried okay.
		if( err == S_OK )
		{
			mDevices[idx].interface = resultInterface;
			prepareDCL(idx,dcl,udcl);

			// connect the device for exclusive access
			IOReturn returnStatus = (*resultInterface)->Open(resultInterface);

			// check to make sure that the device was connected to
			if( returnStatus != noErr )
			{
				gen_fatal( "Failed to connect to firewire device" );
			}
		}
		else
		{
			throw QueryInterfaceFailed();
		}
	}
	else
	{
		throw InterfacePlugInCreationFailed();
	}

	message( "add callback dispatcher to run loop" );
	(*resultInterface)->AddCallbackDispatcherToRunLoop(resultInterface, CFRunLoopGetCurrent() );

	message( "add iso callback to dispatcher to run loop" );
	(*resultInterface)->AddIsochCallbackDispatcherToRunLoop(resultInterface,CFRunLoopGetCurrent());

	return resultInterface;
}

/************************************************************************/
/*!
  @method     releaseService
  @abstract   FWController method to clean up open services. MUST be called
  for each services used trough acquireServices.
 */
/************************************************************************/
void FWController::releaseService( size_t idx )
{
	if( idx < mDevices.size() )
	{
		if( mDevices[idx].dclCommandStruct) delete[] mDevices[idx].dclCommandStruct;
		if( mDevices[idx].dclCommandPool)   (*(mDevices[idx].dclCommandPool))->Release(mDevices[idx].dclCommandPool) ;
		if( mDevices[idx].interface )
		{
			(*(mDevices[idx].interface))->Close(mDevices[idx].interface) ;
			(*(mDevices[idx].interface))->Release(mDevices[idx].interface) ;
		}
	}
	else
	{
		throw InvalidServiceRequested();
	}
}

/************************************************************************/
/*!
  @method     getUnitInfo
  @abstract   Firewire Unit Information retriever
  @discussion Retrieves the Unit Directory and Unit Directory ID
  from a Firewire device on the bus. This identification is needed
  to retrieve the device base address.
 */
/************************************************************************/
void FWController::getUnitInfo( size_t idx, UInt32& adress )
{
	IOFireWireLibConfigDirectoryRef ud   = 0;
	IOFireWireLibConfigDirectoryRef udid = 0;
	FWAddress                       baseAddress;
	CFStringRef                     text;

	message( "get the config directory from the firewire camera" );
	// create a config directory object and return an interface to it.
	ud = ( *mDevices[idx].interface )->GetConfigDirectory( mDevices[idx].interface, CFUUIDGetUUIDBytes( kIOFireWireConfigDirectoryInterfaceID ) );

	// check if the interface was returned.
	if( !ud )
	{
		throw NotEnoughMemory();
	}
	else
	{
		CFDataRef dataRef;
		CFStringRef stringRef;

		message( "checking the type of all the config keys" );

		( *ud )->GetKeyValue_ConfigDirectory( ud, kConfigUnitDependentInfoKey, &udid, CFUUIDGetUUIDBytes( kIOFireWireConfigDirectoryInterfaceID ), nil );
		(*udid)->GetKeyOffset_FWAddress(udid, 0x00, &baseAddress, &text);

		mDevices[idx].address = baseAddress.addressLo;
		adress = mDevices[idx].address;
	}

	if( udid )  (*udid)->Release(udid);
	if( ud   )  (*ud)->Release(ud);
}

int FWController::getCameras( CFMutableDictionaryRef dict, mach_port_t masterPort )
{
	// check that the search criteria is all good.
	if( dict )
	{
		// ----------------------------------------------------------
		// Iterates through services and add them to master list
		// ----------------------------------------------------------
		io_service_t    service;
		FWDevice        device;
		io_iterator_t   iterator;

		// search the I/O registry for any units that match out criteria
		if( kIOReturnSuccess == IOServiceGetMatchingServices( masterPort, dict, &iterator ) )
		{
			message( "extracting services out of the iterator" );
			service = IOIteratorNext( iterator );

			while( service != NULL )
			{
				device.service = service;
				mDevices.push_back(device);
				service = IOIteratorNext( iterator );
			}
		}
		else
		{
			gen_fatal( "failed to perform the match services" );
		}
	}
	else
	{
		gen_fatal( "dictionary was not valid" );
	}

	return mDevices.size();
}

/************************************************************************/
/*!
  @method     findUnit
  @abstract   Search for valid Camera device on the bus
  @discussion Identify camera device on the Firewire bus.
  This identification allows FWController to sort annymous
  firewire device between camera and non-camera devices.
 */
/************************************************************************/
void FWController::findUnit( mach_port_t masterPort )
{
	// ----------------------------------------------------------
	// Build Matching Dictionary
	// ----------------------------------------------------------

	// create a dictionary that defines the type of units that we want
	// to grab off the bus
	CFMutableDictionaryRef  dict = IOServiceMatching( "IOFireWireUnit" );
	UInt32                  value = 45213;
	CFNumberRef             cfValue ;

	cfValue  = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &value );

	// narrow down the search criteria and only grab units that have the
	// specified vendor id
	CFDictionaryAddValue( dict, CFSTR( "Vendor_ID" ), cfValue );
	CFRelease( cfValue );

	int numOfCameras = getCameras( dict, masterPort );

	if( numOfCameras == 0 )
	{
		gen_fatal( "There are no dragonfly cameras attached to the machine" );
	}
	else
	{
		message( "found %d dragonfly cameras", numOfCameras );
	}
}

/************************************************************************/
/*!
  @method     prepareDCL
  @abstract   DCL Command and Structure initializer
  @discussion Allocate and create the DCL Command Pool and
  Structure for the DCL programm of the camera.
 */
/************************************************************************/
void FWController::prepareDCL( size_t idx,  IOFireWireLibDCLCommandPoolRef& dcl, DCLCommandStruct**& udcl )
{
	IOFireWireLibDeviceRef  i = mDevices[idx].interface;

	mDevices[idx].dclCommandPool = (*i)->CreateDCLCommandPool( i, kDCLProgramSize, CFUUIDGetUUIDBytes(kIOFireWireDCLCommandPoolInterfaceID));
	dcl = mDevices[idx].dclCommandPool;

	if( mDevices[idx].dclCommandPool )
	{
		mDevices[idx].dclCommandStruct = new DCLCommandStruct*[kMaxTransferDCLs] ;
		udcl = mDevices[idx].dclCommandStruct;
	}
	else
	{
		throw NotEnoughMemory();
	}
}

/************************************************************************/
/*!
  @method     getService
  @abstract   Service access
  @discussion Send a pointer to a given Firewire IO Service from the bus.
 */
/************************************************************************/
FWDevice::service_t FWController::getService( size_t idx )  const
{
	if(idx < mDevices.size() )
	{
		return mDevices[idx].service;
	}
	else
	{
		throw InvalidServiceRequested();
	}
}

/************************************************************************/
/*!
  @method     getServicesAmount
  @abstract   Service enumeration
  @discussion Retrieve the total number of available DC device found.
 */
/************************************************************************/
size_t              FWController::getServicesAmount() const
{
	return mDevices.size();
}
<commit_msg>now checks for cameras other than the dragon fly.<commit_after>/************************************************************************/
/*!
    @author Original Code Sample from Erik Staats, NWG.
            FWCamAkiz was written by Adrian Daerr

    Copyright (c) 2002 Adrian Daer & Université Paris VII "Denis Diderot" (France).
    Copyright (c) 2004 Joel Falcou & Université Clermont-Ferrand II "Blaise Pascal" (France).
    All rights reserved.

    This file is part of the C+FOX Library.  This
    library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation; either version 2.1,
    or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General
    Public License along with this library; see the file COPYING.
    If not, send mail to the developers of C+FOX

    As a special exception, you may use this file as part of a free
    software library without restriction. Specifically, if other
    files instantiate templates or use macros or inline functions
    from this file, or you compile this file and link it with other
    files to produce an executable, this file does not by itself
    cause the resulting executable to be covered by the GNU Lesser
    General Public License.  This exception does not however
    invalidate any other reasons why the executable file might be
    covered by the GNU Lesser General Public License.
*/
/************************************************************************/

#include <iostream>
#include "constants.h"
#include "exception.h"
#include "FWController.h"

using namespace cfox;

/************************************************************************/
/*!
    @method    FWController
    @abstract   FWController base constructor
    @discussion FWController constructor uses
    a Device Dictionary to find out video device
    on the Firewire bus. From there, it builds an
    internal list of services attached to those
    devices.
*/
/************************************************************************/
FWController::FWController()
{
	// all user-level access of a device begins with a Mach port to
	// communicate with the I/O Kit.
	mach_port_t  masterPort;

	// attempt to get a Mach port and then check to see if there were
	// any problems getting it.
	if( kIOReturnSuccess == IOMasterPort( MACH_PORT_NULL, &masterPort ) )
	{
		findUnit(masterPort);
	}
	else
	{
		throw InvalidIOMasterPort();
	}
}

/************************************************************************/
/*!
    @method   ~FWController()
    @abstract   FWController base destructor
    @discussion Release all memory used by
    the Firewire object and channel. After
    being destroyed, FWController must have
    set all firewire device into a clean
    state for other applications to use them.
*/
/************************************************************************/
FWController::~FWController()
{
    if( mCFPlugInInterface ) IODestroyPlugInInterface(mCFPlugInInterface);
}

/************************************************************************/
/*!
    @method     acquireService
    @abstract   FWController main access onto services
    @discussion acquireService allows client to
    control a specific Firewire device found on the
    bus by referencing them by their service ID.
    acquireService performs all the needed initialisation
    of the base device service, letting the client the choice
    on how to hndle IRM and other device options.
*/
/************************************************************************/
FWDevice::device_ref_t FWController::acquireService( size_t idx, IOFireWireLibDCLCommandPoolRef& dcl, DCLCommandStruct**& udcl )
{
	message( "check that there are actually firewire devices attached to the computer" );
	if( mDevices.size() == 0 )
	{
		gen_fatal( "there are no firewire devices plugged into the computer" );
	}

	SInt32                  score;
	IOFireWireLibDeviceRef  resultInterface = 0;
	ComponentResult         result = noErr;

	// get the IOCFPlugInInterface
	result = IOCreatePlugInInterfaceForService( mDevices[idx].service, kIOFireWireLibTypeID,
			kIOCFPlugInInterfaceID, &mCFPlugInInterface, &score);

	message( "check if the plugin was created sucessfully" );
	if( result == kIOReturnSuccess )
	{
		// get the specific device interface that we want
		HRESULT err = (*mCFPlugInInterface)->QueryInterface(mCFPlugInInterface,
				CFUUIDGetUUIDBytes(kIOFireWireDeviceInterfaceID_v2),(void**) &resultInterface);

		// check if the interface was queried okay.
		if( err == S_OK )
		{
			mDevices[idx].interface = resultInterface;
			prepareDCL(idx,dcl,udcl);

			// connect the device for exclusive access
			IOReturn returnStatus = (*resultInterface)->Open(resultInterface);

			// check to make sure that the device was connected to
			if( returnStatus != noErr )
			{
				gen_fatal( "Failed to connect to firewire device" );
			}
		}
		else
		{
			throw QueryInterfaceFailed();
		}
	}
	else
	{
		throw InterfacePlugInCreationFailed();
	}

	message( "add callback dispatcher to run loop" );
	(*resultInterface)->AddCallbackDispatcherToRunLoop(resultInterface, CFRunLoopGetCurrent() );

	message( "add iso callback to dispatcher to run loop" );
	(*resultInterface)->AddIsochCallbackDispatcherToRunLoop(resultInterface,CFRunLoopGetCurrent());

	return resultInterface;
}

/************************************************************************/
/*!
  @method     releaseService
  @abstract   FWController method to clean up open services. MUST be called
  for each services used trough acquireServices.
 */
/************************************************************************/
void FWController::releaseService( size_t idx )
{
	if( idx < mDevices.size() )
	{
		if( mDevices[idx].dclCommandStruct) delete[] mDevices[idx].dclCommandStruct;
		if( mDevices[idx].dclCommandPool)   (*(mDevices[idx].dclCommandPool))->Release(mDevices[idx].dclCommandPool) ;
		if( mDevices[idx].interface )
		{
			(*(mDevices[idx].interface))->Close(mDevices[idx].interface) ;
			(*(mDevices[idx].interface))->Release(mDevices[idx].interface) ;
		}
	}
	else
	{
		throw InvalidServiceRequested();
	}
}

/************************************************************************/
/*!
  @method     getUnitInfo
  @abstract   Firewire Unit Information retriever
  @discussion Retrieves the Unit Directory and Unit Directory ID
  from a Firewire device on the bus. This identification is needed
  to retrieve the device base address.
 */
/************************************************************************/
void FWController::getUnitInfo( size_t idx, UInt32& adress )
{
	IOFireWireLibConfigDirectoryRef ud   = 0;
	IOFireWireLibConfigDirectoryRef udid = 0;
	FWAddress                       baseAddress;
	CFStringRef                     text;

	message( "get the config directory from the firewire camera" );
	// create a config directory object and return an interface to it.
	ud = ( *mDevices[idx].interface )->GetConfigDirectory( mDevices[idx].interface, CFUUIDGetUUIDBytes( kIOFireWireConfigDirectoryInterfaceID ) );

	// check if the interface was returned.
	if( !ud )
	{
		throw NotEnoughMemory();
	}
	else
	{
		CFDataRef dataRef;
		CFStringRef stringRef;

		message( "checking the type of all the config keys" );

		( *ud )->GetKeyValue_ConfigDirectory( ud, kConfigUnitDependentInfoKey, &udid, CFUUIDGetUUIDBytes( kIOFireWireConfigDirectoryInterfaceID ), nil );
		(*udid)->GetKeyOffset_FWAddress(udid, 0x00, &baseAddress, &text);

		mDevices[idx].address = baseAddress.addressLo;
		adress = mDevices[idx].address;
	}

	if( udid )  (*udid)->Release(udid);
	if( ud   )  (*ud)->Release(ud);
}

int FWController::getCameras( CFMutableDictionaryRef dict, mach_port_t masterPort )
{
	// check that the search criteria is all good.
	if( dict )
	{
		// ----------------------------------------------------------
		// Iterates through services and add them to master list
		// ----------------------------------------------------------
		io_service_t    service;
		FWDevice        device;
		io_iterator_t   iterator;

		// search the I/O registry for any units that match out criteria
		if( kIOReturnSuccess == IOServiceGetMatchingServices( masterPort, dict, &iterator ) )
		{
			message( "extracting services out of the iterator" );
			service = IOIteratorNext( iterator );

			while( service != NULL )
			{
				device.service = service;
				mDevices.push_back(device);
				service = IOIteratorNext( iterator );
			}
		}
		else
		{
			gen_fatal( "failed to perform the match services" );
		}
	}
	else
	{
		gen_fatal( "dictionary was not valid" );
	}

	return mDevices.size();
}

/************************************************************************/
/*!
  @method     findUnit
  @abstract   Search for valid Camera device on the bus
  @discussion Identify camera device on the Firewire bus.
  This identification allows FWController to sort annymous
  firewire device between camera and non-camera devices.
 */
/************************************************************************/
void FWController::findUnit( mach_port_t masterPort )
{
	// ----------------------------------------------------------
	// Build Matching Dictionary
	// ----------------------------------------------------------

	// create a dictionary that defines the type of units that we want
	// to grab off the bus
	CFMutableDictionaryRef  dict = IOServiceMatching( "IOFireWireUnit" );
	UInt32                  value = 45213;
	CFNumberRef             cfValue ;

	cfValue  = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &value );

	// narrow down the search criteria and only grab units that have the
	// specified vendor id
	CFDictionaryAddValue( dict, CFSTR( "Vendor_ID" ), cfValue );
	CFRelease( cfValue );

	int numOfCameras = getCameras( dict, masterPort );

	if( numOfCameras == 0 )
	{
		message( "There are no dragonfly cameras attached to this machine, now looking for others" );

		// reinitialize the dictionary
		dict = IOServiceMatching( "IOFireWireUnit" );

		// find any other cameras on the firewire bus
		numOfCameras = getCameras( dict, masterPort );

		if( numOfCameras == 0 )
		{
			gen_fatal( "There are no cameras attached to this machine" );
		}
		else
		{
			message( "Found %d camera(s)", numOfCameras );
		}
	}
	else
	{
		message( "found %d dragonfly cameras", numOfCameras );
	}
}

/************************************************************************/
/*!
  @method     prepareDCL
  @abstract   DCL Command and Structure initializer
  @discussion Allocate and create the DCL Command Pool and
  Structure for the DCL programm of the camera.
 */
/************************************************************************/
void FWController::prepareDCL( size_t idx,  IOFireWireLibDCLCommandPoolRef& dcl, DCLCommandStruct**& udcl )
{
	IOFireWireLibDeviceRef  i = mDevices[idx].interface;

	mDevices[idx].dclCommandPool = (*i)->CreateDCLCommandPool( i, kDCLProgramSize, CFUUIDGetUUIDBytes(kIOFireWireDCLCommandPoolInterfaceID));
	dcl = mDevices[idx].dclCommandPool;

	if( mDevices[idx].dclCommandPool )
	{
		mDevices[idx].dclCommandStruct = new DCLCommandStruct*[kMaxTransferDCLs] ;
		udcl = mDevices[idx].dclCommandStruct;
	}
	else
	{
		throw NotEnoughMemory();
	}
}

/************************************************************************/
/*!
  @method     getService
  @abstract   Service access
  @discussion Send a pointer to a given Firewire IO Service from the bus.
 */
/************************************************************************/
FWDevice::service_t FWController::getService( size_t idx )  const
{
	if(idx < mDevices.size() )
	{
		return mDevices[idx].service;
	}
	else
	{
		throw InvalidServiceRequested();
	}
}

/************************************************************************/
/*!
  @method     getServicesAmount
  @abstract   Service enumeration
  @discussion Retrieve the total number of available DC device found.
 */
/************************************************************************/
size_t              FWController::getServicesAmount() const
{
	return mDevices.size();
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */
#ifndef CHART_WRAPPED_SERIES_OR_DIAGRAM_PROPERTY_HXX
#define CHART_WRAPPED_SERIES_OR_DIAGRAM_PROPERTY_HXX

#include "WrappedProperty.hxx"
#include "Chart2ModelContact.hxx"
#include "macros.hxx"
#include "DiagramHelper.hxx"
#include <com/sun/star/chart2/XDataSeries.hpp>

#include <boost/shared_ptr.hpp>
#include <vector>

//.............................................................................
namespace chart
{
namespace wrapper
{

enum tSeriesOrDiagramPropertyType
{
    DATA_SERIES,
    DIAGRAM
};

//PROPERTYTYPE is the type of the outer property

template< typename PROPERTYTYPE >
class WrappedSeriesOrDiagramProperty : public WrappedProperty
{
public:
    virtual PROPERTYTYPE getValueFromSeries( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xSeriesPropertySet ) const =0;
    virtual void setValueToSeries( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xSeriesPropertySet, PROPERTYTYPE aNewValue ) const =0;

    explicit WrappedSeriesOrDiagramProperty( const ::rtl::OUString& rName, const ::com::sun::star::uno::Any& rDefaulValue
        , ::boost::shared_ptr< Chart2ModelContact > spChart2ModelContact
        , tSeriesOrDiagramPropertyType ePropertyType )
            : WrappedProperty(rName,::rtl::OUString())
            , m_spChart2ModelContact(spChart2ModelContact)
            , m_aOuterValue(rDefaulValue)
            , m_aDefaultValue(rDefaulValue)
            , m_ePropertyType( ePropertyType )
    {
    }
    virtual ~WrappedSeriesOrDiagramProperty() {};

    bool detectInnerValue( PROPERTYTYPE& rValue, bool& rHasAmbiguousValue ) const
    {
        bool bHasDetectableInnerValue = false;
        rHasAmbiguousValue = false;
        if( m_ePropertyType == DIAGRAM &&
            m_spChart2ModelContact.get() )
        {
            ::std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XDataSeries > > aSeriesVector(
                ::chart::DiagramHelper::getDataSeriesFromDiagram( m_spChart2ModelContact->getChart2Diagram() ) );
            ::std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XDataSeries > >::const_iterator aIter =
                    aSeriesVector.begin();
            for( ; aIter != aSeriesVector.end(); aIter++ )
            {
                PROPERTYTYPE aCurValue = getValueFromSeries( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >::query( *aIter ) );
                if( !bHasDetectableInnerValue )
                    rValue = aCurValue;
                else
                {
                    if( rValue != aCurValue )
                    {
                        rHasAmbiguousValue = true;
                        break;
                    }
                    else
                        rValue = aCurValue;
                }
                bHasDetectableInnerValue = true;
            }
        }
        return bHasDetectableInnerValue;
    }
    void setInnerValue( PROPERTYTYPE aNewValue ) const
    {
        if( m_ePropertyType == DIAGRAM &&
            m_spChart2ModelContact.get() )
        {
            ::std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XDataSeries > > aSeriesVector(
                ::chart::DiagramHelper::getDataSeriesFromDiagram( m_spChart2ModelContact->getChart2Diagram() ) );
            ::std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XDataSeries > >::const_iterator aIter =
                    aSeriesVector.begin();
            for( ; aIter != aSeriesVector.end(); aIter++ )
            {
                ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xSeriesPropertySet( *aIter, ::com::sun::star::uno::UNO_QUERY );
                if( xSeriesPropertySet.is() )
                {
                    setValueToSeries( xSeriesPropertySet, aNewValue );
                }
            }
        }
    }
    virtual void setPropertyValue( const ::com::sun::star::uno::Any& rOuterValue, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xInnerPropertySet ) const
                    throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
    {
        PROPERTYTYPE aNewValue = PROPERTYTYPE();
        if( ! (rOuterValue >>= aNewValue) )
            throw ::com::sun::star::lang::IllegalArgumentException( "statistic property requires different type", 0, 0 );

        if( m_ePropertyType == DIAGRAM )
        {
            m_aOuterValue = rOuterValue;

            bool bHasAmbiguousValue = false;
            PROPERTYTYPE aOldValue = PROPERTYTYPE();
            if( detectInnerValue( aOldValue, bHasAmbiguousValue ) )
            {
                if( bHasAmbiguousValue || aNewValue != aOldValue )
                    setInnerValue( aNewValue );
            }
        }
        else
        {
            setValueToSeries( xInnerPropertySet, aNewValue );
        }
    }

    virtual ::com::sun::star::uno::Any getPropertyValue( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xInnerPropertySet ) const
                            throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
    {
        if( m_ePropertyType == DIAGRAM )
        {
            bool bHasAmbiguousValue = false;
            PROPERTYTYPE aValue;
            if( detectInnerValue( aValue, bHasAmbiguousValue ) )
            {
                if(bHasAmbiguousValue)
                    m_aOuterValue <<= m_aDefaultValue;
                else
                    m_aOuterValue <<= aValue;
            }
            return m_aOuterValue;
        }
        else
        {
            ::com::sun::star::uno::Any aRet( m_aDefaultValue );
            aRet <<= getValueFromSeries( xInnerPropertySet );
            return aRet;
        }
    }

    virtual ::com::sun::star::uno::Any getPropertyDefault( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyState >& /* xInnerPropertyState */ ) const
                            throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
    {
        return m_aDefaultValue;
    }

protected:
    ::boost::shared_ptr< Chart2ModelContact >  m_spChart2ModelContact;
    mutable ::com::sun::star::uno::Any         m_aOuterValue;
    ::com::sun::star::uno::Any                 m_aDefaultValue;
    tSeriesOrDiagramPropertyType               m_ePropertyType;
};

} //namespace wrapper
} //namespace chart
//.............................................................................

// CHART_WRAPPED_SERIES_OR_DIAGRAM_PROPERTY_HXX
#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Prefer prefix ++/-- operators for non-primitive types<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */
#ifndef CHART_WRAPPED_SERIES_OR_DIAGRAM_PROPERTY_HXX
#define CHART_WRAPPED_SERIES_OR_DIAGRAM_PROPERTY_HXX

#include "WrappedProperty.hxx"
#include "Chart2ModelContact.hxx"
#include "macros.hxx"
#include "DiagramHelper.hxx"
#include <com/sun/star/chart2/XDataSeries.hpp>

#include <boost/shared_ptr.hpp>
#include <vector>

//.............................................................................
namespace chart
{
namespace wrapper
{

enum tSeriesOrDiagramPropertyType
{
    DATA_SERIES,
    DIAGRAM
};

//PROPERTYTYPE is the type of the outer property

template< typename PROPERTYTYPE >
class WrappedSeriesOrDiagramProperty : public WrappedProperty
{
public:
    virtual PROPERTYTYPE getValueFromSeries( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xSeriesPropertySet ) const =0;
    virtual void setValueToSeries( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xSeriesPropertySet, PROPERTYTYPE aNewValue ) const =0;

    explicit WrappedSeriesOrDiagramProperty( const ::rtl::OUString& rName, const ::com::sun::star::uno::Any& rDefaulValue
        , ::boost::shared_ptr< Chart2ModelContact > spChart2ModelContact
        , tSeriesOrDiagramPropertyType ePropertyType )
            : WrappedProperty(rName,::rtl::OUString())
            , m_spChart2ModelContact(spChart2ModelContact)
            , m_aOuterValue(rDefaulValue)
            , m_aDefaultValue(rDefaulValue)
            , m_ePropertyType( ePropertyType )
    {
    }
    virtual ~WrappedSeriesOrDiagramProperty() {};

    bool detectInnerValue( PROPERTYTYPE& rValue, bool& rHasAmbiguousValue ) const
    {
        bool bHasDetectableInnerValue = false;
        rHasAmbiguousValue = false;
        if( m_ePropertyType == DIAGRAM &&
            m_spChart2ModelContact.get() )
        {
            ::std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XDataSeries > > aSeriesVector(
                ::chart::DiagramHelper::getDataSeriesFromDiagram( m_spChart2ModelContact->getChart2Diagram() ) );
            ::std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XDataSeries > >::const_iterator aIter =
                    aSeriesVector.begin();
            for( ; aIter != aSeriesVector.end(); ++aIter )
            {
                PROPERTYTYPE aCurValue = getValueFromSeries( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >::query( *aIter ) );
                if( !bHasDetectableInnerValue )
                    rValue = aCurValue;
                else
                {
                    if( rValue != aCurValue )
                    {
                        rHasAmbiguousValue = true;
                        break;
                    }
                    else
                        rValue = aCurValue;
                }
                bHasDetectableInnerValue = true;
            }
        }
        return bHasDetectableInnerValue;
    }
    void setInnerValue( PROPERTYTYPE aNewValue ) const
    {
        if( m_ePropertyType == DIAGRAM &&
            m_spChart2ModelContact.get() )
        {
            ::std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XDataSeries > > aSeriesVector(
                ::chart::DiagramHelper::getDataSeriesFromDiagram( m_spChart2ModelContact->getChart2Diagram() ) );
            ::std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XDataSeries > >::const_iterator aIter =
                    aSeriesVector.begin();
            for( ; aIter != aSeriesVector.end(); ++aIter )
            {
                ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xSeriesPropertySet( *aIter, ::com::sun::star::uno::UNO_QUERY );
                if( xSeriesPropertySet.is() )
                {
                    setValueToSeries( xSeriesPropertySet, aNewValue );
                }
            }
        }
    }
    virtual void setPropertyValue( const ::com::sun::star::uno::Any& rOuterValue, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xInnerPropertySet ) const
                    throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
    {
        PROPERTYTYPE aNewValue = PROPERTYTYPE();
        if( ! (rOuterValue >>= aNewValue) )
            throw ::com::sun::star::lang::IllegalArgumentException( "statistic property requires different type", 0, 0 );

        if( m_ePropertyType == DIAGRAM )
        {
            m_aOuterValue = rOuterValue;

            bool bHasAmbiguousValue = false;
            PROPERTYTYPE aOldValue = PROPERTYTYPE();
            if( detectInnerValue( aOldValue, bHasAmbiguousValue ) )
            {
                if( bHasAmbiguousValue || aNewValue != aOldValue )
                    setInnerValue( aNewValue );
            }
        }
        else
        {
            setValueToSeries( xInnerPropertySet, aNewValue );
        }
    }

    virtual ::com::sun::star::uno::Any getPropertyValue( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xInnerPropertySet ) const
                            throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
    {
        if( m_ePropertyType == DIAGRAM )
        {
            bool bHasAmbiguousValue = false;
            PROPERTYTYPE aValue;
            if( detectInnerValue( aValue, bHasAmbiguousValue ) )
            {
                if(bHasAmbiguousValue)
                    m_aOuterValue <<= m_aDefaultValue;
                else
                    m_aOuterValue <<= aValue;
            }
            return m_aOuterValue;
        }
        else
        {
            ::com::sun::star::uno::Any aRet( m_aDefaultValue );
            aRet <<= getValueFromSeries( xInnerPropertySet );
            return aRet;
        }
    }

    virtual ::com::sun::star::uno::Any getPropertyDefault( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyState >& /* xInnerPropertyState */ ) const
                            throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
    {
        return m_aDefaultValue;
    }

protected:
    ::boost::shared_ptr< Chart2ModelContact >  m_spChart2ModelContact;
    mutable ::com::sun::star::uno::Any         m_aOuterValue;
    ::com::sun::star::uno::Any                 m_aDefaultValue;
    tSeriesOrDiagramPropertyType               m_ePropertyType;
};

} //namespace wrapper
} //namespace chart
//.............................................................................

// CHART_WRAPPED_SERIES_OR_DIAGRAM_PROPERTY_HXX
#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>
// This file is part of lipstick, a QML desktop library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation
// and appearing in the file LICENSE.LGPL included in the packaging
// of this file.
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// Copyright (c) 2011, Robin Burchell
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>
// Copyright (c) 2010, Nokia Corporation and/or its subsidiary(-ies) <directui@nokia.com>

#include <QApplication>
#include <QPainter>
#include <QTimer>
#include <QX11Info>

#include "switcherpixmapitem.h"
#include "xtools/homewindowmonitor.h"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>

// Define this if you'd like to see debug messages from the switcher
#ifdef DEBUG_SWITCHER
#define SWITCHER_DEBUG(things) qDebug() << Q_FUNC_INFO << things
#else
#define SWITCHER_DEBUG(things)
#endif

#ifdef Q_WS_X11
unsigned char xErrorCode = Success;

static int handleXError(Display *, XErrorEvent *event)
{
    xErrorCode = event->error_code;

    return 0;
}
#endif

struct SwitcherPixmapItem::Private
{
    Private()
        : xWindowPixmapIsValid(false)
        , xWindowPixmap(0)
        , xWindowPixmapDamage(0)
        , windowId(0)
    {}

    bool xWindowPixmapIsValid;
    Pixmap xWindowPixmap;
    Damage xWindowPixmapDamage;
    QPixmap qWindowPixmap;
    WId windowId;
};

SwitcherPixmapItem::SwitcherPixmapItem(QDeclarativeItem *parent)
    : QDeclarativeItem(parent)
    , d(new Private)
{
    setFlag(QGraphicsItem::ItemHasNoContents, false);
    connect(qApp, SIGNAL(damageEvent(Qt::HANDLE &, short &, short &, unsigned short &, unsigned short &)), this, SLOT(damageEvent(Qt::HANDLE &, short &, short &, unsigned short &, unsigned short &)));
    connect(HomeWindowMonitor::instance(), SIGNAL(isHomeWindowOnTopChanged()), this, SLOT(toggleDamage()));
}

SwitcherPixmapItem::~SwitcherPixmapItem()
{
    destroyDamage();
    if (d->xWindowPixmap)
        XFreePixmap(QX11Info::display(), d->xWindowPixmap);
    delete d;
}

void SwitcherPixmapItem::toggleDamage()
{
    if (HomeWindowMonitor::instance()->isHomeWindowOnTop()) {
        SWITCHER_DEBUG() << Q_FUNC_INFO << "Creating damage for " << d->windowId;
        createDamage();
        update();
    } else {
        SWITCHER_DEBUG() << Q_FUNC_INFO << "Destroying damage for " << d->windowId;
        destroyDamage();
    }
}

void SwitcherPixmapItem::damageEvent(Qt::HANDLE &damage, short &x, short &y, unsigned short &width, unsigned short &height)
{
    Q_UNUSED(x);
    Q_UNUSED(y);
    Q_UNUSED(width);
    Q_UNUSED(height);
#ifdef Q_WS_X11
    if (d->xWindowPixmapDamage == damage) {
        XDamageSubtract(QX11Info::display(), d->xWindowPixmapDamage, None, None);
        update();
    }
#else
    Q_UNUSED(damage);
#endif
}

void SwitcherPixmapItem::destroyDamage()
{
    if (d->xWindowPixmapDamage != 0) {
        XDamageDestroy(QX11Info::display(), d->xWindowPixmapDamage);
        d->xWindowPixmapDamage = 0;
    }
}

void SwitcherPixmapItem::createDamage()
{
    // TODO: check on display status, don't create damage if off
    if (d->windowId == 0)
        return;

    // Register the pixmap for XDamage events
    d->xWindowPixmapDamage = XDamageCreate(QX11Info::display(), d->windowId, XDamageReportNonEmpty);
}

void SwitcherPixmapItem::updateXWindowPixmap()
{
#ifdef Q_WS_X11
    SWITCHER_DEBUG() << Q_FUNC_INFO << "Resetting X pixmap for " << d->windowId;

    // It is possible that the window is not redirected so check for errors.
    // XSync() needs to be called so that previous errors go to the original
    // handler.
    XSync(QX11Info::display(), FALSE);
    XErrorHandler errh = XSetErrorHandler(handleXError);
    xErrorCode = Success;

    // Get the pixmap ID of the X window
    Pixmap newWindowPixmap = XCompositeNameWindowPixmap(QX11Info::display(), d->windowId);

    // XCompositeNameWindowPixmap doesn't wait for the server to reply, we'll
    // need to do it ourselves to catch the possible BadMatch
    XSync(QX11Info::display(), FALSE);

    d->xWindowPixmapIsValid = xErrorCode == Success;
    if (d->xWindowPixmapIsValid) {
        // Unregister the old pixmap from XDamage events
        destroyDamage();

        if (d->xWindowPixmap != 0) {
            // Dereference the old pixmap ID
            XFreePixmap(QX11Info::display(), d->xWindowPixmap);
        }

        d->xWindowPixmap = newWindowPixmap;

        // Register the pixmap for XDamage events
        if (HomeWindowMonitor::instance()->isHomeWindowOnTop())
            createDamage();

        d->qWindowPixmap = QPixmap::fromX11Pixmap(d->xWindowPixmap, QPixmap::ExplicitlyShared);
    } else {
        // If a BadMatch error occurred the window wasn't redirected yet; deference the invalid pixmap
        if (newWindowPixmap != 0) {
            XFreePixmap(QX11Info::display(), newWindowPixmap);
        }
    }

    // Reset the error handler
    XSetErrorHandler(errh);
#else
#error "not implemented"
#endif
}

void SwitcherPixmapItem::setWindowId(int window)
{
    d->windowId = window;
    d->xWindowPixmapIsValid = false;

    // TODO: should we XFreePixmap here?

    update();
}

int SwitcherPixmapItem::windowId() const
{
    return d->windowId;
}

void SwitcherPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                               QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);

    if (!d->xWindowPixmapIsValid) {
        updateXWindowPixmap();
    }

    QT_TRY {
        painter->drawPixmap(QRect(0, 0, width(), height()), d->qWindowPixmap);
    } QT_CATCH (std::bad_alloc e) {
        // XGetImage failed, the window has been already unmapped
    }
}

bool SwitcherPixmapItem::handleXEvent(const XEvent &event)
{
    WId windowId;

    if (event.type == VisibilityNotify) {
        if (event.xvisibility.state != VisibilityFullyObscured ||
            event.xvisibility.send_event != True) {
            SWITCHER_DEBUG() << Q_FUNC_INFO << "Ignoring VisibilityNotify that isn't a send_event VisibilityFullyObscured for " << event.xvisibility.window;
            return false;
        }

        windowId = event.xvisibility.window;
        SWITCHER_DEBUG() << Q_FUNC_INFO << "Got obscured for " << windowId << "; want " << d->windowId;
    } else if (event.type == ConfigureNotify) {
        windowId = event.xconfigure.window;
        SWITCHER_DEBUG() << Q_FUNC_INFO << "ConfigureNotify for " << windowId << "; want " << d->windowId;
    } else {
        return false;
    }

    if (windowId != d->windowId)
        return false;

    SWITCHER_DEBUG() << Q_FUNC_INFO << "Invalidated, resetting pixmap for " << d->windowId;
    d->xWindowPixmapIsValid = false;
    update();
    return true;
}

<commit_msg>fixup debugging<commit_after>
// This file is part of lipstick, a QML desktop library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation
// and appearing in the file LICENSE.LGPL included in the packaging
// of this file.
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// Copyright (c) 2011, Robin Burchell
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>
// Copyright (c) 2010, Nokia Corporation and/or its subsidiary(-ies) <directui@nokia.com>

#include <QApplication>
#include <QPainter>
#include <QTimer>
#include <QX11Info>

#include "switcherpixmapitem.h"
#include "xtools/homewindowmonitor.h"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>

// Define this if you'd like to see debug messages from the switcher
#ifdef DEBUG_SWITCHER
#define SWITCHER_DEBUG qDebug
#else
#define SWITCHER_DEBUG if (false) qDebug
#endif

#ifdef Q_WS_X11
unsigned char xErrorCode = Success;

static int handleXError(Display *, XErrorEvent *event)
{
    xErrorCode = event->error_code;

    return 0;
}
#endif

struct SwitcherPixmapItem::Private
{
    Private()
        : xWindowPixmapIsValid(false)
        , xWindowPixmap(0)
        , xWindowPixmapDamage(0)
        , windowId(0)
    {}

    bool xWindowPixmapIsValid;
    Pixmap xWindowPixmap;
    Damage xWindowPixmapDamage;
    QPixmap qWindowPixmap;
    WId windowId;
};

SwitcherPixmapItem::SwitcherPixmapItem(QDeclarativeItem *parent)
    : QDeclarativeItem(parent)
    , d(new Private)
{
    setFlag(QGraphicsItem::ItemHasNoContents, false);
    connect(qApp, SIGNAL(damageEvent(Qt::HANDLE &, short &, short &, unsigned short &, unsigned short &)), this, SLOT(damageEvent(Qt::HANDLE &, short &, short &, unsigned short &, unsigned short &)));
    connect(HomeWindowMonitor::instance(), SIGNAL(isHomeWindowOnTopChanged()), this, SLOT(toggleDamage()));
}

SwitcherPixmapItem::~SwitcherPixmapItem()
{
    destroyDamage();
    if (d->xWindowPixmap)
        XFreePixmap(QX11Info::display(), d->xWindowPixmap);
    delete d;
}

void SwitcherPixmapItem::toggleDamage()
{
    if (HomeWindowMonitor::instance()->isHomeWindowOnTop()) {
        SWITCHER_DEBUG() << Q_FUNC_INFO << "Creating damage for " << d->windowId;
        createDamage();
        update();
    } else {
        SWITCHER_DEBUG() << Q_FUNC_INFO << "Destroying damage for " << d->windowId;
        destroyDamage();
    }
}

void SwitcherPixmapItem::damageEvent(Qt::HANDLE &damage, short &x, short &y, unsigned short &width, unsigned short &height)
{
    Q_UNUSED(x);
    Q_UNUSED(y);
    Q_UNUSED(width);
    Q_UNUSED(height);
#ifdef Q_WS_X11
    if (d->xWindowPixmapDamage == damage) {
        XDamageSubtract(QX11Info::display(), d->xWindowPixmapDamage, None, None);
        update();
    }
#else
    Q_UNUSED(damage);
#endif
}

void SwitcherPixmapItem::destroyDamage()
{
    if (d->xWindowPixmapDamage != 0) {
        XDamageDestroy(QX11Info::display(), d->xWindowPixmapDamage);
        d->xWindowPixmapDamage = 0;
    }
}

void SwitcherPixmapItem::createDamage()
{
    // TODO: check on display status, don't create damage if off
    if (d->windowId == 0)
        return;

    // Register the pixmap for XDamage events
    d->xWindowPixmapDamage = XDamageCreate(QX11Info::display(), d->windowId, XDamageReportNonEmpty);
}

void SwitcherPixmapItem::updateXWindowPixmap()
{
#ifdef Q_WS_X11
    SWITCHER_DEBUG() << Q_FUNC_INFO << "Resetting X pixmap for " << d->windowId;

    // It is possible that the window is not redirected so check for errors.
    // XSync() needs to be called so that previous errors go to the original
    // handler.
    XSync(QX11Info::display(), FALSE);
    XErrorHandler errh = XSetErrorHandler(handleXError);
    xErrorCode = Success;

    // Get the pixmap ID of the X window
    Pixmap newWindowPixmap = XCompositeNameWindowPixmap(QX11Info::display(), d->windowId);

    // XCompositeNameWindowPixmap doesn't wait for the server to reply, we'll
    // need to do it ourselves to catch the possible BadMatch
    XSync(QX11Info::display(), FALSE);

    d->xWindowPixmapIsValid = xErrorCode == Success;
    if (d->xWindowPixmapIsValid) {
        // Unregister the old pixmap from XDamage events
        destroyDamage();

        if (d->xWindowPixmap != 0) {
            // Dereference the old pixmap ID
            XFreePixmap(QX11Info::display(), d->xWindowPixmap);
        }

        d->xWindowPixmap = newWindowPixmap;

        // Register the pixmap for XDamage events
        if (HomeWindowMonitor::instance()->isHomeWindowOnTop())
            createDamage();

        d->qWindowPixmap = QPixmap::fromX11Pixmap(d->xWindowPixmap, QPixmap::ExplicitlyShared);
    } else {
        // If a BadMatch error occurred the window wasn't redirected yet; deference the invalid pixmap
        if (newWindowPixmap != 0) {
            XFreePixmap(QX11Info::display(), newWindowPixmap);
        }
    }

    // Reset the error handler
    XSetErrorHandler(errh);
#else
#error "not implemented"
#endif
}

void SwitcherPixmapItem::setWindowId(int window)
{
    d->windowId = window;
    d->xWindowPixmapIsValid = false;

    // TODO: should we XFreePixmap here?

    update();
}

int SwitcherPixmapItem::windowId() const
{
    return d->windowId;
}

void SwitcherPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                               QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);

    if (!d->xWindowPixmapIsValid) {
        updateXWindowPixmap();
    }

    QT_TRY {
        painter->drawPixmap(QRect(0, 0, width(), height()), d->qWindowPixmap);
    } QT_CATCH (std::bad_alloc e) {
        // XGetImage failed, the window has been already unmapped
    }
}

bool SwitcherPixmapItem::handleXEvent(const XEvent &event)
{
    WId windowId;

    if (event.type == VisibilityNotify) {
        if (event.xvisibility.state != VisibilityFullyObscured ||
            event.xvisibility.send_event != True) {
            SWITCHER_DEBUG() << Q_FUNC_INFO << "Ignoring VisibilityNotify that isn't a send_event VisibilityFullyObscured for " << event.xvisibility.window;
            return false;
        }

        windowId = event.xvisibility.window;
        SWITCHER_DEBUG() << Q_FUNC_INFO << "Got obscured for " << windowId << "; want " << d->windowId;
    } else if (event.type == ConfigureNotify) {
        windowId = event.xconfigure.window;
        SWITCHER_DEBUG() << Q_FUNC_INFO << "ConfigureNotify for " << windowId << "; want " << d->windowId;
    } else {
        return false;
    }

    if (windowId != d->windowId)
        return false;

    SWITCHER_DEBUG() << Q_FUNC_INFO << "Invalidated, resetting pixmap for " << d->windowId;
    d->xWindowPixmapIsValid = false;
    update();
    return true;
}

<|endoftext|>


<commit_before>
// This file is part of lipstick, a QML desktop library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation
// and appearing in the file LICENSE.LGPL included in the packaging
// of this file.
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// Copyright (c) 2011, Robin Burchell
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>
// Copyright (c) 2010, Nokia Corporation and/or its subsidiary(-ies) <directui@nokia.com>

#include <QApplication>
#include <QPainter>
#include <QTimer>
#include <QX11Info>

#include "switcherpixmapitem.h"
#include "xtools/homewindowmonitor.h"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>

// Define this if you'd like to see debug messages from the switcher
#ifdef DEBUG_SWITCHER
#define SWITCHER_DEBUG(things) qDebug() << Q_FUNC_INFO << things
#else
#define SWITCHER_DEBUG(things)
#endif

#ifdef Q_WS_X11
unsigned char xErrorCode = Success;

static int handleXError(Display *, XErrorEvent *event)
{
    xErrorCode = event->error_code;

    return 0;
}
#endif

struct SwitcherPixmapItem::Private
{
    Private()
        : xWindowPixmapIsValid(false)
        , xWindowPixmap(0)
        , xWindowPixmapDamage(0)
        , windowId(0)
    {}

    bool xWindowPixmapIsValid;
    Pixmap xWindowPixmap;
    Damage xWindowPixmapDamage;
    QPixmap qWindowPixmap;
    WId windowId;
};

SwitcherPixmapItem::SwitcherPixmapItem(QDeclarativeItem *parent)
    : QDeclarativeItem(parent)
    , d(new Private)
{
    setFlag(QGraphicsItem::ItemHasNoContents, false);
    connect(qApp, SIGNAL(damageEvent(Qt::HANDLE &, short &, short &, unsigned short &, unsigned short &)), this, SLOT(damageEvent(Qt::HANDLE &, short &, short &, unsigned short &, unsigned short &)));
    connect(HomeWindowMonitor::instance(), SIGNAL(isHomeWindowOnTopChanged()), this, SLOT(toggleDamage()));
}

SwitcherPixmapItem::~SwitcherPixmapItem()
{
    destroyDamage();
    if (d->xWindowPixmap)
        XFreePixmap(QX11Info::display(), d->xWindowPixmap);
    delete d;
}

void SwitcherPixmapItem::toggleDamage()
{
    if (HomeWindowMonitor::instance()->isHomeWindowOnTop()) {
        createDamage();
        update();
    } else {
        destroyDamage();
    }
}

void SwitcherPixmapItem::damageEvent(Qt::HANDLE &damage, short &x, short &y, unsigned short &width, unsigned short &height)
{
    Q_UNUSED(x);
    Q_UNUSED(y);
    Q_UNUSED(width);
    Q_UNUSED(height);
#ifdef Q_WS_X11
    if (d->xWindowPixmapDamage == damage) {
        XDamageSubtract(QX11Info::display(), d->xWindowPixmapDamage, None, None);
        update();
    }
#else
    Q_UNUSED(damage);
#endif
}

void SwitcherPixmapItem::destroyDamage()
{
    if (d->xWindowPixmapDamage != 0) {
        XDamageDestroy(QX11Info::display(), d->xWindowPixmapDamage);
        d->xWindowPixmapDamage = 0;
    }
}

void SwitcherPixmapItem::createDamage()
{
    // TODO: check on display status, don't create damage if off
    if (d->windowId == 0)
        return;

    // Register the pixmap for XDamage events
    d->xWindowPixmapDamage = XDamageCreate(QX11Info::display(), d->windowId, XDamageReportNonEmpty);
}

void SwitcherPixmapItem::updateXWindowPixmap()
{
#ifdef Q_WS_X11
    SWITCHER_DEBUG() << Q_FUNC_INFO << "Resetting X pixmap for " << d->windowId;

    // It is possible that the window is not redirected so check for errors.
    // XSync() needs to be called so that previous errors go to the original
    // handler.
    XSync(QX11Info::display(), FALSE);
    XErrorHandler errh = XSetErrorHandler(handleXError);
    xErrorCode = Success;

    // Get the pixmap ID of the X window
    Pixmap newWindowPixmap = XCompositeNameWindowPixmap(QX11Info::display(), d->windowId);

    // XCompositeNameWindowPixmap doesn't wait for the server to reply, we'll
    // need to do it ourselves to catch the possible BadMatch
    XSync(QX11Info::display(), FALSE);

    d->xWindowPixmapIsValid = xErrorCode == Success;
    if (d->xWindowPixmapIsValid) {
        // Unregister the old pixmap from XDamage events
        destroyDamage();

        if (d->xWindowPixmap != 0) {
            // Dereference the old pixmap ID
            XFreePixmap(QX11Info::display(), d->xWindowPixmap);
        }

        d->xWindowPixmap = newWindowPixmap;

        // Register the pixmap for XDamage events
        if (HomeWindowMonitor::instance()->isHomeWindowOnTop())
            createDamage();

        d->qWindowPixmap = QPixmap::fromX11Pixmap(d->xWindowPixmap, QPixmap::ExplicitlyShared);
    } else {
        // If a BadMatch error occurred the window wasn't redirected yet; deference the invalid pixmap
        if (newWindowPixmap != 0) {
            XFreePixmap(QX11Info::display(), newWindowPixmap);
        }
    }

    // Reset the error handler
    XSetErrorHandler(errh);
#else
#error "not implemented"
#endif
}

void SwitcherPixmapItem::setWindowId(int window)
{
    d->windowId = window;
    d->xWindowPixmapIsValid = false;

    // TODO: should we XFreePixmap here?

    update();
}

int SwitcherPixmapItem::windowId() const
{
    return d->windowId;
}

void SwitcherPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                               QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);

    if (!d->xWindowPixmapIsValid) {
        updateXWindowPixmap();
    }

    QT_TRY {
        painter->drawPixmap(QRect(0, 0, width(), height()), d->qWindowPixmap);
    } QT_CATCH (std::bad_alloc e) {
        // XGetImage failed, the window has been already unmapped
    }
}

bool SwitcherPixmapItem::handleXEvent(const XEvent &event)
{
    WId windowId;

    if (event.type == VisibilityNotify) {
        if (event.xvisibility.state != VisibilityFullyObscured ||
            event.xvisibility.send_event != True) {
            SWITCHER_DEBUG() << Q_FUNC_INFO << "Ignoring VisibilityNotify that isn't a send_event VisibilityFullyObscured for " << event.xvisibility.window;
            return false;
        }

        windowId = event.xvisibility.window;
        SWITCHER_DEBUG() << Q_FUNC_INFO << "Got obscured for " << windowId << "; want " << d->windowId;
    } else if (event.type == ConfigureNotify) {
        windowId = event.xconfigure.window;
        SWITCHER_DEBUG() << Q_FUNC_INFO << "ConfigureNotify for " << windowId << "; want " << d->windowId;
    } else {
        return false;
    }

    if (windowId != d->windowId)
        return false;

    SWITCHER_DEBUG() << Q_FUNC_INFO << "Invalidated, resetting pixmap for " << d->windowId;
    d->xWindowPixmapIsValid = false;
    update();
    return true;
}

<commit_msg>debug damage creation/destruction<commit_after>
// This file is part of lipstick, a QML desktop library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation
// and appearing in the file LICENSE.LGPL included in the packaging
// of this file.
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// Copyright (c) 2011, Robin Burchell
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>
// Copyright (c) 2010, Nokia Corporation and/or its subsidiary(-ies) <directui@nokia.com>

#include <QApplication>
#include <QPainter>
#include <QTimer>
#include <QX11Info>

#include "switcherpixmapitem.h"
#include "xtools/homewindowmonitor.h"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>

// Define this if you'd like to see debug messages from the switcher
#ifdef DEBUG_SWITCHER
#define SWITCHER_DEBUG(things) qDebug() << Q_FUNC_INFO << things
#else
#define SWITCHER_DEBUG(things)
#endif

#ifdef Q_WS_X11
unsigned char xErrorCode = Success;

static int handleXError(Display *, XErrorEvent *event)
{
    xErrorCode = event->error_code;

    return 0;
}
#endif

struct SwitcherPixmapItem::Private
{
    Private()
        : xWindowPixmapIsValid(false)
        , xWindowPixmap(0)
        , xWindowPixmapDamage(0)
        , windowId(0)
    {}

    bool xWindowPixmapIsValid;
    Pixmap xWindowPixmap;
    Damage xWindowPixmapDamage;
    QPixmap qWindowPixmap;
    WId windowId;
};

SwitcherPixmapItem::SwitcherPixmapItem(QDeclarativeItem *parent)
    : QDeclarativeItem(parent)
    , d(new Private)
{
    setFlag(QGraphicsItem::ItemHasNoContents, false);
    connect(qApp, SIGNAL(damageEvent(Qt::HANDLE &, short &, short &, unsigned short &, unsigned short &)), this, SLOT(damageEvent(Qt::HANDLE &, short &, short &, unsigned short &, unsigned short &)));
    connect(HomeWindowMonitor::instance(), SIGNAL(isHomeWindowOnTopChanged()), this, SLOT(toggleDamage()));
}

SwitcherPixmapItem::~SwitcherPixmapItem()
{
    destroyDamage();
    if (d->xWindowPixmap)
        XFreePixmap(QX11Info::display(), d->xWindowPixmap);
    delete d;
}

void SwitcherPixmapItem::toggleDamage()
{
    if (HomeWindowMonitor::instance()->isHomeWindowOnTop()) {
        SWITCHER_DEBUG() << Q_FUNC_INFO << "Creating damage for " << d->windowId;
        createDamage();
        update();
    } else {
        SWITCHER_DEBUG() << Q_FUNC_INFO << "Destroying damage for " << d->windowId;
        destroyDamage();
    }
}

void SwitcherPixmapItem::damageEvent(Qt::HANDLE &damage, short &x, short &y, unsigned short &width, unsigned short &height)
{
    Q_UNUSED(x);
    Q_UNUSED(y);
    Q_UNUSED(width);
    Q_UNUSED(height);
#ifdef Q_WS_X11
    if (d->xWindowPixmapDamage == damage) {
        XDamageSubtract(QX11Info::display(), d->xWindowPixmapDamage, None, None);
        update();
    }
#else
    Q_UNUSED(damage);
#endif
}

void SwitcherPixmapItem::destroyDamage()
{
    if (d->xWindowPixmapDamage != 0) {
        XDamageDestroy(QX11Info::display(), d->xWindowPixmapDamage);
        d->xWindowPixmapDamage = 0;
    }
}

void SwitcherPixmapItem::createDamage()
{
    // TODO: check on display status, don't create damage if off
    if (d->windowId == 0)
        return;

    // Register the pixmap for XDamage events
    d->xWindowPixmapDamage = XDamageCreate(QX11Info::display(), d->windowId, XDamageReportNonEmpty);
}

void SwitcherPixmapItem::updateXWindowPixmap()
{
#ifdef Q_WS_X11
    SWITCHER_DEBUG() << Q_FUNC_INFO << "Resetting X pixmap for " << d->windowId;

    // It is possible that the window is not redirected so check for errors.
    // XSync() needs to be called so that previous errors go to the original
    // handler.
    XSync(QX11Info::display(), FALSE);
    XErrorHandler errh = XSetErrorHandler(handleXError);
    xErrorCode = Success;

    // Get the pixmap ID of the X window
    Pixmap newWindowPixmap = XCompositeNameWindowPixmap(QX11Info::display(), d->windowId);

    // XCompositeNameWindowPixmap doesn't wait for the server to reply, we'll
    // need to do it ourselves to catch the possible BadMatch
    XSync(QX11Info::display(), FALSE);

    d->xWindowPixmapIsValid = xErrorCode == Success;
    if (d->xWindowPixmapIsValid) {
        // Unregister the old pixmap from XDamage events
        destroyDamage();

        if (d->xWindowPixmap != 0) {
            // Dereference the old pixmap ID
            XFreePixmap(QX11Info::display(), d->xWindowPixmap);
        }

        d->xWindowPixmap = newWindowPixmap;

        // Register the pixmap for XDamage events
        if (HomeWindowMonitor::instance()->isHomeWindowOnTop())
            createDamage();

        d->qWindowPixmap = QPixmap::fromX11Pixmap(d->xWindowPixmap, QPixmap::ExplicitlyShared);
    } else {
        // If a BadMatch error occurred the window wasn't redirected yet; deference the invalid pixmap
        if (newWindowPixmap != 0) {
            XFreePixmap(QX11Info::display(), newWindowPixmap);
        }
    }

    // Reset the error handler
    XSetErrorHandler(errh);
#else
#error "not implemented"
#endif
}

void SwitcherPixmapItem::setWindowId(int window)
{
    d->windowId = window;
    d->xWindowPixmapIsValid = false;

    // TODO: should we XFreePixmap here?

    update();
}

int SwitcherPixmapItem::windowId() const
{
    return d->windowId;
}

void SwitcherPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                               QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);

    if (!d->xWindowPixmapIsValid) {
        updateXWindowPixmap();
    }

    QT_TRY {
        painter->drawPixmap(QRect(0, 0, width(), height()), d->qWindowPixmap);
    } QT_CATCH (std::bad_alloc e) {
        // XGetImage failed, the window has been already unmapped
    }
}

bool SwitcherPixmapItem::handleXEvent(const XEvent &event)
{
    WId windowId;

    if (event.type == VisibilityNotify) {
        if (event.xvisibility.state != VisibilityFullyObscured ||
            event.xvisibility.send_event != True) {
            SWITCHER_DEBUG() << Q_FUNC_INFO << "Ignoring VisibilityNotify that isn't a send_event VisibilityFullyObscured for " << event.xvisibility.window;
            return false;
        }

        windowId = event.xvisibility.window;
        SWITCHER_DEBUG() << Q_FUNC_INFO << "Got obscured for " << windowId << "; want " << d->windowId;
    } else if (event.type == ConfigureNotify) {
        windowId = event.xconfigure.window;
        SWITCHER_DEBUG() << Q_FUNC_INFO << "ConfigureNotify for " << windowId << "; want " << d->windowId;
    } else {
        return false;
    }

    if (windowId != d->windowId)
        return false;

    SWITCHER_DEBUG() << Q_FUNC_INFO << "Invalidated, resetting pixmap for " << d->windowId;
    d->xWindowPixmapIsValid = false;
    update();
    return true;
}

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qndefmessage.h"
#include "qndefrecord_p.h"

QTM_BEGIN_NAMESPACE

/*!
    \class QNdefMessage
    \brief The QNdefMessage class provides an NFC NDEF message.

    \ingroup connectivity-nfc
    \inmodule QtConnectivity

    A QNdefMessage is a collection of 0 or more QNdefRecords.
*/

/*!
    \fn QNdefMessage::QNdefMessage()

    Constructs a new empty NDEF message.
*/

/*!
    \fn QNdefMessage::QNdefMessage(const QNdefRecord &record)

    Constructs a new NDEF message containing a single record \a record.
*/

/*!
    \fn QNdefMessage::QNdefMessage(const QNdefMessage &message)

    Constructs a new NDEF message that is a copy of \a message.
*/

/*!
    \fn QNdefMessage::QNdefMessage(const QList<QNdefRecord> &records)

    Constructs a new NDEF message that contains all of the records in \a records.
*/

/*!
    Returns an NDEF message parsed from the contents of \a message.

    The \a message paramater is interpreted as the raw message format defined in the NFC
    Specifications.

    If a parse error occurs an empty NDEF message is returned.
*/
QNdefMessage QNdefMessage::fromByteArray(const QByteArray &message)
{
    QNdefMessage result;

    bool seenMessageBegin = false;
    bool seenMessageEnd = false;

    QByteArray partialChunk;
    QNdefRecord record;

    QByteArray::const_iterator i = message.begin();
    while (i != message.end()) {
        quint8 flags = *i;

        bool messageBegin = flags & 0x80;
        bool messageEnd = flags & 0x40;

        bool cf = flags & 0x20;
        bool sr = flags & 0x10;
        bool il = flags & 0x08;
        quint8 typeNameFormat = flags & 0x07;

        if (messageBegin && seenMessageBegin) {
            qWarning("Got message begin but already parsed some records");
            return QNdefMessage();
        }
        if (messageEnd && seenMessageEnd) {
            qWarning("Got message end but already parsed final record");
            return QNdefMessage();
        }
        if (cf && (typeNameFormat != 0x06) && !partialChunk.isEmpty()) {
            qWarning("partial chunk not empty or typeNameFormat not 0x06 as expected");
            return QNdefMessage();
        }

        quint8 typeLength = *(++i);

        if ((typeNameFormat == 0x06) && (typeLength != 0)) {
            qWarning("Invalid chunked data, TYPE_LENGTH != 0");
            return QNdefMessage();
        }

        quint32 payloadLength;
        if (sr)
            payloadLength = *(++i);
        else {
            payloadLength = quint8(*(++i)) << 24;
            payloadLength |= quint8(*(++i)) << 16;
            payloadLength |= quint8(*(++i)) << 8;
            payloadLength |= quint8(*(++i)) << 0;
        }

        quint8 idLength;
        if (il)
            idLength = *(++i);
        else
            idLength = 0;

        if ((typeNameFormat == 0x06) && (idLength != 0)) {
            qWarning("Invalid chunked data, IL != 0");
            return QNdefMessage();
        }

        record.setUserTypeNameFormat(typeNameFormat);

        if (typeLength > 0) {
            QByteArray type(++i, typeLength);
            record.setType(type);
            i += typeLength - 1;
        }

        if (idLength > 0) {
            QByteArray id(++i, idLength);
            record.setId(id);
            i += idLength - 1;
        }

        if (payloadLength > 0) {
            QByteArray payload(++i, payloadLength);

            if (cf) {
                // chunked payload, except last
                partialChunk.append(payload);
            } else if (typeNameFormat == 0x06) {
                // last chunk of chunked payload
                record.setPayload(partialChunk + payload);
                partialChunk.clear();
            } else {
                // non-chunked payload
                record.setPayload(payload);
            }

            i += payloadLength - 1;
        }

        if (!cf)
            result.append(record);

        // move to start of next record
        ++i;
    }

    return result;
}

/*!
    Returns true if this NDEF message is equivalent to \a other; otherwise returns false.
*/
bool QNdefMessage::operator==(const QNdefMessage &other) const
{
    // both records are empty
    if (isEmpty() && other.isEmpty())
        return true;

    // compare empty to really empty
    if (isEmpty() && other.count() == 1 && other.first().typeNameFormat() == QNdefRecord::Empty)
        return true;
    if (other.isEmpty() && count() == 1 && first().typeNameFormat() == QNdefRecord::Empty)
        return true;

    if (count() != other.count())
        return false;

    for (int i = 0; i < count(); ++i) {
        if (at(i) != other.at(i))
            return false;
    }

    return true;
}

/*!
    Returns the NDEF message as a byte array.
*/
QByteArray QNdefMessage::toByteArray() const
{
    QByteArray m;

    for (int i = 0; i < count(); ++i) {
        const QNdefRecord &record = at(i);

        quint8 flags = record.userTypeNameFormat();

        if (i == 0)
            flags |= 0x80;
        if (i == count() - 1)
            flags |= 0x40;

        // cf (chunked records) not supported yet

        if (record.payload().length() < 255)
            flags |= 0x10;

        if (!record.id().isEmpty())
            flags |= 0x08;

        m.append(flags);
        m.append(record.type().length());

        if (flags & 0x10) {
            m.append(quint8(record.payload().length()));
        } else {
            quint32 length = record.payload().length();
            m.append(length >> 24);
            m.append(length >> 16);
            m.append(length >> 8);
            m.append(length & 0x000000ff);
        }

        if (flags & 0x08)
            m.append(record.id().length());

        if (!record.type().isEmpty())
            m.append(record.type());

        if (!record.id().isEmpty())
            m.append(record.id());

        if (!record.payload().isEmpty())
            m.append(record.payload());
    }

    return m;
}

QTM_END_NAMESPACE
<commit_msg>Output something useful from toByteArray for empty NDEF messages.<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qndefmessage.h"
#include "qndefrecord_p.h"

QTM_BEGIN_NAMESPACE

/*!
    \class QNdefMessage
    \brief The QNdefMessage class provides an NFC NDEF message.

    \ingroup connectivity-nfc
    \inmodule QtConnectivity

    A QNdefMessage is a collection of 0 or more QNdefRecords.
*/

/*!
    \fn QNdefMessage::QNdefMessage()

    Constructs a new empty NDEF message.
*/

/*!
    \fn QNdefMessage::QNdefMessage(const QNdefRecord &record)

    Constructs a new NDEF message containing a single record \a record.
*/

/*!
    \fn QNdefMessage::QNdefMessage(const QNdefMessage &message)

    Constructs a new NDEF message that is a copy of \a message.
*/

/*!
    \fn QNdefMessage::QNdefMessage(const QList<QNdefRecord> &records)

    Constructs a new NDEF message that contains all of the records in \a records.
*/

/*!
    Returns an NDEF message parsed from the contents of \a message.

    The \a message paramater is interpreted as the raw message format defined in the NFC
    Specifications.

    If a parse error occurs an empty NDEF message is returned.
*/
QNdefMessage QNdefMessage::fromByteArray(const QByteArray &message)
{
    QNdefMessage result;

    bool seenMessageBegin = false;
    bool seenMessageEnd = false;

    QByteArray partialChunk;
    QNdefRecord record;

    QByteArray::const_iterator i = message.begin();
    while (i != message.end()) {
        quint8 flags = *i;

        bool messageBegin = flags & 0x80;
        bool messageEnd = flags & 0x40;

        bool cf = flags & 0x20;
        bool sr = flags & 0x10;
        bool il = flags & 0x08;
        quint8 typeNameFormat = flags & 0x07;

        if (messageBegin && seenMessageBegin) {
            qWarning("Got message begin but already parsed some records");
            return QNdefMessage();
        }
        if (messageEnd && seenMessageEnd) {
            qWarning("Got message end but already parsed final record");
            return QNdefMessage();
        }
        if (cf && (typeNameFormat != 0x06) && !partialChunk.isEmpty()) {
            qWarning("partial chunk not empty or typeNameFormat not 0x06 as expected");
            return QNdefMessage();
        }

        quint8 typeLength = *(++i);

        if ((typeNameFormat == 0x06) && (typeLength != 0)) {
            qWarning("Invalid chunked data, TYPE_LENGTH != 0");
            return QNdefMessage();
        }

        quint32 payloadLength;
        if (sr)
            payloadLength = *(++i);
        else {
            payloadLength = quint8(*(++i)) << 24;
            payloadLength |= quint8(*(++i)) << 16;
            payloadLength |= quint8(*(++i)) << 8;
            payloadLength |= quint8(*(++i)) << 0;
        }

        quint8 idLength;
        if (il)
            idLength = *(++i);
        else
            idLength = 0;

        if ((typeNameFormat == 0x06) && (idLength != 0)) {
            qWarning("Invalid chunked data, IL != 0");
            return QNdefMessage();
        }

        record.setUserTypeNameFormat(typeNameFormat);

        if (typeLength > 0) {
            QByteArray type(++i, typeLength);
            record.setType(type);
            i += typeLength - 1;
        }

        if (idLength > 0) {
            QByteArray id(++i, idLength);
            record.setId(id);
            i += idLength - 1;
        }

        if (payloadLength > 0) {
            QByteArray payload(++i, payloadLength);

            if (cf) {
                // chunked payload, except last
                partialChunk.append(payload);
            } else if (typeNameFormat == 0x06) {
                // last chunk of chunked payload
                record.setPayload(partialChunk + payload);
                partialChunk.clear();
            } else {
                // non-chunked payload
                record.setPayload(payload);
            }

            i += payloadLength - 1;
        }

        if (!cf)
            result.append(record);

        // move to start of next record
        ++i;
    }

    return result;
}

/*!
    Returns true if this NDEF message is equivalent to \a other; otherwise returns false.
*/
bool QNdefMessage::operator==(const QNdefMessage &other) const
{
    // both records are empty
    if (isEmpty() && other.isEmpty())
        return true;

    // compare empty to really empty
    if (isEmpty() && other.count() == 1 && other.first().typeNameFormat() == QNdefRecord::Empty)
        return true;
    if (other.isEmpty() && count() == 1 && first().typeNameFormat() == QNdefRecord::Empty)
        return true;

    if (count() != other.count())
        return false;

    for (int i = 0; i < count(); ++i) {
        if (at(i) != other.at(i))
            return false;
    }

    return true;
}

/*!
    Returns the NDEF message as a byte array.
*/
QByteArray QNdefMessage::toByteArray() const
{
    // An empty message is treated as a message containing a single empty record.
    if (isEmpty())
        return QNdefMessage(QNdefRecord()).toByteArray();

    QByteArray m;

    for (int i = 0; i < count(); ++i) {
        const QNdefRecord &record = at(i);

        quint8 flags = record.userTypeNameFormat();

        if (i == 0)
            flags |= 0x80;
        if (i == count() - 1)
            flags |= 0x40;

        // cf (chunked records) not supported yet

        if (record.payload().length() < 255)
            flags |= 0x10;

        if (!record.id().isEmpty())
            flags |= 0x08;

        m.append(flags);
        m.append(record.type().length());

        if (flags & 0x10) {
            m.append(quint8(record.payload().length()));
        } else {
            quint32 length = record.payload().length();
            m.append(length >> 24);
            m.append(length >> 16);
            m.append(length >> 8);
            m.append(length & 0x000000ff);
        }

        if (flags & 0x08)
            m.append(record.id().length());

        if (!record.type().isEmpty())
            m.append(record.type());

        if (!record.id().isEmpty())
            m.append(record.id());

        if (!record.payload().isEmpty())
            m.append(record.payload());
    }

    return m;
}

QTM_END_NAMESPACE
<|endoftext|>