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