LibreOffice Module reportdesign (master)  1
AddField.cxx
Go to the documentation of this file.
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 #include <AddField.hxx>
20 #include <UITools.hxx>
21 #include <com/sun/star/sdb/CommandType.hpp>
22 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
23 
24 #include <vcl/svapp.hxx>
25 
26 #include <tools/diagnose_ex.h>
27 
28 #include <connectivity/dbtools.hxx>
29 #include <core_resource.hxx>
30 #include <helpids.h>
31 #include <strings.hrc>
32 #include <strings.hxx>
33 
34 #include <comphelper/sequence.hxx>
35 
36 namespace rptui
37 {
38 
39 using namespace ::com::sun::star;
40 using namespace sdbc;
41 using namespace sdb;
42 using namespace uno;
43 using namespace datatransfer;
44 using namespace beans;
45 using namespace lang;
46 using namespace container;
47 using namespace ::svx;
48 
49 IMPL_LINK(OAddFieldWindow, DragBeginHdl, bool&, rUnsetDragIcon, bool)
50 {
51  rUnsetDragIcon = false;
52  if (m_xListBox->get_selected_index() == -1)
53  {
54  // no drag without a field
55  return true;
56  }
57 
58  m_xHelper->setDescriptors(getSelectedFieldDescriptors());
59  return false;
60 }
61 
62 OAddFieldWindow::OAddFieldWindow(weld::Window* pParent, const uno::Reference< beans::XPropertySet >& xRowSet)
63  : GenericDialogController(pParent, "modules/dbreport/ui/floatingfield.ui", "FloatingField")
64  , ::comphelper::OPropertyChangeListener(m_aMutex)
65  , ::comphelper::OContainerListener(m_aMutex)
66  , m_xRowSet(xRowSet)
67  , m_xActions(m_xBuilder->weld_toolbar("toolbox"))
68  , m_xListBox(m_xBuilder->weld_tree_view("treeview"))
69  , m_xHelpText(m_xBuilder->weld_label("helptext"))
70  , m_nCommandType(0)
71  , m_bEscapeProcessing(false)
72 {
73  m_xListBox->set_help_id(HID_RPT_FIELD_SEL);
74  m_xListBox->set_selection_mode(SelectionMode::Multiple);
75  m_xHelper.set(new svx::OMultiColumnTransferable);
76  rtl::Reference<TransferDataContainer> xHelper(m_xHelper.get());
77  m_xListBox->enable_drag_source(xHelper, DND_ACTION_COPYMOVE | DND_ACTION_LINK);
78  m_xListBox->connect_drag_begin(LINK(this, OAddFieldWindow, DragBeginHdl));
79 
80  m_xDialog->connect_toplevel_focus_changed(LINK(this, OAddFieldWindow, FocusChangeHdl));
81 
82  m_xDialog->set_help_id(HID_RPT_FIELD_SEL_WIN);
83 
84  m_xActions->connect_clicked(LINK(this, OAddFieldWindow, OnSortAction));
85  m_xActions->set_item_active("up", true);
86  m_xListBox->make_sorted();
87  m_xActions->set_item_sensitive("insert", false);
88 
89  m_xListBox->connect_row_activated(LINK( this, OAddFieldWindow, OnDoubleClickHdl ) );
90  m_xListBox->connect_changed(LINK( this, OAddFieldWindow, OnSelectHdl ) );
91  m_xListBox->set_size_request(m_xListBox->get_approximate_digit_width() * 45, m_xListBox->get_height_rows(8));
92 
93  if (!m_xRowSet.is())
94  return;
95 
96  try
97  {
98  // be notified when the settings of report definition change
99  m_pChangeListener = new ::comphelper::OPropertyChangeMultiplexer( this, m_xRowSet );
100  m_pChangeListener->addProperty( PROPERTY_COMMAND );
101  m_pChangeListener->addProperty( PROPERTY_COMMANDTYPE );
102  m_pChangeListener->addProperty( PROPERTY_ESCAPEPROCESSING );
103  m_pChangeListener->addProperty( PROPERTY_FILTER );
104  }
105  catch( const Exception& )
106  {
107  DBG_UNHANDLED_EXCEPTION("reportdesign");
108  }
109 }
110 
111 OAddFieldWindow::~OAddFieldWindow()
112 {
113  m_aListBoxData.clear();
114  if (m_pChangeListener.is())
115  m_pChangeListener->dispose();
116  if ( m_pContainerListener.is() )
117  m_pContainerListener->dispose();
118 }
119 
121 {
122  if (m_xDialog->has_toplevel_focus())
123  m_xListBox->grab_focus();
124 }
125 
126 uno::Sequence< beans::PropertyValue > OAddFieldWindow::getSelectedFieldDescriptors()
127 {
128  std::vector<beans::PropertyValue> aArgs;
129 
130  m_xListBox->selected_foreach([this, &aArgs](weld::TreeIter& rEntry){
131  // build a descriptor for the currently selected field
132  svx::ODataAccessDescriptor aDescriptor;
133  fillDescriptor(rEntry, aDescriptor);
134  aArgs.push_back(beans::PropertyValue());
135  aArgs.back().Value <<= aDescriptor.createPropertyValueSequence();
136 
137  return false;
138  });
139 
140  return comphelper::containerToSequence(aArgs);
141 }
142 
143 void OAddFieldWindow::_propertyChanged( const beans::PropertyChangeEvent& _evt )
144 {
145  OSL_ENSURE( _evt.Source == m_xRowSet, "OAddFieldWindow::_propertyChanged: where did this come from?" );
146  Update();
147 }
148 
149 void OAddFieldWindow::addToList(const uno::Sequence< OUString >& rEntries)
150 {
151  for (const OUString& rEntry : rEntries)
152  {
153  m_aListBoxData.emplace_back(new ColumnInfo(rEntry));
154  OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_aListBoxData.back().get())));
155  m_xListBox->append(sId, rEntry);
156  }
157 }
158 
159 void OAddFieldWindow::addToList(const uno::Reference< container::XNameAccess>& i_xColumns)
160 {
161  const uno::Sequence< OUString > aEntries = i_xColumns->getElementNames();
162  for ( const OUString& rEntry : aEntries )
163  {
164  uno::Reference< beans::XPropertySet> xColumn(i_xColumns->getByName(rEntry),UNO_QUERY_THROW);
165  OUString sLabel;
166  if ( xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_LABEL) )
167  xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
168  m_aListBoxData.emplace_back(new ColumnInfo(rEntry, sLabel));
169  OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_aListBoxData.back().get())));
170  if ( !sLabel.isEmpty() )
171  m_xListBox->append(sId, sLabel);
172  else
173  m_xListBox->append(sId, rEntry);
174  }
175 }
176 
177 void OAddFieldWindow::Update()
178 {
179  SolarMutexGuard aSolarGuard;
180 
181  if ( m_pContainerListener.is() )
182  m_pContainerListener->dispose();
183  m_pContainerListener = nullptr;
184  m_xColumns.clear();
185 
186  try
187  {
188  // ListBox loeschen
189  m_xListBox->clear();
190  m_aListBoxData.clear();
191  const OString aIds[] = { "up", "down" };
192  for (size_t j = 0; j< SAL_N_ELEMENTS(aIds); ++j)
193  m_xActions->set_item_sensitive(aIds[j], false);
194 
195  OUString aTitle(RptResId(RID_STR_FIELDSELECTION));
196  m_xDialog->set_title(aTitle);
197  if ( m_xRowSet.is() )
198  {
199  OUString sCommand( m_aCommandName );
200  sal_Int32 nCommandType( m_nCommandType );
201  bool bEscapeProcessing( m_bEscapeProcessing );
202  OUString sFilter( m_sFilter );
203 
204  OSL_VERIFY( m_xRowSet->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand );
205  OSL_VERIFY( m_xRowSet->getPropertyValue( PROPERTY_COMMANDTYPE ) >>= nCommandType );
206  OSL_VERIFY( m_xRowSet->getPropertyValue( PROPERTY_ESCAPEPROCESSING ) >>= bEscapeProcessing );
207  OSL_VERIFY( m_xRowSet->getPropertyValue( PROPERTY_FILTER ) >>= sFilter );
208 
209  m_aCommandName = sCommand;
210  m_nCommandType = nCommandType;
211  m_bEscapeProcessing = bEscapeProcessing;
212  m_sFilter = sFilter;
213 
214  // add the columns to the list
215  uno::Reference< sdbc::XConnection> xCon = getConnection();
216  if ( xCon.is() && !m_aCommandName.isEmpty() )
217  m_xColumns = dbtools::getFieldsByCommandDescriptor( xCon, GetCommandType(), GetCommand(), m_xHoldAlive );
218  if ( m_xColumns.is() )
219  {
220  addToList(m_xColumns);
221  uno::Reference< container::XContainer> xContainer(m_xColumns,uno::UNO_QUERY);
222  if ( xContainer.is() )
223  m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer);
224  }
225 
226  // add the parameter columns to the list
227  uno::Reference< css::sdbc::XRowSet > xRowSet(m_xRowSet,uno::UNO_QUERY);
228  Sequence< OUString > aParamNames( getParameterNames( xRowSet ) );
229  addToList(aParamNames);
230 
231  // set title
232  aTitle += " " + m_aCommandName;
233  m_xDialog->set_title(aTitle);
234  if ( !m_aCommandName.isEmpty() )
235  {
236  for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
237  m_xActions->set_item_sensitive(aIds[i], true);
238  }
239  OnSelectHdl(*m_xListBox);
240  }
241  }
242  catch( const Exception& )
243  {
244  DBG_UNHANDLED_EXCEPTION("reportdesign");
245  }
246 }
247 
248 uno::Reference< sdbc::XConnection> OAddFieldWindow::getConnection() const
249 {
250  return uno::Reference< sdbc::XConnection>(m_xRowSet->getPropertyValue( PROPERTY_ACTIVECONNECTION ),uno::UNO_QUERY);
251 }
252 
253 void OAddFieldWindow::fillDescriptor(const weld::TreeIter& rSelected, svx::ODataAccessDescriptor& rDescriptor)
254 {
255  if (!m_xColumns.is())
256  return;
257 
258  uno::Reference<container::XChild> xChild(getConnection(),uno::UNO_QUERY);
259  if ( xChild.is( ) )
260  {
261  uno::Reference<sdb::XDocumentDataSource> xDocument( xChild->getParent(), uno::UNO_QUERY );
262  if ( xDocument.is() )
263  {
264  uno::Reference<frame::XModel> xModel(xDocument->getDatabaseDocument(),uno::UNO_QUERY);
265  if ( xModel.is() )
266  rDescriptor[ DataAccessDescriptorProperty::DatabaseLocation ] <<= xModel->getURL();
267  }
268  }
269 
270  rDescriptor[ svx::DataAccessDescriptorProperty::Command ] <<= GetCommand();
271  rDescriptor[ svx::DataAccessDescriptorProperty::CommandType ] <<= GetCommandType();
272  rDescriptor[ svx::DataAccessDescriptorProperty::EscapeProcessing ] <<= m_bEscapeProcessing;
274 
275  ColumnInfo* pInfo = reinterpret_cast<ColumnInfo*>(m_xListBox->get_id(rSelected).toInt64());
277  if ( m_xColumns->hasByName( pInfo->sColumnName ) )
278  rDescriptor[ svx::DataAccessDescriptorProperty::ColumnObject ] = m_xColumns->getByName(pInfo->sColumnName);
279 }
280 
281 void OAddFieldWindow::_elementInserted( const container::ContainerEvent& _rEvent )
282 {
283  OUString sName;
284  if ( !((_rEvent.Accessor >>= sName) && m_xColumns->hasByName(sName)) )
285  return;
286 
287  uno::Reference< beans::XPropertySet> xColumn(m_xColumns->getByName(sName),UNO_QUERY_THROW);
288  OUString sLabel;
289  if ( xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_LABEL) )
290  xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
291  m_aListBoxData.emplace_back(new ColumnInfo(sName, sLabel));
292  OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_aListBoxData.back().get())));
293  if (!sLabel.isEmpty())
294  m_xListBox->append(sId, sLabel);
295  else
296  m_xListBox->append(sId, sName);
297 }
298 
299 void OAddFieldWindow::_elementRemoved( const container::ContainerEvent& /*_rEvent*/ )
300 {
301  m_xListBox->clear();
302  m_aListBoxData.clear();
303  if ( m_xColumns.is() )
304  addToList(m_xColumns);
305 }
306 
307 void OAddFieldWindow::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ )
308 {
309 }
310 
312 {
313  m_xActions->set_item_sensitive("insert", m_xListBox->get_selected_index() != -1);
314 }
315 
316 IMPL_LINK_NOARG( OAddFieldWindow, OnDoubleClickHdl, weld::TreeView&, bool )
317 {
318  m_aCreateLink.Call(*this);
319  return true;
320 }
321 
322 IMPL_LINK(OAddFieldWindow, OnSortAction, const OString&, rCurItem, void)
323 {
324  if (rCurItem == "insert")
325  {
326  OnDoubleClickHdl(*m_xListBox);
327  return;
328  }
329 
330  const OString aIds[] = { "up", "down" };
331 
332  if (rCurItem == "delete")
333  {
334  for (size_t j = 0; j< SAL_N_ELEMENTS(aIds); ++j)
335  m_xActions->set_item_active(aIds[j], false);
336 
337  m_xListBox->make_unsorted();
338  Update();
339  return;
340  }
341 
342  for (size_t j = 0; j< SAL_N_ELEMENTS(aIds); ++j)
343  m_xActions->set_item_active(aIds[j], rCurItem == aIds[j]);
344 
345  m_xListBox->make_sorted();
346  if (m_xActions->get_item_active("down"))
347  m_xListBox->set_sort_order(false);
348 }
349 
350 } // namespace rptui
351 
352 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define PROPERTY_LABEL
Definition: strings.hxx:90
sal_Int32 m_nCommandType
css::uno::Sequence< css::beans::PropertyValue > const & createPropertyValueSequence()
OUString sColumnName
Definition: ColumnInfo.hxx:28
#define PROPERTY_COMMANDTYPE
Definition: strings.hxx:66
const char * sName
#define SAL_N_ELEMENTS(arr)
#define DBG_UNHANDLED_EXCEPTION(...)
int i
IMPL_LINK_NOARG(OAddFieldWindow, OnDoubleClickHdl, weld::TreeView &, bool)
Definition: AddField.cxx:316
IMPL_LINK(OAddFieldWindow, OnSortAction, const OString &, rCurItem, void)
Definition: AddField.cxx:322
OUString RptResId(const char *pId)
#define PROPERTY_FILTER
Definition: strings.hxx:189
IMPL_LINK(OAddFieldWindow, DragBeginHdl, bool &, rUnsetDragIcon, bool)
Definition: AddField.cxx:49
OAddFieldWindow(const OAddFieldWindow &)=delete
#define HID_RPT_FIELD_SEL_WIN
Definition: helpids.h:36
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Reference< XExecutableDialog > m_xDialog
css::uno::Sequence< OUString > getParameterNames(const css::uno::Reference< css::sdbc::XRowSet > &_rxRowSet)
retrieves the names of the parameters of the command which the given RowSet is bound to ...
Reference< XColumn > xColumn
Reference< XConnection > getConnection(const Reference< XRowSet > &_rxRowSet)
OUString sId
ScXMLEditAttributeMap::Entry const aEntries[]
Reference< XModel > xModel
osl::Mutex m_aMutex
Reference< XNameAccess > getFieldsByCommandDescriptor(const Reference< XConnection > &_rxConnection, const sal_Int32 _nCommandType, const OUString &_rCommand, Reference< XComponent > &_rxKeepFieldsAlive, SQLExceptionInfo *_pErrorInfo)
#define PROPERTY_ACTIVECONNECTION
Definition: strings.hxx:193
#define PROPERTY_COMMAND
Definition: strings.hxx:59
OUString m_sFilter
#define PROPERTY_ESCAPEPROCESSING
Definition: strings.hxx:190
#define HID_RPT_FIELD_SEL
Definition: helpids.h:35