Avoid potential negative array index access to cached text.
[LibreOffice.git] / extensions / source / propctrlr / browserline.cxx
blobf4619000dcf83b55bda0bceb895d64a74fd63665
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "browserline.hxx"
22 #include <com/sun/star/uno/XComponentContext.hpp>
23 #include <com/sun/star/inspection/PropertyLineElement.hpp>
24 #include <com/sun/star/graphic/GraphicProvider.hpp>
25 #include <com/sun/star/graphic/XGraphicProvider.hpp>
27 #include <comphelper/processfactory.hxx>
28 #include <comphelper/propertyvalue.hxx>
29 #include <comphelper/string.hxx>
30 #include <tools/debug.hxx>
31 #include <comphelper/diagnose_ex.hxx>
32 #include <utility>
33 #include <vcl/settings.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/weld.hxx>
36 #include <vcl/weldutils.hxx>
38 namespace pcr
42 using ::com::sun::star::uno::Reference;
43 using ::com::sun::star::uno::XComponentContext;
44 using ::com::sun::star::inspection::XPropertyControl;
45 using ::com::sun::star::inspection::XPropertyControlContext;
46 using ::com::sun::star::uno::Exception;
47 using ::com::sun::star::graphic::GraphicProvider;
48 using ::com::sun::star::graphic::XGraphicProvider;
49 using ::com::sun::star::uno::Sequence;
50 using ::com::sun::star::graphic::XGraphic;
52 namespace PropertyLineElement = ::com::sun::star::inspection::PropertyLineElement;
54 OBrowserLine::OBrowserLine(OUString aEntryName, weld::Container* pParent, weld::SizeGroup* pLabelGroup,
55 weld::Container* pInitialControlParent)
56 : m_sEntryName(std::move(aEntryName))
57 , m_xBuilder(Application::CreateBuilder(pParent, "modules/spropctrlr/ui/browserline.ui"))
58 , m_xContainer(m_xBuilder->weld_container("BrowserLine"))
59 , m_xFtTitle(m_xBuilder->weld_label("label"))
60 , m_xBrowseButton(m_xBuilder->weld_button("browse"))
61 , m_xAdditionalBrowseButton(m_xBuilder->weld_button("morebrowse"))
62 , m_pInitialControlParent(pInitialControlParent) // controls start with this as their parent and need to be moved into m_xContainer
63 , m_pParent(pParent)
64 , m_pControlWindow( nullptr )
65 , m_pBrowseButton(nullptr)
66 , m_pAdditionalBrowseButton( nullptr )
67 , m_pClickListener( nullptr )
68 , m_nNameWidth(0)
69 , m_nEnableFlags( 0xFFFF )
70 , m_bIndentTitle( false )
71 , m_bReadOnly( false )
73 pLabelGroup->add_widget(m_xFtTitle.get());
76 OBrowserLine::~OBrowserLine()
78 implHideBrowseButton(true);
79 implHideBrowseButton(false);
80 m_pParent->move(m_xContainer.get(), nullptr);
83 void OBrowserLine::IndentTitle( bool _bIndent )
85 if ( m_bIndentTitle != _bIndent )
87 m_bIndentTitle = _bIndent;
91 void OBrowserLine::SetComponentHelpIds(const OUString& rHelpId)
93 if (m_pControlWindow)
94 m_pControlWindow->set_help_id(rHelpId);
96 if ( m_pBrowseButton )
98 m_pBrowseButton->set_help_id(rHelpId);
100 if ( m_pAdditionalBrowseButton )
102 m_pAdditionalBrowseButton->set_help_id(rHelpId);
107 void OBrowserLine::setControl( const Reference< XPropertyControl >& rxControl )
109 m_xControl = rxControl;
110 auto xWindow = m_xControl->getControlWindow();
111 if (weld::TransportAsXWindow* pTunnel = dynamic_cast<weld::TransportAsXWindow*>(xWindow.get()))
112 m_pControlWindow = pTunnel->getWidget();
113 else
114 m_pControlWindow = nullptr;
115 DBG_ASSERT( m_pControlWindow, "OBrowserLine::setControl: setting NULL controls/windows is not allowed!" );
117 if ( m_pControlWindow )
119 m_pInitialControlParent->move(m_pControlWindow, m_xContainer.get());
120 m_pControlWindow->set_grid_left_attach(1);
121 m_xFtTitle->set_mnemonic_widget(m_pControlWindow);
122 m_pControlWindow->show();
126 bool OBrowserLine::GrabFocus()
128 bool bRes=false;
130 if (m_pControlWindow && m_pControlWindow->get_sensitive())
132 m_pControlWindow->grab_focus();
133 bRes = true;
135 else if ( m_pAdditionalBrowseButton && m_pAdditionalBrowseButton->get_sensitive() )
137 m_pAdditionalBrowseButton->grab_focus();
138 bRes = true;
140 else if ( m_pBrowseButton && m_pBrowseButton->get_sensitive() )
142 m_pBrowseButton->grab_focus();
143 bRes = true;
145 return bRes;
148 void OBrowserLine::Show(bool bFlag)
150 m_xFtTitle->set_visible(bFlag);
151 if (m_pControlWindow)
152 m_pControlWindow->set_visible( bFlag );
153 if ( m_pBrowseButton )
154 m_pBrowseButton->set_visible( bFlag );
155 if ( m_pAdditionalBrowseButton )
156 m_pAdditionalBrowseButton->set_visible( bFlag );
159 void OBrowserLine::Hide()
161 Show(false);
164 void OBrowserLine::SetTitle(const OUString& rNewTitle )
166 if ( GetTitle() == rNewTitle )
167 return;
168 m_xFtTitle->set_label( rNewTitle );
169 if (m_pControlWindow)
170 m_pControlWindow->set_accessible_name(rNewTitle);
171 if ( m_pBrowseButton )
172 m_pBrowseButton->set_accessible_name( rNewTitle );
173 FullFillTitleString();
176 void OBrowserLine::FullFillTitleString()
178 OUStringBuffer aText(m_xFtTitle->get_label());
180 int n10DotsWidth = m_xFtTitle->get_pixel_size("..........").Width();
181 int nTextWidth = m_xFtTitle->get_pixel_size(OUString::unacquired(aText)).Width();
182 int nDiff = m_nNameWidth - nTextWidth;
183 int nExtraChars = (nDiff * 10) / n10DotsWidth;
184 for (int i = 0; i < nExtraChars; ++i)
185 aText.append(".");
187 // for Issue 69452
188 if (AllSettings::GetLayoutRTL())
190 sal_Unicode const cRTL_mark = 0x200F;
191 aText.append( cRTL_mark );
194 m_xFtTitle->set_label(aText.makeStringAndClear());
197 OUString OBrowserLine::GetTitle() const
199 OUString sDisplayName = m_xFtTitle->get_label();
201 // for Issue 69452
202 if (AllSettings::GetLayoutRTL())
204 sal_Unicode const cRTL_mark = 0x200F;
205 sDisplayName = comphelper::string::stripEnd(sDisplayName, cRTL_mark);
208 sDisplayName = comphelper::string::stripEnd(sDisplayName, '.');
210 return sDisplayName;
213 void OBrowserLine::SetReadOnly( bool _bReadOnly )
215 if ( m_bReadOnly != _bReadOnly )
217 m_bReadOnly = _bReadOnly;
218 implUpdateEnabledDisabled();
222 namespace
224 void implSetBitIfAffected(sal_uInt16& nEnabledBits, sal_Int16 _nAffectedMask, sal_Int16 _nTestBit, bool _bSet)
226 if ( _nAffectedMask & _nTestBit )
228 if ( _bSet )
229 nEnabledBits |= _nTestBit;
230 else
231 nEnabledBits &= ~_nTestBit;
235 void implEnable(weld::Widget* pWindow, bool bEnable)
237 // tdf#138131 get_sensitive comparison as bodge for
238 // vcl's recursive Enable behavior
239 if (pWindow && pWindow->get_sensitive() != bEnable)
240 pWindow->set_sensitive(bEnable);
243 void implEnable(weld::Widget* pWindow, sal_uInt16 nEnabledBits, sal_uInt16 nMatchBits)
245 bool bEnable = ((nEnabledBits & nMatchBits) == nMatchBits);
246 implEnable(pWindow, bEnable);
250 void OBrowserLine::implUpdateEnabledDisabled()
252 implEnable( m_xFtTitle.get(), m_nEnableFlags, PropertyLineElement::CompleteLine );
253 if ( m_pControlWindow )
254 implEnable( m_pControlWindow, m_nEnableFlags, PropertyLineElement::CompleteLine | PropertyLineElement::InputControl );
256 if ( m_bReadOnly )
258 implEnable( m_pBrowseButton, false );
259 implEnable( m_pAdditionalBrowseButton, false );
261 else
263 implEnable( m_pBrowseButton, m_nEnableFlags, PropertyLineElement::CompleteLine | PropertyLineElement::PrimaryButton );
264 implEnable( m_pAdditionalBrowseButton, m_nEnableFlags, PropertyLineElement::CompleteLine | PropertyLineElement::SecondaryButton );
268 void OBrowserLine::EnablePropertyLine( bool _bEnable )
270 implSetBitIfAffected( m_nEnableFlags, PropertyLineElement::CompleteLine, PropertyLineElement::CompleteLine, _bEnable );
271 implUpdateEnabledDisabled();
275 void OBrowserLine::EnablePropertyControls( sal_Int16 _nControls, bool _bEnable )
277 implSetBitIfAffected( m_nEnableFlags, _nControls, PropertyLineElement::InputControl, _bEnable );
278 implSetBitIfAffected( m_nEnableFlags, _nControls, PropertyLineElement::PrimaryButton, _bEnable );
279 implSetBitIfAffected( m_nEnableFlags, _nControls, PropertyLineElement::SecondaryButton, _bEnable );
280 implUpdateEnabledDisabled();
283 weld::Button& OBrowserLine::impl_ensureButton(bool bPrimary)
285 weld::Button* pButton;
286 if (bPrimary)
287 pButton = m_pBrowseButton;
288 else
289 pButton = m_pAdditionalBrowseButton;
291 if (!pButton )
293 if (bPrimary)
294 pButton = m_pBrowseButton = m_xBrowseButton.get();
295 else
296 pButton = m_pAdditionalBrowseButton = m_xAdditionalBrowseButton.get();
297 pButton->connect_focus_in(LINK(this, OBrowserLine, OnButtonFocus));
298 pButton->connect_clicked(LINK(this, OBrowserLine, OnButtonClicked));
301 pButton->show();
303 return *pButton;
306 void OBrowserLine::ShowBrowseButton( const OUString& rImageURL, bool bPrimary )
308 weld::Button& rButton( impl_ensureButton( bPrimary ) );
310 OSL_PRECOND( !rImageURL.isEmpty(), "OBrowserLine::ShowBrowseButton: use the other version if you don't have an image!" );
311 Reference<XGraphic> xGraphic;
314 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
315 Reference< XGraphicProvider > xGraphicProvider( GraphicProvider::create(xContext) );
317 Sequence aMediaProperties{ comphelper::makePropertyValue("URL", rImageURL) };
319 xGraphic = Reference<XGraphic>(xGraphicProvider->queryGraphic(aMediaProperties), css::uno::UNO_SET_THROW);
321 catch( const Exception& )
323 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
326 rButton.set_image(xGraphic);
329 void OBrowserLine::ShowBrowseButton(const css::uno::Reference<css::graphic::XGraphic>& rGraphic, bool bPrimary)
331 weld::Button& rButton( impl_ensureButton( bPrimary ) );
332 rButton.set_image(rGraphic);
335 void OBrowserLine::ShowBrowseButton( bool bPrimary )
337 impl_ensureButton(bPrimary);
340 void OBrowserLine::implHideBrowseButton(bool bPrimary)
342 if (bPrimary)
344 if (m_pBrowseButton)
346 m_pBrowseButton->hide();
347 m_pBrowseButton->connect_focus_in(Link<weld::Widget&, void>());
348 m_pBrowseButton = nullptr;
351 else
353 if (m_pAdditionalBrowseButton)
355 m_pAdditionalBrowseButton->hide();
356 m_pAdditionalBrowseButton->connect_focus_in(Link<weld::Widget&, void>());
357 m_pAdditionalBrowseButton = nullptr;
362 void OBrowserLine::HideBrowseButton(bool bPrimary)
364 implHideBrowseButton(bPrimary);
367 void OBrowserLine::SetTitleWidth(sal_uInt16 nWidth)
369 int nMinDotsWidth = m_xFtTitle->get_pixel_size("...").Width();
370 if (m_nNameWidth != nWidth + nMinDotsWidth)
371 m_nNameWidth = nWidth + nMinDotsWidth;
372 FullFillTitleString();
375 void OBrowserLine::SetClickListener( IButtonClickListener* _pListener )
377 m_pClickListener = _pListener;
380 IMPL_LINK(OBrowserLine, OnButtonClicked, weld::Button&, rButton, void)
382 if ( m_pClickListener )
383 m_pClickListener->buttonClicked(this, &rButton == m_pBrowseButton);
386 IMPL_LINK_NOARG( OBrowserLine, OnButtonFocus, weld::Widget&, void )
388 if ( m_xControl.is() )
392 Reference< XPropertyControlContext > xContext( m_xControl->getControlContext(), css::uno::UNO_SET_THROW );
393 xContext->focusGained( m_xControl );
395 catch( const Exception& )
397 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
402 } // namespace pcr
404 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */