//-----------------------------------------------------------------------------
#include <apps/Common/CommonGUIFunctions.h>
#include <apps/Common/wxAbstraction.h>
#include <common/STLHelper.h>
#include "GlobalDataStorage.h"
#include "icons.h"
#include "PropData.h"
#include "PropViewFrame.h"
#include "ValuesFromUserDlg.h"

#include <apps/Common/wxIncludePrologue.h>
#include <wx/arrstr.h>
#include <wx/checklst.h>
#include <wx/file.h>
#include <wx/listbox.h>
#include <wx/progdlg.h>
#include <apps/Common/wxIncludeEpilogue.h>

using namespace std;
using namespace mvIMPACT::acquire::GenICam;

//-----------------------------------------------------------------------------
string BinaryDataFromString( const string& value )
//-----------------------------------------------------------------------------
{
    const string::size_type valueLength = value.size();
    const string::size_type bufSize = ( valueLength + 1 ) / 2;
    string binaryValue;
    binaryValue.resize( bufSize );
    for( string::size_type i = 0; i < bufSize; i++ )
    {
        string token( value.substr( i * 2, ( ( ( i * 2 ) + 2 ) > valueLength ) ? 1 : 2 ) );
        unsigned int tmp;
#if defined(_MSC_VER) && (_MSC_VER >= 1400) // is at least VC 2005 compiler?
        sscanf_s( token.c_str(), "%x", &tmp );
#else
        sscanf( token.c_str(), "%x", &tmp );
#endif // #if defined(_MSC_VER) && (_MSC_VER >= 1400) // is at least VC 2005 compiler?
        binaryValue[i] = static_cast<string::value_type>( tmp );
    }
    return binaryValue;
}

//-----------------------------------------------------------------------------
string BinaryDataToString( const string& value )
//-----------------------------------------------------------------------------
{
    const string::size_type len = value.size();
    string result;
    result.resize( len * 2 );
    const size_t BUF_SIZE = 3;
    char buf[BUF_SIZE];
    for( string::size_type i = 0; i < len; i++ )
    {
#if defined(_MSC_VER) && (_MSC_VER >= 1400) // is at least VC 2005 compiler?
        sprintf_s( buf, 3, "%02x", static_cast<unsigned char>( value[i] ) );
#else
        sprintf( buf, "%02x", static_cast<unsigned char>( value[i] ) );
#endif // #if defined(_MSC_VER) && (_MSC_VER >= 1400) // is at least VC 2005 compiler?
        result[i * 2]   = buf[0];
        result[i * 2 + 1] = buf[1];
    }
    return result;
}

//-----------------------------------------------------------------------------
void WriteFile( const void* pBuf, size_t bufSize, const wxString& pathName, wxTextCtrl* pTextCtrl )
//-----------------------------------------------------------------------------
{
    wxFile file( pathName.c_str(), wxFile::write );
    if( !file.IsOpened() )
    {
        WriteToTextCtrl( pTextCtrl, wxString::Format( wxT( "Storing of %s failed. Could not open file.\n" ), pathName.c_str() ), wxTextAttr( *wxRED ) );
        return;
    }
    size_t bytesWritten = file.Write( pBuf, bufSize );
    if( bytesWritten < bufSize )
    {
        WriteToTextCtrl( pTextCtrl, wxString::Format( wxT( "Storing of %s failed. Could not write all data.\n" ), pathName.c_str() ), wxTextAttr( *wxRED ) );
        return;
    }
    WriteToTextCtrl( pTextCtrl, wxString::Format( wxT( "Storing of %s was successful.\n" ), pathName.c_str() ) );
}

//=============================================================================
//================= Implementation CollectDeviceInformationThread =============
//=============================================================================
//------------------------------------------------------------------------------
class CollectDeviceInformationThread : public wxThread
//------------------------------------------------------------------------------
{
    const mvIMPACT::acquire::DeviceManager& devMgr_;
    mvIMPACT::acquire::GenICam::InterfaceModule im_;
    map<wxString, bool> deviceInformation_;
protected:
    void* Entry( void )
    {
        try
        {
            if( im_.deviceID.isValid() && im_.deviceSelector.isValid() )
            {
                if( im_.deviceID.readS().length() > 0 ) // even if there is NO device, the deviceSelector will contain one 'empty' entry...
                {
                    const int64_type deviceCount = im_.deviceSelector.getMaxValue() + 1;
                    for( int64_type i = 0; i < deviceCount; i++ )
                    {
                        im_.deviceSelector.write( i );
                        const string serial( im_.deviceSerialNumber.isValid() ? im_.deviceSerialNumber.readS() : im_.deviceID.readS() );
                        const Device* const pDev = devMgr_.getDeviceBySerial( serial );
                        const bool boInUse = pDev && pDev->isInUse();
                        deviceInformation_.insert( make_pair( wxString::Format( wxT( "%s(%s)%s" ), ConvertedString( serial ).c_str(), ConvertedString( im_.deviceModelName.isValid() ? im_.deviceModelName.readS() : "UNKNOWN MODEL" ).c_str(), boInUse ? wxT( " - IN USE!" ) : wxT( "" ) ), boInUse ) );
                    }
                }
            }
        }
        catch( const ImpactAcquireException& ) {}
        return 0;
    }
public:
    explicit CollectDeviceInformationThread( const mvIMPACT::acquire::DeviceManager& devMgr, mvIMPACT::acquire::GenICam::SystemModule& systemModule, unsigned int interfaceIndex ) : wxThread( wxTHREAD_JOINABLE ),
        devMgr_( devMgr ), im_( systemModule, interfaceIndex ), deviceInformation_() {}
    const pair<wxString, map<wxString, bool> > GetResults( void ) const
    {
        return make_pair( ConvertedString( im_.interfaceID.read() ), deviceInformation_ );
    }
};

//=============================================================================
//================= Implementation HEXStringValidator =========================
//=============================================================================
//-----------------------------------------------------------------------------
HEXStringValidator::HEXStringValidator( wxString* valPtr /* = NULL */ ) : wxTextValidator( wxFILTER_INCLUDE_CHAR_LIST, valPtr )
//-----------------------------------------------------------------------------
{
    wxArrayString strings;
    strings.push_back( wxT( "a" ) );
    strings.push_back( wxT( "b" ) );
    strings.push_back( wxT( "c" ) );
    strings.push_back( wxT( "d" ) );
    strings.push_back( wxT( "e" ) );
    strings.push_back( wxT( "f" ) );
    strings.push_back( wxT( "A" ) );
    strings.push_back( wxT( "B" ) );
    strings.push_back( wxT( "C" ) );
    strings.push_back( wxT( "D" ) );
    strings.push_back( wxT( "E" ) );
    strings.push_back( wxT( "F" ) );
    for( unsigned int i = 0; i <= 9; i++ )
    {
        wxString s;
        s << i;
        strings.push_back( s );
    }
    SetIncludes( strings );
}

//=============================================================================
//============== Implementation OkAndCancelDlg ================================
//=============================================================================
BEGIN_EVENT_TABLE( OkAndCancelDlg, wxDialog )
    EVT_BUTTON( widBtnOk, OkAndCancelDlg::OnBtnOk )
    EVT_BUTTON( widBtnCancel, OkAndCancelDlg::OnBtnCancel )
    EVT_BUTTON( widBtnApply, OkAndCancelDlg::OnBtnApply )
END_EVENT_TABLE()

//-----------------------------------------------------------------------------
OkAndCancelDlg::OkAndCancelDlg( wxWindow* pParent, wxWindowID id, const wxString& title, const wxPoint& pos /*= wxDefaultPosition*/,
                                const wxSize& size /*= wxDefaultSize*/, long style /*= wxDEFAULT_DIALOG_STYLE*/, const wxString& name /* = "OkAndCancelDlg" */ )
    : wxDialog( pParent, id, title, pos, size, style, name ), pBtnApply_( 0 ), pBtnCancel_( 0 ), pBtnOk_( 0 )
//-----------------------------------------------------------------------------
{

}

//-----------------------------------------------------------------------------
void OkAndCancelDlg::AddButtons( wxWindow* pWindow, wxSizer* pSizer, bool boCreateApplyButton /* = false */ )
//-----------------------------------------------------------------------------
{
    // lower line of buttons
    wxBoxSizer* pButtonSizer = new wxBoxSizer( wxHORIZONTAL );
    pButtonSizer->AddStretchSpacer( 100 );
    pBtnOk_ = new wxButton( pWindow, widBtnOk, wxT( "&Ok" ) );
    pButtonSizer->Add( pBtnOk_, wxSizerFlags().Border( wxALL, 7 ) );
    pBtnCancel_ = new wxButton( pWindow, widBtnCancel, wxT( "&Cancel" ) );
    pButtonSizer->Add( pBtnCancel_, wxSizerFlags().Border( wxALL, 7 ) );
    if( boCreateApplyButton )
    {
        pBtnApply_ = new wxButton( pWindow, widBtnApply, wxT( "&Apply" ) );
        pButtonSizer->Add( pBtnApply_, wxSizerFlags().Border( wxALL, 7 ) );
    }
    pSizer->AddSpacer( 10 );
    pSizer->Add( pButtonSizer, wxSizerFlags().Expand() );
}

//-----------------------------------------------------------------------------
void OkAndCancelDlg::FinalizeDlgCreation( wxWindow* pWindow, wxSizer* pSizer )
//-----------------------------------------------------------------------------
{
    pWindow->SetSizer( pSizer );
    pSizer->SetSizeHints( this );
    SetClientSize( pSizer->GetMinSize() );
    SetSizeHints( GetSize() );
}

//=============================================================================
//============== Implementation ValuesFromUserDlg =============================
//=============================================================================
//-----------------------------------------------------------------------------
ValuesFromUserDlg::ValuesFromUserDlg( wxWindow* pParent, const wxString& title, const vector<ValueData*>& inputData )
    : OkAndCancelDlg( pParent, wxID_ANY, title )
//-----------------------------------------------------------------------------
{
    /*
        |-------------------------------------|
        | pTopDownSizer                       |
        |                spacer               |
        | |---------------------------------| |
        | | pGridSizer                      | |
        | |---------------------------------| |
        |                spacer               |
        | |---------------------------------| |
        | | pButtonSizer                    | |
        | |---------------------------------| |
        |-------------------------------------|
    */

    wxBoxSizer* pTopDownSizer = new wxBoxSizer( wxVERTICAL );
    pTopDownSizer->AddSpacer( 10 );

    wxPanel* pPanel = new wxPanel( this );

    const int colCount = static_cast<int>( inputData.size() );
    userInputData_.resize( colCount );
    ctrls_.resize( colCount );
    wxFlexGridSizer* pGridSizer = new wxFlexGridSizer( 2 );
    for( int i = 0; i < colCount; i++ )
    {
        pGridSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxString( wxT( " " ) ) + inputData[i]->caption_ ) );
        wxControl* p = 0;
        if( dynamic_cast<ValueRangeData*>( inputData[i] ) )
        {
            ValueRangeData* pData = dynamic_cast<ValueRangeData*>( inputData[i] );
            p = new wxSpinCtrl( pPanel, widFirst + i, wxString::Format( wxT( "%d" ), pData->def_ ), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, pData->min_, pData->max_, pData->def_ );
        }
        else if( dynamic_cast<ValueChoiceData*>( inputData[i] ) )
        {
            ValueChoiceData* pData = dynamic_cast<ValueChoiceData*>( inputData[i] );
            p = new wxComboBox( pPanel, widFirst + i, pData->choices_[0], wxDefaultPosition, wxDefaultSize, pData->choices_, wxCB_DROPDOWN | wxCB_READONLY );
        }
        else
        {
            wxASSERT( !"Invalid data type detected!" );
        }
        pGridSizer->Add( p, wxSizerFlags().Expand() );
        ctrls_[i] = p;
    }
    pTopDownSizer->Add( pGridSizer );
    AddButtons( pPanel, pTopDownSizer );
    FinalizeDlgCreation( pPanel, pTopDownSizer );
}

//=============================================================================
//============== Implementation SettingHierarchyDlg ===========================
//=============================================================================
//-----------------------------------------------------------------------------
SettingHierarchyDlg::SettingHierarchyDlg( wxWindow* pParent, const wxString& title, const StringToStringMap& settingRelationships )
    : OkAndCancelDlg( pParent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX )
//-----------------------------------------------------------------------------
{
    /*
        |-------------------------------------|
        | pTopDownSizer                       |
        |                spacer               |
        | |---------------------------------| |
        | | pTreeCtrl                       | |
        | |---------------------------------| |
        |                spacer               |
        | |---------------------------------| |
        | | pButtonSizer                    | |
        | |---------------------------------| |
        |-------------------------------------|
    */

    wxBoxSizer* pTopDownSizer = new wxBoxSizer( wxVERTICAL );
    pTopDownSizer->AddSpacer( 10 );

    wxPanel* pPanel = new wxPanel( this );

    wxTreeCtrl* pTreeCtrl = new wxTreeCtrl( pPanel, wxID_ANY );
    wxTreeItemId rootId = pTreeCtrl->AddRoot( wxT( "Base" ) );
    PopulateTreeCtrl( pTreeCtrl, rootId, wxString( wxT( "Base" ) ), settingRelationships );
    pTreeCtrl->ExpandAll();
    pTopDownSizer->Add( pTreeCtrl, wxSizerFlags( 3 ).Expand() );
    AddButtons( pPanel, pTopDownSizer );
    FinalizeDlgCreation( pPanel, pTopDownSizer );
}

//-----------------------------------------------------------------------------
void SettingHierarchyDlg::PopulateTreeCtrl( wxTreeCtrl* pTreeCtrl, wxTreeItemId currentItem, const wxString& currentItemName, const StringToStringMap& settingRelationships )
//-----------------------------------------------------------------------------
{
    StringToStringMap::const_iterator it = settingRelationships.begin();
    StringToStringMap::const_iterator itEND = settingRelationships.end();
    while( it != itEND )
    {
        if( it->second == currentItemName )
        {
            wxTreeItemId newItem = pTreeCtrl->AppendItem( currentItem, it->first );
            PopulateTreeCtrl( pTreeCtrl, newItem, it->first, settingRelationships );
        }
        ++it;
    }
}

//=============================================================================
//============== Implementation DetailedRequestInformationDlg =================
//=============================================================================

BEGIN_EVENT_TABLE( DetailedRequestInformationDlg, OkAndCancelDlg )
    EVT_SPINCTRL( widSCRequestSelector, DetailedRequestInformationDlg::OnSCRequestSelectorChanged )
#ifdef BUILD_WITH_TEXT_EVENTS_FOR_SPINCTRL // Unfortunately on Linux wxWidgets 2.6.x - ??? handling these messages will cause problems, while on Windows not doing so will not always update the GUI as desired :-(
    EVT_TEXT( widSCRequestSelector, DetailedRequestInformationDlg::OnSCRequestSelectorTextChanged )
#endif // #ifdef BUILD_WITH_TEXT_EVENTS_FOR_SPINCTRL
END_EVENT_TABLE()

//-----------------------------------------------------------------------------
DetailedRequestInformationDlg::DetailedRequestInformationDlg( wxWindow* pParent, const wxString& title, mvIMPACT::acquire::FunctionInterface* pFI )
    : OkAndCancelDlg( pParent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX ),
      pFI_( pFI ), pTreeCtrl_( 0 )
//-----------------------------------------------------------------------------
{
    /*
        |-------------------------------------|
        | pTopDownSizer                       |
        |                spacer               |
        | |---------------------------------| |
        | | pLeftRightSizer                 | |
        | |---------------------------------| |
        |                spacer               |
        | |---------------------------------| |
        | | property display                | |
        | |---------------------------------| |
        |                spacer               |
        | |---------------------------------| |
        | | pButtonSizer                    | |
        | |---------------------------------| |
        |-------------------------------------|
    */

    wxBoxSizer* pTopDownSizer = new wxBoxSizer( wxVERTICAL );
    wxPanel* pPanel = new wxPanel( this );

    wxBoxSizer* pLeftRightSizer = new wxBoxSizer( wxHORIZONTAL );
    pSCRequestSelector_ = new wxSpinCtrl( pPanel, widSCRequestSelector, wxT( "0" ), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, pFI_->requestCount() - 1, 1 );
    pSCRequestSelector_->SetToolTip( wxT( "Can be used to quickly move within the requests currently allocated" ) );
    pLeftRightSizer->AddSpacer( 10 );
    pLeftRightSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxT( "Request Selector: " ) ), wxSizerFlags().Align( wxALIGN_CENTER_VERTICAL ) );
    pLeftRightSizer->AddSpacer( 5 );
    pLeftRightSizer->Add( pSCRequestSelector_, wxSizerFlags().Expand() );

    pTreeCtrl_ = new wxTreeCtrl( pPanel, wxID_ANY );
    PopulateTreeCtrl( pTreeCtrl_, 0 );
    pTreeCtrl_->ExpandAll();
    pTopDownSizer->AddSpacer( 5 );
    pTopDownSizer->Add( pLeftRightSizer, wxSizerFlags().Expand() );
    pTopDownSizer->AddSpacer( 5 );
    pTopDownSizer->Add( pTreeCtrl_, wxSizerFlags( 3 ).Expand() );
    pTopDownSizer->AddSpacer( 10 );
    AddButtons( pPanel, pTopDownSizer );
    FinalizeDlgCreation( pPanel, pTopDownSizer );
    SetSize( 400, 700 );
}

//-----------------------------------------------------------------------------
void DetailedRequestInformationDlg::PopulateTreeCtrl( wxTreeCtrl* pTreeCtrl, wxTreeItemId parent, Component itComponent )
//-----------------------------------------------------------------------------
{
    while( itComponent.isValid() )
    {
        if( itComponent.isList() )
        {
            wxTreeItemId newList = pTreeCtrl->AppendItem( parent, wxString::Format( wxT( "%s" ), ConvertedString( itComponent.name() ).c_str() ) );
            PopulateTreeCtrl( pTreeCtrl, newList, itComponent.firstChild() );
        }
        else if( itComponent.isProp() )
        {
            Property prop( itComponent );
            wxString data = wxString::Format( wxT( "%s%s: " ), ConvertedString( itComponent.name() ).c_str(),
                                              itComponent.isVisible() ? wxT( "" ) : wxT( " (currently invisible)" ) );
            const unsigned int valCount = prop.valCount();
            if( valCount > 1 )
            {
                data.Append( wxT( "[ " ) );
                for( unsigned int i = 0; i < valCount; i++ )
                {
                    data.Append( ConvertedString( prop.readS( static_cast<int>( i ) ) ).c_str() );
                    if( i < valCount - 1 )
                    {
                        data.Append( wxT( ", " ) );
                    }
                }
                data.Append( wxT( " ]" ) );
            }
            else
            {
                data.Append( ConvertedString( prop.readS() ).c_str() );
            }
            pTreeCtrl->AppendItem( parent, data );
        }
        else
        {
            pTreeCtrl->AppendItem( parent, wxString::Format( wxT( "%s" ), ConvertedString( itComponent.name() ).c_str() ) );
        }
        itComponent = itComponent.nextSibling();
    }
}

//-----------------------------------------------------------------------------
void DetailedRequestInformationDlg::PopulateTreeCtrl( wxTreeCtrl* pTreeCtrl, const int requestNr )
//-----------------------------------------------------------------------------
{
    Component itComponent( pFI_->getRequest( requestNr )->getComponentLocator().hObj() );
    wxTreeItemId rootId = pTreeCtrl->AddRoot( ConvertedString( itComponent.name() ) );
    itComponent = itComponent.firstChild();
    PopulateTreeCtrl( pTreeCtrl, rootId, itComponent );
}

//-----------------------------------------------------------------------------
void DetailedRequestInformationDlg::SelectRequest( const int requestNr )
//-----------------------------------------------------------------------------
{
    pTreeCtrl_->DeleteAllItems();
    PopulateTreeCtrl( pTreeCtrl_, requestNr );
    pTreeCtrl_->ExpandAll();
}

//=============================================================================
//============== Implementation DriverInformationDlg ==========================
//=============================================================================
BEGIN_EVENT_TABLE( DriverInformationDlg, OkAndCancelDlg )
    EVT_TREE_STATE_IMAGE_CLICK( widTCtrl, DriverInformationDlg::OnItemStateClick )
    EVT_CLOSE( DriverInformationDlg::OnClose )
END_EVENT_TABLE()

//-----------------------------------------------------------------------------
DriverInformationDlg::DriverInformationDlg( wxWindow* pParent, const wxString& title, ComponentIterator itDrivers,
        const DeviceManager& devMgr, const wxString& newestMVIAVersionAvailable, const wxString& newestMVIAVersionInstalled )
    : OkAndCancelDlg( pParent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX ),
      technologiesToHandleSpeciallyInOurProducers_(), pGenTLDriverConfigurator_( 0 ), systemModules_(), pTreeCtrl_( 0 ), pIconList_( new wxImageList( 16, 16, true, 3 ) ), ignoredInterfacesInfo_(),
      ignoredInterfacesInfoOriginal_(), masterEnumerationBehaviourOriginal_( iebNotConfigured ), newestMVIAVersionAvailable_( newestMVIAVersionAvailable ), newestMVIAVersionInstalled_( newestMVIAVersionInstalled )
//-----------------------------------------------------------------------------
{
    /*
        |-------------------------------------|
        | pTopDownSizer                       |
        |                spacer               |
        | |---------------------------------| |
        | | pTreeCtrl                       | |
        | |---------------------------------| |
        |                spacer               |
        | |---------------------------------| |
        | | pButtonSizer                    | |
        | |---------------------------------| |
        |-------------------------------------|
    */

    wxBusyCursor busyCursorScope;
    // The next command yields control to pending messages in the windowing system. It is necessary in order
    // to get a busy cursor in Linux systems while waiting for the dialog window to appear
    wxYield();
    technologiesToHandleSpeciallyInOurProducers_.push_back( "GEV" );
    technologiesToHandleSpeciallyInOurProducers_.push_back( "U3V" );
    const int64_type systemModuleCount = SystemModule::getSystemModuleCount();
    for( int64_type i = 0; i < systemModuleCount; i++ )
    {
        try
        {
            systemModules_.push_back( new mvIMPACT::acquire::GenICam::SystemModule( i ) );
        }
        catch( const ImpactAcquireException& ) {}
    }
    try
    {
        pGenTLDriverConfigurator_ = new mvIMPACT::acquire::GenICam::GenTLDriverConfigurator();
    }
    catch( const ImpactAcquireException& ) {}

    {
        const wxImage checkboxUndefined( wxBitmap::NewFromPNGData( checkbox_undefined_png, sizeof( checkbox_undefined_png ) ).ConvertToImage() );
        pIconList_->Add( checkboxUndefined.Scale( 16, 16 ) );
        const wxImage checkboxChecked( wxBitmap::NewFromPNGData( checkbox_checked_png, sizeof( checkbox_checked_png ) ).ConvertToImage() );
        pIconList_->Add( checkboxChecked.Scale( 16, 16 ) );
        const wxImage checkboxUnchecked( wxBitmap::NewFromPNGData( checkbox_unchecked_png, sizeof( checkbox_unchecked_png ) ).ConvertToImage() );
        pIconList_->Add( checkboxUnchecked.Scale( 16, 16 ) );
    }

    ReadIgnoredInterfacesInfoAndEnableAllInterfaces();
    UpdateDeviceListWithProgressMessage( this, devMgr );
    wxBoxSizer* pTopDownSizer = new wxBoxSizer( wxVERTICAL );
    pTopDownSizer->AddSpacer( 10 );
    wxPanel* pPanel = new wxPanel( this );
    pTreeCtrl_ = new wxTreeCtrl( pPanel, widTCtrl );
    pTreeCtrl_->SetStateImageList( pIconList_ );
    PopulateTreeCtrl( itDrivers, devMgr );
    // The next line is a workaround to prevent the buttons getting off-screen
    // in Linux systems, when the number of interfaces is high.
    //pTreeCtrl_->SetMaxSize( wxSize( 600, 700 ) );
    pTreeCtrl_->ExpandAll();
    pTopDownSizer->Add( pTreeCtrl_, wxSizerFlags( 1 ).Expand() );
    AddButtons( pPanel, pTopDownSizer );
    FinalizeDlgCreation( pPanel, pTopDownSizer );
    SetSize( 700, 800 );
    Center();
}

//-----------------------------------------------------------------------------
DriverInformationDlg::~DriverInformationDlg()
//-----------------------------------------------------------------------------
{
    pTreeCtrl_->SetStateImageList( 0 );
    delete pIconList_;
    for_each( systemModules_.begin(), systemModules_.end(), ptr_fun( DeleteElement<SystemModule*> ) );
}

//-----------------------------------------------------------------------------
wxTreeItemId DriverInformationDlg::AddComponentListToList( wxTreeItemId parent, mvIMPACT::acquire::ComponentLocator locator, const char* pName )
//-----------------------------------------------------------------------------
{
    ComponentList list;
    locator.bindComponent( list, string( pName ) );
    return list.isValid() ? pTreeCtrl_->AppendItem( parent, ConvertedString( list.name() ) ) : wxTreeItemId();
}

//-----------------------------------------------------------------------------
void DriverInformationDlg::AddStringPropToList( wxTreeItemId parent, ComponentLocator locator, const char* pName )
//-----------------------------------------------------------------------------
{
    PropertyS prop;
    locator.bindComponent( prop, string( pName ) );
    if( prop.isValid() )
    {
        const wxString propName = ConvertedString( prop.name() );
        if( propName == wxString( "Version" ) )
        {
            const wxString propValue = ConvertedString( prop.read().substr( 0, prop.read().find_last_of( "." ) ) );
            if( VersionFromString( propValue ) < VersionFromString( newestMVIAVersionInstalled_ ) )
            {
                const wxTreeItemId treeItem = pTreeCtrl_->AppendItem( parent, wxString::Format( wxT( "%s: %s (It is recommended to update to at least version %s!!!)" ), propName.c_str(), propValue.c_str(), newestMVIAVersionInstalled_.c_str() ) );
                pTreeCtrl_->SetItemTextColour( treeItem, acDarkBluePastel );
                pTreeCtrl_->SetItemBackgroundColour( treeItem, acBluePastel );
                pTreeCtrl_->SetItemTextColour( parent, acDarkBluePastel );
            }
            else if( VersionFromString( propValue ) < VersionFromString( newestMVIAVersionAvailable_ ) )
            {
                const wxTreeItemId treeItem = pTreeCtrl_->AppendItem( parent, wxString::Format( wxT( "%s: %s (Version %s is now available!!!)" ), propName.c_str(), propValue.c_str(), newestMVIAVersionAvailable_.c_str() ) );
                pTreeCtrl_->SetItemTextColour( treeItem, acDarkBluePastel );
                pTreeCtrl_->SetItemTextColour( parent, acDarkBluePastel );
            }
            else
            {
                pTreeCtrl_->AppendItem( parent, wxString::Format( wxT( "%s: %s" ), propName.c_str(), propValue.c_str() ) );
            }
        }
        else
        {
            const wxString propValue = ConvertedString( prop.read() );
            pTreeCtrl_->AppendItem( parent, wxString::Format( wxT( "%s: %s" ), propName.c_str(), propValue.c_str() ) );
        }
    }
}

//-----------------------------------------------------------------------------
void DriverInformationDlg::AppendStringFromProperty( wxString& s, Property& p )
//-----------------------------------------------------------------------------
{
    if( p.isValid() )
    {
        AppendStringFromString( s, p.readS() );
    }
}

//-----------------------------------------------------------------------------
void DriverInformationDlg::AppendStringFromString( wxString& s, const string& toAppend )
//-----------------------------------------------------------------------------
{
    if( s.IsEmpty() )
    {
        s = ConvertedString( toAppend );
    }
    else
    {
        s.Append( wxString::Format( wxT( "(%s)" ), ConvertedString( toAppend ).c_str() ) );
    }
}

//-----------------------------------------------------------------------------
void DriverInformationDlg::ApplyGenTLDriverConfigurationChanges( wxTreeItemId treeItem )
//-----------------------------------------------------------------------------
{
    while( treeItem.IsOk() )
    {
        MyTreeItemData* pItemData = reinterpret_cast<MyTreeItemData*>( pTreeCtrl_->GetItemData( treeItem ) );
        if( pItemData &&
            ( pItemData->type_ == MyTreeItemData::etProducer ) &&
            !pItemData->propertyToValueMap_.empty() )
        {
            const string producerFileName( GetProducerFileName( pItemData->pSystemModule_ ) );
            if( !producerFileName.empty() )
            {
                try
                {
                    if( pGenTLDriverConfigurator_ )
                    {
                        GenTLProducerConfiguration producerConfiguration( pGenTLDriverConfigurator_->hasProducerConfiguration( producerFileName ) ? pGenTLDriverConfigurator_->getProducerConfiguration( producerFileName ) : pGenTLDriverConfigurator_->createProducerConfiguration( producerFileName ) );
                        const map<string, PropertyIInterfaceEnumerationBehaviour> interfaceConfigurations( producerConfiguration.getInterfaceEnumerationBehaviours() );
                        const map<string, PropertyIInterfaceEnumerationBehaviour>::const_iterator itInterfaceConfigurationEND = interfaceConfigurations.end();
                        map<string, string>::const_iterator it = pItemData->propertyToValueMap_.begin();
                        const map<string, string>::const_iterator itEND = pItemData->propertyToValueMap_.end();
                        while( it != itEND )
                        {
                            if( it->first == "EnumerationEnable" )
                            {
                                producerConfiguration.enumerationEnable.write( ( it->second == "0" ) ? bFalse : bTrue );
                            }
                            else
                            {
                                const map<string, PropertyIInterfaceEnumerationBehaviour>::const_iterator itInterfaceConfiguration = interfaceConfigurations.find( it->first );
                                if( itInterfaceConfiguration == itInterfaceConfigurationEND )
                                {
                                    producerConfiguration.createProducerInterfaceConfigurationEntry( it->first ).writeS( it->second );
                                }
                                else
                                {
                                    itInterfaceConfiguration->second.writeS( it->second );
                                }
                            }
                            ++it;
                        }
                    }
                }
                catch( const ImpactAcquireException& ) {}
            }
        }
        if( pTreeCtrl_->HasChildren( treeItem ) )
        {
            wxTreeItemIdValue cookie;
            ApplyGenTLDriverConfigurationChanges( pTreeCtrl_->GetFirstChild( treeItem, cookie ) );
        }
        treeItem = pTreeCtrl_->GetNextSibling( treeItem );
    }
}

//-----------------------------------------------------------------------------
void DriverInformationDlg::SetProducerUndefinedStateIfConflictingInterfaceStates( const wxTreeItemId& itemId )
//-----------------------------------------------------------------------------
{
    if( itemId.IsOk() )
    {
        wxTreeItemIdValue cookie;
        wxTreeItemId interfaceTypeId = pTreeCtrl_->GetFirstChild( itemId, cookie );
        bool boAtLeastOneEnumerate = false;
        bool boAtLeastOneIgnore = false;
        while( interfaceTypeId.IsOk() )
        {
            wxTreeItemId interfaceId = pTreeCtrl_->GetFirstChild( interfaceTypeId, cookie );
            while( interfaceId.IsOk() )
            {
                if( pTreeCtrl_->GetItemState( interfaceId ) == lisChecked )
                {
                    boAtLeastOneEnumerate = true;
                }
                else
                {
                    boAtLeastOneIgnore = true;
                }

                if( boAtLeastOneEnumerate && boAtLeastOneIgnore )
                {
                    pTreeCtrl_->SetItemState( itemId, lisUndefined );
                    return;
                }
                interfaceId = pTreeCtrl_->GetNextChild( interfaceTypeId, cookie );
            }
            interfaceTypeId = pTreeCtrl_->GetNextChild( itemId, cookie );
        }
    }
}

//-----------------------------------------------------------------------------
void DriverInformationDlg::SetTechnologyUndefinedStateIfConflictingInterfaceStates( const wxTreeItemId& itemId )
//-----------------------------------------------------------------------------
{
    if( itemId.IsOk() &&
        ( pTreeCtrl_->GetChildrenCount( itemId, false ) > 1 ) )
    {
        bool boAtLeastOneEnumerate = false;
        bool boAtLeastOneIgnore = false;
        wxTreeItemIdValue cookie;
        wxTreeItemId childId = pTreeCtrl_->GetFirstChild( itemId, cookie );
        while( childId.IsOk() )
        {
            if( pTreeCtrl_->GetItemState( childId ) == lisChecked )
            {
                boAtLeastOneEnumerate = true;
            }
            else
            {
                boAtLeastOneIgnore = true;
            }

            if( boAtLeastOneEnumerate && boAtLeastOneIgnore )
            {
                pTreeCtrl_->SetItemState( itemId, lisUndefined );
                return;
            }
            childId = pTreeCtrl_->GetNextChild( itemId, cookie );
        }
    }
}

//-----------------------------------------------------------------------------
map<wxString, map<wxString, bool> > DriverInformationDlg::EnumerateGenICamDevices( mvIMPACT::acquire::GenICam::SystemModule* pSystemModule, unsigned int interfaceCount, const DeviceManager& devMgr )
//-----------------------------------------------------------------------------
{
    static const int MAX_TIME_MS = 10000;
    const string producerFileName( GetProducerFileName( pSystemModule ) );
    wxProgressDialog progressDialog( wxT( "Obtaining Device Information" ),
                                     wxString::Format( wxT( "Obtaining device information from %u interface%s\n\nGenTL Producer name: %s\nGenTL Producer vendor: %s...\n\nThis dialog will disappear automatically once this operation completes!" ),
                                             interfaceCount,
                                             ( ( interfaceCount > 1 ) ? wxT( "s" ) : wxT( "" ) ),
                                             ConvertedString( producerFileName.empty() ? "Could not be obtained" : producerFileName ).c_str(),
                                             ConvertedString( pSystemModule->TLVendorName.isValid() ? pSystemModule->TLVendorName.readS() : "Could not be obtained" ).c_str() ),
                                     MAX_TIME_MS, // range
                                     this,
                                     wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_ELAPSED_TIME );

    // create a thread for each interface
    vector<CollectDeviceInformationThread*> threads;
    for( unsigned int i = 0; i < interfaceCount; i++ )
    {
        threads.push_back( new CollectDeviceInformationThread( devMgr, *pSystemModule, i ) );
        threads.back()->Run();
    }

    // if at least one thread is still running keep waiting
    for( unsigned int i = 0; i < interfaceCount; i++ )
    {
        if( threads[i]->IsRunning() )
        {
            wxMilliSleep( 100 );
            progressDialog.Pulse();
            i = 0;
        }
    }

    // collect the data and clean up
    map<wxString, map<wxString, bool> > results;
    for( unsigned int i = 0; i < interfaceCount; i++ )
    {
        threads[i]->Wait();
        results.insert( threads[i]->GetResults() );
        delete threads[i];
    }
    progressDialog.Update( MAX_TIME_MS );
    return results;
}

//-----------------------------------------------------------------------------
string DriverInformationDlg::GetProducerFileName( mvIMPACT::acquire::GenICam::SystemModule* pSystemModule ) const
//-----------------------------------------------------------------------------
{
    string fileName;
    if( pSystemModule->TLFileName.isValid() )
    {
        fileName = pSystemModule->TLFileName.readS();
    }
    if( fileName.empty() && pSystemModule->TLPath.isValid() )
    {
        fileName = pSystemModule->TLPath.readS();
        const string::size_type pos = fileName.find_last_of( "/\\" );
        if( ( pos != string::npos ) && ( ( pos + 1 ) < fileName.length() ) )
        {
            fileName = fileName.substr( pos + 1 );
        }
    }
    return fileName;
}

//-----------------------------------------------------------------------------
void DriverInformationDlg::OnItemStateClick( wxTreeEvent& event )
//-----------------------------------------------------------------------------
{
    const wxTreeItemId itemId = event.GetItem();
    MyTreeItemData* pItemData = reinterpret_cast<MyTreeItemData*>( pTreeCtrl_->GetItemData( itemId ) );
    if( !pItemData )
    {
        return;
    }

    const TListItemStates state = ( pTreeCtrl_->GetItemState( itemId ) == lisChecked ) ? lisUnchecked : lisChecked;
    wxTreeItemIdValue cookie;
    SystemModule* pSystemModule = pItemData->pSystemModule_;
    if( pSystemModule->mvInterfaceTechnologyToIgnoreSelector.isValid() &&
        pSystemModule->mvInterfaceTechnologyToIgnoreEnable.isValid() &&
        pSystemModule->mvDeviceUpdateListBehaviour.isValid() )
    {
        // This is a MATRIX VISION producer with integrated interface/technology configuration properties
        pTreeCtrl_->SetItemState( itemId, state );
        if( pTreeCtrl_->GetItemText( itemId ) == wxT( "GigEVision" ) ||
            pTreeCtrl_->GetItemText( itemId ) == wxT( "USB3Vision" ) )
        {
            // recursively apply the same state to all children(interfaces of the same type)
            wxTreeItemId childId = pTreeCtrl_->GetFirstChild( itemId, cookie );
            while( childId.IsOk() )
            {
                pTreeCtrl_->SetItemState( childId, state );
                childId = pTreeCtrl_->GetNextChild( itemId, cookie );
            }

            ignoredInterfacesInfo_[( string( pTreeCtrl_->GetItemText( itemId ) ) == string( "GigEVision" ) ) ? string( "GEV" ) : string( "U3V" )] = ( pTreeCtrl_->GetItemState( itemId ) == lisUnchecked ) ? string( "1" ) : string( "0" );

            // recursively update the settings of all children(interfaces of the same type)
            childId = pTreeCtrl_->GetFirstChild( itemId, cookie );
            while( childId.IsOk() )
            {
                const string itemText( pTreeCtrl_->GetItemText( childId ) );
                IgnoredInterfacesInfo::iterator it = ignoredInterfacesInfo_.begin();
                const IgnoredInterfacesInfo::iterator itEND = ignoredInterfacesInfo_.end();
                while( it != itEND )
                {
                    if( itemText.find( it->first ) != string::npos )
                    {
                        it->second = string( "NotConfigured" );
                        break;
                    }
                    ++it;
                }
                childId = pTreeCtrl_->GetNextChild( itemId, cookie );
            }
        }
        else
        {
            // set the state of the parent (interface type) to undefined or to item state, depending on the states of the other siblings.
            const wxTreeItemId parentId = pTreeCtrl_->GetItemParent( itemId );
            pTreeCtrl_->SetItemState( parentId, state );
            wxTreeItemId siblingId = pTreeCtrl_->GetFirstChild( parentId, cookie );
            while( siblingId.IsOk() )
            {
                if( pTreeCtrl_->GetItemState( siblingId ) != state )
                {
                    pTreeCtrl_->SetItemState( parentId, lisUndefined );
                    break;
                }
                siblingId = pTreeCtrl_->GetNextChild( parentId, cookie );
            }

            // Since configuring a child can modify the parent state too, we have to update the ignoredInterfacesInfo_ to
            // reflect this change, before we do anything else.
            const bool boParentIgnored = ( pTreeCtrl_->GetItemState( parentId ) == lisUnchecked );
            ignoredInterfacesInfo_[( string( pTreeCtrl_->GetItemText( parentId ) ) == string( "GigEVision" ) ) ? string( "GEV" ) : string( "U3V" )] = boParentIgnored ? string( "1" ) : string( "0" );
            const string itemText( pTreeCtrl_->GetItemText( itemId ) );
            IgnoredInterfacesInfo::iterator it = ignoredInterfacesInfo_.begin();
            const IgnoredInterfacesInfo::iterator itEND = ignoredInterfacesInfo_.end();
            while( it != itEND )
            {
                if( itemText.find( it->first ) != string::npos )
                {
                    if( pTreeCtrl_->GetItemState( itemId ) == lisUnchecked )
                    {
                        it->second = boParentIgnored ? string( "NotConfigured" ) : string( "ForceIgnore" );
                    }
                    else if( pTreeCtrl_->GetItemState( itemId ) == lisChecked )
                    {
                        it->second = boParentIgnored ? string( "ForceEnumerate" ) : string( "NotConfigured" );
                    }
                    break;
                }
                ++it;
            }
        }
    }
    else if( pItemData->type_ == MyTreeItemData::etProducer )
    {
        // This is a GenTL producer without integrated interface/technology configuration support and
        // the user has clicked on the root node, thus will access the 'EnumerationEnable' property
        // for this producer.
        pTreeCtrl_->SetItemState( itemId, state );
        // recursively apply the same state to all interfaces
        wxTreeItemId interfaceTypeId = pTreeCtrl_->GetFirstChild( itemId, cookie );
        while( interfaceTypeId.IsOk() )
        {
            wxTreeItemId interfaceId = pTreeCtrl_->GetFirstChild( interfaceTypeId, cookie );
            while( interfaceId.IsOk() )
            {
                pTreeCtrl_->SetItemState( interfaceId, state );
                interfaceId = pTreeCtrl_->GetNextChild( interfaceTypeId, cookie );
            }
            interfaceTypeId = pTreeCtrl_->GetNextChild( itemId, cookie );
        }
        pItemData->propertyToValueMap_.clear();
        pItemData->propertyToValueMap_.insert( make_pair( "EnumerationEnable", state == lisChecked ? "1" : "0" ) );
    }
    else if( pItemData->type_ == MyTreeItemData::etInterface )
    {
        // This is a GenTL producer without integrated interface/technology configuration support and
        // the user has clicked an interface node, thus will access the 'InterfaceEnumeartionBehaviour' property
        // for this interface of the top-level producer.
        pTreeCtrl_->SetItemState( itemId, state );
        // set the state of the parent (producer) to undefined or to item state, depending on the states of the other siblings.
        wxTreeItemId parentId = pTreeCtrl_->GetItemParent( itemId );
        parentId = pTreeCtrl_->GetItemParent( parentId );
        pTreeCtrl_->SetItemState( parentId, state );
        wxTreeItemId interfaceTypeId = pTreeCtrl_->GetFirstChild( parentId, cookie );
        bool boContinueProcessing = true;
        while( interfaceTypeId.IsOk() && boContinueProcessing )
        {
            wxTreeItemId interfaceId = pTreeCtrl_->GetFirstChild( interfaceTypeId, cookie );
            while( interfaceId.IsOk() )
            {
                if( pTreeCtrl_->GetItemState( interfaceId ) != state )
                {
                    pTreeCtrl_->SetItemState( parentId, lisUndefined );
                    boContinueProcessing = false;
                    break;
                }
                interfaceId = pTreeCtrl_->GetNextChild( interfaceTypeId, cookie );
            }
            interfaceTypeId = pTreeCtrl_->GetNextChild( parentId, cookie );
        }

        MyTreeItemData* pParentItemData = reinterpret_cast<MyTreeItemData*>( pTreeCtrl_->GetItemData( parentId ) );
        if( pParentItemData )
        {
            // as later when actually applying the new behaviour (if the user ends the dialog using the 'Ok' button)
            // we will just evaluate the tree items stating they represent a 'producer' we collect all the information
            // in these tree items only!
            const std::map<std::string, std::string>::const_iterator it = pItemData->propertyToValueMap_.find( "InterfaceID" );
            if( it != pItemData->propertyToValueMap_.end() )
            {
                pParentItemData->propertyToValueMap_[it->second] = ( state == lisUnchecked ) ? "ForceIgnore" : "ForceEnumerate";
            }
        }
    }
}

//-----------------------------------------------------------------------------
wxTreeItemId DriverInformationDlg::AddKnownTechnologyTreeItem( SystemModule* pSystemModule, wxTreeItemId producerRootItem, wxTreeItemId treeItem, map<wxString, wxTreeItemId>& interfaceTypeMap, const wxString& technology, const string& technologyShort )
//-----------------------------------------------------------------------------
{
    if( !treeItem.IsOk() )
    {
        treeItem = pTreeCtrl_->AppendItem( producerRootItem, technology, -1, -1, new MyTreeItemData( pSystemModule, MyTreeItemData::etTechnology ) );
        interfaceTypeMap.insert( make_pair( technology, treeItem ) );
        pTreeCtrl_->SetItemBold( treeItem );
        if( pSystemModule->mvInterfaceTechnologyToIgnoreSelector.isValid() )
        {
            pSystemModule->mvInterfaceTechnologyToIgnoreSelector.writeS( technologyShort );
            pTreeCtrl_->SetItemState( treeItem, ( ignoredInterfacesInfo_[technologyShort] == string( "1" ) ) ? lisUnchecked : lisChecked );
        }
    }
    return treeItem;
}

//-----------------------------------------------------------------------------
void DriverInformationDlg::PopulateTreeCtrl( ComponentIterator itDrivers, const DeviceManager& devMgr )
//-----------------------------------------------------------------------------
{
    const wxTreeItemId rootId = pTreeCtrl_->AddRoot( ConvertedString( itDrivers.name() ) );
    itDrivers = itDrivers.firstChild();
    while( itDrivers.isValid() )
    {
        // If the driver is not installed then do not even list it!
        ComponentLocator locator( itDrivers.hObj() );
        if( locator.findComponent( "Version" ) != INVALID_ID )
        {
            ComponentList clDriver( itDrivers.hObj() );
            wxTreeItemId newItem;
            if( clDriver.contentDescriptor().empty() )
            {
                newItem = pTreeCtrl_->AppendItem( rootId, wxEmptyString );
            }
            else
            {
                newItem = pTreeCtrl_->AppendItem( rootId, wxString::Format( wxT( " %s" ), ConvertedString( itDrivers.name() ).c_str() ) );
                pTreeCtrl_->SetItemBold( newItem );
            }
            AddStringPropToList( newItem, locator, "FullPath" );
            AddStringPropToList( newItem, locator, "Version" );

            if( ( clDriver.name() == string( "mvGenTLConsumer" ) ) && !systemModules_.empty() )
            {
                const vector<mvIMPACT::acquire::GenICam::SystemModule*>::size_type systemModuleCount = systemModules_.size();
                for( vector<mvIMPACT::acquire::GenICam::SystemModule*>::size_type systemModuleIndex = 0; systemModuleIndex < systemModuleCount; systemModuleIndex++ )
                {
                    SystemModule* pSystemModule = systemModules_[systemModuleIndex];
                    wxString producerInfo;
                    const string producerFileName( GetProducerFileName( pSystemModule ) );
                    AppendStringFromProperty( producerInfo, pSystemModule->TLDisplayName );
                    AppendStringFromProperty( producerInfo, pSystemModule->TLVendorName );
                    AppendStringFromString( producerInfo, producerFileName );
                    wxTreeItemId producerRootItem = pTreeCtrl_->AppendItem( newItem, producerInfo, -1, -1, new MyTreeItemData( pSystemModule, MyTreeItemData::etProducer ) );
                    if( pGenTLDriverConfigurator_ && !producerFileName.empty() )
                    {
                        if( pGenTLDriverConfigurator_->hasProducerConfiguration( producerFileName ) )
                        {
                            GenTLProducerConfiguration producerConfiguration( pGenTLDriverConfigurator_->getProducerConfiguration( producerFileName ) );
                            pTreeCtrl_->SetItemState( producerRootItem, ( producerConfiguration.enumerationEnable.read() == bTrue ) ? lisChecked : lisUnchecked );
                        }
                        else if( !pSystemModule->mvInterfaceTechnologyToIgnoreEnable.isValid() )
                        {
                            // only set this for top-level items if the producer does NOT offer the internal 'technology/interface ignore' interface
                            pTreeCtrl_->SetItemState( producerRootItem, lisChecked );
                        }
                    }

                    wxTreeItemId interfaceTypeGEV;
                    wxTreeItemId interfaceTypeU3V;
                    if( pSystemModule->interfaceSelector.isValid() )
                    {
                        map<wxString, wxTreeItemId> interfaceTypeMap;
                        const int64_type interfaceCount = pSystemModule->getInterfaceModuleCount();
                        for( int64_type i = 0; i < interfaceCount; i++ )
                        {
                            InterfaceModule im( *pSystemModule, i );
                            wxTreeItemId interfaceTreeItem;
                            const string interfaceType( im.interfaceType.isValid() ? im.interfaceType.readS() : "UNKNOWN-INTERFACE-TYPE" );
                            if( ( interfaceType == string( "GEV" ) ) ||
                                ( interfaceType == string( "GigEVision" ) ) )
                            {
                                interfaceTypeGEV = AddKnownTechnologyTreeItem( pSystemModule, producerRootItem, interfaceTypeGEV, interfaceTypeMap, wxT( "GigEVision" ), "GEV" );
                            }
                            else if( ( interfaceType == string( "U3V" ) ) ||
                                     ( interfaceType == string( "USB3Vision" ) ) )
                            {
                                interfaceTypeU3V = AddKnownTechnologyTreeItem( pSystemModule, producerRootItem, interfaceTypeU3V, interfaceTypeMap, wxT( "USB3Vision" ), "U3V" );
                            }
                            else if( interfaceTypeMap.find( interfaceType ) == interfaceTypeMap.end() )
                            {
                                wxTreeItemId interfaceTypeTreeItem = pTreeCtrl_->AppendItem( producerRootItem, interfaceType, -1, -1, new MyTreeItemData( pSystemModule, MyTreeItemData::etTechnology ) );
                                interfaceTypeMap.insert( make_pair( interfaceType, interfaceTypeTreeItem ) );
                                pTreeCtrl_->SetItemBold( interfaceTypeTreeItem );
                            }
                        }

                        map<wxString, map<wxString, bool> > deviceInformation = EnumerateGenICamDevices( pSystemModule, static_cast<unsigned int>( interfaceCount ), devMgr );
                        for( unsigned int i = 0; i < interfaceCount; i++ )
                        {
                            InterfaceModule im( *pSystemModule, i );
                            wxTreeItemId interfaceTreeItem;
                            const string interfaceID( im.interfaceID.isValid() ? im.interfaceID.readS() : ( pSystemModule->interfaceID.isValid() ? pSystemModule->interfaceID.readS() : "" ) );
                            if( interfaceID.empty() )
                            {
                                continue;
                            }
                            const string interfaceType( im.interfaceType.isValid() ? im.interfaceType.readS() : "UNKNOWN-INTERFACE-TYPE" );
                            if( ( interfaceType == string( "GEV" ) ) ||
                                ( interfaceType == string( "GigEVision" ) ) )
                            {
                                interfaceTreeItem = CreateAndConfigureInterfaceTreeItem( pSystemModule, im, interfaceID, interfaceTypeGEV );
                            }
                            else if( ( interfaceType == string( "U3V" ) ) ||
                                     ( interfaceType == string( "USB3Vision" ) ) )
                            {
                                interfaceTreeItem = CreateAndConfigureInterfaceTreeItem( pSystemModule, im, interfaceID, interfaceTypeU3V );
                            }
                            else
                            {
                                const map<wxString, wxTreeItemId>::const_iterator itInterfaceType = interfaceTypeMap.find( ConvertedString( interfaceType ) );
                                interfaceTreeItem = CreateAndConfigureInterfaceTreeItem( pSystemModule, im, interfaceID, ( itInterfaceType == interfaceTypeMap.end() ) ? producerRootItem : itInterfaceType->second );
                            }
                            const map<wxString, map<wxString, bool> >::const_iterator itDeviceInformationForInterface = deviceInformation.find( interfaceID );
                            if( ( itDeviceInformationForInterface != deviceInformation.end() ) && !itDeviceInformationForInterface->second.empty() )
                            {
                                map<wxString, bool>::const_iterator itDevices = itDeviceInformationForInterface->second.begin();
                                const map<wxString, bool>::const_iterator itDevicesEND = itDeviceInformationForInterface->second.end();
                                while( itDevices != itDevicesEND )
                                {
                                    wxTreeItemId deviceTreeItem = pTreeCtrl_->AppendItem( interfaceTreeItem, itDevices->first );
                                    if( itDevices->second )
                                    {
                                        pTreeCtrl_->SetItemTextColour( deviceTreeItem, acDarkGrey );
                                    }
                                    ++itDevices;
                                }
                            }
                        }
                        if( pSystemModule->mvInterfaceTechnologyToIgnoreEnable.isValid() )
                        {
                            SetTechnologyUndefinedStateIfConflictingInterfaceStates( interfaceTypeGEV );
                            SetTechnologyUndefinedStateIfConflictingInterfaceStates( interfaceTypeU3V );
                        }
                        else
                        {
                            SetProducerUndefinedStateIfConflictingInterfaceStates( producerRootItem );
                        }
                    }
                }
            }
            else
            {
                const wxTreeItemId devices = AddComponentListToList( newItem, locator, "Devices" );
                if( devices.IsOk() )
                {
                    ComponentIterator itDev( locator.findComponent( "Devices" ) );
                    itDev = itDev.firstChild();
                    while( itDev.isValid() )
                    {
                        const PropertyS serial( itDev );
                        const Device* const pDev = devMgr.getDeviceBySerial( serial.read() );
                        const bool boInUse = pDev && pDev->isInUse();
                        const wxTreeItemId deviceTreeItem = pTreeCtrl_->AppendItem( devices, wxString::Format( wxT( "%s(%s)%s" ), ConvertedString( serial.read() ).c_str(), ConvertedString( pDev->product.read() ).c_str(), boInUse ? wxT( " - IN USE!" ) : wxT( "" ) ) );
                        if( boInUse )
                        {
                            pTreeCtrl_->SetItemTextColour( deviceTreeItem, acDarkGrey );
                        }
                        itDev = itDev.nextSibling();
                    }
                }
            }
        }
        itDrivers = itDrivers.nextSibling();
    }
}

//-----------------------------------------------------------------------------
wxTreeItemId DriverInformationDlg::CreateAndConfigureInterfaceTreeItem( SystemModule* pSystemModule, InterfaceModule& im, const string& interfaceID, wxTreeItemId interfaceTypeTreeItem )
//-----------------------------------------------------------------------------
{
    // try to get a human readable name for this interface
    wxString interfaceDisplayName;
    if( im.interfaceDisplayName.isValid() )
    {
        interfaceDisplayName = wxString::Format( wxT( "(%s)" ), ConvertedString( im.interfaceDisplayName.readS() ).c_str() );
    }
    else if( pSystemModule->interfaceDisplayName.isValid() )
    {
        interfaceDisplayName = wxString::Format( wxT( "(%s)" ), ConvertedString( pSystemModule->interfaceDisplayName.readS() ).c_str() );
    }
    const IgnoredInterfacesInfo::const_iterator it = ignoredInterfacesInfo_.find( interfaceID );
    const IgnoredInterfacesInfo::const_iterator itEND = ignoredInterfacesInfo_.end();
    MyTreeItemData* pTreeItemData = new MyTreeItemData( pSystemModule, MyTreeItemData::etInterface );
    pTreeItemData->propertyToValueMap_.insert( make_pair( "InterfaceID", interfaceID ) );
    wxTreeItemId interfaceTreeItem = pTreeCtrl_->AppendItem( interfaceTypeTreeItem, wxString::Format( wxT( "%s%s" ), ConvertedString( interfaceID ).c_str(), interfaceDisplayName.c_str() ), -1, -1, pTreeItemData );
    const string producerFileName( GetProducerFileName( pSystemModule ) );
    if( it != itEND )
    {
        pTreeCtrl_->SetItemState( interfaceTreeItem, ( it->second == string( "NotConfigured" ) ) ? pTreeCtrl_->GetItemState( interfaceTypeTreeItem ) : ( it->second == string( "ForceIgnore" ) ) ? lisUnchecked : lisChecked );
    }
    else if( pGenTLDriverConfigurator_ && !producerFileName.empty() )
    {
        if( pGenTLDriverConfigurator_->hasProducerConfiguration( producerFileName ) )
        {
            GenTLProducerConfiguration producerConfiguration( pGenTLDriverConfigurator_->getProducerConfiguration( producerFileName ) );
            const map<string, PropertyIInterfaceEnumerationBehaviour> interfaceEnumerationBehaviour( producerConfiguration.getInterfaceEnumerationBehaviours() );
            const map<string, PropertyIInterfaceEnumerationBehaviour>::const_iterator itInterfaceEnumerationBehaviour = interfaceEnumerationBehaviour.find( interfaceID );
            if( itInterfaceEnumerationBehaviour == interfaceEnumerationBehaviour.end() )
            {
                pTreeCtrl_->SetItemState( interfaceTreeItem, ( producerConfiguration.enumerationEnable.read() == bTrue ) ? lisChecked : lisUnchecked );
            }
            else
            {
                switch( itInterfaceEnumerationBehaviour->second.read() )
                {
                case iebNotConfigured:
                    pTreeCtrl_->SetItemState( interfaceTreeItem, ( producerConfiguration.enumerationEnable.read() == bTrue ) ? lisChecked : lisUnchecked );
                    break;
                case iebForceEnumerate:
                    pTreeCtrl_->SetItemState( interfaceTreeItem, lisChecked );
                    break;
                case iebForceIgnore:
                    pTreeCtrl_->SetItemState( interfaceTreeItem, lisUnchecked );
                    break;
                }
            }
        }
        else
        {
            pTreeCtrl_->SetItemState( interfaceTreeItem, lisChecked );
        }
    }
    return interfaceTreeItem;
}

//-----------------------------------------------------------------------------
void DriverInformationDlg::ReadIgnoredInterfacesInfoAndEnableAllInterfaces( void )
//-----------------------------------------------------------------------------
{
    const vector<string>::size_type technologyCount = technologiesToHandleSpeciallyInOurProducers_.size();
    const vector<mvIMPACT::acquire::GenICam::SystemModule*>::size_type systemModuleCount = systemModules_.size();
    for( vector<mvIMPACT::acquire::GenICam::SystemModule*>::size_type systemModuleIndex = 0; systemModuleIndex < systemModuleCount; systemModuleIndex++ )
    {
        SystemModule* pSystemModule = systemModules_[systemModuleIndex];
        if( pSystemModule->interfaceID.isValid() &&
            pSystemModule->interfaceSelector.isValid() &&
            pSystemModule->interfaceUpdateList.isValid() &&
            pSystemModule->mvDeviceUpdateListBehaviour.isValid() )
        {
            pSystemModule->interfaceUpdateList.call();
            for( vector<string>::size_type technologyIndex = 0; technologyIndex < technologyCount; technologyIndex++ )
            {
                const string technology( technologiesToHandleSpeciallyInOurProducers_[technologyIndex] );
                string value( "0" );
                if( pSystemModule->mvInterfaceTechnologyToIgnoreSelector.isValid() && pSystemModule->mvInterfaceTechnologyToIgnoreEnable.isValid() )
                {
                    pSystemModule->mvInterfaceTechnologyToIgnoreSelector.writeS( technology );
                    value = ( pSystemModule->mvInterfaceTechnologyToIgnoreEnable.read() == bTrue ) ? "1" : "0";
                }
                ignoredInterfacesInfo_.insert( make_pair( technology, value ) );
                ignoredInterfacesInfoOriginal_.insert( make_pair( technology, value ) );
                if( pSystemModule->mvInterfaceTechnologyToIgnoreEnable.isValid() )
                {
                    pSystemModule->mvInterfaceTechnologyToIgnoreEnable.write( bFalse );
                }
            }
            const int64_type interfaceCount = pSystemModule->interfaceSelector.getMaxValue() + 1;
            for( int64_type i = 0; i < interfaceCount; i++ )
            {
                pSystemModule->interfaceSelector.write( i );
                const string value( pSystemModule->mvDeviceUpdateListBehaviour.isValid() ? pSystemModule->mvDeviceUpdateListBehaviour.readS() : "NotConfigured" );
                ignoredInterfacesInfo_.insert( make_pair( pSystemModule->interfaceID.readS(), value ) );
                ignoredInterfacesInfoOriginal_.insert( make_pair( pSystemModule->interfaceID.readS(), value ) );
                if( pSystemModule->mvDeviceUpdateListBehaviour.isValid() )
                {
                    pSystemModule->mvDeviceUpdateListBehaviour.writeS( "NotConfigured" );
                }
            }
        }
    }
    if( pGenTLDriverConfigurator_ )
    {
        masterEnumerationBehaviourOriginal_ = pGenTLDriverConfigurator_->masterEnumerationBehaviour.read();
        pGenTLDriverConfigurator_->masterEnumerationBehaviour.write( iebForceEnumerate );
    }
}

//-----------------------------------------------------------------------------
void DriverInformationDlg::UpdateIgnoredInterfacesSettings( IgnoredInterfacesInfo& interfacesInfo )
//-----------------------------------------------------------------------------
{
    const vector<string>::size_type technologyCount = technologiesToHandleSpeciallyInOurProducers_.size();
    const vector<mvIMPACT::acquire::GenICam::SystemModule*>::size_type systemModuleCount = systemModules_.size();
    for( vector<mvIMPACT::acquire::GenICam::SystemModule*>::size_type systemModuleIndex = 0; systemModuleIndex < systemModuleCount; systemModuleIndex++ )
    {
        SystemModule* pSystemModule = systemModules_[systemModuleIndex];
        if( pSystemModule->interfaceSelector.isValid() &&
            pSystemModule->interfaceID.isValid() &&
            pSystemModule->interfaceType.isValid() &&
            pSystemModule->mvDeviceUpdateListBehaviour.isValid() )
        {
            for( vector<string>::size_type technologyIndex = 0; technologyIndex < technologyCount; technologyIndex++ )
            {
                const string technology( technologiesToHandleSpeciallyInOurProducers_[technologyIndex] );
                if( pSystemModule && pSystemModule->mvInterfaceTechnologyToIgnoreSelector.isValid() && pSystemModule->mvInterfaceTechnologyToIgnoreEnable.isValid() )
                {
                    pSystemModule->mvInterfaceTechnologyToIgnoreSelector.writeS( technology );
                    if( interfacesInfo[technology] == "1" )
                    {
                        pSystemModule->mvInterfaceTechnologyToIgnoreEnable.write( bTrue );
                    }
                }
            }

            const IgnoredInterfacesInfo::const_iterator itGEV = interfacesInfo.find( "GEV" );
            const IgnoredInterfacesInfo::const_iterator itU3V = interfacesInfo.find( "U3V" );
            const IgnoredInterfacesInfo::const_iterator itEND = interfacesInfo.end();
            assert( ( itGEV != itEND ) && "At this point there should be an 'GEV' entry in the ignored interfaces information map!" );
            assert( ( itU3V != itEND ) && "At this point there should be an 'U3V' entry in the ignored interfaces information map!" );

            const int64_type interfaceCount = pSystemModule->getInterfaceModuleCount();
            for( int64_type i = 0; i < interfaceCount; i++ )
            {
                pSystemModule->interfaceSelector.write( i );
                const string interfaceID( pSystemModule->interfaceID.readS() );
                const IgnoredInterfacesInfo::const_iterator it = interfacesInfo.find( interfaceID );
                if( it == itEND )
                {
                    continue;
                }
                if( it->second == "NotConfigured" )
                {
                    pSystemModule->mvDeviceUpdateListBehaviour.writeS( "NotConfigured" );
                }
                else if( it->second == "ForceEnumerate" )
                {
                    if( ( ( pSystemModule->interfaceType.readS() == "GEV" ) && ( itGEV->second == "1" ) ) ||
                        ( ( pSystemModule->interfaceType.readS() == "U3V" ) && ( itU3V->second == "1" ) ) )
                    {
                        pSystemModule->mvDeviceUpdateListBehaviour.writeS( "ForceEnumerate" );
                    }
                    else
                    {
                        pSystemModule->mvDeviceUpdateListBehaviour.writeS( "NotConfigured" );
                    }
                }
                else if( it->second == "ForceIgnore" )
                {
                    if( ( ( pSystemModule->interfaceType.readS() == "GEV" ) && ( itGEV->second == "0" ) ) ||
                        ( ( pSystemModule->interfaceType.readS() == "U3V" ) && ( itU3V->second == "0" ) ) )
                    {
                        pSystemModule->mvDeviceUpdateListBehaviour.writeS( "ForceIgnore" );
                    }
                    else
                    {
                        pSystemModule->mvDeviceUpdateListBehaviour.writeS( "NotConfigured" );
                    }
                }
            }
        }
    }
    if( pGenTLDriverConfigurator_ )
    {
        pGenTLDriverConfigurator_->masterEnumerationBehaviour.write( masterEnumerationBehaviourOriginal_ );
    }
}

//=============================================================================
//=================== Implementation UpdatesInformationDlg ====================
//=============================================================================
BEGIN_EVENT_TABLE( UpdatesInformationDlg, OkAndCancelDlg )
    EVT_CLOSE( UpdatesInformationDlg::OnClose )
END_EVENT_TABLE()

//-----------------------------------------------------------------------------
UpdatesInformationDlg::UpdatesInformationDlg( wxWindow* pParent, const wxString& title, const StringToStringMap& olderDriverVersions,
        const wxString& currentVersion, const wxString& newestVersion, const wxString& dateReleased, const wxString& whatsNew, const bool boCurrentAutoUpdateCheckState ) :
    OkAndCancelDlg( pParent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize ), olderDriverVersions_( olderDriverVersions ),
    currentVersion_( currentVersion ), newestVersion_( newestVersion ), dateReleased_( dateReleased ), whatsNew_( whatsNew )
//-----------------------------------------------------------------------------
{
    /*
    |-------------------------------------|
    | pTopDownSizer                       |
    |                spacer               |
    | |---------------------------------| |
    | |          Release Info           | |
    | |---------------------------------| |
    |                spacer               |
    | |---------------------------------| |
    | |            WhatsNew             | |
    | |---------------------------------| |
    |-------------------------------------|
    */

    wxBoxSizer* pTopDownSizer = new wxBoxSizer( wxVERTICAL );
    pTopDownSizer->AddSpacer( 20 );
    wxPanel* pPanel = new wxPanel( this );

    wxFont tmpFont = pPanel->GetFont();
    tmpFont.SetPointSize( pPanel->GetFont().GetPointSize() + 1 );

    wxStaticText* pVersionText = new wxStaticText( pPanel, wxID_ANY, ( VersionFromString( currentVersion_ ) < VersionFromString( newestVersion_ ) ) ? wxT( "A newer mvIMPACT Acquire version has been released:" ) : wxT( "The newest mvIMPACT Acquire version has already been installed on your system:" ) );
    pVersionText->SetFont( tmpFont );

    wxStaticText* pNewVersion = new wxStaticText( pPanel, wxID_ANY, ( VersionFromString( newestVersion_ ) >= VersionFromString( currentVersion_ ) ) ? newestVersion_ : currentVersion_ );
    wxStaticText* pDateText = new wxStaticText( pPanel, wxID_ANY, wxT( "Release date:" ) );
    wxStaticText* pDate = new wxStaticText( pPanel, wxID_ANY, ( VersionFromString( newestVersion_ ) >= VersionFromString( currentVersion_ ) ) ? dateReleased_ : wxString( wxT( "Not yet released" ) ) );
    wxStaticText* pWhatsNewText = new wxStaticText( pPanel, wxID_ANY, wxT( "What's new:" ) );

    wxTextCtrl* pWhatsNew = new wxTextCtrl( pPanel, wxID_ANY, whatsNew_, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxBORDER_NONE | wxTE_RICH | wxTE_READONLY | wxTE_DONTWRAP );
    wxFont* fixedWidthFont = new wxFont( 8, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL );
    pWhatsNew->SetFont( *fixedWidthFont );
    pWhatsNew->ShowPosition( 0 );
    pTopDownSizer->Add( pVersionText, wxSizerFlags().Align( wxALIGN_CENTRE_HORIZONTAL ) );
    pTopDownSizer->Add( pNewVersion, wxSizerFlags().Align( wxALIGN_CENTRE_HORIZONTAL ) );
    if( VersionFromString( currentVersion_ ) < VersionFromString( newestVersion_ ) )
    {
        pNewVersion->SetForegroundColour( *wxBLUE );
        wxStaticText* pOldVersion = new wxStaticText( pPanel, wxID_ANY, wxString::Format( wxT( "(current version is %s)" ), currentVersion_.c_str() ) );
        pTopDownSizer->Add( pOldVersion, wxSizerFlags().Align( wxALIGN_CENTRE_HORIZONTAL ) );
    }

    if( olderDriverVersions.empty() )
    {
        pTopDownSizer->AddSpacer( 25 );
        pTopDownSizer->Add( pDateText, wxSizerFlags().Align( wxALIGN_CENTRE_HORIZONTAL ) );
        pTopDownSizer->Add( pDate, wxSizerFlags().Align( wxALIGN_CENTRE_HORIZONTAL ) );
        pTopDownSizer->AddSpacer( 25 );
    }
    else
    {
        wxStaticText* pDriversNotUpToDateText = new wxStaticText( pPanel, wxID_ANY, wxString::Format( wxT( "%s, following driver%s not up to date:" ),
                VersionFromString( currentVersion_ ) < VersionFromString( newestVersion_ ) ? "Furthermore" : "However",
                olderDriverVersions.size() == 1 ? wxT( " is" ) : wxT( "s are" ) ) );
        wxStaticText* pDriversUpdateRecommendationText = new wxStaticText( pPanel, wxID_ANY, wxT( "It is recommended that all installed drivers are of the same version!" ) );
        pDriversNotUpToDateText->SetFont( tmpFont );
        pDriversUpdateRecommendationText->SetFont( tmpFont );

        pTopDownSizer->AddSpacer( 10 );
        pTopDownSizer->Add( pDateText, wxSizerFlags().Align( wxALIGN_CENTRE_HORIZONTAL ) );
        pTopDownSizer->Add( pDate, wxSizerFlags().Align( wxALIGN_CENTRE_HORIZONTAL ) );
        pTopDownSizer->AddSpacer( 25 );
        pTopDownSizer->Add( pDriversNotUpToDateText, wxSizerFlags().Align( wxALIGN_CENTRE_HORIZONTAL ) );

        StringToStringMap::const_iterator it = olderDriverVersions_.begin();
        StringToStringMap::const_iterator itEND = olderDriverVersions_.end();
        for( ; it != itEND; it++ )
        {
            wxStaticText* pOldDriverText = new wxStaticText( pPanel, wxID_ANY, wxString::Format( wxT( "%s(Version %s)" ), ( it->first ).mb_str(), ( it->second ).mb_str() ) );
            pOldDriverText->SetForegroundColour( acDarkBluePastel );
            pTopDownSizer->Add( pOldDriverText, wxSizerFlags().Align( wxALIGN_CENTRE_HORIZONTAL ) );
        }
        pTopDownSizer->AddSpacer( 10 );
        pTopDownSizer->Add( pDriversUpdateRecommendationText, wxSizerFlags().Align( wxALIGN_CENTRE_HORIZONTAL ) );
        pTopDownSizer->AddSpacer( 25 );
    }

    pTopDownSizer->Add( pWhatsNewText, wxSizerFlags().Align( wxALIGN_CENTRE_HORIZONTAL ) );
    pTopDownSizer->AddSpacer( 10 );
    pTopDownSizer->Add( pWhatsNew, wxSizerFlags().Expand() );
    pTopDownSizer->AddSpacer( 10 );

    pDateText->SetFont( tmpFont );
    pWhatsNewText->SetFont( tmpFont );
    tmpFont.SetWeight( wxFONTWEIGHT_BOLD );
    pDate->SetFont( tmpFont );
    tmpFont.SetPointSize( tmpFont.GetPointSize() + 1 );
    pNewVersion->SetFont( tmpFont );

    // lower line of buttons
    wxBoxSizer* pButtonSizer = new wxBoxSizer( wxHORIZONTAL );
    pCBAutoCheckForUpdatesWeekly_ = new wxCheckBox( pPanel, wxID_ANY, wxT( "&Auto-Check For Updates Every Week..." ) );
    pCBAutoCheckForUpdatesWeekly_->SetValue( boCurrentAutoUpdateCheckState );
    pButtonSizer->Add( pCBAutoCheckForUpdatesWeekly_, wxSizerFlags().Border( wxALL, 7 ) );
    pButtonSizer->AddStretchSpacer( 100 );
    if( ( !olderDriverVersions_.empty() ) ||
        ( VersionFromString( currentVersion_ ) < VersionFromString( newestVersion_ ) ) )
    {
        pBtnOk_ = new wxButton( pPanel, widBtnOk, wxT( "&Go To Download Page" ) );
        pButtonSizer->Add( pBtnOk_, wxSizerFlags().Border( wxALL, 7 ) );
    }
    pBtnCancel_ = new wxButton( pPanel, widBtnCancel, wxT( "&Ok" ) );
    pButtonSizer->Add( pBtnCancel_, wxSizerFlags().Border( wxALL, 7 ) );
    pTopDownSizer->Add( pButtonSizer, wxSizerFlags().Expand() );

    FinalizeDlgCreation( pPanel, pTopDownSizer );
    SetSize( 640, -1 );
    Center();
}

//=============================================================================
//============== Implementation FindFeatureDlg ================================
//=============================================================================
BEGIN_EVENT_TABLE( FindFeatureDlg, OkAndCancelDlg )
    EVT_CHECKBOX( widCBMatchCase, FindFeatureDlg::OnMatchCaseChanged )
    EVT_LISTBOX( widLBFeatureList, FindFeatureDlg::OnFeatureListSelect )
    EVT_LISTBOX_DCLICK( widLBFeatureList, FindFeatureDlg::OnFeatureListDblClick )
    EVT_TEXT( widTCFeatureName, FindFeatureDlg::OnFeatureNameTextChanged )
END_EVENT_TABLE()
//-----------------------------------------------------------------------------
FindFeatureDlg::FindFeatureDlg( PropGridFrameBase* pParent, const NameToFeatureMap& nameToFeatureMap, const bool boMatchCaseActive ) :
    OkAndCancelDlg( pParent, wxID_ANY, wxT( "Find Feature" ), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX ),
    pParent_( pParent ), nameToFeatureMap_( nameToFeatureMap )
//-----------------------------------------------------------------------------
{
    /*
        |-------------------------------------|
        | pTopDownSizer                       |
        |                spacer               |
        |                message              |
        |                spacer               |
        | |---------------------------------| |
        | | pLBFeatureList_                 | |
        | |---------------------------------| |
        |                spacer               |
        | |---------------------------------| |
        | | pButtonSizer                    | |
        | |---------------------------------| |
        |-------------------------------------|
    */

    wxPanel* pPanel = new wxPanel( this );

    wxBoxSizer* pTopDownSizer = new wxBoxSizer( wxVERTICAL );
    pTopDownSizer->AddSpacer( 10 );
    pTopDownSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxT( " Type the name of feature you are looking for." ) ) );
    pTopDownSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxT( " " ) ) );
    pTopDownSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxT( " A Double-click on a list item will automatically select the feature and close this dialog. " ) ) );
    pTopDownSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxT( " " ) ) );
    pTopDownSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxT( " Use '|' to combine multiple search strings(whitespace characters will be interpreted as part of the " ) ) );
    pTopDownSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxT( " tokens to search for). " ) ) );
    pTopDownSizer->AddSpacer( 10 );
    pTCFeatureName_ = new wxTextCtrl( pPanel, widTCFeatureName );
    pTopDownSizer->Add( pTCFeatureName_, wxSizerFlags().Expand() );
    pTopDownSizer->AddSpacer( 10 );
    pCBMatchCase_ = new wxCheckBox( pPanel, widCBMatchCase, wxT( "Match &case" ) );
    pCBMatchCase_->SetValue( boMatchCaseActive );
    pTopDownSizer->Add( pCBMatchCase_ );
    pTopDownSizer->AddSpacer( 10 );
    wxArrayString features;
    BuildFeatureList( features );
    pLBFeatureList_ = new wxListBox( pPanel, widLBFeatureList, wxDefaultPosition, wxDefaultSize, features );
    pTopDownSizer->Add( pLBFeatureList_, wxSizerFlags( 6 ).Expand() );
    AddButtons( pPanel, pTopDownSizer );
    FinalizeDlgCreation( pPanel, pTopDownSizer );
    SetSize( 200, 250 );
}

//-----------------------------------------------------------------------------
void FindFeatureDlg::BuildFeatureList( wxArrayString& features, const bool boMatchCase /* = false */, const wxString& pattern /* = wxEmptyString */ ) const
//-----------------------------------------------------------------------------
{
    NameToFeatureMap::const_iterator it = nameToFeatureMap_.begin();
    const NameToFeatureMap::const_iterator itEND = nameToFeatureMap_.end();
    wxArrayString searchTokens = wxSplit( pattern, wxT( '|' ) );
    wxArrayString::size_type searchTokenCount = searchTokens.size();
    while( it != itEND )
    {
        bool boAddToList = pattern.IsEmpty();
        if( !boAddToList )
        {
            const wxString candidate( boMatchCase ? it->first : it->first.Lower() );
            for( wxArrayString::size_type i = 0; i < searchTokenCount; i++ )
            {
                if( candidate.Find( searchTokens[i].c_str() ) != wxNOT_FOUND )
                {
                    boAddToList = true;
                    break;
                }
            }
        }

        if( boAddToList )
        {
            Component c( it->second->GetComponent() );
            if( c.visibility() != cvInvisible )
            {
                const size_t index = features.Add( it->first );
                if( GlobalDataStorage::Instance()->GetComponentVisibility() < c.visibility() )
                {
                    features[index].Append( wxString::Format( wxT( " (%s level)" ), ConvertedString( c.visibilityAsString() ).c_str() ) );
                }
                if( !c.isVisible() )
                {
                    features[index].Append( wxT( " (currently invisible)" ) );
                }
            }
        }
        ++it;
    }
}

//-----------------------------------------------------------------------------
void FindFeatureDlg::OnFeatureListDblClick( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
    SelectFeatureInPropertyGrid( e.GetSelection() );
    Close();
}

//-----------------------------------------------------------------------------
void FindFeatureDlg::SelectFeatureInPropertyGrid( const wxString& selection )
//-----------------------------------------------------------------------------
{
    NameToFeatureMap::const_iterator it = nameToFeatureMap_.find( selection );
    if( it != nameToFeatureMap_.end() )
    {
        pParent_->SelectPropertyInPropertyGrid( it->second );
    }
}

//-----------------------------------------------------------------------------
void FindFeatureDlg::SelectFeatureInPropertyGrid( const int selection )
//-----------------------------------------------------------------------------
{
    SelectFeatureInPropertyGrid( pLBFeatureList_->GetString( selection ) );
}

//-----------------------------------------------------------------------------
void FindFeatureDlg::UpdateFeatureList( void )
//-----------------------------------------------------------------------------
{
    wxString pattern( pCBMatchCase_->GetValue() ? pTCFeatureName_->GetValue() : pTCFeatureName_->GetValue().Lower() );
    while( !pattern.IsEmpty() && ( pattern.Last() == wxT( '|' ) ) )
    {
        pattern.RemoveLast();
    }
    pLBFeatureList_->Clear();
    wxArrayString features;
    BuildFeatureList( features, pCBMatchCase_->GetValue(), pattern );
    if( !features.empty() )
    {
        pLBFeatureList_->InsertItems( features, 0 );
    }
}

//=============================================================================
//============== Implementation DetailedFeatureInfoDlg ========================
//=============================================================================
//-----------------------------------------------------------------------------
DetailedFeatureInfoDlg::DetailedFeatureInfoDlg( wxWindow* pParent, Component comp ) :
    OkAndCancelDlg( pParent, wxID_ANY, wxT( "Detailed Feature Info" ), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX ),
    pLogWindow_( 0 )
//-----------------------------------------------------------------------------
{
    fixedPitchStyle_.SetFont( wxFont( 10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL ) );
    fixedPitchStyle_.SetTextColour( *wxBLUE );
    wxFont font( 10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD );
    //font.SetUnderlined( true );
    fixedPitchStyleBold_.SetFont( font );
    /*
        |-------------------------------------|
        | pFlexGridSizer                      |
        |                spacer               |
        | |---------------------------------| |
        | | pButtonSizer                    | |
        | |---------------------------------| |
        |-------------------------------------|
    */
    wxPanel* pPanel = new wxPanel( this );
    wxBoxSizer* pTopDownSizer = new wxBoxSizer( wxVERTICAL );
    pLogWindow_ = new wxTextCtrl( pPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxBORDER_NONE | wxTE_RICH | wxTE_READONLY );
    AddFeatureInfo( wxT( "Component Name: " ), ConvertedString( comp.name() ) );
    AddFeatureInfo( wxT( "Component Display Name: " ), ConvertedString( comp.displayName() ) );
    AddFeatureInfo( wxT( "Component Description: " ), ConvertedString( comp.docString() ) );
    AddFeatureInfo( wxT( "Component Type: " ), ConvertedString( comp.typeAsString() ) );
    AddFeatureInfo( wxT( "Component Visibility: " ), ConvertedString( comp.visibilityAsString() ) );
    AddFeatureInfo( wxT( "Component Representation: " ), ConvertedString( comp.representationAsString() ) );
    AddFeatureInfo( wxT( "Component Flags: " ), ConvertedString( comp.flagsAsString() ) );
    AddFeatureInfo( wxT( "Component Default State: " ), comp.isDefault() ? wxT( "Yes" ) : wxT( "No" ) );
    {
        vector<mvIMPACT::acquire::Component> selectingFeatures;
        comp.selectingFeatures( selectingFeatures );
        ostringstream oss;
        if( selectingFeatures.empty() )
        {
            oss << "NO OTHER FEATURE";
        }
        else
        {
            PropData::AppendSelectorInfo( oss, selectingFeatures );
        }
        AddFeatureInfo( wxT( "Component Is Selected By: " ), ConvertedString( oss.str() ) );
    }
    {
        vector<mvIMPACT::acquire::Component> selectedFeatures;
        comp.selectedFeatures( selectedFeatures );
        ostringstream oss;
        if( selectedFeatures.empty() )
        {
            oss << "NO OTHER FEATURE";
        }
        else
        {
            PropData::AppendSelectorInfo( oss, selectedFeatures );
        }
        AddFeatureInfo( wxT( "Component Selects: " ), ConvertedString( oss.str() ) );
    }
    AddFeatureInfo( wxT( "Component Handle(HOBJ): " ), wxString::Format( wxT( "0x%08x" ), comp.hObj() ) );
    AddFeatureInfo( wxT( "Component Changed Counter: " ), wxString::Format( wxT( "%d" ), comp.changedCounter() ) );
    AddFeatureInfo( wxT( "Component Changed Counter(Attributes): " ), wxString::Format( wxT( "%d" ), comp.changedCounterAttr() ) );
    const TComponentType type( comp.type() );
    if( type == ctList )
    {
        ComponentList list( comp );
        AddFeatureInfo( wxT( "List Content Descriptor: " ), ConvertedString( list.contentDescriptor() ) );
        AddFeatureInfo( wxT( "List Size: " ), wxString::Format( wxT( "%d" ), list.size() ) );
    }
    else if( type == ctMeth )
    {
        Method meth( comp );
        AddFeatureInfo( wxT( "Method Parameter List: " ), ConvertedString( meth.paramList() ) );
        AddFeatureInfo( wxT( "Method Signature: " ), MethodObject::BuildFriendlyName( meth.hObj() ) );
    }
    else if( type & ctProp )
    {
        Property prop( comp );
        AddFeatureInfo( wxT( "Property String Format String: " ), ConvertedString( prop.stringFormatString() ) );
        const int valCnt = static_cast<int>( prop.valCount() );
        AddFeatureInfo( wxT( "Property Value Count: " ), wxString::Format( wxT( "%d" ), valCnt ) );
        AddFeatureInfo( wxT( "Property Value Count(max): " ), wxString::Format( wxT( "%u" ), prop.maxValCount() ) );
        if( ( prop.type() == ctPropString ) && ( prop.flags() & cfContainsBinaryData ) )
        {
            // The 'prop.type()' check is only needed because some drivers with versions < 1.12.33
            // did incorrectly specify the 'cfContainsBinaryData' flag even though the data type was not 'ctPropString'...
            for( int i = 0; i < valCnt; i++ )
            {
                PropertyS propS( comp );
                AddFeatureInfo( wxString::Format( wxT( "Property Value[%d]: " ), i ), wxEmptyString );
                wxString binaryDataFormatted;
                try
                {
                    wxString binaryDataRAW( ConvertedString( BinaryDataToString( propS.readBinary( i ) ) ) );
                    BinaryDataDlg::FormatData( binaryDataRAW, binaryDataFormatted, 64, 8 );
                    binaryDataFormatted.RemoveLast(); // Remove the last '\n' as this will be added by 'AddFeatureInfo' as well!
                    AddFeatureInfo( wxEmptyString, binaryDataFormatted );
                }
                catch( const ImpactAcquireException& e )
                {
                    AddFeatureInfoFromException( wxEmptyString, e );
                }
                AddFeatureInfo( wxString::Format( wxT( "Property Value Binary Buffer Size[%d]: " ), i ), wxString::Format( wxT( "%u" ), propS.binaryDataBufferSize( i ) ) );
            }
        }
        else
        {
            for( int i = 0; i < valCnt; i++ )
            {
                const wxString infoValue = wxString::Format( wxT( "Property Value[%d]: " ), i );
                try
                {
                    AddFeatureInfo( infoValue, ConvertedString( prop.readS( i, string( ( prop.flags() & cfAllowValueCombinations ) ? "\"%s\" " : "" ) ) ) );
                }
                catch( const ImpactAcquireException& e )
                {
                    AddFeatureInfoFromException( infoValue, e );
                }
            }
        }
        try
        {
            AddFeatureInfo( wxT( "Property Value(min): " ), ConvertedString( prop.hasMinValue() ? prop.readS( plMinValue ) : string( "NOT DEFINED" ) ) );
        }
        catch( const ImpactAcquireException& e )
        {
            AddFeatureInfoFromException( wxT( "Property Value(min): " ), e );
        }
        try
        {
            AddFeatureInfo( wxT( "Property Value(max): " ), ConvertedString( prop.hasMaxValue() ? prop.readS( plMaxValue ) : string( "NOT DEFINED" ) ) );
        }
        catch( const ImpactAcquireException& e )
        {
            AddFeatureInfoFromException( wxT( "Property Value(max): " ), e );
        }
        try
        {
            AddFeatureInfo( wxT( "Property Value(inc): " ), ConvertedString( prop.hasStepWidth() ? prop.readS( plStepWidth ) : string( "NOT DEFINED" ) ) );
        }
        catch( const ImpactAcquireException& e )
        {
            AddFeatureInfoFromException( wxT( "Property Value(inc): " ), e );
        }
        if( ( type == ctPropString ) && ( prop.flags() & cfContainsBinaryData ) )
        {
            PropertyS propS( comp );
            AddFeatureInfo( wxT( "Property Value Binary Buffer Size(max): " ), wxString::Format( wxT( "%u" ), propS.binaryDataBufferMaxSize() ) );
        }

        if( prop.hasDict() )
        {
            const wxString formatString = ConvertedString( prop.stringFormatString() );
            try
            {
                if( type == ctPropInt )
                {
                    vector<pair<string, int> > dict;
                    PropertyI( prop ).getTranslationDict( dict );
                    const vector<pair<string, int> >::size_type vSize = dict.size();
                    for( vector<pair<string, int> >::size_type i = 0; i < vSize; i++ )
                    {
                        const wxString value = wxString::Format( formatString.c_str(), dict[i].second );
                        AddFeatureInfo( wxString::Format( wxT( "Property Translation Dictionary Entry[%u]: " ), static_cast<unsigned int>( i ) ), wxString::Format( wxT( "%s(%s)" ), ConvertedString( dict[i].first ).c_str(), value.c_str() ) );
                    }
                }
                else if( type == ctPropInt64 )
                {
                    vector<pair<string, int64_type> > dict;
                    PropertyI64( prop ).getTranslationDict( dict );
                    const vector<pair<string, int64_type> >::size_type vSize = dict.size();
                    for( vector<pair<string, int64_type> >::size_type i = 0; i < vSize; i++ )
                    {
                        const wxString value = wxString::Format( formatString.c_str(), dict[i].second );
                        AddFeatureInfo( wxString::Format( wxT( "Property Translation Dictionary Entry[%u]: " ), static_cast<unsigned int>( i ) ), wxString::Format( wxT( "%s(%s)" ), ConvertedString( dict[i].first ).c_str(), value.c_str() ) );
                    }
                }
                else if( type == ctPropFloat )
                {
                    vector<pair<string, double> > dict;
                    PropertyF( prop ).getTranslationDict( dict );
                    const vector<pair<string, double> >::size_type vSize = dict.size();
                    for( vector<pair<string, double> >::size_type i = 0; i < vSize; i++ )
                    {
                        const wxString value = wxString::Format( formatString.c_str(), dict[i].second );
                        AddFeatureInfo( wxString::Format( wxT( "Property Translation Dictionary Entry[%u]: " ), static_cast<unsigned int>( i ) ), wxString::Format( wxT( "%s(%s)" ), ConvertedString( dict[i].first ).c_str(), value.c_str() ) );
                    }
                }
            }
            catch( const ImpactAcquireException& e )
            {
                AddFeatureInfoFromException( wxT( "Property Translation Dictionary: " ), e );
            }
        }
    }
    pTopDownSizer->Add( pLogWindow_, wxSizerFlags( 6 ).Expand() );
    pLogWindow_->ScrollLines( -( 256 * 256 ) ); // make sure the text control always shows the beginning of the help text
    AddButtons( pPanel, pTopDownSizer );
    FinalizeDlgCreation( pPanel, pTopDownSizer );
    SetSize( 700, 700 );
}

//-----------------------------------------------------------------------------
void DetailedFeatureInfoDlg::AddFeatureInfo( const wxString& infoName, const wxString& info )
//-----------------------------------------------------------------------------
{
    WriteToTextCtrl( pLogWindow_, infoName, fixedPitchStyleBold_ );
    if( !infoName.IsEmpty() && ( infoName.Last() != wxChar( wxT( ' ' ) ) ) )
    {
        WriteToTextCtrl( pLogWindow_, wxT( " " ), fixedPitchStyle_ );
    }
    WriteToTextCtrl( pLogWindow_, info, fixedPitchStyle_ );
    WriteToTextCtrl( pLogWindow_, wxT( "\n" ) );
}

//-----------------------------------------------------------------------------
void DetailedFeatureInfoDlg::AddFeatureInfoFromException( const wxString& infoName, const ImpactAcquireException& e )
//-----------------------------------------------------------------------------
{
    AddFeatureInfo( infoName, wxString::Format( wxT( "There was a problem reading this value: %s(%d(%s))" ), ConvertedString( e.getErrorString() ).c_str(), e.getErrorCode(), ConvertedString( e.getErrorCodeAsString() ).c_str() ) );
}

//=============================================================================
//============== Implementation BinaryDataDlg =================================
//=============================================================================
BEGIN_EVENT_TABLE( BinaryDataDlg, OkAndCancelDlg )
    EVT_TEXT( widTCBinaryData, BinaryDataDlg::OnBinaryDataTextChanged )
END_EVENT_TABLE()
//-----------------------------------------------------------------------------
BinaryDataDlg::BinaryDataDlg( wxWindow* pParent, const wxString& featureName, const wxString& value ) :
    OkAndCancelDlg( pParent, wxID_ANY, wxString::Format( wxT( "Binary Data Editor(%s)" ), featureName.c_str() ), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX ),
    pTCBinaryData_( 0 ), pTCAsciiData_( 0 )
//-----------------------------------------------------------------------------
{
    /*
        |-------------------------------------|
        | pTopDownSizer                       |
        |                spacer               |
        | |---------------------------------| |
        | | pLeftRightSizer                 | |
        | |---------------------------------| |
        | |---------------------------------| |
        | | pButtonSizer                    | |
        | |---------------------------------| |
        |-------------------------------------|
    */

    wxPanel* pPanel = new wxPanel( this );

    wxFont fixedPitchFont( 10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL );
    fixedPitchStyle_.SetFont( fixedPitchFont );

    pTCBinaryData_ = new wxTextCtrl( pPanel, widTCBinaryData, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxBORDER_NONE | wxTE_RICH2, HEXStringValidator_ );
    pTCBinaryData_->SetDefaultStyle( fixedPitchStyle_ );
    pTCAsciiData_ = new wxTextCtrl( pPanel, widTCAsciiData, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxBORDER_NONE | wxTE_RICH2 | wxTE_READONLY );
    pTCAsciiData_->SetDefaultStyle( fixedPitchStyle_ );
    WriteToTextCtrl( pTCBinaryData_, value, fixedPitchStyle_ );
    ReformatBinaryData();

    wxBoxSizer* pLeftRightSizer = new wxBoxSizer( wxHORIZONTAL );
    pLeftRightSizer->Add( pTCBinaryData_, wxSizerFlags( 2 ).Expand() );
    pLeftRightSizer->Add( pTCAsciiData_, wxSizerFlags( 1 ).Expand() );

    wxBoxSizer* pTopDownSizer = new wxBoxSizer( wxVERTICAL );
    pTopDownSizer->AddSpacer( 10 );
    pTopDownSizer->Add( pLeftRightSizer, wxSizerFlags( 6 ).Expand() );
    AddButtons( pPanel, pTopDownSizer );
    FinalizeDlgCreation( pPanel, pTopDownSizer );
    SetSize( 560, 200 );
}

//-----------------------------------------------------------------------------
size_t BinaryDataDlg::FormatData( const wxString& data, wxString& formattedData, const int lineLength, const int fieldLength )
//-----------------------------------------------------------------------------
{
    const size_t len = data.Length();
    for( size_t i = 0; i < len; i++ )
    {
        formattedData.Append( data[i] );
        if( i > 0 )
        {
            if( ( ( i + 1 ) % lineLength ) == 0 )
            {
                formattedData.Append( wxT( "\n" ) );
            }
            else if( ( ( i + 1 ) % fieldLength ) == 0 )
            {
                formattedData.Append( wxT( " " ) );
            }
        }
    }
    return formattedData.Length();
}

//-----------------------------------------------------------------------------
wxString BinaryDataDlg::GetBinaryData( void ) const
//-----------------------------------------------------------------------------
{
    wxString data( pTCBinaryData_->GetValue() );
    RemoveSeparatorChars( data );
    return data;
}

//-----------------------------------------------------------------------------
void BinaryDataDlg::OnBinaryDataTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
    ReformatBinaryData();
    UpdateAsciiData();
}

//-----------------------------------------------------------------------------
void BinaryDataDlg::ReformatBinaryData( void )
//-----------------------------------------------------------------------------
{
    wxString data( pTCBinaryData_->GetValue() );
    long x = 0;
    long y = 0;
    pTCBinaryData_->PositionToXY( pTCBinaryData_->GetInsertionPoint(), &x, &y );

    const size_t pos = static_cast<size_t>( ( y * 36 ) + x );
    if( ( ( x == 9 ) || ( x == 18 ) || ( x == 27 ) ) &&
        ( ( data.Length() > pos ) && ( data[pos] == wxT( ' ' ) ) ) )
    {
        ++x;
    }
    RemoveSeparatorChars( data );
    wxString formattedData;
    FormatData( data, formattedData, 32, 8 );
#if wxCHECK_VERSION(2, 7, 1)
    pTCBinaryData_->ChangeValue( formattedData ); // this function will NOT generate a wxEVT_COMMAND_TEXT_UPDATED event.
#else
    pTCBinaryData_->SetValue( formattedData ); // this function will generate a wxEVT_COMMAND_TEXT_UPDATED event and has been declared deprecated.
#endif // #if wxCHECK_VERSION(2, 7, 1)
    pTCBinaryData_->SetStyle( 0, pTCBinaryData_->GetLastPosition(), fixedPitchStyle_ );
    if( x == 36 )
    {
        if( lastDataLength_ > formattedData.Length() )
        {

        }
        else if( lastDataLength_ < formattedData.Length() )
        {
            x = 1;
            ++y;
        }
    }
    lastDataLength_ = formattedData.Length();
    pTCBinaryData_->SetInsertionPoint( pTCBinaryData_->XYToPosition( x, y ) );
}

//-----------------------------------------------------------------------------
void BinaryDataDlg::RemoveSeparatorChars( wxString& data )
//-----------------------------------------------------------------------------
{
    data.Replace( wxT( " " ), wxT( "" ) );
    data.Replace( wxT( "\n" ), wxT( "" ) );
    data.Replace( wxT( "\r" ), wxT( "" ) );
}

//-----------------------------------------------------------------------------
void BinaryDataDlg::UpdateAsciiData( void )
//-----------------------------------------------------------------------------
{
    string binaryDataRawANSI( GetBinaryData().mb_str() );
    string binaryData( BinaryDataFromString( binaryDataRawANSI ) );
    const string::size_type len = binaryData.size();
    for( string::size_type i = 0; i < len; i++ )
    {
        if( static_cast<unsigned char>( binaryData[i] ) < 32 ) // 32 is the whitespace
        {
            binaryData[i] = '.';
        }
    }
    wxString formattedData;
    FormatData( ConvertedString( binaryData ), formattedData, 16, 4 );
#if wxCHECK_VERSION(2, 7, 1)
    pTCAsciiData_->ChangeValue( formattedData ); // this function will NOT generate a wxEVT_COMMAND_TEXT_UPDATED event.
#else
    pTCAsciiData_->SetValue( formattedData ); // this function will generate a wxEVT_COMMAND_TEXT_UPDATED event and has been declared deprecated.
#endif // #if wxCHECK_VERSION(2, 7, 1)
    pTCAsciiData_->SetStyle( 0, pTCAsciiData_->GetLastPosition(), fixedPitchStyle_ );
}

//=============================================================================
//============== Implementation AssignSettingsToDisplaysDlg ===================
//=============================================================================
//-----------------------------------------------------------------------------
AssignSettingsToDisplaysDlg::AssignSettingsToDisplaysDlg( wxWindow* pParent, const wxString& title,
        const vector<pair<string, int> >& settings, const SettingToDisplayDict& settingToDisplayDict, size_t displayCount )
    : OkAndCancelDlg( pParent, wxID_ANY, title )
//-----------------------------------------------------------------------------
{
    /*
        |-------------------------------------|
        | pTopDownSizer                       |
        |                spacer               |
        |                message              |
        |                spacer               |
        | |---------------------------------| |
        | | pGridSizer                      | |
        | |---------------------------------| |
        |                spacer               |
        | |---------------------------------| |
        | | pButtonSizer                    | |
        | |---------------------------------| |
        |-------------------------------------|
    */

    wxBoxSizer* pTopDownSizer = new wxBoxSizer( wxVERTICAL );
    pTopDownSizer->AddSpacer( 10 );
    wxPanel* pPanel = new wxPanel( this, wxID_ANY, wxPoint( 5, 5 ) );
    pTopDownSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxT( " Whenever a request is returned by\n the driver it will be drawn onto the\n display the used capture setting\n has been assigned to." ) ) );
    pTopDownSizer->AddSpacer( 10 );
    const int colCount = static_cast<int>( settings.size() );
    ctrls_.resize( colCount );
    wxFlexGridSizer* pGridSizer = new wxFlexGridSizer( 2 );
    wxArrayString choices;
    for( size_t i = 0; i < displayCount; i++ )
    {
        choices.Add( wxString::Format( wxT( "Display %u" ), static_cast<unsigned int>( i ) ) );
    }
    for( int i = 0; i < colCount; i++ )
    {
        pGridSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxString( wxT( " " ) ) + ConvertedString( settings[i].first ) ) );
        SettingToDisplayDict::const_iterator it = settingToDisplayDict.find( settings[i].second );
        wxArrayString::size_type selection = 0;
        if( settingToDisplayDict.empty() )
        {
            selection = i % displayCount;
        }
        else
        {
            selection = ( it != settingToDisplayDict.end() ) ? static_cast<wxArrayString::size_type>( it->second ) : 0;
        }
        ctrls_[i] = new wxComboBox( pPanel, widFirst + i, choices[selection], wxDefaultPosition, wxDefaultSize, choices, wxCB_DROPDOWN | wxCB_READONLY );
        pGridSizer->Add( ctrls_[i], wxSizerFlags().Expand() );
    }
    pTopDownSizer->Add( pGridSizer );
    AddButtons( pPanel, pTopDownSizer );
    FinalizeDlgCreation( pPanel, pTopDownSizer );
}

//=============================================================================
//============== Implementation RawImageImportDlg =============================
//=============================================================================
//-----------------------------------------------------------------------------
RawImageImportDlg::RawImageImportDlg( PropGridFrameBase* pParent, const wxString& title, const wxFileName& fileName )
    : OkAndCancelDlg( pParent, wxID_ANY, title ), pParent_( pParent )
//-----------------------------------------------------------------------------
{
    /*
        |-------------------------------------|
        | pTopDownSizer                       |
        |                spacer               |
        | |---------------------------------| |
        | | pGridSizer                      | |
        | |---------------------------------| |
        |                spacer               |
        | |---------------------------------| |
        | | pButtonSizer                    | |
        | |---------------------------------| |
        |-------------------------------------|
    */

    wxBoxSizer* pTopDownSizer = new wxBoxSizer( wxVERTICAL );
    pTopDownSizer->AddSpacer( 10 );

    wxPanel* pPanel = new wxPanel( this );
    wxFlexGridSizer* pGridSizer = new wxFlexGridSizer( 2 );
    wxArrayString pixelFormatChoices;
    pixelFormatChoices.Add( wxT( "Mono8" ) );
    pixelFormatChoices.Add( wxT( "Mono10" ) );
    pixelFormatChoices.Add( wxT( "Mono12" ) );
    pixelFormatChoices.Add( wxT( "Mono12Packed_V1" ) );
    pixelFormatChoices.Add( wxT( "Mono12Packed_V2" ) );
    pixelFormatChoices.Add( wxT( "Mono14" ) );
    pixelFormatChoices.Add( wxT( "Mono16" ) );
    pixelFormatChoices.Add( wxT( "BGR888Packed" ) );
    pixelFormatChoices.Add( wxT( "BGR101010Packed_V2" ) );
    pixelFormatChoices.Add( wxT( "RGB888Packed" ) );
    pixelFormatChoices.Add( wxT( "RGB101010Packed" ) );
    pixelFormatChoices.Add( wxT( "RGB121212Packed" ) );
    pixelFormatChoices.Add( wxT( "RGB141414Packed" ) );
    pixelFormatChoices.Add( wxT( "RGB161616Packed" ) );
    pixelFormatChoices.Add( wxT( "RGBx888Packed" ) );
    pixelFormatChoices.Add( wxT( "RGB888Planar" ) );
    pixelFormatChoices.Add( wxT( "RGBx888Planar" ) );
    pixelFormatChoices.Add( wxT( "YUV411_UYYVYY_Packed" ) );
    pixelFormatChoices.Add( wxT( "YUV422Packed" ) );
    pixelFormatChoices.Add( wxT( "YUV422_UYVYPacked" ) );
    pixelFormatChoices.Add( wxT( "YUV422_10Packed" ) );
    pixelFormatChoices.Add( wxT( "YUV422_UYVY_10Packed" ) );
    pixelFormatChoices.Add( wxT( "YUV444_UYVPacked" ) );
    pixelFormatChoices.Add( wxT( "YUV444_UYV_10Packed" ) );
    pixelFormatChoices.Add( wxT( "YUV444Packed" ) );
    pixelFormatChoices.Add( wxT( "YUV444_10Packed" ) );
    pixelFormatChoices.Add( wxT( "YUV422Planar" ) );

    wxArrayString bayerParityChoices;
    bayerParityChoices.Add( wxT( "Undefined" ) );
    bayerParityChoices.Add( wxT( "Red-green" ) );
    bayerParityChoices.Add( wxT( "Green-red" ) );
    bayerParityChoices.Add( wxT( "Blue-green" ) );
    bayerParityChoices.Add( wxT( "Green-blue" ) );

    // The file name is expected to look like this:
    // <name(don't care).<width>x<height>.<pixel format>(BayerPattern=<pattern>).raw
    wxString nakedName = fileName.GetName().BeforeFirst( wxT( '.' ) );
    wxString resolution = fileName.GetName().AfterFirst( wxT( '.' ) ).BeforeFirst( wxT( '.' ) );
    wxString width( resolution.BeforeFirst( wxT( 'x' ) ) );
    wxString height( resolution.AfterFirst( wxT( 'x' ) ) );
    wxString format = fileName.GetName().AfterLast( wxT( '.' ) );
    wxString formatNaked = format.BeforeFirst( wxT( '(' ) );
    wxString bayerPattern = format.AfterFirst( wxT( '=' ) ).BeforeFirst( wxT( ')' ) );

    if( nakedName.IsEmpty() || resolution.IsEmpty() || format.IsEmpty() )
    {
        pParent_->WriteLogMessage( wxString::Format( wxT( "Failed to extract file format from %s(%s %sx%s %s).\n" ), fileName.GetFullPath().c_str(), nakedName.c_str(), width.c_str(), height.c_str(), format.c_str() ) );
    }

    const size_t pixelFormatCount = pixelFormatChoices.Count();
    wxString initialPixelFormat = pixelFormatChoices[0];
    for( size_t i = 1; i < pixelFormatCount; i++ )
    {
        if( formatNaked == pixelFormatChoices[i] )
        {
            initialPixelFormat = pixelFormatChoices[i];
            break;
        }
    }

    const size_t bayerParityCount = bayerParityChoices.Count();
    wxString initialbayerParity = bayerParityChoices[0];
    for( size_t i = 1; i < bayerParityCount; i++ )
    {
        if( bayerPattern == bayerParityChoices[i] )
        {
            initialbayerParity = bayerParityChoices[i];
            break;
        }
    }

    pGridSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxT( " Pixel Format:" ) ) );
    pCBPixelFormat_ = new wxComboBox( pPanel, wxID_ANY, initialPixelFormat, wxDefaultPosition, wxDefaultSize, pixelFormatChoices, wxCB_DROPDOWN | wxCB_READONLY );
    pGridSizer->Add( pCBPixelFormat_, wxSizerFlags().Expand() );

    pGridSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxT( " Bayer Parity:" ) ) );
    pCBBayerParity_ = new wxComboBox( pPanel, wxID_ANY, initialbayerParity, wxDefaultPosition, wxDefaultSize, bayerParityChoices, wxCB_DROPDOWN | wxCB_READONLY );
    pGridSizer->Add( pCBBayerParity_, wxSizerFlags().Expand() );

    long w;
    width.ToLong( &w );
    width = wxString::Format( wxT( "%d" ), w ); // get rid of incorrect additional characters (in case someone did name the file 'bla.1024sdfgsdx1024@blub.Mono8.raw' this removes the 'sdfgsd' sequence
    pGridSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxT( " Width:" ) ) );
    pSCWidth_ = new wxSpinCtrl( pPanel, wxID_ANY, width, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 1024 * 256, w );
    pGridSizer->Add( pSCWidth_, wxSizerFlags().Expand() );

    long h;
    height.ToLong( &h );
    height = wxString::Format( wxT( "%d" ), h ); // get rid of incorrect additional characters (in case someone did name the file 'bla.1024sdfgsdx1024@blub.Mono8.raw' this removes the '@blub' sequence
    pGridSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxT( " Height:" ) ) );
    pSCHeight_ = new wxSpinCtrl( pPanel, wxID_ANY, height, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 1024 * 256, h );
    pGridSizer->Add( pSCHeight_, wxSizerFlags().Expand() );

    pTopDownSizer->Add( pGridSizer );
    AddButtons( pPanel, pTopDownSizer );
    FinalizeDlgCreation( pPanel, pTopDownSizer );
}

//-----------------------------------------------------------------------------
wxString RawImageImportDlg::GetFormat( void ) const
//-----------------------------------------------------------------------------
{
    wxString format( pCBPixelFormat_->GetValue() );
    if( pCBBayerParity_->GetValue() != wxT( "Undefined" ) )
    {
        format.Append( wxString::Format( wxT( "(BayerParity: %s)" ), pCBBayerParity_->GetValue().c_str() ) );
    }
    return format;
}

//-----------------------------------------------------------------------------
long RawImageImportDlg::GetWidth( void ) const
//-----------------------------------------------------------------------------
{
    return pSCWidth_->GetValue();
}

//-----------------------------------------------------------------------------
long RawImageImportDlg::GetHeight( void ) const
//-----------------------------------------------------------------------------
{
    return pSCHeight_->GetValue();
}

//=============================================================================
//============== Implementation OptionsDlg ====================================
//=============================================================================
//-----------------------------------------------------------------------------
OptionsDlg::OptionsDlg( PropGridFrameBase* pParent, const map<TWarnings, bool>& initialWarningConfiguration,
                        const map<TAppearance, bool>& initialAppearanceConfiguration,
                        const map<TPropertyGrid, bool>& initialPropertyGridConfiguration,
                        const map<TMiscellaneous, bool>& initialMiscellaneousConfiguration )
    : OkAndCancelDlg( pParent, wxID_ANY, wxT( "Options" ) ), pWarningConfiguration_( 0 ),
      pAppearanceConfiguration_( 0 ), pPropertyGridConfiguration_( 0 ), pMiscellaneousConfiguration_( 0 ),
      initialWarningConfiguration_(), initialAppearanceConfiguration_(), initialPropertyGridConfiguration_(),
      initialMiscellaneousConfiguration_(), boShowQuickSetupOnDeviceOpen_( false )
//-----------------------------------------------------------------------------
{
    /*
        |-------------------------------------|
        | pTopDownSizer                       |
        |                spacer               |
        | |---------------------------------| |
        | | pAppearanceConfiguration        | |
        | |---------------------------------| |
        |                spacer               |
        | |---------------------------------| |
        | | pWarningConfiguration           | |
        | |---------------------------------| |
        |                spacer               |
        | |---------------------------------| |
        | | pPropertyGridConfiguration      | |
        | |---------------------------------| |
        |                spacer               |
        | |---------------------------------| |
        | | pMiscellaneousConfiguration     | |
        | |---------------------------------| |
        |                spacer               |
        | |---------------------------------| |
        | | pButtonSizer                    | |
        | |---------------------------------| |
        |-------------------------------------|
    */

    wxBoxSizer* pTopDownSizer = new wxBoxSizer( wxVERTICAL );
    pTopDownSizer->AddSpacer( 10 );

    wxPanel* pPanel = new wxPanel( this );

    wxArrayString choices;
    choices.resize( aMAX );
    choices[aShowLeftToolBar] = wxT( "Show Left Tool Bar" );
    choices[aShowUpperToolBar] = wxT( "Show Upper Tool Bar" );
    choices[aShowStatusBar] =  wxT( "Show Status Bar" );
    CreateCheckListBox( pPanel, pTopDownSizer, &pAppearanceConfiguration_, choices, wxT( "Appearance: " ), initialAppearanceConfiguration );

    choices.resize( wMAX );
    choices[wWarnOnOutdatedFirmware] = wxT( "Warn On Outdated Firmware" );
    choices[wWarnOnReducedDriverPerformance] = wxT( "Warn On Reduced Driver Performance" );
#if defined(linux) || defined(__linux) || defined(__linux__)
    choices[wWarnOnPotentialNetworkUSBBufferIssues] = wxT( "Warn On Potential Network/USB Buffer Issues" );
#endif // #if defined(linux) || defined(__linux) || defined(__linux__)
    choices[wWarnOnPotentialFirewallIssues] = wxT( "Warn On Potential Firewall Issues" );
    CreateCheckListBox( pPanel, pTopDownSizer, &pWarningConfiguration_, choices, wxT( "Warnings: " ), initialWarningConfiguration );

    choices.resize( pgMAX );
    choices[pgDisplayToolTips] = wxT( "Display Tool Tips" );
    choices[pgUseSelectorGrouping] = wxT( "Use Selector Grouping" );
    choices[pgPreferDisplayNames] = wxT( "Prefer Display Names" );
    choices[pgCreateEditorsWithSlider] = wxT( "Create Editors With Slider" );
    choices[pgDisplayPropertyIndicesAsHex] = wxT( "Display Property Indices As Hex" );
    CreateCheckListBox( pPanel, pTopDownSizer, &pPropertyGridConfiguration_, choices, wxT( "Property Grid: " ), initialPropertyGridConfiguration );

    choices.resize( mMAX );
    choices[mAllowFastSingleFrameAcquisition] = wxT( "Allow Fast Single Frame Acquisition" );
    choices[mDisplayDetailedInformationOnCallbacks] = wxT( "Display Detailed Information On Callbacks" );
    choices[mDisplayMethodExecutionErrors] = wxT( "Display Method Execution Errors" );
    choices[mDisplayFeatureChangeTimeConsumption] = wxT( "Display Feature Change Time Consumption" );
    choices[mDisplayStatusBarTooltip] = wxT( "Display Status Bar Tooltip" );

    wxStaticBoxSizer* pMiscellaneousConfigurationSizer = CreateCheckListBox( pPanel, pTopDownSizer, &pMiscellaneousConfiguration_, choices, wxT( "Miscellaneous: " ), initialMiscellaneousConfiguration );

    pCBShowQuickSetupOnDeviceOpen_ = new wxCheckBox( pPanel, wxID_ANY, wxT( "Show Quick Setup On Device Open" ) );
    pMiscellaneousConfigurationSizer->AddSpacer( 5 );
    pMiscellaneousConfigurationSizer->Add( pCBShowQuickSetupOnDeviceOpen_ );

    AddButtons( pPanel, pTopDownSizer );
    FinalizeDlgCreation( pPanel, pTopDownSizer );
}

//-----------------------------------------------------------------------------
void OptionsDlg::BackupCurrentState( void )
//-----------------------------------------------------------------------------
{
    StoreCheckListBoxStateToMap( pWarningConfiguration_, initialWarningConfiguration_ );
    StoreCheckListBoxStateToMap( pAppearanceConfiguration_, initialAppearanceConfiguration_ );
    StoreCheckListBoxStateToMap( pPropertyGridConfiguration_, initialPropertyGridConfiguration_ );
    StoreCheckListBoxStateToMap( pMiscellaneousConfiguration_, initialMiscellaneousConfiguration_ );
    boShowQuickSetupOnDeviceOpen_ = pCBShowQuickSetupOnDeviceOpen_->IsChecked();
}

//-----------------------------------------------------------------------------
template<typename _Ty>
wxStaticBoxSizer* OptionsDlg::CreateCheckListBox( wxPanel* pPanel, wxBoxSizer* pTopDownSizer, wxCheckListBox** ppCheckListBox, const wxArrayString& choices, const wxString& title, const map<_Ty, bool>& initialConfiguration )
//-----------------------------------------------------------------------------
{
    *ppCheckListBox = new wxCheckListBox( pPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices );
    RestoreCheckListBoxStateFromMap( *ppCheckListBox, initialConfiguration );
    wxStaticBoxSizer* pConfigurationSizer = new wxStaticBoxSizer( wxVERTICAL, pPanel, title );
    pConfigurationSizer->Add( *ppCheckListBox, wxSizerFlags().Expand() );
    pTopDownSizer->Add( pConfigurationSizer, wxSizerFlags().Expand() );
    pTopDownSizer->AddSpacer( 10 );
    return pConfigurationSizer;
}

//-----------------------------------------------------------------------------
template<typename _Ty>
void OptionsDlg::RestoreCheckListBoxStateFromMap( wxCheckListBox* pCheckListBox, const map<_Ty, bool>& stateMap )
//-----------------------------------------------------------------------------
{
    typename map<_Ty, bool>::const_iterator it = stateMap.begin();
    const typename map<_Ty, bool>::const_iterator itEND = stateMap.end();
    while( it != itEND )
    {
        if( it->first < static_cast<_Ty>( pCheckListBox->GetCount() ) )
        {
            pCheckListBox->Check( it->first, it->second );
        }
        ++it;
    }
}

//-----------------------------------------------------------------------------
void OptionsDlg::RestorePreviousState( void )
//-----------------------------------------------------------------------------
{
    RestoreCheckListBoxStateFromMap( pWarningConfiguration_, initialWarningConfiguration_ );
    RestoreCheckListBoxStateFromMap( pAppearanceConfiguration_, initialAppearanceConfiguration_ );
    RestoreCheckListBoxStateFromMap( pPropertyGridConfiguration_, initialPropertyGridConfiguration_ );
    RestoreCheckListBoxStateFromMap( pMiscellaneousConfiguration_, initialMiscellaneousConfiguration_ );
    pCBShowQuickSetupOnDeviceOpen_->SetValue( boShowQuickSetupOnDeviceOpen_ );
}

//-----------------------------------------------------------------------------
template<typename _Ty>
void OptionsDlg::StoreCheckListBoxStateToMap( wxCheckListBox* pCheckListBox, map<_Ty, bool>& stateMap )
//-----------------------------------------------------------------------------
{
    stateMap.clear();
    const unsigned int count = pCheckListBox->GetCount();
    for( unsigned int i = 0; i < count; i++ )
    {
        stateMap.insert( make_pair( static_cast<_Ty>( i ), pCheckListBox->IsChecked( i ) ) );
    }
}

//=============================================================================
//============== Implementation WelcomeDlg ====================================
//=============================================================================
//-----------------------------------------------------------------------------
WelcomeToPropViewDialog::WelcomeToPropViewDialog( PropGridFrameBase* pParent ) :
    OkAndCancelDlg( pParent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
//-----------------------------------------------------------------------------
{
    /*
        |----------------------------------------|
        | pSTWelcome                             |
        |                spacer                  |
        | pInfoTextSizer                         |
        |                spacer                  |
        | |------------------------------------| |
        | | button OptionShowQSWSizer          | |
        | |------------------------------------| |
        |                spacer                  |
        | |------------------------------------| |
        | | button OptionDontShowQSWSizer      | |
        | |------------------------------------| |
        |                spacer                  |
        | |------------------------------------| |
        | | button OptionNeverShowQSWSizer     | |
        | |-------------------------------- ---| |
        |----------------------------------------|
    */

    wxPanel* pPanel = new wxPanel( this );

    wxFont headlineFont ( pPanel->GetFont() );
    headlineFont.SetWeight( wxFONTWEIGHT_BOLD );
    headlineFont.SetPointSize( 16 );

    const wxString showQSWHeadline( wxT( "Welcome to the Quick Setup wizard" ) );
    const wxString showQSWInformationString( wxT( "The 'Quick Setup' wizard is a configuration dialog that allows to optimize the device and driver settings to get the best possible\nresults regarding acquisition speed and image quality." ) );
    const wxString showQSWOptionOKString( wxT( "Show 'Quick Setup' wizard now (recommended for beginners)." ) );
    const wxString showQSWOptionDontShowString( wxT( "Don't show the 'Quick Setup' wizard now." ) );
    const wxString showQSWOptionNeverShowString( wxT( "Never show the 'Quick Setup' wizard upon device open." ) );

    pBtnOk_ = new wxButton( pPanel, widBtnOk, showQSWOptionOKString, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, wxT( "btnOK" ) );
    pBtnApply_ = new wxButton( pPanel, widBtnCancel, showQSWOptionDontShowString, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, wxT( "btnNO" ) );
    pBtnCancel_ = new wxButton( pPanel, widBtnApply, showQSWOptionNeverShowString, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, wxT( "btnNEVER" ) );

    pBtnOk_->SetBitmap( wxBitmap::NewFromPNGData( checked_png, sizeof( checked_png ) ) );
    pBtnApply_->SetBitmap( wxBitmap::NewFromPNGData( cancel_png, sizeof( cancel_png ) ) );
    pBtnCancel_->SetBitmap( wxBitmap::NewFromPNGData( unavailable_png, sizeof( unavailable_png ) ) );

    pBtnOk_->SetToolTip( wxT( "Proceeds to 'Quick Setup' wizard." ) );
    pBtnApply_->SetToolTip( wxT( "No settings will be changed, but the 'Quick Setup' wizard won't be disabled completely." ) );
    pBtnCancel_->SetToolTip( wxT( "The 'Quick Setup' wizard can be reenabled by enabling the 'Show Quick Setup On Device Open' option at the settings menu 'Settings -> Options...'" ) );

    wxBoxSizer* pInfoTextSizer = new wxBoxSizer( wxHORIZONTAL );
    pInfoTextSizer->AddSpacer( 12 );
    pInfoTextSizer->Add( new wxStaticText( pPanel, wxID_ANY, showQSWInformationString ), wxSizerFlags( ).Expand() );
    pInfoTextSizer->AddSpacer( 12 );

    wxStaticText* pSTWelcome =  new wxStaticText( pPanel, wxID_ANY, showQSWHeadline );
    pSTWelcome->SetFont( headlineFont );

    // putting it all together
    wxBoxSizer* pTopDownSizer = new wxBoxSizer( wxVERTICAL );
    pTopDownSizer->AddSpacer( 12 );
    pTopDownSizer->Add( pSTWelcome, wxSizerFlags().Expand() );
    pTopDownSizer->AddSpacer( 12 );
    pTopDownSizer->Add( pInfoTextSizer, wxSizerFlags().Expand() );
    pTopDownSizer->AddSpacer( 12 );
    AddButtonToSizer( pBtnOk_, pTopDownSizer );
    AddButtonToSizer( pBtnApply_, pTopDownSizer );
    AddButtonToSizer( pBtnCancel_, pTopDownSizer );

    wxBoxSizer* pOuterSizer = new wxBoxSizer( wxHORIZONTAL );
    pOuterSizer->AddSpacer( 12 );
    pOuterSizer->Add( pTopDownSizer, wxSizerFlags().Expand() );
    pOuterSizer->AddSpacer( 12 );

    FinalizeDlgCreation( pPanel, pOuterSizer );
}
