diff options
Diffstat (limited to 'extensions/source/dbpilots')
20 files changed, 3957 insertions, 0 deletions
diff --git a/extensions/source/dbpilots/commonpagesdbp.cxx b/extensions/source/dbpilots/commonpagesdbp.cxx new file mode 100644 index 000000000..2e133e9c5 --- /dev/null +++ b/extensions/source/dbpilots/commonpagesdbp.cxx @@ -0,0 +1,449 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "commonpagesdbp.hxx" +#include <strings.hrc> +#include <bitmaps.hlst> +#include <componentmodule.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sdb/XCompletedConnection.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <comphelper/interaction.hxx> +#include <connectivity/dbtools.hxx> +#include <sfx2/docfilt.hxx> +#include <unotools/pathoptions.hxx> +#include <sfx2/filedlghelper.hxx> +#include <svl/filenotation.hxx> +#include <osl/diagnose.h> + +namespace dbp +{ + + + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::sdbcx; + using namespace ::com::sun::star::task; + using namespace ::comphelper; + + OTableSelectionPage::OTableSelectionPage(weld::Container* pPage, OControlWizard* pWizard) + : OControlWizardPage(pPage, pWizard, "modules/sabpilot/ui/tableselectionpage.ui", "TableSelectionPage") + , m_xTable(m_xBuilder->weld_tree_view("table")) + , m_xDatasource(m_xBuilder->weld_tree_view("datasource")) + , m_xDatasourceLabel(m_xBuilder->weld_label("datasourcelabel")) + , m_xSearchDatabase(m_xBuilder->weld_button("search")) + , m_xSourceBox(m_xBuilder->weld_container("sourcebox")) + { + try + { + m_xDSContext = getContext().xDatasourceContext; + if (m_xDSContext.is()) + fillListBox(*m_xDatasource, m_xDSContext->getElementNames()); + } + catch (const Exception&) + { + OSL_FAIL("OTableSelectionPage::OTableSelectionPage: could not collect the data source names!"); + } + + m_xDatasource->connect_changed(LINK(this, OTableSelectionPage, OnListboxSelection)); + m_xTable->connect_changed(LINK(this, OTableSelectionPage, OnListboxSelection)); + m_xTable->connect_row_activated(LINK(this, OTableSelectionPage, OnListboxDoubleClicked)); + m_xSearchDatabase->connect_clicked(LINK(this, OTableSelectionPage, OnSearchClicked)); + } + + OTableSelectionPage::~OTableSelectionPage() + { + } + + void OTableSelectionPage::Activate() + { + OControlWizardPage::Activate(); + m_xDatasource->grab_focus(); + } + + bool OTableSelectionPage::canAdvance() const + { + if (!OControlWizardPage::canAdvance()) + return false; + + if (0 == m_xDatasource->count_selected_rows()) + return false; + + if (0 == m_xTable->count_selected_rows()) + return false; + + return true; + } + + void OTableSelectionPage::initializePage() + { + OControlWizardPage::initializePage(); + + const OControlWizardContext& rContext = getContext(); + try + { + OUString sDataSourceName; + rContext.xForm->getPropertyValue("DataSourceName") >>= sDataSourceName; + + Reference< XConnection > xConnection; + bool bEmbedded = ::dbtools::isEmbeddedInDatabase( rContext.xForm, xConnection ); + if ( bEmbedded ) + { + m_xSourceBox->hide(); + m_xDatasource->append_text(sDataSourceName); + } + m_xDatasource->select_text(sDataSourceName); + + implFillTables(xConnection); + + OUString sCommand; + OSL_VERIFY( rContext.xForm->getPropertyValue("Command") >>= sCommand ); + sal_Int32 nCommandType = CommandType::TABLE; + OSL_VERIFY( rContext.xForm->getPropertyValue("CommandType") >>= nCommandType ); + + // search the entry of the given type with the given name + for (sal_Int32 nLookup = 0; nLookup < m_xTable->n_children(); ++nLookup) + { + if (sCommand == m_xTable->get_text(nLookup)) + { + if (m_xTable->get_id(nLookup).toInt32() == nCommandType) + { + m_xTable->select( nLookup ); + break; + } + } + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.abpilot", "OTableSelectionPage::initializePage"); + } + } + + bool OTableSelectionPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OControlWizardPage::commitPage(_eReason)) + return false; + + const OControlWizardContext& rContext = getContext(); + try + { + Reference< XConnection > xOldConn; + if ( !rContext.bEmbedded ) + { + xOldConn = getFormConnection(); + + OUString sDataSource = m_xDatasource->get_selected_text(); + rContext.xForm->setPropertyValue("DataSourceName", Any( sDataSource ) ); + } + OUString sCommand = m_xTable->get_selected_text(); + sal_Int32 nCommandType = m_xTable->get_selected_id().toInt32(); + + rContext.xForm->setPropertyValue("Command", Any( sCommand ) ); + rContext.xForm->setPropertyValue("CommandType", Any( nCommandType ) ); + + if ( !rContext.bEmbedded ) + setFormConnection( xOldConn, false ); + + if (!updateContext()) + return false; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.dbpilots", "OTableSelectionPage::commitPage"); + } + + return true; + } + + IMPL_LINK_NOARG( OTableSelectionPage, OnSearchClicked, weld::Button&, void ) + { + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION, + FileDialogFlags::NONE, getDialog()->getDialog()); + aFileDlg.SetDisplayDirectory( SvtPathOptions().GetWorkPath() ); + + std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetFilterByName("StarOffice XML (Base)"); + OSL_ENSURE(pFilter,"Filter: StarOffice XML (Base) could not be found!"); + if ( pFilter ) + { + aFileDlg.AddFilter(pFilter->GetUIName(),pFilter->GetDefaultExtension()); + } + + if (ERRCODE_NONE == aFileDlg.Execute()) + { + OUString sDataSourceName = aFileDlg.GetPath(); + ::svt::OFileNotation aFileNotation(sDataSourceName); + sDataSourceName = aFileNotation.get(::svt::OFileNotation::N_SYSTEM); + m_xDatasource->append_text(sDataSourceName); + m_xDatasource->select_text(sDataSourceName); + LINK(this, OTableSelectionPage, OnListboxSelection).Call(*m_xDatasource); + } + } + + IMPL_LINK(OTableSelectionPage, OnListboxDoubleClicked, weld::TreeView&, _rBox, bool) + { + if (_rBox.count_selected_rows()) + getDialog()->travelNext(); + return true; + } + + IMPL_LINK(OTableSelectionPage, OnListboxSelection, weld::TreeView&, _rBox, void) + { + if (m_xDatasource.get() == &_rBox) + { // new data source selected + implFillTables(); + } + + updateDialogTravelUI(); + } + + namespace + { + void lcl_fillEntries(weld::TreeView& rListBox, const Sequence<OUString>& rNames, const OUString& rImage, sal_Int32 nCommandType) + { + for (auto const & name : rNames) + { + rListBox.append(OUString::number(nCommandType), name, rImage); + } + } + } + + void OTableSelectionPage::implFillTables(const Reference< XConnection >& _rxConn) + { + m_xTable->clear(); + + weld::WaitObject aWaitCursor(getDialog()->getDialog()); + + // will be the table tables of the selected data source + Sequence< OUString > aTableNames; + Sequence< OUString > aQueryNames; + + // connect to the data source + Any aSQLException; + Reference< XConnection > xConn = _rxConn; + if ( !xConn.is() ) + { + if (!m_xDSContext.is()) + return; + // connect to the data source + try + { + OUString sCurrentDatasource = m_xDatasource->get_selected_text(); + if (!sCurrentDatasource.isEmpty()) + { + // obtain the DS object + Reference< XCompletedConnection > xDatasource; + // check if I know this one otherwise transform it into a file URL + if ( !m_xDSContext->hasByName(sCurrentDatasource) ) + { + ::svt::OFileNotation aFileNotation(sCurrentDatasource); + sCurrentDatasource = aFileNotation.get(::svt::OFileNotation::N_URL); + } + + if (m_xDSContext->getByName(sCurrentDatasource) >>= xDatasource) + { // connect + // get the default SDB interaction handler + Reference< XInteractionHandler > xHandler = getDialog()->getInteractionHandler(getDialog()->getDialog()); + if (!xHandler.is() ) + return; + xConn = xDatasource->connectWithCompletion(xHandler); + setFormConnection( xConn ); + } + else + { + OSL_FAIL("OTableSelectionPage::implFillTables: invalid data source object returned by the context"); + } + } + } + catch(const SQLContext& e) { aSQLException <<= e; } + catch(const SQLWarning& e) { aSQLException <<= e; } + catch(const SQLException& e) { aSQLException <<= e; } + catch (const Exception&) + { + OSL_FAIL("OTableSelectionPage::implFillTables: could not fill the table list!"); + } + } + + // will be the table tables of the selected data source + if ( xConn.is() ) + { + try + { + // get the tables + Reference< XTablesSupplier > xSupplTables(xConn, UNO_QUERY); + if ( xSupplTables.is() ) + { + Reference< XNameAccess > xTables = xSupplTables->getTables(); + if (xTables.is()) + aTableNames = xTables->getElementNames(); + } + + // and the queries + Reference< XQueriesSupplier > xSuppQueries( xConn, UNO_QUERY ); + if ( xSuppQueries.is() ) + { + Reference< XNameAccess > xQueries = xSuppQueries->getQueries(); + if ( xQueries.is() ) + aQueryNames = xQueries->getElementNames(); + } + } + catch(const SQLContext& e) { aSQLException <<= e; } + catch(const SQLWarning& e) { aSQLException <<= e; } + catch(const SQLException& e) { aSQLException <<= e; } + catch (const Exception&) + { + OSL_FAIL("OTableSelectionPage::implFillTables: could not fill the table list!"); + } + } + + + if ( aSQLException.hasValue() ) + { // an SQLException (or derivee) was thrown ... + Reference< XInteractionRequest > xRequest = new OInteractionRequest(aSQLException); + try + { + // get the default SDB interaction handler + Reference< XInteractionHandler > xHandler = getDialog()->getInteractionHandler(getDialog()->getDialog()); + if ( xHandler.is() ) + xHandler->handle(xRequest); + } + catch(const Exception&) { } + return; + } + + lcl_fillEntries(*m_xTable, aTableNames, BMP_TABLE, CommandType::TABLE); + lcl_fillEntries(*m_xTable, aQueryNames, BMP_QUERY, CommandType::QUERY); + } + + OMaybeListSelectionPage::OMaybeListSelectionPage(weld::Container* pPage, OControlWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID) + : OControlWizardPage(pPage, pWizard, rUIXMLDescription, rID) + , m_pYes(nullptr) + , m_pNo(nullptr) + , m_pList(nullptr) + { + } + + OMaybeListSelectionPage::~OMaybeListSelectionPage() + { + } + + void OMaybeListSelectionPage::announceControls(weld::RadioButton& _rYesButton, weld::RadioButton& _rNoButton, weld::ComboBox& _rSelection) + { + m_pYes = &_rYesButton; + m_pNo = &_rNoButton; + m_pList = &_rSelection; + + m_pYes->connect_toggled(LINK(this, OMaybeListSelectionPage, OnRadioSelected)); + m_pNo->connect_toggled(LINK(this, OMaybeListSelectionPage, OnRadioSelected)); + implEnableWindows(); + } + + IMPL_LINK(OMaybeListSelectionPage, OnRadioSelected, weld::Toggleable&, rButton, void) + { + if (!rButton.get_active()) + return; + implEnableWindows(); + } + + void OMaybeListSelectionPage::implInitialize(const OUString& _rSelection) + { + DBG_ASSERT(m_pYes, "OMaybeListSelectionPage::implInitialize: no controls announced!"); + bool bIsSelection = ! _rSelection.isEmpty(); + m_pYes->set_active(bIsSelection); + m_pNo->set_active(!bIsSelection); + m_pList->set_sensitive(bIsSelection); + + m_pList->set_active_text(bIsSelection ? _rSelection : OUString()); + } + + void OMaybeListSelectionPage::implCommit(OUString& _rSelection) + { + _rSelection = m_pYes->get_active() ? m_pList->get_active_text() : OUString(); + } + + void OMaybeListSelectionPage::implEnableWindows() + { + m_pList->set_sensitive(m_pYes->get_active()); + } + + void OMaybeListSelectionPage::Activate() + { + OControlWizardPage::Activate(); + + DBG_ASSERT(m_pYes, "OMaybeListSelectionPage::Activate: no controls announced!"); + if (m_pYes->get_active()) + m_pList->grab_focus(); + else + m_pNo->grab_focus(); + } + + ODBFieldPage::ODBFieldPage(weld::Container* pPage, OControlWizard* pWizard) + : OMaybeListSelectionPage(pPage, pWizard, "modules/sabpilot/ui/optiondbfieldpage.ui", "OptionDBField") + , m_xDescription(m_xBuilder->weld_label("explLabel")) + , m_xStoreYes(m_xBuilder->weld_radio_button("yesRadiobutton")) + , m_xStoreNo(m_xBuilder->weld_radio_button("noRadiobutton")) + , m_xStoreWhere(m_xBuilder->weld_combo_box("storeInFieldCombobox")) + { + SetPageTitle(compmodule::ModuleRes(RID_STR_OPTION_DB_FIELD_TITLE)); + + announceControls(*m_xStoreYes, *m_xStoreNo, *m_xStoreWhere); + } + + ODBFieldPage::~ODBFieldPage() + { + } + + void ODBFieldPage::initializePage() + { + OMaybeListSelectionPage::initializePage(); + + // fill the fields page + fillListBox(*m_xStoreWhere, getContext().aFieldNames); + + implInitialize(getDBFieldSetting()); + } + + bool ODBFieldPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OMaybeListSelectionPage::commitPage(_eReason)) + return false; + + implCommit(getDBFieldSetting()); + + return true; + } + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/commonpagesdbp.hxx b/extensions/source/dbpilots/commonpagesdbp.hxx new file mode 100644 index 000000000..1ae742150 --- /dev/null +++ b/extensions/source/dbpilots/commonpagesdbp.hxx @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "controlwizard.hxx" +#include <vcl/weld.hxx> +#include <com/sun/star/sdb/XDatabaseContext.hpp> + +namespace dbp +{ + class OTableSelectionPage final : public OControlWizardPage + { + std::unique_ptr<weld::TreeView> m_xTable; + std::unique_ptr<weld::TreeView> m_xDatasource; + std::unique_ptr<weld::Label> m_xDatasourceLabel; + std::unique_ptr<weld::Button> m_xSearchDatabase; + std::unique_ptr<weld::Container> m_xSourceBox; + + css::uno::Reference< css::sdb::XDatabaseContext > + m_xDSContext; + + public: + explicit OTableSelectionPage(weld::Container* pPage, OControlWizard* pParent); + virtual ~OTableSelectionPage() override; + + private: + // BuilderPage overridables + void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + + DECL_LINK( OnListboxSelection, weld::TreeView&, void ); + DECL_LINK( OnListboxDoubleClicked, weld::TreeView&, bool ); + DECL_LINK( OnSearchClicked, weld::Button&, void ); + + void implFillTables(const css::uno::Reference< css::sdbc::XConnection >& + _rxConn = css::uno::Reference< css::sdbc::XConnection >()); + + // OControlWizardPage overridables + virtual bool canAdvance() const override; + }; + + class OMaybeListSelectionPage : public OControlWizardPage + { + weld::RadioButton* m_pYes; + weld::RadioButton* m_pNo; + weld::ComboBox* m_pList; + + public: + OMaybeListSelectionPage(weld::Container* pPage, OControlWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID); + virtual ~OMaybeListSelectionPage() override; + + protected: + DECL_LINK( OnRadioSelected, weld::Toggleable&, void ); + + // BuilderPage overridables + void Activate() override; + + // own helper + void announceControls( + weld::RadioButton& _rYesButton, + weld::RadioButton& _rNoButton, + weld::ComboBox& _rSelection); + + void implEnableWindows(); + + void implInitialize(const OUString& _rSelection); + void implCommit(OUString& _rSelection); + }; + + class ODBFieldPage : public OMaybeListSelectionPage + { + protected: + std::unique_ptr<weld::Label> m_xDescription; + std::unique_ptr<weld::RadioButton> m_xStoreYes; + std::unique_ptr<weld::RadioButton> m_xStoreNo; + std::unique_ptr<weld::ComboBox> m_xStoreWhere; + + public: + explicit ODBFieldPage(weld::Container* pPage, OControlWizard* pWizard); + virtual ~ODBFieldPage() override; + + protected: + void setDescriptionText(const OUString& rDesc) + { + m_xDescription->set_label(rDesc); + } + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + + // own overridables + virtual OUString& getDBFieldSetting() = 0; + }; + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/controlwizard.cxx b/extensions/source/dbpilots/controlwizard.cxx new file mode 100644 index 000000000..20052c4cb --- /dev/null +++ b/extensions/source/dbpilots/controlwizard.cxx @@ -0,0 +1,663 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "controlwizard.hxx" +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/sheet/XSpreadsheetView.hpp> +#include <com/sun/star/drawing/XDrawView.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/interaction.hxx> +#include <vcl/stdtext.hxx> +#include <connectivity/conncleanup.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <tools/urlobj.hxx> + +#define WIZARD_SIZE_X 60 +#define WIZARD_SIZE_Y 23 + +namespace dbp +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::sdbcx; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::drawing; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::sheet; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::task; + using namespace ::comphelper; + using namespace ::dbtools; + + struct OAccessRegulator + { + friend class OControlWizardPage; + + protected: + OAccessRegulator() { } + }; + + OControlWizardPage::OControlWizardPage(weld::Container* pPage, OControlWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID) + : OControlWizardPage_Base(pPage, pWizard, rUIXMLDescription, rID) + , m_pDialog(pWizard) + { + m_xContainer->set_size_request(m_xContainer->get_approximate_digit_width() * WIZARD_SIZE_X, + m_xContainer->get_text_height() * WIZARD_SIZE_Y); + } + + OControlWizardPage::~OControlWizardPage() + { + } + + OControlWizard* OControlWizardPage::getDialog() + { + return m_pDialog; + } + + const OControlWizard* OControlWizardPage::getDialog() const + { + return m_pDialog; + } + + bool OControlWizardPage::updateContext() + { + return m_pDialog->updateContext(OAccessRegulator()); + } + + Reference< XConnection > OControlWizardPage::getFormConnection() const + { + return m_pDialog->getFormConnection(OAccessRegulator()); + } + + void OControlWizardPage::setFormConnection( const Reference< XConnection >& _rxConn, bool _bAutoDispose ) + { + m_pDialog->setFormConnection( OAccessRegulator(), _rxConn, _bAutoDispose ); + } + + const OControlWizardContext& OControlWizardPage::getContext() const + { + return m_pDialog->getContext(); + } + + void OControlWizardPage::fillListBox(weld::TreeView& _rList, const Sequence< OUString >& _rItems) + { + _rList.clear(); + const OUString* pItems = _rItems.getConstArray(); + const OUString* pEnd = pItems + _rItems.getLength(); + sal_Int32 nIndex = 0; + for (;pItems < pEnd; ++pItems, ++nIndex) + { + _rList.append(OUString::number(nIndex), *pItems); + } + } + + void OControlWizardPage::fillListBox(weld::ComboBox& _rList, const Sequence< OUString >& _rItems) + { + _rList.clear(); + const OUString* pItems = _rItems.getConstArray(); + const OUString* pEnd = pItems + _rItems.getLength(); + for (;pItems < pEnd; ++pItems) + { + _rList.append_text(*pItems); + } + } + + void OControlWizardPage::enableFormDatasourceDisplay() + { + if (m_xFormContentType) + // nothing to do + return; + + m_xFrame = m_xBuilder->weld_frame("sourceframe"); + m_xFrame->show(); + m_xFormContentType = m_xBuilder->weld_label("contenttype"); + m_xFormContentTypeLabel = m_xBuilder->weld_label("contenttypelabel"); + m_xFormDatasource = m_xBuilder->weld_label("datasource"); + m_xFormDatasourceLabel = m_xBuilder->weld_label("datasourcelabel"); + m_xFormTable = m_xBuilder->weld_label("formtable"); + m_xFormTableLabel = m_xBuilder->weld_label("formtablelabel"); + + const OControlWizardContext& rContext = getContext(); + if ( rContext.bEmbedded ) + { + m_xFormDatasourceLabel->hide(); + m_xFormDatasource->hide(); + } + } + + void OControlWizardPage::initializePage() + { + if (m_xFormDatasource && m_xFormContentTypeLabel && m_xFormTable) + { + const OControlWizardContext& rContext = getContext(); + OUString sDataSource; + OUString sCommand; + sal_Int32 nCommandType = CommandType::COMMAND; + try + { + rContext.xForm->getPropertyValue("DataSourceName") >>= sDataSource; + rContext.xForm->getPropertyValue("Command") >>= sCommand; + rContext.xForm->getPropertyValue("CommandType") >>= nCommandType; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.dbpilots", "OControlWizardPage::initializePage"); + } + + INetURLObject aURL( sDataSource ); + if( aURL.GetProtocol() != INetProtocol::NotValid ) + sDataSource = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset); + m_xFormDatasource->set_label(sDataSource); + m_xFormTable->set_label(sCommand); + + TranslateId pCommandTypeResourceId; + switch (nCommandType) + { + case CommandType::TABLE: + pCommandTypeResourceId = RID_STR_TYPE_TABLE; + break; + + case CommandType::QUERY: + pCommandTypeResourceId = RID_STR_TYPE_QUERY; + break; + + default: + pCommandTypeResourceId = RID_STR_TYPE_COMMAND; + break; + } + m_xFormContentType->set_label(compmodule::ModuleRes(pCommandTypeResourceId)); + } + + OControlWizardPage_Base::initializePage(); + } + + OControlWizard::OControlWizard(weld::Window* _pParent, + const Reference< XPropertySet >& _rxObjectModel, const Reference< XComponentContext >& _rxContext ) + : WizardMachine(_pParent, WizardButtonFlags::CANCEL | WizardButtonFlags::PREVIOUS | WizardButtonFlags::NEXT | WizardButtonFlags::FINISH) + , m_xContext(_rxContext) + { + m_aContext.xObjectModel = _rxObjectModel; + initContext(); + + defaultButton(WizardButtonFlags::NEXT); + enableButtons(WizardButtonFlags::FINISH, false); + } + + OControlWizard::~OControlWizard() + { + } + + short OControlWizard::run() + { + // get the class id of the control we're dealing with + sal_Int16 nClassId = FormComponentType::CONTROL; + try + { + getContext().xObjectModel->getPropertyValue("ClassId") >>= nClassId; + } + catch(const Exception&) + { + OSL_FAIL("OControlWizard::activate: could not obtain the class id!"); + } + if (!approveControl(nClassId)) + { + // TODO: MessageBox or exception + return RET_CANCEL; + } + + ActivatePage(); + + m_xAssistant->set_current_page(0); + + return OControlWizard_Base::run(); + } + + void OControlWizard::implDetermineShape() + { + Reference< XIndexAccess > xPageObjects = m_aContext.xDrawPage; + DBG_ASSERT(xPageObjects.is(), "OControlWizard::implDetermineShape: invalid page!"); + + // for comparing the model + Reference< XControlModel > xModelCompare(m_aContext.xObjectModel, UNO_QUERY); + + if (!xPageObjects.is()) + return; + + // loop through all objects of the page + sal_Int32 nObjects = xPageObjects->getCount(); + Reference< XControlShape > xControlShape; + Reference< XControlModel > xControlModel; + for (sal_Int32 i=0; i<nObjects; ++i) + { + if (xPageObjects->getByIndex(i) >>= xControlShape) + { // it _is_ a control shape + xControlModel = xControlShape->getControl(); + DBG_ASSERT(xControlModel.is(), "OControlWizard::implDetermineShape: control shape without model!"); + if (xModelCompare.get() == xControlModel.get()) + { + m_aContext.xObjectShape = xControlShape; + break; + } + } + } + } + + + void OControlWizard::implDetermineForm() + { + Reference< XChild > xModelAsChild(m_aContext.xObjectModel, UNO_QUERY); + Reference< XInterface > xControlParent; + if (xModelAsChild.is()) + xControlParent = xModelAsChild->getParent(); + + m_aContext.xForm.set(xControlParent, UNO_QUERY); + m_aContext.xRowSet.set(xControlParent, UNO_QUERY); + DBG_ASSERT(m_aContext.xForm.is() && m_aContext.xRowSet.is(), + "OControlWizard::implDetermineForm: missing some interfaces of the control parent!"); + + } + + + void OControlWizard::implDeterminePage() + { + try + { + // get the document model + Reference< XChild > xControlAsChild(m_aContext.xObjectModel, UNO_QUERY); + Reference< XChild > xModelSearch(xControlAsChild->getParent(), UNO_QUERY); + + Reference< XModel > xModel(xModelSearch, UNO_QUERY); + while (xModelSearch.is() && !xModel.is()) + { + xModelSearch.set(xModelSearch->getParent(), UNO_QUERY); + xModel.set(xModelSearch, UNO_QUERY); + } + + Reference< XDrawPage > xPage; + if (xModel.is()) + { + m_aContext.xDocumentModel = xModel; + + Reference< XDrawPageSupplier > xPageSupp(xModel, UNO_QUERY); + if (xPageSupp.is()) + { // it's a document with only one page -> Writer + xPage = xPageSupp->getDrawPage(); + } + else + { + // get the controller currently working on this model + Reference< XController > xController = xModel->getCurrentController(); + DBG_ASSERT(xController.is(), "OControlWizard::implDeterminePage: no current controller!"); + + // maybe it's a spreadsheet + Reference< XSpreadsheetView > xView(xController, UNO_QUERY); + if (xView.is()) + { // okay, it is one + Reference< XSpreadsheet > xSheet = xView->getActiveSheet(); + xPageSupp.set(xSheet, UNO_QUERY); + DBG_ASSERT(xPageSupp.is(), "OControlWizard::implDeterminePage: a spreadsheet which is no page supplier!"); + if (xPageSupp.is()) + xPage = xPageSupp->getDrawPage(); + } + else + { // can be a draw/impress doc only + Reference< XDrawView > xDrawView(xController, UNO_QUERY); + DBG_ASSERT(xDrawView.is(), "OControlWizard::implDeterminePage: no alternatives left ... can't determine the page!"); + if (xDrawView.is()) + xPage = xDrawView->getCurrentPage(); + } + } + } + else + { + DBG_ASSERT(xPage.is(), "OControlWizard::implDeterminePage: can't determine the page (no model)!"); + } + m_aContext.xDrawPage = xPage; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.dbpilots", "OControlWizard::implDeterminePage"); + } + } + + + void OControlWizard::implGetDSContext() + { + try + { + DBG_ASSERT(m_xContext.is(), "OControlWizard::implGetDSContext: invalid service factory!"); + + m_aContext.xDatasourceContext = DatabaseContext::create(m_xContext); + } + catch(const Exception&) + { + OSL_FAIL("OControlWizard::implGetDSContext: invalid database context!"); + } + } + + + Reference< XConnection > OControlWizard::getFormConnection(const OAccessRegulator&) const + { + return getFormConnection(); + } + + Reference< XConnection > OControlWizard::getFormConnection() const + { + Reference< XConnection > xConn; + try + { + if ( !::dbtools::isEmbeddedInDatabase(m_aContext.xForm,xConn) ) + m_aContext.xForm->getPropertyValue("ActiveConnection") >>= xConn; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.dbpilots", "OControlWizard::getFormConnection"); + } + return xConn; + } + + + void OControlWizard::setFormConnection( const OAccessRegulator& _rAccess, const Reference< XConnection >& _rxConn, bool _bAutoDispose ) + { + try + { + Reference< XConnection > xOldConn = getFormConnection(_rAccess); + if (xOldConn.get() == _rxConn.get()) + return; + + disposeComponent(xOldConn); + + // set the new connection + if ( _bAutoDispose ) + { + // for this, use an AutoDisposer (so the conn is cleaned up when the form dies or gets another connection) + Reference< XRowSet > xFormRowSet( m_aContext.xForm, UNO_QUERY ); + new OAutoConnectionDisposer( xFormRowSet, _rxConn ); + } + else + { + m_aContext.xForm->setPropertyValue("ActiveConnection", Any( _rxConn ) ); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.dbpilots", "OControlWizard::setFormConnection"); + } + } + + + bool OControlWizard::updateContext(const OAccessRegulator&) + { + return initContext(); + } + + Reference< XInteractionHandler > OControlWizard::getInteractionHandler(weld::Window* _pWindow) const + { + Reference< XInteractionHandler > xHandler; + try + { + xHandler.set( InteractionHandler::createWithParent(m_xContext, nullptr), UNO_QUERY_THROW ); + } + catch(const Exception&) { } + if (!xHandler.is()) + { + ShowServiceNotAvailableError(_pWindow, u"com.sun.star.task.InteractionHandler", true); + } + return xHandler; + } + + bool OControlWizard::initContext() + { + DBG_ASSERT(m_aContext.xObjectModel.is(), "OGroupBoxWizard::initContext: have no control model to work with!"); + if (!m_aContext.xObjectModel.is()) + return false; + + // reset the context + m_aContext.xForm.clear(); + m_aContext.xRowSet.clear(); + m_aContext.xDocumentModel.clear(); + m_aContext.xDrawPage.clear(); + m_aContext.xObjectShape.clear(); + m_aContext.aFieldNames.realloc(0); + + m_aContext.xObjectContainer.clear(); + m_aContext.aTypes.clear(); + m_aContext.bEmbedded = false; + + Any aSQLException; + Reference< XPreparedStatement > xStatement; + try + { + // get the datasource context + implGetDSContext(); + + // first, determine the form the control belongs to + implDetermineForm(); + + // need the page, too + implDeterminePage(); + + // the shape of the control + implDetermineShape(); + + // get the columns of the object the settings refer to + Reference< XNameAccess > xColumns; + + if (m_aContext.xForm.is()) + { + // collect some properties of the form + OUString sObjectName = ::comphelper::getString(m_aContext.xForm->getPropertyValue("Command")); + sal_Int32 nObjectType = ::comphelper::getINT32(m_aContext.xForm->getPropertyValue("CommandType")); + + // calculate the connection the rowset is working with + Reference< XConnection > xConnection; + m_aContext.bEmbedded = ::dbtools::isEmbeddedInDatabase( m_aContext.xForm, xConnection ); + if ( !m_aContext.bEmbedded ) + xConnection = ::dbtools::connectRowset( m_aContext.xRowSet, m_xContext, nullptr ); + + // get the fields + if (xConnection.is()) + { + switch (nObjectType) + { + case 0: + { + Reference< XTablesSupplier > xSupplyTables(xConnection, UNO_QUERY); + if (xSupplyTables.is() && xSupplyTables->getTables().is() && xSupplyTables->getTables()->hasByName(sObjectName)) + { + Reference< XColumnsSupplier > xSupplyColumns; + m_aContext.xObjectContainer = xSupplyTables->getTables(); + m_aContext.xObjectContainer->getByName(sObjectName) >>= xSupplyColumns; + DBG_ASSERT(xSupplyColumns.is(), "OControlWizard::initContext: invalid table columns!"); + xColumns = xSupplyColumns->getColumns(); + } + } + break; + case 1: + { + Reference< XQueriesSupplier > xSupplyQueries(xConnection, UNO_QUERY); + if (xSupplyQueries.is() && xSupplyQueries->getQueries().is() && xSupplyQueries->getQueries()->hasByName(sObjectName)) + { + Reference< XColumnsSupplier > xSupplyColumns; + m_aContext.xObjectContainer = xSupplyQueries->getQueries(); + m_aContext.xObjectContainer->getByName(sObjectName) >>= xSupplyColumns; + DBG_ASSERT(xSupplyColumns.is(), "OControlWizard::initContext: invalid query columns!"); + xColumns = xSupplyColumns->getColumns(); + } + } + break; + default: + { + xStatement = xConnection->prepareStatement(sObjectName); + + // not interested in any results, only in the fields + Reference< XPropertySet > xStatementProps(xStatement, UNO_QUERY); + xStatementProps->setPropertyValue("MaxRows", Any(sal_Int32(0))); + + // TODO: think about handling local SQLExceptions here ... + Reference< XColumnsSupplier > xSupplyCols(xStatement->executeQuery(), UNO_QUERY); + if (xSupplyCols.is()) + xColumns = xSupplyCols->getColumns(); + } + } + } + } + + if (xColumns.is()) + { + m_aContext.aFieldNames = xColumns->getElementNames(); + const OUString* pBegin = m_aContext.aFieldNames.getConstArray(); + const OUString* pEnd = pBegin + m_aContext.aFieldNames.getLength(); + for(;pBegin != pEnd;++pBegin) + { + sal_Int32 nFieldType = DataType::OTHER; + try + { + Reference< XPropertySet > xColumn; + xColumns->getByName(*pBegin) >>= xColumn; + xColumn->getPropertyValue("Type") >>= nFieldType; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( + "extensions.dbpilots", + "unexpected exception while gathering column information!"); + } + m_aContext.aTypes.emplace(*pBegin,nFieldType); + } + } + } + catch(const SQLContext& e) { aSQLException <<= e; } + catch(const SQLWarning& e) { aSQLException <<= e; } + catch(const SQLException& e) { aSQLException <<= e; } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.dbpilots", "OControlWizard::initContext: could not retrieve the control context"); + } + + ::comphelper::disposeComponent(xStatement); + + if (aSQLException.hasValue()) + { // an SQLException (or derivee) was thrown ... + + // prepend an extra SQLContext explaining what we were doing + SQLContext aContext; + aContext.Message = compmodule::ModuleRes(RID_STR_COULDNOTOPENTABLE); + aContext.NextException = aSQLException; + + // create an interaction handler to display this exception + Reference< XInteractionHandler > xHandler = getInteractionHandler(m_xAssistant.get()); + if ( !xHandler.is() ) + return false; + + Reference< XInteractionRequest > xRequest = new OInteractionRequest(Any(aContext)); + try + { + xHandler->handle(xRequest); + } + catch(const Exception&) { } + return false; + } + + return m_aContext.aFieldNames.hasElements(); + } + + + void OControlWizard::commitControlSettings(OControlWizardSettings const * _pSettings) + { + DBG_ASSERT(m_aContext.xObjectModel.is(), "OControlWizard::commitControlSettings: have no control model to work with!"); + if (!m_aContext.xObjectModel.is()) + return; + + // the only thing we have at the moment is the label + try + { + Reference< XPropertySetInfo > xInfo = m_aContext.xObjectModel->getPropertySetInfo(); + if (xInfo.is() && xInfo->hasPropertyByName("Label")) + { + OUString sControlLabel(_pSettings->sControlLabel); + m_aContext.xObjectModel->setPropertyValue( + "Label", + Any(sControlLabel) + ); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.dbpilots", "OControlWizard::commitControlSettings: could not commit the basic control settings!"); + } + } + + + void OControlWizard::initControlSettings(OControlWizardSettings* _pSettings) + { + DBG_ASSERT(m_aContext.xObjectModel.is(), "OControlWizard::initControlSettings: have no control model to work with!"); + if (!m_aContext.xObjectModel.is()) + return; + + // initialize some settings from the control model give + try + { + OUString sLabelPropertyName("Label"); + Reference< XPropertySetInfo > xInfo = m_aContext.xObjectModel->getPropertySetInfo(); + if (xInfo.is() && xInfo->hasPropertyByName(sLabelPropertyName)) + { + OUString sControlLabel; + m_aContext.xObjectModel->getPropertyValue(sLabelPropertyName) >>= sControlLabel; + _pSettings->sControlLabel = sControlLabel; + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.dbpilots", "OControlWizard::initControlSettings: could not retrieve the basic control settings!"); + } + } + + + bool OControlWizard::needDatasourceSelection() + { + // lemme see ... + return !getContext().aFieldNames.hasElements(); + // if we got fields, the data source is valid ... + } + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/controlwizard.hxx b/extensions/source/dbpilots/controlwizard.hxx new file mode 100644 index 000000000..cf55c655e --- /dev/null +++ b/extensions/source/dbpilots/controlwizard.hxx @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/form/FormComponentType.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <vcl/weld.hxx> +#include <vcl/wizardmachine.hxx> +#include "dbptypes.hxx" +#include <strings.hrc> +#include <componentmodule.hxx> +#include "wizardcontext.hxx" + +class ResId; + +namespace dbp +{ + struct OControlWizardSettings + { + OUString sControlLabel; + }; + + class OControlWizard; + typedef ::vcl::OWizardPage OControlWizardPage_Base; + class OControlWizardPage : public OControlWizardPage_Base + { + OControlWizard* m_pDialog; + std::unique_ptr<weld::Label> m_xFormDatasourceLabel; + std::unique_ptr<weld::Label> m_xFormDatasource; + std::unique_ptr<weld::Label> m_xFormContentTypeLabel; + std::unique_ptr<weld::Label> m_xFormContentType; + std::unique_ptr<weld::Label> m_xFormTableLabel; + std::unique_ptr<weld::Label> m_xFormTable; + std::unique_ptr<weld::Frame> m_xFrame; + + protected: + OControlWizard* getDialog(); + const OControlWizard* getDialog() const; + const OControlWizardContext& getContext() const; + bool updateContext(); + void setFormConnection(const css::uno::Reference< css::sdbc::XConnection >& _rxConn, bool _bAutoDispose = true ); + css::uno::Reference< css::sdbc::XConnection > + getFormConnection() const; + public: + OControlWizardPage(weld::Container* pPage, OControlWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID); + virtual ~OControlWizardPage() override; + + protected: + static void fillListBox( + weld::TreeView& _rList, + const css::uno::Sequence< OUString >& _rItems); + static void fillListBox( + weld::ComboBox& _rList, + const css::uno::Sequence< OUString >& _rItems); + + protected: + void enableFormDatasourceDisplay(); + + protected: + // OWizardPage overridables + virtual void initializePage() override; + }; + + struct OAccessRegulator; + + typedef ::vcl::WizardMachine OControlWizard_Base; + class OControlWizard : public OControlWizard_Base + { + private: + OControlWizardContext m_aContext; + css::uno::Reference< css::uno::XComponentContext > + m_xContext; + + public: + OControlWizard( + weld::Window* _pParent, + const css::uno::Reference< css::beans::XPropertySet >& _rxObjectModel, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + virtual ~OControlWizard() override; + + // make the same base class methods public + using OControlWizard_Base::travelNext; + + public: + const css::uno::Reference< css::uno::XComponentContext >& + getComponentContext() const { return m_xContext; } + + const OControlWizardContext& getContext() const { return m_aContext; } + bool updateContext(const OAccessRegulator&); + void setFormConnection(const OAccessRegulator&, const css::uno::Reference< css::sdbc::XConnection >& _rxConn, bool _bAutoDispose ); + css::uno::Reference< css::sdbc::XConnection > + getFormConnection(const OAccessRegulator&) const; + + /** returns the com.sun.star.task.InteractionHandler + @param _pWindow The window will be used when an error message has to be shown. + */ + css::uno::Reference< css::task::XInteractionHandler > getInteractionHandler(weld::Window* _pWindow) const; + + protected: + // initialize the derivees settings (which have to be derived from OControlWizardSettings) + // with some common data extracted from the control model + void initControlSettings(OControlWizardSettings* _pSettings); + // commit the control-relevant settings + void commitControlSettings(OControlWizardSettings const * _pSettings); + + bool needDatasourceSelection(); + + css::uno::Reference< css::sdbc::XConnection > + getFormConnection() const; + + virtual bool approveControl(sal_Int16 _nClassId) = 0; + + virtual short run() override; + + private: + bool initContext(); + + void implGetDSContext(); + void implDetermineForm(); + void implDeterminePage(); + void implDetermineShape(); + }; + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/dbp.component b/extensions/source/dbpilots/dbp.component new file mode 100644 index 000000000..5cff1fb3c --- /dev/null +++ b/extensions/source/dbpilots/dbp.component @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="org.openoffice.comp.dbp.OGridWizard" + constructor="extensions_dbp_OGridWizard_get_implementation"> + <service name="com.sun.star.sdb.GridControlAutoPilot"/> + </implementation> + <implementation name="org.openoffice.comp.dbp.OGroupBoxWizard" + constructor="extensions_dbp_OGroupBoxWizard_get_implementation"> + <service name="com.sun.star.sdb.GroupBoxAutoPilot"/> + </implementation> + <implementation name="org.openoffice.comp.dbp.OListComboWizard" + constructor="extensions_dbp_OListComboWizard_get_implementation"> + <service name="com.sun.star.sdb.ListComboBoxAutoPilot"/> + </implementation> +</component> diff --git a/extensions/source/dbpilots/dbptools.cxx b/extensions/source/dbpilots/dbptools.cxx new file mode 100644 index 000000000..1b647e84c --- /dev/null +++ b/extensions/source/dbpilots/dbptools.cxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "dbptools.hxx" +#include <tools/debug.hxx> +#include <osl/diagnose.h> + + +namespace dbp +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::container; + + + void disambiguateName(const Reference< XNameAccess >& _rxContainer, OUString& _rElementsName) + { + DBG_ASSERT(_rxContainer.is(), "::dbp::disambiguateName: invalid container!"); + if (!_rxContainer.is()) + return; + + try + { + OUString sBase(_rElementsName); + for (sal_Int32 i=1; i<0x7FFFFFFF; ++i) + { + _rElementsName = sBase; + _rElementsName += OUString::number(i); + if (!_rxContainer->hasByName(_rElementsName)) + return; + } + // can't do anything ... no free names + _rElementsName = sBase; + } + catch(const Exception&) + { + OSL_FAIL("::dbp::disambiguateName: something went (strangely) wrong!"); + } + } + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/dbptools.hxx b/extensions/source/dbpilots/dbptools.hxx new file mode 100644 index 000000000..d7577f187 --- /dev/null +++ b/extensions/source/dbpilots/dbptools.hxx @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/container/XNameAccess.hpp> + + +namespace dbp +{ + + + void disambiguateName( + const css::uno::Reference< css::container::XNameAccess >& _rxContainer, + OUString& _rElementsName); + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/dbptypes.hxx b/extensions/source/dbpilots/dbptypes.hxx new file mode 100644 index 000000000..8b86fe506 --- /dev/null +++ b/extensions/source/dbpilots/dbptypes.hxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <rtl/ustring.hxx> + +#include <map> +#include <set> + +namespace dbp +{ +typedef std::set<OUString> StringBag; +typedef std::map<sal_uInt32, OUString> MapInt2String; + +} // namespace dbp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/gridwizard.cxx b/extensions/source/dbpilots/gridwizard.cxx new file mode 100644 index 000000000..3cf1d0324 --- /dev/null +++ b/extensions/source/dbpilots/gridwizard.cxx @@ -0,0 +1,446 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <vector> + +#include "gridwizard.hxx" +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/form/XGridColumnFactory.hpp> +#include <com/sun/star/awt/MouseWheelBehavior.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <sal/log.hxx> +#include <tools/debug.hxx> +#include "dbptools.hxx" +#include <helpids.h> + +#define GW_STATE_DATASOURCE_SELECTION 0 +#define GW_STATE_FIELDSELECTION 1 + + +namespace dbp +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::awt; + + OGridWizard::OGridWizard(weld::Window* _pParent, + const Reference< XPropertySet >& _rxObjectModel, const Reference< XComponentContext >& _rxContext ) + : OControlWizard(_pParent, _rxObjectModel, _rxContext) + , m_bHadDataSelection(true) + { + initControlSettings(&m_aSettings); + + m_xPrevPage->set_help_id(HID_GRIDWIZARD_PREVIOUS); + m_xNextPage->set_help_id(HID_GRIDWIZARD_NEXT); + m_xCancel->set_help_id(HID_GRIDWIZARD_CANCEL); + m_xFinish->set_help_id(HID_GRIDWIZARD_FINISH); + setTitleBase(compmodule::ModuleRes(RID_STR_GRIDWIZARD_TITLE)); + + // if we do not need the data source selection page ... + if (!needDatasourceSelection()) + { // ... skip it! + skip(); + m_bHadDataSelection = false; + } + } + + bool OGridWizard::approveControl(sal_Int16 _nClassId) + { + if (FormComponentType::GRIDCONTROL != _nClassId) + return false; + + Reference< XGridColumnFactory > xColumnFactory(getContext().xObjectModel, UNO_QUERY); + return xColumnFactory.is(); + } + + void OGridWizard::implApplySettings() + { + const OControlWizardContext& rContext = getContext(); + + // the factory for the columns + Reference< XGridColumnFactory > xColumnFactory(rContext.xObjectModel, UNO_QUERY); + DBG_ASSERT(xColumnFactory.is(), "OGridWizard::implApplySettings: should never have made it 'til here!"); + // (if we're here, what the hell happened in approveControl??) + + // the container for the columns + Reference< XNameContainer > xColumnContainer(rContext.xObjectModel, UNO_QUERY); + DBG_ASSERT(xColumnContainer.is(), "OGridWizard::implApplySettings: no container!"); + + if (!xColumnFactory.is() || !xColumnContainer.is()) + return; + + static constexpr OUStringLiteral s_sMouseWheelBehavior = u"MouseWheelBehavior"; + static constexpr OUStringLiteral s_sEmptyString = u""; + + // collect "descriptors" for the to-be-created (grid)columns + std::vector< OUString > aColumnServiceNames; // service names to be used with the XGridColumnFactory + std::vector< OUString > aColumnLabelPostfixes; // postfixes to append to the column labels + std::vector< OUString > aFormFieldNames; // data field names + + aColumnServiceNames.reserve(getSettings().aSelectedFields.getLength()); + aColumnLabelPostfixes.reserve(getSettings().aSelectedFields.getLength()); + aFormFieldNames.reserve(getSettings().aSelectedFields.getLength()); + + // loop through the selected field names + const OUString* pSelectedFields = getSettings().aSelectedFields.getConstArray(); + const OUString* pEnd = pSelectedFields + getSettings().aSelectedFields.getLength(); + for (;pSelectedFields < pEnd; ++pSelectedFields) + { + // get the information for the selected column + sal_Int32 nFieldType = DataType::OTHER; + OControlWizardContext::TNameTypeMap::const_iterator aFind = rContext.aTypes.find(*pSelectedFields); + if ( aFind != rContext.aTypes.end() ) + nFieldType = aFind->second; + + aFormFieldNames.push_back(*pSelectedFields); + switch (nFieldType) + { + case DataType::BIT: + case DataType::BOOLEAN: + aColumnServiceNames.push_back(OUString("CheckBox")); + aColumnLabelPostfixes.push_back(s_sEmptyString); + break; + + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + aColumnServiceNames.push_back(OUString("NumericField")); + aColumnLabelPostfixes.push_back(s_sEmptyString); + break; + + case DataType::FLOAT: + case DataType::REAL: + case DataType::DOUBLE: + case DataType::NUMERIC: + case DataType::DECIMAL: + aColumnServiceNames.push_back(OUString("FormattedField")); + aColumnLabelPostfixes.push_back(s_sEmptyString); + break; + + case DataType::DATE: + aColumnServiceNames.push_back(OUString("DateField")); + aColumnLabelPostfixes.push_back(s_sEmptyString); + break; + + case DataType::TIME: + aColumnServiceNames.push_back(OUString("TimeField")); + aColumnLabelPostfixes.push_back(s_sEmptyString); + break; + + case DataType::TIMESTAMP: + aColumnServiceNames.push_back(OUString("DateField")); + aColumnLabelPostfixes.push_back(compmodule::ModuleRes(RID_STR_DATEPOSTFIX)); + + aFormFieldNames.push_back(*pSelectedFields); + aColumnServiceNames.push_back(OUString("TimeField")); + aColumnLabelPostfixes.push_back(compmodule::ModuleRes(RID_STR_TIMEPOSTFIX)); + break; + + default: + aColumnServiceNames.push_back(OUString("TextField")); + aColumnLabelPostfixes.push_back(s_sEmptyString); + } + } + + DBG_ASSERT( aFormFieldNames.size() == aColumnServiceNames.size() + && aColumnServiceNames.size() == aColumnLabelPostfixes.size(), + "OGridWizard::implApplySettings: inconsistent descriptor sequences!"); + + // now loop through the descriptions and create the (grid)columns out of th descriptors + { + Reference< XNameAccess > xExistenceChecker(xColumnContainer); + + std::vector< OUString >::const_iterator pColumnLabelPostfix = aColumnLabelPostfixes.begin(); + std::vector< OUString >::const_iterator pFormFieldName = aFormFieldNames.begin(); + + for (const auto& rColumnServiceName : aColumnServiceNames) + { + // create a (grid)column for the (resultset)column + try + { + Reference< XPropertySet > xColumn( xColumnFactory->createColumn(rColumnServiceName), UNO_SET_THROW ); + Reference< XPropertySetInfo > xColumnPSI( xColumn->getPropertySetInfo(), UNO_SET_THROW ); + + OUString sColumnName(rColumnServiceName); + disambiguateName(xExistenceChecker, sColumnName); + + // the data field the column should be bound to + xColumn->setPropertyValue("DataField", Any(*pFormFieldName)); + // the label + xColumn->setPropertyValue("Label", Any(*pFormFieldName + *pColumnLabelPostfix)); + // the width (<void/> => column will be auto-sized) + xColumn->setPropertyValue("Width", Any()); + + if ( xColumnPSI->hasPropertyByName( s_sMouseWheelBehavior ) ) + xColumn->setPropertyValue( s_sMouseWheelBehavior, Any( MouseWheelBehavior::SCROLL_DISABLED ) ); + + // insert the column + xColumnContainer->insertByName(sColumnName, Any(xColumn)); + } + catch(const Exception&) + { + SAL_WARN( "extensions.dbpilots", "OGridWizard::implApplySettings: " + "unexpected exception while creating the grid column for field " << + *pFormFieldName ); + } + + ++pColumnLabelPostfix; + ++pFormFieldName; + } + } + } + + std::unique_ptr<BuilderPage> OGridWizard::createPage(WizardState _nState) + { + OString sIdent(OString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + switch (_nState) + { + case GW_STATE_DATASOURCE_SELECTION: + return std::make_unique<OTableSelectionPage>(pPageContainer, this); + case GW_STATE_FIELDSELECTION: + return std::make_unique<OGridFieldsSelection>(pPageContainer, this); + } + + return nullptr; + } + + vcl::WizardTypes::WizardState OGridWizard::determineNextState( WizardState _nCurrentState ) const + { + switch (_nCurrentState) + { + case GW_STATE_DATASOURCE_SELECTION: + return GW_STATE_FIELDSELECTION; + case GW_STATE_FIELDSELECTION: + return WZS_INVALID_STATE; + } + + return WZS_INVALID_STATE; + } + + void OGridWizard::enterState(WizardState _nState) + { + OControlWizard::enterState(_nState); + + enableButtons(WizardButtonFlags::PREVIOUS, m_bHadDataSelection ? (GW_STATE_DATASOURCE_SELECTION < _nState) : GW_STATE_FIELDSELECTION < _nState); + enableButtons(WizardButtonFlags::NEXT, GW_STATE_FIELDSELECTION != _nState); + if (_nState < GW_STATE_FIELDSELECTION) + enableButtons(WizardButtonFlags::FINISH, false); + + if (GW_STATE_FIELDSELECTION == _nState) + defaultButton(WizardButtonFlags::FINISH); + } + + + bool OGridWizard::leaveState(WizardState _nState) + { + if (!OControlWizard::leaveState(_nState)) + return false; + + if (GW_STATE_FIELDSELECTION == _nState) + defaultButton(WizardButtonFlags::NEXT); + + return true; + } + + + bool OGridWizard::onFinish() + { + if ( !OControlWizard::onFinish() ) + return false; + + implApplySettings(); + + return true; + } + + OGridFieldsSelection::OGridFieldsSelection(weld::Container* pPage, OGridWizard* pWizard) + : OGridPage(pPage, pWizard, "modules/sabpilot/ui/gridfieldsselectionpage.ui", "GridFieldsSelection") + , m_xExistFields(m_xBuilder->weld_tree_view("existingfields")) + , m_xSelectOne(m_xBuilder->weld_button("fieldright")) + , m_xSelectAll(m_xBuilder->weld_button("allfieldsright")) + , m_xDeselectOne(m_xBuilder->weld_button("fieldleft")) + , m_xDeselectAll(m_xBuilder->weld_button("allfieldsleft")) + , m_xSelFields(m_xBuilder->weld_tree_view("selectedfields")) + { + enableFormDatasourceDisplay(); + + m_xSelectOne->connect_clicked(LINK(this, OGridFieldsSelection, OnMoveOneEntry)); + m_xSelectAll->connect_clicked(LINK(this, OGridFieldsSelection, OnMoveAllEntries)); + m_xDeselectOne->connect_clicked(LINK(this, OGridFieldsSelection, OnMoveOneEntry)); + m_xDeselectAll->connect_clicked(LINK(this, OGridFieldsSelection, OnMoveAllEntries)); + + m_xExistFields->connect_changed(LINK(this, OGridFieldsSelection, OnEntrySelected)); + m_xSelFields->connect_changed(LINK(this, OGridFieldsSelection, OnEntrySelected)); + m_xExistFields->connect_row_activated(LINK(this, OGridFieldsSelection, OnEntryDoubleClicked)); + m_xSelFields->connect_row_activated(LINK(this, OGridFieldsSelection, OnEntryDoubleClicked)); + } + + OGridFieldsSelection::~OGridFieldsSelection() + { + } + + void OGridFieldsSelection::Activate() + { + OGridPage::Activate(); + m_xExistFields->grab_focus(); + } + + bool OGridFieldsSelection::canAdvance() const + { + return false; + // we're the last page in our wizard + } + + void OGridFieldsSelection::initializePage() + { + OGridPage::initializePage(); + + const OControlWizardContext& rContext = getContext(); + fillListBox(*m_xExistFields, rContext.aFieldNames); + + m_xSelFields->clear(); + const OGridSettings& rSettings = getSettings(); + const OUString* pSelected = rSettings.aSelectedFields.getConstArray(); + const OUString* pEnd = pSelected + rSettings.aSelectedFields.getLength(); + for (; pSelected < pEnd; ++pSelected) + { + m_xSelFields->append_text(*pSelected); + m_xExistFields->remove_text(*pSelected); + } + + implCheckButtons(); + } + + bool OGridFieldsSelection::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OGridPage::commitPage(_eReason)) + return false; + + OGridSettings& rSettings = getSettings(); + const sal_Int32 nSelected = m_xSelFields->n_children(); + + rSettings.aSelectedFields.realloc(nSelected); + OUString* pSelected = rSettings.aSelectedFields.getArray(); + + for (sal_Int32 i=0; i<nSelected; ++i, ++pSelected) + *pSelected = m_xSelFields->get_text(i); + + return true; + } + + void OGridFieldsSelection::implCheckButtons() + { + m_xSelectOne->set_sensitive(m_xExistFields->count_selected_rows() != 0); + m_xSelectAll->set_sensitive(m_xExistFields->n_children() != 0); + + m_xDeselectOne->set_sensitive(m_xSelFields->count_selected_rows() != 0); + m_xDeselectAll->set_sensitive(m_xSelFields->n_children() != 0); + + getDialog()->enableButtons(WizardButtonFlags::FINISH, 0 != m_xSelFields->n_children()); + } + + IMPL_LINK(OGridFieldsSelection, OnEntryDoubleClicked, weld::TreeView&, rList, bool) + { + weld::Button* pSimulateButton = m_xExistFields.get() == &rList ? m_xSelectOne.get() : m_xDeselectOne.get(); + if (pSimulateButton->get_sensitive()) + OnMoveOneEntry(*pSimulateButton); + return true; + } + + IMPL_LINK_NOARG(OGridFieldsSelection, OnEntrySelected, weld::TreeView&, void) + { + implCheckButtons(); + } + + IMPL_LINK(OGridFieldsSelection, OnMoveOneEntry, weld::Button&, rButton, void) + { + bool bMoveRight = (m_xSelectOne.get() == &rButton); + weld::TreeView& rMoveTo = bMoveRight ? *m_xSelFields : *m_xExistFields; + + // the index of the selected entry + const sal_Int32 nSelected = bMoveRight ? m_xExistFields->get_selected_index() : m_xSelFields->get_selected_index(); + // the (original) relative position of the entry + int nRelativeIndex = bMoveRight ? m_xExistFields->get_id(nSelected).toInt32() : m_xSelFields->get_id(nSelected).toInt32(); + + sal_Int32 nInsertPos = -1; + if (!bMoveRight) + { // need to determine an insert pos which reflects the original + nInsertPos = 0; + while (nInsertPos < rMoveTo.n_children()) + { + if (rMoveTo.get_id(nInsertPos).toInt32() > nRelativeIndex) + break; + ++nInsertPos; + } + } + + // the text of the entry to move + OUString sMovingEntry = bMoveRight ? m_xExistFields->get_text(nSelected) : m_xSelFields->get_text(nSelected); + + // insert the entry preserving it's "relative position" entry data + OUString sId(OUString::number(nRelativeIndex)); + rMoveTo.insert(nullptr, nInsertPos, &sMovingEntry, &sId, nullptr, nullptr, false, nullptr); + + // remove the entry from its old list + if (bMoveRight) + { + sal_Int32 nSelectPos = m_xExistFields->get_selected_index(); + m_xExistFields->remove(nSelected); + if ((nSelectPos != -1) && (nSelectPos < m_xExistFields->n_children())) + m_xExistFields->select(nSelectPos); + + m_xExistFields->grab_focus(); + } + else + { + sal_Int32 nSelectPos = m_xSelFields->get_selected_index(); + m_xSelFields->remove(nSelected); + if ((nSelectPos != -1) && (nSelectPos < m_xSelFields->n_children())) + m_xSelFields->select(nSelectPos); + + m_xSelFields->grab_focus(); + } + + implCheckButtons(); + } + + IMPL_LINK(OGridFieldsSelection, OnMoveAllEntries, weld::Button&, rButton, void) + { + bool bMoveRight = (m_xSelectAll.get() == &rButton); + m_xExistFields->clear(); + m_xSelFields->clear(); + fillListBox(bMoveRight ? *m_xSelFields : *m_xExistFields, getContext().aFieldNames); + + implCheckButtons(); + } + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/gridwizard.hxx b/extensions/source/dbpilots/gridwizard.hxx new file mode 100644 index 000000000..774e6cd69 --- /dev/null +++ b/extensions/source/dbpilots/gridwizard.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "controlwizard.hxx" +#include "commonpagesdbp.hxx" + +using vcl::WizardTypes::WizardState; +using vcl::WizardTypes::CommitPageReason; + +namespace dbp +{ + struct OGridSettings : public OControlWizardSettings + { + css::uno::Sequence< OUString > aSelectedFields; + }; + + class OGridWizard final : public OControlWizard + { + OGridSettings m_aSettings; + bool m_bHadDataSelection : 1; + + public: + OGridWizard(weld::Window* _pParent, + const css::uno::Reference< css::beans::XPropertySet >& _rxObjectModel, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + + OGridSettings& getSettings() { return m_aSettings; } + + private: + // OWizardMachine overridables + virtual std::unique_ptr<BuilderPage> createPage( WizardState _nState ) override; + virtual WizardState determineNextState( WizardState _nCurrentState ) const override; + virtual void enterState( WizardState _nState ) override; + virtual bool leaveState( WizardState _nState ) override; + virtual bool onFinish() override; + + virtual bool approveControl(sal_Int16 _nClassId) override; + + void implApplySettings(); + }; + + class OGridPage : public OControlWizardPage + { + public: + OGridPage(weld::Container* pPage, OGridWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID) + : OControlWizardPage(pPage, pWizard, rUIXMLDescription, rID) + { + } + protected: + OGridSettings& getSettings() { return static_cast<OGridWizard*>(getDialog())->getSettings(); } + }; + + class OGridFieldsSelection final : public OGridPage + { + std::unique_ptr<weld::TreeView> m_xExistFields; + std::unique_ptr<weld::Button> m_xSelectOne; + std::unique_ptr<weld::Button> m_xSelectAll; + std::unique_ptr<weld::Button> m_xDeselectOne; + std::unique_ptr<weld::Button> m_xDeselectAll; + std::unique_ptr<weld::TreeView> m_xSelFields; + + public: + explicit OGridFieldsSelection(weld::Container* pPage, OGridWizard* pWizard); + virtual ~OGridFieldsSelection() override; + + private: + // BuilderPage overridables + virtual void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + + DECL_LINK(OnMoveOneEntry, weld::Button&, void); + DECL_LINK(OnMoveAllEntries, weld::Button&, void); + DECL_LINK(OnEntrySelected, weld::TreeView&, void); + DECL_LINK(OnEntryDoubleClicked, weld::TreeView&, bool); + + void implCheckButtons(); + }; +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/groupboxwiz.cxx b/extensions/source/dbpilots/groupboxwiz.cxx new file mode 100644 index 000000000..a093d9154 --- /dev/null +++ b/extensions/source/dbpilots/groupboxwiz.cxx @@ -0,0 +1,468 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "groupboxwiz.hxx" +#include "commonpagesdbp.hxx" +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include "optiongrouplayouter.hxx" +#include <helpids.h> +#include <o3tl/safeint.hxx> + +#define GBW_STATE_OPTIONLIST 0 +#define GBW_STATE_DEFAULTOPTION 1 +#define GBW_STATE_OPTIONVALUES 2 +#define GBW_STATE_DBFIELD 3 +#define GBW_STATE_FINALIZE 4 + +namespace dbp +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::form; + + OGroupBoxWizard::OGroupBoxWizard(weld::Window* _pParent, + const Reference< XPropertySet >& _rxObjectModel, const Reference< XComponentContext >& _rxContext ) + : OControlWizard(_pParent, _rxObjectModel, _rxContext) + , m_bVisitedDefault(false) + , m_bVisitedDB(false) + { + initControlSettings(&m_aSettings); + + m_xPrevPage->set_help_id(HID_GROUPWIZARD_PREVIOUS); + m_xNextPage->set_help_id(HID_GROUPWIZARD_NEXT); + m_xCancel->set_help_id(HID_GROUPWIZARD_CANCEL); + m_xFinish->set_help_id(HID_GROUPWIZARD_FINISH); + setTitleBase(compmodule::ModuleRes(RID_STR_GROUPWIZARD_TITLE)); + } + + bool OGroupBoxWizard::approveControl(sal_Int16 _nClassId) + { + return FormComponentType::GROUPBOX == _nClassId; + } + + std::unique_ptr<BuilderPage> OGroupBoxWizard::createPage(::vcl::WizardTypes::WizardState _nState) + { + OString sIdent(OString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + switch (_nState) + { + case GBW_STATE_OPTIONLIST: + return std::make_unique<ORadioSelectionPage>(pPageContainer, this); + + case GBW_STATE_DEFAULTOPTION: + return std::make_unique<ODefaultFieldSelectionPage>(pPageContainer, this); + + case GBW_STATE_OPTIONVALUES: + return std::make_unique<OOptionValuesPage>(pPageContainer, this); + + case GBW_STATE_DBFIELD: + return std::make_unique<OOptionDBFieldPage>(pPageContainer, this); + + case GBW_STATE_FINALIZE: + return std::make_unique<OFinalizeGBWPage>(pPageContainer, this); + } + + return nullptr; + } + + vcl::WizardTypes::WizardState OGroupBoxWizard::determineNextState( ::vcl::WizardTypes::WizardState _nCurrentState ) const + { + switch (_nCurrentState) + { + case GBW_STATE_OPTIONLIST: + return GBW_STATE_DEFAULTOPTION; + + case GBW_STATE_DEFAULTOPTION: + return GBW_STATE_OPTIONVALUES; + + case GBW_STATE_OPTIONVALUES: + if (getContext().aFieldNames.hasElements()) + return GBW_STATE_DBFIELD; + else + return GBW_STATE_FINALIZE; + + case GBW_STATE_DBFIELD: + return GBW_STATE_FINALIZE; + } + + return WZS_INVALID_STATE; + } + + void OGroupBoxWizard::enterState(::vcl::WizardTypes::WizardState _nState) + { + // some stuff to do before calling the base class (modifying our settings) + switch (_nState) + { + case GBW_STATE_DEFAULTOPTION: + if (!m_bVisitedDefault) + { // assume that the first of the radio buttons should be selected + DBG_ASSERT(m_aSettings.aLabels.size(), "OGroupBoxWizard::enterState: should never have reached this state!"); + m_aSettings.sDefaultField = m_aSettings.aLabels[0]; + } + m_bVisitedDefault = true; + break; + + case GBW_STATE_DBFIELD: + if (!m_bVisitedDB) + { // try to generate a default for the DB field + // (simply use the first field in the DB names collection) + if (getContext().aFieldNames.hasElements()) + m_aSettings.sDBField = getContext().aFieldNames[0]; + } + m_bVisitedDB = true; + break; + } + + // setting the def button... to be done before the base class is called, too, 'cause the base class + // calls the pages, which are allowed to override our def button behaviour + defaultButton(GBW_STATE_FINALIZE == _nState ? WizardButtonFlags::FINISH : WizardButtonFlags::NEXT); + + // allow "finish" on the last page only + enableButtons(WizardButtonFlags::FINISH, GBW_STATE_FINALIZE == _nState); + // allow previous on all pages but the first one + enableButtons(WizardButtonFlags::PREVIOUS, GBW_STATE_OPTIONLIST != _nState); + // allow next on all pages but the last one + enableButtons(WizardButtonFlags::NEXT, GBW_STATE_FINALIZE != _nState); + + OControlWizard::enterState(_nState); + } + + bool OGroupBoxWizard::onFinish() + { + // commit the basic control settings + commitControlSettings(&m_aSettings); + + // create the radio buttons + try + { + OOptionGroupLayouter aLayouter( getComponentContext() ); + aLayouter.doLayout(getContext(), getSettings()); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.dbpilots", + "caught an exception while creating the radio shapes!"); + } + + return OControlWizard::onFinish(); + } + + ORadioSelectionPage::ORadioSelectionPage(weld::Container* pPage, OControlWizard* pWizard) + : OGBWPage(pPage, pWizard, "modules/sabpilot/ui/groupradioselectionpage.ui", "GroupRadioSelectionPage") + , m_xRadioName(m_xBuilder->weld_entry("radiolabels")) + , m_xMoveRight(m_xBuilder->weld_button("toright")) + , m_xMoveLeft(m_xBuilder->weld_button("toleft")) + , m_xExistingRadios(m_xBuilder->weld_tree_view("radiobuttons")) + { + if (getContext().aFieldNames.hasElements()) + { + enableFormDatasourceDisplay(); + } + + m_xMoveLeft->connect_clicked(LINK(this, ORadioSelectionPage, OnMoveEntry)); + m_xMoveRight->connect_clicked(LINK(this, ORadioSelectionPage, OnMoveEntry)); + m_xRadioName->connect_changed(LINK(this, ORadioSelectionPage, OnNameModified)); + m_xExistingRadios->connect_changed(LINK(this, ORadioSelectionPage, OnEntrySelected)); + + implCheckMoveButtons(); + m_xExistingRadios->set_selection_mode(SelectionMode::Multiple); + + getDialog()->defaultButton(m_xMoveRight.get()); + } + + ORadioSelectionPage::~ORadioSelectionPage() + { + } + + void ORadioSelectionPage::Activate() + { + OGBWPage::Activate(); + m_xRadioName->grab_focus(); + } + + void ORadioSelectionPage::initializePage() + { + OGBWPage::initializePage(); + + m_xRadioName->set_text(""); + + // no need to initialize the list of radios here + // (we're the only one affecting this special setting, so it will be in the same state as last time this + // page was committed) + + implCheckMoveButtons(); + } + + bool ORadioSelectionPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OGBWPage::commitPage(_eReason)) + return false; + + // copy the names of the radio buttons to be inserted + // and initialize the values + OOptionGroupSettings& rSettings = getSettings(); + rSettings.aLabels.clear(); + rSettings.aValues.clear(); + rSettings.aLabels.reserve(m_xExistingRadios->n_children()); + rSettings.aValues.reserve(m_xExistingRadios->n_children()); + for (sal_Int32 i=0; i<m_xExistingRadios->n_children(); ++i) + { + rSettings.aLabels.push_back(m_xExistingRadios->get_text(i)); + rSettings.aValues.push_back(OUString::number(i + 1)); + } + + return true; + } + + IMPL_LINK( ORadioSelectionPage, OnMoveEntry, weld::Button&, rButton, void ) + { + bool bMoveLeft = (m_xMoveLeft.get() == &rButton); + if (bMoveLeft) + { + while (m_xExistingRadios->count_selected_rows()) + m_xExistingRadios->remove(m_xExistingRadios->get_selected_index()); + } + else + { + m_xExistingRadios->append_text(m_xRadioName->get_text()); + m_xRadioName->set_text(""); + } + + implCheckMoveButtons(); + + //adjust the focus + if (bMoveLeft) + m_xExistingRadios->grab_focus(); + else + m_xRadioName->grab_focus(); + } + + IMPL_LINK_NOARG( ORadioSelectionPage, OnEntrySelected, weld::TreeView&, void ) + { + implCheckMoveButtons(); + } + + IMPL_LINK_NOARG( ORadioSelectionPage, OnNameModified, weld::Entry&, void ) + { + implCheckMoveButtons(); + } + + bool ORadioSelectionPage::canAdvance() const + { + return 0 != m_xExistingRadios->n_children(); + } + + void ORadioSelectionPage::implCheckMoveButtons() + { + bool bHaveSome = (0 != m_xExistingRadios->n_children()); + bool bSelectedSome = (0 != m_xExistingRadios->count_selected_rows()); + bool bUnfinishedInput = !m_xRadioName->get_text().isEmpty(); + + m_xMoveLeft->set_sensitive(bSelectedSome); + m_xMoveRight->set_sensitive(bUnfinishedInput); + + OControlWizard* pDialogController = getDialog(); + + pDialogController->enableButtons(WizardButtonFlags::NEXT, bHaveSome); + + weld::Dialog* pDialog = pDialogController->getDialog(); + + if (bUnfinishedInput) + { + if (!pDialog->is_default_widget(m_xMoveRight.get())) + pDialogController->defaultButton(m_xMoveRight.get()); + } + else + { + if (pDialog->is_default_widget(m_xMoveRight.get())) + pDialogController->defaultButton(WizardButtonFlags::NEXT); + } + } + + ODefaultFieldSelectionPage::ODefaultFieldSelectionPage(weld::Container* pPage, OControlWizard* pWizard) + : OMaybeListSelectionPage(pPage, pWizard, "modules/sabpilot/ui/defaultfieldselectionpage.ui", "DefaultFieldSelectionPage") + , m_xDefSelYes(m_xBuilder->weld_radio_button("defaultselectionyes")) + , m_xDefSelNo(m_xBuilder->weld_radio_button("defaultselectionno")) + , m_xDefSelection(m_xBuilder->weld_combo_box("defselectionfield")) + { + announceControls(*m_xDefSelYes, *m_xDefSelNo, *m_xDefSelection); + } + + ODefaultFieldSelectionPage::~ODefaultFieldSelectionPage() + { + } + + void ODefaultFieldSelectionPage::initializePage() + { + OMaybeListSelectionPage::initializePage(); + + const OOptionGroupSettings& rSettings = getSettings(); + + // fill the listbox + m_xDefSelection->clear(); + for (auto const& label : rSettings.aLabels) + m_xDefSelection->append_text(label); + + implInitialize(rSettings.sDefaultField); + } + + bool ODefaultFieldSelectionPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OMaybeListSelectionPage::commitPage(_eReason)) + return false; + + OOptionGroupSettings& rSettings = getSettings(); + implCommit(rSettings.sDefaultField); + + return true; + } + + OOptionValuesPage::OOptionValuesPage(weld::Container* pPage, OControlWizard* pWizard) + : OGBWPage(pPage, pWizard, "modules/sabpilot/ui/optionvaluespage.ui", "OptionValuesPage") + , m_xValue(m_xBuilder->weld_entry("optionvalue")) + , m_xOptions(m_xBuilder->weld_tree_view("radiobuttons")) + , m_nLastSelection(::vcl::WizardTypes::WizardState(-1)) + { + m_xOptions->connect_changed(LINK(this, OOptionValuesPage, OnOptionSelected)); + } + + OOptionValuesPage::~OOptionValuesPage() + { + } + + IMPL_LINK_NOARG( OOptionValuesPage, OnOptionSelected, weld::TreeView&, void ) + { + implTraveledOptions(); + } + + void OOptionValuesPage::Activate() + { + OGBWPage::Activate(); + m_xValue->grab_focus(); + } + + void OOptionValuesPage::implTraveledOptions() + { + if (::vcl::WizardTypes::WizardState(-1) != m_nLastSelection) + { + // save the value for the last option + DBG_ASSERT(o3tl::make_unsigned(m_nLastSelection) < m_aUncommittedValues.size(), "OOptionValuesPage::implTraveledOptions: invalid previous selection index!"); + m_aUncommittedValues[m_nLastSelection] = m_xValue->get_text(); + } + + m_nLastSelection = m_xOptions->get_selected_index(); + DBG_ASSERT(o3tl::make_unsigned(m_nLastSelection) < m_aUncommittedValues.size(), "OOptionValuesPage::implTraveledOptions: invalid new selection index!"); + m_xValue->set_text(m_aUncommittedValues[m_nLastSelection]); + } + + void OOptionValuesPage::initializePage() + { + OGBWPage::initializePage(); + + const OOptionGroupSettings& rSettings = getSettings(); + DBG_ASSERT(rSettings.aLabels.size(), "OOptionValuesPage::initializePage: no options!!"); + DBG_ASSERT(rSettings.aLabels.size() == rSettings.aValues.size(), "OOptionValuesPage::initializePage: inconsistent data!"); + + // fill the list with all available options + m_xOptions->clear(); + m_nLastSelection = -1; + for (auto const& label : rSettings.aLabels) + m_xOptions->append_text(label); + + // remember the values ... can't set them directly in the settings without the explicit commit call + // so we need have a copy of the values + m_aUncommittedValues = rSettings.aValues; + + // select the first entry + m_xOptions->select(0); + implTraveledOptions(); + } + + bool OOptionValuesPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OGBWPage::commitPage(_eReason)) + return false; + + OOptionGroupSettings& rSettings = getSettings(); + + // commit the current value + implTraveledOptions(); + // copy the uncommitted values + rSettings.aValues = m_aUncommittedValues; + + return true; + } + + OOptionDBFieldPage::OOptionDBFieldPage(weld::Container* pPage, OControlWizard* pWizard) + : ODBFieldPage(pPage, pWizard) + { + setDescriptionText(compmodule::ModuleRes(RID_STR_GROUPWIZ_DBFIELD)); + } + + OUString& OOptionDBFieldPage::getDBFieldSetting() + { + return static_cast<OGroupBoxWizard*>(getDialog())->getSettings().sDBField; + } + + OFinalizeGBWPage::OFinalizeGBWPage(weld::Container* pPage, OControlWizard* pWizard) + : OGBWPage(pPage, pWizard, "modules/sabpilot/ui/optionsfinalpage.ui", "OptionsFinalPage") + , m_xName(m_xBuilder->weld_entry("nameit")) + { + } + + OFinalizeGBWPage::~OFinalizeGBWPage() + { + } + + void OFinalizeGBWPage::Activate() + { + OGBWPage::Activate(); + m_xName->grab_focus(); + } + + bool OFinalizeGBWPage::canAdvance() const + { + return false; + } + + void OFinalizeGBWPage::initializePage() + { + OGBWPage::initializePage(); + + const OOptionGroupSettings& rSettings = getSettings(); + m_xName->set_text(rSettings.sControlLabel); + } + + bool OFinalizeGBWPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OGBWPage::commitPage(_eReason)) + return false; + + getSettings().sControlLabel = m_xName->get_text(); + + return true; + } + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/groupboxwiz.hxx b/extensions/source/dbpilots/groupboxwiz.hxx new file mode 100644 index 000000000..18fa12c7f --- /dev/null +++ b/extensions/source/dbpilots/groupboxwiz.hxx @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "controlwizard.hxx" +#include "commonpagesdbp.hxx" + +using vcl::WizardTypes::WizardState; +using vcl::WizardTypes::CommitPageReason; + +namespace dbp +{ + + struct OOptionGroupSettings : public OControlWizardSettings + { + std::vector<OUString> aLabels; + std::vector<OUString> aValues; + OUString sDefaultField; + OUString sDBField; + }; + + class OGroupBoxWizard final : public OControlWizard + { + OOptionGroupSettings m_aSettings; + + bool m_bVisitedDefault : 1; + bool m_bVisitedDB : 1; + + public: + OGroupBoxWizard( + weld::Window* _pParent, + const css::uno::Reference< css::beans::XPropertySet >& _rxObjectModel, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + OOptionGroupSettings& getSettings() { return m_aSettings; } + + private: + // OWizardMachine overridables + virtual std::unique_ptr<BuilderPage> createPage( WizardState _nState ) override; + virtual WizardState determineNextState( WizardState _nCurrentState ) const override; + virtual void enterState( WizardState _nState ) override; + virtual bool onFinish() override; + + virtual bool approveControl(sal_Int16 _nClassId) override; + }; + + class OGBWPage : public OControlWizardPage + { + public: + OGBWPage(weld::Container* pPage, OControlWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID) + : OControlWizardPage(pPage, pWizard, rUIXMLDescription, rID) + { + } + + protected: + OOptionGroupSettings& getSettings() { return static_cast<OGroupBoxWizard*>(getDialog())->getSettings(); } + }; + + class ORadioSelectionPage final : public OGBWPage + { + std::unique_ptr<weld::Entry> m_xRadioName; + std::unique_ptr<weld::Button> m_xMoveRight; + std::unique_ptr<weld::Button> m_xMoveLeft; + std::unique_ptr<weld::TreeView> m_xExistingRadios; + + public: + explicit ORadioSelectionPage(weld::Container* pPage, OControlWizard* pWizard); + virtual ~ORadioSelectionPage() override; + + private: + // BuilderPage overridables + void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + + DECL_LINK( OnMoveEntry, weld::Button&, void ); + DECL_LINK( OnEntrySelected, weld::TreeView&, void ); + DECL_LINK( OnNameModified, weld::Entry&, void ); + + void implCheckMoveButtons(); + }; + + class ODefaultFieldSelectionPage final : public OMaybeListSelectionPage + { + std::unique_ptr<weld::RadioButton> m_xDefSelYes; + std::unique_ptr<weld::RadioButton> m_xDefSelNo; + std::unique_ptr<weld::ComboBox> m_xDefSelection; + + public: + explicit ODefaultFieldSelectionPage(weld::Container* pPage, OControlWizard* pWizard); + virtual ~ODefaultFieldSelectionPage() override; + + private: + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + + OOptionGroupSettings& getSettings() { return static_cast<OGroupBoxWizard*>(getDialog())->getSettings(); } + }; + + class OOptionValuesPage final : public OGBWPage + { + std::unique_ptr<weld::Entry> m_xValue; + std::unique_ptr<weld::TreeView> m_xOptions; + + std::vector<OUString> m_aUncommittedValues; + ::vcl::WizardTypes::WizardState + m_nLastSelection; + + public: + explicit OOptionValuesPage(weld::Container* pPage, OControlWizard* pWizard); + virtual ~OOptionValuesPage() override; + + private: + // BuilderPage overridables + void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + + void implTraveledOptions(); + + DECL_LINK( OnOptionSelected, weld::TreeView&, void ); + }; + + class OOptionDBFieldPage : public ODBFieldPage + { + public: + explicit OOptionDBFieldPage(weld::Container* pPage, OControlWizard* pWizard); + + protected: + // ODBFieldPage overridables + virtual OUString& getDBFieldSetting() override; + }; + + class OFinalizeGBWPage final : public OGBWPage + { + std::unique_ptr<weld::Entry> m_xName; + + public: + explicit OFinalizeGBWPage(weld::Container* pPage, OControlWizard* pWizard); + virtual ~OFinalizeGBWPage() override; + + private: + // BuilderPage overridables + void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + }; + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/listcombowizard.cxx b/extensions/source/dbpilots/listcombowizard.cxx new file mode 100644 index 000000000..ae27f9553 --- /dev/null +++ b/extensions/source/dbpilots/listcombowizard.cxx @@ -0,0 +1,485 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "listcombowizard.hxx" +#include "commonpagesdbp.hxx" +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/form/ListSourceType.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <connectivity/dbtools.hxx> +#include <helpids.h> +#include <osl/diagnose.h> + + +namespace dbp +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::sdbcx; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::form; + using namespace ::dbtools; + + OListComboWizard::OListComboWizard(weld::Window* _pParent, + const Reference< XPropertySet >& _rxObjectModel, const Reference< XComponentContext >& _rxContext ) + : OControlWizard(_pParent, _rxObjectModel, _rxContext) + , m_bListBox(false) + , m_bHadDataSelection(true) + { + initControlSettings(&m_aSettings); + + m_xPrevPage->set_help_id(HID_LISTWIZARD_PREVIOUS); + m_xNextPage->set_help_id(HID_LISTWIZARD_NEXT); + m_xCancel->set_help_id(HID_LISTWIZARD_CANCEL); + m_xFinish->set_help_id(HID_LISTWIZARD_FINISH); + + // if we do not need the data source selection page ... + if (!needDatasourceSelection()) + { // ... skip it! + skip(); + m_bHadDataSelection = false; + } + } + + bool OListComboWizard::approveControl(sal_Int16 _nClassId) + { + switch (_nClassId) + { + case FormComponentType::LISTBOX: + m_bListBox = true; + setTitleBase(compmodule::ModuleRes(RID_STR_LISTWIZARD_TITLE)); + return true; + case FormComponentType::COMBOBOX: + m_bListBox = false; + setTitleBase(compmodule::ModuleRes(RID_STR_COMBOWIZARD_TITLE)); + return true; + } + return false; + } + + std::unique_ptr<BuilderPage> OListComboWizard::createPage(WizardState _nState) + { + OString sIdent(OString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + switch (_nState) + { + case LCW_STATE_DATASOURCE_SELECTION: + return std::make_unique<OTableSelectionPage>(pPageContainer, this); + case LCW_STATE_TABLESELECTION: + return std::make_unique<OContentTableSelection>(pPageContainer, this); + case LCW_STATE_FIELDSELECTION: + return std::make_unique<OContentFieldSelection>(pPageContainer, this); + case LCW_STATE_FIELDLINK: + return std::make_unique<OLinkFieldsPage>(pPageContainer, this); + case LCW_STATE_COMBODBFIELD: + return std::make_unique<OComboDBFieldPage>(pPageContainer, this); + } + + return nullptr; + } + + vcl::WizardTypes::WizardState OListComboWizard::determineNextState( WizardState _nCurrentState ) const + { + switch (_nCurrentState) + { + case LCW_STATE_DATASOURCE_SELECTION: + return LCW_STATE_TABLESELECTION; + case LCW_STATE_TABLESELECTION: + return LCW_STATE_FIELDSELECTION; + case LCW_STATE_FIELDSELECTION: + return getFinalState(); + } + + return WZS_INVALID_STATE; + } + + void OListComboWizard::enterState(WizardState _nState) + { + OControlWizard::enterState(_nState); + + enableButtons(WizardButtonFlags::PREVIOUS, m_bHadDataSelection ? (LCW_STATE_DATASOURCE_SELECTION < _nState) : LCW_STATE_TABLESELECTION < _nState); + enableButtons(WizardButtonFlags::NEXT, getFinalState() != _nState); + if (_nState < getFinalState()) + enableButtons(WizardButtonFlags::FINISH, false); + + if (getFinalState() == _nState) + defaultButton(WizardButtonFlags::FINISH); + } + + + bool OListComboWizard::leaveState(WizardState _nState) + { + if (!OControlWizard::leaveState(_nState)) + return false; + + if (getFinalState() == _nState) + defaultButton(WizardButtonFlags::NEXT); + + return true; + } + + + void OListComboWizard::implApplySettings() + { + try + { + // for quoting identifiers, we need the connection meta data + Reference< XConnection > xConn = getFormConnection(); + DBG_ASSERT(xConn.is(), "OListComboWizard::implApplySettings: no connection, unable to quote!"); + Reference< XDatabaseMetaData > xMetaData; + if (xConn.is()) + xMetaData = xConn->getMetaData(); + + // do some quotings + if (xMetaData.is()) + { + OUString sQuoteString = xMetaData->getIdentifierQuoteString(); + if (isListBox()) // only when we have a listbox this should be not empty + getSettings().sLinkedListField = quoteName(sQuoteString, getSettings().sLinkedListField); + + OUString sCatalog, sSchema, sName; + ::dbtools::qualifiedNameComponents( xMetaData, getSettings().sListContentTable, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation ); + getSettings().sListContentTable = ::dbtools::composeTableNameForSelect( xConn, sCatalog, sSchema, sName ); + + getSettings().sListContentField = quoteName(sQuoteString, getSettings().sListContentField); + } + + // ListSourceType: SQL + getContext().xObjectModel->setPropertyValue("ListSourceType", Any(sal_Int32(ListSourceType_SQL))); + + if (isListBox()) + { + // BoundColumn: 1 + getContext().xObjectModel->setPropertyValue("BoundColumn", Any(sal_Int16(1))); + + // build the statement to set as list source + OUString sStatement = "SELECT " + + getSettings().sListContentField + ", " + getSettings().sLinkedListField + + " FROM " + getSettings().sListContentTable; + Sequence< OUString > aListSource { sStatement }; + getContext().xObjectModel->setPropertyValue("ListSource", Any(aListSource)); + } + else + { + // build the statement to set as list source + OUString sStatement = "SELECT DISTINCT " + + getSettings().sListContentField + + " FROM " + getSettings().sListContentTable; + getContext().xObjectModel->setPropertyValue( "ListSource", Any(sStatement)); + } + + // the bound field + getContext().xObjectModel->setPropertyValue("DataField", Any(getSettings().sLinkedFormField)); + } + catch(const Exception&) + { + OSL_FAIL("OListComboWizard::implApplySettings: could not set the property values for the listbox!"); + } + } + + + bool OListComboWizard::onFinish() + { + if ( !OControlWizard::onFinish() ) + return false; + + implApplySettings(); + return true; + } + + Reference< XNameAccess > OLCPage::getTables() const + { + Reference< XConnection > xConn = getFormConnection(); + DBG_ASSERT(xConn.is(), "OLCPage::getTables: should have an active connection when reaching this page!"); + + Reference< XTablesSupplier > xSuppTables(xConn, UNO_QUERY); + Reference< XNameAccess > xTables; + if (xSuppTables.is()) + xTables = xSuppTables->getTables(); + + DBG_ASSERT(xTables.is() || !xConn.is(), "OLCPage::getTables: got no tables from the connection!"); + + return xTables; + } + + + Sequence< OUString > OLCPage::getTableFields() + { + Reference< XNameAccess > xTables = getTables(); + Sequence< OUString > aColumnNames; + if (xTables.is()) + { + try + { + // the list table as XColumnsSupplier + Reference< XColumnsSupplier > xSuppCols; + xTables->getByName(getSettings().sListContentTable) >>= xSuppCols; + DBG_ASSERT(xSuppCols.is(), "OLCPage::getTableFields: no columns supplier!"); + + // the columns + Reference< XNameAccess > xColumns; + if (xSuppCols.is()) + xColumns = xSuppCols->getColumns(); + + // the column names + if (xColumns.is()) + aColumnNames = xColumns->getElementNames(); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.dbpilots", "OLinkFieldsPage::initializePage: caught an exception while retrieving the columns"); + } + } + return aColumnNames; + } + + OContentTableSelection::OContentTableSelection(weld::Container* pPage, OListComboWizard* pWizard) + : OLCPage(pPage, pWizard, "modules/sabpilot/ui/contenttablepage.ui", "TableSelectionPage") + , m_xSelectTable(m_xBuilder->weld_tree_view("table")) + { + enableFormDatasourceDisplay(); + + m_xSelectTable->connect_row_activated(LINK(this, OContentTableSelection, OnTableDoubleClicked)); + m_xSelectTable->connect_changed(LINK(this, OContentTableSelection, OnTableSelected)); + } + + OContentTableSelection::~OContentTableSelection() + { + } + + void OContentTableSelection::Activate() + { + OLCPage::Activate(); + m_xSelectTable->grab_focus(); + } + + bool OContentTableSelection::canAdvance() const + { + if (!OLCPage::canAdvance()) + return false; + + return 0 != m_xSelectTable->count_selected_rows(); + } + + IMPL_LINK_NOARG( OContentTableSelection, OnTableSelected, weld::TreeView&, void ) + { + updateDialogTravelUI(); + } + + IMPL_LINK( OContentTableSelection, OnTableDoubleClicked, weld::TreeView&, _rListBox, bool ) + { + if (_rListBox.count_selected_rows()) + getDialog()->travelNext(); + return true; + } + + void OContentTableSelection::initializePage() + { + OLCPage::initializePage(); + + // fill the list with the table name + m_xSelectTable->clear(); + try + { + Reference< XNameAccess > xTables = getTables(); + Sequence< OUString > aTableNames; + if (xTables.is()) + aTableNames = xTables->getElementNames(); + fillListBox(*m_xSelectTable, aTableNames); + } + catch(const Exception&) + { + OSL_FAIL("OContentTableSelection::initializePage: could not retrieve the table names!"); + } + + m_xSelectTable->select_text(getSettings().sListContentTable); + } + + + bool OContentTableSelection::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OLCPage::commitPage(_eReason)) + return false; + + OListComboSettings& rSettings = getSettings(); + rSettings.sListContentTable = m_xSelectTable->get_selected_text(); + if (rSettings.sListContentTable.isEmpty() && (::vcl::WizardTypes::eTravelBackward != _eReason)) + // need to select a table + return false; + + return true; + } + + OContentFieldSelection::OContentFieldSelection(weld::Container* pPage, OListComboWizard* pWizard) + : OLCPage(pPage, pWizard, "modules/sabpilot/ui/contentfieldpage.ui", "FieldSelectionPage") + , m_xSelectTableField(m_xBuilder->weld_tree_view("selectfield")) + , m_xDisplayedField(m_xBuilder->weld_entry("displayfield")) + , m_xInfo(m_xBuilder->weld_label("info")) + { + m_xInfo->set_label(compmodule::ModuleRes( isListBox() ? RID_STR_FIELDINFO_LISTBOX : RID_STR_FIELDINFO_COMBOBOX)); + m_xSelectTableField->connect_changed(LINK(this, OContentFieldSelection, OnFieldSelected)); + m_xSelectTableField->connect_row_activated(LINK(this, OContentFieldSelection, OnTableDoubleClicked)); + } + + OContentFieldSelection::~OContentFieldSelection() + { + } + + void OContentFieldSelection::initializePage() + { + OLCPage::initializePage(); + + // fill the list of fields + fillListBox(*m_xSelectTableField, getTableFields()); + + m_xSelectTableField->select_text(getSettings().sListContentField); + m_xDisplayedField->set_text(getSettings().sListContentField); + } + + bool OContentFieldSelection::canAdvance() const + { + if (!OLCPage::canAdvance()) + return false; + + return 0 != m_xSelectTableField->count_selected_rows(); + } + + IMPL_LINK_NOARG( OContentFieldSelection, OnTableDoubleClicked, weld::TreeView&, bool ) + { + if (m_xSelectTableField->count_selected_rows()) + getDialog()->travelNext(); + return true; + } + + IMPL_LINK_NOARG( OContentFieldSelection, OnFieldSelected, weld::TreeView&, void ) + { + updateDialogTravelUI(); + m_xDisplayedField->set_text(m_xSelectTableField->get_selected_text()); + } + + bool OContentFieldSelection::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OLCPage::commitPage(_eReason)) + return false; + + getSettings().sListContentField = m_xSelectTableField->get_selected_text(); + + return true; + } + + OLinkFieldsPage::OLinkFieldsPage(weld::Container* pPage, OListComboWizard* pWizard) + : OLCPage(pPage, pWizard, "modules/sabpilot/ui/fieldlinkpage.ui", "FieldLinkPage") + , m_xValueListField(m_xBuilder->weld_combo_box("valuefield")) + , m_xTableField(m_xBuilder->weld_combo_box("listtable")) + { + m_xValueListField->connect_changed(LINK(this, OLinkFieldsPage, OnSelectionModified)); + m_xTableField->connect_changed(LINK(this, OLinkFieldsPage, OnSelectionModified)); + } + + OLinkFieldsPage::~OLinkFieldsPage() + { + } + + void OLinkFieldsPage::Activate() + { + OLCPage::Activate(); + m_xValueListField->grab_focus(); + } + + void OLinkFieldsPage::initializePage() + { + OLCPage::initializePage(); + + // fill the value list + fillListBox(*m_xValueListField, getContext().aFieldNames); + // fill the table field list + fillListBox(*m_xTableField, getTableFields()); + + // the initial selections + m_xValueListField->set_entry_text(getSettings().sLinkedFormField); + m_xTableField->set_entry_text(getSettings().sLinkedListField); + + implCheckFinish(); + } + + bool OLinkFieldsPage::canAdvance() const + { + // we're on the last page here, no travelNext allowed ... + return false; + } + + void OLinkFieldsPage::implCheckFinish() + { + bool bInvalidSelection = (-1 == m_xValueListField->find_text(m_xValueListField->get_active_text())); + bInvalidSelection |= (-1 == m_xTableField->find_text(m_xTableField->get_active_text())); + getDialog()->enableButtons(WizardButtonFlags::FINISH, !bInvalidSelection); + } + + IMPL_LINK_NOARG(OLinkFieldsPage, OnSelectionModified, weld::ComboBox&, void) + { + implCheckFinish(); + } + + bool OLinkFieldsPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OLCPage::commitPage(_eReason)) + return false; + + getSettings().sLinkedFormField = m_xValueListField->get_active_text(); + getSettings().sLinkedListField = m_xTableField->get_active_text(); + + return true; + } + + OComboDBFieldPage::OComboDBFieldPage(weld::Container* pPage, OControlWizard* pWizard) + : ODBFieldPage(pPage, pWizard) + { + setDescriptionText(compmodule::ModuleRes(RID_STR_COMBOWIZ_DBFIELD)); + } + + OUString& OComboDBFieldPage::getDBFieldSetting() + { + return static_cast<OListComboWizard*>(getDialog())->getSettings().sLinkedFormField; + } + + void OComboDBFieldPage::Activate() + { + ODBFieldPage::Activate(); + getDialog()->enableButtons(WizardButtonFlags::FINISH, true); + } + + bool OComboDBFieldPage::canAdvance() const + { + // we're on the last page here, no travelNext allowed ... + return false; + } + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/listcombowizard.hxx b/extensions/source/dbpilots/listcombowizard.hxx new file mode 100644 index 000000000..7ab6a8a21 --- /dev/null +++ b/extensions/source/dbpilots/listcombowizard.hxx @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "controlwizard.hxx" +#include "commonpagesdbp.hxx" + +using vcl::WizardTypes::WizardState; +using vcl::WizardTypes::CommitPageReason; + +namespace dbp +{ + +#define LCW_STATE_DATASOURCE_SELECTION 0 +#define LCW_STATE_TABLESELECTION 1 +#define LCW_STATE_FIELDSELECTION 2 +#define LCW_STATE_FIELDLINK 3 +#define LCW_STATE_COMBODBFIELD 4 + + struct OListComboSettings : public OControlWizardSettings + { + OUString sListContentTable; + OUString sListContentField; + OUString sLinkedFormField; + OUString sLinkedListField; + }; + + class OListComboWizard final : public OControlWizard + { + OListComboSettings m_aSettings; + bool m_bListBox : 1; + bool m_bHadDataSelection : 1; + + public: + OListComboWizard( + weld::Window* pParent, + const css::uno::Reference< css::beans::XPropertySet >& _rxObjectModel, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + OListComboSettings& getSettings() { return m_aSettings; } + + bool isListBox() const { return m_bListBox; } + + private: + // OWizardMachine overridables + virtual std::unique_ptr<BuilderPage> createPage( WizardState _nState ) override; + virtual WizardState determineNextState( WizardState _nCurrentState ) const override; + virtual void enterState( WizardState _nState ) override; + virtual bool leaveState( WizardState _nState ) override; + virtual bool onFinish() override; + + virtual bool approveControl(sal_Int16 _nClassId) override; + + WizardState getFinalState() const { return isListBox() ? LCW_STATE_FIELDLINK : LCW_STATE_COMBODBFIELD; } + + void implApplySettings(); + }; + + class OLCPage : public OControlWizardPage + { + public: + OLCPage(weld::Container* pPage, OListComboWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID) + : OControlWizardPage(pPage, pWizard, rUIXMLDescription, rID) + { + } + + protected: + OListComboSettings& getSettings() { return static_cast<OListComboWizard*>(getDialog())->getSettings(); } + bool isListBox() { return static_cast<OListComboWizard*>(getDialog())->isListBox(); } + + protected: + css::uno::Reference< css::container::XNameAccess > getTables() const; + css::uno::Sequence< OUString > getTableFields(); + }; + + class OContentTableSelection final : public OLCPage + { + std::unique_ptr<weld::TreeView> m_xSelectTable; + + public: + explicit OContentTableSelection(weld::Container* pPage, OListComboWizard* pWizard); + virtual ~OContentTableSelection() override; + + private: + // BuilderPage overridables + virtual void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + + DECL_LINK( OnTableDoubleClicked, weld::TreeView&, bool ); + DECL_LINK( OnTableSelected, weld::TreeView&, void ); + }; + + class OContentFieldSelection final : public OLCPage + { + std::unique_ptr<weld::TreeView> m_xSelectTableField; + std::unique_ptr<weld::Entry> m_xDisplayedField; + std::unique_ptr<weld::Label> m_xInfo; + + public: + explicit OContentFieldSelection(weld::Container* pPage, OListComboWizard* pWizard); + virtual ~OContentFieldSelection() override; + + private: + DECL_LINK( OnFieldSelected, weld::TreeView&, void ); + DECL_LINK( OnTableDoubleClicked, weld::TreeView&, bool ); + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + }; + + class OLinkFieldsPage final : public OLCPage + { + std::unique_ptr<weld::ComboBox> m_xValueListField; + std::unique_ptr<weld::ComboBox> m_xTableField; + + public: + explicit OLinkFieldsPage(weld::Container* pPage, OListComboWizard* pWizard); + virtual ~OLinkFieldsPage() override; + + private: + // BuilderPage overridables + virtual void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + + void implCheckFinish(); + + DECL_LINK(OnSelectionModified, weld::ComboBox&, void); + }; + + class OComboDBFieldPage : public ODBFieldPage + { + public: + explicit OComboDBFieldPage(weld::Container* pPage, OControlWizard* pWizard); + + protected: + // BuilderPage overridables + virtual void Activate() override; + + // OWizardPage overridables + virtual bool canAdvance() const override; + + // ODBFieldPage overridables + virtual OUString& getDBFieldSetting() override; + }; + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/moduledbp.cxx b/extensions/source/dbpilots/moduledbp.cxx new file mode 100644 index 000000000..0a8f8fd4d --- /dev/null +++ b/extensions/source/dbpilots/moduledbp.cxx @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <componentmodule.cxx> + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/optiongrouplayouter.cxx b/extensions/source/dbpilots/optiongrouplayouter.cxx new file mode 100644 index 000000000..f877a1768 --- /dev/null +++ b/extensions/source/dbpilots/optiongrouplayouter.cxx @@ -0,0 +1,204 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "optiongrouplayouter.hxx" +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/drawing/ShapeCollection.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/drawing/XShapeGrouper.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include "groupboxwiz.hxx" +#include "dbptools.hxx" +#include <tools/diagnose_ex.h> + + +namespace dbp +{ + + +#define BUTTON_HEIGHT 300 +#define HEIGHT 450 +#define OFFSET 300 +#define MIN_WIDTH 600 + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::drawing; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::text; + using namespace ::com::sun::star::view; + + OOptionGroupLayouter::OOptionGroupLayouter(const Reference< XComponentContext >& _rxContext) + :mxContext(_rxContext) + { + } + + + void OOptionGroupLayouter::doLayout(const OControlWizardContext& _rContext, const OOptionGroupSettings& _rSettings) + { + Reference< XShapes > xPageShapes = _rContext.xDrawPage; + if (!xPageShapes.is()) + { + OSL_FAIL("OOptionGroupLayouter::OOptionGroupLayouter: missing the XShapes interface for the page!"); + return; + } + + Reference< XMultiServiceFactory > xDocFactory(_rContext.xDocumentModel, UNO_QUERY); + if (!xDocFactory.is()) + { + OSL_FAIL("OOptionGroupLayouter::OOptionGroupLayouter: no document service factory!"); + return; + } + + // no. of buttons to create + sal_Int32 nRadioButtons = _rSettings.aLabels.size(); + + // the shape of the groupbox + css::awt::Size aControlShapeSize = _rContext.xObjectShape->getSize(); + // maybe need to adjust the size if the control shapes + sal_Int32 nMinShapeHeight = BUTTON_HEIGHT*(nRadioButtons+1) + BUTTON_HEIGHT + BUTTON_HEIGHT/4; + if (aControlShapeSize.Height < nMinShapeHeight) + aControlShapeSize.Height = nMinShapeHeight; + if (aControlShapeSize.Width < MIN_WIDTH) + aControlShapeSize.Width = MIN_WIDTH; + _rContext.xObjectShape->setSize(aControlShapeSize); + + // if we're working on a writer document, we need to anchor the shape + implAnchorShape(Reference< XPropertySet >(_rContext.xObjectShape, UNO_QUERY)); + + // shape collection (for grouping the shapes) + Reference< XShapes > xButtonCollection( ShapeCollection::create(mxContext) ); + // first member : the shape of the control + xButtonCollection->add(_rContext.xObjectShape); + + sal_Int32 nTempHeight = (aControlShapeSize.Height - BUTTON_HEIGHT/4) / (nRadioButtons + 1); + + css::awt::Point aShapePosition = _rContext.xObjectShape->getPosition(); + + css::awt::Size aButtonSize(aControlShapeSize); + aButtonSize.Width = aControlShapeSize.Width - OFFSET; + aButtonSize.Height = HEIGHT; + css::awt::Point aButtonPosition; + aButtonPosition.X = aShapePosition.X + OFFSET; + + OUString sElementsName("RadioGroup"); + disambiguateName(Reference< XNameAccess >(_rContext.xForm, UNO_QUERY), sElementsName); + + auto aLabelIter = _rSettings.aLabels.cbegin(); + auto aValueIter = _rSettings.aValues.cbegin(); + for (sal_Int32 i=0; i<nRadioButtons; ++i, ++aLabelIter, ++aValueIter) + { + aButtonPosition.Y = aShapePosition.Y + (i+1) * nTempHeight; + + Reference< XPropertySet > xRadioModel( + xDocFactory->createInstance("com.sun.star.form.component.RadioButton"), + UNO_QUERY); + + // the label + xRadioModel->setPropertyValue("Label", Any(*aLabelIter)); + // the value + xRadioModel->setPropertyValue("RefValue", Any(*aValueIter)); + + // default selection + if (_rSettings.sDefaultField == *aLabelIter) + xRadioModel->setPropertyValue("DefaultState", Any(sal_Int16(1))); + + // the connection to the database field + if (!_rSettings.sDBField.isEmpty()) + xRadioModel->setPropertyValue("DataField", Any(_rSettings.sDBField)); + + // the name for the model + xRadioModel->setPropertyValue("Name", Any(sElementsName)); + + // create a shape for the radio button + Reference< XControlShape > xRadioShape( + xDocFactory->createInstance("com.sun.star.drawing.ControlShape"), + UNO_QUERY); + Reference< XPropertySet > xShapeProperties(xRadioShape, UNO_QUERY); + + // if we're working on a writer document, we need to anchor the shape + implAnchorShape(xShapeProperties); + + // position it + xRadioShape->setSize(aButtonSize); + xRadioShape->setPosition(aButtonPosition); + // knitting with the model + xRadioShape->setControl(Reference< XControlModel >(xRadioModel, UNO_QUERY)); + + // the name of the shape + // tdf#117282 com.sun.star.drawing.ControlShape *has* no property + // of type 'Name'. In older versions it was an error that this did + // not throw an UnknownPropertyException. Still, it was never set + // at the Shape/SdrObject and was lost. + // Thus - just do no tset it. It is/stays part of the FormControl + // data, so it will be shown in the FormControl dialogs. It is not + // shown/used in SdrObject::Name dialog (e.g. context menu/Name...) + // if (xShapeProperties.is()) + // xShapeProperties->setPropertyValue("Name", makeAny(sElementsName)); + + // add to the page + xPageShapes->add(xRadioShape); + // add to the collection (for the later grouping) + xButtonCollection->add(xRadioShape); + + // set the GroupBox as "LabelControl" for the RadioButton + // (_after_ having inserted the model into the page!) + xRadioModel->setPropertyValue("LabelControl", Any(_rContext.xObjectModel)); + } + + // group the shapes + try + { + Reference< XShapeGrouper > xGrouper(_rContext.xDrawPage, UNO_QUERY); + if (xGrouper.is()) + { + Reference< XShapeGroup > xGroupedOptions = xGrouper->group(xButtonCollection); + Reference< XSelectionSupplier > xSelector(_rContext.xDocumentModel->getCurrentController(), UNO_QUERY); + if (xSelector.is()) + xSelector->select(Any(xGroupedOptions)); + } + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.dbpilots", + "caught an exception while grouping the shapes!"); + } + } + + + void OOptionGroupLayouter::implAnchorShape(const Reference< XPropertySet >& _rxShapeProps) + { + static constexpr OUStringLiteral s_sAnchorPropertyName = u"AnchorType"; + Reference< XPropertySetInfo > xPropertyInfo; + if (_rxShapeProps.is()) + xPropertyInfo = _rxShapeProps->getPropertySetInfo(); + if (xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(s_sAnchorPropertyName)) + _rxShapeProps->setPropertyValue(s_sAnchorPropertyName, Any(TextContentAnchorType_AT_PAGE)); + } + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/optiongrouplayouter.hxx b/extensions/source/dbpilots/optiongrouplayouter.hxx new file mode 100644 index 000000000..64a6998c1 --- /dev/null +++ b/extensions/source/dbpilots/optiongrouplayouter.hxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + + +namespace dbp +{ + + + struct OControlWizardContext; + struct OOptionGroupSettings; + + class OOptionGroupLayouter final + { + css::uno::Reference< css::uno::XComponentContext > + mxContext; + + public: + explicit OOptionGroupLayouter( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + void doLayout( + const OControlWizardContext& _rContext, + const OOptionGroupSettings& _rSettings + ); + + private: + static void implAnchorShape( + const css::uno::Reference< css::beans::XPropertySet >& _rxShapeProps + ); + }; + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/unoautopilot.hxx b/extensions/source/dbpilots/unoautopilot.hxx new file mode 100644 index 000000000..a61df8a6a --- /dev/null +++ b/extensions/source/dbpilots/unoautopilot.hxx @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <svtools/genericunodialog.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/proparrhlp.hxx> +#include <componentmodule.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <vcl/svapp.hxx> + +namespace dbp +{ + typedef ::svt::OGenericUnoDialog OUnoAutoPilot_Base; + template <class TYPE> + class OUnoAutoPilot final + :public OUnoAutoPilot_Base + ,public ::comphelper::OPropertyArrayUsageHelper< OUnoAutoPilot< TYPE > > + { + public: + explicit OUnoAutoPilot(const css::uno::Reference< css::uno::XComponentContext >& _rxORB, + OUString aImplementationName, + const css::uno::Sequence<OUString>& aSupportedServices) + : OUnoAutoPilot_Base(_rxORB), + m_ImplementationName(aImplementationName), + m_SupportedServices(aSupportedServices) + { + } + + + // XTypeProvider + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override + { + return css::uno::Sequence<sal_Int8>(); + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override + { + return m_ImplementationName; + } + + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override + { + return m_SupportedServices; + } + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override + { + css::uno::Reference< css::beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override + { + return *this->getArrayHelper(); + } + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override + { + css::uno::Sequence< css::beans::Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); + } + + private: + // OGenericUnoDialog overridables + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override + { + return std::make_unique<TYPE>(Application::GetFrameWeld(rParent), m_xObjectModel, m_aContext); + } + + virtual void implInitialize(const css::uno::Any& _rValue) override + { + css::beans::PropertyValue aArgument; + if (_rValue >>= aArgument) + if (aArgument.Name == "ObjectModel") + { + aArgument.Value >>= m_xObjectModel; + return; + } + + OUnoAutoPilot_Base::implInitialize(_rValue); + } + + css::uno::Reference< css::beans::XPropertySet > m_xObjectModel; + OUString m_ImplementationName; + css::uno::Sequence<OUString> m_SupportedServices; + + }; + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/wizardcontext.hxx b/extensions/source/dbpilots/wizardcontext.hxx new file mode 100644 index 000000000..65f4c1410 --- /dev/null +++ b/extensions/source/dbpilots/wizardcontext.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <map> + +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdb/XDatabaseContext.hpp> +#include <com/sun/star/sdbc/XRowSet.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/frame/XModel.hpp> + + +namespace dbp +{ + + struct OControlWizardContext + { + // the global data source context + css::uno::Reference< css::sdb::XDatabaseContext > + xDatasourceContext; + + // the control mode + css::uno::Reference< css::beans::XPropertySet > + xObjectModel; + // the form the control model belongs to + css::uno::Reference< css::beans::XPropertySet > + xForm; + // the form as rowset + css::uno::Reference< css::sdbc::XRowSet > + xRowSet; + + // the model of the document + css::uno::Reference< css::frame::XModel > + xDocumentModel; + // the page where the control mode resides + css::uno::Reference< css::drawing::XDrawPage > + xDrawPage; + // the shape which carries the control + css::uno::Reference< css::drawing::XControlShape > + xObjectShape; + + // the tables or queries of the data source the form is bound to (if any) + css::uno::Reference< css::container::XNameAccess > + xObjectContainer; + // the column types container of the object the form is bound to (table, query or SQL statement) + typedef std::map<OUString, sal_Int32> TNameTypeMap; + TNameTypeMap aTypes; + // the column names of the object the form is bound to (table, query or SQL statement) + css::uno::Sequence< OUString > + aFieldNames; + + bool bEmbedded; + }; + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/wizardservices.cxx b/extensions/source/dbpilots/wizardservices.cxx new file mode 100644 index 000000000..25bcf7942 --- /dev/null +++ b/extensions/source/dbpilots/wizardservices.cxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include "unoautopilot.hxx" +#include "groupboxwiz.hxx" +#include "listcombowizard.hxx" +#include "gridwizard.hxx" + +// the registration methods + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_dbp_OGroupBoxWizard_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire( + new ::dbp::OUnoAutoPilot< ::dbp::OGroupBoxWizard>( + context, + "org.openoffice.comp.dbp.OGroupBoxWizard", + { "com.sun.star.sdb.GroupBoxAutoPilot" } + )); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_dbp_OListComboWizard_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire( + new ::dbp::OUnoAutoPilot< ::dbp::OListComboWizard>( + context, + "org.openoffice.comp.dbp.OListComboWizard", + { "com.sun.star.sdb.ListComboBoxAutoPilot" } + )); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_dbp_OGridWizard_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire( + new ::dbp::OUnoAutoPilot< ::dbp::OGridWizard>( + context, + "org.openoffice.comp.dbp.OGridWizard", + { "com.sun.star.sdb.GridControlAutoPilot" } + )); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |