/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define LID_RECORD_LABEL 1000 #define LID_RECORD_FILLER 1001 namespace frm { using ::com::sun::star::uno::makeAny; namespace FormFeature = ::com::sun::star::form::runtime::FormFeature; namespace { bool isArtificialItem( sal_Int16 _nFeatureId ) { return ( _nFeatureId == LID_RECORD_LABEL ) || ( _nFeatureId == LID_RECORD_FILLER ); } OUString getLabelString(const char* pResId) { OUString sLabel( " " + FRM_RES_STRING(pResId) + " " ); return sLabel; } OUString lcl_getCommandURL( const sal_Int16 _nFormFeature ) { const char* pAsciiCommandName = nullptr; switch ( _nFormFeature ) { case FormFeature::MoveAbsolute : pAsciiCommandName = "AbsoluteRecord"; break; case FormFeature::TotalRecords : pAsciiCommandName = "RecTotal"; break; case FormFeature::MoveToFirst : pAsciiCommandName = "FirstRecord"; break; case FormFeature::MoveToPrevious : pAsciiCommandName = "PrevRecord"; break; case FormFeature::MoveToNext : pAsciiCommandName = "NextRecord"; break; case FormFeature::MoveToLast : pAsciiCommandName = "LastRecord"; break; case FormFeature::SaveRecordChanges : pAsciiCommandName = "RecSave"; break; case FormFeature::UndoRecordChanges : pAsciiCommandName = "RecUndo"; break; case FormFeature::MoveToInsertRow : pAsciiCommandName = "NewRecord"; break; case FormFeature::DeleteRecord : pAsciiCommandName = "DeleteRecord"; break; case FormFeature::ReloadForm : pAsciiCommandName = "Refresh"; break; case FormFeature::RefreshCurrentControl : pAsciiCommandName = "RefreshFormControl"; break; case FormFeature::SortAscending : pAsciiCommandName = "Sortup"; break; case FormFeature::SortDescending : pAsciiCommandName = "SortDown"; break; case FormFeature::InteractiveSort : pAsciiCommandName = "OrderCrit"; break; case FormFeature::AutoFilter : pAsciiCommandName = "AutoFilter"; break; case FormFeature::InteractiveFilter : pAsciiCommandName = "FilterCrit"; break; case FormFeature::ToggleApplyFilter : pAsciiCommandName = "FormFiltered"; break; case FormFeature::RemoveFilterAndSort : pAsciiCommandName = "RemoveFilterSort"; break; } if ( pAsciiCommandName != nullptr ) return ".uno:" + OUString::createFromAscii( pAsciiCommandName ); OSL_FAIL( "lcl_getCommandURL: unknown FormFeature!" ); return OUString(); } } class ImplNavToolBar : public ToolBox { protected: const IFeatureDispatcher* m_pDispatcher; public: explicit ImplNavToolBar( vcl::Window* _pParent ) :ToolBox( _pParent, WB_3DLOOK ) ,m_pDispatcher( nullptr ) { } void setDispatcher( const IFeatureDispatcher* _pDispatcher ) { m_pDispatcher = _pDispatcher; } protected: // ToolBox overridables virtual void Select() override; }; void ImplNavToolBar::Select() { if ( m_pDispatcher ) { sal_Int16 nFeatureId = sal_uInt16(GetCurItemId()); if ( !m_pDispatcher->isEnabled( nFeatureId ) ) // the toolbox is a little bit buggy: With ToolBoxItemBits::REPEAT, it sometimes // happens that a select is reported, even though the respective // item has just been disabled. return; m_pDispatcher->dispatch( nFeatureId ); } } NavigationToolBar::NavigationToolBar( vcl::Window* _pParent, WinBits _nStyle, const PCommandImageProvider& _pImageProvider, const OUString & sModuleId ) :Window( _pParent, _nStyle ) ,m_pDispatcher( nullptr ) ,m_pImageProvider( _pImageProvider ) ,m_eImageSize( eSmall ) ,m_pToolbar( nullptr ) ,m_sModuleId( sModuleId ) { implInit( ); } NavigationToolBar::~NavigationToolBar( ) { disposeOnce(); } void NavigationToolBar::dispose() { for (auto & childWin : m_aChildWins) childWin.disposeAndClear(); m_aChildWins.clear(); m_pToolbar.disposeAndClear(); vcl::Window::dispose(); } void NavigationToolBar::setDispatcher( const IFeatureDispatcher* _pDispatcher ) { m_pDispatcher = _pDispatcher; m_pToolbar->setDispatcher( _pDispatcher ); RecordPositionInput* pPositionWindow = static_cast< RecordPositionInput* >( m_pToolbar->GetItemWindow( ToolBoxItemId(FormFeature::MoveAbsolute) ) ); OSL_ENSURE( pPositionWindow, "NavigationToolBar::setDispatcher: can't forward the dispatcher to the position window!" ); if ( pPositionWindow ) pPositionWindow->setDispatcher( _pDispatcher ); // update feature states for ( ToolBox::ImplToolItems::size_type nPos = 0; nPos < m_pToolbar->GetItemCount(); ++nPos ) { sal_uInt16 nItemId = sal_uInt16(m_pToolbar->GetItemId( nPos )); if ( ( nItemId == LID_RECORD_LABEL ) || ( nItemId == LID_RECORD_FILLER ) ) continue; // is this item enabled? bool bEnabled = m_pDispatcher && m_pDispatcher->isEnabled( nItemId ); implEnableItem( nItemId, bEnabled ); } } void NavigationToolBar::implEnableItem( sal_uInt16 _nItemId, bool _bEnabled ) { m_pToolbar->EnableItem( ToolBoxItemId(_nItemId), _bEnabled ); if ( _nItemId == FormFeature::MoveAbsolute ) m_pToolbar->EnableItem( ToolBoxItemId(LID_RECORD_LABEL), _bEnabled ); if ( _nItemId == FormFeature::TotalRecords ) m_pToolbar->EnableItem( ToolBoxItemId(LID_RECORD_FILLER), _bEnabled ); } void NavigationToolBar::enableFeature( sal_Int16 _nFeatureId, bool _bEnabled ) { DBG_ASSERT( m_pToolbar->GetItemPos( ToolBoxItemId(_nFeatureId) ) != ToolBox::ITEM_NOTFOUND, "NavigationToolBar::enableFeature: invalid id!" ); implEnableItem( static_cast(_nFeatureId), _bEnabled ); } void NavigationToolBar::checkFeature( sal_Int16 _nFeatureId, bool _bEnabled ) { DBG_ASSERT( m_pToolbar->GetItemPos( ToolBoxItemId(_nFeatureId) ) != ToolBox::ITEM_NOTFOUND, "NavigationToolBar::checkFeature: invalid id!" ); m_pToolbar->CheckItem( ToolBoxItemId(_nFeatureId), _bEnabled ); } void NavigationToolBar::setFeatureText( sal_Int16 _nFeatureId, const OUString& _rText ) { DBG_ASSERT( m_pToolbar->GetItemPos( ToolBoxItemId(_nFeatureId) ) != ToolBox::ITEM_NOTFOUND, "NavigationToolBar::checkFeature: invalid id!" ); vcl::Window* pItemWindow = m_pToolbar->GetItemWindow( ToolBoxItemId(_nFeatureId) ); if ( pItemWindow ) { if (_nFeatureId == FormFeature::TotalRecords) static_cast(pItemWindow)->set_label(_rText); else if (_nFeatureId == FormFeature::MoveAbsolute) static_cast(pItemWindow)->set_text(_rText); } else m_pToolbar->SetItemText( ToolBoxItemId(_nFeatureId), _rText ); } void NavigationToolBar::implInit( ) { m_pToolbar = VclPtr::Create( this ); m_pToolbar->Show(); // need the SfxApplication for retrieving information about our // items. We could duplicate all the information here in our lib // (such as the item text and the image), but why should we? static struct FeatureDescription { sal_uInt16 nId; bool bRepeat; bool bItemWindow; } const aSupportedFeatures[] = { { LID_RECORD_LABEL, false, true }, { FormFeature::MoveAbsolute, false, true }, { LID_RECORD_FILLER, false, true }, { FormFeature::TotalRecords, false, true }, { FormFeature::MoveToFirst, true, false }, { FormFeature::MoveToPrevious, true, false }, { FormFeature::MoveToNext, true, false }, { FormFeature::MoveToLast, true, false }, { FormFeature::MoveToInsertRow, false, false }, { 0, false, false }, { FormFeature::SaveRecordChanges, false, false }, { FormFeature::UndoRecordChanges, false, false }, { FormFeature::DeleteRecord, false, false }, { FormFeature::ReloadForm, false, false }, { FormFeature::RefreshCurrentControl, false, false }, { 0, false, false }, { FormFeature::SortAscending, false, false }, { FormFeature::SortDescending, false, false }, { FormFeature::InteractiveSort, false, false }, { FormFeature::AutoFilter, false, false }, { FormFeature::InteractiveFilter, false, false }, { FormFeature::ToggleApplyFilter, false, false }, { FormFeature::RemoveFilterAndSort, false, false }, }; FeatureDescription const * pSupportedFeatures = aSupportedFeatures; FeatureDescription const * pSupportedFeaturesEnd = aSupportedFeatures + SAL_N_ELEMENTS( aSupportedFeatures ); for ( ; pSupportedFeatures < pSupportedFeaturesEnd; ++pSupportedFeatures ) { if ( pSupportedFeatures->nId ) { // it's _not_ a separator // insert the entry m_pToolbar->InsertItem( ToolBoxItemId(pSupportedFeatures->nId), OUString(), pSupportedFeatures->bRepeat ? ToolBoxItemBits::REPEAT : ToolBoxItemBits::NONE ); m_pToolbar->SetQuickHelpText( ToolBoxItemId(pSupportedFeatures->nId), OUString() ); // TODO if ( !isArtificialItem( pSupportedFeatures->nId ) ) { OUString sCommandURL( lcl_getCommandURL( pSupportedFeatures->nId ) ); m_pToolbar->SetItemCommand( ToolBoxItemId(pSupportedFeatures->nId), sCommandURL ); auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(sCommandURL, m_sModuleId); m_pToolbar->SetQuickHelpText(ToolBoxItemId(pSupportedFeatures->nId), vcl::CommandInfoProvider::GetLabelForCommand(aProperties)); } if ( pSupportedFeatures->bItemWindow ) { vcl::Window* pItemWindow = nullptr; if ( FormFeature::MoveAbsolute == pSupportedFeatures->nId ) { pItemWindow = VclPtr::Create( m_pToolbar ); static_cast< RecordPositionInput* >( pItemWindow )->setDispatcher( m_pDispatcher ); } else if (pSupportedFeatures->nId == LID_RECORD_FILLER) pItemWindow = VclPtr::Create(m_pToolbar, getLabelString(RID_STR_LABEL_OF)); else if (pSupportedFeatures->nId == LID_RECORD_LABEL) pItemWindow = VclPtr::Create(m_pToolbar, getLabelString(RID_STR_LABEL_RECORD)); else if (pSupportedFeatures->nId == FormFeature::TotalRecords) pItemWindow = VclPtr::Create(m_pToolbar, ""); m_aChildWins.emplace_back(pItemWindow ); m_pToolbar->SetItemWindow( ToolBoxItemId(pSupportedFeatures->nId), pItemWindow ); } } else { // a separator m_pToolbar->InsertSeparator( ); } } forEachItemWindow( &NavigationToolBar::adjustItemWindowWidth ); implUpdateImages(); } void NavigationToolBar::implUpdateImages() { OSL_ENSURE( m_pImageProvider, "NavigationToolBar::implUpdateImages: no image provider => no images!" ); if ( !m_pImageProvider ) return; const ToolBox::ImplToolItems::size_type nItemCount = m_pToolbar->GetItemCount(); // collect the FormFeatures in the toolbar std::vector aFormFeatures; aFormFeatures.reserve( nItemCount ); for ( ToolBox::ImplToolItems::size_type i=0; iGetItemId( i ); if ( ( ToolBoxItemType::BUTTON == m_pToolbar->GetItemType( i ) ) && !isArtificialItem( sal_uInt16(nId) ) ) aFormFeatures.push_back( sal_uInt16(nId) ); } // translate them into command URLs css::uno::Sequence< OUString > aCommandURLs( aFormFeatures.size() ); size_t i = 0; for (auto const& formFeature : aFormFeatures) { aCommandURLs[i++] = lcl_getCommandURL(formFeature); } // retrieve the images for the command URLs std::vector aCommandImages = m_pImageProvider->getCommandImages( aCommandURLs, m_eImageSize == eLarge ); // and set them at the toolbar auto commandImage = aCommandImages.begin(); for (sal_Int16 formFeature : aFormFeatures) { m_pToolbar->SetItemImage( ToolBoxItemId(formFeature), *commandImage ); ++commandImage; } // parts of our layout is dependent on the size of our icons Resize(); } void NavigationToolBar::implSetImageSize( ImageSize _eSize ) { if ( _eSize != m_eImageSize ) { m_eImageSize = _eSize; implUpdateImages(); } } void NavigationToolBar::SetImageSize( ImageSize _eSize ) { implSetImageSize( _eSize ); } void NavigationToolBar::ShowFunctionGroup( FunctionGroup _eGroup, bool _bShow ) { const sal_uInt16* pGroupIds = nullptr; switch ( _eGroup ) { case ePosition: { static const sal_uInt16 aPositionIds[] = { LID_RECORD_LABEL, FormFeature::MoveAbsolute, LID_RECORD_FILLER, FormFeature::TotalRecords, 0 }; pGroupIds = aPositionIds; } break; case eNavigation: { static const sal_uInt16 aNavigationIds[] = { FormFeature::MoveToFirst, FormFeature::MoveToPrevious, FormFeature::MoveToNext, FormFeature::MoveToLast, FormFeature::MoveToInsertRow, 0 }; pGroupIds = aNavigationIds; } break; case eRecordActions: { static const sal_uInt16 aActionIds[] = { FormFeature::SaveRecordChanges, FormFeature::UndoRecordChanges, FormFeature::DeleteRecord, FormFeature::ReloadForm, FormFeature::RefreshCurrentControl, 0 }; pGroupIds = aActionIds; } break; case eFilterSort: { static const sal_uInt16 aFilterSortIds[] = { FormFeature::SortAscending, FormFeature::SortDescending, FormFeature::InteractiveSort, FormFeature::AutoFilter, FormFeature::InteractiveFilter, FormFeature::ToggleApplyFilter, FormFeature::RemoveFilterAndSort, 0 }; pGroupIds = aFilterSortIds; } break; default: OSL_FAIL( "NavigationToolBar::ShowFunctionGroup: invalid group id!" ); } if ( pGroupIds ) while ( *pGroupIds ) m_pToolbar->ShowItem( ToolBoxItemId(*pGroupIds++), _bShow ); } bool NavigationToolBar::IsFunctionGroupVisible( FunctionGroup _eGroup ) { sal_uInt16 nIndicatorItem = 0; switch ( _eGroup ) { case ePosition : nIndicatorItem = LID_RECORD_LABEL; break; case eNavigation : nIndicatorItem = FormFeature::MoveToFirst; break; case eRecordActions : nIndicatorItem = FormFeature::SaveRecordChanges; break; case eFilterSort : nIndicatorItem = FormFeature::SortAscending; break; default: OSL_FAIL( "NavigationToolBar::IsFunctionGroupVisible: invalid group id!" ); } return m_pToolbar->IsItemVisible( ToolBoxItemId(nIndicatorItem) ); } void NavigationToolBar::StateChanged( StateChangedType nType ) { Window::StateChanged( nType ); switch ( nType ) { case StateChangedType::Zoom: // m_pToolbar->SetZoom( GetZoom() ); // forEachItemWindow( setItemWindowZoom, NULL ); // the ToolBox class is not zoomable at the moment, so // we better have no zoom at all instead of only half a zoom ... break; case StateChangedType::ControlFont: forEachItemWindow( &NavigationToolBar::setItemControlFont ); forEachItemWindow( &NavigationToolBar::adjustItemWindowWidth ); break; case StateChangedType::ControlForeground: forEachItemWindow( &NavigationToolBar::setItemControlForeground ); break; case StateChangedType::Mirroring: { sal_Bool bIsRTLEnabled( IsRTLEnabled() ); m_pToolbar->EnableRTL( bIsRTLEnabled ); forEachItemWindow( &NavigationToolBar::enableItemRTL, &bIsRTLEnabled ); Resize(); } break; default:; } } void NavigationToolBar::Resize() { // resize/position the toolbox as a whole sal_Int32 nToolbarHeight = m_pToolbar->CalcWindowSizePixel().Height(); sal_Int32 nMyHeight = GetOutputSizePixel().Height(); m_pToolbar->SetPosSizePixel( Point( 0, ( nMyHeight - nToolbarHeight ) / 2 ), Size( GetSizePixel().Width(), nToolbarHeight ) ); Window::Resize(); } void NavigationToolBar::SetControlBackground() { Window::SetControlBackground(); m_pToolbar->SetControlBackground(); forEachItemWindow( &NavigationToolBar::setItemBackground, nullptr ); implUpdateImages(); } void NavigationToolBar::SetControlBackground( const Color& _rColor ) { Window::SetControlBackground( _rColor ); m_pToolbar->SetControlBackground( _rColor ); forEachItemWindow( &NavigationToolBar::setItemBackground, &_rColor ); implUpdateImages(); } void NavigationToolBar::SetTextLineColor( ) { Window::SetTextLineColor( ); m_pToolbar->SetTextLineColor( ); forEachItemWindow( &NavigationToolBar::setTextLineColor, nullptr ); } void NavigationToolBar::SetTextLineColor( const Color& _rColor ) { Window::SetTextLineColor( _rColor ); m_pToolbar->SetTextLineColor( _rColor ); forEachItemWindow( &NavigationToolBar::setTextLineColor, &_rColor ); } void NavigationToolBar::forEachItemWindow( ItemWindowHandler _handler ) { for ( ToolBox::ImplToolItems::size_type item = 0; item < m_pToolbar->GetItemCount(); ++item ) { ToolBoxItemId nItemId = m_pToolbar->GetItemId( item ); vcl::Window* pItemWindow = m_pToolbar->GetItemWindow( nItemId ); if ( pItemWindow ) (this->*_handler)( sal_uInt16(nItemId), pItemWindow ); } } void NavigationToolBar::forEachItemWindow( ItemWindowHandler2 _handler, const void* _pParam ) { for ( ToolBox::ImplToolItems::size_type item = 0; item < m_pToolbar->GetItemCount(); ++item ) { ToolBoxItemId nItemId = m_pToolbar->GetItemId( item ); vcl::Window* pItemWindow = m_pToolbar->GetItemWindow( nItemId ); if ( pItemWindow ) (*_handler)( sal_uInt16(nItemId), pItemWindow, _pParam ); } } void NavigationToolBar::setItemBackground( sal_uInt16 /* _nItemId */, vcl::Window* _pItemWindow, const void* _pColor ) { if ( _pColor ) _pItemWindow->SetControlBackground( *static_cast< const Color* >( _pColor ) ); else _pItemWindow->SetControlBackground(); } void NavigationToolBar::setTextLineColor( sal_uInt16 /* _nItemId */, vcl::Window* _pItemWindow, const void* _pColor ) { if ( _pColor ) _pItemWindow->SetTextLineColor( *static_cast< const Color* >( _pColor ) ); else _pItemWindow->SetTextLineColor(); } void NavigationToolBar::setItemControlFont( sal_uInt16 /* _nItemId */, vcl::Window* _pItemWindow ) const { if ( IsControlFont() ) _pItemWindow->SetControlFont( GetControlFont() ); else _pItemWindow->SetControlFont( ); } void NavigationToolBar::setItemControlForeground( sal_uInt16 /* _nItemId */, vcl::Window* _pItemWindow ) const { if ( IsControlForeground() ) _pItemWindow->SetControlForeground( GetControlForeground() ); else _pItemWindow->SetControlForeground( ); _pItemWindow->SetTextColor( GetTextColor() ); } void NavigationToolBar::adjustItemWindowWidth( sal_uInt16 _nItemId, vcl::Window* _pItemWindow ) const { int nHeight = 0; OUString sItemText; switch ( _nItemId ) { case LID_RECORD_LABEL: sItemText = getLabelString( RID_STR_LABEL_RECORD ); break; case LID_RECORD_FILLER: sItemText = getLabelString( RID_STR_LABEL_OF ); break; case FormFeature::MoveAbsolute: sItemText = "12345678"; nHeight = _pItemWindow->get_preferred_size().Height(); break; case FormFeature::TotalRecords: sItemText = "123456"; break; } if (nHeight == 0) nHeight = _pItemWindow->GetTextHeight() + 4; Size aSize(_pItemWindow->GetTextWidth(sItemText), nHeight); aSize.AdjustWidth(6 ); _pItemWindow->SetSizePixel( aSize ); m_pToolbar->SetItemWindow( ToolBoxItemId(_nItemId), _pItemWindow ); } void NavigationToolBar::enableItemRTL( sal_uInt16 /*_nItemId*/, vcl::Window* _pItemWindow, const void* _pIsRTLEnabled ) { _pItemWindow->EnableRTL( *static_cast< const sal_Bool* >( _pIsRTLEnabled ) ); } RecordPositionInput::RecordPositionInput(vcl::Window* pParent) : RecordItemWindow(pParent) , m_pDispatcher( nullptr ) { } void RecordPositionInput::setDispatcher( const IFeatureDispatcher* _pDispatcher ) { m_pDispatcher = _pDispatcher; } void RecordPositionInput::PositionFired(sal_Int64 nRecord) { if (!m_pDispatcher) return; m_pDispatcher->dispatchWithArgument( FormFeature::MoveAbsolute, "Position", makeAny( static_cast(nRecord) ) ); } } // namespace frm /* vim:set shiftwidth=4 softtabstop=4 expandtab: */