<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: textcharacterpropertiescontext.cxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "oox/drawingml/textcharacterpropertiescontext.hxx"

#include <com/sun/star/awt/FontSlant.hpp>
#include <com/sun/star/awt/FontWeight.hpp>
#include <com/sun/star/awt/FontStrikeout.hpp>
#include <com/sun/star/awt/FontUnderline.hpp>
#include <com/sun/star/lang/Locale.hpp>

#include "oox/helper/attributelist.hxx"
#include "oox/drawingml/drawingmltypes.hxx"
#include "oox/drawingml/colorchoicecontext.hxx"
#include "oox/drawingml/lineproperties.hxx"
#include "oox/core/namespaces.hxx"
#include "oox/core/relations.hxx"
#include "textfontcontext.hxx"
#include "hyperlinkcontext.hxx"
#include "tokens.hxx"

using ::rtl::OUString;
using namespace ::oox::core;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::xml::sax;
using namespace ::com::sun::star::awt;

namespace oox { namespace drawingml {

// --------------------------------------------------------------------

// CT_TextCharacterProperties
TextCharacterPropertiesContext::TextCharacterPropertiesContext(
        ContextHandler& rParent,
        const Reference< XFastAttributeList >& rXAttributes,
        oox::drawingml::TextCharacterProperties& rTextCharacterProperties )
: ContextHandler( rParent )
, mrTextCharacterProperties( rTextCharacterProperties )
{
    AttributeList attribs( rXAttributes );
    PropertyMap& rPropertyMap( mrTextCharacterProperties.getTextCharacterPropertyMap() );

    rtl::OUString aVal( rXAttributes->getOptionalValue( XML_sz ) );
    if ( aVal.getLength() )
    {
        float fTextSize = GetTextSize( aVal );
        const rtl::OUString sCharHeight( CREATE_OUSTRING( "CharHeight" ) );
        const rtl::OUString sCharHeightAsian( CREATE_OUSTRING( "CharHeightAsian" ) );
        const rtl::OUString sCharHeightComplex( CREATE_OUSTRING( "CharHeightComplex" ) );
        rPropertyMap[ sCharHeight ] <<= fTextSize;
        rPropertyMap[ sCharHeightAsian ] <<= fTextSize;
        rPropertyMap[ sCharHeightComplex ] <<= fTextSize;
    }

    bool bIsBold = attribs.getBool( XML_b, false );
    const rtl::OUString sCharWeight( CREATE_OUSTRING( "CharWeight" ) );
    const rtl::OUString sCharWeightAsian( CREATE_OUSTRING( "CharWeightAsian" ) );
    const rtl::OUString sCharWeightComplex( CREATE_OUSTRING( "CharWeightComplex" ) );
    rPropertyMap[ sCharWeight ] <<= ( bIsBold ? FontWeight::BOLD : FontWeight::NORMAL );
    rPropertyMap[ sCharWeightAsian ] <<= ( bIsBold ? FontWeight::BOLD : FontWeight::NORMAL );
    rPropertyMap[ sCharWeightComplex ] <<= ( bIsBold ? FontWeight::BOLD : FontWeight::NORMAL );

    bool bIsItalic = attribs.getBool( XML_i, false );
    const rtl::OUString sCharFontPosture( CREATE_OUSTRING( "CharPosture" ) );
    const rtl::OUString sCharFontPostureAsian( CREATE_OUSTRING( "CharPostureAsian" ) );
    const rtl::OUString sCharFontPostureComplex( CREATE_OUSTRING( "CharPostureComplex" ) );
    rPropertyMap[ sCharFontPosture ] <<= ( bIsItalic ? FontSlant_ITALIC : FontSlant_NONE );
    rPropertyMap[ sCharFontPostureAsian ] <<= ( bIsItalic ? FontSlant_ITALIC : FontSlant_NONE );
    rPropertyMap[ sCharFontPostureComplex ] <<= ( bIsItalic ? FontSlant_ITALIC : FontSlant_NONE );

    sal_Int32 nFontUnderline( rXAttributes->getOptionalValueToken( XML_u, 0 ) );
    if ( nFontUnderline )
    {
        const rtl::OUString sCharUnderline( CREATE_OUSTRING( "CharUnderline" ) );
        rPropertyMap[ sCharUnderline ] <<= GetFontUnderline( nFontUnderline );
        mrTextCharacterProperties.getHasUnderline() <<= sal_True;
    }

    const rtl::OUString sCharStrikeout( CREATE_OUSTRING( "CharStrikeout" ) );
    rPropertyMap[ sCharStrikeout ] <<= GetFontStrikeout( rXAttributes->getOptionalValueToken( XML_strike, XML_noStrike ) );

    // ST_TextCapsType
    const rtl::OUString sCharCaseMap( CREATE_OUSTRING( "CharCaseMap" ) );
    rPropertyMap[ sCharCaseMap ] <<= GetCaseMap( rXAttributes->getOptionalValueToken( XML_cap, XML_none ) );

    OUString sLang = rXAttributes->getOptionalValue( XML_lang );
    if( sLang.getLength( ) )
    {
        const rtl::OUString sCharLocale( CREATE_OUSTRING( "CharLocale" ) );
        const rtl::OUString sCharLocaleAsian( CREATE_OUSTRING( "CharLocaleAsian" ) );
        const rtl::OUString sCharLocaleComplex( CREATE_OUSTRING( "CharLocaleComplex" ) );

        com::sun::star::lang::Locale aLocale;
        OUString aString( sLang );
        sal_Int32  nSepPos = aString.indexOf( (sal_Unicode)'-', 0 );
        if ( nSepPos != -1 )
        {
            aLocale.Language = aString.copy( 0, nSepPos );
            aLocale.Country = aString.copy( nSepPos+1 );
        }
        else
        {
            aLocale.Language = aString;
        }

        rPropertyMap[ sCharLocale ] <<= aLocale;
        rPropertyMap[ sCharLocaleAsian ] <<= aLocale;
        rPropertyMap[ sCharLocaleComplex ] <<= aLocale;
    }

// TODO
/*   todo: we need to be able to iterate over the XFastAttributes

  // ST_TextNonNegativePoint
    const rtl::OUString sCharKerning( CREATE_OUSTRING( "CharKerning" ) );
    //case NMSP_DRAWINGML|XML_kern:

  // ST_TextLanguageID
    OUString sAltLang = rXAttributes->getOptionalValue( XML_altLang );

        case NMSP_DRAWINGML|XML_kumimoji:       // xsd:boolean
            break;
        case NMSP_DRAWINGML|XML_spc:            // ST_TextPoint
        case NMSP_DRAWINGML|XML_normalizeH:     // xsd:boolean
        case NMSP_DRAWINGML|XML_baseline:       // ST_Percentage
        case NMSP_DRAWINGML|XML_noProof:        // xsd:boolean
        case NMSP_DRAWINGML|XML_dirty:          // xsd:boolean
        case NMSP_DRAWINGML|XML_err:            // xsd:boolean
        case NMSP_DRAWINGML|XML_smtClean:       // xsd:boolean
        case NMSP_DRAWINGML|XML_smtId:          // xsd:unsignedInt
            break;
*/

}

TextCharacterPropertiesContext::~TextCharacterPropertiesContext()
{
    PropertyMap& rPropertyMap( mrTextCharacterProperties.getTextCharacterPropertyMap() );

    sal_Int16 nPitch, nFamily;

    if( maLatinFont.is() )
    {
        const rtl::OUString sCharFontName( CREATE_OUSTRING( "CharFontName" ) );
        const rtl::OUString sCharFontPitch( CREATE_OUSTRING( "CharFontPitch" ) );
        const rtl::OUString sCharFontFamily( CREATE_OUSTRING( "CharFontFamily" ) );
        GetFontPitch( maLatinFont.mnPitch, nPitch, nFamily);
        rPropertyMap[ sCharFontName ] <<= maLatinFont.msTypeface;
        rPropertyMap[ sCharFontPitch ] <<= nPitch;
        rPropertyMap[ sCharFontFamily ] <<= nFamily;
    }
    if( maAsianFont.is() )
    {
        const rtl::OUString sCharFontNameAsian( CREATE_OUSTRING( "CharFontNameAsian" ) );
        const rtl::OUString sCharFontPitchAsian( CREATE_OUSTRING( "CharFontPitchAsian" ) );
        const rtl::OUString sCharFontFamilyAsian( CREATE_OUSTRING( "CharFontFamilyAsian" ) );
        GetFontPitch( maAsianFont.mnPitch, nPitch, nFamily);
        rPropertyMap[ sCharFontNameAsian ] <<= maAsianFont.msTypeface;
        rPropertyMap[ sCharFontPitchAsian ] <<= nFamily;
        rPropertyMap[ sCharFontFamilyAsian ] <<= nPitch;
    }
    if( maComplexFont.is() )
    {
        const rtl::OUString sCharFontNameComplex( CREATE_OUSTRING( "CharFontNameComplex" ) );
        const rtl::OUString sCharFontPitchComplex( CREATE_OUSTRING( "CharFontPitchComplex" ) );
        const rtl::OUString sCharFontFamilyComplex( CREATE_OUSTRING( "CharFontFamilyComplex" ) );
        GetFontPitch( maComplexFont.mnPitch, nPitch, nFamily );
        rPropertyMap[ sCharFontNameComplex ] <<= maComplexFont.msTypeface;
        rPropertyMap[ sCharFontPitchComplex ] <<= nPitch;
        rPropertyMap[ sCharFontFamilyComplex ] <<= nFamily;
    }
}

// --------------------------------------------------------------------

void TextCharacterPropertiesContext::endFastElement( sal_Int32 ) throw (SAXException, RuntimeException)
{
}

// --------------------------------------------------------------------

Reference< XFastContextHandler > TextCharacterPropertiesContext::createFastChildContext( sal_Int32 aElementToken, const Reference< XFastAttributeList >& xAttributes ) throw (SAXException, RuntimeException)
{
    Reference< XFastContextHandler > xRet;
    switch( aElementToken )
    {
        // not supported.....
      case NMSP_DRAWINGML|XML_ln:           // CT_LineProperties
// TODO unsupported yet
//          xRet.set( new LinePropertiesContext( getHandler(), xAttributes, maTextOutlineProperties ) );
            break;
        // EG_FillProperties
      case NMSP_DRAWINGML|XML_solidFill:
            xRet.set( new colorChoiceContext( *this, *mrTextCharacterProperties.getCharColor() ) );
            break;
        // EG_EffectProperties
    case NMSP_DRAWINGML|XML_effectDag:
            // CT_EffectContainer 5.1.10.25
      case NMSP_DRAWINGML|XML_effectLst:
            // CT_EffectList 5.1.10.26
            break;

        case NMSP_DRAWINGML|XML_highlight:      //CT_Color
            xRet.set( new colorChoiceContext( *this, *mrTextCharacterProperties.getHighlightColor() ) );
            break;

        // EG_TextUnderlineLine
        case NMSP_DRAWINGML|XML_uLnTx:          // CT_TextUnderlineLineFollowText
             mrTextCharacterProperties.getUnderlineLineFollowText() <<= sal_True;
            break;
        case NMSP_DRAWINGML|XML_uLn:            // CT_LineProperties
// TODO unsupported yet
//          xRet.set( new LinePropertiesContext( getHandler(), xAttributes, maUnderlineProperties ) );
            break;

        // EG_TextUnderlineFill
        case NMSP_DRAWINGML|XML_uFillTx:        // CT_TextUnderlineFillFollowText
             mrTextCharacterProperties.getUnderlineFillFollowText() <<= sal_True;
            break;
        case NMSP_DRAWINGML|XML_uFill:          // CT_TextUnderlineFillGroupWrapper->EG_FillProperties (not supported)
            xRet.set( new colorChoiceContext( *this, *mrTextCharacterProperties.getUnderlineColor() ) );
            break;

        case NMSP_DRAWINGML|XML_ea:             // CT_TextFont
            xRet.set( new TextFontContext( *this, aElementToken,  xAttributes, maAsianFont ) );
            break;
        case NMSP_DRAWINGML|XML_cs:             // CT_TextFont
            xRet.set( new TextFontContext( *this, aElementToken,  xAttributes, maComplexFont ) );
            break;
        case NMSP_DRAWINGML|XML_sym:            // CT_TextFont
            xRet.set( new TextFontContext( *this, aElementToken,  xAttributes, maSymbolFont ) );
            break;
        case NMSP_DRAWINGML|XML_latin:          // CT_TextFont
            xRet.set( new TextFontContext( *this, aElementToken,  xAttributes, maLatinFont ) );
            break;
        case NMSP_DRAWINGML|XML_hlinkClick:     // CT_Hyperlink
        case NMSP_DRAWINGML|XML_hlinkMouseOver: // CT_Hyperlink
            xRet.set( new HyperLinkContext( *this, xAttributes,  mrTextCharacterProperties.getHyperlinkPropertyMap() ) );
            break;
    }
    if ( !xRet.is() )
        xRet.set( this );
    return xRet;
}

// --------------------------------------------------------------------

} }

