<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: filprp.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 15:26:45 $
 *
 *  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 _FILPRP_HXX_
#define _FILPRP_HXX_

#ifndef _UCBHELPER_MACROS_HXX
#include <ucbhelper/macros.hxx>
#endif
#ifndef _CPPUHELPER_WEAK_HXX_
#include <cppuhelper/weak.hxx>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSETINFO_HPP_
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_UCB_XCONTENTPROVIDER_HPP_
#include <com/sun/star/ucb/XContentProvider.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XTYPEPROVIDER_HPP_
#include <com/sun/star/lang/XTypeProvider.hpp>
#endif

namespace fileaccess {

    class shell;

    class XPropertySetInfo_impl
        : public cppu::OWeakObject,
          public com::sun::star::lang::XTypeProvider,
          public com::sun::star::beans::XPropertySetInfo
    {
    public:
        XPropertySetInfo_impl( shell* pMyShell,const rtl::OUString& aUnqPath );
        XPropertySetInfo_impl( shell* pMyShell,const com::sun::star::uno::Sequence< com::sun::star::beans::Property >& seq );

        virtual ~XPropertySetInfo_impl();

        // XInterface
        virtual com::sun::star::uno::Any SAL_CALL
        queryInterface(
            const com::sun::star::uno::Type& aType )
            throw( com::sun::star::uno::RuntimeException);

        virtual void SAL_CALL
        acquire(
            void )
            throw();

        virtual void SAL_CALL
        release(
            void )
            throw();

        // XTypeProvider

        XTYPEPROVIDER_DECL()

        virtual com::sun::star::uno::Sequence< com::sun::star::beans::Property > SAL_CALL
        getProperties(
            void )
            throw( com::sun::star::uno::RuntimeException );

        virtual com::sun::star::beans::Property SAL_CALL
        getPropertyByName(
            const rtl::OUString& aName )
            throw( com::sun::star::beans::UnknownPropertyException,
                   com::sun::star::uno::RuntimeException);

        virtual sal_Bool SAL_CALL
        hasPropertyByName( const rtl::OUString& Name )
            throw( com::sun::star::uno::RuntimeException );

    private:
        shell*                                                                     m_pMyShell;
        com::sun::star::uno::Reference< com::sun::star::ucb::XContentProvider >    m_xProvider;
        sal_Int32                                                                  m_count;
        com::sun::star::uno::Sequence< com::sun::star::beans::Property >           m_seq;
    };
}

#endif

<commit_msg>INTEGRATION: CWS changefileheader (1.4.184); FILE MERGED 2008/04/01 16:02:15 thb 1.4.184.3: #i85898# Stripping all external header guards 2008/04/01 12:58:06 thb 1.4.184.2: #i85898# Stripping all external header guards 2008/03/31 15:30:17 rt 1.4.184.1: #i87441# Change license header to LPGL v3.<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: filprp.hxx,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.
 *
 ************************************************************************/
#ifndef _FILPRP_HXX_
#define _FILPRP_HXX_

#include <ucbhelper/macros.hxx>
#include <cppuhelper/weak.hxx>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/ucb/XContentProvider.hpp>
#include <com/sun/star/lang/XTypeProvider.hpp>

namespace fileaccess {

    class shell;

    class XPropertySetInfo_impl
        : public cppu::OWeakObject,
          public com::sun::star::lang::XTypeProvider,
          public com::sun::star::beans::XPropertySetInfo
    {
    public:
        XPropertySetInfo_impl( shell* pMyShell,const rtl::OUString& aUnqPath );
        XPropertySetInfo_impl( shell* pMyShell,const com::sun::star::uno::Sequence< com::sun::star::beans::Property >& seq );

        virtual ~XPropertySetInfo_impl();

        // XInterface
        virtual com::sun::star::uno::Any SAL_CALL
        queryInterface(
            const com::sun::star::uno::Type& aType )
            throw( com::sun::star::uno::RuntimeException);

        virtual void SAL_CALL
        acquire(
            void )
            throw();

        virtual void SAL_CALL
        release(
            void )
            throw();

        // XTypeProvider

        XTYPEPROVIDER_DECL()

        virtual com::sun::star::uno::Sequence< com::sun::star::beans::Property > SAL_CALL
        getProperties(
            void )
            throw( com::sun::star::uno::RuntimeException );

        virtual com::sun::star::beans::Property SAL_CALL
        getPropertyByName(
            const rtl::OUString& aName )
            throw( com::sun::star::beans::UnknownPropertyException,
                   com::sun::star::uno::RuntimeException);

        virtual sal_Bool SAL_CALL
        hasPropertyByName( const rtl::OUString& Name )
            throw( com::sun::star::uno::RuntimeException );

    private:
        shell*                                                                     m_pMyShell;
        com::sun::star::uno::Reference< com::sun::star::ucb::XContentProvider >    m_xProvider;
        sal_Int32                                                                  m_count;
        com::sun::star::uno::Sequence< com::sun::star::beans::Property >           m_seq;
    };
}

#endif

<|endoftext|>


<commit_before><commit_msg>Create 10474.cpp<commit_after><|endoftext|>


<commit_before>/*******************************************************************************
 * c7a/net/net-group.hpp
 *
 * NetGroup is a collection of NetConnections providing simple MPI-like
 * collectives and point-to-point communication.
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_NET_NET_GROUP_HEADER
#define C7A_NET_NET_GROUP_HEADER

#include <c7a/net/net-endpoint.hpp>
#include <c7a/net/net-connection.hpp>
#include <c7a/common/functional.hpp>
#include <c7a/common/logger.hpp>

#include <algorithm>
#include <cassert>
#include <cstring>
#include <map>
#include <string>
#include <thread>
#include <utility>
#include <vector>

namespace c7a {
namespace net {

//! \addtogroup net Network Communication
//! \{

typedef unsigned int ClientId;

/*!
 * Collection of NetConnections to workers, allow point-to-point client
 * communication and simple collectives like MPI.
 */
class NetGroup
{
    static const bool debug = false;

public:
    //! \name Construction
    //! \{

    //! Construct a mock NetGroup using a complete graph of local stream sockets
    //! for testing, and starts a thread for each client, which gets passed the
    //! NetGroup object. This is ideal for testing network communication
    //! protocols. See tests/net/test-net-group.cpp for examples.
    static void ExecuteLocalMock(
        size_t num_clients,
        const std::function<void(NetGroup*)>& thread_function);

    //! Construct a remote NetGroup using a list of NetEndpoints of which this
    //! object will be the my_rank-th item. The NetGroup opens a listening port
    //! on the my_rank-th NetEndpoint, which hence must be local. If
    //! construction or any connection fails, a NetException is thrown.
    NetGroup(ClientId my_rank,
             const std::vector<NetEndpoint>& endpoints);

    //! \}

    //! non-copyable: delete copy-constructor
    NetGroup(const NetGroup&) = delete;
    //! non-copyable: delete assignment operator
    NetGroup& operator = (const NetGroup&) = delete;

    //! \name Status und Access to NetConnections
    //! \{

    //! Return NetConnection to client id.
    NetConnection & Connection(ClientId id)
    {
        if (id >= connections_.size())
            throw NetException("NetGroup::GetClient() requested "
                               "invalid client id " + std::to_string(id));

        return connections_[id];
    }

    //! Return number of connections in this group.
    size_t Size() const
    {
        return connections_.size();
    }

    //! Return my rank in the connection group
    size_t MyRank() const
    {
        return my_rank_;
    }

    //! Closes all client connections
    void Close()
    {
        if (listener_.IsValid())
            listener_.Close();

        for (size_t i = 0; i != connections_.size(); ++i)
        {
            if (i == my_rank_) continue;

            if (connections_[i].IsValid())
                connections_[i].Close();
        }

        connections_.clear();
        my_rank_ = -1;
    }

    //! Closes all client connections
    ~NetGroup()
    {
        Close();
    }

    //! \}

    //! \name Richer ReceiveFromAny Functions
    //! \{

    /*!
     * Receive a fixed-length integral type from any worker into out_value, puts
     * worker id in *src.
     */

    template <typename T>
    void ReceiveFromAny(ClientId* out_src, T* out_value)
    {
        fd_set fd_set;
        int max_fd = 0;

        FD_ZERO(&fd_set);

        // add file descriptor to read set for poll TODO(ts): make this faster
        // (somewhen)

        sLOG0 << "--- NetGroup::ReceiveFromAny() - select():";

        for (size_t i = 0; i != connections_.size(); ++i)
        {
            if (i == my_rank_) continue;

            int fd = connections_[i].GetSocket().fd();
            FD_SET(fd, &fd_set);
            max_fd = std::max(max_fd, fd);
            sLOG0 << "select from fd=" << fd;
        }

        int retval = select(max_fd + 1, &fd_set, NULL, NULL, NULL);

        if (retval < 0) {
            perror("select()");
            abort();
        }
        else if (retval == 0) {
            perror("select() TIMEOUT");
            abort();
        }

        for (size_t i = 0; i < connections_.size(); i++)
        {
            if (i == my_rank_) continue;

            int fd = connections_[i].GetSocket().fd();

            if (FD_ISSET(fd, &fd_set))
            {
                sLOG << "select() readable fd" << fd;

                *out_src = i;
                return connections_[i].Receive<T>(out_value);
            }
        }

        sLOG << "Select() returned but no fd was readable.";

        return ReceiveFromAny<T>(out_src, out_value);
    }

    /*!
     * Receives a string message from any worker into out_data, which will be
     * resized as needed, puts worker id in *src.
     */
    void ReceiveStringFromAny(ClientId* out_src, std::string* out_data)
    {
        fd_set fd_set;
        int max_fd = 0;

        FD_ZERO(&fd_set);

        // add file descriptor to read set for poll TODO(ts): make this faster
        // (somewhen)

        sLOG0 << "--- NetGroup::ReceiveFromAny() - select():";

        for (size_t i = 0; i != connections_.size(); ++i)
        {
            if (i == my_rank_) continue;

            int fd = connections_[i].GetSocket().fd();
            FD_SET(fd, &fd_set);
            max_fd = std::max(max_fd, fd);
            sLOG0 << "select from fd=" << fd;
        }

        int retval = select(max_fd + 1, &fd_set, NULL, NULL, NULL);

        if (retval < 0) {
            perror("select()");
            abort();
        }
        else if (retval == 0) {
            perror("select() TIMEOUT");
            abort();
        }

        for (size_t i = 0; i < connections_.size(); i++)
        {
            if (i == my_rank_) continue;

            int fd = connections_[i].GetSocket().fd();

            if (FD_ISSET(fd, &fd_set))
            {
                sLOG << my_rank_ << "- select() readable fd" << fd << "id" << i;

                *out_src = i;
                return connections_[i].ReceiveString(out_data);
            }
        }

        sLOG << my_rank_ << " - Select() returned but no fd was readable.";

        return ReceiveStringFromAny(out_src, out_data);
    }

    //! \}

    //! \name Collective Operations
    //! \{

    template <typename T, typename BinarySumOp = SumOp<T> >
    void AllReduce(T& value, BinarySumOp sumOp = BinarySumOp());

    template <typename T, typename BinarySumOp = SumOp<T> >
    void PrefixSum(T& value, BinarySumOp sumOp = BinarySumOp());
    //! \}

protected:
    //! Construct object but initialize other fields later, used by
    //! ExecuteLocalMock to create many NetGroup objects.
    NetGroup(ClientId id, size_t num_clients)
        : my_rank_(id),
          connections_(num_clients)
    { }

private:
    //! The client id of this object in the NetGroup.
    ClientId my_rank_;

    //! Connections to all other clients in the NetGroup.
    std::vector<NetConnection> connections_;

    //! Socket on which to listen for incoming connections.
    NetConnection listener_;
};

template <typename T, typename BinarySumOp>
void NetGroup::AllReduce(T& value, BinarySumOp sum_op)
{
    // For each dimension of the hypercube, exchange data between workers with
    // different bits at position d

    for (size_t d = 1; d < this->Size(); d <<= 1)
    {
        // Send value to worker with id = id XOR d
        if ((this->MyRank() ^ d) < this->Size()) {
            this->Connection(this->MyRank() ^ d).Send(value);
            sLOG << "ALL_REDUCE: Worker" << this->MyRank() << ": Sending" << value
                 << "to worker" << (this->MyRank() ^ d);
        }

        // Receive value from worker with id = id XOR d
        T recv_data;
        if ((this->MyRank() ^ d) < this->Size()) {
            this->Connection(this->MyRank() ^ d).Receive(&recv_data);
            value = sum_op(value, recv_data);
            sLOG << "ALL_REDUCE: Worker" << this->MyRank() << ": Received" << recv_data
                 << "from worker" << (this->MyRank() ^ d)
                 << "value =" << value;
        }
    }

    sLOG << "ALL_REDUCE: Worker" << this->MyRank()
         << ": value after all reduce =" << value;
}

template <typename T, typename BinarySumOp>
void NetGroup::PrefixSum(T& value, BinarySumOp sumOp)
{
    // The total sum in the current hypercube. This is stored, because later,
    // bigger hypercubes need this value.
    T total_sum = value;

    for (size_t d = 1; d < this->Size(); d <<= 1)
    {
        // Send total sum of this hypercube to worker with id = id XOR d
        if ((this->MyRank() ^ d) < this->Size()) {
            this->Connection(this->MyRank() ^ d).Send(total_sum);
            sLOG << "PREFIX_SUM: Worker" << this->MyRank() << ": Sending" << total_sum
                 << "to worker" << (this->MyRank() ^ d);
        }

        // Receive total sum of smaller hypercube from worker with id = id XOR d
        T recv_data;
        if ((this->MyRank() ^ d) < this->Size()) {
            this->Connection(this->MyRank() ^ d).Receive(&recv_data);
            total_sum = sumOp(total_sum, recv_data);
            // Variable 'value' represents the prefix sum of this worker
            if (this->MyRank() & d)
                value = sumOp(value, recv_data);
            sLOG << "PREFIX_SUM: Worker" << this->MyRank() << ": Received" << recv_data
                 << "from worker" << (this->MyRank() ^ d)
                 << "value =" << value;
        }
    }

    sLOG << "PREFIX_SUM: Worker" << this->MyRank()
         << ": value after prefix sum =" << value;
}
//! \}

} // namespace net
} // namespace c7a

#endif // !C7A_NET_NET_GROUP_HEADER

/******************************************************************************/
<commit_msg>Removing superfluous this-> in collectives.<commit_after>/*******************************************************************************
 * c7a/net/net-group.hpp
 *
 * NetGroup is a collection of NetConnections providing simple MPI-like
 * collectives and point-to-point communication.
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_NET_NET_GROUP_HEADER
#define C7A_NET_NET_GROUP_HEADER

#include <c7a/net/net-endpoint.hpp>
#include <c7a/net/net-connection.hpp>
#include <c7a/common/functional.hpp>
#include <c7a/common/logger.hpp>

#include <algorithm>
#include <cassert>
#include <cstring>
#include <map>
#include <string>
#include <thread>
#include <utility>
#include <vector>

namespace c7a {
namespace net {

//! \addtogroup net Network Communication
//! \{

typedef unsigned int ClientId;

/*!
 * Collection of NetConnections to workers, allow point-to-point client
 * communication and simple collectives like MPI.
 */
class NetGroup
{
    static const bool debug = false;

public:
    //! \name Construction
    //! \{

    //! Construct a mock NetGroup using a complete graph of local stream sockets
    //! for testing, and starts a thread for each client, which gets passed the
    //! NetGroup object. This is ideal for testing network communication
    //! protocols. See tests/net/test-net-group.cpp for examples.
    static void ExecuteLocalMock(
        size_t num_clients,
        const std::function<void(NetGroup*)>& thread_function);

    //! Construct a remote NetGroup using a list of NetEndpoints of which this
    //! object will be the my_rank-th item. The NetGroup opens a listening port
    //! on the my_rank-th NetEndpoint, which hence must be local. If
    //! construction or any connection fails, a NetException is thrown.
    NetGroup(ClientId my_rank,
             const std::vector<NetEndpoint>& endpoints);

    //! \}

    //! non-copyable: delete copy-constructor
    NetGroup(const NetGroup&) = delete;
    //! non-copyable: delete assignment operator
    NetGroup& operator = (const NetGroup&) = delete;

    //! \name Status und Access to NetConnections
    //! \{

    //! Return NetConnection to client id.
    NetConnection & Connection(ClientId id)
    {
        if (id >= connections_.size())
            throw NetException("NetGroup::GetClient() requested "
                               "invalid client id " + std::to_string(id));

        return connections_[id];
    }

    //! Return number of connections in this group.
    size_t Size() const
    {
        return connections_.size();
    }

    //! Return my rank in the connection group
    size_t MyRank() const
    {
        return my_rank_;
    }

    //! Closes all client connections
    void Close()
    {
        if (listener_.IsValid())
            listener_.Close();

        for (size_t i = 0; i != connections_.size(); ++i)
        {
            if (i == my_rank_) continue;

            if (connections_[i].IsValid())
                connections_[i].Close();
        }

        connections_.clear();
        my_rank_ = -1;
    }

    //! Closes all client connections
    ~NetGroup()
    {
        Close();
    }

    //! \}

    //! \name Richer ReceiveFromAny Functions
    //! \{

    /*!
     * Receive a fixed-length integral type from any worker into out_value, puts
     * worker id in *src.
     */

    template <typename T>
    void ReceiveFromAny(ClientId* out_src, T* out_value)
    {
        fd_set fd_set;
        int max_fd = 0;

        FD_ZERO(&fd_set);

        // add file descriptor to read set for poll TODO(ts): make this faster
        // (somewhen)

        sLOG0 << "--- NetGroup::ReceiveFromAny() - select():";

        for (size_t i = 0; i != connections_.size(); ++i)
        {
            if (i == my_rank_) continue;

            int fd = connections_[i].GetSocket().fd();
            FD_SET(fd, &fd_set);
            max_fd = std::max(max_fd, fd);
            sLOG0 << "select from fd=" << fd;
        }

        int retval = select(max_fd + 1, &fd_set, NULL, NULL, NULL);

        if (retval < 0) {
            perror("select()");
            abort();
        }
        else if (retval == 0) {
            perror("select() TIMEOUT");
            abort();
        }

        for (size_t i = 0; i < connections_.size(); i++)
        {
            if (i == my_rank_) continue;

            int fd = connections_[i].GetSocket().fd();

            if (FD_ISSET(fd, &fd_set))
            {
                sLOG << "select() readable fd" << fd;

                *out_src = i;
                return connections_[i].Receive<T>(out_value);
            }
        }

        sLOG << "Select() returned but no fd was readable.";

        return ReceiveFromAny<T>(out_src, out_value);
    }

    /*!
     * Receives a string message from any worker into out_data, which will be
     * resized as needed, puts worker id in *src.
     */
    void ReceiveStringFromAny(ClientId* out_src, std::string* out_data)
    {
        fd_set fd_set;
        int max_fd = 0;

        FD_ZERO(&fd_set);

        // add file descriptor to read set for poll TODO(ts): make this faster
        // (somewhen)

        sLOG0 << "--- NetGroup::ReceiveFromAny() - select():";

        for (size_t i = 0; i != connections_.size(); ++i)
        {
            if (i == my_rank_) continue;

            int fd = connections_[i].GetSocket().fd();
            FD_SET(fd, &fd_set);
            max_fd = std::max(max_fd, fd);
            sLOG0 << "select from fd=" << fd;
        }

        int retval = select(max_fd + 1, &fd_set, NULL, NULL, NULL);

        if (retval < 0) {
            perror("select()");
            abort();
        }
        else if (retval == 0) {
            perror("select() TIMEOUT");
            abort();
        }

        for (size_t i = 0; i < connections_.size(); i++)
        {
            if (i == my_rank_) continue;

            int fd = connections_[i].GetSocket().fd();

            if (FD_ISSET(fd, &fd_set))
            {
                sLOG << my_rank_ << "- select() readable fd" << fd << "id" << i;

                *out_src = i;
                return connections_[i].ReceiveString(out_data);
            }
        }

        sLOG << my_rank_ << " - Select() returned but no fd was readable.";

        return ReceiveStringFromAny(out_src, out_data);
    }

    //! \}

    //! \name Collective Operations
    //! \{

    template <typename T, typename BinarySumOp = SumOp<T> >
    void AllReduce(T& value, BinarySumOp sumOp = BinarySumOp());

    template <typename T, typename BinarySumOp = SumOp<T> >
    void PrefixSum(T& value, BinarySumOp sumOp = BinarySumOp());
    //! \}

protected:
    //! Construct object but initialize other fields later, used by
    //! ExecuteLocalMock to create many NetGroup objects.
    NetGroup(ClientId id, size_t num_clients)
        : my_rank_(id),
          connections_(num_clients)
    { }

private:
    //! The client id of this object in the NetGroup.
    ClientId my_rank_;

    //! Connections to all other clients in the NetGroup.
    std::vector<NetConnection> connections_;

    //! Socket on which to listen for incoming connections.
    NetConnection listener_;
};

template <typename T, typename BinarySumOp>
void NetGroup::AllReduce(T& value, BinarySumOp sum_op)
{
    // For each dimension of the hypercube, exchange data between workers with
    // different bits at position d

    for (size_t d = 1; d < Size(); d <<= 1)
    {
        // Send value to worker with id = id XOR d
        if ((MyRank() ^ d) < Size()) {
            Connection(MyRank() ^ d).Send(value);
            sLOG << "ALL_REDUCE: Worker" << MyRank() << ": Sending" << value
                 << "to worker" << (MyRank() ^ d);
        }

        // Receive value from worker with id = id XOR d
        T recv_data;
        if ((MyRank() ^ d) < Size()) {
            Connection(MyRank() ^ d).Receive(&recv_data);
            value = sum_op(value, recv_data);
            sLOG << "ALL_REDUCE: Worker" << MyRank() << ": Received" << recv_data
                 << "from worker" << (MyRank() ^ d)
                 << "value =" << value;
        }
    }

    sLOG << "ALL_REDUCE: Worker" << MyRank()
         << ": value after all reduce =" << value;
}

template <typename T, typename BinarySumOp>
void NetGroup::PrefixSum(T& value, BinarySumOp sumOp)
{
    // The total sum in the current hypercube. This is stored, because later,
    // bigger hypercubes need this value.
    T total_sum = value;

    for (size_t d = 1; d < Size(); d <<= 1)
    {
        // Send total sum of this hypercube to worker with id = id XOR d
        if ((MyRank() ^ d) < Size()) {
            Connection(MyRank() ^ d).Send(total_sum);
            sLOG << "PREFIX_SUM: Worker" << MyRank() << ": Sending" << total_sum
                 << "to worker" << (MyRank() ^ d);
        }

        // Receive total sum of smaller hypercube from worker with id = id XOR d
        T recv_data;
        if ((MyRank() ^ d) < Size()) {
            Connection(MyRank() ^ d).Receive(&recv_data);
            total_sum = sumOp(total_sum, recv_data);
            // Variable 'value' represents the prefix sum of this worker
            if (MyRank() & d)
                value = sumOp(value, recv_data);
            sLOG << "PREFIX_SUM: Worker" << MyRank() << ": Received" << recv_data
                 << "from worker" << (MyRank() ^ d)
                 << "value =" << value;
        }
    }

    sLOG << "PREFIX_SUM: Worker" << MyRank()
         << ": value after prefix sum =" << value;
}
//! \}

} // namespace net
} // namespace c7a

#endif // !C7A_NET_NET_GROUP_HEADER

/******************************************************************************/
<|endoftext|>


<commit_before><commit_msg>This CL is just some speculation based on the observation of the crash stack report on Windows:<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/audio/audio_manager_base.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
#include "media/audio/audio_output_dispatcher_impl.h"
#include "media/audio/audio_output_proxy.h"
#include "media/audio/audio_output_resampler.h"
#include "media/audio/fake_audio_input_stream.h"
#include "media/audio/fake_audio_output_stream.h"
#include "media/base/media_switches.h"

namespace media {

static const int kStreamCloseDelaySeconds = 5;

// Default maximum number of output streams that can be open simultaneously
// for all platforms.
static const int kDefaultMaxOutputStreams = 16;

// Default maximum number of input streams that can be open simultaneously
// for all platforms.
static const int kDefaultMaxInputStreams = 16;

static const int kMaxInputChannels = 2;

const char AudioManagerBase::kDefaultDeviceName[] = "Default";
const char AudioManagerBase::kDefaultDeviceId[] = "default";
const char AudioManagerBase::kLoopbackInputDeviceId[] = "loopback";

struct AudioManagerBase::DispatcherParams {
  DispatcherParams(const AudioParameters& input,
                   const AudioParameters& output,
                   const std::string& output_device_id)
      : input_params(input),
        output_params(output) {}
  ~DispatcherParams() {}

  const AudioParameters input_params;
  const AudioParameters output_params;
  const std::string output_device_id;
  scoped_refptr<AudioOutputDispatcher> dispatcher;

 private:
  DISALLOW_COPY_AND_ASSIGN(DispatcherParams);
};

class AudioManagerBase::CompareByParams {
 public:
  explicit CompareByParams(const DispatcherParams* dispatcher)
      : dispatcher_(dispatcher) {}
  bool operator()(DispatcherParams* dispatcher_in) const {
    // We will reuse the existing dispatcher when:
    // 1) Unified IO is not used, input_params and output_params of the
    //    existing dispatcher are the same as the requested dispatcher.
    // 2) Unified IO is used, input_params and output_params of the existing
    //    dispatcher are the same as the request dispatcher.
    return (dispatcher_->input_params == dispatcher_in->input_params &&
            dispatcher_->output_params == dispatcher_in->output_params &&
            dispatcher_->output_device_id == dispatcher_in->output_device_id);
  }

 private:
  const DispatcherParams* dispatcher_;
};

AudioManagerBase::AudioManagerBase(AudioLogFactory* audio_log_factory)
    : max_num_output_streams_(kDefaultMaxOutputStreams),
      max_num_input_streams_(kDefaultMaxInputStreams),
      num_output_streams_(0),
      num_input_streams_(0),
      // TODO(dalecurtis): Switch this to an ObserverListThreadSafe, so we don't
      // block the UI thread when swapping devices.
      output_listeners_(
          ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY),
      audio_thread_("AudioThread"),
      audio_log_factory_(audio_log_factory) {
#if defined(OS_WIN)
  audio_thread_.init_com_with_mta(true);
#elif defined(OS_MACOSX)
  // CoreAudio calls must occur on the main thread of the process, which in our
  // case is sadly the browser UI thread.  Failure to execute calls on the right
  // thread leads to crashes and odd behavior.  See http://crbug.com/158170.
  // TODO(dalecurtis): We should require the message loop to be passed in.
  const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
  if (!cmd_line->HasSwitch(switches::kDisableMainThreadAudio) &&
      base::MessageLoopProxy::current().get() &&
      base::MessageLoopForUI::IsCurrent()) {
    task_runner_ = base::MessageLoopProxy::current();
    return;
  }
#endif

  CHECK(audio_thread_.Start());
  task_runner_ = audio_thread_.message_loop_proxy();
}

AudioManagerBase::~AudioManagerBase() {
  // The platform specific AudioManager implementation must have already
  // stopped the audio thread. Otherwise, we may destroy audio streams before
  // stopping the thread, resulting an unexpected behavior.
  // This way we make sure activities of the audio streams are all stopped
  // before we destroy them.
  CHECK(!audio_thread_.IsRunning());
  // All the output streams should have been deleted.
  DCHECK_EQ(0, num_output_streams_);
  // All the input streams should have been deleted.
  DCHECK_EQ(0, num_input_streams_);
}

base::string16 AudioManagerBase::GetAudioInputDeviceModel() {
  return base::string16();
}

scoped_refptr<base::SingleThreadTaskRunner> AudioManagerBase::GetTaskRunner() {
  return task_runner_;
}

scoped_refptr<base::SingleThreadTaskRunner>
AudioManagerBase::GetWorkerTaskRunner() {
  // Lazily start the worker thread.
  if (!audio_thread_.IsRunning())
    CHECK(audio_thread_.Start());

  return audio_thread_.message_loop_proxy();
}

AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
    const AudioParameters& params,
    const std::string& device_id) {
  // TODO(miu): Fix ~50 call points across several unit test modules to call
  // this method on the audio thread, then uncomment the following:
  // DCHECK(task_runner_->BelongsToCurrentThread());

  if (!params.IsValid()) {
    DLOG(ERROR) << "Audio parameters are invalid";
    return NULL;
  }

  // Limit the number of audio streams opened. This is to prevent using
  // excessive resources for a large number of audio streams. More
  // importantly it prevents instability on certain systems.
  // See bug: http://crbug.com/30242.
  if (num_output_streams_ >= max_num_output_streams_) {
    DLOG(ERROR) << "Number of opened output audio streams "
                << num_output_streams_
                << " exceed the max allowed number "
                << max_num_output_streams_;
    return NULL;
  }

  AudioOutputStream* stream;
  switch (params.format()) {
    case AudioParameters::AUDIO_PCM_LINEAR:
      DCHECK(device_id.empty())
          << "AUDIO_PCM_LINEAR supports only the default device.";
      stream = MakeLinearOutputStream(params);
      break;
    case AudioParameters::AUDIO_PCM_LOW_LATENCY:
      stream = MakeLowLatencyOutputStream(params, device_id);
      break;
    case AudioParameters::AUDIO_FAKE:
      stream = FakeAudioOutputStream::MakeFakeStream(this, params);
      break;
    default:
      stream = NULL;
      break;
  }

  if (stream) {
    ++num_output_streams_;
  }

  return stream;
}

AudioInputStream* AudioManagerBase::MakeAudioInputStream(
    const AudioParameters& params,
    const std::string& device_id) {
  // TODO(miu): Fix ~20 call points across several unit test modules to call
  // this method on the audio thread, then uncomment the following:
  // DCHECK(task_runner_->BelongsToCurrentThread());

  if (!params.IsValid() || (params.channels() > kMaxInputChannels) ||
      device_id.empty()) {
    DLOG(ERROR) << "Audio parameters are invalid for device " << device_id;
    return NULL;
  }

  if (num_input_streams_ >= max_num_input_streams_) {
    DLOG(ERROR) << "Number of opened input audio streams "
                << num_input_streams_
                << " exceed the max allowed number " << max_num_input_streams_;
    return NULL;
  }

  AudioInputStream* stream;
  switch (params.format()) {
    case AudioParameters::AUDIO_PCM_LINEAR:
      stream = MakeLinearInputStream(params, device_id);
      break;
    case AudioParameters::AUDIO_PCM_LOW_LATENCY:
      stream = MakeLowLatencyInputStream(params, device_id);
      break;
    case AudioParameters::AUDIO_FAKE:
      stream = FakeAudioInputStream::MakeFakeStream(this, params);
      break;
    default:
      stream = NULL;
      break;
  }

  if (stream) {
    ++num_input_streams_;
  }

  return stream;
}

AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
    const AudioParameters& params,
    const std::string& device_id) {
  DCHECK(task_runner_->BelongsToCurrentThread());

  // If the caller supplied an empty device id to select the default device,
  // we fetch the actual device id of the default device so that the lookup
  // will find the correct device regardless of whether it was opened as
  // "default" or via the specific id.
  // NOTE: Implementations that don't yet support opening non-default output
  // devices may return an empty string from GetDefaultOutputDeviceID().
  std::string output_device_id = device_id.empty() ?
      GetDefaultOutputDeviceID() : device_id;

  // If we're not using AudioOutputResampler our output parameters are the same
  // as our input parameters.
  AudioParameters output_params = params;
  if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
    output_params =
        GetPreferredOutputStreamParameters(output_device_id, params);

    // Ensure we only pass on valid output parameters.
    if (!output_params.IsValid()) {
      // We've received invalid audio output parameters, so switch to a mock
      // output device based on the input parameters.  This may happen if the OS
      // provided us junk values for the hardware configuration.
      LOG(ERROR) << "Invalid audio output parameters received; using fake "
                 << "audio path. Channels: " << output_params.channels() << ", "
                 << "Sample Rate: " << output_params.sample_rate() << ", "
                 << "Bits Per Sample: " << output_params.bits_per_sample()
                 << ", Frames Per Buffer: "
                 << output_params.frames_per_buffer();

      // Tell the AudioManager to create a fake output device.
      output_params = AudioParameters(
          AudioParameters::AUDIO_FAKE, params.channel_layout(),
          params.sample_rate(), params.bits_per_sample(),
          params.frames_per_buffer());
    }
  }

  DispatcherParams* dispatcher_params =
      new DispatcherParams(params, output_params, output_device_id);

  AudioOutputDispatchers::iterator it =
      std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(),
                   CompareByParams(dispatcher_params));
  if (it != output_dispatchers_.end()) {
    delete dispatcher_params;
    return new AudioOutputProxy((*it)->dispatcher.get());
  }

  const base::TimeDelta kCloseDelay =
      base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds);
  scoped_refptr<AudioOutputDispatcher> dispatcher;
  if (output_params.format() != AudioParameters::AUDIO_FAKE) {
    dispatcher = new AudioOutputResampler(this, params, output_params,
                                          output_device_id,
                                          kCloseDelay);
  } else {
    dispatcher = new AudioOutputDispatcherImpl(this, output_params,
                                               output_device_id,
                                               kCloseDelay);
  }

  dispatcher_params->dispatcher = dispatcher;
  output_dispatchers_.push_back(dispatcher_params);
  return new AudioOutputProxy(dispatcher.get());
}

void AudioManagerBase::ShowAudioInputSettings() {
}

void AudioManagerBase::GetAudioInputDeviceNames(
    AudioDeviceNames* device_names) {
}

void AudioManagerBase::GetAudioOutputDeviceNames(
    AudioDeviceNames* device_names) {
}

void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) {
  DCHECK(stream);
  // TODO(xians) : Have a clearer destruction path for the AudioOutputStream.
  // For example, pass the ownership to AudioManager so it can delete the
  // streams.
  --num_output_streams_;
  delete stream;
}

void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) {
  DCHECK(stream);
  // TODO(xians) : Have a clearer destruction path for the AudioInputStream.
  --num_input_streams_;
  delete stream;
}

void AudioManagerBase::Shutdown() {
  // Only true when we're sharing the UI message loop with the browser.  The UI
  // loop is no longer running at this time and browser destruction is imminent.
  if (task_runner_->BelongsToCurrentThread()) {
    ShutdownOnAudioThread();
  } else {
    task_runner_->PostTask(FROM_HERE, base::Bind(
        &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this)));
  }

  // Stop() will wait for any posted messages to be processed first.
  audio_thread_.Stop();
}

void AudioManagerBase::ShutdownOnAudioThread() {
  DCHECK(task_runner_->BelongsToCurrentThread());

  AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
  for (; it != output_dispatchers_.end(); ++it) {
    scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher;
    dispatcher->Shutdown();

    // All AudioOutputProxies must have been freed before Shutdown is called.
    // If they still exist, things will go bad.  They have direct pointers to
    // both physical audio stream objects that belong to the dispatcher as
    // well as the message loop of the audio thread that will soon go away.
    // So, better crash now than later.
    DCHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive";
    dispatcher = NULL;
  }

  output_dispatchers_.clear();
}

void AudioManagerBase::AddOutputDeviceChangeListener(
    AudioDeviceListener* listener) {
  DCHECK(task_runner_->BelongsToCurrentThread());
  output_listeners_.AddObserver(listener);
}

void AudioManagerBase::RemoveOutputDeviceChangeListener(
    AudioDeviceListener* listener) {
  DCHECK(task_runner_->BelongsToCurrentThread());
  output_listeners_.RemoveObserver(listener);
}

void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() {
  DCHECK(task_runner_->BelongsToCurrentThread());
  DVLOG(1) << "Firing OnDeviceChange() notifications.";
  FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange());
}

AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() {
  return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(),
      AudioParameters());
}

AudioParameters AudioManagerBase::GetOutputStreamParameters(
    const std::string& device_id) {
  return GetPreferredOutputStreamParameters(device_id,
      AudioParameters());
}

AudioParameters AudioManagerBase::GetInputStreamParameters(
    const std::string& device_id) {
  NOTREACHED();
  return AudioParameters();
}

std::string AudioManagerBase::GetAssociatedOutputDeviceID(
    const std::string& input_device_id) {
  return "";
}

std::string AudioManagerBase::GetDefaultOutputDeviceID() {
  return "";
}

int AudioManagerBase::GetUserBufferSize() {
  const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
  int buffer_size = 0;
  std::string buffer_size_str(cmd_line->GetSwitchValueASCII(
      switches::kAudioBufferSize));
  if (base::StringToInt(buffer_size_str, &buffer_size) && buffer_size > 0)
    return buffer_size;

  return 0;
}

scoped_ptr<AudioLog> AudioManagerBase::CreateAudioLog(
    AudioLogFactory::AudioComponent component) {
  return audio_log_factory_->CreateAudioLog(component);
}

void AudioManagerBase::FixWedgedAudio() {
  DCHECK(task_runner_->BelongsToCurrentThread());
#if defined(OS_MACOSX)
  // Through trial and error, we've found that one way to restore audio after a
  // hang is to close all outstanding audio streams.  Once all streams have been
  // closed, new streams appear to work correctly.
  //
  // In Chrome terms, this means we need to ask all AudioOutputDispatchers to
  // close all Open()'d streams.  Once all streams across all dispatchers have
  // been closed, we ask for all previously Start()'d streams to be recreated
  // using the same AudioSourceCallback they had before.
  //
  // Since this operation takes place on the audio thread we can be sure that no
  // other state-changing stream operations will take place while the fix is in
  // progress.
  //
  // See http://crbug.com/160920 for additional details.
  for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
       it != output_dispatchers_.end(); ++it) {
    (*it)->dispatcher->CloseStreamsForWedgeFix();
  }
  for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
       it != output_dispatchers_.end(); ++it) {
    (*it)->dispatcher->RestartStreamsForWedgeFix();
  }
#endif
}

}  // namespace media
<commit_msg>Fix the output device selection introduced by 163343002.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/audio/audio_manager_base.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
#include "media/audio/audio_output_dispatcher_impl.h"
#include "media/audio/audio_output_proxy.h"
#include "media/audio/audio_output_resampler.h"
#include "media/audio/fake_audio_input_stream.h"
#include "media/audio/fake_audio_output_stream.h"
#include "media/base/media_switches.h"

namespace media {

static const int kStreamCloseDelaySeconds = 5;

// Default maximum number of output streams that can be open simultaneously
// for all platforms.
static const int kDefaultMaxOutputStreams = 16;

// Default maximum number of input streams that can be open simultaneously
// for all platforms.
static const int kDefaultMaxInputStreams = 16;

static const int kMaxInputChannels = 2;

const char AudioManagerBase::kDefaultDeviceName[] = "Default";
const char AudioManagerBase::kDefaultDeviceId[] = "default";
const char AudioManagerBase::kLoopbackInputDeviceId[] = "loopback";

struct AudioManagerBase::DispatcherParams {
  DispatcherParams(const AudioParameters& input,
                   const AudioParameters& output,
                   const std::string& output_device_id)
      : input_params(input),
        output_params(output),
        output_device_id(output_device_id) {}
  ~DispatcherParams() {}

  const AudioParameters input_params;
  const AudioParameters output_params;
  const std::string output_device_id;
  scoped_refptr<AudioOutputDispatcher> dispatcher;

 private:
  DISALLOW_COPY_AND_ASSIGN(DispatcherParams);
};

class AudioManagerBase::CompareByParams {
 public:
  explicit CompareByParams(const DispatcherParams* dispatcher)
      : dispatcher_(dispatcher) {}
  bool operator()(DispatcherParams* dispatcher_in) const {
    // We will reuse the existing dispatcher when:
    // 1) Unified IO is not used, input_params and output_params of the
    //    existing dispatcher are the same as the requested dispatcher.
    // 2) Unified IO is used, input_params and output_params of the existing
    //    dispatcher are the same as the request dispatcher.
    return (dispatcher_->input_params == dispatcher_in->input_params &&
            dispatcher_->output_params == dispatcher_in->output_params &&
            dispatcher_->output_device_id == dispatcher_in->output_device_id);
  }

 private:
  const DispatcherParams* dispatcher_;
};

AudioManagerBase::AudioManagerBase(AudioLogFactory* audio_log_factory)
    : max_num_output_streams_(kDefaultMaxOutputStreams),
      max_num_input_streams_(kDefaultMaxInputStreams),
      num_output_streams_(0),
      num_input_streams_(0),
      // TODO(dalecurtis): Switch this to an ObserverListThreadSafe, so we don't
      // block the UI thread when swapping devices.
      output_listeners_(
          ObserverList<AudioDeviceListener>::NOTIFY_EXISTING_ONLY),
      audio_thread_("AudioThread"),
      audio_log_factory_(audio_log_factory) {
#if defined(OS_WIN)
  audio_thread_.init_com_with_mta(true);
#elif defined(OS_MACOSX)
  // CoreAudio calls must occur on the main thread of the process, which in our
  // case is sadly the browser UI thread.  Failure to execute calls on the right
  // thread leads to crashes and odd behavior.  See http://crbug.com/158170.
  // TODO(dalecurtis): We should require the message loop to be passed in.
  const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
  if (!cmd_line->HasSwitch(switches::kDisableMainThreadAudio) &&
      base::MessageLoopProxy::current().get() &&
      base::MessageLoopForUI::IsCurrent()) {
    task_runner_ = base::MessageLoopProxy::current();
    return;
  }
#endif

  CHECK(audio_thread_.Start());
  task_runner_ = audio_thread_.message_loop_proxy();
}

AudioManagerBase::~AudioManagerBase() {
  // The platform specific AudioManager implementation must have already
  // stopped the audio thread. Otherwise, we may destroy audio streams before
  // stopping the thread, resulting an unexpected behavior.
  // This way we make sure activities of the audio streams are all stopped
  // before we destroy them.
  CHECK(!audio_thread_.IsRunning());
  // All the output streams should have been deleted.
  DCHECK_EQ(0, num_output_streams_);
  // All the input streams should have been deleted.
  DCHECK_EQ(0, num_input_streams_);
}

base::string16 AudioManagerBase::GetAudioInputDeviceModel() {
  return base::string16();
}

scoped_refptr<base::SingleThreadTaskRunner> AudioManagerBase::GetTaskRunner() {
  return task_runner_;
}

scoped_refptr<base::SingleThreadTaskRunner>
AudioManagerBase::GetWorkerTaskRunner() {
  // Lazily start the worker thread.
  if (!audio_thread_.IsRunning())
    CHECK(audio_thread_.Start());

  return audio_thread_.message_loop_proxy();
}

AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
    const AudioParameters& params,
    const std::string& device_id) {
  // TODO(miu): Fix ~50 call points across several unit test modules to call
  // this method on the audio thread, then uncomment the following:
  // DCHECK(task_runner_->BelongsToCurrentThread());

  if (!params.IsValid()) {
    DLOG(ERROR) << "Audio parameters are invalid";
    return NULL;
  }

  // Limit the number of audio streams opened. This is to prevent using
  // excessive resources for a large number of audio streams. More
  // importantly it prevents instability on certain systems.
  // See bug: http://crbug.com/30242.
  if (num_output_streams_ >= max_num_output_streams_) {
    DLOG(ERROR) << "Number of opened output audio streams "
                << num_output_streams_
                << " exceed the max allowed number "
                << max_num_output_streams_;
    return NULL;
  }

  AudioOutputStream* stream;
  switch (params.format()) {
    case AudioParameters::AUDIO_PCM_LINEAR:
      DCHECK(device_id.empty())
          << "AUDIO_PCM_LINEAR supports only the default device.";
      stream = MakeLinearOutputStream(params);
      break;
    case AudioParameters::AUDIO_PCM_LOW_LATENCY:
      stream = MakeLowLatencyOutputStream(params, device_id);
      break;
    case AudioParameters::AUDIO_FAKE:
      stream = FakeAudioOutputStream::MakeFakeStream(this, params);
      break;
    default:
      stream = NULL;
      break;
  }

  if (stream) {
    ++num_output_streams_;
  }

  return stream;
}

AudioInputStream* AudioManagerBase::MakeAudioInputStream(
    const AudioParameters& params,
    const std::string& device_id) {
  // TODO(miu): Fix ~20 call points across several unit test modules to call
  // this method on the audio thread, then uncomment the following:
  // DCHECK(task_runner_->BelongsToCurrentThread());

  if (!params.IsValid() || (params.channels() > kMaxInputChannels) ||
      device_id.empty()) {
    DLOG(ERROR) << "Audio parameters are invalid for device " << device_id;
    return NULL;
  }

  if (num_input_streams_ >= max_num_input_streams_) {
    DLOG(ERROR) << "Number of opened input audio streams "
                << num_input_streams_
                << " exceed the max allowed number " << max_num_input_streams_;
    return NULL;
  }

  AudioInputStream* stream;
  switch (params.format()) {
    case AudioParameters::AUDIO_PCM_LINEAR:
      stream = MakeLinearInputStream(params, device_id);
      break;
    case AudioParameters::AUDIO_PCM_LOW_LATENCY:
      stream = MakeLowLatencyInputStream(params, device_id);
      break;
    case AudioParameters::AUDIO_FAKE:
      stream = FakeAudioInputStream::MakeFakeStream(this, params);
      break;
    default:
      stream = NULL;
      break;
  }

  if (stream) {
    ++num_input_streams_;
  }

  return stream;
}

AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
    const AudioParameters& params,
    const std::string& device_id) {
  DCHECK(task_runner_->BelongsToCurrentThread());

  // If the caller supplied an empty device id to select the default device,
  // we fetch the actual device id of the default device so that the lookup
  // will find the correct device regardless of whether it was opened as
  // "default" or via the specific id.
  // NOTE: Implementations that don't yet support opening non-default output
  // devices may return an empty string from GetDefaultOutputDeviceID().
  std::string output_device_id = device_id.empty() ?
      GetDefaultOutputDeviceID() : device_id;

  // If we're not using AudioOutputResampler our output parameters are the same
  // as our input parameters.
  AudioParameters output_params = params;
  if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
    output_params =
        GetPreferredOutputStreamParameters(output_device_id, params);

    // Ensure we only pass on valid output parameters.
    if (!output_params.IsValid()) {
      // We've received invalid audio output parameters, so switch to a mock
      // output device based on the input parameters.  This may happen if the OS
      // provided us junk values for the hardware configuration.
      LOG(ERROR) << "Invalid audio output parameters received; using fake "
                 << "audio path. Channels: " << output_params.channels() << ", "
                 << "Sample Rate: " << output_params.sample_rate() << ", "
                 << "Bits Per Sample: " << output_params.bits_per_sample()
                 << ", Frames Per Buffer: "
                 << output_params.frames_per_buffer();

      // Tell the AudioManager to create a fake output device.
      output_params = AudioParameters(
          AudioParameters::AUDIO_FAKE, params.channel_layout(),
          params.sample_rate(), params.bits_per_sample(),
          params.frames_per_buffer());
    }
  }

  DispatcherParams* dispatcher_params =
      new DispatcherParams(params, output_params, output_device_id);

  AudioOutputDispatchers::iterator it =
      std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(),
                   CompareByParams(dispatcher_params));
  if (it != output_dispatchers_.end()) {
    delete dispatcher_params;
    return new AudioOutputProxy((*it)->dispatcher.get());
  }

  const base::TimeDelta kCloseDelay =
      base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds);
  scoped_refptr<AudioOutputDispatcher> dispatcher;
  if (output_params.format() != AudioParameters::AUDIO_FAKE) {
    dispatcher = new AudioOutputResampler(this, params, output_params,
                                          output_device_id,
                                          kCloseDelay);
  } else {
    dispatcher = new AudioOutputDispatcherImpl(this, output_params,
                                               output_device_id,
                                               kCloseDelay);
  }

  dispatcher_params->dispatcher = dispatcher;
  output_dispatchers_.push_back(dispatcher_params);
  return new AudioOutputProxy(dispatcher.get());
}

void AudioManagerBase::ShowAudioInputSettings() {
}

void AudioManagerBase::GetAudioInputDeviceNames(
    AudioDeviceNames* device_names) {
}

void AudioManagerBase::GetAudioOutputDeviceNames(
    AudioDeviceNames* device_names) {
}

void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) {
  DCHECK(stream);
  // TODO(xians) : Have a clearer destruction path for the AudioOutputStream.
  // For example, pass the ownership to AudioManager so it can delete the
  // streams.
  --num_output_streams_;
  delete stream;
}

void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) {
  DCHECK(stream);
  // TODO(xians) : Have a clearer destruction path for the AudioInputStream.
  --num_input_streams_;
  delete stream;
}

void AudioManagerBase::Shutdown() {
  // Only true when we're sharing the UI message loop with the browser.  The UI
  // loop is no longer running at this time and browser destruction is imminent.
  if (task_runner_->BelongsToCurrentThread()) {
    ShutdownOnAudioThread();
  } else {
    task_runner_->PostTask(FROM_HERE, base::Bind(
        &AudioManagerBase::ShutdownOnAudioThread, base::Unretained(this)));
  }

  // Stop() will wait for any posted messages to be processed first.
  audio_thread_.Stop();
}

void AudioManagerBase::ShutdownOnAudioThread() {
  DCHECK(task_runner_->BelongsToCurrentThread());

  AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
  for (; it != output_dispatchers_.end(); ++it) {
    scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher;
    dispatcher->Shutdown();

    // All AudioOutputProxies must have been freed before Shutdown is called.
    // If they still exist, things will go bad.  They have direct pointers to
    // both physical audio stream objects that belong to the dispatcher as
    // well as the message loop of the audio thread that will soon go away.
    // So, better crash now than later.
    DCHECK(dispatcher->HasOneRef()) << "AudioOutputProxies are still alive";
    dispatcher = NULL;
  }

  output_dispatchers_.clear();
}

void AudioManagerBase::AddOutputDeviceChangeListener(
    AudioDeviceListener* listener) {
  DCHECK(task_runner_->BelongsToCurrentThread());
  output_listeners_.AddObserver(listener);
}

void AudioManagerBase::RemoveOutputDeviceChangeListener(
    AudioDeviceListener* listener) {
  DCHECK(task_runner_->BelongsToCurrentThread());
  output_listeners_.RemoveObserver(listener);
}

void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() {
  DCHECK(task_runner_->BelongsToCurrentThread());
  DVLOG(1) << "Firing OnDeviceChange() notifications.";
  FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange());
}

AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() {
  return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(),
      AudioParameters());
}

AudioParameters AudioManagerBase::GetOutputStreamParameters(
    const std::string& device_id) {
  return GetPreferredOutputStreamParameters(device_id,
      AudioParameters());
}

AudioParameters AudioManagerBase::GetInputStreamParameters(
    const std::string& device_id) {
  NOTREACHED();
  return AudioParameters();
}

std::string AudioManagerBase::GetAssociatedOutputDeviceID(
    const std::string& input_device_id) {
  return "";
}

std::string AudioManagerBase::GetDefaultOutputDeviceID() {
  return "";
}

int AudioManagerBase::GetUserBufferSize() {
  const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
  int buffer_size = 0;
  std::string buffer_size_str(cmd_line->GetSwitchValueASCII(
      switches::kAudioBufferSize));
  if (base::StringToInt(buffer_size_str, &buffer_size) && buffer_size > 0)
    return buffer_size;

  return 0;
}

scoped_ptr<AudioLog> AudioManagerBase::CreateAudioLog(
    AudioLogFactory::AudioComponent component) {
  return audio_log_factory_->CreateAudioLog(component);
}

void AudioManagerBase::FixWedgedAudio() {
  DCHECK(task_runner_->BelongsToCurrentThread());
#if defined(OS_MACOSX)
  // Through trial and error, we've found that one way to restore audio after a
  // hang is to close all outstanding audio streams.  Once all streams have been
  // closed, new streams appear to work correctly.
  //
  // In Chrome terms, this means we need to ask all AudioOutputDispatchers to
  // close all Open()'d streams.  Once all streams across all dispatchers have
  // been closed, we ask for all previously Start()'d streams to be recreated
  // using the same AudioSourceCallback they had before.
  //
  // Since this operation takes place on the audio thread we can be sure that no
  // other state-changing stream operations will take place while the fix is in
  // progress.
  //
  // See http://crbug.com/160920 for additional details.
  for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
       it != output_dispatchers_.end(); ++it) {
    (*it)->dispatcher->CloseStreamsForWedgeFix();
  }
  for (AudioOutputDispatchers::iterator it = output_dispatchers_.begin();
       it != output_dispatchers_.end(); ++it) {
    (*it)->dispatcher->RestartStreamsForWedgeFix();
  }
#endif
}

}  // namespace media
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com)
 *
 *    This source code is free software; you can redistribute it
 *    and/or modify it in source code form under the terms of the GNU
 *    General Public License as published by the Free Software
 *    Foundation; either version 2 of the License, or (at your option)
 *    any later version.
 *
 *    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 General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

# include "config.h"

# include <iostream>

# include  <cassert>
# include  <typeinfo>
# include  "netlist.h"
# include  "netmisc.h"

NexusSet* NetExpr::nex_input(bool rem_out)
{
      cerr << get_fileline()
	   << ": internal error: nex_input not implemented: "
	   << *this << endl;
      return 0;
}

NexusSet* NetProc::nex_input(bool rem_out)
{
      cerr << get_fileline()
	   << ": internal error: NetProc::nex_input not implemented"
	   << endl;
      return 0;
}

NexusSet* NetEBinary::nex_input(bool rem_out)
{
      NexusSet*result = left_->nex_input(rem_out);
      NexusSet*tmp = right_->nex_input(rem_out);
      result->add(*tmp);
      delete tmp;
      return result;
}

NexusSet* NetEConcat::nex_input(bool rem_out)
{
      if (parms_[0] == NULL) return NULL;
      NexusSet*result = parms_[0]->nex_input(rem_out);
      for (unsigned idx = 1 ;  idx < parms_.count() ;  idx += 1) {
	    if (parms_[idx] == NULL) {
		  delete result;
		  return NULL;
	    }
	    NexusSet*tmp = parms_[idx]->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }
      return result;
}

NexusSet* NetEAccess::nex_input(bool rem_out)
{
      return new NexusSet;
}

/*
 * A constant has not inputs, so always return an empty set.
 */
NexusSet* NetEConst::nex_input(bool rem_out)
{
      return new NexusSet;
}

NexusSet* NetECReal::nex_input(bool rem_out)
{
      return new NexusSet;
}

/*
 * A parameter by definition has no inputs. It represents a constant
 * value, even if that value is a constant expression.
 */
NexusSet* NetEParam::nex_input(bool rem_out)
{
      return new NexusSet;
}

NexusSet* NetEEvent::nex_input(bool rem_out)
{
      return new NexusSet;
}

NexusSet* NetEScope::nex_input(bool rem_out)
{
      return new NexusSet;
}

NexusSet* NetESelect::nex_input(bool rem_out)
{
      NexusSet*result = base_? base_->nex_input(rem_out) : new NexusSet();
      NexusSet*tmp = expr_->nex_input(rem_out);
      if (tmp == NULL) {
	    delete result;
	    return NULL;
      }
      result->add(*tmp);
      delete tmp;
      return result;
}

NexusSet* NetESFunc::nex_input(bool rem_out)
{
      if (nparms_ == 0)
	    return new NexusSet;

      NexusSet*result = parms_[0]->nex_input(rem_out);
      for (unsigned idx = 1 ;  idx < nparms_ ;  idx += 1) {
	    NexusSet*tmp = parms_[idx]->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }
      return result;
}

NexusSet* NetESignal::nex_input(bool rem_out)
{
      NexusSet*result = new NexusSet;
      for (unsigned idx = 0 ;  idx < net_->pin_count() ;  idx += 1)
	    result->add(net_->pin(idx).nexus());

      return result;
}

NexusSet* NetETernary::nex_input(bool rem_out)
{
      NexusSet*tmp;
      NexusSet*result = cond_->nex_input(rem_out);

      tmp = true_val_->nex_input(rem_out);
      result->add(*tmp);
      delete tmp;

      tmp = false_val_->nex_input(rem_out);
      result->add(*tmp);
      delete tmp;

      return result;
}

NexusSet* NetEUFunc::nex_input(bool rem_out)
{
      NexusSet*result = new NexusSet;
      for (unsigned idx = 0 ;  idx < parms_.count() ;  idx += 1) {
	    NexusSet*tmp = parms_[idx]->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }

      return result;
}

NexusSet* NetEUnary::nex_input(bool rem_out)
{
      return expr_->nex_input(rem_out);
}

NexusSet* NetAssign_::nex_input(bool rem_out)
{
      NexusSet*result = new NexusSet;
      if (word_) {
	    NexusSet*tmp = word_->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }
      if (base_) {
	    NexusSet*tmp = base_->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }

      return result;
}

NexusSet* NetAssignBase::nex_input(bool rem_out)
{
      NexusSet*result = rval_->nex_input(rem_out);

	/* It is possible that the lval_ can have nex_input values. In
	   particular, index expressions are statement inputs as well,
	   so should be addressed here. */
      for (NetAssign_*cur = lval_ ;  cur ;  cur = cur->more) {
	    NexusSet*tmp = cur->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }

      return result;
}

/*
 * The nex_input of a begin/end block is the NexusSet of bits that the
 * block reads from outside the block. That means it is the union of
 * the nex_input for all the substatements.
 *
 * The input set for a sequential set is not exactly the union of the
 * input sets because there is the possibility of intermediate values,
 * that don't deserve to be in the input set. To wit:
 *
 *      begin
 *         t = a + b;
 *         c = ~t;
 *      end
 *
 * In this example, "t" should not be in the input set because it is
 * used by the sequence as a temporary value.
 */
NexusSet* NetBlock::nex_input(bool rem_out)
{
      if (last_ == 0)
	    return new NexusSet;

      if (type_ == PARA) {
	    cerr << get_fileline() << ": internal error: Sorry, "
		 << "I don't know how to synthesize fork/join blocks."
		 << endl;
	    return 0;
      }

      NetProc*cur = last_->next_;
	/* This is the accumulated input set. */
      NexusSet*result = new NexusSet;
	/* This is an accumulated output set. */
      NexusSet*prev = new NexusSet;

      do {
	      /* Get the inputs for the current statement. */
	    NexusSet*tmp = cur->nex_input(rem_out);

	      /* Add the current input set to the accumulated input set. */
	    if (tmp != 0) result->add(*tmp);
	    delete tmp;

	      /* Add the current outputs to the accumulated output set,
		 so they can be removed from the input set below. */
	    cur->nex_output(*prev);

	    cur = cur->next_;
      } while (cur != last_->next_);

        /* Remove from the input set those bits that are outputs
           from other statements. They aren't really inputs
           to the block, just internal intermediate values. */
      if (rem_out) result->rem(*prev);

      return result;
}

/*
 * The inputs to a case statement are the inputs to the expression,
 * the inputs to all the guards, and the inputs to all the guarded
 * statements.
 */
NexusSet* NetCase::nex_input(bool rem_out)
{
      NexusSet*result = expr_->nex_input(rem_out);
      if (result == 0)
	    return 0;

      for (unsigned idx = 0 ;  idx < nitems_ ;  idx += 1) {

	      /* Skip cases that have empty statements. */
	    if (items_[idx].statement == 0)
		  continue;

	    NexusSet*tmp = items_[idx].statement->nex_input(rem_out);
	    assert(tmp);
	    result->add(*tmp);
	    delete tmp;

	      /* Usually, this is the guard expression. The default
		 case is special and is identified by a null
		 guard. The default guard obviously has no input. */
	    if (items_[idx].guard) {
		  tmp = items_[idx].guard->nex_input(rem_out);
		  assert(tmp);
		  result->add(*tmp);
		  delete tmp;
	    }
      }

      return result;
}

NexusSet* NetCAssign::nex_input(bool rem_out)
{
      cerr << get_fileline() << ": internal warning: NetCAssign::nex_input()"
	   << " not implemented." << endl;
      return new NexusSet;
}

NexusSet* NetCondit::nex_input(bool rem_out)
{
      NexusSet*result = expr_->nex_input(rem_out);
      if (if_ != 0) {
	    NexusSet*tmp = if_->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }

      if (else_ != 0) {
	    NexusSet*tmp = else_->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }

      return result;
}

NexusSet* NetForce::nex_input(bool rem_out)
{
      cerr << get_fileline() << ": internal warning: NetForce::nex_input()"
	   << " not implemented." << endl;
      return new NexusSet;
}

NexusSet* NetForever::nex_input(bool rem_out)
{
      NexusSet*result = statement_->nex_input(rem_out);
      return result;
}

/*
 * The NetPDelay statement is a statement of the form
 *
 *   #<expr> <statement>
 *
 * The nex_input set is the input set of the <statement>. Do *not*
 * include the input set of the <expr> because it does not affect the
 * result. The statement can be omitted.
 */
NexusSet* NetPDelay::nex_input(bool rem_out)
{
      if (statement_ == 0) return 0;
      NexusSet*result = statement_->nex_input(rem_out);
      return result;
}

NexusSet* NetRepeat::nex_input(bool rem_out)
{
      NexusSet*result = statement_->nex_input(rem_out);
      NexusSet*tmp = expr_->nex_input(rem_out);
      result->add(*tmp);
      delete tmp;
      return result;
}

NexusSet* NetSTask::nex_input(bool rem_out)
{
      if (parms_.count() == 0)
	    return new NexusSet;

      NexusSet*result = parms_[0]->nex_input(rem_out);
      for (unsigned idx = 1 ;  idx < parms_.count() ;  idx += 1) {
	    NexusSet*tmp = parms_[idx]->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }

      return result;
}

/*
 * The NetUTask represents a call to a user defined task. There are no
 * parameters to consider, because the compiler already removed them
 * and converted them to blocking assignments.
 */
NexusSet* NetUTask::nex_input(bool rem_out)
{
      return new NexusSet;
}

NexusSet* NetWhile::nex_input(bool rem_out)
{
      NexusSet*result = proc_->nex_input(rem_out);
      NexusSet*tmp = cond_->nex_input(rem_out);
      result->add(*tmp);
      delete tmp;
      return result;
}
<commit_msg>Print a warning for an implicit sensitivity list that has selects.<commit_after>/*
 * Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com)
 *
 *    This source code is free software; you can redistribute it
 *    and/or modify it in source code form under the terms of the GNU
 *    General Public License as published by the Free Software
 *    Foundation; either version 2 of the License, or (at your option)
 *    any later version.
 *
 *    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 General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

# include "config.h"

# include <iostream>

# include  <cassert>
# include  <typeinfo>
# include  "netlist.h"
# include  "netmisc.h"

NexusSet* NetExpr::nex_input(bool rem_out)
{
      cerr << get_fileline()
	   << ": internal error: nex_input not implemented: "
	   << *this << endl;
      return 0;
}

NexusSet* NetProc::nex_input(bool rem_out)
{
      cerr << get_fileline()
	   << ": internal error: NetProc::nex_input not implemented"
	   << endl;
      return 0;
}

NexusSet* NetEBinary::nex_input(bool rem_out)
{
      NexusSet*result = left_->nex_input(rem_out);
      NexusSet*tmp = right_->nex_input(rem_out);
      result->add(*tmp);
      delete tmp;
      return result;
}

NexusSet* NetEConcat::nex_input(bool rem_out)
{
      if (parms_[0] == NULL) return NULL;
      NexusSet*result = parms_[0]->nex_input(rem_out);
      for (unsigned idx = 1 ;  idx < parms_.count() ;  idx += 1) {
	    if (parms_[idx] == NULL) {
		  delete result;
		  return NULL;
	    }
	    NexusSet*tmp = parms_[idx]->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }
      return result;
}

NexusSet* NetEAccess::nex_input(bool rem_out)
{
      return new NexusSet;
}

/*
 * A constant has not inputs, so always return an empty set.
 */
NexusSet* NetEConst::nex_input(bool rem_out)
{
      return new NexusSet;
}

NexusSet* NetECReal::nex_input(bool rem_out)
{
      return new NexusSet;
}

/*
 * A parameter by definition has no inputs. It represents a constant
 * value, even if that value is a constant expression.
 */
NexusSet* NetEParam::nex_input(bool rem_out)
{
      return new NexusSet;
}

NexusSet* NetEEvent::nex_input(bool rem_out)
{
      return new NexusSet;
}

NexusSet* NetEScope::nex_input(bool rem_out)
{
      return new NexusSet;
}

NexusSet* NetESelect::nex_input(bool rem_out)
{
      NexusSet*result = base_? base_->nex_input(rem_out) : new NexusSet();
      NexusSet*tmp = expr_->nex_input(rem_out);
      if (tmp == NULL) {
	    delete result;
	    return NULL;
      }
      result->add(*tmp);
      delete tmp;
	/* See the comment for NetESignal below. */
      if (base_) {
	    cerr << get_fileline() << ": warning: @* is sensitive to all "
	            "bits in '" << *expr_ << "'." << endl;
      }
      return result;
}

NexusSet* NetESFunc::nex_input(bool rem_out)
{
      if (nparms_ == 0)
	    return new NexusSet;

      NexusSet*result = parms_[0]->nex_input(rem_out);
      for (unsigned idx = 1 ;  idx < nparms_ ;  idx += 1) {
	    NexusSet*tmp = parms_[idx]->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }
      return result;
}

NexusSet* NetESignal::nex_input(bool rem_out)
{
	/*
	 * This is not what I would expect for the various selects (bit,
	 * part, index, array). This code adds all the bits/array words
	 * instead of building the appropriate select and then using it
	 * as the trigger. Other simulators also add everything.
	 */
      NexusSet*result = new NexusSet;
	/* If we have an array index add it to the sensitivity list. */
      if (word_) {
	    NexusSet*tmp;
	    tmp = word_->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
	    cerr << get_fileline() << ": warning: @* is sensitive to all "
                 << net_->array_count() << " words in array '"
                 << name() << "'." << endl;
      }
      for (unsigned idx = 0 ;  idx < net_->pin_count() ;  idx += 1)
	    result->add(net_->pin(idx).nexus());

      return result;
}

NexusSet* NetETernary::nex_input(bool rem_out)
{
      NexusSet*tmp;
      NexusSet*result = cond_->nex_input(rem_out);

      tmp = true_val_->nex_input(rem_out);
      result->add(*tmp);
      delete tmp;

      tmp = false_val_->nex_input(rem_out);
      result->add(*tmp);
      delete tmp;

      return result;
}

NexusSet* NetEUFunc::nex_input(bool rem_out)
{
      NexusSet*result = new NexusSet;
      for (unsigned idx = 0 ;  idx < parms_.count() ;  idx += 1) {
	    NexusSet*tmp = parms_[idx]->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }

      return result;
}

NexusSet* NetEUnary::nex_input(bool rem_out)
{
      return expr_->nex_input(rem_out);
}

NexusSet* NetAssign_::nex_input(bool rem_out)
{
      NexusSet*result = new NexusSet;
      if (word_) {
	    NexusSet*tmp = word_->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }
      if (base_) {
	    NexusSet*tmp = base_->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }

      return result;
}

NexusSet* NetAssignBase::nex_input(bool rem_out)
{
      NexusSet*result = rval_->nex_input(rem_out);

	/* It is possible that the lval_ can have nex_input values. In
	   particular, index expressions are statement inputs as well,
	   so should be addressed here. */
      for (NetAssign_*cur = lval_ ;  cur ;  cur = cur->more) {
	    NexusSet*tmp = cur->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }

      return result;
}

/*
 * The nex_input of a begin/end block is the NexusSet of bits that the
 * block reads from outside the block. That means it is the union of
 * the nex_input for all the substatements.
 *
 * The input set for a sequential set is not exactly the union of the
 * input sets because there is the possibility of intermediate values,
 * that don't deserve to be in the input set. To wit:
 *
 *      begin
 *         t = a + b;
 *         c = ~t;
 *      end
 *
 * In this example, "t" should not be in the input set because it is
 * used by the sequence as a temporary value.
 */
NexusSet* NetBlock::nex_input(bool rem_out)
{
      if (last_ == 0)
	    return new NexusSet;

      if (type_ == PARA) {
	    cerr << get_fileline() << ": internal error: Sorry, "
		 << "I don't know how to synthesize fork/join blocks."
		 << endl;
	    return 0;
      }

      NetProc*cur = last_->next_;
	/* This is the accumulated input set. */
      NexusSet*result = new NexusSet;
	/* This is an accumulated output set. */
      NexusSet*prev = new NexusSet;

      do {
	      /* Get the inputs for the current statement. */
	    NexusSet*tmp = cur->nex_input(rem_out);

	      /* Add the current input set to the accumulated input set. */
	    if (tmp != 0) result->add(*tmp);
	    delete tmp;

	      /* Add the current outputs to the accumulated output set,
		 so they can be removed from the input set below. */
	    cur->nex_output(*prev);

	    cur = cur->next_;
      } while (cur != last_->next_);

        /* Remove from the input set those bits that are outputs
           from other statements. They aren't really inputs
           to the block, just internal intermediate values. */
      if (rem_out) result->rem(*prev);

      return result;
}

/*
 * The inputs to a case statement are the inputs to the expression,
 * the inputs to all the guards, and the inputs to all the guarded
 * statements.
 */
NexusSet* NetCase::nex_input(bool rem_out)
{
      NexusSet*result = expr_->nex_input(rem_out);
      if (result == 0)
	    return 0;

      for (unsigned idx = 0 ;  idx < nitems_ ;  idx += 1) {

	      /* Skip cases that have empty statements. */
	    if (items_[idx].statement == 0)
		  continue;

	    NexusSet*tmp = items_[idx].statement->nex_input(rem_out);
	    assert(tmp);
	    result->add(*tmp);
	    delete tmp;

	      /* Usually, this is the guard expression. The default
		 case is special and is identified by a null
		 guard. The default guard obviously has no input. */
	    if (items_[idx].guard) {
		  tmp = items_[idx].guard->nex_input(rem_out);
		  assert(tmp);
		  result->add(*tmp);
		  delete tmp;
	    }
      }

      return result;
}

NexusSet* NetCAssign::nex_input(bool rem_out)
{
      cerr << get_fileline() << ": internal warning: NetCAssign::nex_input()"
	   << " not implemented." << endl;
      return new NexusSet;
}

NexusSet* NetCondit::nex_input(bool rem_out)
{
      NexusSet*result = expr_->nex_input(rem_out);
      if (if_ != 0) {
	    NexusSet*tmp = if_->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }

      if (else_ != 0) {
	    NexusSet*tmp = else_->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }

      return result;
}

NexusSet* NetForce::nex_input(bool rem_out)
{
      cerr << get_fileline() << ": internal warning: NetForce::nex_input()"
	   << " not implemented." << endl;
      return new NexusSet;
}

NexusSet* NetForever::nex_input(bool rem_out)
{
      NexusSet*result = statement_->nex_input(rem_out);
      return result;
}

/*
 * The NetPDelay statement is a statement of the form
 *
 *   #<expr> <statement>
 *
 * The nex_input set is the input set of the <statement>. Do *not*
 * include the input set of the <expr> because it does not affect the
 * result. The statement can be omitted.
 */
NexusSet* NetPDelay::nex_input(bool rem_out)
{
      if (statement_ == 0) return 0;
      NexusSet*result = statement_->nex_input(rem_out);
      return result;
}

NexusSet* NetRepeat::nex_input(bool rem_out)
{
      NexusSet*result = statement_->nex_input(rem_out);
      NexusSet*tmp = expr_->nex_input(rem_out);
      result->add(*tmp);
      delete tmp;
      return result;
}

NexusSet* NetSTask::nex_input(bool rem_out)
{
      if (parms_.count() == 0)
	    return new NexusSet;

      NexusSet*result = parms_[0]->nex_input(rem_out);
      for (unsigned idx = 1 ;  idx < parms_.count() ;  idx += 1) {
	    NexusSet*tmp = parms_[idx]->nex_input(rem_out);
	    result->add(*tmp);
	    delete tmp;
      }

      return result;
}

/*
 * The NetUTask represents a call to a user defined task. There are no
 * parameters to consider, because the compiler already removed them
 * and converted them to blocking assignments.
 */
NexusSet* NetUTask::nex_input(bool rem_out)
{
      return new NexusSet;
}

NexusSet* NetWhile::nex_input(bool rem_out)
{
      NexusSet*result = proc_->nex_input(rem_out);
      NexusSet*tmp = cond_->nex_input(rem_out);
      result->add(*tmp);
      delete tmp;
      return result;
}
<|endoftext|>


<commit_before>/*
    This file is part of Akregator.

    Copyright (C) 2004 Teemu Rytilahti <tpr@d5k.net>
                  2005 Frank Osterfeld <frank.osterfeld at kdemail.net>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    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 General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <kaction.h>
#include <kapplication.h>
#include <kfiledialog.h>
#include <khtmlview.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kmenu.h>
#include <kmessagebox.h>
#include <kprocess.h>
#include <krun.h>
#include <kshell.h>
#include <ktoolinvocation.h>
#include <kurl.h>
#include <kparts/browserextension.h>

#include <QClipboard>
#include <QPaintDevice>

#include "viewer.h"
#include "akregator_run.h"
#include "akregatorconfig.h"

using namespace Akregator;

Viewer::Viewer(QWidget *parent, const char *name)
    : KHTMLPart(parent, name), m_url(0)
{
    setZoomFactor(100);
    setJScriptEnabled(true);
    setJavaEnabled(true);
    setMetaRefreshEnabled(true);
    setPluginsEnabled(true);
    setDNDEnabled(true);
    setAutoloadImages(true);
    setStatusMessagesEnabled(true);

    // change the cursor when loading stuff...
    connect( this, SIGNAL(started(KIO::Job *)),
             this, SLOT(slotStarted(KIO::Job *)));
    connect( this, SIGNAL(completed()),
             this, SLOT(slotCompleted()));

    connect( browserExtension(), SIGNAL(popupMenu (KXMLGUIClient*, const QPoint&, const KURL&, const KParts::URLArgs&, KParts::BrowserExtension::PopupFlags, mode_t)), this, SLOT(slotPopupMenu(KXMLGUIClient*, const QPoint&, const KURL&, const KParts::URLArgs&, KParts::BrowserExtension::PopupFlags, mode_t)));

    KStdAction::print(this, SLOT(slotPrint()), actionCollection(), "viewer_print");
    KStdAction::copy(this, SLOT(slotCopy()), actionCollection(), "viewer_copy");

    new KAction( i18n("&Increase Font Sizes"), "viewmag+", "Ctrl+Plus", this, SLOT(slotZoomIn()), actionCollection(), "incFontSizes" );
    new KAction( i18n("&Decrease Font Sizes"), "viewmag-", "Ctrl+Minus", this, SLOT(slotZoomOut()), actionCollection(), "decFontSizes" );

    connect(this, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()));

    connect( browserExtension(), SIGNAL(openURLRequestDelayed(const KURL&, const KParts::URLArgs&)), this, SLOT(slotOpenURLRequest(const KURL&, const KParts::URLArgs& )) );

    new KAction(i18n("Copy &Link Address"), "", 0,
                                 this, SLOT(slotCopyLinkAddress()),
                                 actionCollection(), "copylinkaddress");
    new KAction(i18n("&Save Link As..."), "", 0,
                                 this, SLOT(slotSaveLinkAs()),
                                 actionCollection(), "savelinkas");
}

Viewer::~Viewer()
{}

bool Viewer::closeURL()
{
    emit browserExtension()->loadingProgress(-1);
    emit canceled(QString::null);
    return KHTMLPart::closeURL();
}

int Viewer::pointsToPixel(int pointSize) const
{
    return ( pointSize * view()->logicalDpiY() + 36 ) / 72 ;
}

void Viewer::displayInExternalBrowser(const KURL &url, const QString &mimetype)
{
   if (!url.isValid()) return;
   if (Settings::externalBrowserUseKdeDefault())
   {
       if (mimetype.isEmpty())
           KToolInvocation::invokeBrowser(url.url(), "0");
       else
           KRun::runURL(url, mimetype, false, false);
   }
   else
   {
       QString cmd = Settings::externalBrowserCustomCommand();
       QString urlStr = url.url();
       cmd.replace(QRegExp("%u"), urlStr);
       KProcess *proc = new KProcess;
       QStringList cmdAndArgs = KShell::splitArgs(cmd);
       *proc << cmdAndArgs;
       proc->start(KProcess::DontCare);
       delete proc;
   }
}

void Viewer::slotOpenURLRequest(const KURL& /*url*/, const KParts::URLArgs& /*args*/)
{

}

void Viewer::urlSelected(const QString &url, int button, int state, const QString &_target, KParts::URLArgs args)
{
    m_url = completeURL(url);
    browserExtension()->setURLArgs(args);
    if (button == Qt::LeftButton)
    {
        switch (Settings::lMBBehaviour())
        {
            case Settings::EnumLMBBehaviour::OpenInExternalBrowser:
                slotOpenLinkInBrowser();
                break;
            case Settings::EnumLMBBehaviour::OpenInBackground:
                slotOpenLinkInBackgroundTab();
                break;
            default:
                slotOpenLinkInForegroundTab();
                break;
        }
        return;
    }
    else if (button == Qt::MidButton)
    {
        switch (Settings::mMBBehaviour())
        {
            case Settings::EnumMMBBehaviour::OpenInExternalBrowser:
                slotOpenLinkInBrowser();
                break;
            case Settings::EnumMMBBehaviour::OpenInBackground:
                slotOpenLinkInBackgroundTab();
                break;
            default:
                slotOpenLinkInForegroundTab();
                break;
        }
        return;
    }
    KHTMLPart::urlSelected(url,button,state,_target,args);
}

void Viewer::slotPopupMenu(KXMLGUIClient*, const QPoint& p, const KURL& kurl, const KParts::URLArgs&, KParts::BrowserExtension::PopupFlags kpf, mode_t)
{
   const bool isLink = (kpf & KParts::BrowserExtension::ShowNavigationItems) == 0;
   const bool isSelection = (kpf & KParts::BrowserExtension::ShowTextSelectionItems) != 0;

   QString url = kurl.url();

   m_url = url;
   KMenu popup;

   if (isLink && !isSelection)
   {
        popup.insertItem(SmallIcon("tab_new"), i18n("Open Link in New &Tab"), this, SLOT(slotOpenLinkInForegroundTab()));
        popup.insertItem(SmallIcon("window_new"), i18n("Open Link in External &Browser"), this, SLOT(slotOpenLinkInBrowser()));
        popup.insertSeparator();
        action("savelinkas")->plug(&popup);
        action("copylinkaddress")->plug(&popup);
   }
   else
   {
       if (isSelection)
       {
            action("viewer_copy")->plug(&popup);
            popup.insertSeparator();
       }
       action("viewer_print")->plug(&popup);
       //KAction *ac = action("setEncoding");
       //if (ac)
       //     ac->plug(&popup);
   }
   popup.exec(p);
}

// taken from KDevelop
void Viewer::slotCopy()
{
    QString text = selectedText();
    text.replace( QChar( 0xa0 ), ' ' );
    QClipboard *cb = QApplication::clipboard();
    disconnect( cb, SIGNAL( selectionChanged() ), this, SLOT( slotClearSelection() ) );
    cb->setText(text);
    connect( cb, SIGNAL( selectionChanged() ), this, SLOT( slotClearSelection() ) );
}

void Viewer::slotCopyLinkAddress()
{
   if(m_url.isEmpty()) return;
   QClipboard *cb = QApplication::clipboard();
   cb->setText(m_url.prettyURL(), QClipboard::Clipboard);
   cb->setText(m_url.prettyURL(), QClipboard::Selection);
}

void Viewer::slotSelectionChanged()
{
    action("viewer_copy")->setEnabled(!selectedText().isEmpty());
}

void Viewer::slotOpenLinkInternal()
{
   openURL(m_url);
}

void Viewer::slotOpenLinkInForegroundTab()
{
    emit urlClicked(m_url, false);
}

void Viewer::slotOpenLinkInBackgroundTab()
{
    emit urlClicked(m_url, true);
}

void Viewer::slotOpenLinkInBrowser()
{
    displayInExternalBrowser(m_url, QString::null);
}

