<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: license_dialog.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: ihi $ $Date: 2007-11-22 15:22:46 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"

#include "cppuhelper/implbase2.hxx"
#include "cppuhelper/implementationentry.hxx"
#include "unotools/configmgr.hxx"
#include "comphelper/servicedecl.hxx"
#include "comphelper/unwrapargs.hxx"
#include "i18npool/mslangid.hxx"
#include "vcl/svapp.hxx"
#include "vcl/msgbox.hxx"
#include "toolkit/helper/vclunohelper.hxx"
#include "com/sun/star/lang/XServiceInfo.hpp"
#include "com/sun/star/task/XJobExecutor.hpp"
#include "svtools/svmedit.hxx"
#include "svtools/lstner.hxx"
#include "svtools/xtextedt.hxx"
//#include <vcl/mnemonic.hxx>
//#include <vcl/tabpage.hxx>
//#include <vcl/fixed.hxx>
//#include <vcl/button.hxx>
//#include <vcl/dialog.hxx>
#include <vcl/scrbar.hxx>
//#include <svtools/wizardmachine.hxx>

//#include "boost/bind.hpp"
#include "dp_gui_shared.hxx"
#include "license_dialog.hxx"
#include "dp_gui.hrc"

using namespace ::dp_misc;
namespace cssu = ::com::sun::star::uno;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using ::rtl::OUString;

namespace dp_gui {

class LicenseView : public MultiLineEdit, public SfxListener
{
    BOOL            mbEndReached;
    Link            maEndReachedHdl;
    Link            maScrolledHdl;

public:
    LicenseView( Window* pParent, const ResId& rResId );
    ~LicenseView();

    void ScrollDown( ScrollType eScroll );

    BOOL IsEndReached() const;
    BOOL EndReached() const { return mbEndReached; }
    void SetEndReached( BOOL bEnd ) { mbEndReached = bEnd; }

    void SetEndReachedHdl( const Link& rHdl )  { maEndReachedHdl = rHdl; }
    const Link& GetAutocompleteHdl() const { return maEndReachedHdl; }

    void SetScrolledHdl( const Link& rHdl )  { maScrolledHdl = rHdl; }
    const Link& GetScrolledHdl() const { return maScrolledHdl; }

    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );

protected:
    using MultiLineEdit::Notify;
};

struct LicenseDialogImpl : public ModalDialog
{
    cssu::Reference<cssu::XComponentContext> m_xComponentContext;
    FixedText m_ftHead;
    FixedText m_ftBody1;
    FixedText m_ftBody1Txt;
    FixedText m_ftBody2;
    FixedText m_ftBody2Txt;
    FixedImage m_fiArrow1;
    FixedImage m_fiArrow2;
    LicenseView m_mlLicense;
    PushButton m_pbDown;
    FixedLine m_flBottom;

    OKButton m_acceptButton;
    CancelButton m_declineButton;

    DECL_LINK(PageDownHdl, PushButton*);
    DECL_LINK(ScrolledHdl, LicenseView*);
    DECL_LINK(EndReachedHdl, LicenseView*);

    bool m_bLicenseRead;

    virtual ~LicenseDialogImpl();

    LicenseDialogImpl(
        Window * pParent,
        css::uno::Reference< css::uno::XComponentContext > const & xContext,
        const ::rtl::OUString & sLicenseText);

    virtual void Activate();

};

LicenseView::LicenseView( Window* pParent, const ResId& rResId )
    : MultiLineEdit( pParent, rResId )
{
    SetLeftMargin( 5 );
    mbEndReached = IsEndReached();
    StartListening( *GetTextEngine() );
}

LicenseView::~LicenseView()
{
    maEndReachedHdl = Link();
    maScrolledHdl   = Link();
    EndListeningAll();
}

void LicenseView::ScrollDown( ScrollType eScroll )
{
    ScrollBar*  pScroll = GetVScrollBar();
    if ( pScroll )
        pScroll->DoScrollAction( eScroll );
}

BOOL LicenseView::IsEndReached() const
{
    BOOL bEndReached;

    ExtTextView*    pView = GetTextView();
    ExtTextEngine*  pEdit = GetTextEngine();
    ULONG           nHeight = pEdit->GetTextHeight();
    Size            aOutSize = pView->GetWindow()->GetOutputSizePixel();
    Point           aBottom( 0, aOutSize.Height() );

    if ( (ULONG) pView->GetDocPos( aBottom ).Y() >= nHeight - 1 )
        bEndReached = TRUE;
    else
        bEndReached = FALSE;

    return bEndReached;
}

void LicenseView::Notify( SfxBroadcaster&, const SfxHint& rHint )
{
    if ( rHint.IsA( TYPE(TextHint) ) )
    {
        BOOL    bLastVal = EndReached();
        ULONG   nId = ((const TextHint&)rHint).GetId();

        if ( nId == TEXT_HINT_PARAINSERTED )
        {
            if ( bLastVal )
                mbEndReached = IsEndReached();
        }
        else if ( nId == TEXT_HINT_VIEWSCROLLED )
        {
            if ( ! mbEndReached )
                mbEndReached = IsEndReached();
            maScrolledHdl.Call( this );
        }

        if ( EndReached() && !bLastVal )
        {
            maEndReachedHdl.Call( this );
        }
    }
}

//==============================================================================================================

LicenseDialogImpl::LicenseDialogImpl(
    Window * pParent,
    cssu::Reference< cssu::XComponentContext > const & xContext,
    const ::rtl::OUString & sLicenseText):
        ModalDialog(pParent, DpGuiResId(RID_DLG_LICENSE))
        ,m_xComponentContext(xContext)
        ,m_ftHead(this, DpGuiResId(FT_LICENSE_HEADER))
        ,m_ftBody1(this, DpGuiResId(FT_LICENSE_BODY_1))
        ,m_ftBody1Txt(this, DpGuiResId(FT_LICENSE_BODY_1_TXT))
        ,m_ftBody2(this, DpGuiResId(FT_LICENSE_BODY_2))
        ,m_ftBody2Txt(this, DpGuiResId(FT_LICENSE_BODY_2_TXT))
        ,m_fiArrow1(this, DpGuiResId(FI_LICENSE_ARROW1))
        ,m_fiArrow2(this, DpGuiResId(FI_LICENSE_ARROW2))
        ,m_mlLicense(this, DpGuiResId(ML_LICENSE))
        ,m_pbDown(this, DpGuiResId(PB_LICENSE_DOWN))
        ,m_flBottom(this, DpGuiResId(FL_LICENSE))
        ,m_acceptButton(this, DpGuiResId(BTN_LICENSE_ACCEPT))
        ,m_declineButton(this, DpGuiResId(BTN_LICENSE_DECLINE))
        ,m_bLicenseRead(false)

{

    if (GetBackground().GetColor().IsDark())
    {
        // high contrast mode needs other images
        m_fiArrow1.SetImage(Image(DpGuiResId(IMG_LICENCE_ARROW_HC)));
        m_fiArrow2.SetImage(Image(DpGuiResId(IMG_LICENCE_ARROW_HC)));
    }

    FreeResource();

    m_acceptButton.SetUniqueId(UID_BTN_LICENSE_ACCEPT);
    m_fiArrow1.Show(true);
    m_fiArrow2.Show(false);
    m_mlLicense.SetText(sLicenseText);

    m_mlLicense.SetEndReachedHdl( LINK(this, LicenseDialogImpl, EndReachedHdl) );
    m_mlLicense.SetScrolledHdl( LINK(this, LicenseDialogImpl, ScrolledHdl) );
    m_pbDown.SetClickHdl( LINK(this, LicenseDialogImpl, PageDownHdl) );

    // We want a automatic repeating page down button
    WinBits aStyle = m_pbDown.GetStyle();
    aStyle |= WB_REPEAT;
    m_pbDown.SetStyle( aStyle );
}

LicenseDialogImpl::~LicenseDialogImpl()
{
}

void LicenseDialogImpl::Activate()
{
    if (!m_bLicenseRead)
    {
        //Only enable the scroll down button if the license text does not fit into the window
        if (m_mlLicense.IsEndReached())
        {
            m_pbDown.Disable();
            m_acceptButton.Enable();
            m_acceptButton.GrabFocus();
        }
        else
        {
            m_pbDown.Enable();
            m_pbDown.GrabFocus();
            m_acceptButton.Disable();
        }
    }
}

IMPL_LINK( LicenseDialogImpl, ScrolledHdl, LicenseView *, EMPTYARG )
{

    if (m_mlLicense.IsEndReached())
        m_pbDown.Disable();
    else
        m_pbDown.Enable();

    return 0;
}

IMPL_LINK( LicenseDialogImpl, PageDownHdl, PushButton *, EMPTYARG )
{
    m_mlLicense.ScrollDown( SCROLL_PAGEDOWN );
    return 0;
}

IMPL_LINK( LicenseDialogImpl, EndReachedHdl, LicenseView *, EMPTYARG )
{
    m_acceptButton.Enable();
    m_acceptButton.GrabFocus();
    m_fiArrow1.Show(false);
    m_fiArrow2.Show(true);
    m_bLicenseRead = true;
    return 0;
}

//=================================================================================

LicenseDialog::LicenseDialog( Sequence<Any> const& args,
                          Reference<XComponentContext> const& xComponentContext)
    : m_xComponentContext(xComponentContext)
{
    comphelper::unwrapArgs( args, m_parent, m_sLicenseText );
}

// XExecutableDialog
//______________________________________________________________________________
void LicenseDialog::setTitle( OUString const & ) throw (RuntimeException)
{

}

//______________________________________________________________________________
sal_Int16 LicenseDialog::execute() throw (RuntimeException)
{
    //if (! dp_gui::DialogImpl::s_dialog.is())
    //{
    //
    //}

    const ::vos::OGuard guard( Application::GetSolarMutex() );
    std::auto_ptr<LicenseDialogImpl> dlg(new LicenseDialogImpl(
        VCLUnoHelper::GetWindow(m_parent), m_xComponentContext, m_sLicenseText));

    //if (m_initialTitle.getLength() > 0) {
//          dialog->SetText( m_initialTitle );
//          m_initialTitle = OUString();
//      }

    return dlg->Execute();
}

// XJobExecutor
//______________________________________________________________________________
//void LicenseDialog::trigger( OUString const & event ) throw (RuntimeException)
//{
//    execute();
//}

} // namespace dp_gui

<commit_msg>INTEGRATION: CWS jl87_SRC680 (1.7.44); FILE MERGED 2008/01/22 15:00:24 jl 1.7.44.1: #i80684# licence dialog will be executed in main thread<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: license_dialog.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: vg $ $Date: 2008-02-12 16:17:49 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"

#include "cppuhelper/implbase2.hxx"
#include "cppuhelper/implementationentry.hxx"
#include "unotools/configmgr.hxx"
#include "comphelper/servicedecl.hxx"
#include "comphelper/unwrapargs.hxx"
#include "i18npool/mslangid.hxx"
#include "vcl/svapp.hxx"
#include "vcl/msgbox.hxx"
#include "toolkit/helper/vclunohelper.hxx"
#include "com/sun/star/lang/XServiceInfo.hpp"
#include "com/sun/star/task/XJobExecutor.hpp"
#include "svtools/svmedit.hxx"
#include "svtools/lstner.hxx"
#include "svtools/xtextedt.hxx"
#include <vcl/scrbar.hxx>
#include "vcl/threadex.hxx"

#include "boost/bind.hpp"
#include "dp_gui_shared.hxx"
#include "license_dialog.hxx"
#include "dp_gui.hrc"

using namespace ::dp_misc;
namespace cssu = ::com::sun::star::uno;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using ::rtl::OUString;

namespace dp_gui {

class LicenseView : public MultiLineEdit, public SfxListener
{
    BOOL            mbEndReached;
    Link            maEndReachedHdl;
    Link            maScrolledHdl;

public:
    LicenseView( Window* pParent, const ResId& rResId );
    ~LicenseView();

    void ScrollDown( ScrollType eScroll );

    BOOL IsEndReached() const;
    BOOL EndReached() const { return mbEndReached; }
    void SetEndReached( BOOL bEnd ) { mbEndReached = bEnd; }

    void SetEndReachedHdl( const Link& rHdl )  { maEndReachedHdl = rHdl; }
    const Link& GetAutocompleteHdl() const { return maEndReachedHdl; }

    void SetScrolledHdl( const Link& rHdl )  { maScrolledHdl = rHdl; }
    const Link& GetScrolledHdl() const { return maScrolledHdl; }

    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );

protected:
    using MultiLineEdit::Notify;
};

struct LicenseDialogImpl : public ModalDialog
{
    cssu::Reference<cssu::XComponentContext> m_xComponentContext;
    FixedText m_ftHead;
    FixedText m_ftBody1;
    FixedText m_ftBody1Txt;
    FixedText m_ftBody2;
    FixedText m_ftBody2Txt;
    FixedImage m_fiArrow1;
    FixedImage m_fiArrow2;
    LicenseView m_mlLicense;
    PushButton m_pbDown;
    FixedLine m_flBottom;

    OKButton m_acceptButton;
    CancelButton m_declineButton;

    DECL_LINK(PageDownHdl, PushButton*);
    DECL_LINK(ScrolledHdl, LicenseView*);
    DECL_LINK(EndReachedHdl, LicenseView*);

    bool m_bLicenseRead;

    virtual ~LicenseDialogImpl();

    LicenseDialogImpl(
        Window * pParent,
        css::uno::Reference< css::uno::XComponentContext > const & xContext,
        const ::rtl::OUString & sLicenseText);

    virtual void Activate();

};

LicenseView::LicenseView( Window* pParent, const ResId& rResId )
    : MultiLineEdit( pParent, rResId )
{
    SetLeftMargin( 5 );
    mbEndReached = IsEndReached();
    StartListening( *GetTextEngine() );
}

LicenseView::~LicenseView()
{
    maEndReachedHdl = Link();
    maScrolledHdl   = Link();
    EndListeningAll();
}

void LicenseView::ScrollDown( ScrollType eScroll )
{
    ScrollBar*  pScroll = GetVScrollBar();
    if ( pScroll )
        pScroll->DoScrollAction( eScroll );
}

BOOL LicenseView::IsEndReached() const
{
    BOOL bEndReached;

    ExtTextView*    pView = GetTextView();
    ExtTextEngine*  pEdit = GetTextEngine();
    ULONG           nHeight = pEdit->GetTextHeight();
    Size            aOutSize = pView->GetWindow()->GetOutputSizePixel();
    Point           aBottom( 0, aOutSize.Height() );

    if ( (ULONG) pView->GetDocPos( aBottom ).Y() >= nHeight - 1 )
        bEndReached = TRUE;
    else
        bEndReached = FALSE;

    return bEndReached;
}

void LicenseView::Notify( SfxBroadcaster&, const SfxHint& rHint )
{
    if ( rHint.IsA( TYPE(TextHint) ) )
    {
        BOOL    bLastVal = EndReached();
        ULONG   nId = ((const TextHint&)rHint).GetId();

        if ( nId == TEXT_HINT_PARAINSERTED )
        {
            if ( bLastVal )
                mbEndReached = IsEndReached();
        }
        else if ( nId == TEXT_HINT_VIEWSCROLLED )
        {
            if ( ! mbEndReached )
                mbEndReached = IsEndReached();
            maScrolledHdl.Call( this );
        }

        if ( EndReached() && !bLastVal )
        {
            maEndReachedHdl.Call( this );
        }
    }
}

//==============================================================================================================

LicenseDialogImpl::LicenseDialogImpl(
    Window * pParent,
    cssu::Reference< cssu::XComponentContext > const & xContext,
    const ::rtl::OUString & sLicenseText):
        ModalDialog(pParent, DpGuiResId(RID_DLG_LICENSE))
        ,m_xComponentContext(xContext)
        ,m_ftHead(this, DpGuiResId(FT_LICENSE_HEADER))
        ,m_ftBody1(this, DpGuiResId(FT_LICENSE_BODY_1))
        ,m_ftBody1Txt(this, DpGuiResId(FT_LICENSE_BODY_1_TXT))
        ,m_ftBody2(this, DpGuiResId(FT_LICENSE_BODY_2))
        ,m_ftBody2Txt(this, DpGuiResId(FT_LICENSE_BODY_2_TXT))
        ,m_fiArrow1(this, DpGuiResId(FI_LICENSE_ARROW1))
        ,m_fiArrow2(this, DpGuiResId(FI_LICENSE_ARROW2))
        ,m_mlLicense(this, DpGuiResId(ML_LICENSE))
        ,m_pbDown(this, DpGuiResId(PB_LICENSE_DOWN))
        ,m_flBottom(this, DpGuiResId(FL_LICENSE))
        ,m_acceptButton(this, DpGuiResId(BTN_LICENSE_ACCEPT))
        ,m_declineButton(this, DpGuiResId(BTN_LICENSE_DECLINE))
        ,m_bLicenseRead(false)

{

    if (GetBackground().GetColor().IsDark())
    {
        // high contrast mode needs other images
        m_fiArrow1.SetImage(Image(DpGuiResId(IMG_LICENCE_ARROW_HC)));
        m_fiArrow2.SetImage(Image(DpGuiResId(IMG_LICENCE_ARROW_HC)));
    }

    FreeResource();

    m_acceptButton.SetUniqueId(UID_BTN_LICENSE_ACCEPT);
    m_fiArrow1.Show(true);
    m_fiArrow2.Show(false);
    m_mlLicense.SetText(sLicenseText);

    m_mlLicense.SetEndReachedHdl( LINK(this, LicenseDialogImpl, EndReachedHdl) );
    m_mlLicense.SetScrolledHdl( LINK(this, LicenseDialogImpl, ScrolledHdl) );
    m_pbDown.SetClickHdl( LINK(this, LicenseDialogImpl, PageDownHdl) );

    // We want a automatic repeating page down button
    WinBits aStyle = m_pbDown.GetStyle();
    aStyle |= WB_REPEAT;
    m_pbDown.SetStyle( aStyle );
}

LicenseDialogImpl::~LicenseDialogImpl()
{
}

void LicenseDialogImpl::Activate()
{
    if (!m_bLicenseRead)
    {
        //Only enable the scroll down button if the license text does not fit into the window
        if (m_mlLicense.IsEndReached())
        {
            m_pbDown.Disable();
            m_acceptButton.Enable();
            m_acceptButton.GrabFocus();
        }
        else
        {
            m_pbDown.Enable();
            m_pbDown.GrabFocus();
            m_acceptButton.Disable();
        }
    }
}

IMPL_LINK( LicenseDialogImpl, ScrolledHdl, LicenseView *, EMPTYARG )
{

    if (m_mlLicense.IsEndReached())
        m_pbDown.Disable();
    else
        m_pbDown.Enable();

    return 0;
}

IMPL_LINK( LicenseDialogImpl, PageDownHdl, PushButton *, EMPTYARG )
{
    m_mlLicense.ScrollDown( SCROLL_PAGEDOWN );
    return 0;
}

IMPL_LINK( LicenseDialogImpl, EndReachedHdl, LicenseView *, EMPTYARG )
{
    m_acceptButton.Enable();
    m_acceptButton.GrabFocus();
    m_fiArrow1.Show(false);
    m_fiArrow2.Show(true);
    m_bLicenseRead = true;
    return 0;
}

//=================================================================================

LicenseDialog::LicenseDialog( Sequence<Any> const& args,
                          Reference<XComponentContext> const& xComponentContext)
    : m_xComponentContext(xComponentContext)
{
    comphelper::unwrapArgs( args, m_parent, m_sLicenseText );
}

// XExecutableDialog
//______________________________________________________________________________
void LicenseDialog::setTitle( OUString const & ) throw (RuntimeException)
{

}

//______________________________________________________________________________
sal_Int16 LicenseDialog::execute() throw (RuntimeException)
{
    return vcl::solarthread::syncExecute(
        boost::bind( &LicenseDialog::solar_execute, this));
}

sal_Int16 LicenseDialog::solar_execute()
{
    std::auto_ptr<LicenseDialogImpl> dlg(new LicenseDialogImpl(
        VCLUnoHelper::GetWindow(m_parent), m_xComponentContext, m_sLicenseText));

    return dlg->Execute();
}

} // namespace dp_gui

<|endoftext|>


<commit_before>/*
 *  MachUtilities.cpp
 *  MWorksCore
 *
 *  Created by Christopher Stawarz on 5/13/11.
 *  Copyright 2011 MIT. All rights reserved.
 *
 */

#include "MachUtilities.h"

#include <mach/mach.h>

#include "Utilities.h"

BEGIN_NAMESPACE_MW

mach_timebase_info_data_t MachTimebase::getTimebaseInfo() {
    mach_timebase_info_data_t timebaseInfo;
    if (logMachError("mach_timebase_info", mach_timebase_info(&timebaseInfo))) {
        throw SimpleException(M_SYSTEM_MESSAGE_DOMAIN, "Unable to create MachTimebase");
    }
    return timebaseInfo;
}

MachThreadSelf::MachThreadSelf(const std::string &name) :
    port(mach_thread_self())
{
    pthread_setname_np(name.c_str());
}

MachThreadSelf::~MachThreadSelf() {
    //
    // NOTE: Although Apple's docs don't mention it, it's crucial to release the port returned by
    // mach_thread_self with mach_port_deallocate.  Otherwise, the port is leaked.  See
    // http://technosloth.blogspot.com/2010/08/unexpected-mach-port-refcounts.html
    //
    if (logMachError("mach_port_deallocate", mach_port_deallocate(mach_task_self(), port))) {
        mwarning(M_SYSTEM_MESSAGE_DOMAIN,
                 "Unable to release Mach thread self port; application is leaking system resources");
    }
}

//
// MachThreadSelf::setPriority attempts to map each MWorks TaskPriority level to an appropriate
// kernel scheduler priority.
//
// The scheduler priorities available to non-realtime, user-space threads range from 0 (MINPRI_USER)
// to 63 (MAXPRI_USER).  By default, user-space threads have priority 31 (BASEPRI_DEFAULT).
// Inspection (using logMachThreadInfo; see below) on macOS 10.14.3 and iOS 12.1.4 reveals that the
// application main thread runs at priority 46 (BASEPRI_BACKGROUND) or 47 (BASEPRI_FOREGROUND),
// depending on whether the application is currently frontmost.  Inspection also shows that
// the thread created by a CVDisplayLink has priority 54 and runs in non-timesharing mode.
//
// Based on these observations, we have chosen MW_STIMULUS_PRIORITY to match that used by
// CVDisplayLink (54), and we have assigned MW_IODEVICE_PRIORITY and MW_DEFAULT_PRIORITY to the two
// levels immediately below MW_STIMULUS_PRIORITY (53 and 52, respectively).  Consequently, each of
// these three priorities
//   1. is always above that of the main thread and
//   2. lies in the most elevated band of user-space priorities (52-63).
//
// Finally, note that we do *not* adjust the priority of network tasks.  For those, we simply accept
// the system default.
//
// TODO: We should periodically check whether the priorities of system-created threads still match
// our previous observations.
//
// References:
//   * _Mac OS X Internals: A Systems Approach_ by Amit Singh (http://a.co/1igATUN )
//   * osfmk/kern/sched.h in the XNU kernel source (available from https://opensource.apple.com )
//

namespace {
    constexpr int BASEPRI_DEFAULT      = 31;  // From sched.h
    constexpr int MW_DEFAULT_PRIORITY  = 52;
    constexpr int MW_IODEVICE_PRIORITY = 53;
    constexpr int MW_STIMULUS_PRIORITY = 54;
}

bool MachThreadSelf::setPriority(TaskPriority priority) {
    //
    // NOTE: The kernel computes a thread's priority by adding BASEPRI_DEFAULT to its importance
    // value.  Therefore, to obtain our desired thread priorities, we must *subtract* BASEPRI_DEFAULT
    // from them to obtain the appropriate importance values.
    //
    switch (priority) {
        case TaskPriority::Network:
            // No adjustment
            return true;

        case TaskPriority::Default:
            return setImportance(MW_DEFAULT_PRIORITY - BASEPRI_DEFAULT);

        case TaskPriority::IODevice:
            // Since I/O device threads typically perform a fixed amount of work at regular intervals,
            // they are good candidates for non-timesharing scheduling
            return (setImportance(MW_IODEVICE_PRIORITY - BASEPRI_DEFAULT) &&
                    setTimesharing(false));

        case TaskPriority::Stimulus:
            // Copy the configuration of CVDisplayLink threads.  This is primarily for the benefit of
            // the CADisplayLink thread spawned by IOSStimulusDisplay.
            return (setImportance(MW_STIMULUS_PRIORITY - BASEPRI_DEFAULT) &&
                    setTimesharing(false));
    }
}

bool MachThreadSelf::setQOSClass(qos_class_t qosClass, int relativePriority) {
    const auto errorNum = pthread_set_qos_class_self_np(qosClass, relativePriority);
    if (0 != errorNum) {
        merror(M_SYSTEM_MESSAGE_DOMAIN,
               "pthread_set_qos_class_self_np failed: %s (%d)",
               strerror(errorNum),
               errorNum);
        return false;
    }
    return true;
}

bool MachThreadSelf::setImportance(integer_t importance) {
    thread_precedence_policy_data_t precedencePolicyData;
    precedencePolicyData.importance = importance;

    return !logMachError("thread_policy_set",
                         thread_policy_set(port,
                                           THREAD_PRECEDENCE_POLICY,
                                           reinterpret_cast<thread_policy_t>(&precedencePolicyData),
                                           THREAD_PRECEDENCE_POLICY_COUNT));
}

bool MachThreadSelf::setTimesharing(bool timesharing) {
    thread_extended_policy_data_t extendedPolicyData;
    extendedPolicyData.timeshare = timesharing;

    return !logMachError("thread_policy_set",
                         thread_policy_set(port,
                                           THREAD_EXTENDED_POLICY,
                                           reinterpret_cast<thread_policy_t>(&extendedPolicyData),
                                           THREAD_EXTENDED_POLICY_COUNT));
}

bool MachThreadSelf::setRealtime(uint32_t period, uint32_t computation, uint32_t constraint, bool preemptible) {
    thread_time_constraint_policy_data_t timeConstraintPolicyData;
    timeConstraintPolicyData.period = period;
    timeConstraintPolicyData.computation = computation;
    timeConstraintPolicyData.constraint = constraint;
    timeConstraintPolicyData.preemptible = preemptible;

    return !logMachError("thread_policy_set",
                         thread_policy_set(port,
                                           THREAD_TIME_CONSTRAINT_POLICY,
                                           reinterpret_cast<thread_policy_t>(&timeConstraintPolicyData),
                                           THREAD_TIME_CONSTRAINT_POLICY_COUNT));
}

void logMachThreadInfo() {
    //
    // Log (to stderr) the scheduling information for all threads in the current process
    //

    thread_array_t threadList;
    mach_msg_type_number_t threadCount;
    if (logMachError("task_threads", task_threads(mach_task_self(), &threadList, &threadCount))) {
        return;
    }

    for (int threadNumber = 0; threadNumber < threadCount; threadNumber++) {
        fprintf(stderr, "\nThread %d", threadNumber + 1);

        const auto thread = threadList[threadNumber];
        mach_msg_type_number_t policyInfoCount;
        boolean_t getDefault;

        {
            thread_precedence_policy_data_t precedencePolicyData;
            policyInfoCount = THREAD_PRECEDENCE_POLICY_COUNT;
            getDefault = FALSE;
            if (KERN_SUCCESS == thread_policy_get(thread,
                                                  THREAD_PRECEDENCE_POLICY,
                                                  reinterpret_cast<thread_policy_t>(&precedencePolicyData),
                                                  &policyInfoCount,
                                                  &getDefault))
            {
                if (!getDefault) {
                    fprintf(stderr, "\n  importance = %d", precedencePolicyData.importance);
                }
            }
        }

        {
            thread_extended_policy_data_t extendedPolicyData;
            policyInfoCount = THREAD_EXTENDED_POLICY_COUNT;
            getDefault = FALSE;
            if (KERN_SUCCESS == thread_policy_get(thread,
                                                  THREAD_EXTENDED_POLICY,
                                                  reinterpret_cast<thread_policy_t>(&extendedPolicyData),
                                                  &policyInfoCount,
                                                  &getDefault))
            {
                if (!getDefault) {
                    fprintf(stderr, "\n  timeshare: %s", (extendedPolicyData.timeshare ? "YES" : "NO"));
                }
            }
        }

        {
            thread_time_constraint_policy_data_t timeConstraintPolicyData;
            policyInfoCount = THREAD_TIME_CONSTRAINT_POLICY_COUNT;
            getDefault = FALSE;
            if (KERN_SUCCESS == thread_policy_get(thread,
                                                  THREAD_TIME_CONSTRAINT_POLICY,
                                                  reinterpret_cast<thread_policy_t>(&timeConstraintPolicyData),
                                                  &policyInfoCount,
                                                  &getDefault))
            {
                if (!getDefault) {
                    fprintf(stderr,
                            "\n  realtime:"
                            "\n    period = %u"
                            "\n    computation = %u"
                            "\n    constraint = %u"
                            "\n    preemptible: %s",
                            timeConstraintPolicyData.period,
                            timeConstraintPolicyData.computation,
                            timeConstraintPolicyData.constraint,
                            (timeConstraintPolicyData.preemptible ? "YES" : "NO"));
                }
            }
        }

        {
            thread_extended_info_data_t extendedInfo;
            mach_msg_type_number_t extendedInfoCount = THREAD_EXTENDED_INFO_COUNT;
            if (KERN_SUCCESS == thread_info(thread,
                                            THREAD_EXTENDED_INFO,
                                            reinterpret_cast<thread_info_t>(&extendedInfo),
                                            &extendedInfoCount))
            {
                fprintf(stderr,
                        "\n  priority         = %d"
                        "\n  current priority = %d"
                        "\n  maximum priority = %d"
                        "\n  name: \"%s\"",
                        extendedInfo.pth_priority,
                        extendedInfo.pth_curpri,
                        extendedInfo.pth_maxpriority,
                        extendedInfo.pth_name);
            }
        }

        fprintf(stderr, "\n");
    }

    fflush(stderr);
}

bool logMachError(const char *functionName, mach_error_t error) {
    const bool failed = (error != ERR_SUCCESS);
    if (failed) {
        merror(M_SYSTEM_MESSAGE_DOMAIN, "%s failed: %s (%d)", functionName, mach_error_string(error), error);
    }
    return failed;
}

END_NAMESPACE_MW

<commit_msg>logMachThreadInfo now reports each thread's QoS class (if any)<commit_after>/*
 *  MachUtilities.cpp
 *  MWorksCore
 *
 *  Created by Christopher Stawarz on 5/13/11.
 *  Copyright 2011 MIT. All rights reserved.
 *
 */

#include "MachUtilities.h"

#include <mach/mach.h>

#include "Utilities.h"

BEGIN_NAMESPACE_MW

mach_timebase_info_data_t MachTimebase::getTimebaseInfo() {
    mach_timebase_info_data_t timebaseInfo;
    if (logMachError("mach_timebase_info", mach_timebase_info(&timebaseInfo))) {
        throw SimpleException(M_SYSTEM_MESSAGE_DOMAIN, "Unable to create MachTimebase");
    }
    return timebaseInfo;
}

MachThreadSelf::MachThreadSelf(const std::string &name) :
    port(mach_thread_self())
{
    pthread_setname_np(name.c_str());
}

MachThreadSelf::~MachThreadSelf() {
    //
    // NOTE: Although Apple's docs don't mention it, it's crucial to release the port returned by
    // mach_thread_self with mach_port_deallocate.  Otherwise, the port is leaked.  See
    // http://technosloth.blogspot.com/2010/08/unexpected-mach-port-refcounts.html
    //
    if (logMachError("mach_port_deallocate", mach_port_deallocate(mach_task_self(), port))) {
        mwarning(M_SYSTEM_MESSAGE_DOMAIN,
                 "Unable to release Mach thread self port; application is leaking system resources");
    }
}

//
// MachThreadSelf::setPriority attempts to map each MWorks TaskPriority level to an appropriate
// kernel scheduler priority.
//
// The scheduler priorities available to non-realtime, user-space threads range from 0 (MINPRI_USER)
// to 63 (MAXPRI_USER).  By default, user-space threads have priority 31 (BASEPRI_DEFAULT).
// Inspection (using logMachThreadInfo; see below) on macOS 10.14.3 and iOS 12.1.4 reveals that the
// application main thread runs at priority 46 (BASEPRI_BACKGROUND) or 47 (BASEPRI_FOREGROUND),
// depending on whether the application is currently frontmost.  Inspection also shows that
// the thread created by a CVDisplayLink has priority 54 and runs in non-timesharing mode.
//
// Based on these observations, we have chosen MW_STIMULUS_PRIORITY to match that used by
// CVDisplayLink (54), and we have assigned MW_IODEVICE_PRIORITY and MW_DEFAULT_PRIORITY to the two
// levels immediately below MW_STIMULUS_PRIORITY (53 and 52, respectively).  Consequently, each of
// these three priorities
//   1. is always above that of the main thread and
//   2. lies in the most elevated band of user-space priorities (52-63).
//
// Finally, note that we do *not* adjust the priority of network tasks.  For those, we simply accept
// the system default.
//
// TODO: We should periodically check whether the priorities of system-created threads still match
// our previous observations.
//
// References:
//   * _Mac OS X Internals: A Systems Approach_ by Amit Singh (http://a.co/1igATUN )
//   * osfmk/kern/sched.h in the XNU kernel source (available from https://opensource.apple.com )
//

namespace {
    constexpr int BASEPRI_DEFAULT      = 31;  // From sched.h
    constexpr int MW_DEFAULT_PRIORITY  = 52;
    constexpr int MW_IODEVICE_PRIORITY = 53;
    constexpr int MW_STIMULUS_PRIORITY = 54;
}

bool MachThreadSelf::setPriority(TaskPriority priority) {
    //
    // NOTE: The kernel computes a thread's priority by adding BASEPRI_DEFAULT to its importance
    // value.  Therefore, to obtain our desired thread priorities, we must *subtract* BASEPRI_DEFAULT
    // from them to obtain the appropriate importance values.
    //
    switch (priority) {
        case TaskPriority::Network:
            // No adjustment
            return true;

        case TaskPriority::Default:
            return setImportance(MW_DEFAULT_PRIORITY - BASEPRI_DEFAULT);

        case TaskPriority::IODevice:
            // Since I/O device threads typically perform a fixed amount of work at regular intervals,
            // they are good candidates for non-timesharing scheduling
            return (setImportance(MW_IODEVICE_PRIORITY - BASEPRI_DEFAULT) &&
                    setTimesharing(false));

        case TaskPriority::Stimulus:
            // Copy the configuration of CVDisplayLink threads.  This is primarily for the benefit of
            // the CADisplayLink thread spawned by IOSStimulusDisplay.
            return (setImportance(MW_STIMULUS_PRIORITY - BASEPRI_DEFAULT) &&
                    setTimesharing(false));
    }
}

bool MachThreadSelf::setQOSClass(qos_class_t qosClass, int relativePriority) {
    const auto errorNum = pthread_set_qos_class_self_np(qosClass, relativePriority);
    if (0 != errorNum) {
        merror(M_SYSTEM_MESSAGE_DOMAIN,
               "pthread_set_qos_class_self_np failed: %s (%d)",
               strerror(errorNum),
               errorNum);
        return false;
    }
    return true;
}

bool MachThreadSelf::setImportance(integer_t importance) {
    thread_precedence_policy_data_t precedencePolicyData;
    precedencePolicyData.importance = importance;

    return !logMachError("thread_policy_set",
                         thread_policy_set(port,
                                           THREAD_PRECEDENCE_POLICY,
                                           reinterpret_cast<thread_policy_t>(&precedencePolicyData),
                                           THREAD_PRECEDENCE_POLICY_COUNT));
}

bool MachThreadSelf::setTimesharing(bool timesharing) {
    thread_extended_policy_data_t extendedPolicyData;
    extendedPolicyData.timeshare = timesharing;

    return !logMachError("thread_policy_set",
                         thread_policy_set(port,
                                           THREAD_EXTENDED_POLICY,
                                           reinterpret_cast<thread_policy_t>(&extendedPolicyData),
                                           THREAD_EXTENDED_POLICY_COUNT));
}

bool MachThreadSelf::setRealtime(uint32_t period, uint32_t computation, uint32_t constraint, bool preemptible) {
    thread_time_constraint_policy_data_t timeConstraintPolicyData;
    timeConstraintPolicyData.period = period;
    timeConstraintPolicyData.computation = computation;
    timeConstraintPolicyData.constraint = constraint;
    timeConstraintPolicyData.preemptible = preemptible;

    return !logMachError("thread_policy_set",
                         thread_policy_set(port,
                                           THREAD_TIME_CONSTRAINT_POLICY,
                                           reinterpret_cast<thread_policy_t>(&timeConstraintPolicyData),
                                           THREAD_TIME_CONSTRAINT_POLICY_COUNT));
}

void logMachThreadInfo() {
    //
    // Log (to stderr) the scheduling information for all threads in the current process
    //

    thread_array_t threadList;
    mach_msg_type_number_t threadCount;
    if (logMachError("task_threads", task_threads(mach_task_self(), &threadList, &threadCount))) {
        return;
    }

    for (int threadNumber = 0; threadNumber < threadCount; threadNumber++) {
        fprintf(stderr, "\nThread %d", threadNumber + 1);

        const auto thread = threadList[threadNumber];
        mach_msg_type_number_t policyInfoCount;
        boolean_t getDefault;

        if (auto pthread = pthread_from_mach_thread_np(thread)) {
            qos_class_t qosClass;
            int relativePriority;
            if (0 == pthread_get_qos_class_np(pthread, &qosClass, &relativePriority) &&
                QOS_CLASS_UNSPECIFIED != qosClass)
            {
                fprintf(stderr, "\n  QoS class: ");
                switch (qosClass) {
                    case QOS_CLASS_USER_INTERACTIVE:
                        fprintf(stderr, "USER INTERACTIVE");
                        break;
                    case QOS_CLASS_USER_INITIATED:
                        fprintf(stderr, "USER INITIATED");
                        break;
                    case QOS_CLASS_DEFAULT:
                        fprintf(stderr, "DEFAULT");
                        break;
                    case QOS_CLASS_UTILITY:
                        fprintf(stderr, "UTILITY");
                        break;
                    case QOS_CLASS_BACKGROUND:
                        fprintf(stderr, "BACKGROUND");
                        break;
                    default:
                        fprintf(stderr, "Unknown (%u)", qosClass);
                        break;
                }
                if (relativePriority != 0) {
                    fprintf(stderr, "\n  QoS relative priority: %d", relativePriority);
                }
            }
        }

        {
            thread_precedence_policy_data_t precedencePolicyData;
            policyInfoCount = THREAD_PRECEDENCE_POLICY_COUNT;
            getDefault = FALSE;
            if (KERN_SUCCESS == thread_policy_get(thread,
                                                  THREAD_PRECEDENCE_POLICY,
                                                  reinterpret_cast<thread_policy_t>(&precedencePolicyData),
                                                  &policyInfoCount,
                                                  &getDefault))
            {
                if (!getDefault) {
                    fprintf(stderr, "\n  importance = %d", precedencePolicyData.importance);
                }
            }
        }

        {
            thread_extended_policy_data_t extendedPolicyData;
            policyInfoCount = THREAD_EXTENDED_POLICY_COUNT;
            getDefault = FALSE;
            if (KERN_SUCCESS == thread_policy_get(thread,
                                                  THREAD_EXTENDED_POLICY,
                                                  reinterpret_cast<thread_policy_t>(&extendedPolicyData),
                                                  &policyInfoCount,
                                                  &getDefault))
            {
                if (!getDefault) {
                    fprintf(stderr, "\n  timeshare: %s", (extendedPolicyData.timeshare ? "YES" : "NO"));
                }
            }
        }

        {
            thread_time_constraint_policy_data_t timeConstraintPolicyData;
            policyInfoCount = THREAD_TIME_CONSTRAINT_POLICY_COUNT;
            getDefault = FALSE;
            if (KERN_SUCCESS == thread_policy_get(thread,
                                                  THREAD_TIME_CONSTRAINT_POLICY,
                                                  reinterpret_cast<thread_policy_t>(&timeConstraintPolicyData),
                                                  &policyInfoCount,
                                                  &getDefault))
            {
                if (!getDefault) {
                    fprintf(stderr,
                            "\n  realtime:"
                            "\n    period = %u"
                            "\n    computation = %u"
                            "\n    constraint = %u"
                            "\n    preemptible: %s",
                            timeConstraintPolicyData.period,
                            timeConstraintPolicyData.computation,
                            timeConstraintPolicyData.constraint,
                            (timeConstraintPolicyData.preemptible ? "YES" : "NO"));
                }
            }
        }

        {
            thread_extended_info_data_t extendedInfo;
            mach_msg_type_number_t extendedInfoCount = THREAD_EXTENDED_INFO_COUNT;
            if (KERN_SUCCESS == thread_info(thread,
                                            THREAD_EXTENDED_INFO,
                                            reinterpret_cast<thread_info_t>(&extendedInfo),
                                            &extendedInfoCount))
            {
                fprintf(stderr,
                        "\n  priority         = %d"
                        "\n  current priority = %d"
                        "\n  maximum priority = %d"
                        "\n  name: \"%s\"",
                        extendedInfo.pth_priority,
                        extendedInfo.pth_curpri,
                        extendedInfo.pth_maxpriority,
                        extendedInfo.pth_name);
            }
        }

        fprintf(stderr, "\n");
    }

    fflush(stderr);
}

bool logMachError(const char *functionName, mach_error_t error) {
    const bool failed = (error != ERR_SUCCESS);
    if (failed) {
        merror(M_SYSTEM_MESSAGE_DOMAIN, "%s failed: %s (%d)", functionName, mach_error_string(error), error);
    }
    return failed;
}

END_NAMESPACE_MW

<|endoftext|>


<commit_before>/*
This file is part of KDE

  Copyright (C) 1998-2000 Waldo Bastian (bastian@kde.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <iostream>

#include <QApplication>
#include <QClipboard>
#include <QColorDialog>
#include <QCommandLineParser>
#include <QDialogButtonBox>
#include <QMenu>
#include <QMimeData>
#include <QPushButton>
#include <QDebug>

#include <KAboutData>
#include <KLocalizedString>
#include <KHelpMenu>

static const char description[] =
	I18N_NOOP("KDE Color Chooser");

static const char version[] = "v2.0.0";

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);

  KAboutData aboutData("kcolorchooser", i18n("KColorChooser"),
                version, i18n(description), KAboutLicense::BSDL,
                i18n("(c) 2000, Waldo Bastian"));
  aboutData.addAuthor(i18n("Waldo Bastian"), QString(), "bastian@kde.org");
  aboutData.addAuthor(i18n("Hugo Parente Lima"),i18n("KF5 port"), "hugo.pl@gmail.com");
  aboutData.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), i18nc("EMAIL OF TRANSLATORS", "Your emails"));
  aboutData.setProductName("kdelibs/kdeui");
  KLocalizedString::setApplicationDomain("kcolorchooser");
  KAboutData::setApplicationData(aboutData);

  QCommandLineParser parser;
  parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
  aboutData.setupCommandLine(&parser);
  QCommandLineOption print("print", i18n("Print the selected color to stdout."));
  parser.addOption(print);
  QCommandLineOption color("color", i18n("Set initially selected color."), "color");
  parser.addOption(color);
  parser.process(app);
  aboutData.processCommandLine(&parser);

  QColorDialog dlg;
  dlg.setOption(QColorDialog::DontUseNativeDialog);
  QDialogButtonBox *box = dlg.findChild<QDialogButtonBox*>();
  if (!box)
      return 1;

  box->addButton(QDialogButtonBox::Help);

  KHelpMenu *help = new KHelpMenu(&dlg, aboutData);
  QObject::connect(box, &QDialogButtonBox::helpRequested, [=] () {
      QPushButton *button = box->button(QDialogButtonBox::Help);
      QPoint pos = button->pos();
      pos.ry() += button->height();
      pos = box->mapToGlobal(pos);
      help->menu()->exec(pos);
  });

  if (parser.isSet(color)) {
      dlg.setCurrentColor(QColor(parser.value(color)));
  } else {
      const QMimeData* mimeData = QApplication::clipboard()->mimeData(QClipboard::Clipboard);
      QColor clipboardColor = mimeData->colorData().value<QColor>();
      if (clipboardColor.isValid()) {
          dlg.setCurrentColor(clipboardColor);
      }
  }

  dlg.show();
  app.exec();

  const  QColor c = dlg.currentColor();
  if (parser.isSet(print) && c.isValid()) {
      std::cout << c.name().toUtf8().constData() << std::endl;
  }
}
<commit_msg>Fix crash if mimeData is null<commit_after>/*
This file is part of KDE

  Copyright (C) 1998-2000 Waldo Bastian (bastian@kde.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <iostream>

#include <QApplication>
#include <QClipboard>
#include <QColorDialog>
#include <QCommandLineParser>
#include <QDialogButtonBox>
#include <QMenu>
#include <QMimeData>
#include <QPushButton>
#include <QDebug>

#include <KAboutData>
#include <KLocalizedString>
#include <KHelpMenu>

static const char description[] =
	I18N_NOOP("KDE Color Chooser");

static const char version[] = "v2.0.0";

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);

  KAboutData aboutData("kcolorchooser", i18n("KColorChooser"),
                version, i18n(description), KAboutLicense::BSDL,
                i18n("(c) 2000, Waldo Bastian"));
  aboutData.addAuthor(i18n("Waldo Bastian"), QString(), "bastian@kde.org");
  aboutData.addAuthor(i18n("Hugo Parente Lima"),i18n("KF5 port"), "hugo.pl@gmail.com");
  aboutData.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), i18nc("EMAIL OF TRANSLATORS", "Your emails"));
  aboutData.setProductName("kdelibs/kdeui");
  KLocalizedString::setApplicationDomain("kcolorchooser");
  KAboutData::setApplicationData(aboutData);

  QCommandLineParser parser;
  parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
  aboutData.setupCommandLine(&parser);
  QCommandLineOption print("print", i18n("Print the selected color to stdout."));
  parser.addOption(print);
  QCommandLineOption color("color", i18n("Set initially selected color."), "color");
  parser.addOption(color);
  parser.process(app);
  aboutData.processCommandLine(&parser);

  QColorDialog dlg;
  dlg.setOption(QColorDialog::DontUseNativeDialog);
  QDialogButtonBox *box = dlg.findChild<QDialogButtonBox*>();
  if (!box)
      return 1;

  box->addButton(QDialogButtonBox::Help);

  KHelpMenu *help = new KHelpMenu(&dlg, aboutData);
  QObject::connect(box, &QDialogButtonBox::helpRequested, [=] () {
      QPushButton *button = box->button(QDialogButtonBox::Help);
      QPoint pos = button->pos();
      pos.ry() += button->height();
      pos = box->mapToGlobal(pos);
      help->menu()->exec(pos);
  });

  if (parser.isSet(color)) {
      dlg.setCurrentColor(QColor(parser.value(color)));
  } else {
      const QMimeData* mimeData = QApplication::clipboard()->mimeData(QClipboard::Clipboard);
      if (mimeData) {
          QColor clipboardColor = mimeData->colorData().value<QColor>();
          if (clipboardColor.isValid()) {
              dlg.setCurrentColor(clipboardColor);
          }
      }
  }

  dlg.show();
  app.exec();

  const  QColor c = dlg.currentColor();
  if (parser.isSet(print) && c.isValid()) {
      std::cout << c.name().toUtf8().constData() << std::endl;
  }
}
<|endoftext|>


<commit_before>/**
 * << detailed description >>
 *
 * @file TestReactions.cpp
 * @brief << brief description >>
 * @author clonker
 * @date 22.06.16
 */

#include <gtest/gtest.h>
#include <readdy/kernel/singlecpu/reactions/SingleCPUReactions.h>
#include <readdy/model/Kernel.h>
#include <boost/algorithm/string.hpp>
#include <readdy/plugin/KernelProvider.h>
#include <readdy/model/programs/Programs.h>

TEST(SingleCPUTestReactions, CheckInOutTypesAndPositions) {
    using fusion_t = readdy::model::reactions::Fusion;
    using fission_t = readdy::model::reactions::Fission;
    using enzymatic_t = readdy::model::reactions::Enzymatic;
    using conversion_t = readdy::model::reactions::Conversion;
    using death_t = readdy::model::reactions::Death;
    using particle_t = readdy::model::Particle;
    auto kernel = readdy::plugin::KernelProvider::getInstance().create("SingleCPU");
    kernel->getKernelContext().setPeriodicBoundary(false, false, false);
    kernel->getKernelContext().setBoxSize(100, 100, 100);
    const auto diff = kernel->getKernelContext().getShortestDifferenceFun();
    kernel->getKernelContext().setDiffusionConstant("A", .1); // type id 0
    kernel->getKernelContext().setDiffusionConstant("B", .1); // type id 1
    kernel->getKernelContext().setDiffusionConstant("C", .1); // type id 2

    // test conversion
    {
        auto conversion = kernel->getReactionFactory().createReaction<conversion_t>("A->B", 0, 1, 1);
        particle_t p_A{0, 0, 0, 0};
        particle_t p_out{5, 5, 5, 1};
        conversion->perform(p_A, p_A, p_out, p_out);
        EXPECT_EQ(p_out.getType(), conversion->getTypeTo());
        EXPECT_EQ(p_out.getPos(), p_A.getPos());
    }

    // test fusion
    {
        double eductDistance = .4;
        double weight1 = .3, weight2 = .7;
        auto fusion = kernel->getReactionFactory().createReaction<fusion_t>("A+B->C", 0, 1, 2, 1, eductDistance, weight1, weight2);
        particle_t p_out1{50, 50, 50, 70};
        particle_t p_out2{50, 50, 50, 70};
        particle_t p_A{1, 0, 0, 0};
        particle_t p_B{-1, 0, 0, 1};
        fusion->perform(p_A, p_B, p_out1, p_out1);
        fusion->perform(p_B, p_A, p_out2, p_out2);

        EXPECT_EQ(p_out1.getPos(), p_out2.getPos());
        EXPECT_EQ(p_out1.getType(), p_out2.getType());
        EXPECT_EQ(p_out1.getType(), fusion->getTo());

        EXPECT_EQ(readdy::model::Vec3(.4, 0, 0), p_out1.getPos());
    }

    // fission
    {
        double productDistance = .4;
        double weight1 = .3, weight2 = .7;
        auto fission = kernel->getReactionFactory().createReaction<fission_t>("C->A+B", 2, 0, 1, productDistance, 1, weight1, weight2);
        particle_t p_C{0, 0, 0, 2};
        particle_t p_out1{50, 50, 50, 70};
        particle_t p_out2{50, 50, 50, 70};
        fission->perform(p_C, p_C, p_out1, p_out2);

        EXPECT_EQ(p_out1.getType(), fission->getTo1());
        EXPECT_EQ(p_out2.getType(), fission->getTo2());
        auto p_12 = diff(p_out1.getPos(), p_out2.getPos());
        auto p_12_nondirect = p_out2.getPos() - p_out1.getPos();
        EXPECT_EQ(p_12_nondirect, p_12);
        auto distance = sqrt(p_12 * p_12);
        EXPECT_DOUBLE_EQ(productDistance, distance);
    }

    // enzymatic
    {
        auto enzymatic = kernel->getReactionFactory().createReaction<enzymatic_t>("A+C->B+C", 2, 0, 1, 1, .5);
        particle_t p_A{0, 0, 0, 0};
        particle_t p_C{5, 5, 5, 2};
        {
            particle_t p_out1{50, 50, 50, 70};
            particle_t p_out2{50, 50, 50, 70};
            enzymatic->perform(p_A, p_C, p_out1, p_out2);
            if (p_out1.getType() == enzymatic->getCatalyst()) {
                EXPECT_EQ(enzymatic->getCatalyst(), p_out1.getType());
                EXPECT_EQ(enzymatic->getTo(), p_out2.getType());
                EXPECT_EQ(p_C.getPos(), p_out1.getPos());
                EXPECT_EQ(p_A.getPos(), p_out2.getPos());
            } else {
                EXPECT_EQ(enzymatic->getCatalyst(), p_out2.getType());
                EXPECT_EQ(enzymatic->getTo(), p_out1.getType());
                EXPECT_EQ(p_C.getPos(), p_out2.getPos());
                EXPECT_EQ(p_A.getPos(), p_out1.getPos());
            }
        }
        {
            particle_t p_out1{50, 50, 50, 70};
            particle_t p_out2{50, 50, 50, 70};
            enzymatic->perform(p_C, p_A, p_out1, p_out2);
            if (p_out1.getType() == enzymatic->getCatalyst()) {
                EXPECT_EQ(enzymatic->getCatalyst(), p_out1.getType());
                EXPECT_EQ(enzymatic->getTo(), p_out2.getType());
                EXPECT_EQ(p_C.getPos(), p_out1.getPos());
                EXPECT_EQ(p_A.getPos(), p_out2.getPos());
            } else {
                EXPECT_EQ(enzymatic->getCatalyst(), p_out2.getType());
                EXPECT_EQ(enzymatic->getTo(), p_out1.getType());
                EXPECT_EQ(p_C.getPos(), p_out2.getPos());
                EXPECT_EQ(p_A.getPos(), p_out1.getPos());
            }
        }
    }

}

TEST(SingleCPUTestReactions, TestDecay) {
    using fusion_t = readdy::model::reactions::Fusion;
    using fission_t = readdy::model::reactions::Fission;
    using enzymatic_t = readdy::model::reactions::Enzymatic;
    using conversion_t = readdy::model::reactions::Conversion;
    using death_t = readdy::model::reactions::Death;
    using particle_t = readdy::model::Particle;
    auto kernel = readdy::plugin::KernelProvider::getInstance().create("SingleCPU");
    kernel->getKernelContext().setBoxSize(10, 10, 10);
    kernel->getKernelContext().setTimeStep(1);
    kernel->getKernelContext().setDiffusionConstant("X", .25);
    kernel->getKernelContext().registerDeathReaction("X decay", "X", .5);
    kernel->getKernelContext().registerFissionReaction("X fission", "X", "X", "X", .15, .00);

    auto &&integrator = kernel->createProgram<readdy::model::programs::EulerBDIntegrator>();
    auto &&forces = kernel->createProgram<readdy::model::programs::CalculateForces>();
    auto &&neighborList = kernel->createProgram<readdy::model::programs::UpdateNeighborList>();
    auto &&reactionsProgram = kernel->createProgram<readdy::model::programs::reactions::UncontrolledApproximation>();

    auto pp_obs = kernel->createObservable<readdy::model::ParticlePositionObservable>(1);
    auto connection = kernel->connectObservable(pp_obs.get());

    const int n_particles = 200;
    const unsigned int typeId = kernel->getKernelContext().getParticleTypeID("X");
    std::vector<readdy::model::Particle> particlesToBeginWith{n_particles, {0, 0, 0, typeId}};
    kernel->getKernelStateModel().addParticles(particlesToBeginWith);

    neighborList->execute();
    for (size_t t = 0; t < 20; t++) {

        forces->execute();
        integrator->execute();
        neighborList->execute();
        reactionsProgram->execute();

        pp_obs->evaluate();

    }

    EXPECT_EQ(0, kernel->getKernelStateModel().getParticlePositions().size());

    connection.disconnect();
}

/**
 * Setting:
 *  - Five particle types A,B,C,D,E.
 *  - They are instantiated such that there is one A particle, one B and one C particle.
 *  - B and C particle are within the reaction radius of their assigned reaction.
 * Reactions (all with rate 1, dt = 1):
 *  - A has no interaction with the other particles and dies after one time step (death rate 1)
 *  - B + C -> E
 *  - B + D -> A
 *  - E -> A
 *  - C -> D
 * Expected:
 *  - After one time step, the A particle dies and either C -> D or B + C -> E
 *  - After two time steps:
 *      - If previously C -> D, one is left with one B and one D particle,
 *        which will react to one A particle
 *      - If previously B + C -> E, one is left with one E particle,
 *        which will convert to one A particle
 *  - After three time steps, one is left with one A particle which then will
 *    decay within the next timestep, leaving no particles.
 * Assert:
 *   - t = 0: n_particles == 3 with 1x A, 1x B, 1x C
 *   - t = 1: n_particles == 2 || n_particles == 1 with (1x B, 1x D) || 1x E
 *   - t = 2: n_particles == 1 with 1x A
 *   - t > 2: n_particles == 0
 */
TEST(SingleCPUTestReactions, TestMultipleReactionTypes) {
    using fusion_t = readdy::model::reactions::Fusion;
    using fission_t = readdy::model::reactions::Fission;
    using enzymatic_t = readdy::model::reactions::Enzymatic;
    using conversion_t = readdy::model::reactions::Conversion;
    using death_t = readdy::model::reactions::Death;
    using particle_t = readdy::model::Particle;
    auto kernel = readdy::plugin::KernelProvider::getInstance().create("SingleCPU");
    kernel->getKernelContext().setBoxSize(10, 10, 10);
    kernel->getKernelContext().setTimeStep(1);

    kernel->getKernelContext().setDiffusionConstant("A", .25);
    kernel->getKernelContext().setDiffusionConstant("B", .25);
    kernel->getKernelContext().setDiffusionConstant("C", .25);
    kernel->getKernelContext().setDiffusionConstant("D", .25);
    kernel->getKernelContext().setDiffusionConstant("E", .25);

    kernel->getKernelContext().registerDeathReaction("A decay", "A", 1);
    kernel->getKernelContext().registerFusionReaction("B+C->E", "B", "C", "E", 1, 17);
    kernel->getKernelContext().registerFusionReaction("B+D->A", "B", "D", "A", 1, 17);
    kernel->getKernelContext().registerConversionReaction("E->A", "E", "A", 1);
    kernel->getKernelContext().registerConversionReaction("C->D", "C", "D", 1);

    auto &&integrator = kernel->createProgram<readdy::model::programs::EulerBDIntegrator>();
    auto &&forces = kernel->createProgram<readdy::model::programs::CalculateForces>();
    auto &&neighborList = kernel->createProgram<readdy::model::programs::UpdateNeighborList>();
    auto &&reactionsProgram = kernel->createProgram<readdy::model::programs::reactions::UncontrolledApproximation>();

    const auto typeId_A = kernel->getKernelContext().getParticleTypeID("A");
    const auto typeId_B = kernel->getKernelContext().getParticleTypeID("B");
    const auto typeId_C = kernel->getKernelContext().getParticleTypeID("C");
    const auto typeId_D = kernel->getKernelContext().getParticleTypeID("D");
    const auto typeId_E = kernel->getKernelContext().getParticleTypeID("E");

    kernel->getKernelStateModel().addParticle({4, 4, 4, typeId_A});
    kernel->getKernelStateModel().addParticle({-2, 0, 0, typeId_B});
    kernel->getKernelStateModel().addParticle({2, 0, 0, typeId_C});

    auto pred_contains_A = [=](const readdy::model::Particle &p) { return p.getType() == typeId_A; };
    auto pred_contains_B = [=](const readdy::model::Particle &p) { return p.getType() == typeId_B; };
    auto pred_contains_C = [=](const readdy::model::Particle &p) { return p.getType() == typeId_C; };
    auto pred_contains_D = [=](const readdy::model::Particle &p) { return p.getType() == typeId_D; };
    auto pred_contains_E = [=](const readdy::model::Particle &p) { return p.getType() == typeId_E; };

    for (unsigned int t = 0; t < 4; t++) {

        const auto particles = kernel->getKernelStateModel().getParticles();

        bool containsA = std::find_if(particles.begin(), particles.end(), pred_contains_A) != particles.end();
        bool containsB = std::find_if(particles.begin(), particles.end(), pred_contains_B) != particles.end();
        bool containsC = std::find_if(particles.begin(), particles.end(), pred_contains_C) != particles.end();
        bool containsD = std::find_if(particles.begin(), particles.end(), pred_contains_D) != particles.end();
        bool containsE = std::find_if(particles.begin(), particles.end(), pred_contains_E) != particles.end();

        switch (t) {
            case 0: {
                EXPECT_EQ(3, particles.size());
                EXPECT_TRUE(containsA);
                EXPECT_TRUE(containsB);
                EXPECT_TRUE(containsC);
                break;
            }
            case 1: {
                EXPECT_TRUE(particles.size() == 2 || particles.size() == 1);
                if (particles.size() == 2) {
                    BOOST_LOG_TRIVIAL(debug) << "------> conversion happened";
                    EXPECT_TRUE(containsB);
                    EXPECT_TRUE(containsD);
                } else {
                    BOOST_LOG_TRIVIAL(debug) << "------> fusion happened";
                    EXPECT_TRUE(containsE);
                }
                break;
            }
            case 2: {
                EXPECT_EQ(1, particles.size());
                EXPECT_TRUE(containsA);
                break;
            }
            case 3: {
                EXPECT_EQ(0, particles.size());
                break;
            }
            default: {
                FAIL();
            }
        }

        // propagate
        neighborList->execute();
        forces->execute();
        integrator->execute();

        neighborList->execute();
        reactionsProgram->execute();
        kernel->evaluateObservables(t);
    }
}
<commit_msg>[test/singlecpu] added missing context.configure<commit_after>/**
 * << detailed description >>
 *
 * @file TestReactions.cpp
 * @brief << brief description >>
 * @author clonker
 * @date 22.06.16
 */

#include <gtest/gtest.h>
#include <readdy/kernel/singlecpu/reactions/SingleCPUReactions.h>
#include <readdy/model/Kernel.h>
#include <boost/algorithm/string.hpp>
#include <readdy/plugin/KernelProvider.h>
#include <readdy/model/programs/Programs.h>

TEST(SingleCPUTestReactions, CheckInOutTypesAndPositions) {
    using fusion_t = readdy::model::reactions::Fusion;
    using fission_t = readdy::model::reactions::Fission;
    using enzymatic_t = readdy::model::reactions::Enzymatic;
    using conversion_t = readdy::model::reactions::Conversion;
    using death_t = readdy::model::reactions::Death;
    using particle_t = readdy::model::Particle;
    auto kernel = readdy::plugin::KernelProvider::getInstance().create("SingleCPU");
    kernel->getKernelContext().setPeriodicBoundary(false, false, false);
    kernel->getKernelContext().setBoxSize(100, 100, 100);
    const auto diff = kernel->getKernelContext().getShortestDifferenceFun();
    kernel->getKernelContext().setDiffusionConstant("A", .1); // type id 0
    kernel->getKernelContext().setDiffusionConstant("B", .1); // type id 1
    kernel->getKernelContext().setDiffusionConstant("C", .1); // type id 2

    // test conversion
    {
        auto conversion = kernel->getReactionFactory().createReaction<conversion_t>("A->B", 0, 1, 1);
        particle_t p_A{0, 0, 0, 0};
        particle_t p_out{5, 5, 5, 1};
        conversion->perform(p_A, p_A, p_out, p_out);
        EXPECT_EQ(p_out.getType(), conversion->getTypeTo());
        EXPECT_EQ(p_out.getPos(), p_A.getPos());
    }

    // test fusion
    {
        double eductDistance = .4;
        double weight1 = .3, weight2 = .7;
        auto fusion = kernel->getReactionFactory().createReaction<fusion_t>("A+B->C", 0, 1, 2, 1, eductDistance, weight1, weight2);
        particle_t p_out1{50, 50, 50, 70};
        particle_t p_out2{50, 50, 50, 70};
        particle_t p_A{1, 0, 0, 0};
        particle_t p_B{-1, 0, 0, 1};
        fusion->perform(p_A, p_B, p_out1, p_out1);
        fusion->perform(p_B, p_A, p_out2, p_out2);

        EXPECT_EQ(p_out1.getPos(), p_out2.getPos());
        EXPECT_EQ(p_out1.getType(), p_out2.getType());
        EXPECT_EQ(p_out1.getType(), fusion->getTo());

        EXPECT_EQ(readdy::model::Vec3(.4, 0, 0), p_out1.getPos());
    }

    // fission
    {
        double productDistance = .4;
        double weight1 = .3, weight2 = .7;
        auto fission = kernel->getReactionFactory().createReaction<fission_t>("C->A+B", 2, 0, 1, productDistance, 1, weight1, weight2);
        particle_t p_C{0, 0, 0, 2};
        particle_t p_out1{50, 50, 50, 70};
        particle_t p_out2{50, 50, 50, 70};
        fission->perform(p_C, p_C, p_out1, p_out2);

        EXPECT_EQ(p_out1.getType(), fission->getTo1());
        EXPECT_EQ(p_out2.getType(), fission->getTo2());
        auto p_12 = diff(p_out1.getPos(), p_out2.getPos());
        auto p_12_nondirect = p_out2.getPos() - p_out1.getPos();
        EXPECT_EQ(p_12_nondirect, p_12);
        auto distance = sqrt(p_12 * p_12);
        EXPECT_DOUBLE_EQ(productDistance, distance);
    }

    // enzymatic
    {
        auto enzymatic = kernel->getReactionFactory().createReaction<enzymatic_t>("A+C->B+C", 2, 0, 1, 1, .5);
        particle_t p_A{0, 0, 0, 0};
        particle_t p_C{5, 5, 5, 2};
        {
            particle_t p_out1{50, 50, 50, 70};
            particle_t p_out2{50, 50, 50, 70};
            enzymatic->perform(p_A, p_C, p_out1, p_out2);
            if (p_out1.getType() == enzymatic->getCatalyst()) {
                EXPECT_EQ(enzymatic->getCatalyst(), p_out1.getType());
                EXPECT_EQ(enzymatic->getTo(), p_out2.getType());
                EXPECT_EQ(p_C.getPos(), p_out1.getPos());
                EXPECT_EQ(p_A.getPos(), p_out2.getPos());
            } else {
                EXPECT_EQ(enzymatic->getCatalyst(), p_out2.getType());
                EXPECT_EQ(enzymatic->getTo(), p_out1.getType());
                EXPECT_EQ(p_C.getPos(), p_out2.getPos());
                EXPECT_EQ(p_A.getPos(), p_out1.getPos());
            }
        }
        {
            particle_t p_out1{50, 50, 50, 70};
            particle_t p_out2{50, 50, 50, 70};
            enzymatic->perform(p_C, p_A, p_out1, p_out2);
            if (p_out1.getType() == enzymatic->getCatalyst()) {
                EXPECT_EQ(enzymatic->getCatalyst(), p_out1.getType());
                EXPECT_EQ(enzymatic->getTo(), p_out2.getType());
                EXPECT_EQ(p_C.getPos(), p_out1.getPos());
                EXPECT_EQ(p_A.getPos(), p_out2.getPos());
            } else {
                EXPECT_EQ(enzymatic->getCatalyst(), p_out2.getType());
                EXPECT_EQ(enzymatic->getTo(), p_out1.getType());
                EXPECT_EQ(p_C.getPos(), p_out2.getPos());
                EXPECT_EQ(p_A.getPos(), p_out1.getPos());
            }
        }
    }

}

TEST(SingleCPUTestReactions, TestDecay) {
    using fusion_t = readdy::model::reactions::Fusion;
    using fission_t = readdy::model::reactions::Fission;
    using enzymatic_t = readdy::model::reactions::Enzymatic;
    using conversion_t = readdy::model::reactions::Conversion;
    using death_t = readdy::model::reactions::Death;
    using particle_t = readdy::model::Particle;
    auto kernel = readdy::plugin::KernelProvider::getInstance().create("SingleCPU");
    kernel->getKernelContext().setBoxSize(10, 10, 10);
    kernel->getKernelContext().setTimeStep(1);
    kernel->getKernelContext().setDiffusionConstant("X", .25);
    kernel->getKernelContext().registerDeathReaction("X decay", "X", .5);
    kernel->getKernelContext().registerFissionReaction("X fission", "X", "X", "X", .15, .00);

    auto &&integrator = kernel->createProgram<readdy::model::programs::EulerBDIntegrator>();
    auto &&forces = kernel->createProgram<readdy::model::programs::CalculateForces>();
    auto &&neighborList = kernel->createProgram<readdy::model::programs::UpdateNeighborList>();
    auto &&reactionsProgram = kernel->createProgram<readdy::model::programs::reactions::UncontrolledApproximation>();

    auto pp_obs = kernel->createObservable<readdy::model::ParticlePositionObservable>(1);
    auto connection = kernel->connectObservable(pp_obs.get());

    const int n_particles = 200;
    const unsigned int typeId = kernel->getKernelContext().getParticleTypeID("X");
    std::vector<readdy::model::Particle> particlesToBeginWith{n_particles, {0, 0, 0, typeId}};
    kernel->getKernelStateModel().addParticles(particlesToBeginWith);
    kernel->getKernelContext().configure();
    neighborList->execute();
    for (size_t t = 0; t < 20; t++) {

        forces->execute();
        integrator->execute();
        neighborList->execute();
        reactionsProgram->execute();

        pp_obs->evaluate();

    }

    EXPECT_EQ(0, kernel->getKernelStateModel().getParticlePositions().size());

    connection.disconnect();
}

/**
 * Setting:
 *  - Five particle types A,B,C,D,E.
 *  - They are instantiated such that there is one A particle, one B and one C particle.
 *  - B and C particle are within the reaction radius of their assigned reaction.
 * Reactions (all with rate 1, dt = 1):
 *  - A has no interaction with the other particles and dies after one time step (death rate 1)
 *  - B + C -> E
 *  - B + D -> A
 *  - E -> A
 *  - C -> D
 * Expected:
 *  - After one time step, the A particle dies and either C -> D or B + C -> E
 *  - After two time steps:
 *      - If previously C -> D, one is left with one B and one D particle,
 *        which will react to one A particle
 *      - If previously B + C -> E, one is left with one E particle,
 *        which will convert to one A particle
 *  - After three time steps, one is left with one A particle which then will
 *    decay within the next timestep, leaving no particles.
 * Assert:
 *   - t = 0: n_particles == 3 with 1x A, 1x B, 1x C
 *   - t = 1: n_particles == 2 || n_particles == 1 with (1x B, 1x D) || 1x E
 *   - t = 2: n_particles == 1 with 1x A
 *   - t > 2: n_particles == 0
 */
TEST(SingleCPUTestReactions, TestMultipleReactionTypes) {
    using fusion_t = readdy::model::reactions::Fusion;
    using fission_t = readdy::model::reactions::Fission;
    using enzymatic_t = readdy::model::reactions::Enzymatic;
    using conversion_t = readdy::model::reactions::Conversion;
    using death_t = readdy::model::reactions::Death;
    using particle_t = readdy::model::Particle;
    auto kernel = readdy::plugin::KernelProvider::getInstance().create("SingleCPU");
    kernel->getKernelContext().setBoxSize(10, 10, 10);
    kernel->getKernelContext().setTimeStep(1);

    kernel->getKernelContext().setDiffusionConstant("A", .25);
    kernel->getKernelContext().setDiffusionConstant("B", .25);
    kernel->getKernelContext().setDiffusionConstant("C", .25);
    kernel->getKernelContext().setDiffusionConstant("D", .25);
    kernel->getKernelContext().setDiffusionConstant("E", .25);

    kernel->getKernelContext().registerDeathReaction("A decay", "A", 1);
    kernel->getKernelContext().registerFusionReaction("B+C->E", "B", "C", "E", 1, 17);
    kernel->getKernelContext().registerFusionReaction("B+D->A", "B", "D", "A", 1, 17);
    kernel->getKernelContext().registerConversionReaction("E->A", "E", "A", 1);
    kernel->getKernelContext().registerConversionReaction("C->D", "C", "D", 1);

    auto &&integrator = kernel->createProgram<readdy::model::programs::EulerBDIntegrator>();
    auto &&forces = kernel->createProgram<readdy::model::programs::CalculateForces>();
    auto &&neighborList = kernel->createProgram<readdy::model::programs::UpdateNeighborList>();
    auto &&reactionsProgram = kernel->createProgram<readdy::model::programs::reactions::UncontrolledApproximation>();

    const auto typeId_A = kernel->getKernelContext().getParticleTypeID("A");
    const auto typeId_B = kernel->getKernelContext().getParticleTypeID("B");
    const auto typeId_C = kernel->getKernelContext().getParticleTypeID("C");
    const auto typeId_D = kernel->getKernelContext().getParticleTypeID("D");
    const auto typeId_E = kernel->getKernelContext().getParticleTypeID("E");

    kernel->getKernelStateModel().addParticle({4, 4, 4, typeId_A});
    kernel->getKernelStateModel().addParticle({-2, 0, 0, typeId_B});
    kernel->getKernelStateModel().addParticle({2, 0, 0, typeId_C});

    auto pred_contains_A = [=](const readdy::model::Particle &p) { return p.getType() == typeId_A; };
    auto pred_contains_B = [=](const readdy::model::Particle &p) { return p.getType() == typeId_B; };
    auto pred_contains_C = [=](const readdy::model::Particle &p) { return p.getType() == typeId_C; };
    auto pred_contains_D = [=](const readdy::model::Particle &p) { return p.getType() == typeId_D; };
    auto pred_contains_E = [=](const readdy::model::Particle &p) { return p.getType() == typeId_E; };

    kernel->getKernelContext().configure();

    for (unsigned int t = 0; t < 4; t++) {

        const auto particles = kernel->getKernelStateModel().getParticles();

        bool containsA = std::find_if(particles.begin(), particles.end(), pred_contains_A) != particles.end();
        bool containsB = std::find_if(particles.begin(), particles.end(), pred_contains_B) != particles.end();
        bool containsC = std::find_if(particles.begin(), particles.end(), pred_contains_C) != particles.end();
        bool containsD = std::find_if(particles.begin(), particles.end(), pred_contains_D) != particles.end();
        bool containsE = std::find_if(particles.begin(), particles.end(), pred_contains_E) != particles.end();

        switch (t) {
            case 0: {
                EXPECT_EQ(3, particles.size());
                EXPECT_TRUE(containsA);
                EXPECT_TRUE(containsB);
                EXPECT_TRUE(containsC);
                break;
            }
            case 1: {
                EXPECT_TRUE(particles.size() == 2 || particles.size() == 1);
                if (particles.size() == 2) {
                    BOOST_LOG_TRIVIAL(debug) << "------> conversion happened";
                    EXPECT_TRUE(containsB);
                    EXPECT_TRUE(containsD);
                } else {
                    BOOST_LOG_TRIVIAL(debug) << "------> fusion happened";
                    EXPECT_TRUE(containsE);
                }
                break;
            }
            case 2: {
                EXPECT_EQ(1, particles.size());
                EXPECT_TRUE(containsA);
                break;
            }
            case 3: {
                EXPECT_EQ(0, particles.size());
                break;
            }
            default: {
                FAIL();
            }
        }

        // propagate
        neighborList->execute();
        forces->execute();
        integrator->execute();

        neighborList->execute();
        reactionsProgram->execute();
        kernel->evaluateObservables(t);
    }
}
<|endoftext|>