<commit_msg>INTEGRATION: CWS ooxtablefilter (1.3.2); FILE MERGED 2008/06/10 09:52:55 sj 1.3.2.2: RESYNC: (1.3-1.4); FILE MERGED 2008/04/02 17:43:48 sj 1.3.2.1: added table import<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: textcharacterpropertiescontext.cxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "oox/drawingml/textcharacterpropertiescontext.hxx"

#include <com/sun/star/awt/FontSlant.hpp>
#include <com/sun/star/awt/FontWeight.hpp>
#include <com/sun/star/awt/FontStrikeout.hpp>
#include <com/sun/star/awt/FontUnderline.hpp>
#include <com/sun/star/lang/Locale.hpp>

#include "oox/helper/attributelist.hxx"
#include "oox/drawingml/drawingmltypes.hxx"
#include "oox/drawingml/colorchoicecontext.hxx"
#include "oox/drawingml/lineproperties.hxx"
#include "oox/drawingml/textfontcontext.hxx"
#include "oox/core/namespaces.hxx"
#include "oox/core/relations.hxx"
#include "hyperlinkcontext.hxx"
#include "tokens.hxx"

using ::rtl::OUString;
using namespace ::oox::core;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::xml::sax;
using namespace ::com::sun::star::awt;

namespace oox { namespace drawingml {

// --------------------------------------------------------------------

// CT_TextCharacterProperties
TextCharacterPropertiesContext::TextCharacterPropertiesContext(
        ContextHandler& rParent,
        const Reference< XFastAttributeList >& rXAttributes,
        oox::drawingml::TextCharacterProperties& rTextCharacterProperties )
: ContextHandler( rParent )
, mrTextCharacterProperties( rTextCharacterProperties )
{
    AttributeList attribs( rXAttributes );
    PropertyMap& rPropertyMap( mrTextCharacterProperties.getTextCharacterPropertyMap() );

    rtl::OUString aVal( rXAttributes->getOptionalValue( XML_sz ) );
    if ( aVal.getLength() )
    {
        float fTextSize = GetTextSize( aVal );
        const rtl::OUString sCharHeight( CREATE_OUSTRING( "CharHeight" ) );
        const rtl::OUString sCharHeightAsian( CREATE_OUSTRING( "CharHeightAsian" ) );
        const rtl::OUString sCharHeightComplex( CREATE_OUSTRING( "CharHeightComplex" ) );
        rPropertyMap[ sCharHeight ] <<= fTextSize;
        rPropertyMap[ sCharHeightAsian ] <<= fTextSize;
        rPropertyMap[ sCharHeightComplex ] <<= fTextSize;
    }

    bool bIsBold = attribs.getBool( XML_b, false );
    const rtl::OUString sCharWeight( CREATE_OUSTRING( "CharWeight" ) );
    const rtl::OUString sCharWeightAsian( CREATE_OUSTRING( "CharWeightAsian" ) );
    const rtl::OUString sCharWeightComplex( CREATE_OUSTRING( "CharWeightComplex" ) );
    rPropertyMap[ sCharWeight ] <<= ( bIsBold ? FontWeight::BOLD : FontWeight::NORMAL );
    rPropertyMap[ sCharWeightAsian ] <<= ( bIsBold ? FontWeight::BOLD : FontWeight::NORMAL );
    rPropertyMap[ sCharWeightComplex ] <<= ( bIsBold ? FontWeight::BOLD : FontWeight::NORMAL );

    bool bIsItalic = attribs.getBool( XML_i, false );
    const rtl::OUString sCharFontPosture( CREATE_OUSTRING( "CharPosture" ) );
    const rtl::OUString sCharFontPostureAsian( CREATE_OUSTRING( "CharPostureAsian" ) );
    const rtl::OUString sCharFontPostureComplex( CREATE_OUSTRING( "CharPostureComplex" ) );
    rPropertyMap[ sCharFontPosture ] <<= ( bIsItalic ? FontSlant_ITALIC : FontSlant_NONE );
    rPropertyMap[ sCharFontPostureAsian ] <<= ( bIsItalic ? FontSlant_ITALIC : FontSlant_NONE );
    rPropertyMap[ sCharFontPostureComplex ] <<= ( bIsItalic ? FontSlant_ITALIC : FontSlant_NONE );

    sal_Int32 nFontUnderline( rXAttributes->getOptionalValueToken( XML_u, 0 ) );
    if ( nFontUnderline )
    {
        const rtl::OUString sCharUnderline( CREATE_OUSTRING( "CharUnderline" ) );
        rPropertyMap[ sCharUnderline ] <<= GetFontUnderline( nFontUnderline );
        mrTextCharacterProperties.getHasUnderline() <<= sal_True;
    }

    const rtl::OUString sCharStrikeout( CREATE_OUSTRING( "CharStrikeout" ) );
    rPropertyMap[ sCharStrikeout ] <<= GetFontStrikeout( rXAttributes->getOptionalValueToken( XML_strike, XML_noStrike ) );

    // ST_TextCapsType
    const rtl::OUString sCharCaseMap( CREATE_OUSTRING( "CharCaseMap" ) );
    rPropertyMap[ sCharCaseMap ] <<= GetCaseMap( rXAttributes->getOptionalValueToken( XML_cap, XML_none ) );

    OUString sLang = rXAttributes->getOptionalValue( XML_lang );
    if( sLang.getLength( ) )
    {
        const rtl::OUString sCharLocale( CREATE_OUSTRING( "CharLocale" ) );
        const rtl::OUString sCharLocaleAsian( CREATE_OUSTRING( "CharLocaleAsian" ) );
        const rtl::OUString sCharLocaleComplex( CREATE_OUSTRING( "CharLocaleComplex" ) );

        com::sun::star::lang::Locale aLocale;
        OUString aString( sLang );
        sal_Int32  nSepPos = aString.indexOf( (sal_Unicode)'-', 0 );
        if ( nSepPos != -1 )
        {
            aLocale.Language = aString.copy( 0, nSepPos );
            aLocale.Country = aString.copy( nSepPos+1 );
        }
        else
        {
            aLocale.Language = aString;
        }

        rPropertyMap[ sCharLocale ] <<= aLocale;
        rPropertyMap[ sCharLocaleAsian ] <<= aLocale;
        rPropertyMap[ sCharLocaleComplex ] <<= aLocale;
    }

// TODO
/*   todo: we need to be able to iterate over the XFastAttributes

  // ST_TextNonNegativePoint
    const rtl::OUString sCharKerning( CREATE_OUSTRING( "CharKerning" ) );
    //case NMSP_DRAWINGML|XML_kern:

  // ST_TextLanguageID
    OUString sAltLang = rXAttributes->getOptionalValue( XML_altLang );

        case NMSP_DRAWINGML|XML_kumimoji:       // xsd:boolean
            break;
        case NMSP_DRAWINGML|XML_spc:            // ST_TextPoint
        case NMSP_DRAWINGML|XML_normalizeH:     // xsd:boolean
        case NMSP_DRAWINGML|XML_baseline:       // ST_Percentage
        case NMSP_DRAWINGML|XML_noProof:        // xsd:boolean
        case NMSP_DRAWINGML|XML_dirty:          // xsd:boolean
        case NMSP_DRAWINGML|XML_err:            // xsd:boolean
        case NMSP_DRAWINGML|XML_smtClean:       // xsd:boolean
        case NMSP_DRAWINGML|XML_smtId:          // xsd:unsignedInt
            break;
*/

}

TextCharacterPropertiesContext::~TextCharacterPropertiesContext()
{
    PropertyMap& rPropertyMap( mrTextCharacterProperties.getTextCharacterPropertyMap() );

    sal_Int16 nPitch, nFamily;

    if( maLatinFont.is() )
    {
        const rtl::OUString sCharFontName( CREATE_OUSTRING( "CharFontName" ) );
        const rtl::OUString sCharFontPitch( CREATE_OUSTRING( "CharFontPitch" ) );
        const rtl::OUString sCharFontFamily( CREATE_OUSTRING( "CharFontFamily" ) );
        GetFontPitch( maLatinFont.mnPitch, nPitch, nFamily);
        rPropertyMap[ sCharFontName ] <<= maLatinFont.msTypeface;
        rPropertyMap[ sCharFontPitch ] <<= nPitch;
        rPropertyMap[ sCharFontFamily ] <<= nFamily;
    }
    if( maAsianFont.is() )
    {
        const rtl::OUString sCharFontNameAsian( CREATE_OUSTRING( "CharFontNameAsian" ) );
        const rtl::OUString sCharFontPitchAsian( CREATE_OUSTRING( "CharFontPitchAsian" ) );
        const rtl::OUString sCharFontFamilyAsian( CREATE_OUSTRING( "CharFontFamilyAsian" ) );
        GetFontPitch( maAsianFont.mnPitch, nPitch, nFamily);
        rPropertyMap[ sCharFontNameAsian ] <<= maAsianFont.msTypeface;
        rPropertyMap[ sCharFontPitchAsian ] <<= nFamily;
        rPropertyMap[ sCharFontFamilyAsian ] <<= nPitch;
    }
    if( maComplexFont.is() )
    {
        const rtl::OUString sCharFontNameComplex( CREATE_OUSTRING( "CharFontNameComplex" ) );
        const rtl::OUString sCharFontPitchComplex( CREATE_OUSTRING( "CharFontPitchComplex" ) );
        const rtl::OUString sCharFontFamilyComplex( CREATE_OUSTRING( "CharFontFamilyComplex" ) );
        GetFontPitch( maComplexFont.mnPitch, nPitch, nFamily );
        rPropertyMap[ sCharFontNameComplex ] <<= maComplexFont.msTypeface;
        rPropertyMap[ sCharFontPitchComplex ] <<= nPitch;
        rPropertyMap[ sCharFontFamilyComplex ] <<= nFamily;
    }
}

// --------------------------------------------------------------------

void TextCharacterPropertiesContext::endFastElement( sal_Int32 ) throw (SAXException, RuntimeException)
{
}

// --------------------------------------------------------------------

Reference< XFastContextHandler > TextCharacterPropertiesContext::createFastChildContext( sal_Int32 aElementToken, const Reference< XFastAttributeList >& xAttributes ) throw (SAXException, RuntimeException)
{
    Reference< XFastContextHandler > xRet;
    switch( aElementToken )
    {
        // not supported.....
      case NMSP_DRAWINGML|XML_ln:           // CT_LineProperties
// TODO unsupported yet
//          xRet.set( new LinePropertiesContext( getHandler(), xAttributes, maTextOutlineProperties ) );
            break;
        // EG_FillProperties
      case NMSP_DRAWINGML|XML_solidFill:
            xRet.set( new colorChoiceContext( *this, *mrTextCharacterProperties.getCharColor() ) );
            break;
        // EG_EffectProperties
    case NMSP_DRAWINGML|XML_effectDag:
            // CT_EffectContainer 5.1.10.25
      case NMSP_DRAWINGML|XML_effectLst:
            // CT_EffectList 5.1.10.26
            break;

        case NMSP_DRAWINGML|XML_highlight:      //CT_Color
            xRet.set( new colorChoiceContext( *this, *mrTextCharacterProperties.getHighlightColor() ) );
            break;

        // EG_TextUnderlineLine
        case NMSP_DRAWINGML|XML_uLnTx:          // CT_TextUnderlineLineFollowText
             mrTextCharacterProperties.getUnderlineLineFollowText() <<= sal_True;
            break;
        case NMSP_DRAWINGML|XML_uLn:            // CT_LineProperties
// TODO unsupported yet
//          xRet.set( new LinePropertiesContext( getHandler(), xAttributes, maUnderlineProperties ) );
            break;

        // EG_TextUnderlineFill
        case NMSP_DRAWINGML|XML_uFillTx:        // CT_TextUnderlineFillFollowText
             mrTextCharacterProperties.getUnderlineFillFollowText() <<= sal_True;
            break;
        case NMSP_DRAWINGML|XML_uFill:          // CT_TextUnderlineFillGroupWrapper->EG_FillProperties (not supported)
            xRet.set( new colorChoiceContext( *this, *mrTextCharacterProperties.getUnderlineColor() ) );
            break;

        // CT_FontCollection
        case NMSP_DRAWINGML|XML_ea:             // CT_TextFont
            xRet.set( new TextFontContext( *this, aElementToken,  xAttributes, maAsianFont ) );
            break;
        case NMSP_DRAWINGML|XML_cs:             // CT_TextFont
            xRet.set( new TextFontContext( *this, aElementToken,  xAttributes, maComplexFont ) );
            break;
        case NMSP_DRAWINGML|XML_sym:            // CT_TextFont
            xRet.set( new TextFontContext( *this, aElementToken,  xAttributes, maSymbolFont ) );
            break;
        case NMSP_DRAWINGML|XML_latin:          // CT_TextFont
            xRet.set( new TextFontContext( *this, aElementToken,  xAttributes, maLatinFont ) );
            break;

        case NMSP_DRAWINGML|XML_hlinkClick:     // CT_Hyperlink
        case NMSP_DRAWINGML|XML_hlinkMouseOver: // CT_Hyperlink
            xRet.set( new HyperLinkContext( *this, xAttributes,  mrTextCharacterProperties.getHyperlinkPropertyMap() ) );
            break;
    }
    if ( !xRet.is() )
        xRet.set( this );
    return xRet;
}

// --------------------------------------------------------------------

} }

<|endoftext|>


<commit_before>#include "conferenceview.h"

#include "videowidget.h"
#include "ui_callingwidget.h"

#include <QLabel>
#include <QGridLayout>
#include <QDebug>

uint16_t ROWMAXLENGTH = 3;

ConferenceView::ConferenceView(QWidget *parent):
  parent_(parent),
  layout_(NULL),
  layoutWidget_(NULL),
  callingWidget_(NULL),
  row_(0),
  column_(0),
  activeCalls_(),
  deniedCalls_()
{}

void ConferenceView::init(QGridLayout* conferenceLayout, QWidget* layoutwidget,
                          Ui::CallerWidget* callingwidget, QWidget* holdingWidget)
{
  layout_ = conferenceLayout;
  layoutWidget_ = layoutwidget;
  callingWidget_ = callingwidget;
  holdingWidget_ = holdingWidget;
}

void ConferenceView::callingTo(QString callID, QString name)
{
  if(activeCalls_.find(callID) != activeCalls_.end())
  {
    qWarning() << "WARNING: Outgoing call already has an allocated view";
    return;
  }

  QLabel* label = new QLabel(parent_);
  label->setText("Calling...");

  QFont font = QFont("Times", 16);
  label->setFont(font);
  label->setAlignment(Qt::AlignHCenter);
  layout_->addWidget(label, row_, column_);

  activeCalls_[callID] = new CallInfo{WAITINGPEER, name, layout_->itemAtPosition(row_,column_),
                         row_, column_};

  nextSlot();
}

void ConferenceView::incomingCall(QString callID, QString name)
{
  Q_ASSERT(callingWidget_);
  if(callingWidget_ == NULL)
  {
    qWarning() << "WARNING: Calling widget is missing!!";
  }
  if(activeCalls_.find(callID) != activeCalls_.end())
  {
    qWarning() << "WARNING: Incoming call already has an allocated view";
    return;
  }

  // TODO display a incoming call widget instead of layout/stream?
  //QLabel* label = new QLabel(parent_);
  QLabel* label = new QLabel(NULL);
  label->setText("Incoming call from " + name);

  QFont font = QFont("Times", 16);
  label->setFont(font);
  label->setAlignment(Qt::AlignHCenter);
  layout_->addWidget(label, row_, column_);

  activeCalls_[callID] = new CallInfo{ASKINGUSER, name, layout_->itemAtPosition(row_,column_),
                          row_, column_};

  qDebug() << "Displaying pop-up for somebody calling";
  callingWidget_->CallerLabel->setText(name + " is calling..");
  holdingWidget_->show();

  askingQueue_.append(callID);
  nextSlot();
}

// if our call is accepted or we accepted their call
VideoWidget* ConferenceView::addVideoStream(QString callID)
{
  VideoWidget* view = new VideoWidget();
  if(activeCalls_.find(callID) == activeCalls_.end())
  {
    qWarning() << "WARNING: Adding a videostream without previous.";
    return NULL;
  }
  else if(activeCalls_[callID]->state != ASKINGUSER
          && activeCalls_[callID]->state != WAITINGPEER)
  {
    qWarning() << "WARNING: activating stream without previous state set";
    return NULL;
  }

  // add the widget in place of previous one
  activeCalls_[callID]->state = ACTIVE;

  // TODO delete previous widget now instead of with parent.
  // Now they accumulate in memory until call has ended
  delete activeCalls_[callID]->item->widget();
  layout_->removeItem(activeCalls_[callID]->item);
  layout_->addWidget(view, activeCalls_[callID]->row, activeCalls_[callID]->column);
  activeCalls_[callID]->item = layout_->itemAtPosition(activeCalls_[callID]->row,
                                                       activeCalls_[callID]->column);
  return view;
}

void ringing(QString callID)
{
  // get widget from layout and change the text.
}

void ConferenceView::removeCaller(QString callID)
{
  if(activeCalls_.find(callID) == activeCalls_.end() || activeCalls_[callID]->item == NULL )
  {
    qWarning() << "WARNING: Trying to remove nonexisting call from ConferenceView";
    return;
  }

  delete activeCalls_[callID]->item->widget();
  layout_->removeItem(activeCalls_[callID]->item);

  activeCalls_.erase(callID);
}

void ConferenceView::nextSlot()
{
  // TODO improve this algorithm for more optimized layout
  ++column_;
  if(column_ == ROWMAXLENGTH)
  {
    column_ = 0;
    ++row_;
  }
}

QString ConferenceView::acceptNewest()
{
  QString last = askingQueue_.last();
  askingQueue_.pop_back();
  if(askingQueue_.size() == 0)
  {
    holdingWidget_->hide();
  }

  return last;
}

QString ConferenceView::rejectNewest()
{
  QString last = askingQueue_.last();
  askingQueue_.pop_back();
  if(askingQueue_.size() == 0)
  {
    holdingWidget_->hide();
  }

  removeCaller(last);
  return last;
}

void ConferenceView::close()
{
  while(!activeCalls_.empty())
  {
    removeCaller((*activeCalls_.begin()).first);
  }
}
<commit_msg>Conference layout is fully cleared, when there are pending call while the call is ended.<commit_after>#include "conferenceview.h"

#include "videowidget.h"
#include "ui_callingwidget.h"

#include <QLabel>
#include <QGridLayout>
#include <QDebug>

uint16_t ROWMAXLENGTH = 3;

ConferenceView::ConferenceView(QWidget *parent):
  parent_(parent),
  layout_(NULL),
  layoutWidget_(NULL),
  callingWidget_(NULL),
  row_(0),
  column_(0),
  activeCalls_(),
  deniedCalls_()
{}

void ConferenceView::init(QGridLayout* conferenceLayout, QWidget* layoutwidget,
                          Ui::CallerWidget* callingwidget, QWidget* holdingWidget)
{
  layout_ = conferenceLayout;
  layoutWidget_ = layoutwidget;
  callingWidget_ = callingwidget;
  holdingWidget_ = holdingWidget;
}

void ConferenceView::callingTo(QString callID, QString name)
{
  if(activeCalls_.find(callID) != activeCalls_.end())
  {
    qWarning() << "WARNING: Outgoing call already has an allocated view";
    return;
  }

  QLabel* label = new QLabel(parent_);
  label->setText("Calling...");

  QFont font = QFont("Times", 16);
  label->setFont(font);
  label->setAlignment(Qt::AlignHCenter);
  layout_->addWidget(label, row_, column_);

  activeCalls_[callID] = new CallInfo{WAITINGPEER, name, layout_->itemAtPosition(row_,column_),
                         row_, column_};

  nextSlot();
}

void ConferenceView::incomingCall(QString callID, QString name)
{
  Q_ASSERT(callingWidget_);
  if(callingWidget_ == NULL)
  {
    qWarning() << "WARNING: Calling widget is missing!!";
  }
  if(activeCalls_.find(callID) != activeCalls_.end())
  {
    qWarning() << "WARNING: Incoming call already has an allocated view";
    return;
  }

  // TODO display a incoming call widget instead of layout/stream?
  //QLabel* label = new QLabel(parent_);
  QLabel* label = new QLabel(NULL);
  label->setText("Incoming call from " + name);

  QFont font = QFont("Times", 16);
  label->setFont(font);
  label->setAlignment(Qt::AlignHCenter);
  layout_->addWidget(label, row_, column_);

  activeCalls_[callID] = new CallInfo{ASKINGUSER, name, layout_->itemAtPosition(row_,column_),
                          row_, column_};

  qDebug() << "Displaying pop-up for somebody calling";
  callingWidget_->CallerLabel->setText(name + " is calling..");
  holdingWidget_->show();

  askingQueue_.append(callID);
  nextSlot();
}

// if our call is accepted or we accepted their call
VideoWidget* ConferenceView::addVideoStream(QString callID)
{
  VideoWidget* view = new VideoWidget();
  if(activeCalls_.find(callID) == activeCalls_.end())
  {
    qWarning() << "WARNING: Adding a videostream without previous.";
    return NULL;
  }
  else if(activeCalls_[callID]->state != ASKINGUSER
          && activeCalls_[callID]->state != WAITINGPEER)
  {
    qWarning() << "WARNING: activating stream without previous state set";
    return NULL;
  }

  // add the widget in place of previous one
  activeCalls_[callID]->state = ACTIVE;

  // TODO delete previous widget now instead of with parent.
  // Now they accumulate in memory until call has ended
  delete activeCalls_[callID]->item->widget();
  layout_->removeItem(activeCalls_[callID]->item);
  layout_->addWidget(view, activeCalls_[callID]->row, activeCalls_[callID]->column);
  activeCalls_[callID]->item = layout_->itemAtPosition(activeCalls_[callID]->row,
                                                       activeCalls_[callID]->column);
  return view;
}

void ringing(QString callID)
{
  // get widget from layout and change the text.
}

void ConferenceView::removeCaller(QString callID)
{
  if(activeCalls_.find(callID) == activeCalls_.end() || activeCalls_[callID]->item == NULL )
  {
    qWarning() << "WARNING: Trying to remove nonexisting call from ConferenceView";
    return;
  }

  delete activeCalls_[callID]->item->widget();
  layout_->removeItem(activeCalls_[callID]->item);

  activeCalls_.erase(callID);
}

void ConferenceView::nextSlot()
{
  // TODO improve this algorithm for more optimized layout
  ++column_;
  if(column_ == ROWMAXLENGTH)
  {
    column_ = 0;
    ++row_;
  }
}

QString ConferenceView::acceptNewest()
{
  QString last = askingQueue_.last();
  askingQueue_.pop_back();
  if(askingQueue_.size() == 0)
  {
    holdingWidget_->hide();
  }

  return last;
}

QString ConferenceView::rejectNewest()
{
  QString last = askingQueue_.last();
  askingQueue_.pop_back();
  if(askingQueue_.size() == 0)
  {
    holdingWidget_->hide();
  }

  removeCaller(last);
  return last;
}

void ConferenceView::close()
{
  while(!activeCalls_.empty())
  {
    removeCaller((*activeCalls_.begin()).first);
  }

  askingQueue_.clear();

  row_ = 0;
  column_ = 0;
}
<|endoftext|>


<commit_before>#include "conferenceview.h"

#include "videowidget.h"
#include "ui_callingwidget.h"

#include <QLabel>
#include <QGridLayout>
#include <QDebug>

uint16_t ROWMAXLENGTH = 3;

ConferenceView::ConferenceView(QWidget *parent):
  parent_(parent),
  layout_(NULL),
  layoutWidget_(NULL),
  callingWidget_(NULL),
  row_(0),
  column_(0),
  activeCalls_(),
  deniedCalls_()
{}

void ConferenceView::init(QGridLayout* conferenceLayout, QWidget* layoutwidget,
                          Ui::CallerWidget* callingwidget, QWidget* holdingWidget)
{
  layout_ = conferenceLayout;
  layoutWidget_ = layoutwidget;
  callingWidget_ = callingwidget;
}

void ConferenceView::callingTo(QString callID, QString name)
{
  if(activeCalls_.find(callID) != activeCalls_.end())
  {
    qWarning() << "WARNING: Outgoing call already has an allocated view";
    return;
  }

  QLabel* label = new QLabel(parent_);
  label->setText("Calling...");

  QFont font = QFont("Times", 16);
  label->setFont(font);
  label->setAlignment(Qt::AlignHCenter);
  layout_->addWidget(label, row_, column_);

  activeCalls_[callID] = new CallInfo{WAITINGPEER, name, layout_->itemAtPosition(row_,column_),
                         row_, column_};

  nextSlot();
}

void ConferenceView::incomingCall(QString callID, QString name)
{
  Q_ASSERT(callingWidget_);
  if(callingWidget_ == NULL)
  {
    qWarning() << "WARNING: Calling widget is missing!!";
  }
  if(activeCalls_.find(callID) != activeCalls_.end())
  {
    qWarning() << "WARNING: Incoming call already has an allocated view";
    return;
  }

  // TODO display a incoming call widget instead of layout/stream?
  QLabel* label = new QLabel(parent_);
  label->setText("Incoming call from " + name);

  QFont font = QFont("Times", 16);
  label->setFont(font);
  label->setAlignment(Qt::AlignHCenter);
  layout_->addWidget(label, row_, column_);

  activeCalls_[callID] = new CallInfo{ASKINGUSER, name, layout_->itemAtPosition(row_,column_),
                          row_, column_};

  qDebug() << "Displaying pop-up for somebody calling";
  callingWidget_->CallerLabel->setText(name + " is calling..");
  holdingWidget_->show();

  askingQueue_.append(callID);
  nextSlot();
}

// if our call is accepted or we accepted their call
VideoWidget* ConferenceView::addVideoStream(QString callID)
{
  VideoWidget* view = new VideoWidget;
  if(activeCalls_.find(callID) != activeCalls_.end())
  {
    qDebug() << "Adding a stream without previous. Must be ourselves";
    return view;
  }
  else if(activeCalls_[callID]->state != ASKINGUSER
          && activeCalls_[callID]->state != WAITINGPEER)
  {
    qWarning() << "WARNING: activating stream without previous state set";
    return NULL;
  }

  // add the widget in place of previous one
  activeCalls_[callID]->state = ACTIVE;

  // TODO delete previous widget now instead of with parent
  layout_->addWidget(view, row_, column_);
  activeCalls_[callID]->item = layout_->itemAtPosition(row_,column_);
  return view;
}

void ringing(QString callID)
{
  // get widget from layout and change the text.
}

void ConferenceView::removeCaller(QString callID)
{
  if(activeCalls_.find(callID) == activeCalls_.end() || activeCalls_[callID]->item == NULL )
  {
    qWarning() << "WARNING: Trying to remove nonexisting call from ConferenceView";
    return;
  }

  layout_->removeItem(activeCalls_[callID]->item);

  activeCalls_.erase(callID);
}

void ConferenceView::nextSlot()
{
  // TODO improve this algorithm for more optimized layout
  ++column_;
  if(column_ == ROWMAXLENGTH)
  {
    column_ = 0;
    ++row_;
  }
}

QString ConferenceView::acceptNewest()
{
  QString last = askingQueue_.last();
  askingQueue_.pop_back();
  return last;
}

QString ConferenceView::rejectNewest()
{
  QString last = askingQueue_.last();
  askingQueue_.pop_back();
  return last;
}

void ConferenceView::close()
{
  for(auto call : activeCalls_)
  {
    delete call.second;
  }
}
<commit_msg>Calling ourselves seems to be working now.<commit_after>#include "conferenceview.h"

#include "videowidget.h"
#include "ui_callingwidget.h"

#include <QLabel>
#include <QGridLayout>
#include <QDebug>

uint16_t ROWMAXLENGTH = 3;

ConferenceView::ConferenceView(QWidget *parent):
  parent_(parent),
  layout_(NULL),
  layoutWidget_(NULL),
  callingWidget_(NULL),
  row_(0),
  column_(0),
  activeCalls_(),
  deniedCalls_()
{}

void ConferenceView::init(QGridLayout* conferenceLayout, QWidget* layoutwidget,
                          Ui::CallerWidget* callingwidget, QWidget* holdingWidget)
{
  layout_ = conferenceLayout;
  layoutWidget_ = layoutwidget;
  callingWidget_ = callingwidget;
}

void ConferenceView::callingTo(QString callID, QString name)
{
  if(activeCalls_.find(callID) != activeCalls_.end())
  {
    qWarning() << "WARNING: Outgoing call already has an allocated view";
    return;
  }

  QLabel* label = new QLabel(parent_);
  label->setText("Calling...");

  QFont font = QFont("Times", 16);
  label->setFont(font);
  label->setAlignment(Qt::AlignHCenter);
  layout_->addWidget(label, row_, column_);

  activeCalls_[callID] = new CallInfo{WAITINGPEER, name, layout_->itemAtPosition(row_,column_),
                         row_, column_};

  nextSlot();
}

void ConferenceView::incomingCall(QString callID, QString name)
{
  Q_ASSERT(callingWidget_);
  if(callingWidget_ == NULL)
  {
    qWarning() << "WARNING: Calling widget is missing!!";
  }
  if(activeCalls_.find(callID) != activeCalls_.end())
  {
    qWarning() << "WARNING: Incoming call already has an allocated view";
    return;
  }

  // TODO display a incoming call widget instead of layout/stream?
  //QLabel* label = new QLabel(parent_);
  QLabel* label = new QLabel(NULL);
  label->setText("Incoming call from " + name);

  QFont font = QFont("Times", 16);
  label->setFont(font);
  label->setAlignment(Qt::AlignHCenter);
  layout_->addWidget(label, row_, column_);

  activeCalls_[callID] = new CallInfo{ASKINGUSER, name, layout_->itemAtPosition(row_,column_),
                          row_, column_};

  qDebug() << "Displaying pop-up for somebody calling";
  callingWidget_->CallerLabel->setText(name + " is calling..");
  holdingWidget_->show();

  askingQueue_.append(callID);
  nextSlot();
}

// if our call is accepted or we accepted their call
VideoWidget* ConferenceView::addVideoStream(QString callID)
{
  VideoWidget* view = new VideoWidget();
  if(activeCalls_.find(callID) == activeCalls_.end())
  {
    qWarning() << "WARNING: Adding a videostream without previous.";
    return NULL;
  }
  else if(activeCalls_[callID]->state != ASKINGUSER
          && activeCalls_[callID]->state != WAITINGPEER)
  {
    qWarning() << "WARNING: activating stream without previous state set";
    return NULL;
  }

  // add the widget in place of previous one
  activeCalls_[callID]->state = ACTIVE;

  // TODO delete previous widget now instead of with parent.
  // Now they accumulate in memory until call has ended
  delete activeCalls_[callID]->item->widget();
  layout_->removeItem(activeCalls_[callID]->item);
  layout_->addWidget(view, activeCalls_[callID]->row, activeCalls_[callID]->column);
  activeCalls_[callID]->item = layout_->itemAtPosition(activeCalls_[callID]->row,
                                                       activeCalls_[callID]->column);
  return view;
}

void ringing(QString callID)
{
  // get widget from layout and change the text.
}

void ConferenceView::removeCaller(QString callID)
{
  if(activeCalls_.find(callID) == activeCalls_.end() || activeCalls_[callID]->item == NULL )
  {
    qWarning() << "WARNING: Trying to remove nonexisting call from ConferenceView";
    return;
  }

  layout_->removeItem(activeCalls_[callID]->item);

  activeCalls_.erase(callID);
}

void ConferenceView::nextSlot()
{
  // TODO improve this algorithm for more optimized layout
  ++column_;
  if(column_ == ROWMAXLENGTH)
  {
    column_ = 0;
    ++row_;
  }
}

QString ConferenceView::acceptNewest()
{
  QString last = askingQueue_.last();
  askingQueue_.pop_back();
  return last;
}

QString ConferenceView::rejectNewest()
{
  QString last = askingQueue_.last();
  askingQueue_.pop_back();
  return last;
}

void ConferenceView::close()
{
  for(auto call : activeCalls_)
  {
    delete call.second;
  }
}
<|endoftext|>


<commit_before>/*
 * opencog/atoms/base/Handle.cc
 *
 * Copyright (C) 2002-2007 Novamente LLC
 * Copyright (C) 2013 Linas Vepstas <linas@linas.org>
 * All Rights Reserved
 *
 * Written by Thiago Maia <thiago@vettatech.com>
 *            Andre Senna <senna@vettalabs.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <climits>
#include <opencog/atoms/base/Handle.h>
#include <opencog/atoms/base/Atom.h>
#include <opencog/atomspace/AtomTable.h>

namespace opencog {

const Handle Handle::UNDEFINED;
const AtomPtr Handle::NULL_POINTER;

Handle::Handle(const UUID u)
{
	_ptr = do_res(u)._ptr;
}

UUID Handle::value(void) const
{
    const Atom* a = operator->();
    if (a) return a->getUUID();
    return ULONG_MAX;
}

// ===================================================
// Atom comparison.

#if 0
bool Handle::atoms_eq(const AtomPtr& a, const AtomPtr& b)
{
    if (a == b) return true;
    if (NULL == a or NULL == b) return false;
    return *a == *b;
}
#endif

bool Handle::atoms_less(const Atom* pa, const Atom* pb)
{
    if (pa == pb) return false;
    if (NULL == pa) return true;
    if (NULL == pb) return false;

    const Atom* a(dynamic_cast<const Atom*>(pa));
    const Atom* b(dynamic_cast<const Atom*>(pb));
    UUID ua = a->getUUID();
    UUID ub = b->getUUID();
    if (INVALID_UUID != ua or INVALID_UUID != ub) return ua < ub;

    // If both UUID's are invalid, we still need to compare
    // the atoms somehow. The need to compare in some "reasonable"
    // way, so that OrderedHandleSet works correctly when it uses
    // the std::less<Handle> operator, which calls this function.
    // Performing an address-space comparison is all I can think
    // of...
    // if (*a == *b) return false; lets not do this cpu-time-waster...
    return a < b;
}

bool Handle::content_based_atoms_less(const Atom* a, const Atom* b)
{
    if (a == b) return false;
    if (nullptr == a) return true;
    if (nullptr == b) return false;

    // Otherwise we compare them by content. This is expensive but
    // useful when you really want a deterministic comparison.
    return a->operator<(*b);
}

// ===================================================
// Handle resolution stuff.

// Its a vector, not a set, because its priority ranked.
std::vector<const AtomTable*> Handle::_resolver;

void Handle::set_resolver(const AtomTable* tab)
{
    _resolver.push_back(tab);
}

void Handle::clear_resolver(const AtomTable* tab)
{
    auto it = std::find(_resolver.begin(), _resolver.end(), tab);
    if (it != _resolver.end())
        _resolver.erase(it);
}

// Search several atomspaces, in order.  First one to come up with
// the atom wins.  Seems to work, for now.
inline Handle Handle::do_res(UUID uuid)
{
    for (const AtomTable* at : _resolver) {
        Handle h(at->getHandle(uuid));
        if (NULL != h) return h;
    }
    return Handle();
}

std::string h_to_string(const Handle& h)
{
	if ((AtomPtr)h == nullptr)
		return "nullatom\n";
	else
		return h->toString();
}
std::string hs_to_string(const HandleSeq& hs)
{
	std::stringstream ss; std::operator<<(ss, hs); return ss.str();
}
std::string ohs_to_string(const OrderedHandleSet& ohs)
{
	std::stringstream ss; std::operator<<(ss, ohs) << ohs; return ss.str();
}
std::string uhs_to_string(const UnorderedHandleSet& uhs)
{
	std::stringstream ss; std::operator<<(ss, uhs); return ss.str();
}
std::string hmap_to_string(const HandleMap& hmap)
{
	std::stringstream ss;
	ss << "size = " << hmap.size() << std::endl;
	int i = 0;
	for (const auto& p : hmap) {
		ss << "key[" << i << "]:" << std::endl << h_to_string(p.first)
		   << "value[" << i << "]:" << std::endl << h_to_string(p.second);
		i++;
	}
	return ss.str();
}
std::string hmultimap_to_string(const HandleMultimap& hmultimap)
{
	std::stringstream ss;
	ss << "size = " << hmultimap.size() << std::endl;
	int i = 0;
	for (const auto& p : hmultimap) {
		ss << "key[" << i << "]:" << std::endl << h_to_string(p.first)
		   << "value[" << i << "]:" << std::endl;
		for (const auto s : p.second)
			ss << h_to_string(s);
		i++;
	}
	return ss.str();
}
std::string hmaps_to_string(const HandleMapSeq& hms)
{
	std::stringstream ss;
	ss << "size = " << hms.size() << std::endl;
	for (unsigned i = 0; i < hms.size(); i++)
		ss << "--- map[" << i << "] ---" << std::endl
		   << hmap_to_string(hms[i]);
	return ss.str();
}
std::string atomtype_to_string(Type type)
{
	std::stringstream ss;
	ss << classserver().getTypeName(type) << std::endl;
	return ss.str();
}

std::string oc_to_string(const Handle& h)
{
	return h_to_string(h);
}
std::string oc_to_string(const HandleSeq& hs)
{
	return hs_to_string(hs);
}
std::string oc_to_string(const OrderedHandleSet& ohs)
{
	return ohs_to_string(ohs);
}
std::string oc_to_string(const UnorderedHandleSet& uhs)
{
	return uhs_to_string(uhs);
}
std::string oc_to_string(const HandleMap& hm)
{
	return hmap_to_string(hm);
}
std::string oc_to_string(const HandleMultimap& hmm)
{
	return hmultimap_to_string(hmm);
}
std::string oc_to_string(const HandleMapSeq& hms)
{
	return hmaps_to_string(hms);
}
std::string oc_to_string(Type type)
{
	return atomtype_to_string(type);
}

} // ~namespace opencog

namespace std {

// Hack around the lack template use in Handle.h due to circular dependencies
#define GEN_HANDLE_CONTAINER_OSTREAM_OPERATOR(T) \
ostream& operator<<(ostream& out, const T& hs) { \
	out << "size = " << hs.size() << endl; \
	size_t i = 0; \
	for (const opencog::Handle& h : hs) { \
		out << "atom[" << i << "]:" << endl << h_to_string(h); \
		i++; \
	} \
	return out; \
}
GEN_HANDLE_CONTAINER_OSTREAM_OPERATOR(opencog::HandleSeq)
GEN_HANDLE_CONTAINER_OSTREAM_OPERATOR(opencog::OrderedHandleSet)
GEN_HANDLE_CONTAINER_OSTREAM_OPERATOR(opencog::UnorderedHandleSet)

} // ~namespace std
<commit_msg>Bug fix<commit_after>/*
 * opencog/atoms/base/Handle.cc
 *
 * Copyright (C) 2002-2007 Novamente LLC
 * Copyright (C) 2013 Linas Vepstas <linas@linas.org>
 * All Rights Reserved
 *
 * Written by Thiago Maia <thiago@vettatech.com>
 *            Andre Senna <senna@vettalabs.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <climits>
#include <opencog/atoms/base/Handle.h>
#include <opencog/atoms/base/Atom.h>
#include <opencog/atomspace/AtomTable.h>

namespace opencog {

const Handle Handle::UNDEFINED;
const AtomPtr Handle::NULL_POINTER;

Handle::Handle(const UUID u)
{
	_ptr = do_res(u)._ptr;
}

UUID Handle::value(void) const
{
    const Atom* a = operator->();
    // The is link/node is a low-cost way of checking if the
    // pointer really is an atom pointer, and not just protoAtom,
    // which does not have a uuid.
    if (a and (a->isLink() or a->isNode())) return a->getUUID();
    return ULONG_MAX;
}

// ===================================================
// Atom comparison.

#if 0
bool Handle::atoms_eq(const AtomPtr& a, const AtomPtr& b)
{
    if (a == b) return true;
    if (NULL == a or NULL == b) return false;
    return *a == *b;
}
#endif

bool Handle::atoms_less(const Atom* pa, const Atom* pb)
{
    if (pa == pb) return false;
    if (NULL == pa) return true;
    if (NULL == pb) return false;

    const Atom* a(dynamic_cast<const Atom*>(pa));
    const Atom* b(dynamic_cast<const Atom*>(pb));
    UUID ua = a->getUUID();
    UUID ub = b->getUUID();
    if (INVALID_UUID != ua or INVALID_UUID != ub) return ua < ub;

    // If both UUID's are invalid, we still need to compare
    // the atoms somehow. The need to compare in some "reasonable"
    // way, so that OrderedHandleSet works correctly when it uses
    // the std::less<Handle> operator, which calls this function.
    // Performing an address-space comparison is all I can think
    // of...
    // if (*a == *b) return false; lets not do this cpu-time-waster...
    return a < b;
}

bool Handle::content_based_atoms_less(const Atom* a, const Atom* b)
{
    if (a == b) return false;
    if (nullptr == a) return true;
    if (nullptr == b) return false;

    // Otherwise we compare them by content. This is expensive but
    // useful when you really want a deterministic comparison.
    return a->operator<(*b);
}

// ===================================================
// Handle resolution stuff.

// Its a vector, not a set, because its priority ranked.
std::vector<const AtomTable*> Handle::_resolver;

void Handle::set_resolver(const AtomTable* tab)
{
    _resolver.push_back(tab);
}

void Handle::clear_resolver(const AtomTable* tab)
{
    auto it = std::find(_resolver.begin(), _resolver.end(), tab);
    if (it != _resolver.end())
        _resolver.erase(it);
}

// Search several atomspaces, in order.  First one to come up with
// the atom wins.  Seems to work, for now.
inline Handle Handle::do_res(UUID uuid)
{
    for (const AtomTable* at : _resolver) {
        Handle h(at->getHandle(uuid));
        if (NULL != h) return h;
    }
    return Handle();
}

std::string h_to_string(const Handle& h)
{
	if ((AtomPtr)h == nullptr)
		return "nullatom\n";
	else
		return h->toString();
}
std::string hs_to_string(const HandleSeq& hs)
{
	std::stringstream ss; std::operator<<(ss, hs); return ss.str();
}
std::string ohs_to_string(const OrderedHandleSet& ohs)
{
	std::stringstream ss; std::operator<<(ss, ohs) << ohs; return ss.str();
}
std::string uhs_to_string(const UnorderedHandleSet& uhs)
{
	std::stringstream ss; std::operator<<(ss, uhs); return ss.str();
}
std::string hmap_to_string(const HandleMap& hmap)
{
	std::stringstream ss;
	ss << "size = " << hmap.size() << std::endl;
	int i = 0;
	for (const auto& p : hmap) {
		ss << "key[" << i << "]:" << std::endl << h_to_string(p.first)
		   << "value[" << i << "]:" << std::endl << h_to_string(p.second);
		i++;
	}
	return ss.str();
}
std::string hmultimap_to_string(const HandleMultimap& hmultimap)
{
	std::stringstream ss;
	ss << "size = " << hmultimap.size() << std::endl;
	int i = 0;
	for (const auto& p : hmultimap) {
		ss << "key[" << i << "]:" << std::endl << h_to_string(p.first)
		   << "value[" << i << "]:" << std::endl;
		for (const auto s : p.second)
			ss << h_to_string(s);
		i++;
	}
	return ss.str();
}
std::string hmaps_to_string(const HandleMapSeq& hms)
{
	std::stringstream ss;
	ss << "size = " << hms.size() << std::endl;
	for (unsigned i = 0; i < hms.size(); i++)
		ss << "--- map[" << i << "] ---" << std::endl
		   << hmap_to_string(hms[i]);
	return ss.str();
}
std::string atomtype_to_string(Type type)
{
	std::stringstream ss;
	ss << classserver().getTypeName(type) << std::endl;
	return ss.str();
}

std::string oc_to_string(const Handle& h)
{
	return h_to_string(h);
}
std::string oc_to_string(const HandleSeq& hs)
{
	return hs_to_string(hs);
}
std::string oc_to_string(const OrderedHandleSet& ohs)
{
	return ohs_to_string(ohs);
}
std::string oc_to_string(const UnorderedHandleSet& uhs)
{
	return uhs_to_string(uhs);
}
std::string oc_to_string(const HandleMap& hm)
{
	return hmap_to_string(hm);
}
std::string oc_to_string(const HandleMultimap& hmm)
{
	return hmultimap_to_string(hmm);
}
std::string oc_to_string(const HandleMapSeq& hms)
{
	return hmaps_to_string(hms);
}
std::string oc_to_string(Type type)
{
	return atomtype_to_string(type);
}

} // ~namespace opencog

namespace std {

// Hack around the lack template use in Handle.h due to circular dependencies
#define GEN_HANDLE_CONTAINER_OSTREAM_OPERATOR(T) \
ostream& operator<<(ostream& out, const T& hs) { \
	out << "size = " << hs.size() << endl; \
	size_t i = 0; \
	for (const opencog::Handle& h : hs) { \
		out << "atom[" << i << "]:" << endl << h_to_string(h); \
		i++; \
	} \
	return out; \
}
GEN_HANDLE_CONTAINER_OSTREAM_OPERATOR(opencog::HandleSeq)
GEN_HANDLE_CONTAINER_OSTREAM_OPERATOR(opencog::OrderedHandleSet)
GEN_HANDLE_CONTAINER_OSTREAM_OPERATOR(opencog::UnorderedHandleSet)

} // ~namespace std
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: processw.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 21:19:11 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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.
 *
 *    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; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _PROCESSW_HXX
#define _PROCESSW_HXX

#ifndef __SBX_SBX_FACTORY_HXX //autogen
#include <sbxfac.hxx>
#endif
#ifndef __SBX_SBXVARIABLE_HXX //autogen
#include <sbxvar.hxx>
#endif
#ifndef _SBX_SBXOBJECT_HXX //autogen
#include <sbxobj.hxx>
#endif
#include "process.hxx"

class ProcessWrapper : public SbxObject
{
    // Definition eines Tabelleneintrags. Dies wird hier gemacht,
    // da dadurch die Methoden und Properties als private deklariert
    // werden koennen.
#if defined ( ICC ) || defined ( HPUX ) || defined ( C50 ) || defined ( C52 )
public:
#endif
    typedef void( ProcessWrapper::*pMeth )
        ( SbxVariable* pThis, SbxArray* pArgs, BOOL bWrite );
#if defined ( ICC ) || defined ( HPUX )
private:
#endif

    struct Methods {
        const char* pName;      // Name des Eintrags
        SbxDataType eType;      // Datentyp
        short nArgs;            // Argumente und Flags
        pMeth pFunc;            // Function Pointer
    };
    static Methods aProcessMethods[];   // Methodentabelle
    Methods *pMethods;  // Aktuelle Methodentabelle

    // Methoden
    void PSetImage( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void PStart( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void PGetExitCode( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void PIsRunning( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void PWasGPF( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );

    // Interne Member und Methoden
    Process *pProcess;

    // Infoblock auffuellen
    SbxInfo* GetInfo( short nIdx );

    // Broadcaster Notification
    virtual void SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType,
                             const SfxHint& rHint, const TypeId& rHintType );
public:
    ProcessWrapper();
    ~ProcessWrapper();
    // Suchen eines Elements
    virtual SbxVariable* Find( const String&, SbxClassType );
};

// Die dazugehoerige Factory:

class ProcessFactory : public SbxFactory
{
public:
    virtual SbxObject* CreateObject( const String& );
};

#endif
<commit_msg>INTEGRATION: CWS warnings01 (1.4.28); FILE MERGED 2005/11/18 14:29:39 gh 1.4.28.1: solaris warnings (some more)<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: processw.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 17:37:40 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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.
 *
 *    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; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _PROCESSW_HXX
#define _PROCESSW_HXX

#ifndef __SBX_SBX_FACTORY_HXX //autogen
#include <sbxfac.hxx>
#endif
#ifndef __SBX_SBXVARIABLE_HXX //autogen
#include <sbxvar.hxx>
#endif
#ifndef _SBX_SBXOBJECT_HXX //autogen
#include <sbxobj.hxx>
#endif
#include "process.hxx"

class ProcessWrapper : public SbxObject
{
using SbxVariable::GetInfo;
    // Definition eines Tabelleneintrags. Dies wird hier gemacht,
    // da dadurch die Methoden und Properties als private deklariert
    // werden koennen.
#if defined ( ICC ) || defined ( HPUX ) || defined ( C50 ) || defined ( C52 )
public:
#endif
    typedef void( ProcessWrapper::*pMeth )
        ( SbxVariable* pThis, SbxArray* pArgs, BOOL bWrite );
#if defined ( ICC ) || defined ( HPUX )
private:
#endif

    struct Methods {
        const char* pName;      // Name des Eintrags
        SbxDataType eType;      // Datentyp
        short nArgs;            // Argumente und Flags
        pMeth pFunc;            // Function Pointer
    };
    static Methods aProcessMethods[];   // Methodentabelle
    Methods *pMethods;  // Aktuelle Methodentabelle

    // Methoden
    void PSetImage( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void PStart( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void PGetExitCode( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void PIsRunning( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void PWasGPF( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );

    // Interne Member und Methoden
    Process *pProcess;

    // Infoblock auffuellen
    SbxInfo* GetInfo( short nIdx );

    // Broadcaster Notification
    virtual void SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType,
                             const SfxHint& rHint, const TypeId& rHintType );
public:
    ProcessWrapper();
    ~ProcessWrapper();
    // Suchen eines Elements
    virtual SbxVariable* Find( const String&, SbxClassType );
};

// Die dazugehoerige Factory:

class ProcessFactory : public SbxFactory
{
public:
    virtual SbxObject* CreateObject( const String& );
};

#endif
<|endoftext|>


<commit_before>/**
 * @file
 * @brief Implementation of logger
 *
 * @copyright MIT License
 */

#include "log.h"

#include <algorithm>
#include <array>
#include <chrono>
#include <exception>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <string>
#include <unistd.h>

using namespace allpix;

// Last name used while printing (for identifying process logs)
std::string DefaultLogger::last_identifier_;
// Last message send used to check if extra spaces are needed
std::string DefaultLogger::last_message_;

/**
 * The logger will save the number of uncaught exceptions during construction to compare that with the number of exceptions
 * during destruction later.
 */
DefaultLogger::DefaultLogger() : exception_count_(get_uncaught_exceptions(true)) {}

/**
 * The output is written to the streams as soon as the logger gets out-of-scope and desctructed. The destructor checks
 * specifically if an exception is thrown while output is written to the stream. In that case the log stream will not be
 * forwarded to the output streams and the message will be discarded.
 */
DefaultLogger::~DefaultLogger() {
    // Check if an exception is thrown while adding output to the stream
    if(exception_count_ != get_uncaught_exceptions(false)) {
        return;
    }

    // TODO [doc] any extra exceptions here need to be catched

    // Get output string
    std::string out(os.str());

    // Replace every newline by indented code if necessary
    auto start_pos = out.find('\n');
    if(start_pos != std::string::npos) {
        std::string spcs(indent_count_ + 1, ' ');
        spcs[0] = '\n';
        do {
            out.replace(start_pos, 1, spcs);
            start_pos += spcs.length();
        } while((start_pos = out.find('\n', start_pos)) != std::string::npos);
    }

    // Add extra spaces if necessary
    size_t extra_spaces = 0;
    if(!identifier_.empty() && last_identifier_ == identifier_) {
        // Put carriage return for process logs
        out = '\r' + out;

        // Set extra spaces to fully cover previous message
        if(last_message_.size() > out.size()) {
            extra_spaces = last_message_.size() - out.size();
        }
    } else if(!last_identifier_.empty()) {
        // End process log and continue normal logging
        out = '\n' + out;
    }
    last_identifier_ = identifier_;

    // Save last message
    last_message_ = out;

    // Add extra spaces if required
    if(extra_spaces > 0) {
        out += std::string(extra_spaces, ' ');
    }

    // Add final newline if not a progress log
    if(identifier_.empty()) {
        out += '\n';
    }

    // Create a version without any special terminal characters
    std::string out_no_special;
    size_t prev = 0, pos = 0;
    while((pos = out.find("\x1B[", prev)) != std::string::npos) {
        out_no_special += out.substr(prev, pos - prev);
        prev = out.find("m", pos) + 1;
        if(prev == std::string::npos)
            break;
    }
    out_no_special += out.substr(prev);

    // Print output to streams
    for(auto stream : get_streams()) {
        if(is_terminal(*stream)) {
            (*stream) << out;
        } else {
            (*stream) << out_no_special;
        }
        (*stream).flush();
    }
}

/**
 * @warning No other log message should be send after this method
 * @note Does not close the streams
 */
void DefaultLogger::finish() {
    if(!last_identifier_.empty()) {
        // Flush final line if necessary
        for(auto stream : get_streams()) {
            (*stream) << std::endl;
            (*stream).flush();
        }
    }

    last_identifier_ = "";
    last_message_ = "";

    // Enable cursor again if stream supports it
    for(auto stream : get_streams()) {
        if(is_terminal(*stream)) {
            (*stream) << "\x1B[?25h";
        }
    }
}

/**
 * This method is typically automatically called by the \ref LOG macro to return a stream after constructing the logger. The
 * header of the stream is added before returning the output stream.
 */
std::ostringstream&
DefaultLogger::getStream(LogLevel level, const std::string& file, const std::string& function, uint32_t line) {
    // Add date in all except short format
    if(get_format() != LogFormat::SHORT) {
        os << "\x1B[1m"; // BOLD
        os << "|" << get_current_date() << "| ";
        os << "\x1B[0m"; // RESET
    }

    // Set color for log level
    if(level == LogLevel::FATAL || level == LogLevel::ERROR) {
        os << "\x1B[31;1m"; // RED
    } else if(level == LogLevel::WARNING) {
        os << "\x1B[33;1m"; // YELLOW
    } else if(level == LogLevel::TRACE || level == LogLevel::DEBUG) {
        os << "\x1B[36m"; // NON-BOLD CYAN
    } else {
        os << "\x1B[36;1m"; // CYAN
    }

    // Add log level (shortly in the short format)
    if(get_format() != LogFormat::SHORT) {
        std::string level_str = "(";
        level_str += getStringFromLevel(level);
        level_str += ")";
        os << std::setw(9) << level_str << " ";
    } else {
        os << "(" << getStringFromLevel(level).substr(0, 1) << ") ";
    }
    os << "\x1B[0m"; // RESET

    // Add section if available
    if(!get_section().empty()) {
        os << "\x1B[1m"; // BOLD
        os << "[" << get_section() << "] ";
        os << "\x1B[0m"; // RESET
    }

    // Print function name and line number information in debug format
    if(get_format() == LogFormat::LONG) {
        os << "\x1B[1m"; // BOLD
        os << "<" << file << "/" << function << ":L" << line << "> ";
        os << "\x1B[0m"; // RESET
    }

    // Save the indent count to fix with newlines
    indent_count_ = static_cast<unsigned int>(os.str().size());
    return os;
}

/**
 * @throws std::invalid_argument If an empty identifier is provided
 *
 * This method is typically automatically called by the \ref LOG_PROCESS macro.
 */
std::ostringstream& DefaultLogger::getProcessStream(
    const std::string& identifier, LogLevel level, const std::string& file, const std::string& function, uint32_t line) {
    // Get the standard process stream
    std::ostringstream& stream = getStream(level, file, function, line);

    // Save the identifier to indicate a progress log
    if(identifier.empty()) {
        throw std::invalid_argument("the process log identifier cannot be empty");
    }
    identifier_ = identifier;

    return stream;
}

// Getter and setters for the reporting level
LogLevel& DefaultLogger::get_reporting_level() {
    static LogLevel reporting_level = LogLevel::INFO;
    return reporting_level;
}
void DefaultLogger::setReportingLevel(LogLevel level) {
    get_reporting_level() = level;
}
LogLevel DefaultLogger::getReportingLevel() {
    return get_reporting_level();
}

// String to LogLevel conversions and vice versa
std::string DefaultLogger::getStringFromLevel(LogLevel level) {
    static const std::array<std::string, 7> type = {{"FATAL", "QUIET", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE"}};
    return type.at(static_cast<decltype(type)::size_type>(level));
}
/**
 * @throws std::invalid_argument If the string does not correspond with an existing log level
 */
LogLevel DefaultLogger::getLevelFromString(const std::string& level) {
    if(level == "TRACE") {
        return LogLevel::TRACE;
    }
    if(level == "DEBUG") {
        return LogLevel::DEBUG;
    }
    if(level == "INFO") {
        return LogLevel::INFO;
    }
    if(level == "WARNING") {
        return LogLevel::WARNING;
    }
    if(level == "ERROR") {
        return LogLevel::ERROR;
    }
    if(level == "QUIET") {
        return LogLevel::QUIET;
    }
    if(level == "FATAL") {
        return LogLevel::FATAL;
    }

    throw std::invalid_argument("unknown log level");
}

// Getter and setters for the format
LogFormat& DefaultLogger::get_format() {
    static LogFormat reporting_level = LogFormat::DEFAULT;
    return reporting_level;
}
void DefaultLogger::setFormat(LogFormat level) {
    get_format() = level;
}
LogFormat DefaultLogger::getFormat() {
    return get_format();
}

// Convert string to log format and vice versa
std::string DefaultLogger::getStringFromFormat(LogFormat format) {
    static const std::array<std::string, 3> type = {{"SHORT", "DEFAULT", "LONG"}};
    return type.at(static_cast<decltype(type)::size_type>(format));
}
/**
 * @throws std::invalid_argument If the string does not correspond with an existing log format
 */
LogFormat DefaultLogger::getFormatFromString(const std::string& format) {
    if(format == "SHORT") {
        return LogFormat::SHORT;
    }
    if(format == "DEFAULT") {
        return LogFormat::DEFAULT;
    }
    if(format == "LONG") {
        return LogFormat::LONG;
    }

    throw std::invalid_argument("unknown log format");
}

/**
 * The streams are shared by all logger instantiations.
 */
const std::vector<std::ostream*>& DefaultLogger::getStreams() {
    return get_streams();
}
std::vector<std::ostream*>& DefaultLogger::get_streams() {
    static std::vector<std::ostream*> streams;
    return streams;
}
void DefaultLogger::clearStreams() {
    get_streams().clear();
}
/**
 * The caller has to make sure that the added ostream exists for as long log messages may be written. The std::cout stream is
 * added automatically to the list of streams and does not need to be added itself.
 *
 * @note Streams cannot be individually removed at the moment and only all at once using \ref clearStreams().
 */
void DefaultLogger::addStream(std::ostream& stream) {
    // Disable cursor if stream supports it
    if(is_terminal(stream)) {
        stream << "\x1B[?25l";
    }

    get_streams().push_back(&stream);
}

// Getters and setters for the section header
std::string& DefaultLogger::get_section() {
    static std::string section;
    return section;
}
void DefaultLogger::setSection(std::string section) {
    get_section() = std::move(section);
}
std::string DefaultLogger::getSection() {
    return get_section();
}

/**
 * The date is returned in the hh:mm:ss.ms format
 */
std::string DefaultLogger::get_current_date() {
    // FIXME: revise this to get microseconds in a better way
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);

    std::stringstream ss;
    ss << std::put_time(std::localtime(&in_time_t), "%X");

    auto seconds_from_epoch = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
    auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch() - seconds_from_epoch).count();
    ss << ".";
    ss << std::setfill('0') << std::setw(3);
    ss << millis;
    return ss.str();
}

/*
 * It is impossible to know for sure a terminal has support for all extra terminal features, but every modern terminal has
 * this so we just assume it.
 */
bool DefaultLogger::is_terminal(std::ostream& stream) {
    if(&std::cout == &stream) {
        return isatty(fileno(stdout));
    } else if(&std::cerr == &stream) {
        return isatty(fileno(stderr));
    }

    return false;
}

/**
 * The number of uncaught exceptions can only be properly determined in C++17. In earlier versions it is only possible to
 * check if there is at least a single exception thrown and that function is used instead. This means a return value of zero
 * corresponds to no exception and one to at least one exception.
 */
int DefaultLogger::get_uncaught_exceptions(bool cons = false) {
#if __cplusplus > 201402L
    // we can only do this fully correctly in C++17
    return std::uncaught_exceptions();
#else
    if(cons) {
        return 0;
    }
    return static_cast<int>(std::uncaught_exception());
#endif
}
<commit_msg>add extra space to clear<commit_after>/**
 * @file
 * @brief Implementation of logger
 *
 * @copyright MIT License
 */

#include "log.h"

#include <algorithm>
#include <array>
#include <chrono>
#include <exception>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <string>
#include <unistd.h>

using namespace allpix;

// Last name used while printing (for identifying process logs)
std::string DefaultLogger::last_identifier_;
// Last message send used to check if extra spaces are needed
std::string DefaultLogger::last_message_;

/**
 * The logger will save the number of uncaught exceptions during construction to compare that with the number of exceptions
 * during destruction later.
 */
DefaultLogger::DefaultLogger() : exception_count_(get_uncaught_exceptions(true)) {}

/**
 * The output is written to the streams as soon as the logger gets out-of-scope and desctructed. The destructor checks
 * specifically if an exception is thrown while output is written to the stream. In that case the log stream will not be
 * forwarded to the output streams and the message will be discarded.
 */
DefaultLogger::~DefaultLogger() {
    // Check if an exception is thrown while adding output to the stream
    if(exception_count_ != get_uncaught_exceptions(false)) {
        return;
    }

    // TODO [doc] any extra exceptions here need to be catched

    // Get output string
    std::string out(os.str());

    // Replace every newline by indented code if necessary
    auto start_pos = out.find('\n');
    if(start_pos != std::string::npos) {
        std::string spcs(indent_count_ + 1, ' ');
        spcs[0] = '\n';
        do {
            out.replace(start_pos, 1, spcs);
            start_pos += spcs.length();
        } while((start_pos = out.find('\n', start_pos)) != std::string::npos);
    }

    // Add extra spaces if necessary
    size_t extra_spaces = 0;
    if(!identifier_.empty() && last_identifier_ == identifier_) {
        // Put carriage return for process logs
        out = '\r' + out;

        // Set extra spaces to fully cover previous message
        if(last_message_.size() > out.size()) {
            extra_spaces = last_message_.size() - out.size();
        }
    } else if(!last_identifier_.empty()) {
        // End process log and continue normal logging
        out = '\n' + out;
    }
    last_identifier_ = identifier_;

    // Save last message
    last_message_ = out;
    last_message_ += " ";

    // Add extra spaces if required
    if(extra_spaces > 0) {
        out += std::string(extra_spaces, ' ');
    }

    // Add final newline if not a progress log
    if(identifier_.empty()) {
        out += '\n';
    }

    // Create a version without any special terminal characters
    std::string out_no_special;
    size_t prev = 0, pos = 0;
    while((pos = out.find("\x1B[", prev)) != std::string::npos) {
        out_no_special += out.substr(prev, pos - prev);
        prev = out.find("m", pos) + 1;
        if(prev == std::string::npos)
            break;
    }
    out_no_special += out.substr(prev);

    // Print output to streams
    for(auto stream : get_streams()) {
        if(is_terminal(*stream)) {
            (*stream) << out;
        } else {
            (*stream) << out_no_special;
        }
        (*stream).flush();
    }
}

/**
 * @warning No other log message should be send after this method
 * @note Does not close the streams
 */
void DefaultLogger::finish() {
    if(!last_identifier_.empty()) {
        // Flush final line if necessary
        for(auto stream : get_streams()) {
            (*stream) << std::endl;
            (*stream).flush();
        }
    }

    last_identifier_ = "";
    last_message_ = "";

    // Enable cursor again if stream supports it
    for(auto stream : get_streams()) {
        if(is_terminal(*stream)) {
            (*stream) << "\x1B[?25h";
        }
    }
}

/**
 * This method is typically automatically called by the \ref LOG macro to return a stream after constructing the logger. The
 * header of the stream is added before returning the output stream.
 */
std::ostringstream&
DefaultLogger::getStream(LogLevel level, const std::string& file, const std::string& function, uint32_t line) {
    // Add date in all except short format
    if(get_format() != LogFormat::SHORT) {
        os << "\x1B[1m"; // BOLD
        os << "|" << get_current_date() << "| ";
        os << "\x1B[0m"; // RESET
    }

    // Set color for log level
    if(level == LogLevel::FATAL || level == LogLevel::ERROR) {
        os << "\x1B[31;1m"; // RED
    } else if(level == LogLevel::WARNING) {
        os << "\x1B[33;1m"; // YELLOW
    } else if(level == LogLevel::TRACE || level == LogLevel::DEBUG) {
        os << "\x1B[36m"; // NON-BOLD CYAN
    } else {
        os << "\x1B[36;1m"; // CYAN
    }

    // Add log level (shortly in the short format)
    if(get_format() != LogFormat::SHORT) {
        std::string level_str = "(";
        level_str += getStringFromLevel(level);
        level_str += ")";
        os << std::setw(9) << level_str << " ";
    } else {
        os << "(" << getStringFromLevel(level).substr(0, 1) << ") ";
    }
    os << "\x1B[0m"; // RESET

    // Add section if available
    if(!get_section().empty()) {
        os << "\x1B[1m"; // BOLD
        os << "[" << get_section() << "] ";
        os << "\x1B[0m"; // RESET
    }

    // Print function name and line number information in debug format
    if(get_format() == LogFormat::LONG) {
        os << "\x1B[1m"; // BOLD
        os << "<" << file << "/" << function << ":L" << line << "> ";
        os << "\x1B[0m"; // RESET
    }

    // Save the indent count to fix with newlines
    indent_count_ = static_cast<unsigned int>(os.str().size());
    return os;
}

/**
 * @throws std::invalid_argument If an empty identifier is provided
 *
 * This method is typically automatically called by the \ref LOG_PROCESS macro.
 */
std::ostringstream& DefaultLogger::getProcessStream(
    const std::string& identifier, LogLevel level, const std::string& file, const std::string& function, uint32_t line) {
    // Get the standard process stream
    std::ostringstream& stream = getStream(level, file, function, line);

    // Save the identifier to indicate a progress log
    if(identifier.empty()) {
        throw std::invalid_argument("the process log identifier cannot be empty");
    }
    identifier_ = identifier;

    return stream;
}

// Getter and setters for the reporting level
LogLevel& DefaultLogger::get_reporting_level() {
    static LogLevel reporting_level = LogLevel::INFO;
    return reporting_level;
}
void DefaultLogger::setReportingLevel(LogLevel level) {
    get_reporting_level() = level;
}
LogLevel DefaultLogger::getReportingLevel() {
    return get_reporting_level();
}

// String to LogLevel conversions and vice versa
std::string DefaultLogger::getStringFromLevel(LogLevel level) {
    static const std::array<std::string, 7> type = {{"FATAL", "QUIET", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE"}};
    return type.at(static_cast<decltype(type)::size_type>(level));
}
/**
 * @throws std::invalid_argument If the string does not correspond with an existing log level
 */
LogLevel DefaultLogger::getLevelFromString(const std::string& level) {
    if(level == "TRACE") {
        return LogLevel::TRACE;
    }
    if(level == "DEBUG") {
        return LogLevel::DEBUG;
    }
    if(level == "INFO") {
        return LogLevel::INFO;
    }
    if(level == "WARNING") {
        return LogLevel::WARNING;
    }
    if(level == "ERROR") {
        return LogLevel::ERROR;
    }
    if(level == "QUIET") {
        return LogLevel::QUIET;
    }
    if(level == "FATAL") {
        return LogLevel::FATAL;
    }

    throw std::invalid_argument("unknown log level");
}

// Getter and setters for the format
LogFormat& DefaultLogger::get_format() {
    static LogFormat reporting_level = LogFormat::DEFAULT;
    return reporting_level;
}
void DefaultLogger::setFormat(LogFormat level) {
    get_format() = level;
}
LogFormat DefaultLogger::getFormat() {
    return get_format();
}

// Convert string to log format and vice versa
std::string DefaultLogger::getStringFromFormat(LogFormat format) {
    static const std::array<std::string, 3> type = {{"SHORT", "DEFAULT", "LONG"}};
    return type.at(static_cast<decltype(type)::size_type>(format));
}
/**
 * @throws std::invalid_argument If the string does not correspond with an existing log format
 */
LogFormat DefaultLogger::getFormatFromString(const std::string& format) {
    if(format == "SHORT") {
        return LogFormat::SHORT;
    }
    if(format == "DEFAULT") {
        return LogFormat::DEFAULT;
    }
    if(format == "LONG") {
        return LogFormat::LONG;
    }

    throw std::invalid_argument("unknown log format");
}

/**
 * The streams are shared by all logger instantiations.
 */
const std::vector<std::ostream*>& DefaultLogger::getStreams() {
    return get_streams();
}
std::vector<std::ostream*>& DefaultLogger::get_streams() {
    static std::vector<std::ostream*> streams;
    return streams;
}
void DefaultLogger::clearStreams() {
    get_streams().clear();
}
/**
 * The caller has to make sure that the added ostream exists for as long log messages may be written. The std::cout stream is
 * added automatically to the list of streams and does not need to be added itself.
 *
 * @note Streams cannot be individually removed at the moment and only all at once using \ref clearStreams().
 */
void DefaultLogger::addStream(std::ostream& stream) {
    // Disable cursor if stream supports it
    if(is_terminal(stream)) {
        stream << "\x1B[?25l";
    }

    get_streams().push_back(&stream);
}

// Getters and setters for the section header
std::string& DefaultLogger::get_section() {
    static std::string section;
    return section;
}
void DefaultLogger::setSection(std::string section) {
    get_section() = std::move(section);
}
std::string DefaultLogger::getSection() {
    return get_section();
}

/**
 * The date is returned in the hh:mm:ss.ms format
 */
std::string DefaultLogger::get_current_date() {
    // FIXME: revise this to get microseconds in a better way
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);

    std::stringstream ss;
    ss << std::put_time(std::localtime(&in_time_t), "%X");

    auto seconds_from_epoch = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
    auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch() - seconds_from_epoch).count();
    ss << ".";
    ss << std::setfill('0') << std::setw(3);
    ss << millis;
    return ss.str();
}

/*
 * It is impossible to know for sure a terminal has support for all extra terminal features, but every modern terminal has
 * this so we just assume it.
 */
bool DefaultLogger::is_terminal(std::ostream& stream) {
    if(&std::cout == &stream) {
        return isatty(fileno(stdout));
    } else if(&std::cerr == &stream) {
        return isatty(fileno(stderr));
    }

    return false;
}

/**
 * The number of uncaught exceptions can only be properly determined in C++17. In earlier versions it is only possible to
 * check if there is at least a single exception thrown and that function is used instead. This means a return value of zero
 * corresponds to no exception and one to at least one exception.
 */
int DefaultLogger::get_uncaught_exceptions(bool cons = false) {
#if __cplusplus > 201402L
    // we can only do this fully correctly in C++17
    return std::uncaught_exceptions();
#else
    if(cons) {
        return 0;
    }
    return static_cast<int>(std::uncaught_exception());
#endif
}
<|endoftext|>