void Viewer::slotSaveLinkAs()
{
    KURL tmp( m_url );

    if ( tmp.fileName(false).isEmpty() )
        tmp.setFileName( "index.html" );
    KParts::BrowserRun::simpleSave(tmp, tmp.fileName());
}

void Viewer::slotStarted(KIO::Job *)
{
   widget()->setCursor( Qt::WaitCursor );
}

void Viewer::slotCompleted()
{
   widget()->unsetCursor();
}

void Viewer::slotScrollUp()
{
    view()->scrollBy(0,-10);
}

void Viewer::slotScrollDown()
{
    view()->scrollBy(0,10);
}

void Viewer::slotZoomIn()
{
    int zf = zoomFactor();
    if (zf < 100)
    {
        zf = zf - (zf % 20) + 20;
        setZoomFactor(zf);
    }
    else
    {
        zf = zf - (zf % 50) + 50;
        setZoomFactor(zf < 300 ? zf : 300);
    }
}

void Viewer::slotZoomOut()
{
    int zf = zoomFactor();
    if (zf <= 100)
    {
        zf = zf - (zf % 20) - 20;
        setZoomFactor(zf > 20 ? zf : 20);
    }
    else
    {
        zf = zf - (zf % 50) - 50;
        setZoomFactor(zf);
    }
}

void Viewer::slotSetZoomFactor(int percent)
{
    setZoomFactor(percent);
}

// some code taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
void Viewer::slotPrint( )
{
    view()->print();
}

void Viewer::setSafeMode()
{
    setJScriptEnabled(false);
    setJavaEnabled(false);
    setMetaRefreshEnabled(false);
    setPluginsEnabled(false);
    setDNDEnabled(true);
    setAutoloadImages(true);
    setStatusMessagesEnabled(false);
}

#include "viewer.moc"

// vim: set et ts=4 sts=4 sw=4:
<commit_msg>fix namespace (should fix --enable-final)<commit_after>/*
    This file is part of Akregator.

    Copyright (C) 2004 Teemu Rytilahti <tpr@d5k.net>
                  2005 Frank Osterfeld <frank.osterfeld at kdemail.net>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    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 General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <kaction.h>
#include <kapplication.h>
#include <kfiledialog.h>
#include <khtmlview.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kmenu.h>
#include <kmessagebox.h>
#include <kprocess.h>
#include <krun.h>
#include <kshell.h>
#include <ktoolinvocation.h>
#include <kurl.h>
#include <kparts/browserextension.h>

#include <QClipboard>
#include <QPaintDevice>

#include "viewer.h"
#include "akregator_run.h"
#include "akregatorconfig.h"

namespace Akregator {

Viewer::Viewer(QWidget *parent, const char *name)
    : KHTMLPart(parent, name), m_url(0)
{
    setZoomFactor(100);
    setJScriptEnabled(true);
    setJavaEnabled(true);
    setMetaRefreshEnabled(true);
    setPluginsEnabled(true);
    setDNDEnabled(true);
    setAutoloadImages(true);
    setStatusMessagesEnabled(true);

    // change the cursor when loading stuff...
    connect( this, SIGNAL(started(KIO::Job *)),
             this, SLOT(slotStarted(KIO::Job *)));
    connect( this, SIGNAL(completed()),
             this, SLOT(slotCompleted()));

    connect( browserExtension(), SIGNAL(popupMenu (KXMLGUIClient*, const QPoint&, const KURL&, const KParts::URLArgs&, KParts::BrowserExtension::PopupFlags, mode_t)), this, SLOT(slotPopupMenu(KXMLGUIClient*, const QPoint&, const KURL&, const KParts::URLArgs&, KParts::BrowserExtension::PopupFlags, mode_t)));

    KStdAction::print(this, SLOT(slotPrint()), actionCollection(), "viewer_print");
    KStdAction::copy(this, SLOT(slotCopy()), actionCollection(), "viewer_copy");

    new KAction( i18n("&Increase Font Sizes"), "viewmag+", "Ctrl+Plus", this, SLOT(slotZoomIn()), actionCollection(), "incFontSizes" );
    new KAction( i18n("&Decrease Font Sizes"), "viewmag-", "Ctrl+Minus", this, SLOT(slotZoomOut()), actionCollection(), "decFontSizes" );

    connect(this, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()));

    connect( browserExtension(), SIGNAL(openURLRequestDelayed(const KURL&, const KParts::URLArgs&)), this, SLOT(slotOpenURLRequest(const KURL&, const KParts::URLArgs& )) );

    new KAction(i18n("Copy &Link Address"), "", 0,
                                 this, SLOT(slotCopyLinkAddress()),
                                 actionCollection(), "copylinkaddress");
    new KAction(i18n("&Save Link As..."), "", 0,
                                 this, SLOT(slotSaveLinkAs()),
                                 actionCollection(), "savelinkas");
}

Viewer::~Viewer()
{}

bool Viewer::closeURL()
{
    emit browserExtension()->loadingProgress(-1);
    emit canceled(QString::null);
    return KHTMLPart::closeURL();
}

int Viewer::pointsToPixel(int pointSize) const
{
    return ( pointSize * view()->logicalDpiY() + 36 ) / 72 ;
}

void Viewer::displayInExternalBrowser(const KURL &url, const QString &mimetype)
{
   if (!url.isValid()) return;
   if (Settings::externalBrowserUseKdeDefault())
   {
       if (mimetype.isEmpty())
           KToolInvocation::invokeBrowser(url.url(), "0");
       else
           KRun::runURL(url, mimetype, false, false);
   }
   else
   {
       QString cmd = Settings::externalBrowserCustomCommand();
       QString urlStr = url.url();
       cmd.replace(QRegExp("%u"), urlStr);
       KProcess *proc = new KProcess;
       QStringList cmdAndArgs = KShell::splitArgs(cmd);
       *proc << cmdAndArgs;
       proc->start(KProcess::DontCare);
       delete proc;
   }
}

void Viewer::slotOpenURLRequest(const KURL& /*url*/, const KParts::URLArgs& /*args*/)
{

}

void Viewer::urlSelected(const QString &url, int button, int state, const QString &_target, KParts::URLArgs args)
{
    m_url = completeURL(url);
    browserExtension()->setURLArgs(args);
    if (button == Qt::LeftButton)
    {
        switch (Settings::lMBBehaviour())
        {
            case Settings::EnumLMBBehaviour::OpenInExternalBrowser:
                slotOpenLinkInBrowser();
                break;
            case Settings::EnumLMBBehaviour::OpenInBackground:
                slotOpenLinkInBackgroundTab();
                break;
            default:
                slotOpenLinkInForegroundTab();
                break;
        }
        return;
    }
    else if (button == Qt::MidButton)
    {
        switch (Settings::mMBBehaviour())
        {
            case Settings::EnumMMBBehaviour::OpenInExternalBrowser:
                slotOpenLinkInBrowser();
                break;
            case Settings::EnumMMBBehaviour::OpenInBackground:
                slotOpenLinkInBackgroundTab();
                break;
            default:
                slotOpenLinkInForegroundTab();
                break;
        }
        return;
    }
    KHTMLPart::urlSelected(url,button,state,_target,args);
}

void Viewer::slotPopupMenu(KXMLGUIClient*, const QPoint& p, const KURL& kurl, const KParts::URLArgs&, KParts::BrowserExtension::PopupFlags kpf, mode_t)
{
   const bool isLink = (kpf & KParts::BrowserExtension::ShowNavigationItems) == 0;
   const bool isSelection = (kpf & KParts::BrowserExtension::ShowTextSelectionItems) != 0;

   QString url = kurl.url();

   m_url = url;
   KMenu popup;

   if (isLink && !isSelection)
   {
        popup.insertItem(SmallIcon("tab_new"), i18n("Open Link in New &Tab"), this, SLOT(slotOpenLinkInForegroundTab()));
        popup.insertItem(SmallIcon("window_new"), i18n("Open Link in External &Browser"), this, SLOT(slotOpenLinkInBrowser()));
        popup.insertSeparator();
        action("savelinkas")->plug(&popup);
        action("copylinkaddress")->plug(&popup);
   }
   else
   {
       if (isSelection)
       {
            action("viewer_copy")->plug(&popup);
            popup.insertSeparator();
       }
       action("viewer_print")->plug(&popup);
       //KAction *ac = action("setEncoding");
       //if (ac)
       //     ac->plug(&popup);
   }
   popup.exec(p);
}

// taken from KDevelop
void Viewer::slotCopy()
{
    QString text = selectedText();
    text.replace( QChar( 0xa0 ), ' ' );
    QClipboard *cb = QApplication::clipboard();
    disconnect( cb, SIGNAL( selectionChanged() ), this, SLOT( slotClearSelection() ) );
    cb->setText(text);
    connect( cb, SIGNAL( selectionChanged() ), this, SLOT( slotClearSelection() ) );
}

void Viewer::slotCopyLinkAddress()
{
   if(m_url.isEmpty()) return;
   QClipboard *cb = QApplication::clipboard();
   cb->setText(m_url.prettyURL(), QClipboard::Clipboard);
   cb->setText(m_url.prettyURL(), QClipboard::Selection);
}

void Viewer::slotSelectionChanged()
{
    action("viewer_copy")->setEnabled(!selectedText().isEmpty());
}

void Viewer::slotOpenLinkInternal()
{
   openURL(m_url);
}

void Viewer::slotOpenLinkInForegroundTab()
{
    emit urlClicked(m_url, false);
}

void Viewer::slotOpenLinkInBackgroundTab()
{
    emit urlClicked(m_url, true);
}

void Viewer::slotOpenLinkInBrowser()
{
    displayInExternalBrowser(m_url, QString::null);
}

void Viewer::slotSaveLinkAs()
{
    KURL tmp( m_url );

    if ( tmp.fileName(false).isEmpty() )
        tmp.setFileName( "index.html" );
    KParts::BrowserRun::simpleSave(tmp, tmp.fileName());
}

void Viewer::slotStarted(KIO::Job *)
{
   widget()->setCursor( Qt::WaitCursor );
}

void Viewer::slotCompleted()
{
   widget()->unsetCursor();
}

void Viewer::slotScrollUp()
{
    view()->scrollBy(0,-10);
}

void Viewer::slotScrollDown()
{
    view()->scrollBy(0,10);
}

void Viewer::slotZoomIn()
{
    int zf = zoomFactor();
    if (zf < 100)
    {
        zf = zf - (zf % 20) + 20;
        setZoomFactor(zf);
    }
    else
    {
        zf = zf - (zf % 50) + 50;
        setZoomFactor(zf < 300 ? zf : 300);
    }
}

void Viewer::slotZoomOut()
{
    int zf = zoomFactor();
    if (zf <= 100)
    {
        zf = zf - (zf % 20) - 20;
        setZoomFactor(zf > 20 ? zf : 20);
    }
    else
    {
        zf = zf - (zf % 50) - 50;
        setZoomFactor(zf);
    }
}

void Viewer::slotSetZoomFactor(int percent)
{
    setZoomFactor(percent);
}

// some code taken from KDevelop (lib/widgets/kdevhtmlpart.cpp)
void Viewer::slotPrint( )
{
    view()->print();
}

void Viewer::setSafeMode()
{
    setJScriptEnabled(false);
    setJavaEnabled(false);
    setMetaRefreshEnabled(false);
    setPluginsEnabled(false);
    setDNDEnabled(true);
    setAutoloadImages(true);
    setStatusMessagesEnabled(false);
}

} // namespace Akregator

#include "viewer.moc"

// vim: set et ts=4 sts=4 sw=4:
<|endoftext|>