Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / extensions / source / dbpilots / controlwizard.cxx
blob59ce90acbe7d1b2264c04a5c4e563957643c206e
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 "controlwizard.hxx"
21 #include <tools/debug.hxx>
22 #include <com/sun/star/container/XNameAccess.hpp>
23 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
24 #include <com/sun/star/sdb/DatabaseContext.hpp>
25 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
26 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
27 #include <com/sun/star/container/XChild.hpp>
28 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
29 #include <com/sun/star/frame/XModel.hpp>
30 #include <com/sun/star/sheet/XSpreadsheetView.hpp>
31 #include <com/sun/star/drawing/XDrawView.hpp>
32 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
33 #include <com/sun/star/sdb/CommandType.hpp>
34 #include <com/sun/star/sdbc/SQLWarning.hpp>
35 #include <com/sun/star/sdb/SQLContext.hpp>
36 #include <com/sun/star/task/InteractionHandler.hpp>
37 #include <comphelper/types.hxx>
38 #include <connectivity/dbtools.hxx>
39 #include <comphelper/interaction.hxx>
40 #include <vcl/stdtext.hxx>
41 #include <connectivity/conncleanup.hxx>
42 #include <com/sun/star/sdbc/DataType.hpp>
43 #include <tools/urlobj.hxx>
44 #include <osl/diagnose.h>
46 #define WIZARD_SIZE_X 60
47 #define WIZARD_SIZE_Y 23
49 namespace dbp
51 using namespace ::com::sun::star::uno;
52 using namespace ::com::sun::star::awt;
53 using namespace ::com::sun::star::lang;
54 using namespace ::com::sun::star::sdb;
55 using namespace ::com::sun::star::sdbc;
56 using namespace ::com::sun::star::sdbcx;
57 using namespace ::com::sun::star::beans;
58 using namespace ::com::sun::star::container;
59 using namespace ::com::sun::star::drawing;
60 using namespace ::com::sun::star::frame;
61 using namespace ::com::sun::star::sheet;
62 using namespace ::com::sun::star::form;
63 using namespace ::com::sun::star::task;
64 using namespace ::comphelper;
65 using namespace ::dbtools;
67 struct OAccessRegulator
69 friend class OControlWizardPage;
71 protected:
72 OAccessRegulator() { }
75 OControlWizardPage::OControlWizardPage(weld::Container* pPage, OControlWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID)
76 : OControlWizardPage_Base(pPage, pWizard, rUIXMLDescription, rID)
77 , m_pDialog(pWizard)
79 m_xContainer->set_size_request(m_xContainer->get_approximate_digit_width() * WIZARD_SIZE_X,
80 m_xContainer->get_text_height() * WIZARD_SIZE_Y);
83 OControlWizardPage::~OControlWizardPage()
87 OControlWizard* OControlWizardPage::getDialog()
89 return m_pDialog;
92 const OControlWizard* OControlWizardPage::getDialog() const
94 return m_pDialog;
97 bool OControlWizardPage::updateContext()
99 return m_pDialog->updateContext(OAccessRegulator());
102 Reference< XConnection > OControlWizardPage::getFormConnection() const
104 return m_pDialog->getFormConnection(OAccessRegulator());
107 void OControlWizardPage::setFormConnection( const Reference< XConnection >& _rxConn, bool _bAutoDispose )
109 m_pDialog->setFormConnection( OAccessRegulator(), _rxConn, _bAutoDispose );
112 const OControlWizardContext& OControlWizardPage::getContext() const
114 return m_pDialog->getContext();
117 void OControlWizardPage::fillListBox(weld::TreeView& _rList, const Sequence< OUString >& _rItems)
119 _rList.clear();
120 const OUString* pItems = _rItems.getConstArray();
121 const OUString* pEnd = pItems + _rItems.getLength();
122 sal_Int32 nIndex = 0;
123 for (;pItems < pEnd; ++pItems, ++nIndex)
125 _rList.append(OUString::number(nIndex), *pItems);
129 void OControlWizardPage::fillListBox(weld::ComboBox& _rList, const Sequence< OUString >& _rItems)
131 _rList.clear();
132 const OUString* pItems = _rItems.getConstArray();
133 const OUString* pEnd = pItems + _rItems.getLength();
134 for (;pItems < pEnd; ++pItems)
136 _rList.append_text(*pItems);
140 void OControlWizardPage::enableFormDatasourceDisplay()
142 if (m_xFormContentType)
143 // nothing to do
144 return;
146 m_xFrame = m_xBuilder->weld_frame("sourceframe");
147 m_xFrame->show();
148 m_xFormContentType = m_xBuilder->weld_label("contenttype");
149 m_xFormContentTypeLabel = m_xBuilder->weld_label("contenttypelabel");
150 m_xFormDatasource = m_xBuilder->weld_label("datasource");
151 m_xFormDatasourceLabel = m_xBuilder->weld_label("datasourcelabel");
152 m_xFormTable = m_xBuilder->weld_label("formtable");
153 m_xFormTableLabel = m_xBuilder->weld_label("formtablelabel");
155 const OControlWizardContext& rContext = getContext();
156 if ( rContext.bEmbedded )
158 m_xFormDatasourceLabel->hide();
159 m_xFormDatasource->hide();
163 void OControlWizardPage::initializePage()
165 if (m_xFormDatasource && m_xFormContentTypeLabel && m_xFormTable)
167 const OControlWizardContext& rContext = getContext();
168 OUString sDataSource;
169 OUString sCommand;
170 sal_Int32 nCommandType = CommandType::COMMAND;
173 rContext.xForm->getPropertyValue("DataSourceName") >>= sDataSource;
174 rContext.xForm->getPropertyValue("Command") >>= sCommand;
175 rContext.xForm->getPropertyValue("CommandType") >>= nCommandType;
177 catch(const Exception&)
179 OSL_FAIL("OControlWizardPage::initializePage: caught an exception!");
182 INetURLObject aURL( sDataSource );
183 if( aURL.GetProtocol() != INetProtocol::NotValid )
184 sDataSource = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
185 m_xFormDatasource->set_label(sDataSource);
186 m_xFormTable->set_label(sCommand);
188 const char* pCommandTypeResourceId = nullptr;
189 switch (nCommandType)
191 case CommandType::TABLE:
192 pCommandTypeResourceId = RID_STR_TYPE_TABLE;
193 break;
195 case CommandType::QUERY:
196 pCommandTypeResourceId = RID_STR_TYPE_QUERY;
197 break;
199 default:
200 pCommandTypeResourceId = RID_STR_TYPE_COMMAND;
201 break;
203 m_xFormContentType->set_label(compmodule::ModuleRes(pCommandTypeResourceId));
206 OControlWizardPage_Base::initializePage();
209 OControlWizard::OControlWizard(weld::Window* _pParent,
210 const Reference< XPropertySet >& _rxObjectModel, const Reference< XComponentContext >& _rxContext )
211 : WizardMachine(_pParent, WizardButtonFlags::CANCEL | WizardButtonFlags::PREVIOUS | WizardButtonFlags::NEXT | WizardButtonFlags::FINISH)
212 , m_xContext(_rxContext)
214 m_aContext.xObjectModel = _rxObjectModel;
215 initContext();
217 defaultButton(WizardButtonFlags::NEXT);
218 enableButtons(WizardButtonFlags::FINISH, false);
221 OControlWizard::~OControlWizard()
225 short OControlWizard::run()
227 // get the class id of the control we're dealing with
228 sal_Int16 nClassId = FormComponentType::CONTROL;
231 getContext().xObjectModel->getPropertyValue("ClassId") >>= nClassId;
233 catch(const Exception&)
235 OSL_FAIL("OControlWizard::activate: could not obtain the class id!");
237 if (!approveControl(nClassId))
239 // TODO: MessageBox or exception
240 return RET_CANCEL;
243 ActivatePage();
245 m_xAssistant->set_current_page(0);
247 return OControlWizard_Base::run();
250 void OControlWizard::implDetermineShape()
252 Reference< XIndexAccess > xPageObjects = m_aContext.xDrawPage;
253 DBG_ASSERT(xPageObjects.is(), "OControlWizard::implDetermineShape: invalid page!");
255 // for comparing the model
256 Reference< XControlModel > xModelCompare(m_aContext.xObjectModel, UNO_QUERY);
258 if (xPageObjects.is())
260 // loop through all objects of the page
261 sal_Int32 nObjects = xPageObjects->getCount();
262 Reference< XControlShape > xControlShape;
263 Reference< XControlModel > xControlModel;
264 for (sal_Int32 i=0; i<nObjects; ++i)
266 if (xPageObjects->getByIndex(i) >>= xControlShape)
267 { // it _is_ a control shape
268 xControlModel = xControlShape->getControl();
269 DBG_ASSERT(xControlModel.is(), "OControlWizard::implDetermineShape: control shape without model!");
270 if (xModelCompare.get() == xControlModel.get())
272 m_aContext.xObjectShape = xControlShape;
273 break;
281 void OControlWizard::implDetermineForm()
283 Reference< XChild > xModelAsChild(m_aContext.xObjectModel, UNO_QUERY);
284 Reference< XInterface > xControlParent;
285 if (xModelAsChild.is())
286 xControlParent = xModelAsChild->getParent();
288 m_aContext.xForm.set(xControlParent, UNO_QUERY);
289 m_aContext.xRowSet.set(xControlParent, UNO_QUERY);
290 DBG_ASSERT(m_aContext.xForm.is() && m_aContext.xRowSet.is(),
291 "OControlWizard::implDetermineForm: missing some interfaces of the control parent!");
296 void OControlWizard::implDeterminePage()
300 // get the document model
301 Reference< XChild > xControlAsChild(m_aContext.xObjectModel, UNO_QUERY);
302 Reference< XChild > xModelSearch(xControlAsChild->getParent(), UNO_QUERY);
304 Reference< XModel > xModel(xModelSearch, UNO_QUERY);
305 while (xModelSearch.is() && !xModel.is())
307 xModelSearch.set(xModelSearch->getParent(), UNO_QUERY);
308 xModel.set(xModelSearch, UNO_QUERY);
311 Reference< XDrawPage > xPage;
312 if (xModel.is())
314 m_aContext.xDocumentModel = xModel;
316 Reference< XDrawPageSupplier > xPageSupp(xModel, UNO_QUERY);
317 if (xPageSupp.is())
318 { // it's a document with only one page -> Writer
319 xPage = xPageSupp->getDrawPage();
321 else
323 // get the controller currently working on this model
324 Reference< XController > xController = xModel->getCurrentController();
325 DBG_ASSERT(xController.is(), "OControlWizard::implDeterminePage: no current controller!");
327 // maybe it's a spreadsheet
328 Reference< XSpreadsheetView > xView(xController, UNO_QUERY);
329 if (xView.is())
330 { // okay, it is one
331 Reference< XSpreadsheet > xSheet = xView->getActiveSheet();
332 xPageSupp.set(xSheet, UNO_QUERY);
333 DBG_ASSERT(xPageSupp.is(), "OControlWizard::implDeterminePage: a spreadsheet which is no page supplier!");
334 if (xPageSupp.is())
335 xPage = xPageSupp->getDrawPage();
337 else
338 { // can be a draw/impress doc only
339 Reference< XDrawView > xDrawView(xController, UNO_QUERY);
340 DBG_ASSERT(xDrawView.is(), "OControlWizard::implDeterminePage: no alternatives left ... can't determine the page!");
341 if (xDrawView.is())
342 xPage = xDrawView->getCurrentPage();
346 else
348 DBG_ASSERT(xPage.is(), "OControlWizard::implDeterminePage: can't determine the page (no model)!");
350 m_aContext.xDrawPage = xPage;
352 catch(const Exception&)
354 OSL_FAIL("OControlWizard::implDeterminePage: caught an exception!");
359 void OControlWizard::implGetDSContext()
363 DBG_ASSERT(m_xContext.is(), "OControlWizard::implGetDSContext: invalid service factory!");
365 m_aContext.xDatasourceContext = DatabaseContext::create(m_xContext);
367 catch(const Exception&)
369 OSL_FAIL("OControlWizard::implGetDSContext: invalid database context!");
374 Reference< XConnection > OControlWizard::getFormConnection(const OAccessRegulator&) const
376 return getFormConnection();
379 Reference< XConnection > OControlWizard::getFormConnection() const
381 Reference< XConnection > xConn;
384 if ( !::dbtools::isEmbeddedInDatabase(m_aContext.xForm,xConn) )
385 m_aContext.xForm->getPropertyValue("ActiveConnection") >>= xConn;
387 catch(const Exception&)
389 OSL_FAIL("OControlWizard::getFormConnection: caught an exception!");
391 return xConn;
395 void OControlWizard::setFormConnection( const OAccessRegulator& _rAccess, const Reference< XConnection >& _rxConn, bool _bAutoDispose )
399 Reference< XConnection > xOldConn = getFormConnection(_rAccess);
400 if (xOldConn.get() == _rxConn.get())
401 return;
403 disposeComponent(xOldConn);
405 // set the new connection
406 if ( _bAutoDispose )
408 // for this, use an AutoDisposer (so the conn is cleaned up when the form dies or gets another connection)
409 Reference< XRowSet > xFormRowSet( m_aContext.xForm, UNO_QUERY );
410 rtl::Reference<OAutoConnectionDisposer> pAutoDispose = new OAutoConnectionDisposer( xFormRowSet, _rxConn );
412 else
414 m_aContext.xForm->setPropertyValue("ActiveConnection", makeAny( _rxConn ) );
417 catch(const Exception&)
419 OSL_FAIL("OControlWizard::setFormConnection: caught an exception!");
424 bool OControlWizard::updateContext(const OAccessRegulator&)
426 return initContext();
429 Reference< XInteractionHandler > OControlWizard::getInteractionHandler(weld::Window* _pWindow) const
431 Reference< XInteractionHandler > xHandler;
434 xHandler.set( InteractionHandler::createWithParent(m_xContext, nullptr), UNO_QUERY_THROW );
436 catch(const Exception&) { }
437 if (!xHandler.is())
439 const OUString sInteractionHandlerServiceName("com.sun.star.task.InteractionHandler");
440 ShowServiceNotAvailableError(_pWindow, sInteractionHandlerServiceName, true);
442 return xHandler;
445 bool OControlWizard::initContext()
447 DBG_ASSERT(m_aContext.xObjectModel.is(), "OGroupBoxWizard::initContext: have no control model to work with!");
448 if (!m_aContext.xObjectModel.is())
449 return false;
451 // reset the context
452 m_aContext.xForm.clear();
453 m_aContext.xRowSet.clear();
454 m_aContext.xDocumentModel.clear();
455 m_aContext.xDrawPage.clear();
456 m_aContext.xObjectShape.clear();
457 m_aContext.aFieldNames.realloc(0);
459 m_aContext.xObjectContainer.clear();
460 m_aContext.aTypes.clear();
461 m_aContext.bEmbedded = false;
463 Any aSQLException;
464 Reference< XPreparedStatement > xStatement;
467 // get the datasource context
468 implGetDSContext();
470 // first, determine the form the control belongs to
471 implDetermineForm();
473 // need the page, too
474 implDeterminePage();
476 // the shape of the control
477 implDetermineShape();
479 // get the columns of the object the settings refer to
480 Reference< XNameAccess > xColumns;
482 if (m_aContext.xForm.is())
484 // collect some properties of the form
485 OUString sObjectName = ::comphelper::getString(m_aContext.xForm->getPropertyValue("Command"));
486 sal_Int32 nObjectType = ::comphelper::getINT32(m_aContext.xForm->getPropertyValue("CommandType"));
488 // calculate the connection the rowset is working with
489 Reference< XConnection > xConnection;
490 m_aContext.bEmbedded = ::dbtools::isEmbeddedInDatabase( m_aContext.xForm, xConnection );
491 if ( !m_aContext.bEmbedded )
492 xConnection = ::dbtools::connectRowset( m_aContext.xRowSet, m_xContext, nullptr );
494 // get the fields
495 if (xConnection.is())
497 switch (nObjectType)
499 case 0:
501 Reference< XTablesSupplier > xSupplyTables(xConnection, UNO_QUERY);
502 if (xSupplyTables.is() && xSupplyTables->getTables().is() && xSupplyTables->getTables()->hasByName(sObjectName))
504 Reference< XColumnsSupplier > xSupplyColumns;
505 m_aContext.xObjectContainer = xSupplyTables->getTables();
506 m_aContext.xObjectContainer->getByName(sObjectName) >>= xSupplyColumns;
507 DBG_ASSERT(xSupplyColumns.is(), "OControlWizard::initContext: invalid table columns!");
508 xColumns = xSupplyColumns->getColumns();
511 break;
512 case 1:
514 Reference< XQueriesSupplier > xSupplyQueries(xConnection, UNO_QUERY);
515 if (xSupplyQueries.is() && xSupplyQueries->getQueries().is() && xSupplyQueries->getQueries()->hasByName(sObjectName))
517 Reference< XColumnsSupplier > xSupplyColumns;
518 m_aContext.xObjectContainer = xSupplyQueries->getQueries();
519 m_aContext.xObjectContainer->getByName(sObjectName) >>= xSupplyColumns;
520 DBG_ASSERT(xSupplyColumns.is(), "OControlWizard::initContext: invalid query columns!");
521 xColumns = xSupplyColumns->getColumns();
524 break;
525 default:
527 xStatement = xConnection->prepareStatement(sObjectName);
529 // not interested in any results, only in the fields
530 Reference< XPropertySet > xStatementProps(xStatement, UNO_QUERY);
531 xStatementProps->setPropertyValue("MaxRows", makeAny(sal_Int32(0)));
533 // TODO: think about handling local SQLExceptions here ...
534 Reference< XColumnsSupplier > xSupplyCols(xStatement->executeQuery(), UNO_QUERY);
535 if (xSupplyCols.is())
536 xColumns = xSupplyCols->getColumns();
542 if (xColumns.is())
544 m_aContext.aFieldNames = xColumns->getElementNames();
545 const OUString* pBegin = m_aContext.aFieldNames.getConstArray();
546 const OUString* pEnd = pBegin + m_aContext.aFieldNames.getLength();
547 for(;pBegin != pEnd;++pBegin)
549 sal_Int32 nFieldType = DataType::OTHER;
552 Reference< XPropertySet > xColumn;
553 xColumns->getByName(*pBegin) >>= xColumn;
554 xColumn->getPropertyValue("Type") >>= nFieldType;
556 catch(const Exception&)
558 OSL_FAIL("OControlWizard::initContext: unexpected exception while gathering column information!");
560 m_aContext.aTypes.emplace(*pBegin,nFieldType);
564 catch(const SQLContext& e) { aSQLException <<= e; }
565 catch(const SQLWarning& e) { aSQLException <<= e; }
566 catch(const SQLException& e) { aSQLException <<= e; }
567 catch(const Exception&)
569 OSL_FAIL("OControlWizard::initContext: could not retrieve the control context (caught an exception)!");
572 ::comphelper::disposeComponent(xStatement);
574 if (aSQLException.hasValue())
575 { // an SQLException (or derivee) was thrown ...
577 // prepend an extra SQLContext explaining what we were doing
578 SQLContext aContext;
579 aContext.Message = compmodule::ModuleRes(RID_STR_COULDNOTOPENTABLE);
580 aContext.NextException = aSQLException;
582 // create an interaction handler to display this exception
583 Reference< XInteractionHandler > xHandler = getInteractionHandler(m_xAssistant.get());
584 if ( !xHandler.is() )
585 return false;
587 Reference< XInteractionRequest > xRequest = new OInteractionRequest(makeAny(aContext));
590 xHandler->handle(xRequest);
592 catch(const Exception&) { }
593 return false;
596 return m_aContext.aFieldNames.hasElements();
600 void OControlWizard::commitControlSettings(OControlWizardSettings const * _pSettings)
602 DBG_ASSERT(m_aContext.xObjectModel.is(), "OControlWizard::commitControlSettings: have no control model to work with!");
603 if (!m_aContext.xObjectModel.is())
604 return;
606 // the only thing we have at the moment is the label
609 Reference< XPropertySetInfo > xInfo = m_aContext.xObjectModel->getPropertySetInfo();
610 if (xInfo.is() && xInfo->hasPropertyByName("Label"))
612 OUString sControlLabel(_pSettings->sControlLabel);
613 m_aContext.xObjectModel->setPropertyValue(
614 "Label",
615 makeAny(sControlLabel)
619 catch(const Exception&)
621 OSL_FAIL("OControlWizard::commitControlSettings: could not commit the basic control settings!");
626 void OControlWizard::initControlSettings(OControlWizardSettings* _pSettings)
628 DBG_ASSERT(m_aContext.xObjectModel.is(), "OControlWizard::initControlSettings: have no control model to work with!");
629 if (!m_aContext.xObjectModel.is())
630 return;
632 // initialize some settings from the control model give
635 OUString sLabelPropertyName("Label");
636 Reference< XPropertySetInfo > xInfo = m_aContext.xObjectModel->getPropertySetInfo();
637 if (xInfo.is() && xInfo->hasPropertyByName(sLabelPropertyName))
639 OUString sControlLabel;
640 m_aContext.xObjectModel->getPropertyValue(sLabelPropertyName) >>= sControlLabel;
641 _pSettings->sControlLabel = sControlLabel;
644 catch(const Exception&)
646 OSL_FAIL("OControlWizard::initControlSettings: could not retrieve the basic control settings!");
651 bool OControlWizard::needDatasourceSelection()
653 // lemme see ...
654 return !getContext().aFieldNames.hasElements();
655 // if we got fields, the data source is valid ...
659 } // namespace dbp
662 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */