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  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <core_resource.hxx>
21 #include <paramdialog.hxx>
22 #include <strings.hrc>
23 #include <strings.hxx>
24 #include <com/sun/star/util/NumberFormatter.hpp>
25 #include <comphelper/types.hxx>
26 #include <connectivity/dbtools.hxx>
27 #include <vcl/weld.hxx>
28 #include <o3tl/safeint.hxx>
29 #include <osl/diagnose.h>
30 #include <tools/diagnose_ex.h>
31 
32 namespace dbaui
33 {
34 
35     using namespace ::com::sun::star::uno;
36     using namespace ::com::sun::star::lang;
37     using namespace ::com::sun::star::beans;
38     using namespace ::com::sun::star::container;
39     using namespace ::com::sun::star::sdbc;
40     using namespace ::com::sun::star::util;
41     using namespace ::connectivity;
42 
43     // OParameterDialog
44 
45 
OParameterDialog(weld::Window * pParent,const Reference<XIndexAccess> & rParamContainer,const Reference<XConnection> & _rxConnection,const Reference<XComponentContext> & rxContext)46     OParameterDialog::OParameterDialog(
47             weld::Window* pParent, const Reference< XIndexAccess > & rParamContainer,
48             const Reference< XConnection > & _rxConnection, const Reference< XComponentContext >& rxContext)
49         : GenericDialogController(pParent, "dbaccess/ui/parametersdialog.ui", "Parameters")
50         , m_nCurrentlySelected(-1)
51         , m_xConnection(_rxConnection)
52         , m_aPredicateInput( rxContext, _rxConnection, getParseContext() )
53         , m_xAllParams(m_xBuilder->weld_tree_view("allParamTreeview"))
54         , m_xParam(m_xBuilder->weld_entry("paramEntry"))
55         , m_xTravelNext(m_xBuilder->weld_button("next"))
56         , m_xOKBtn(m_xBuilder->weld_button("ok"))
57         , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
58     {
59         m_xAllParams->set_size_request(-1, m_xAllParams->get_height_rows(10));
60 
61         if (rxContext.is())
62             m_xFormatter.set( NumberFormatter::create( rxContext ), UNO_QUERY_THROW);
63         else {
64             OSL_FAIL("OParameterDialog::OParameterDialog: need a service factory!");
65         }
66 
67         Reference< XNumberFormatsSupplier >  xNumberFormats = ::dbtools::getNumberFormats(m_xConnection, true);
68         if (!xNumberFormats.is())
69             ::comphelper::disposeComponent(m_xFormatter);
70         else
71             m_xFormatter->attachNumberFormatsSupplier(xNumberFormats);
72         try
73         {
74             OSL_ENSURE(rParamContainer->getCount(), "OParameterDialog::OParameterDialog : can't handle empty containers !");
75 
76             m_aFinalValues.realloc(rParamContainer->getCount());
77             PropertyValue* pValues = m_aFinalValues.getArray();
78 
79             for (sal_Int32 i = 0, nCount = rParamContainer->getCount(); i<nCount; ++i, ++pValues)
80             {
81                 Reference< XPropertySet >  xParamAsSet;
82                 rParamContainer->getByIndex(i) >>= xParamAsSet;
83                 OSL_ENSURE(xParamAsSet.is(),"Parameter is null!");
84                 if(!xParamAsSet.is())
85                     continue;
86                 pValues->Name = ::comphelper::getString(xParamAsSet->getPropertyValue(PROPERTY_NAME));
87                 m_xAllParams->append_text(pValues->Name);
88 
89                 m_aVisitedParams.push_back(VisitFlags::NONE);
90                     // not visited, not dirty
91             }
92 
93             m_xParams = rParamContainer;
94         }
95         catch(Exception&)
96         {
97             DBG_UNHANDLED_EXCEPTION("dbaccess");
98         }
99 
100         Construct();
101 
102         m_aResetVisitFlag.SetInvokeHandler(LINK(this, OParameterDialog, OnVisitedTimeout));
103     }
104 
~OParameterDialog()105     OParameterDialog::~OParameterDialog()
106     {
107         if (m_aResetVisitFlag.IsActive())
108             m_aResetVisitFlag.Stop();
109     }
110 
Construct()111     void OParameterDialog::Construct()
112     {
113         m_xAllParams->connect_changed(LINK(this, OParameterDialog, OnEntryListBoxSelected));
114         m_xParam->connect_focus_out(LINK(this, OParameterDialog, OnValueLoseFocusHdl));
115         m_xParam->connect_changed(LINK(this, OParameterDialog, OnValueModified));
116         m_xTravelNext->connect_clicked(LINK(this, OParameterDialog, OnButtonClicked));
117         m_xOKBtn->connect_clicked(LINK(this, OParameterDialog, OnButtonClicked));
118         m_xCancelBtn->connect_clicked(LINK(this, OParameterDialog, OnButtonClicked));
119 
120         if (m_xAllParams->n_children())
121         {
122             m_xAllParams->select(0);
123             OnEntrySelected();
124 
125             if (m_xAllParams->n_children() == 1)
126             {
127                 m_xTravelNext->set_sensitive(false);
128             }
129 
130             if (m_xAllParams->n_children() > 1)
131             {
132                 m_xOKBtn->set_has_default(false);
133                 m_xTravelNext->set_has_default(true);
134             }
135         }
136 
137         m_xParam->grab_focus();
138     }
139 
IMPL_LINK_NOARG(OParameterDialog,OnValueLoseFocusHdl,weld::Widget &,void)140     IMPL_LINK_NOARG(OParameterDialog, OnValueLoseFocusHdl, weld::Widget&, void)
141     {
142         CheckValueForError();
143     }
144 
CheckValueForError()145     bool OParameterDialog::CheckValueForError()
146     {
147         if (m_nCurrentlySelected != -1)
148         {
149             if ( !( m_aVisitedParams[ m_nCurrentlySelected ] & VisitFlags::Dirty ) )
150                 // nothing to do, the value isn't dirty
151                 return false;
152         }
153 
154         bool bRet = false;
155 
156         Reference< XPropertySet >  xParamAsSet;
157         m_xParams->getByIndex(m_nCurrentlySelected) >>= xParamAsSet;
158         if (xParamAsSet.is())
159         {
160             if (m_xConnection.is() && m_xFormatter.is())
161             {
162                 OUString sParamValue(m_xParam->get_text());
163                 bool bValid = m_aPredicateInput.normalizePredicateString( sParamValue, xParamAsSet );
164                 m_xParam->set_text(sParamValue);
165                 m_xParam->set_message_type(bValid ? weld::EntryMessageType::Normal : weld::EntryMessageType::Error);
166                 OUString sToolTip;
167                 if ( bValid )
168                 {
169                     // with this the value isn't dirty anymore
170                     if (m_nCurrentlySelected != -1)
171                         m_aVisitedParams[m_nCurrentlySelected] &= ~VisitFlags::Dirty;
172                 }
173                 else
174                 {
175                     OUString sName;
176                     try
177                     {
178                         sName = ::comphelper::getString(xParamAsSet->getPropertyValue(PROPERTY_NAME));
179                     }
180                     catch(Exception&)
181                     {
182                         DBG_UNHANDLED_EXCEPTION("dbaccess");
183                     }
184 
185                     OUString sMessage(DBA_RES(STR_COULD_NOT_CONVERT_PARAM));
186                     sToolTip = sMessage.replaceAll( "$name$", sName );
187                     m_xParam->grab_focus();
188                     bRet = true;
189                 }
190                 m_xParam->set_tooltip_text(sToolTip);
191                 m_xOKBtn->set_sensitive(bValid);
192             }
193         }
194 
195         return bRet;
196     }
197 
IMPL_LINK(OParameterDialog,OnButtonClicked,weld::Button &,rButton,void)198     IMPL_LINK(OParameterDialog, OnButtonClicked, weld::Button&, rButton, void)
199     {
200         if (m_xCancelBtn.get() == &rButton)
201         {
202             // no interpreting of the given values anymore...
203             m_xParam->connect_focus_out(Link<weld::Widget&, void>()); // no direct call from the control anymore ...
204             m_xDialog->response(RET_CANCEL);
205         }
206         else if (m_xOKBtn.get() == &rButton)
207         {
208             // transfer the current values into the Any
209             if (OnEntrySelected())
210             {   // there was an error interpreting the current text
211                 return;
212             }
213 
214             if (m_xParams.is())
215             {
216                 // write the parameters
217                 try
218                 {
219                     PropertyValue* pValues = m_aFinalValues.getArray();
220                     for (sal_Int32 i = 0, nCount = m_xParams->getCount(); i<nCount; ++i, ++pValues)
221                     {
222                         Reference< XPropertySet >  xParamAsSet;
223                         m_xParams->getByIndex(i) >>= xParamAsSet;
224 
225                         OUString sValue;
226                         pValues->Value >>= sValue;
227                         pValues->Value = m_aPredicateInput.getPredicateValue( sValue, xParamAsSet );
228                     }
229                 }
230                 catch(Exception&)
231                 {
232                     DBG_UNHANDLED_EXCEPTION("dbaccess");
233                 }
234 
235             }
236             m_xDialog->response(RET_OK);
237         }
238         else if (m_xTravelNext.get() == &rButton)
239         {
240             if (sal_Int32 nCount = m_xAllParams->n_children())
241             {
242                 sal_Int32 nCurrent = m_xAllParams->get_selected_index();
243                 OSL_ENSURE(static_cast<size_t>(nCount) == m_aVisitedParams.size(), "OParameterDialog::OnButtonClicked : inconsistent lists !");
244 
245                 // search the next entry in list we haven't visited yet
246                 sal_Int32 nNext = (nCurrent + 1) % nCount;
247                 while ((nNext != nCurrent) && ( m_aVisitedParams[nNext] & VisitFlags::Visited ))
248                     nNext = (nNext + 1) % nCount;
249 
250                 if ( m_aVisitedParams[nNext] & VisitFlags::Visited )
251                     // there is no such "not visited yet" entry -> simply take the next one
252                     nNext = (nCurrent + 1) % nCount;
253 
254                 m_xAllParams->select(nNext);
255                 OnEntrySelected();
256             }
257         }
258     }
259 
IMPL_LINK_NOARG(OParameterDialog,OnEntryListBoxSelected,weld::TreeView &,void)260     IMPL_LINK_NOARG(OParameterDialog, OnEntryListBoxSelected, weld::TreeView&, void)
261     {
262         OnEntrySelected();
263     }
264 
OnEntrySelected()265     bool OParameterDialog::OnEntrySelected()
266     {
267         if (m_aResetVisitFlag.IsActive())
268         {
269             LINK(this, OParameterDialog, OnVisitedTimeout).Call(&m_aResetVisitFlag);
270             m_aResetVisitFlag.Stop();
271         }
272         // save the old values
273         if (m_nCurrentlySelected != -1)
274         {
275             // do the transformation of the current text
276             if (CheckValueForError())
277             {   // there was an error interpreting the text
278                 m_xAllParams->select(m_nCurrentlySelected);
279                 return true;
280             }
281 
282             m_aFinalValues[m_nCurrentlySelected].Value <<= m_xParam->get_text();
283         }
284 
285         // initialize the controls with the new values
286         sal_Int32 nSelected = m_xAllParams->get_selected_index();
287         OSL_ENSURE(nSelected != -1, "OParameterDialog::OnEntrySelected : no current entry !");
288 
289         m_xParam->set_text(::comphelper::getString(m_aFinalValues[nSelected].Value));
290         m_nCurrentlySelected = nSelected;
291 
292         // with this the value isn't dirty
293         OSL_ENSURE(o3tl::make_unsigned(m_nCurrentlySelected) < m_aVisitedParams.size(), "OParameterDialog::OnEntrySelected : invalid current entry !");
294         m_aVisitedParams[m_nCurrentlySelected] &= ~VisitFlags::Dirty;
295 
296         m_aResetVisitFlag.SetTimeout(1000);
297         m_aResetVisitFlag.Start();
298 
299         return false;
300     }
301 
IMPL_LINK_NOARG(OParameterDialog,OnVisitedTimeout,Timer *,void)302     IMPL_LINK_NOARG(OParameterDialog, OnVisitedTimeout, Timer*, void)
303     {
304         OSL_ENSURE(m_nCurrentlySelected != -1, "OParameterDialog::OnVisitedTimeout : invalid call !");
305 
306         // mark the currently selected entry as visited
307         OSL_ENSURE(o3tl::make_unsigned(m_nCurrentlySelected) < m_aVisitedParams.size(), "OParameterDialog::OnVisitedTimeout : invalid entry !");
308         m_aVisitedParams[m_nCurrentlySelected] |= VisitFlags::Visited;
309 
310         // was it the last "not visited yet" entry ?
311         bool bVisited = false;
312         for (auto const& visitedParam : m_aVisitedParams)
313         {
314             if (!(visitedParam & VisitFlags::Visited))
315             {
316                 bVisited = true;
317                 break;
318             }
319         }
320 
321         if (!bVisited)
322         {
323             // yes, there isn't another one -> change the "default button"
324             m_xTravelNext->set_has_default(false);
325             m_xOKBtn->set_has_default(true);
326         }
327     }
328 
IMPL_LINK(OParameterDialog,OnValueModified,weld::Entry &,rEdit,void)329     IMPL_LINK(OParameterDialog, OnValueModified, weld::Entry&, rEdit, void)
330     {
331         // mark the currently selected entry as dirty
332         OSL_ENSURE(o3tl::make_unsigned(m_nCurrentlySelected) < m_aVisitedParams.size(), "OParameterDialog::OnValueModified : invalid entry !");
333         m_aVisitedParams[m_nCurrentlySelected] |= VisitFlags::Dirty;
334         rEdit.set_message_type(weld::EntryMessageType::Normal);
335     }
336 
337 }   // namespace dbaui
338 
339 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
340