void PrintDialog::setupOptionalUI()

in main/vcl/source/window/printdlg.cxx [1179:1760]


void PrintDialog::setupOptionalUI()
{
    std::vector< boost::shared_ptr<vcl::RowOrColumn> > aDynamicColumns;
    boost::shared_ptr< vcl::RowOrColumn > pCurColumn;

    Window* pCurParent = 0, *pDynamicPageParent = 0;
    sal_uInt16 nOptPageId = 9, nCurSubGroup = 0;
    bool bOnStaticPage = false;
    bool bSubgroupOnStaticPage = false;
    
    std::multimap< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> > aPropertyToDependencyRowMap;
    
    const Sequence< PropertyValue >& rOptions( maPController->getUIOptions() );
    for( int i = 0; i < rOptions.getLength(); i++ )
    {
        Sequence< beans::PropertyValue > aOptProp;
        rOptions[i].Value >>= aOptProp;

        // extract ui element
        bool bEnabled = true;
        rtl::OUString aCtrlType;
        rtl::OUString aText;
        rtl::OUString aPropertyName;
        Sequence< rtl::OUString > aChoices;
        Sequence< sal_Bool > aChoicesDisabled;
        Sequence< rtl::OUString > aHelpTexts;
        Sequence< rtl::OUString > aHelpIds;
        sal_Int64 nMinValue = 0, nMaxValue = 0;
        sal_Int32 nCurHelpText = 0;
        rtl::OUString aGroupingHint;
        rtl::OUString aDependsOnName;
        sal_Int32 nDependsOnValue = 0;
        sal_Bool bUseDependencyRow = sal_False;

        for( int n = 0; n < aOptProp.getLength(); n++ )
        {
            const beans::PropertyValue& rEntry( aOptProp[ n ] );
            if( rEntry.Name.equalsAscii( "Text" ) )
            {
                rEntry.Value >>= aText;
            }
            else if( rEntry.Name.equalsAscii( "ControlType" ) )
            {
                rEntry.Value >>= aCtrlType;
            }
            else if( rEntry.Name.equalsAscii( "Choices" ) )
            {
                rEntry.Value >>= aChoices;
            }
            else if( rEntry.Name.equalsAscii( "ChoicesDisabled" ) )
            {
                rEntry.Value >>= aChoicesDisabled;
            }
            else if( rEntry.Name.equalsAscii( "Property" ) )
            {
                PropertyValue aVal;
                rEntry.Value >>= aVal;
                aPropertyName = aVal.Name;
            }
            else if( rEntry.Name.equalsAscii( "Enabled" ) )
            {
                sal_Bool bValue = sal_True;
                rEntry.Value >>= bValue;
                bEnabled = bValue;
            }
            else if( rEntry.Name.equalsAscii( "GroupingHint" ) )
            {
                rEntry.Value >>= aGroupingHint;
            }
            else if( rEntry.Name.equalsAscii( "DependsOnName" ) )
            {
                rEntry.Value >>= aDependsOnName;
            }
            else if( rEntry.Name.equalsAscii( "DependsOnEntry" ) )
            {
                rEntry.Value >>= nDependsOnValue;
            }
            else if( rEntry.Name.equalsAscii( "AttachToDependency" ) )
            {
                rEntry.Value >>= bUseDependencyRow;
            }
            else if( rEntry.Name.equalsAscii( "MinValue" ) )
            {
                rEntry.Value >>= nMinValue;
            }
            else if( rEntry.Name.equalsAscii( "MaxValue" ) )
            {
                rEntry.Value >>= nMaxValue;
            }
            else if( rEntry.Name.equalsAscii( "HelpText" ) )
            {
                if( ! (rEntry.Value >>= aHelpTexts) )
                {
                    rtl::OUString aHelpText;
                    if( (rEntry.Value >>= aHelpText) )
                    {
                        aHelpTexts.realloc( 1 );
                        *aHelpTexts.getArray() = aHelpText;
                    }
                }
            }
            else if( rEntry.Name.equalsAscii( "HelpId" ) )
            {
                if( ! (rEntry.Value >>= aHelpIds ) )
                {
                    rtl::OUString aHelpId;
                    if( (rEntry.Value >>= aHelpId) )
                    {
                        aHelpIds.realloc( 1 );
                        *aHelpIds.getArray() = aHelpId;
                    }
                }
            }
            else if( rEntry.Name.equalsAscii( "HintNoLayoutPage" ) )
            {
                sal_Bool bNoLayoutPage = sal_False;
                rEntry.Value >>= bNoLayoutPage;
                mbShowLayoutPage = ! bNoLayoutPage;
            }
        }
        
        // bUseDependencyRow should only be true if a dependency exists
        bUseDependencyRow = bUseDependencyRow && (aDependsOnName.getLength() != 0);
        
        // is it necessary to switch between static and dynamic pages ?
        bool bSwitchPage = false;
        if( aGroupingHint.getLength() )
            bSwitchPage = true;
        else if( aCtrlType.equalsAscii( "Subgroup" ) || (bOnStaticPage && ! bSubgroupOnStaticPage )  )
            bSwitchPage = true;
        if( bSwitchPage )
        {
            // restore to dynamic
            pCurParent = pDynamicPageParent;
            if( ! aDynamicColumns.empty() )
                pCurColumn = aDynamicColumns.back();
            else
                pCurColumn.reset();
            bOnStaticPage = false;
            bSubgroupOnStaticPage = false;

            if( aGroupingHint.equalsAscii( "PrintRange" ) )
            {
                pCurColumn = maJobPage.mxPrintRange;
                pCurParent = &maJobPage;            // set job page as current parent
                bOnStaticPage = true;
            }
            else if( aGroupingHint.equalsAscii( "OptionsPage" ) )
            {
                pCurColumn = boost::dynamic_pointer_cast<vcl::RowOrColumn>(maOptionsPage.getLayout());
                pCurParent = &maOptionsPage;        // set options page as current parent
                bOnStaticPage = true;
            }
            else if( aGroupingHint.equalsAscii( "OptionsPageOptGroup" ) )
            {
                pCurColumn = maOptionsPage.mxOptGroup;
                pCurParent = &maOptionsPage;        // set options page as current parent
                bOnStaticPage = true;
            }
            else if( aGroupingHint.equalsAscii( "LayoutPage" ) )
            {
                pCurColumn = boost::dynamic_pointer_cast<vcl::RowOrColumn>(maNUpPage.getLayout());
                pCurParent = &maNUpPage;            // set layout page as current parent
                bOnStaticPage = true;
            }
            else if( aGroupingHint.getLength() )
            {
                pCurColumn = boost::dynamic_pointer_cast<vcl::RowOrColumn>(maJobPage.getLayout());
                pCurParent = &maJobPage;            // set job page as current parent
                bOnStaticPage = true;
            }
        }

        if( aCtrlType.equalsAscii( "Group" ) ||
            ( ! pCurParent && ! (bOnStaticPage || aGroupingHint.getLength() ) ) )
        {
            // add new tab page
            TabPage* pNewGroup = new TabPage( &maTabCtrl );
            maControls.push_front( pNewGroup );
            pDynamicPageParent = pCurParent = pNewGroup;
            pNewGroup->SetText( aText );
            maTabCtrl.InsertPage( ++nOptPageId, aText );
            maTabCtrl.SetTabPage( nOptPageId, pNewGroup );
            
            // set help id
            setHelpId( pNewGroup, aHelpIds, 0 );
            // set help text
            setHelpText( pNewGroup, aHelpTexts, 0 );
            
            // reset subgroup counter
            nCurSubGroup = 0;

            aDynamicColumns.push_back( boost::dynamic_pointer_cast<vcl::RowOrColumn>(pNewGroup->getLayout()) );
            pCurColumn = aDynamicColumns.back();
            pCurColumn->setParentWindow( pNewGroup );
            bSubgroupOnStaticPage = false;
            bOnStaticPage = false;
        }
        else if( aCtrlType.equalsAscii( "Subgroup" ) && (pCurParent || aGroupingHint.getLength() ) )
        {
            bSubgroupOnStaticPage = (aGroupingHint.getLength() != 0);
            // create group FixedLine
            if( ! aGroupingHint.equalsAscii( "PrintRange" ) ||
                ! pCurColumn->countElements() == 0
               )
            {
                Window* pNewSub = NULL;
                if( aGroupingHint.equalsAscii( "PrintRange" ) )
                    pNewSub = new FixedText( pCurParent, WB_VCENTER );
                else
                    pNewSub = new FixedLine( pCurParent );
                maControls.push_front( pNewSub );
                pNewSub->SetText( aText );
                pNewSub->Show();
                
                // set help id
                setHelpId( pNewSub, aHelpIds, 0 );
                // set help text
                setHelpText( pNewSub, aHelpTexts, 0 );
                // add group to current column
                pCurColumn->addWindow( pNewSub );
            }

            // add an indent to the current column
            vcl::Indenter* pIndent = new vcl::Indenter( pCurColumn.get(), -1 );
            pCurColumn->addChild( pIndent );
            // and create a column inside the indent
            pCurColumn.reset( new vcl::RowOrColumn( pIndent ) );
            pIndent->setChild( pCurColumn );
        }
        // EVIL
        else if( aCtrlType.equalsAscii( "Bool" ) &&
                 aGroupingHint.equalsAscii( "LayoutPage" ) &&
                 aPropertyName.equalsAscii( "PrintProspect" )
                 )
        {
            maNUpPage.maBrochureBtn.SetText( aText );
            maNUpPage.maBrochureBtn.Show();
            setHelpText( &maNUpPage.maBrochureBtn, aHelpTexts, 0 );

            sal_Bool bVal = sal_False;
            PropertyValue* pVal = maPController->getValue( aPropertyName );
            if( pVal )
                pVal->Value >>= bVal;
            maNUpPage.maBrochureBtn.Check( bVal );
            maNUpPage.maBrochureBtn.Enable( maPController->isUIOptionEnabled( aPropertyName ) && pVal != NULL );
            maNUpPage.maBrochureBtn.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) );
            
            maPropertyToWindowMap[ aPropertyName ].push_back( &maNUpPage.maBrochureBtn );
            maControlToPropertyMap[&maNUpPage.maBrochureBtn] = aPropertyName;

            aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >( aPropertyName, maNUpPage.mxBrochureDep ) );
        }            
        else
        {
            boost::shared_ptr<vcl::RowOrColumn> pSaveCurColumn( pCurColumn );
            
            if( bUseDependencyRow )
            {
                // find the correct dependency row (if any)
                std::pair< std::multimap< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >::iterator,
                           std::multimap< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >::iterator > aDepRange;
                aDepRange = aPropertyToDependencyRowMap.equal_range( aDependsOnName );
                if( aDepRange.first != aDepRange.second )
                {
                    while( nDependsOnValue && aDepRange.first != aDepRange.second )
                    {
                        nDependsOnValue--;
                        ++aDepRange.first;
                    }
                    if( aDepRange.first != aPropertyToDependencyRowMap.end() )
                    {
                        pCurColumn = aDepRange.first->second;
                        maReverseDependencySet.insert( aPropertyName );
                    }
                }
            }
            if( aCtrlType.equalsAscii( "Bool" ) && pCurParent )
            {
                // add a check box
                CheckBox* pNewBox = new CheckBox( pCurParent );
                maControls.push_front( pNewBox );
                pNewBox->SetText( aText );
                pNewBox->Show();
    
                sal_Bool bVal = sal_False;
                PropertyValue* pVal = maPController->getValue( aPropertyName );
                if( pVal )
                    pVal->Value >>= bVal;
                pNewBox->Check( bVal );
                pNewBox->SetToggleHdl( LINK( this, PrintDialog, UIOption_CheckHdl ) );
                
                maPropertyToWindowMap[ aPropertyName ].push_back( pNewBox );
                maControlToPropertyMap[pNewBox] = aPropertyName;
                
                // set help id
                setHelpId( pNewBox, aHelpIds, 0 );
                // set help text
                setHelpText( pNewBox, aHelpTexts, 0 );
    
                boost::shared_ptr<vcl::RowOrColumn> pDependencyRow( new vcl::RowOrColumn( pCurColumn.get(), false ) );
                pCurColumn->addChild( pDependencyRow );
                aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >( aPropertyName, pDependencyRow ) );
                    
                // add checkbox to current column
                pDependencyRow->addWindow( pNewBox );
            }
            else if( aCtrlType.equalsAscii( "Radio" ) && pCurParent )
            {
                boost::shared_ptr<vcl::RowOrColumn> pRadioColumn( pCurColumn );
                if( aText.getLength() )
                {
                    // add a FixedText:
                    FixedText* pHeading = new FixedText( pCurParent );
                    maControls.push_front( pHeading );
                    pHeading->SetText( aText );
                    pHeading->Show();
    
                    // set help id
                    setHelpId( pHeading, aHelpIds, nCurHelpText );
                    // set help text
                    setHelpText( pHeading, aHelpTexts, nCurHelpText );
                    nCurHelpText++;
                    // add fixed text to current column
                    pCurColumn->addWindow( pHeading );
                    // add an indent to the current column
                    vcl::Indenter* pIndent = new vcl::Indenter( pCurColumn.get(), 15 );
                    pCurColumn->addChild( pIndent );
                    // and create a column inside the indent
                    pRadioColumn.reset( new vcl::RowOrColumn( pIndent ) );
                    pIndent->setChild( pRadioColumn );
                }
                // iterate options
                sal_Int32 nSelectVal = 0;
                PropertyValue* pVal = maPController->getValue( aPropertyName );
                if( pVal && pVal->Value.hasValue() )
                    pVal->Value >>= nSelectVal;
                for( sal_Int32 m = 0; m < aChoices.getLength(); m++ )
                {
                    boost::shared_ptr<vcl::LabeledElement> pLabel( new vcl::LabeledElement( pRadioColumn.get(), 1 ) );
                    pRadioColumn->addChild( pLabel );
                    boost::shared_ptr<vcl::RowOrColumn> pDependencyRow( new vcl::RowOrColumn( pLabel.get(), false ) );
                    pLabel->setElement( pDependencyRow );
                    aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >( aPropertyName, pDependencyRow ) );
                    
                    RadioButton* pBtn = new RadioButton( pCurParent, m == 0 ? WB_GROUP : 0 );
                    maControls.push_front( pBtn );
                    pBtn->SetText( aChoices[m] );
                    pBtn->Check( m == nSelectVal );
                    pBtn->SetToggleHdl( LINK( this, PrintDialog, UIOption_RadioHdl ) );
                    if( aChoicesDisabled.getLength() > m && aChoicesDisabled[m] == sal_True )
                        pBtn->Enable( sal_False );
                    pBtn->Show();
                    maPropertyToWindowMap[ aPropertyName ].push_back( pBtn );
                    maControlToPropertyMap[pBtn] = aPropertyName;
                    maControlToNumValMap[pBtn] = m;
    
                    // set help id
                    setHelpId( pBtn, aHelpIds, nCurHelpText );
                    // set help text
                    setHelpText( pBtn, aHelpTexts, nCurHelpText );
                    nCurHelpText++;
                    // add the radio button to the column
                    pLabel->setLabel( pBtn );
                }
            }
            else if( ( aCtrlType.equalsAscii( "List" )   ||
                       aCtrlType.equalsAscii( "Range" )  ||
                       aCtrlType.equalsAscii( "Edit" )
                     ) && pCurParent )
            {
                // create a row in the current column
                boost::shared_ptr<vcl::RowOrColumn> pFieldColumn( new vcl::RowOrColumn( pCurColumn.get(), false ) );
                pCurColumn->addChild( pFieldColumn );
                aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >( aPropertyName, pFieldColumn ) );
    
                vcl::LabeledElement* pLabel = NULL;
                if( aText.getLength() )
                {
                    // add a FixedText:
                    FixedText* pHeading = new FixedText( pCurParent, WB_VCENTER );
                    maControls.push_front( pHeading );
                    pHeading->SetText( aText );
                    pHeading->Show();
    
                    // add to row
                    pLabel = new vcl::LabeledElement( pFieldColumn.get(), 2 );
                    pFieldColumn->addChild( pLabel );
                    pLabel->setLabel( pHeading );
                }
                
                if( aCtrlType.equalsAscii( "List" ) )
                {
                    ListBox* pList = new ListBox( pCurParent, WB_DROPDOWN | WB_BORDER );
                    maControls.push_front( pList );
    
                    // iterate options
                    for( sal_Int32 m = 0; m < aChoices.getLength(); m++ )
                    {
                        pList->InsertEntry( aChoices[m] );
                    }
                    sal_Int32 nSelectVal = 0;
                    PropertyValue* pVal = maPController->getValue( aPropertyName );
                    if( pVal && pVal->Value.hasValue() )
                        pVal->Value >>= nSelectVal;
                    pList->SelectEntryPos( static_cast<sal_uInt16>(nSelectVal) );
                    pList->SetSelectHdl( LINK( this, PrintDialog, UIOption_SelectHdl ) );
                    pList->SetDropDownLineCount( static_cast<sal_uInt16>(aChoices.getLength()) );
                    pList->Show();
                    
                    // set help id
                    setHelpId( pList, aHelpIds, 0 );
                    // set help text
                    setHelpText( pList, aHelpTexts, 0 );
    
                    maPropertyToWindowMap[ aPropertyName ].push_back( pList );
                    maControlToPropertyMap[pList] = aPropertyName;
    
                    // finish the pair
                    if( pLabel )
                        pLabel->setElement( pList );
                    else
                        pFieldColumn->addWindow( pList );
                }
                else if( aCtrlType.equalsAscii( "Range" ) )
                {
                    NumericField* pField = new NumericField( pCurParent, WB_BORDER | WB_SPIN );
                    maControls.push_front( pField );
                    
                    // set min/max and current value
                    if( nMinValue != nMaxValue )
                    {
                        pField->SetMin( nMinValue );
                        pField->SetMax( nMaxValue );
                    }
                    sal_Int64 nCurVal = 0;
                    PropertyValue* pVal = maPController->getValue( aPropertyName );
                    if( pVal && pVal->Value.hasValue() )
                        pVal->Value >>= nCurVal;
                    pField->SetValue( nCurVal );
                    pField->SetModifyHdl( LINK( this, PrintDialog, UIOption_ModifyHdl ) );
                    pField->Show();
                    
                    // set help id
                    setHelpId( pField, aHelpIds, 0 );
                    // set help text
                    setHelpText( pField, aHelpTexts, 0 );
    
                    maPropertyToWindowMap[ aPropertyName ].push_back( pField );
                    maControlToPropertyMap[pField] = aPropertyName;
    
                    // add to row
                    if( pLabel )
                        pLabel->setElement( pField );
                    else
                        pFieldColumn->addWindow( pField );
                }
                else if( aCtrlType.equalsAscii( "Edit" ) )
                {
                    Edit* pField = new Edit( pCurParent, WB_BORDER );
                    maControls.push_front( pField );
                    
                    rtl::OUString aCurVal;
                    PropertyValue* pVal = maPController->getValue( aPropertyName );
                    if( pVal && pVal->Value.hasValue() )
                        pVal->Value >>= aCurVal;
                    pField->SetText( aCurVal );
                    pField->SetModifyHdl( LINK( this, PrintDialog, UIOption_ModifyHdl ) );
                    pField->Show();
                    
                    // set help id
                    setHelpId( pField, aHelpIds, 0 );
                    // set help text
                    setHelpText( pField, aHelpTexts, 0 );
    
                    maPropertyToWindowMap[ aPropertyName ].push_back( pField );
                    maControlToPropertyMap[pField] = aPropertyName;
    
                    // add to row
                    if( pLabel )
                        pLabel->setElement( pField );
                    else
                        pFieldColumn->addWindow( pField, 2 );
                }
            }
            else
            {
                DBG_ERROR( "Unsupported UI option" );
            }
            
            pCurColumn = pSaveCurColumn;
        }
    }
    
    // #i106506# if no brochure button, then the singular Pages radio button
    // makes no sense, so replace it by a FixedText label
    if( ! maNUpPage.maBrochureBtn.IsVisible() )
    {
        if( maNUpPage.mxPagesBtnLabel.get() )
        {
            maNUpPage.maPagesBoxTitleTxt.SetText( maNUpPage.maPagesBtn.GetText() );
            maNUpPage.maPagesBoxTitleTxt.Show( sal_True );
            maNUpPage.mxPagesBtnLabel->setLabel( &maNUpPage.maPagesBoxTitleTxt );
            maNUpPage.maPagesBtn.Show( sal_False );
        }
    }
    
    // update enable states
    checkOptionalControlDependencies();
    
    // print range empty (currently math only) -> hide print range and spacer line
    if( maJobPage.mxPrintRange->countElements() == 0 )
    {
        maJobPage.mxPrintRange->show( false, false );
        maJobPage.maCopySpacer.Show( sal_False );
        maJobPage.maReverseOrderBox.Show( sal_False );
    }
    else
    {
        // add an indent to the current column
        vcl::Indenter* pIndent = new vcl::Indenter( maJobPage.mxPrintRange.get(), -1 );
        maJobPage.mxPrintRange->addChild( pIndent );
        // and create a column inside the indent
        pIndent->setWindow( &maJobPage.maReverseOrderBox );
        maJobPage.maReverseOrderBox.Show( sal_True );
    }
    
#ifdef WNT
    // FIXME: the GetNativeControlRegion call on Windows has some issues
    // (which skew the results of GetOptimalSize())
    // however fixing this thoroughly needs to take interaction with paint into
    // account, making the right fix less simple. Fix this the right way
    // at some point. For now simply add some space at the lowest element
    size_t nIndex = maJobPage.getLayout()->countElements();
    if( nIndex > 0 ) // sanity check
        maJobPage.getLayout()->setBorders( nIndex-1, 0, 0, 0, -1 );
#endif

    // create auto mnemomnics now so they can be calculated in layout
    ImplWindowAutoMnemonic( &maJobPage );
    ImplWindowAutoMnemonic( &maNUpPage );
    ImplWindowAutoMnemonic( &maOptionsPage );
    ImplWindowAutoMnemonic( this );

    // calculate job page
    Size aMaxSize = maJobPage.getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED );
    // and layout page
    updateMaxSize( maNUpPage.getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED ), aMaxSize );
    // and options page
    updateMaxSize( maOptionsPage.getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED ), aMaxSize );

    for( std::vector< boost::shared_ptr<vcl::RowOrColumn> >::iterator it = aDynamicColumns.begin();
         it != aDynamicColumns.end(); ++it )
    {
        Size aPageSize( (*it)->getOptimalSize( WINDOWSIZE_PREFERRED ) );
        updateMaxSize( aPageSize, aMaxSize );
    }

    // resize dialog if necessary
    Size aTabSize = maTabCtrl.GetTabPageSizePixel();
    maTabCtrl.SetMinimumSizePixel( maTabCtrl.GetSizePixel() );
    if( aMaxSize.Height() > aTabSize.Height() || aMaxSize.Width() > aTabSize.Width() )
    {
        Size aCurSize( GetOutputSizePixel() );
        if( aMaxSize.Height() > aTabSize.Height() )
		{
            aCurSize.Height() += aMaxSize.Height() - aTabSize.Height();
			aTabSize.Height() = aMaxSize.Height();
		}
        if( aMaxSize.Width() > aTabSize.Width() )
        {
            aCurSize.Width() += aMaxSize.Width() - aTabSize.Width();
            // and the tab ctrl needs more space, too
            aTabSize.Width() = aMaxSize.Width();
        }
        maTabCtrl.SetTabPageSizePixel( aTabSize );
        maTabCtrl.SetMinimumSizePixel( maTabCtrl.GetSizePixel() );
    }

    Size aSz = getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED );
    SetOutputSizePixel( aSz );
}