Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  bibload.cxx   Sprache: C

 
/* -*- 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 .
 */


#include <tools/debug.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <svl/itemprop.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <comphelper/processfactory.hxx>
#include <com/sun/star/awt/XVclWindowPeer.hpp>
#include <com/sun/star/sdbc/ResultSetType.hpp>
#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
#include <com/sun/star/sdbc/SQLException.hpp>
#include <com/sun/star/sdb/XColumn.hpp>
#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
#include <com/sun/star/sdbc/XRowSet.hpp>
#include <com/sun/star/frame/XFrameLoader.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/text/BibliographyDataField.hpp>
#include <com/sun/star/form/XLoadable.hpp>
#include <com/sun/star/frame/XLayoutManager.hpp>
#include <vcl/window.hxx>
#include <vcl/svapp.hxx>

#include "bibresid.hxx"
#include <strings.hrc>
#include "bibcont.hxx"
#include "bibbeam.hxx"
#include "bibmod.hxx"
#include "bibview.hxx"
#include "framectr.hxx"
#include "datman.hxx"
#include "bibconfig.hxx"
#include <cppuhelper/implbase.hxx>
#include <rtl/ref.hxx>
#include <o3tl/string_view.hxx>

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::sdb;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::form;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::frame;

namespace {

class BibliographyLoader : public cppu::WeakImplHelper
                            < XServiceInfo, XNameAccess, XPropertySet, XFrameLoader >
{
    HdlBibModul                                     m_pBibMod;
    rtl::Reference<BibDataManager>                  m_xDatMan;
    Reference< XNameAccess >                        m_xColumns;
    Reference< XResultSet >                         m_xCursor;

private:

    void                    loadView(const Reference< XFrame > & aFrame,
                                const Reference< XLoadEventListener > & aListener);

    BibDataManager*         GetDataManager()const;
    Reference< XNameAccess > const &    GetDataColumns() const;
    Reference< XResultSet > const &     GetDataCursor() const;
    Reference< sdb::XColumn >           GetIdentifierColumn() const;

public:
                            BibliographyLoader();
                            virtual ~BibliographyLoader() override;

    // XServiceInfo
    OUString               SAL_CALL getImplementationName() override;
    sal_Bool               SAL_CALL supportsService(const OUString& ServiceName) override;
    Sequence< OUString >   SAL_CALL getSupportedServiceNames() override;

    //XNameAccess
    virtual Any SAL_CALL getByName(const OUString& aName) override;
    virtual Sequence< OUString > SAL_CALL getElementNames() override;
    virtual sal_Bool SAL_CALL hasByName(const OUString& aName) override;

    //XElementAccess
    virtual Type  SAL_CALL getElementType() override;
    virtual sal_Bool SAL_CALL hasElements() override;

    //XPropertySet
    virtual Reference< XPropertySetInfo >  SAL_CALL getPropertySetInfo() override;
    virtual void SAL_CALL setPropertyValue(const OUString& PropertyName, const Any& aValue) override;
    virtual Any SAL_CALL getPropertyValue(const OUString& PropertyName) override;
    virtual void SAL_CALL addPropertyChangeListener(const OUString& PropertyName, const Reference< XPropertyChangeListener > & aListener) override;
    virtual void SAL_CALL removePropertyChangeListener(const OUString& PropertyName, const Reference< XPropertyChangeListener > & aListener) override;
    virtual void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference< XVetoableChangeListener > & aListener) override;
    virtual void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName, const Reference< XVetoableChangeListener > & aListener) override;

    // XLoader
    virtual void            SAL_CALL load(const Reference< XFrame > & aFrame, const OUString& aURL,
                                const Sequence< PropertyValue >& aArgs,
                                const Reference< XLoadEventListener > & aListener) override;
    virtual void            SAL_CALL cancel() override;
};

}

BibliographyLoader::BibliographyLoader() :
    m_pBibMod(nullptr)
{
}

BibliographyLoader::~BibliographyLoader()
{
    Reference< lang::XComponent >  xComp(m_xCursor, UNO_QUERY);
    if (xComp.is())
        xComp->dispose();
    if(m_pBibMod)
        CloseBibModul(m_pBibMod);
}


// XServiceInfo
OUString BibliographyLoader::getImplementationName()
{
    return u"com.sun.star.extensions.Bibliography"_ustr;
}

// XServiceInfo
sal_Bool BibliographyLoader::supportsService(const OUString& ServiceName)
{
    return cppu::supportsService(this, ServiceName);
}

// XServiceInfo
Sequence< OUString > BibliographyLoader::getSupportedServiceNames()
{
    return { u"com.sun.star.frame.FrameLoader"_ustr, u"com.sun.star.frame.Bibliography"_ustr };
}

extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
extensions_BibliographyLoader_get_implementation(
    css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
{
    return cppu::acquire(new BibliographyLoader());
}

void BibliographyLoader::cancel()
{
    //!
    //!
}

void BibliographyLoader::load(const Reference< XFrame > & rFrame, const OUString& rURL,
        const Sequence< PropertyValue >& /*rArgs*/,
        const Reference< XLoadEventListener > & rListener)
{

    SolarMutexGuard aGuard;

    m_pBibMod = OpenBibModul();

    std::u16string_view aPartName = o3tl::getToken(rURL, 1, '/' );
    Reference<XPropertySet> xPrSet(rFrame, UNO_QUERY);
    if(xPrSet.is())
    {
        Any aTitle;
        aTitle <<= BibResId(RID_BIB_STR_FRAME_TITLE);
        xPrSet->setPropertyValue(u"Title"_ustr, aTitle);
    }
    if(aPartName == u"View" || aPartName == u"View1")
    {
        loadView(rFrame, rListener);
    }
}


void BibliographyLoader::loadView(const Reference< XFrame > & rFrame,
        const Reference< XLoadEventListener > & rListener)
{
    SolarMutexGuard aGuard;
    //!
    if(!m_pBibMod)
        m_pBibMod = OpenBibModul();

    m_xDatMan = BibModul::createDataManager();
    BibDBDescriptor aBibDesc = BibModul::GetConfig()->GetBibliographyURL();

    if(aBibDesc.sDataSource.isEmpty())
    {
        DBChangeDialogConfig_Impl aConfig;
        const Sequence<OUString> aSources = aConfig.GetDataSourceNames();
        if(aSources.hasElements())
            aBibDesc.sDataSource = aSources[0];
    }

    m_xDatMan->createDatabaseForm( aBibDesc );

    Reference<awt::XWindow> aWindow = rFrame->getContainerWindow();

    VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( aWindow );

    VclPtrInstance<BibBookContainer> pMyWindow( pParent );
    pMyWindow->Show();

    VclPtrInstance< ::bib::BibView> pView( pMyWindow, m_xDatMan.get(), WB_VSCROLL | WB_HSCROLL | WB_3DLOOK );
    pView->Show();
    m_xDatMan->SetView( pView );

    VclPtrInstance< ::bib::BibBeamer> pBeamer( pMyWindow, m_xDatMan.get() );
    pBeamer->Show();
    pMyWindow->createTopFrame(pBeamer);

    pMyWindow->createBottomFrame(pView);

    Reference< awt::XWindow >  xWin ( pMyWindow->GetComponentInterface(), UNO_QUERY );

    Reference< XController >  xCtrRef( new BibFrameController_Impl( xWin, m_xDatMan.get() ) );

    xCtrRef->attachFrame(rFrame);
    rFrame->setComponent( xWin, xCtrRef);
    pBeamer->SetXController(xCtrRef);

    if (aWindow)
    {
        // not earlier because SetFocus() is triggered in setVisible()
        aWindow->setVisible(true);
    }

    Reference<XLoadable>(m_xDatMan)->load();
    m_xDatMan->RegisterInterceptor(pBeamer);

    if ( rListener.is() )
        rListener->loadFinished( this );

    // attach menu bar
    Reference< XPropertySet > xPropSet( rFrame, UNO_QUERY );
    Reference< css::frame::XLayoutManager > xLayoutManager;
    if ( xPropSet.is() )
    {
        try
        {
            Any a = xPropSet->getPropertyValue(u"LayoutManager"_ustr);
            a >>= xLayoutManager;
        }
        catch ( const uno::Exception& )
        {
        }
    }

    if ( xLayoutManager.is() )
        xLayoutManager->createElement( u"private:resource/menubar/menubar"_ustr );
}

BibDataManager* BibliographyLoader::GetDataManager()const
{
    if(!m_xDatMan.is())
    {
        if(!m_pBibMod)
            const_cast< BibliographyLoader* >( this )->m_pBibMod = OpenBibModul();
        const_cast< BibliographyLoader* >( this )->m_xDatMan = BibModul::createDataManager();
    }
    return m_xDatMan.get();
}

Reference< XNameAccess > const & BibliographyLoader::GetDataColumns() const
{
    if (!m_xColumns.is())
    {
        Reference< XMultiServiceFactory >  xMgr = comphelper::getProcessServiceFactory();
        Reference< XRowSet >  xRowSet(xMgr->createInstance(u"com.sun.star.sdb.RowSet"_ustr), UNO_QUERY);
        Reference< XPropertySet >  xResultSetProps(xRowSet, UNO_QUERY);
        DBG_ASSERT(xResultSetProps.is() , "BibliographyLoader::GetDataCursor : invalid row set (no XResultSet or no XPropertySet) !");

        BibDBDescriptor aBibDesc = BibModul::GetConfig()->GetBibliographyURL();

        Any aBibUrlAny; aBibUrlAny <<= aBibDesc.sDataSource;
        xResultSetProps->setPropertyValue(u"DataSourceName"_ustr, aBibUrlAny);
        Any aCommandType; aCommandType <<= aBibDesc.nCommandType;
        xResultSetProps->setPropertyValue(u"CommandType"_ustr, aCommandType);
        Any aTableName; aTableName <<= aBibDesc.sTableOrQuery;
        xResultSetProps->setPropertyValue(u"Command"_ustr, aTableName);
        Any aResultSetType; aResultSetType <<= sal_Int32(ResultSetType::SCROLL_INSENSITIVE);
        xResultSetProps->setPropertyValue(u"ResultSetType"_ustr, aResultSetType);
        Any aResultSetCurrency; aResultSetCurrency <<= sal_Int32(ResultSetConcurrency::UPDATABLE);
        xResultSetProps->setPropertyValue(u"ResultSetConcurrency"_ustr, aResultSetCurrency);

        bool bSuccess = false;
        try
        {
            xRowSet->execute();
            bSuccess = true;
        }
        catch(const SQLException&)
        {
            DBG_UNHANDLED_EXCEPTION("extensions.biblio");
        }
        catch(const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION("extensions.biblio");
            bSuccess = false;
        }

        if (!bSuccess)
        {
            Reference< XComponent >  xSetComp(xRowSet, UNO_QUERY);
            if (xSetComp.is())
                xSetComp->dispose();
            xRowSet = nullptr;
        }
        else
            const_cast<BibliographyLoader*>(this)->m_xCursor = xRowSet.get();

        Reference< sdbcx::XColumnsSupplier >  xSupplyCols(m_xCursor, UNO_QUERY);
        if (xSupplyCols.is())
            const_cast<BibliographyLoader*>(this)->m_xColumns = xSupplyCols->getColumns();
    }

    return m_xColumns;
}

Reference< sdb::XColumn >  BibliographyLoader::GetIdentifierColumn() const
{
    BibDataManager* pDatMan = GetDataManager();
    Reference< XNameAccess >  xColumns = GetDataColumns();
    OUString sIdentifierColumnName = pDatMan->GetIdentifierMapping();

    Reference< sdb::XColumn >  xReturn;
    if (xColumns.is() && xColumns->hasByName(sIdentifierColumnName))
    {
        xReturn.set(xColumns->getByName(sIdentifierColumnName), UNO_QUERY);
    }
    return xReturn;
}

Reference< XResultSet > const &  BibliographyLoader::GetDataCursor() const
{
    if (!m_xCursor.is())
        GetDataColumns();
    if (m_xCursor.is())
        m_xCursor->first();
    return m_xCursor;
}

static OUString lcl_AddProperty(const Reference< XNameAccess >&  xColumns,
        const Mapping* pMapping, const OUString& rColumnName)
{
    OUString sColumnName(rColumnName);
    if(pMapping)
    {
        for(const auto & aColumnPair : pMapping->aColumnPairs)
        {
            if(aColumnPair.sLogicalColumnName == rColumnName)
            {
                sColumnName = aColumnPair.sRealColumnName;
                break;
            }
        }
    }
    OUString uColumnName(sColumnName);
    OUString uRet;
    Reference< sdb::XColumn >  xCol;
    if (xColumns->hasByName(uColumnName))
        xCol.set(xColumns->getByName(uColumnName), UNO_QUERY);
    if (xCol.is())
        uRet = xCol->getString();
    return uRet;
}

Any BibliographyLoader::getByName(const OUString& rName)
{
    Any aRet;
    try
    {
        BibDataManager* pDatMan = GetDataManager();
        Reference< XResultSet >  xCursor = GetDataCursor();
        Reference< sdbcx::XColumnsSupplier >  xSupplyCols(xCursor, UNO_QUERY);
        Reference< XNameAccess >  xColumns;
        if (!xSupplyCols.is())
            return aRet;
        xColumns = xSupplyCols->getColumns();
        DBG_ASSERT(xSupplyCols.is(), "BibliographyLoader::getByName : invalid columns returned by the data cursor (may be the result set is not alive ?) !");
        if (!xColumns.is())
            return aRet;

        const OUString sIdentifierMapping = pDatMan->GetIdentifierMapping();
        Reference< sdb::XColumn >  xColumn;
        if (xColumns->hasByName(sIdentifierMapping))
            xColumn.set(xColumns->getByName(sIdentifierMapping), UNO_QUERY);
        if (xColumn.is())
        {
            do
            {
                if ((rName == xColumn->getString()) && !xColumn->wasNull())
                {
                    Sequence<PropertyValue> aPropSequ(COLUMN_COUNT);
                    PropertyValue* pValues = aPropSequ.getArray();
                    BibConfig* pConfig = BibModul::GetConfig();
                    BibDBDescriptor aBibDesc = BibModul::GetConfig()->GetBibliographyURL();
                    const Mapping* pMapping = pConfig->GetMapping(aBibDesc);
                    for(sal_uInt16 nEntry = 0; nEntry < COLUMN_COUNT; nEntry++)
                    {
                        const OUString& sColName = pConfig->GetDefColumnName(
                                                    nEntry);
                        pValues[nEntry].Name = sColName;
                        pValues[nEntry].Value <<= lcl_AddProperty(xColumns, pMapping, sColName);
                    }
                    aRet <<= aPropSequ;

                    break;
                }
            }
            while(xCursor->next());
        }
    }
    catch(const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("extensions.biblio");
    }
    return aRet;
}

Sequence< OUString > BibliographyLoader::getElementNames()
{
    Sequence< OUString > aRet(10);
    int nRealNameCount = 0;
    try
    {
        Reference< XResultSet >  xCursor(GetDataCursor());
        Reference< sdb::XColumn >  xIdColumn(GetIdentifierColumn());
        if (xIdColumn.is()) // implies xCursor.is()
        {
            do
            {
                OUString sTemp = xIdColumn->getString();
                if (!sTemp.isEmpty() && !xIdColumn->wasNull())
                {
                    int nLen = aRet.getLength();
                    if(nLen == nRealNameCount)
                        aRet.realloc(nLen + 10);
                    OUString* pArray = aRet.getArray();
                    pArray[nRealNameCount] = sTemp;
                    nRealNameCount++;
                }
            }
            while (xCursor->next());
        }
    }
    catch(const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("extensions.biblio");
    }

    aRet.realloc(nRealNameCount);
    return aRet;
}

sal_Bool BibliographyLoader::hasByName(const OUString& rName)
{
    bool bRet = false;
    try
    {
        Reference< XResultSet >  xCursor = GetDataCursor();
        Reference< sdb::XColumn >  xIdColumn = GetIdentifierColumn();

        if (xIdColumn.is())     // implies xCursor.is()
        {
            do
            {
                OUString sCurrentId = xIdColumn->getString();
                if (!xIdColumn->wasNull() && rName.startsWith(sCurrentId))
                {
                    bRet = true;
                    break;
                }
            }
            while(xCursor->next());
        }
    }
    catch(const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("extensions.biblio");
    }
    return bRet;
}

Type  BibliographyLoader::getElementType()
{
    return cppu::UnoType<Sequence<PropertyValue>>::get();
}

sal_Bool BibliographyLoader::hasElements()
{
    Reference< XNameAccess >  xColumns = GetDataColumns();
    return xColumns.is() && xColumns->getElementNames().hasElements();
}

Reference< XPropertySetInfo >  BibliographyLoader::getPropertySetInfo()
{
    static const SfxItemPropertyMapEntry aBibProps_Impl[] =
    {
        { u"BibliographyDataFieldNames"_ustr, 0, cppu::UnoType<Sequence<PropertyValue>>::get(), PropertyAttribute::READONLY, 0},
    };
    static Reference< XPropertySetInfo >  xRet =
        SfxItemPropertySet(aBibProps_Impl).getPropertySetInfo();
    return xRet;
}

void BibliographyLoader::setPropertyValue(const OUString& /*PropertyName*/,
                                        const Any& /*aValue*/)
{
    throw UnknownPropertyException();
    //no changeable properties
}

Any BibliographyLoader::getPropertyValue(const OUString& rPropertyName)
{
    Any aRet;
    static const sal_uInt16 aInternalMapping[] =
    {
        IDENTIFIER_POS             , // BibliographyDataField_IDENTIFIER
        AUTHORITYTYPE_POS          , // BibliographyDataField_BIBILIOGRAPHIC_TYPE
        ADDRESS_POS                , // BibliographyDataField_ADDRESS
        ANNOTE_POS                 , // BibliographyDataField_ANNOTE
        AUTHOR_POS                 , // BibliographyDataField_AUTHOR
        BOOKTITLE_POS              , // BibliographyDataField_BOOKTITLE
        CHAPTER_POS                , // BibliographyDataField_CHAPTER
        EDITION_POS                , // BibliographyDataField_EDITION
        EDITOR_POS                 , // BibliographyDataField_EDITOR
        HOWPUBLISHED_POS           , // BibliographyDataField_HOWPUBLISHED
        INSTITUTION_POS            , // BibliographyDataField_INSTITUTION
        JOURNAL_POS                , // BibliographyDataField_JOURNAL
        MONTH_POS                  , // BibliographyDataField_MONTH
        NOTE_POS                   , // BibliographyDataField_NOTE
        NUMBER_POS                 , // BibliographyDataField_NUMBER
        ORGANIZATIONS_POS          , // BibliographyDataField_ORGANIZATIONS
        PAGES_POS                  , // BibliographyDataField_PAGES
        PUBLISHER_POS              , // BibliographyDataField_PUBLISHER
        SCHOOL_POS                 , // BibliographyDataField_SCHOOL
        SERIES_POS                 , // BibliographyDataField_SERIES
        TITLE_POS                  , // BibliographyDataField_TITLE
        REPORTTYPE_POS             , // BibliographyDataField_REPORT_TYPE
        VOLUME_POS                 , // BibliographyDataField_VOLUME
        YEAR_POS                   , // BibliographyDataField_YEAR
        URL_POS                    , // BibliographyDataField_URL
        CUSTOM1_POS                , // BibliographyDataField_CUSTOM1
        CUSTOM2_POS                , // BibliographyDataField_CUSTOM2
        CUSTOM3_POS                , // BibliographyDataField_CUSTOM3
        CUSTOM4_POS                , // BibliographyDataField_CUSTOM4
        CUSTOM5_POS                , // BibliographyDataField_CUSTOM5
        ISBN_POS                   , // BibliographyDataField_ISBN
        LOCAL_URL_POS                // BibliographyDataField_LOCAL_URL
    };
    if(rPropertyName != "BibliographyDataFieldNames")
        throw UnknownPropertyException(rPropertyName);
    Sequence<PropertyValue> aSeq(COLUMN_COUNT);
    PropertyValue* pArray = aSeq.getArray();
    BibConfig* pConfig = BibModul::GetConfig();
    for(sal_uInt16 i = 0; i <= text::BibliographyDataField::LOCAL_URL ; i++)
    {
        pArray[i].Name = pConfig->GetDefColumnName(aInternalMapping[i]);
        pArray[i].Value <<= static_cast<sal_Int16>(i);
    }
    aRet <<= aSeq;
    return aRet;
}

void BibliographyLoader::addPropertyChangeListener(
        const OUString& /*PropertyName*/, const Reference< XPropertyChangeListener > & /*aListener*/)
{
    //no bound properties
}

void BibliographyLoader::removePropertyChangeListener(
        const OUString& /*PropertyName*/, const Reference< XPropertyChangeListener > & /*aListener*/)
{
    //no bound properties
}

void BibliographyLoader::addVetoableChangeListener(
    const OUString& /*PropertyName*/, const Reference< XVetoableChangeListener > & /*aListener*/)
{
    //no vetoable properties
}

void BibliographyLoader::removeVetoableChangeListener(
    const OUString& /*PropertyName*/, const Reference< XVetoableChangeListener > & /*aListener*/)
{
    //no vetoable properties
}


/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=92 H=94 G=92

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge