1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  */
9 
10 #include "limitboxcontroller.hxx"
11 #include <apitools.hxx>
12 
13 #include <com/sun/star/frame/XDispatchProvider.hpp>
14 #include <com/sun/star/frame/XFrame.hpp>
15 #include <com/sun/star/beans/PropertyValue.hpp>
16 #include <com/sun/star/util/XURLTransformer.hpp>
17 
18 #include <vcl/InterimItemWindow.hxx>
19 #include <vcl/event.hxx>
20 #include <vcl/svapp.hxx>
21 #include <vcl/window.hxx>
22 #include <toolkit/helper/vclunohelper.hxx>
23 #include <cppuhelper/queryinterface.hxx>
24 
25 #include <core_resource.hxx>
26 #include <strings.hrc>
27 
28 using namespace ::com::sun::star;
29 
30 namespace
31 {
32 
33 /// Default values
34 sal_Int64 const aDefLimitAry[] =
35 {
36     5,
37     10,
38     20,
39     50
40 };
41 
42 }
43 
44 namespace dbaui
45 {
46 
47 /**
48  * Input box to add limit to an SQL query (maximum number of result's rows)
49  * This box is reachable on the Query Design Toolbar
50  */
51 class LimitBox final : public InterimItemWindow
52 {
53 public:
LimitBox(vcl::Window * pParent,LimitBoxController * pCtrl)54     LimitBox(vcl::Window* pParent, LimitBoxController* pCtrl)
55         : InterimItemWindow(pParent, "dbaccess/ui/limitbox.ui", "LimitBox")
56         , m_pControl( pCtrl )
57         , m_xWidget(m_xBuilder->weld_combo_box("limit"))
58     {
59         InitControlBase(m_xWidget.get());
60 
61         LoadDefaultLimits();
62 
63         m_xWidget->connect_key_press(LINK(this, LimitBox, KeyInputHdl));
64         m_xWidget->connect_entry_activate(LINK(this, LimitBox, ActivateHdl));
65         m_xWidget->connect_changed(LINK(this, LimitBox, ChangeHdl));
66         m_xWidget->connect_focus_out(LINK(this, LimitBox, FocusOutHdl));
67         m_xWidget->set_entry_width_chars(6);
68         SetSizePixel(m_xContainer->get_preferred_size());
69     }
70 
dispose()71     virtual void dispose() override
72     {
73         m_xWidget.reset();
74         InterimItemWindow::dispose();
75     }
76 
~LimitBox()77     virtual ~LimitBox() override
78     {
79         disposeOnce();
80     }
81 
set_sensitive(bool bSensitive)82     void set_sensitive(bool bSensitive)
83     {
84         m_xWidget->set_sensitive(bSensitive);
85     }
86 
set_value(int nLimit)87     void set_value(int nLimit)
88     {
89         if (nLimit < 0)
90             m_xWidget->set_active(0);
91         else
92             m_xWidget->set_entry_text(OUString::number(nLimit));
93         m_xWidget->save_value();
94     }
95 
96 private:
97     LimitBoxController* m_pControl;
98     std::unique_ptr<weld::ComboBox> m_xWidget;
99 
100     DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
101     DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
102     DECL_LINK(ChangeHdl, weld::ComboBox&, void);
103     DECL_LINK(FocusOutHdl, weld::Widget&, void);
104 
Apply()105     void Apply()
106     {
107         if (!m_xWidget->get_value_changed_from_saved())
108             return;
109         uno::Sequence< beans::PropertyValue > aArgs( 1 );
110         aArgs[0].Name  = "DBLimit.Value";
111         sal_Int64 nLimit;
112         OUString sActiveText = m_xWidget->get_active_text();
113         if (sActiveText == DBA_RES(STR_QUERY_LIMIT_ALL))
114             nLimit = -1;
115         else
116         {
117             nLimit = m_xWidget->get_active_text().toInt64();
118             if (nLimit < 0)
119                 nLimit = -1;
120         }
121         set_value(nLimit);
122         aArgs[0].Value <<= nLimit;
123         m_pControl->dispatchCommand( aArgs );
124     }
125 
126     ///Initialize entries
LoadDefaultLimits()127     void LoadDefaultLimits()
128     {
129         m_xWidget->freeze();
130         m_xWidget->append_text(DBA_RES(STR_QUERY_LIMIT_ALL));
131         for (auto nIndex : aDefLimitAry)
132         {
133             m_xWidget->append_text(OUString::number(nIndex));
134         }
135         m_xWidget->thaw();
136     }
137 };
138 
IMPL_LINK(LimitBox,KeyInputHdl,const KeyEvent &,rKEvt,bool)139 IMPL_LINK(LimitBox, KeyInputHdl, const KeyEvent&, rKEvt, bool)
140 {
141     bool bHandled = false;
142     const sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
143     switch (nCode)
144     {
145         case KEY_ESCAPE:
146             m_xWidget->set_entry_text(m_xWidget->get_saved_value());
147             bHandled = true;
148             break;
149         case KEY_RETURN:
150         {
151             bHandled = ActivateHdl(*m_xWidget);
152             break;
153         }
154     }
155     return bHandled || ChildKeyInput(rKEvt);
156 }
157 
IMPL_LINK_NOARG(LimitBox,FocusOutHdl,weld::Widget &,void)158 IMPL_LINK_NOARG(LimitBox, FocusOutHdl, weld::Widget&, void)
159 {
160     if (!m_xWidget || m_xWidget->has_focus()) // comboboxes can be comprised of multiple widgets, ensure all have lost focus
161         return;
162     Apply();
163 }
164 
IMPL_LINK(LimitBox,ChangeHdl,weld::ComboBox &,rComboBox,void)165 IMPL_LINK(LimitBox, ChangeHdl, weld::ComboBox&, rComboBox, void)
166 {
167     if (rComboBox.changed_by_direct_pick())
168         ActivateHdl(rComboBox);
169 }
170 
IMPL_LINK_NOARG(LimitBox,ActivateHdl,weld::ComboBox &,bool)171 IMPL_LINK_NOARG(LimitBox, ActivateHdl, weld::ComboBox&, bool)
172 {
173     GrabFocusToDocument();
174     Apply();
175     return true;
176 }
177 
LimitBoxController(const uno::Reference<uno::XComponentContext> & rxContext)178 LimitBoxController::LimitBoxController(
179     const uno::Reference< uno::XComponentContext >& rxContext ) :
180     svt::ToolboxController( rxContext,
181                             uno::Reference< frame::XFrame >(),
182                             ".uno:DBLimit" ),
183     m_xLimitBox( nullptr )
184 {
185 }
186 
~LimitBoxController()187 LimitBoxController::~LimitBoxController()
188 {
189 }
190 
191 /// XInterface
queryInterface(const uno::Type & aType)192 uno::Any SAL_CALL LimitBoxController::queryInterface( const uno::Type& aType )
193 {
194     uno::Any a = ToolboxController::queryInterface( aType );
195     if ( a.hasValue() )
196         return a;
197 
198     return ::cppu::queryInterface( aType, static_cast< lang::XServiceInfo* >( this ));
199 }
200 
acquire()201 void SAL_CALL LimitBoxController::acquire() noexcept
202 {
203     ToolboxController::acquire();
204 }
205 
release()206 void SAL_CALL LimitBoxController::release() noexcept
207 {
208     ToolboxController::release();
209 }
210 
211 
212 /// XServiceInfo
getImplementationName()213 OUString SAL_CALL LimitBoxController::getImplementationName()
214 {
215     return "org.libreoffice.comp.dbu.LimitBoxController";
216 }
217 
IMPLEMENT_SERVICE_INFO_SUPPORTS(LimitBoxController)218 IMPLEMENT_SERVICE_INFO_SUPPORTS(LimitBoxController)
219 
220 css::uno::Sequence< OUString > SAL_CALL LimitBoxController::getSupportedServiceNames()
221 {
222     return { "com.sun.star.frame.ToolbarController" };
223 }
224 
225 /// XComponent
dispose()226 void SAL_CALL LimitBoxController::dispose()
227 {
228     svt::ToolboxController::dispose();
229 
230     SolarMutexGuard aSolarMutexGuard;
231     m_xLimitBox.disposeAndClear();
232 }
233 
234 /// XStatusListener
statusChanged(const frame::FeatureStateEvent & rEvent)235 void SAL_CALL LimitBoxController::statusChanged(
236     const frame::FeatureStateEvent& rEvent )
237 {
238     if ( !m_xLimitBox )
239         return;
240 
241     SolarMutexGuard aSolarMutexGuard;
242     if ( rEvent.FeatureURL.Path == "DBLimit" )
243     {
244         if ( rEvent.IsEnabled )
245         {
246             m_xLimitBox->set_sensitive(true);
247             sal_Int64 nLimit = 0;
248             if (rEvent.State >>= nLimit)
249                 m_xLimitBox->set_value(nLimit);
250         }
251         else
252             m_xLimitBox->set_sensitive(false);
253     }
254 }
255 
256 /// XToolbarController
execute(sal_Int16)257 void SAL_CALL LimitBoxController::execute( sal_Int16 /*KeyModifier*/ )
258 {
259 }
260 
click()261 void SAL_CALL LimitBoxController::click()
262 {
263 }
264 
doubleClick()265 void SAL_CALL LimitBoxController::doubleClick()
266 {
267 }
268 
createPopupWindow()269 uno::Reference< awt::XWindow > SAL_CALL LimitBoxController::createPopupWindow()
270 {
271     return uno::Reference< awt::XWindow >();
272 }
273 
createItemWindow(const uno::Reference<awt::XWindow> & xParent)274 uno::Reference< awt::XWindow > SAL_CALL LimitBoxController::createItemWindow(
275     const uno::Reference< awt::XWindow >& xParent )
276 {
277     uno::Reference< awt::XWindow > xItemWindow;
278 
279     VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent );
280     if ( pParent )
281     {
282         SolarMutexGuard aSolarMutexGuard;
283         m_xLimitBox = VclPtr<LimitBox>::Create(pParent, this);
284         xItemWindow = VCLUnoHelper::GetInterface(m_xLimitBox);
285     }
286 
287     return xItemWindow;
288 }
289 
dispatchCommand(const uno::Sequence<beans::PropertyValue> & rArgs)290 void LimitBoxController::dispatchCommand(
291     const uno::Sequence< beans::PropertyValue >& rArgs )
292 {
293     uno::Reference< frame::XDispatchProvider > xDispatchProvider( m_xFrame, uno::UNO_QUERY );
294     if ( xDispatchProvider.is() )
295     {
296         util::URL                               aURL;
297         uno::Reference< frame::XDispatch >      xDispatch;
298         uno::Reference< util::XURLTransformer > xURLTransformer = getURLTransformer();
299 
300         aURL.Complete = ".uno:DBLimit";
301         xURLTransformer->parseStrict( aURL );
302         xDispatch = xDispatchProvider->queryDispatch( aURL, OUString(), 0 );
303         if ( xDispatch.is() )
304             xDispatch->dispatch( aURL, rArgs );
305     }
306 }
307 
308 } // dbaui namespace
309 
310 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
org_libreoffice_comp_dbu_LimitBoxController_get_implementation(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const &)311 org_libreoffice_comp_dbu_LimitBoxController_get_implementation(
312     css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
313 {
314     return cppu::acquire(new ::dbaui::LimitBoxController(context));
315 }
316 
317 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
318