diff options
Diffstat (limited to '')
360 files changed, 98972 insertions, 0 deletions
diff --git a/dbaccess/source/ui/app/AppController.cxx b/dbaccess/source/ui/app/AppController.cxx new file mode 100644 index 000000000..06508d5c2 --- /dev/null +++ b/dbaccess/source/ui/app/AppController.cxx @@ -0,0 +1,2834 @@ +/* -*- 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 <memory> +#include "AppController.hxx" +#include <core_resource.hxx> +#include <dbexchange.hxx> +#include <strings.hxx> +#include <advancedsettingsdlg.hxx> +#include "subcomponentmanager.hxx" + +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/container/XContentEnumerationAccess.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/container/XHierarchicalNameContainer.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/ErrorMessageDialog.hpp> +#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/sdbcx/XAlterView.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbcx/XRename.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/util/XFlushable.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/util/XModifyBroadcaster.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/document/XEmbeddedScripts.hpp> +#include <com/sun/star/frame/XModel2.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/sdb/application/DatabaseObject.hpp> +#include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp> +#include <com/sun/star/document/XDocumentEventBroadcaster.hpp> +#include <tools/diagnose_ex.h> +#include <tools/urlobj.hxx> +#include <osl/diagnose.h> + +#include <svl/filenotation.hxx> +#include <vcl/transfer.hxx> +#include <svtools/cliplistener.hxx> + +#include <comphelper/interfacecontainer3.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/uno3.hxx> +#include <comphelper/types.hxx> +#include <comphelper/interaction.hxx> + +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +#include <unotools/closeveto.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/moduleoptions.hxx> +#include <unotools/historyoptions.hxx> + +#include <sfx2/mailmodelapi.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/QuerySaveDocument.hxx> + +#include <cppuhelper/exc_hlp.hxx> + +#include <connectivity/dbtools.hxx> +#include <connectivity/dbexception.hxx> + +#include <svx/dbaexchange.hxx> +#include <svx/dbaobjectex.hxx> +#include <svx/svxdlg.hxx> + +#include <osl/mutex.hxx> +#include "AppView.hxx" +#include <browserids.hxx> +#include <strings.hrc> +#include <defaultobjectnamecheck.hxx> +#include <databaseobjectview.hxx> +#include <dbtreelistbox.hxx> +#include "AppDetailView.hxx" +#include <linkeddocuments.hxx> +#include <UITools.hxx> +#include <dsntypes.hxx> +#include <dlgsave.hxx> +#include <dbaccess_slotid.hrc> + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_OApplicationController_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::OApplicationController(context)); +} + +namespace dbaui +{ +using namespace ::dbtools; +using namespace ::svx; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::view; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::frame; +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::datatransfer; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::task; +using ::com::sun::star::document::XEmbeddedScripts; +using ::com::sun::star::document::XDocumentEventBroadcaster; +using ::com::sun::star::sdb::application::NamedDatabaseObject; + +namespace DatabaseObject = ::com::sun::star::sdb::application::DatabaseObject; +namespace DatabaseObjectContainer = ::com::sun::star::sdb::application::DatabaseObjectContainer; + +OUString SAL_CALL OApplicationController::getImplementationName() +{ + return SERVICE_SDB_APPLICATIONCONTROLLER; +} + +Sequence< OUString> SAL_CALL OApplicationController::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.application.DefaultViewController" }; +} + +namespace { + +class SelectionGuard; + +} + +// OApplicationController +class SelectionNotifier +{ +private: + ::comphelper::OInterfaceContainerHelper3<XSelectionChangeListener> m_aSelectionListeners; + ::cppu::OWeakObject& m_rContext; + sal_Int32 m_nSelectionNestingLevel; + +public: + SelectionNotifier( ::osl::Mutex& _rMutex, ::cppu::OWeakObject& _rContext ) + :m_aSelectionListeners( _rMutex ) + ,m_rContext( _rContext ) + ,m_nSelectionNestingLevel( 0 ) + { + } + + SelectionNotifier(const SelectionNotifier&) = delete; + const SelectionNotifier& operator=(const SelectionNotifier&) = delete; + + void addListener( const Reference< XSelectionChangeListener >& Listener ) + { + m_aSelectionListeners.addInterface( Listener ); + } + + void removeListener( const Reference< XSelectionChangeListener >& Listener ) + { + m_aSelectionListeners.removeInterface( Listener ); + } + + void disposing() + { + EventObject aEvent( m_rContext ); + m_aSelectionListeners.disposeAndClear( aEvent ); + } + + struct SelectionGuardAccess { friend SelectionGuard; private: SelectionGuardAccess() { } }; + + /** enters a block which modifies the selection of our owner. + + Can be called multiple times, the only important thing is to call leaveSelection + equally often. + */ + void enterSelection( SelectionGuardAccess ) + { + ++m_nSelectionNestingLevel; + } + + /** leaves a block which modifies the selection of our owner + + Must be paired with enterSelection calls. + + When the last block is left, i.e. the last leaveSelection call is made on the current stack, + then our SelectionChangeListeners are notified + */ + void leaveSelection( SelectionGuardAccess ) + { + if ( --m_nSelectionNestingLevel == 0 ) + { + EventObject aEvent( m_rContext ); + m_aSelectionListeners.notifyEach( &XSelectionChangeListener::selectionChanged, aEvent ); + } + } +}; + +namespace { + +class SelectionGuard +{ +public: + explicit SelectionGuard( SelectionNotifier& _rNotifier ) + :m_rNotifier( _rNotifier ) + { + m_rNotifier.enterSelection( SelectionNotifier::SelectionGuardAccess() ); + } + + ~SelectionGuard() + { + m_rNotifier.leaveSelection( SelectionNotifier::SelectionGuardAccess() ); + } + + SelectionGuard(const SelectionGuard&) = delete; + const SelectionGuard& operator=(const SelectionGuard&) = delete; + +private: + SelectionNotifier& m_rNotifier; +}; + +} + +// OApplicationController +OApplicationController::OApplicationController(const Reference< XComponentContext >& _rxORB) + :OGenericUnoController( _rxORB ) + ,m_aContextMenuInterceptors( getMutex() ) + ,m_pSubComponentManager( new SubComponentManager( *this, getSharedMutex() ) ) + ,m_aTypeCollection( _rxORB ) + ,m_aTableCopyHelper(this) + ,m_nAsyncDrop(nullptr) + ,m_aSelectContainerEvent( LINK( this, OApplicationController, OnSelectContainer ) ) + ,m_ePreviewMode(E_PREVIEWNONE) + ,m_eCurrentType(E_NONE) + ,m_bNeedToReconnect(false) + ,m_bSuspended( false ) + ,m_pSelectionNotifier( new SelectionNotifier( getMutex(), *this ) ) +{ +} + +OApplicationController::~OApplicationController() +{ + if ( !rBHelper.bDisposed && !rBHelper.bInDispose ) + { + OSL_FAIL("Please check who doesn't dispose this component!"); + // increment ref count to prevent double call of Dtor + osl_atomic_increment( &m_refCount ); + dispose(); + } + clearView(); +} + +IMPLEMENT_FORWARD_XTYPEPROVIDER2(OApplicationController,OGenericUnoController,OApplicationController_Base) +IMPLEMENT_FORWARD_XINTERFACE2(OApplicationController,OGenericUnoController,OApplicationController_Base) +void OApplicationController::disconnect() +{ + if ( m_xDataSourceConnection.is() ) + stopConnectionListening( m_xDataSourceConnection ); + + try + { + // temporary (hopefully!) hack for #i55274# + Reference< XFlushable > xFlush( m_xDataSourceConnection, UNO_QUERY ); + if ( xFlush.is() && m_xMetaData.is() && !m_xMetaData->isReadOnly() ) + xFlush->flush(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + m_xDataSourceConnection.clear(); + m_xMetaData.clear(); + + InvalidateAll(); +} + +void SAL_CALL OApplicationController::disposing() +{ + for( const auto& rContainerListener : m_aCurrentContainers ) + { + if( rContainerListener.is() ) + { + rContainerListener->removeContainerListener( this ); + } + } + + m_aCurrentContainers.clear(); + m_pSubComponentManager->disposing(); + m_pSelectionNotifier->disposing(); + + if ( getView() ) + { + getContainer()->showPreview(nullptr); + m_pClipboardNotifier->ClearCallbackLink(); + m_pClipboardNotifier->RemoveListener( getView() ); + m_pClipboardNotifier.clear(); + } + + disconnect(); + try + { + Reference < XFrame > xFrame; + attachFrame( xFrame ); + + if ( m_xDataSource.is() ) + { + m_xDataSource->removePropertyChangeListener(OUString(), this); + m_xDataSource->removePropertyChangeListener(PROPERTY_INFO, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_URL, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_ISPASSWORDREQUIRED, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_LAYOUTINFORMATION, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_SUPPRESSVERSIONCL, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_TABLEFILTER, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_TABLETYPEFILTER, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_USER, this); + m_xDataSource = nullptr; + } + + Reference< XModifyBroadcaster > xBroadcaster( m_xModel, UNO_QUERY ); + if ( xBroadcaster.is() ) + xBroadcaster->removeModifyListener(static_cast<XModifyListener*>(this)); + + if ( m_xModel.is() ) + { + OUString sUrl = m_xModel->getURL(); + if ( !sUrl.isEmpty() ) + { + if ( ::comphelper::NamedValueCollection::getOrDefault( m_xModel->getArgs(), u"PickListEntry", true ) ) + { + OUString aFilter; + INetURLObject aURL( m_xModel->getURL() ); + std::shared_ptr<const SfxFilter> pFilter = getStandardDatabaseFilter(); + if ( pFilter ) + aFilter = pFilter->GetFilterName(); + + // add to svtool history options + SvtHistoryOptions::AppendItem( EHistoryType::PickList, + aURL.GetURLNoPass( INetURLObject::DecodeMechanism::NONE ), + aFilter, + getStrippedDatabaseName(), + std::nullopt, std::nullopt); + + // add to recent document list + if ( aURL.GetProtocol() == INetProtocol::File ) + Application::AddToRecentDocumentList( aURL.GetURLNoPass( INetURLObject::DecodeMechanism::NONE ), + pFilter ? pFilter->GetMimeType() : OUString(), + pFilter ? pFilter->GetServiceName() : OUString() ); + } + } + + m_xModel->disconnectController( this ); + + m_xModel.clear(); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + clearView(); + OGenericUnoController::disposing(); // here the m_refCount must be equal 5 +} + +bool OApplicationController::Construct(vcl::Window* _pParent) +{ + setView( VclPtr<OApplicationView>::Create( _pParent, getORB(), *this, m_ePreviewMode ) ); + + // late construction + bool bSuccess = false; + try + { + getContainer()->Construct(); + bSuccess = true; + } + catch(const SQLException&) + { + } + catch(const Exception&) + { + OSL_FAIL("OApplicationController::Construct : the construction of UnoDataBrowserView failed !"); + } + + if ( !bSuccess ) + { + clearView(); + return false; + } + + // now that we have a view we can create the clipboard listener + m_aSystemClipboard = TransferableDataHelper::CreateFromSystemClipboard( getView() ); + m_aSystemClipboard.StartClipboardListening( ); + + m_pClipboardNotifier = new TransferableClipboardListener( LINK( this, OApplicationController, OnClipboardChanged ) ); + m_pClipboardNotifier->AddListener( getView() ); + + OGenericUnoController::Construct( _pParent ); + getView()->Show(); + + return true; +} + +void SAL_CALL OApplicationController::disposing(const EventObject& _rSource) +{ + ::osl::MutexGuard aGuard( getMutex() ); + Reference<XConnection> xCon(_rSource.Source, UNO_QUERY); + if ( xCon.is() ) + { + OSL_ENSURE( m_xDataSourceConnection == xCon, + "OApplicationController::disposing: which connection does this come from?" ); + + if ( getContainer() && getContainer()->getElementType() == E_TABLE ) + getContainer()->clearPages(); + if ( m_xDataSourceConnection == xCon ) + { + m_xMetaData.clear(); + m_xDataSourceConnection.clear(); + } + } + else if ( _rSource.Source == m_xModel ) + { + m_xModel.clear(); + } + else if ( _rSource.Source == m_xDataSource ) + { + m_xDataSource = nullptr; + } + else + { + Reference<XContainer> xContainer( _rSource.Source, UNO_QUERY ); + if ( xContainer.is() ) + { + TContainerVector::iterator aFind = std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xContainer); + if ( aFind != m_aCurrentContainers.end() ) + m_aCurrentContainers.erase(aFind); + } + OGenericUnoController::disposing( _rSource ); + } +} + +sal_Bool SAL_CALL OApplicationController::suspend(sal_Bool bSuspend) +{ + // notify the OnPrepareViewClosing event (before locking any mutex) + Reference< XDocumentEventBroadcaster > xBroadcaster( m_xModel, UNO_QUERY ); + if ( xBroadcaster.is() ) + { + xBroadcaster->notifyDocumentEvent( + "OnPrepareViewClosing", + this, + Any() + ); + } + + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + if ( getView() && getView()->IsInModalMode() ) + return false; + + bool bCanSuspend = true; + + if ( m_bSuspended != bool(bSuspend) ) + { + if ( bSuspend && !closeSubComponents() ) + return false; + + Reference<XModifiable> xModi(m_xModel,UNO_QUERY); + Reference<XStorable> xStor(getModel(),UNO_QUERY); + + if ( bSuspend + && xStor.is() + && !xStor->isReadonly() + && ( xModi.is() + && xModi->isModified() + ) + ) + { + switch (ExecuteQuerySaveDocument(getFrameWeld(), getStrippedDatabaseName())) + { + case RET_YES: + Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>()); + bCanSuspend = !xModi->isModified(); + // when we save the document this must be false else some press cancel + break; + case RET_CANCEL: + bCanSuspend = false; + break; + default: + break; + } + } + } + + if ( bCanSuspend ) + m_bSuspended = bSuspend; + + return bCanSuspend; +} + +FeatureState OApplicationController::GetState(sal_uInt16 _nId) const +{ + FeatureState aReturn; + aReturn.bEnabled = false; + // check this first + if ( !getContainer() || m_bReadOnly ) + return aReturn; + + try + { + switch (_nId) + { + case SID_NEWDOCDIRECT: + aReturn.bEnabled = true; + aReturn.sTitle = "private:factory/sdatabase"; + break; + case SID_OPENURL: + aReturn.bEnabled = true; + if ( m_xModel.is() ) + aReturn.sTitle = m_xModel->getURL(); + break; + case ID_BROWSER_COPY: + { + sal_Int32 nCount = getContainer()->getSelectionCount(); + aReturn.bEnabled = nCount >= 1; + if ( aReturn.bEnabled && nCount == 1 && getContainer()->getElementType() == E_TABLE ) + aReturn.bEnabled = getContainer()->isALeafSelected(); + } + break; + case ID_BROWSER_CUT: + aReturn.bEnabled = !isDataSourceReadOnly() && getContainer()->getSelectionCount() >= 1; + aReturn.bEnabled = aReturn.bEnabled && (getContainer()->getElementType() != E_TABLE || getContainer()->isCutAllowed()); + break; + case ID_BROWSER_PASTE: + switch( getContainer()->getElementType() ) + { + case E_TABLE: + aReturn.bEnabled = !isDataSourceReadOnly() && !isConnectionReadOnly() && isTableFormat(); + break; + case E_QUERY: + aReturn.bEnabled = !isDataSourceReadOnly() && getViewClipboard().HasFormat(SotClipboardFormatId::DBACCESS_QUERY); + break; + default: + aReturn.bEnabled = !isDataSourceReadOnly() && OComponentTransferable::canExtractComponentDescriptor(getViewClipboard().GetDataFlavorExVector(),getContainer()->getElementType() == E_FORM); + } + break; + case SID_DB_APP_PASTE_SPECIAL: + aReturn.bEnabled = getContainer()->getElementType() == E_TABLE && !isDataSourceReadOnly() && !isConnectionReadOnly() && isTableFormat(); + break; + case SID_OPENDOC: + aReturn.bEnabled = true; + break; + case ID_BROWSER_SAVEDOC: + aReturn.bEnabled = !isDataSourceReadOnly(); + break; + case ID_BROWSER_SAVEASDOC: + aReturn.bEnabled = true; + break; + case ID_BROWSER_SORTUP: + aReturn.bEnabled = getContainer()->isFilled() && getContainer()->getElementCount(); + aReturn.bChecked = aReturn.bEnabled && getContainer()->isSortUp(); + break; + case ID_BROWSER_SORTDOWN: + aReturn.bEnabled = getContainer()->isFilled() && getContainer()->getElementCount(); + aReturn.bChecked = aReturn.bEnabled && !getContainer()->isSortUp(); + break; + + case SID_NEWDOC: + case SID_APP_NEW_FORM: + case ID_DOCUMENT_CREATE_REPWIZ: + aReturn.bEnabled = !isDataSourceReadOnly() && SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::WRITER); + break; + case SID_APP_NEW_REPORT: + aReturn.bEnabled = !isDataSourceReadOnly() + && SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::WRITER); + if ( aReturn.bEnabled ) + { + Reference< XContentEnumerationAccess > xEnumAccess(m_xContext->getServiceManager(), UNO_QUERY); + aReturn.bEnabled = xEnumAccess.is(); + if ( aReturn.bEnabled ) + { + const OUString sReportEngineServiceName = ::dbtools::getDefaultReportEngineServiceName(m_xContext); + aReturn.bEnabled = !sReportEngineServiceName.isEmpty(); + if ( aReturn.bEnabled ) + { + const Reference< XEnumeration > xEnumDrivers = xEnumAccess->createContentEnumeration(sReportEngineServiceName); + aReturn.bEnabled = xEnumDrivers.is() && xEnumDrivers->hasMoreElements(); + } + } + } + break; + case SID_DB_APP_VIEW_TABLES: + aReturn.bEnabled = true; + aReturn.bChecked = getContainer()->getElementType() == E_TABLE; + break; + case SID_DB_APP_VIEW_QUERIES: + aReturn.bEnabled = true; + aReturn.bChecked = getContainer()->getElementType() == E_QUERY; + break; + case SID_DB_APP_VIEW_FORMS: + aReturn.bEnabled = true; + aReturn.bChecked = getContainer()->getElementType() == E_FORM; + break; + case SID_DB_APP_VIEW_REPORTS: + aReturn.bEnabled = true; + aReturn.bChecked = getContainer()->getElementType() == E_REPORT; + break; + case ID_NEW_QUERY_DESIGN: + case ID_NEW_QUERY_SQL: + case ID_APP_NEW_QUERY_AUTO_PILOT: + case SID_DB_FORM_NEW_PILOT: + aReturn.bEnabled = !isDataSourceReadOnly(); + break; + case ID_NEW_VIEW_DESIGN: + case SID_DB_NEW_VIEW_SQL: + case ID_NEW_VIEW_DESIGN_AUTO_PILOT: + aReturn.bEnabled = !isDataSourceReadOnly() && !isConnectionReadOnly(); + if ( aReturn.bEnabled ) + { + Reference<XViewsSupplier> xViewsSup( getConnection(), UNO_QUERY ); + aReturn.bEnabled = xViewsSup.is(); + } + break; + case ID_NEW_TABLE_DESIGN: + case ID_NEW_TABLE_DESIGN_AUTO_PILOT: + aReturn.bEnabled = !isDataSourceReadOnly() && !isConnectionReadOnly(); + break; + case ID_DIRECT_SQL: + aReturn.bEnabled = true; + break; + case SID_APP_NEW_FOLDER: + aReturn.bEnabled = !isDataSourceReadOnly() && getContainer()->getSelectionCount() <= 1; + if ( aReturn.bEnabled ) + { + const ElementType eType = getContainer()->getElementType(); + aReturn.bEnabled = eType == E_REPORT || eType == E_FORM; + } + break; + case SID_FORM_CREATE_REPWIZ_PRE_SEL: + case SID_REPORT_CREATE_REPWIZ_PRE_SEL: + case SID_APP_NEW_REPORT_PRE_SEL: + aReturn.bEnabled = !isDataSourceReadOnly() + && SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::WRITER) + && getContainer()->isALeafSelected(); + if ( aReturn.bEnabled ) + { + ElementType eType = getContainer()->getElementType(); + aReturn.bEnabled = eType == E_QUERY || eType == E_TABLE; + if ( aReturn.bEnabled && SID_APP_NEW_REPORT_PRE_SEL == _nId ) + { + Reference< XContentEnumerationAccess > xEnumAccess(m_xContext->getServiceManager(), UNO_QUERY); + aReturn.bEnabled = xEnumAccess.is(); + if ( aReturn.bEnabled ) + { + static constexpr OUStringLiteral s_sReportDesign = u"org.libreoffice.report.pentaho.SOReportJobFactory"; + Reference< XEnumeration > xEnumDrivers = xEnumAccess->createContentEnumeration(s_sReportDesign); + aReturn.bEnabled = xEnumDrivers.is() && xEnumDrivers->hasMoreElements(); + } + } + } + break; + case SID_DB_APP_DELETE: + case SID_DB_APP_RENAME: + aReturn.bEnabled = isRenameDeleteAllowed(getContainer()->getElementType(), _nId == SID_DB_APP_DELETE); + break; + case SID_DB_APP_TABLE_DELETE: + case SID_DB_APP_TABLE_RENAME: + aReturn.bEnabled = isRenameDeleteAllowed(E_TABLE, _nId == SID_DB_APP_TABLE_DELETE); + break; + case SID_DB_APP_QUERY_DELETE: + case SID_DB_APP_QUERY_RENAME: + aReturn.bEnabled = isRenameDeleteAllowed(E_QUERY, _nId == SID_DB_APP_QUERY_DELETE); + break; + case SID_DB_APP_FORM_DELETE: + case SID_DB_APP_FORM_RENAME: + aReturn.bEnabled = isRenameDeleteAllowed(E_FORM, _nId == SID_DB_APP_FORM_DELETE); + break; + case SID_DB_APP_REPORT_DELETE: + case SID_DB_APP_REPORT_RENAME: + aReturn.bEnabled = isRenameDeleteAllowed(E_REPORT, _nId == SID_DB_APP_REPORT_DELETE); + break; + + case SID_SELECTALL: + aReturn.bEnabled = getContainer()->getElementCount() > 0 && getContainer()->getSelectionCount() != getContainer()->getElementCount(); + break; + case SID_DB_APP_EDIT: + case SID_DB_APP_TABLE_EDIT: + case SID_DB_APP_QUERY_EDIT: + case SID_DB_APP_FORM_EDIT: + case SID_DB_APP_REPORT_EDIT: + aReturn.bEnabled = !isDataSourceReadOnly() && getContainer()->getSelectionCount() > 0 + && getContainer()->isALeafSelected(); + break; + case SID_DB_APP_EDIT_SQL_VIEW: + if ( isDataSourceReadOnly() ) + aReturn.bEnabled = false; + else + { + switch ( getContainer()->getElementType() ) + { + case E_QUERY: + aReturn.bEnabled = ( getContainer()->getSelectionCount() > 0 ) + && ( getContainer()->isALeafSelected() ); + break; + case E_TABLE: + aReturn.bEnabled = false; + // there's one exception: views which support altering their underlying + // command can be edited in SQL view, too + if ( ( getContainer()->getSelectionCount() > 0 ) + && ( getContainer()->isALeafSelected() ) + ) + { + std::vector< OUString > aSelected; + getSelectionElementNames( aSelected ); + bool bAlterableViews = true; + for (auto const& selectedName : aSelected) + { + bAlterableViews &= impl_isAlterableView_nothrow(selectedName); + if (!bAlterableViews) + break; + } + aReturn.bEnabled = bAlterableViews; + } + break; + default: + break; + } + } + break; + case SID_DB_APP_OPEN: + case SID_DB_APP_TABLE_OPEN: + case SID_DB_APP_QUERY_OPEN: + case SID_DB_APP_FORM_OPEN: + case SID_DB_APP_REPORT_OPEN: + aReturn.bEnabled = getContainer()->getSelectionCount() > 0 && getContainer()->isALeafSelected(); + break; + case SID_DB_APP_DSUSERADMIN: + aReturn.bEnabled = !dbaccess::ODsnTypeCollection::isEmbeddedDatabase(::comphelper::getString(m_xDataSource->getPropertyValue(PROPERTY_URL))); + break; + case SID_DB_APP_DSRELDESIGN: + aReturn.bEnabled = true; + break; + case SID_DB_APP_TABLEFILTER: + aReturn.bEnabled = !isDataSourceReadOnly(); + break; + case SID_DB_APP_REFRESH_TABLES: + aReturn.bEnabled = getContainer()->getElementType() == E_TABLE && isConnected(); + break; + case SID_DB_APP_DSPROPS: + aReturn.bEnabled = m_xDataSource.is() && dbaccess::ODsnTypeCollection::isShowPropertiesEnabled(::comphelper::getString(m_xDataSource->getPropertyValue(PROPERTY_URL))); + break; + case SID_DB_APP_DSCONNECTION_TYPE: + aReturn.bEnabled = !isDataSourceReadOnly() && m_xDataSource.is() && !dbaccess::ODsnTypeCollection::isEmbeddedDatabase(::comphelper::getString(m_xDataSource->getPropertyValue(PROPERTY_URL))); + break; + case SID_DB_APP_DSADVANCED_SETTINGS: + aReturn.bEnabled = m_xDataSource.is() && AdvancedSettingsDialog::doesHaveAnyAdvancedSettings( m_aTypeCollection.getType(::comphelper::getString( m_xDataSource->getPropertyValue( PROPERTY_URL ) )) ); + break; + case SID_DB_APP_CONVERTTOVIEW: + aReturn.bEnabled = !isDataSourceReadOnly(); + if ( aReturn.bEnabled ) + { + ElementType eType = getContainer()->getElementType(); + aReturn.bEnabled = eType == E_QUERY && getContainer()->getSelectionCount() > 0; + if ( aReturn.bEnabled ) + { + Reference<XViewsSupplier> xViewSup( getConnection(), UNO_QUERY ); + aReturn.bEnabled = xViewSup.is() && Reference<XAppend>(xViewSup->getViews(),UNO_QUERY).is(); + } + } + break; + case SID_DB_APP_DISABLE_PREVIEW: + aReturn.bEnabled = true; + aReturn.bChecked = getContainer()->getPreviewMode() == E_PREVIEWNONE; + break; + case SID_DB_APP_VIEW_DOCINFO_PREVIEW: + { + ElementType eType = getContainer()->getElementType(); + aReturn.bEnabled = (E_REPORT == eType || E_FORM == eType); + aReturn.bChecked = getContainer()->getPreviewMode() == E_DOCUMENTINFO; + } + break; + case SID_DB_APP_VIEW_DOC_PREVIEW: + aReturn.bEnabled = true; + aReturn.bChecked = getContainer()->getPreviewMode() == E_DOCUMENT; + break; + case ID_BROWSER_UNDO: + aReturn.bEnabled = false; + break; + case SID_MAIL_SENDDOC: + aReturn.bEnabled = true; + break; + case SID_DB_APP_SENDREPORTASMAIL: + { + ElementType eType = getContainer()->getElementType(); + aReturn.bEnabled = E_REPORT == eType && getContainer()->getSelectionCount() > 0 && getContainer()->isALeafSelected(); + } + break; + case SID_DB_APP_SENDREPORTTOWRITER: + case SID_DB_APP_DBADMIN: + aReturn.bEnabled = false; + break; + case SID_DB_APP_STATUS_TYPE: + aReturn.bEnabled = m_xDataSource.is(); + if ( aReturn.bEnabled ) + { + OUString sURL; + m_xDataSource->getPropertyValue(PROPERTY_URL) >>= sURL; + OUString sDSTypeName; + if ( dbaccess::ODsnTypeCollection::isEmbeddedDatabase( sURL ) ) + { + sDSTypeName = DBA_RES(RID_STR_EMBEDDED_DATABASE); + } + else + { + sDSTypeName = m_aTypeCollection.getTypeDisplayName(sURL); + } + aReturn.sTitle = sDSTypeName; + } + break; + case SID_DB_APP_STATUS_DBNAME: + aReturn.bEnabled = m_xDataSource.is(); + if ( aReturn.bEnabled ) + { + OUString sURL; + m_xDataSource->getPropertyValue(PROPERTY_URL) >>= sURL; + OUString sDatabaseName; + OUString sHostName; + sal_Int32 nPortNumber( -1 ); + + m_aTypeCollection.extractHostNamePort( sURL, sDatabaseName, sHostName, nPortNumber ); + + if ( sDatabaseName.isEmpty() ) + sDatabaseName = m_aTypeCollection.cutPrefix( sURL ); + if ( m_aTypeCollection.isFileSystemBased(sURL) ) + { + sDatabaseName = SvtPathOptions().SubstituteVariable( sDatabaseName ); + if ( !sDatabaseName.isEmpty() ) + { + ::svt::OFileNotation aFileNotation(sDatabaseName); + // set this decoded URL as text + sDatabaseName = aFileNotation.get(::svt::OFileNotation::N_SYSTEM); + } + } + + if ( sDatabaseName.isEmpty() ) + sDatabaseName = m_aTypeCollection.getTypeDisplayName( sURL ); + + aReturn.sTitle = sDatabaseName; + } + break; + case SID_DB_APP_STATUS_USERNAME: + aReturn.bEnabled = m_xDataSource.is(); + if ( aReturn.bEnabled ) + m_xDataSource->getPropertyValue( PROPERTY_USER ) >>= aReturn.sTitle; + break; + case SID_DB_APP_STATUS_HOSTNAME: + aReturn.bEnabled = m_xDataSource.is(); + if ( aReturn.bEnabled ) + { + OUString sURL; + m_xDataSource->getPropertyValue( PROPERTY_URL ) >>= sURL; + + OUString sHostName, sDatabaseName; + sal_Int32 nPortNumber = -1; + m_aTypeCollection.extractHostNamePort( sURL, sDatabaseName, sHostName, nPortNumber ); + aReturn.sTitle = sHostName; + } + break; + default: + aReturn = OGenericUnoController::GetState(_nId); + } + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return aReturn; +} + +namespace +{ + bool lcl_handleException_nothrow( const Reference< XModel >& _rxDocument, const Any& _rException ) + { + bool bHandled = false; + + // try handling the error with an interaction handler + Reference< XInteractionHandler > xHandler = ::comphelper::NamedValueCollection::getOrDefault( _rxDocument->getArgs(), u"InteractionHandler", Reference< XInteractionHandler >() ); + if ( xHandler.is() ) + { + rtl::Reference pRequest( new ::comphelper::OInteractionRequest( _rException ) ); + rtl::Reference pApprove( new ::comphelper::OInteractionApprove ); + pRequest->addContinuation( pApprove ); + + try + { + xHandler->handle( pRequest ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + bHandled = pApprove->wasSelected(); + } + return bHandled; + } +} + +void OApplicationController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + if ( isUserDefinedFeature( _nId ) ) + { + OGenericUnoController::Execute( _nId, aArgs ); + return; + } + + if ( !getContainer() || m_bReadOnly ) + return; // return without execution + + try + { + switch(_nId) + { + case ID_BROWSER_CUT: + getContainer()->cut(); + break; + case ID_BROWSER_COPY: + { + rtl::Reference<TransferableHelper> pTransfer = copyObject(); + if ( pTransfer ) + pTransfer->CopyToClipboard(getView()); + } + break; + case ID_BROWSER_PASTE: + { + const TransferableDataHelper& rTransferData( getViewClipboard() ); + ElementType eType = getContainer()->getElementType(); + + switch( eType ) + { + case E_TABLE: + { + // get the selected tablename + std::vector< OUString > aList; + getSelectionElementNames( aList ); + if ( !aList.empty() ) + m_aTableCopyHelper.SetTableNameForAppend( *aList.begin() ); + else + m_aTableCopyHelper.ResetTableNameForAppend(); + + m_aTableCopyHelper.pasteTable( rTransferData , getDatabaseName(), ensureConnection() ); + } + break; + + case E_QUERY: + if ( rTransferData.HasFormat(SotClipboardFormatId::DBACCESS_QUERY) ) + paste( E_QUERY, ODataAccessObjectTransferable::extractObjectDescriptor( rTransferData ) ); + break; + default: + { + std::vector< OUString> aList; + getSelectionElementNames(aList); + OUString sFolderNameToInsertInto; + if ( !aList.empty() ) + { + Reference< XHierarchicalNameAccess > xContainer(getElements(eType),UNO_QUERY); + if ( xContainer.is() + && xContainer->hasByHierarchicalName(*aList.begin()) + && (xContainer->getByHierarchicalName(*aList.begin()) >>= xContainer) + && xContainer.is() + ) + sFolderNameToInsertInto = *aList.begin(); + } + paste( eType, OComponentTransferable::extractComponentDescriptor( rTransferData ), + sFolderNameToInsertInto ); + } + break; + } + } + break; + case SID_DB_APP_PASTE_SPECIAL: + { + if ( !aArgs.hasElements() ) + { + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<SfxAbstractPasteDialog> pDlg(pFact->CreatePasteDialog(getFrameWeld())); + std::vector<SotClipboardFormatId> aFormatIds; + getSupportedFormats(getContainer()->getElementType(),aFormatIds); + for (auto const& formatId : aFormatIds) + pDlg->Insert(formatId,""); + + const TransferableDataHelper& rClipboard = getViewClipboard(); + pasteFormat(pDlg->GetFormat(rClipboard.GetTransferable())); + } + else + { + const PropertyValue* pIter = aArgs.getConstArray(); + const PropertyValue* pEnd = pIter + aArgs.getLength(); + for( ; pIter != pEnd ; ++pIter) + { + if ( pIter->Name == "FormatStringId" ) + { + sal_uLong nTmp; + if ( pIter->Value >>= nTmp ) + pasteFormat(static_cast<SotClipboardFormatId>(nTmp)); + break; + } + } + } + } + break; + case SID_NEWDOCDIRECT: + case SID_OPENDOC: + { + Reference < XDispatchProvider > xProv( getFrame(), UNO_QUERY ); + if ( xProv.is() ) + { + URL aURL; + OUString aTarget; + if ( _nId == SID_NEWDOCDIRECT ) + { + aURL.Complete = "private:factory/sdatabase?Interactive"; + aTarget = "_default"; + } + else + aURL.Complete = ".uno:Open"; + + if ( m_xUrlTransformer.is() ) + m_xUrlTransformer->parseStrict( aURL ); + Reference < XDispatch > xDisp = xProv->queryDispatch( aURL, aTarget, 0 ); + if ( xDisp.is() ) + xDisp->dispatch( aURL, Sequence < PropertyValue >() ); + } + } + break; + case ID_BROWSER_SAVEDOC: + { + Reference< XStorable > xStore( m_xModel, UNO_QUERY_THROW ); + try + { + xStore->store(); + } + catch( const Exception& ) + { + lcl_handleException_nothrow( m_xModel, ::cppu::getCaughtException() ); + } + } + break; + + case ID_BROWSER_SAVEASDOC: + { + OUString sUrl; + if ( m_xModel.is() ) + sUrl = m_xModel->getURL(); + + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION, + FileDialogFlags::NONE, getFrameWeld()); + aFileDlg.SetContext(sfx2::FileDialogHelper::BaseSaveAs); + if (!sUrl.isEmpty()) + aFileDlg.SetDisplayDirectory( sUrl ); + + std::shared_ptr<const SfxFilter> pFilter = getStandardDatabaseFilter(); + if ( pFilter ) + { + aFileDlg.AddFilter(pFilter->GetUIName(),pFilter->GetDefaultExtension()); + aFileDlg.SetCurrentFilter(pFilter->GetUIName()); + } + + if ( aFileDlg.Execute() != ERRCODE_NONE ) + break; + + Reference<XStorable> xStore( m_xModel, UNO_QUERY_THROW ); + INetURLObject aURL( aFileDlg.GetPath() ); + try + { + xStore->storeAsURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Sequence< PropertyValue >() ); + } + catch( const Exception& ) + { + lcl_handleException_nothrow( m_xModel, ::cppu::getCaughtException() ); + } + + /*updateTitle();*/ + m_bCurrentlyModified = false; + InvalidateFeature(ID_BROWSER_SAVEDOC); + if ( getContainer()->getElementType() == E_NONE ) + { + getContainer()->selectContainer(E_NONE); + getContainer()->selectContainer(E_TABLE); + // #i95524# + getContainer()->Invalidate(); + refreshTables(); + } + + } + break; + case ID_BROWSER_SORTUP: + getContainer()->sortUp(); + InvalidateFeature(ID_BROWSER_SORTDOWN); + break; + case ID_BROWSER_SORTDOWN: + getContainer()->sortDown(); + InvalidateFeature(ID_BROWSER_SORTUP); + break; + + case ID_NEW_TABLE_DESIGN_AUTO_PILOT: + case ID_NEW_VIEW_DESIGN_AUTO_PILOT: + case ID_APP_NEW_QUERY_AUTO_PILOT: + case SID_DB_FORM_NEW_PILOT: + case SID_REPORT_CREATE_REPWIZ_PRE_SEL: + case SID_APP_NEW_REPORT_PRE_SEL: + case SID_FORM_CREATE_REPWIZ_PRE_SEL: + case ID_DOCUMENT_CREATE_REPWIZ: + case SID_APP_NEW_FORM: + case SID_APP_NEW_REPORT: + case ID_NEW_QUERY_SQL: + case ID_NEW_QUERY_DESIGN: + case ID_NEW_TABLE_DESIGN: + { + ElementType eType = E_TABLE; + bool bAutoPilot = false; + ::comphelper::NamedValueCollection aCreationArgs; + + switch( _nId ) + { + case SID_DB_FORM_NEW_PILOT: + case SID_FORM_CREATE_REPWIZ_PRE_SEL: + bAutoPilot = true; + [[fallthrough]]; + case SID_APP_NEW_FORM: + eType = E_FORM; + break; + case ID_DOCUMENT_CREATE_REPWIZ: + case SID_REPORT_CREATE_REPWIZ_PRE_SEL: + bAutoPilot = true; + [[fallthrough]]; + case SID_APP_NEW_REPORT: + case SID_APP_NEW_REPORT_PRE_SEL: + eType = E_REPORT; + break; + case ID_APP_NEW_QUERY_AUTO_PILOT: + bAutoPilot = true; + eType = E_QUERY; + break; + case ID_NEW_QUERY_DESIGN: + aCreationArgs.put( PROPERTY_GRAPHICAL_DESIGN, true ); + [[fallthrough]]; + case ID_NEW_QUERY_SQL: + eType = E_QUERY; + break; + case ID_NEW_TABLE_DESIGN_AUTO_PILOT: + bAutoPilot = true; + [[fallthrough]]; + case ID_NEW_TABLE_DESIGN: + break; + default: + OSL_FAIL("illegal switch call!"); + } + if ( bAutoPilot ) + getContainer()->PostUserEvent( LINK( this, OApplicationController, OnCreateWithPilot ), reinterpret_cast< void* >( eType ) ); + else + { + Reference< XComponent > xDocDefinition; + newElement( eType, aCreationArgs, xDocDefinition ); + } + } + break; + case SID_APP_NEW_FOLDER: + { + ElementType eType = getContainer()->getElementType(); + OUString sName = getContainer()->getQualifiedName( nullptr ); + insertHierarchyElement(eType,sName); + } + break; + case ID_NEW_VIEW_DESIGN: + case SID_DB_NEW_VIEW_SQL: + { + SharedConnection xConnection( ensureConnection() ); + if ( xConnection.is() ) + { + QueryDesigner aDesigner( getORB(), this, getFrame(), true ); + + ::comphelper::NamedValueCollection aCreationArgs; + aCreationArgs.put( PROPERTY_GRAPHICAL_DESIGN, ID_NEW_VIEW_DESIGN == _nId ); + + const Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY ); + const Reference< XComponent > xComponent = aDesigner.createNew( xDataSource, aCreationArgs ); + onDocumentOpened( OUString(), E_QUERY, E_OPEN_DESIGN, xComponent, nullptr ); + } + } + break; + case SID_DB_APP_DELETE: + case SID_DB_APP_TABLE_DELETE: + case SID_DB_APP_QUERY_DELETE: + case SID_DB_APP_FORM_DELETE: + case SID_DB_APP_REPORT_DELETE: + deleteEntries(); + break; + case SID_DB_APP_RENAME: + case SID_DB_APP_TABLE_RENAME: + case SID_DB_APP_QUERY_RENAME: + case SID_DB_APP_FORM_RENAME: + case SID_DB_APP_REPORT_RENAME: + renameEntry(); + break; + case SID_DB_APP_EDIT: + case SID_DB_APP_EDIT_SQL_VIEW: + case SID_DB_APP_TABLE_EDIT: + case SID_DB_APP_QUERY_EDIT: + case SID_DB_APP_FORM_EDIT: + case SID_DB_APP_REPORT_EDIT: + doAction( _nId, E_OPEN_DESIGN ); + break; + case SID_DB_APP_OPEN: + case SID_DB_APP_TABLE_OPEN: + case SID_DB_APP_QUERY_OPEN: + case SID_DB_APP_FORM_OPEN: + case SID_DB_APP_REPORT_OPEN: + doAction( _nId, E_OPEN_NORMAL ); + break; + case SID_DB_APP_CONVERTTOVIEW: + doAction( _nId, E_OPEN_NORMAL ); + break; + case SID_SELECTALL: + getContainer()->selectAll(); + InvalidateAll(); + break; + case SID_DB_APP_DSRELDESIGN: + { + Reference< XComponent > xRelationDesigner; + if ( !m_pSubComponentManager->activateSubFrame( OUString(), SID_DB_APP_DSRELDESIGN, E_OPEN_DESIGN, xRelationDesigner ) ) + { + SharedConnection xConnection( ensureConnection() ); + if ( xConnection.is() ) + { + RelationDesigner aDesigner( getORB(), this, m_aCurrentFrame.getFrame() ); + + const Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY ); + const Reference< XComponent > xComponent = aDesigner.createNew( xDataSource ); + onDocumentOpened( OUString(), SID_DB_APP_DSRELDESIGN, E_OPEN_DESIGN, xComponent, nullptr ); + } + } + } + break; + case SID_DB_APP_DSUSERADMIN: + { + SharedConnection xConnection( ensureConnection() ); + if ( xConnection.is() ) + openDialog("com.sun.star.sdb.UserAdministrationDialog"); + } + break; + case SID_DB_APP_TABLEFILTER: + // opens the table filter dialog for the selected data source + openDialog( "com.sun.star.sdb.TableFilterDialog" ); + askToReconnect(); + break; + case SID_DB_APP_REFRESH_TABLES: + refreshTables(); + break; + case SID_DB_APP_DSPROPS: + // opens the administration dialog for the selected data source + openDialog( "com.sun.star.sdb.DatasourceAdministrationDialog" ); + askToReconnect(); + break; + case SID_DB_APP_DSADVANCED_SETTINGS: + openDialog("com.sun.star.sdb.AdvancedDatabaseSettingsDialog"); + askToReconnect(); + break; + case SID_DB_APP_DSCONNECTION_TYPE: + openDialog("com.sun.star.sdb.DataSourceTypeChangeDialog"); + askToReconnect(); + break; + case ID_DIRECT_SQL: + { + SharedConnection xConnection( ensureConnection() ); + if ( xConnection.is() ) + // opens the DirectSQLDialog to execute hand made sql statements. + openDialog( SERVICE_SDB_DIRECTSQLDIALOG ); + } + break; + case SID_DB_APP_VIEW_TABLES: + m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_TABLE ) ); + break; + case SID_DB_APP_VIEW_QUERIES: + m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_QUERY ) ); + break; + case SID_DB_APP_VIEW_FORMS: + m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_FORM ) ); + break; + case SID_DB_APP_VIEW_REPORTS: + m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_REPORT ) ); + break; + case SID_DB_APP_DISABLE_PREVIEW: + m_ePreviewMode = E_PREVIEWNONE; + getContainer()->switchPreview(m_ePreviewMode); + break; + case SID_DB_APP_VIEW_DOCINFO_PREVIEW: + m_ePreviewMode = E_DOCUMENTINFO; + getContainer()->switchPreview(m_ePreviewMode); + break; + case SID_DB_APP_VIEW_DOC_PREVIEW: + m_ePreviewMode = E_DOCUMENT; + getContainer()->switchPreview(m_ePreviewMode); + break; + case SID_MAIL_SENDDOC: + { + SfxMailModel aSendMail; + if ( aSendMail.AttachDocument(getModel(), OUString()) == SfxMailModel::SEND_MAIL_OK ) + aSendMail.Send( getFrame() ); + } + break; + case SID_DB_APP_SENDREPORTASMAIL: + doAction( _nId, E_OPEN_FOR_MAIL ); + break; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + InvalidateFeature(_nId); +} + +void OApplicationController::describeSupportedFeatures() +{ + OGenericUnoController::describeSupportedFeatures(); + + implDescribeSupportedFeature( ".uno:AddDirect", SID_NEWDOCDIRECT, CommandGroup::APPLICATION ); + implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVEDOC, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:SendMail", SID_MAIL_SENDDOC, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:DBSendReportAsMail",SID_DB_APP_SENDREPORTASMAIL, + CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:DBSendReportToWriter",SID_DB_APP_SENDREPORTTOWRITER, + CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:DBNewForm", SID_APP_NEW_FORM, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DBNewFolder", SID_APP_NEW_FOLDER, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DBNewFormAutoPilot", SID_DB_FORM_NEW_PILOT, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DBNewFormAutoPilotWithPreSelection", + SID_FORM_CREATE_REPWIZ_PRE_SEL, + CommandGroup::APPLICATION ); + + implDescribeSupportedFeature( ".uno:DBNewReport", SID_APP_NEW_REPORT, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DBNewReportAutoPilot", + ID_DOCUMENT_CREATE_REPWIZ, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DBNewReportAutoPilotWithPreSelection", + SID_REPORT_CREATE_REPWIZ_PRE_SEL, + CommandGroup::APPLICATION ); + implDescribeSupportedFeature( ".uno:DBNewQuery", ID_NEW_QUERY_DESIGN, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DBNewQuerySql", ID_NEW_QUERY_SQL, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DBNewQueryAutoPilot",ID_APP_NEW_QUERY_AUTO_PILOT, + CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DBNewTable", ID_NEW_TABLE_DESIGN, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DBNewTableAutoPilot",ID_NEW_TABLE_DESIGN_AUTO_PILOT, + CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DBNewView", ID_NEW_VIEW_DESIGN, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DBNewViewSQL", SID_DB_NEW_VIEW_SQL, CommandGroup::INSERT ); + + implDescribeSupportedFeature( ".uno:DBDelete", SID_DB_APP_DELETE, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Delete", SID_DB_APP_DELETE, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBRename", SID_DB_APP_RENAME, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBEdit", SID_DB_APP_EDIT, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBEditSqlView", SID_DB_APP_EDIT_SQL_VIEW, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBOpen", SID_DB_APP_OPEN, CommandGroup::EDIT ); + + implDescribeSupportedFeature( ".uno:DBTableDelete", SID_DB_APP_TABLE_DELETE, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBTableRename", SID_DB_APP_TABLE_RENAME, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBTableEdit", SID_DB_APP_TABLE_EDIT, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBTableOpen", SID_DB_APP_TABLE_OPEN, CommandGroup::EDIT ); + + implDescribeSupportedFeature( ".uno:DBQueryDelete", SID_DB_APP_QUERY_DELETE, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBQueryRename", SID_DB_APP_QUERY_RENAME, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBQueryEdit", SID_DB_APP_QUERY_EDIT, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBQueryOpen", SID_DB_APP_QUERY_OPEN, CommandGroup::EDIT ); + + implDescribeSupportedFeature( ".uno:DBFormDelete", SID_DB_APP_FORM_DELETE, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBFormRename", SID_DB_APP_FORM_RENAME, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBFormEdit", SID_DB_APP_FORM_EDIT, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBFormOpen", SID_DB_APP_FORM_OPEN, CommandGroup::EDIT ); + + implDescribeSupportedFeature( ".uno:DBReportDelete", SID_DB_APP_REPORT_DELETE, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBReportRename", SID_DB_APP_REPORT_RENAME, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBReportEdit", SID_DB_APP_REPORT_EDIT, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBReportOpen", SID_DB_APP_REPORT_OPEN, CommandGroup::EDIT ); + + implDescribeSupportedFeature( ".uno:SelectAll", SID_SELECTALL, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Undo", ID_BROWSER_UNDO, CommandGroup::EDIT ); + + implDescribeSupportedFeature( ".uno:Sortup", ID_BROWSER_SORTUP, CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:SortDown", ID_BROWSER_SORTDOWN, CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:DBRelationDesign", SID_DB_APP_DSRELDESIGN, CommandGroup::APPLICATION ); + implDescribeSupportedFeature( ".uno:DBUserAdmin", SID_DB_APP_DSUSERADMIN, CommandGroup::APPLICATION ); + implDescribeSupportedFeature( ".uno:DBTableFilter", SID_DB_APP_TABLEFILTER, CommandGroup::APPLICATION ); + implDescribeSupportedFeature( ".uno:DBDSProperties", SID_DB_APP_DSPROPS, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBDSConnectionType", SID_DB_APP_DSCONNECTION_TYPE, + CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBDSAdvancedSettings", + SID_DB_APP_DSADVANCED_SETTINGS, + CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:PasteSpecial", SID_DB_APP_PASTE_SPECIAL, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBConvertToView", SID_DB_APP_CONVERTTOVIEW, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBRefreshTables", SID_DB_APP_REFRESH_TABLES, CommandGroup::APPLICATION ); + implDescribeSupportedFeature( ".uno:DBDirectSQL", ID_DIRECT_SQL, CommandGroup::APPLICATION ); + implDescribeSupportedFeature( ".uno:DBViewTables", SID_DB_APP_VIEW_TABLES, CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:DBViewQueries", SID_DB_APP_VIEW_QUERIES, CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:DBViewForms", SID_DB_APP_VIEW_FORMS, CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:DBViewReports", SID_DB_APP_VIEW_REPORTS, CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:DBDisablePreview", SID_DB_APP_DISABLE_PREVIEW,CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:DBShowDocInfoPreview", + SID_DB_APP_VIEW_DOCINFO_PREVIEW, + CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:DBShowDocPreview", SID_DB_APP_VIEW_DOC_PREVIEW, + CommandGroup::VIEW ); + + implDescribeSupportedFeature( ".uno:OpenUrl", SID_OPENURL, CommandGroup::APPLICATION ); + + // this one should not appear under Tools->Customize->Keyboard + implDescribeSupportedFeature( ".uno:DBNewReportWithPreSelection", + SID_APP_NEW_REPORT_PRE_SEL ); + implDescribeSupportedFeature( ".uno:DBDSImport", SID_DB_APP_DSIMPORT); + implDescribeSupportedFeature( ".uno:DBDSExport", SID_DB_APP_DSEXPORT); + implDescribeSupportedFeature( ".uno:DBDBAdmin", SID_DB_APP_DBADMIN); + + // status info + implDescribeSupportedFeature( ".uno:DBStatusType", SID_DB_APP_STATUS_TYPE); + implDescribeSupportedFeature( ".uno:DBStatusDBName", SID_DB_APP_STATUS_DBNAME); + implDescribeSupportedFeature( ".uno:DBStatusUserName", SID_DB_APP_STATUS_USERNAME); + implDescribeSupportedFeature( ".uno:DBStatusHostName", SID_DB_APP_STATUS_HOSTNAME); +} + +OApplicationView* OApplicationController::getContainer() const +{ + return static_cast< OApplicationView* >( getView() ); +} + +// css::container::XContainerListener +void SAL_CALL OApplicationController::elementInserted( const ContainerEvent& _rEvent ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + Reference< XContainer > xContainer(_rEvent.Source, UNO_QUERY); + if ( std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xContainer) == m_aCurrentContainers.end() ) + return; + + OSL_ENSURE(getContainer(),"View is NULL! -> GPF"); + if ( !getContainer() ) + return; + + OUString sName; + _rEvent.Accessor >>= sName; + ElementType eType = getElementType(xContainer); + + switch( eType ) + { + case E_TABLE: + ensureConnection(); + break; + case E_FORM: + case E_REPORT: + { + Reference< XContainer > xSubContainer(_rEvent.Element,UNO_QUERY); + if ( xSubContainer.is() ) + containerFound(xSubContainer); + } + break; + default: + break; + } + getContainer()->elementAdded(eType,sName,_rEvent.Element); +} + +void SAL_CALL OApplicationController::elementRemoved( const ContainerEvent& _rEvent ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + Reference< XContainer > xContainer(_rEvent.Source, UNO_QUERY); + if ( std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xContainer) == m_aCurrentContainers.end() ) + return; + + OSL_ENSURE(getContainer(),"View is NULL! -> GPF"); + OUString sName; + _rEvent.Accessor >>= sName; + ElementType eType = getElementType(xContainer); + switch( eType ) + { + case E_TABLE: + ensureConnection(); + break; + case E_FORM: + case E_REPORT: + { + Reference<XContent> xContent(xContainer,UNO_QUERY); + if ( xContent.is() ) + { + sName = xContent->getIdentifier()->getContentIdentifier() + "/" + sName; + } + } + break; + default: + break; + } + getContainer()->elementRemoved(eType,sName); +} + +void SAL_CALL OApplicationController::elementReplaced( const ContainerEvent& _rEvent ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + Reference< XContainer > xContainer(_rEvent.Source, UNO_QUERY); + if ( std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xContainer) == m_aCurrentContainers.end() ) + return; + + OSL_ENSURE(getContainer(),"View is NULL! -> GPF"); + OUString sName; + try + { + _rEvent.Accessor >>= sName; + Reference<XPropertySet> xProp(_rEvent.Element,UNO_QUERY); + + ElementType eType = getElementType(xContainer); + switch( eType ) + { + case E_TABLE: + { + ensureConnection(); + if ( xProp.is() && m_xMetaData.is() ) + //TODO: tdf#133497 "OApplicationController::elementReplaced effectively does + // nothing": + (void) ::dbaui::composeTableName( m_xMetaData, xProp, ::dbtools::EComposeRule::InDataManipulation, false ); + } + break; + case E_FORM: + case E_REPORT: + { + Reference<XContent> xContent(xContainer,UNO_QUERY); + if ( xContent.is() ) + { + sName = xContent->getIdentifier()->getContentIdentifier() + "/" + sName; + } + } + break; + default: + break; + } + // getContainer()->elementReplaced(getContainer()->getElementType(),sName,sNewName); + } + catch( Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +namespace +{ + OUString lcl_getToolBarResource(ElementType _eType) + { + OUString sToolbar; + switch(_eType) + { + case E_TABLE: + sToolbar = "private:resource/toolbar/tableobjectbar"; + break; + case E_QUERY: + sToolbar = "private:resource/toolbar/queryobjectbar"; + break; + case E_FORM: + sToolbar = "private:resource/toolbar/formobjectbar"; + break; + case E_REPORT: + sToolbar = "private:resource/toolbar/reportobjectbar"; + break; + case E_NONE: + break; + default: + OSL_FAIL("Invalid ElementType!"); + break; + } + return sToolbar; + } +} + +bool OApplicationController::onContainerSelect(ElementType _eType) +{ + OSL_ENSURE(getContainer(),"View is NULL! -> GPF"); + + if ( m_eCurrentType != _eType && _eType != E_NONE ) + { + SelectionGuard aSelGuard( *m_pSelectionNotifier ); + + if ( _eType == E_TABLE ) + { + try + { + SharedConnection xConnection( ensureConnection() ); + if ( xConnection.is() && getContainer()->getDetailView() ) + { + getContainer()->getDetailView()->createTablesPage(xConnection); + Reference<XTablesSupplier> xTabSup(xConnection,UNO_QUERY); + if ( xTabSup.is() ) + addContainerListener(xTabSup->getTables()); + } + else + { + return false; + } + } + catch( const Exception& ) + { + return false; + } + } + else if ( _eType == E_QUERY ) + { + // tdf#126578: retrieve connection to be able to call "Create as View" + ensureConnection(); + } + Reference< XLayoutManager > xLayoutManager = getLayoutManager( getFrame() ); + if ( xLayoutManager.is() ) + { + OUString sToolbar = lcl_getToolBarResource(_eType); + OUString sDestroyToolbar = lcl_getToolBarResource(m_eCurrentType); + + xLayoutManager->lock(); + xLayoutManager->destroyElement( sDestroyToolbar ); + if ( !sToolbar.isEmpty() ) + { + xLayoutManager->createElement( sToolbar ); + xLayoutManager->requestElement( sToolbar ); + } + xLayoutManager->unlock(); + xLayoutManager->doLayout(); + } + + if ( _eType != E_TABLE && getContainer()->getDetailView() ) + { + Reference< XNameAccess > xContainer = getElements(_eType); + addContainerListener(xContainer); + getContainer()->getDetailView()->createPage(_eType,xContainer); + } + + SelectionByElementType::const_iterator pendingSelection = m_aPendingSelection.find( _eType ); + if ( pendingSelection != m_aPendingSelection.end() ) + { + getContainer()->selectElements( comphelper::containerToSequence(pendingSelection->second) ); + + m_aPendingSelection.erase( pendingSelection ); + } + + InvalidateAll(); + } + m_eCurrentType = _eType; + + return true; +} + +bool OApplicationController::onEntryDoubleClick(const weld::TreeView& rTreeView) +{ + OApplicationView* pContainer = getContainer(); + if (!pContainer) + return false; // not handled + + std::unique_ptr<weld::TreeIter> xHdlEntry = rTreeView.make_iterator(); + if (!rTreeView.get_cursor(xHdlEntry.get())) + return false; + + if (!pContainer->isLeaf(rTreeView, *xHdlEntry)) + return false; // not handled + + try + { + // opens a new frame with either the table or the query or report or form or view + openElementWithArguments( + getContainer()->getQualifiedName(xHdlEntry.get()), + getContainer()->getElementType(), + E_OPEN_NORMAL, + 0, + ::comphelper::NamedValueCollection() ); + return true; // handled + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return false; // not handled +} + +bool OApplicationController::impl_isAlterableView_nothrow( const OUString& _rTableOrViewName ) const +{ + OSL_PRECOND( m_xDataSourceConnection.is(), "OApplicationController::impl_isAlterableView_nothrow: no connection!" ); + + bool bIsAlterableView( false ); + try + { + Reference< XViewsSupplier > xViewsSupp( m_xDataSourceConnection, UNO_QUERY ); + Reference< XNameAccess > xViews; + if ( xViewsSupp.is() ) + xViews = xViewsSupp->getViews(); + + Reference< XAlterView > xAsAlterableView; + if ( xViews.is() && xViews->hasByName( _rTableOrViewName ) ) + xAsAlterableView.set( xViews->getByName( _rTableOrViewName ), UNO_QUERY ); + + bIsAlterableView = xAsAlterableView.is(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bIsAlterableView; +} + +Reference< XComponent > OApplicationController::openElementWithArguments( const OUString& _sName, ElementType _eType, + ElementOpenMode _eOpenMode, sal_uInt16 _nInstigatorCommand, const ::comphelper::NamedValueCollection& _rAdditionalArguments ) +{ + OSL_PRECOND( getContainer(), "OApplicationController::openElementWithArguments: no view!" ); + if ( !getContainer() ) + return nullptr; + + Reference< XComponent > xRet; + if ( _eOpenMode == E_OPEN_DESIGN ) + { + // https://bz.apache.org/ooo/show_bug.cgi?id=30382 + getContainer()->showPreview(nullptr); + } + + bool isStandaloneDocument = false; + switch ( _eType ) + { + case E_REPORT: + if ( _eOpenMode != E_OPEN_DESIGN ) + { + // reports which are opened in a mode other than design are no sub components of our application + // component, but standalone documents. + isStandaloneDocument = true; + } + [[fallthrough]]; + case E_FORM: + { + if ( isStandaloneDocument || !m_pSubComponentManager->activateSubFrame( _sName, _eType, _eOpenMode, xRet ) ) + { + std::unique_ptr< OLinkedDocumentsAccess > aHelper = getDocumentsAccess( _eType ); + if ( !aHelper->isConnected() ) + break; + + Reference< XComponent > xDefinition; + xRet = aHelper->open( _sName, xDefinition, _eOpenMode, _rAdditionalArguments ); + + if ( !isStandaloneDocument ) + onDocumentOpened( _sName, _eType, _eOpenMode, xRet, xDefinition ); + } + } + break; + + case E_QUERY: + case E_TABLE: + { + if ( !m_pSubComponentManager->activateSubFrame( _sName, _eType, _eOpenMode, xRet ) ) + { + SharedConnection xConnection( ensureConnection() ); + if ( !xConnection.is() ) + break; + + std::unique_ptr< DatabaseObjectView > pDesigner; + ::comphelper::NamedValueCollection aArguments( _rAdditionalArguments ); + + Any aDataSource; + if ( _eOpenMode == E_OPEN_DESIGN ) + { + bool bAddViewTypeArg = false; + + if ( _eType == E_TABLE ) + { + if ( impl_isAlterableView_nothrow( _sName ) ) + { + pDesigner.reset( new QueryDesigner( getORB(), this, m_aCurrentFrame.getFrame(), true ) ); + bAddViewTypeArg = true; + } + else + { + pDesigner.reset( new TableDesigner( getORB(), this, m_aCurrentFrame.getFrame() ) ); + } + } + else if ( _eType == E_QUERY ) + { + pDesigner.reset( new QueryDesigner( getORB(), this, m_aCurrentFrame.getFrame(), false ) ); + bAddViewTypeArg = true; + } + aDataSource <<= m_xDataSource; + + if ( bAddViewTypeArg ) + { + const bool bQueryGraphicalMode =( _nInstigatorCommand != SID_DB_APP_EDIT_SQL_VIEW ); + aArguments.put( PROPERTY_GRAPHICAL_DESIGN, bQueryGraphicalMode ); + } + + } + else + { + pDesigner.reset( new ResultSetBrowser( getORB(), this, m_aCurrentFrame.getFrame(), _eType == E_TABLE ) ); + + if ( !aArguments.has( PROPERTY_SHOWMENU ) ) + aArguments.put( PROPERTY_SHOWMENU, Any( true ) ); + + aDataSource <<= getDatabaseName(); + } + + xRet.set( pDesigner->openExisting( aDataSource, _sName, aArguments ) ); + onDocumentOpened( _sName, _eType, _eOpenMode, xRet, nullptr ); + } + } + break; + + default: + OSL_FAIL( "OApplicationController::openElement: illegal object type!" ); + break; + } + return xRet; +} + +IMPL_LINK( OApplicationController, OnSelectContainer, void*, _pType, void ) +{ + ElementType eType = static_cast<ElementType>(reinterpret_cast< sal_IntPtr >( _pType )); + if (getContainer()) + getContainer()->selectContainer(eType); +} + +IMPL_LINK( OApplicationController, OnCreateWithPilot, void*, _pType, void ) +{ + ElementType eType = static_cast<ElementType>(reinterpret_cast< sal_IntPtr >( _pType )); + newElementWithPilot( eType ); +} + +void OApplicationController::newElementWithPilot( ElementType _eType ) +{ + utl::CloseVeto aKeepDoc( getFrame() ); + // prevent the document being closed while the wizard is open + + OSL_ENSURE( getContainer(), "OApplicationController::newElementWithPilot: without a view?" ); + + switch ( _eType ) + { + case E_REPORT: + case E_FORM: + { + std::unique_ptr<OLinkedDocumentsAccess> aHelper = getDocumentsAccess(_eType); + if ( aHelper->isConnected() ) + { + sal_Int32 nCommandType = -1; + const OUString sCurrentSelected( getCurrentlySelectedName( nCommandType ) ); + if ( E_REPORT == _eType ) + aHelper->newReportWithPilot( nCommandType, sCurrentSelected ); + else + aHelper->newFormWithPilot( nCommandType, sCurrentSelected ); + } + } + break; + case E_QUERY: + case E_TABLE: + { + std::unique_ptr<OLinkedDocumentsAccess> aHelper = getDocumentsAccess(_eType); + if ( aHelper->isConnected() ) + { + if ( E_QUERY == _eType ) + aHelper->newQueryWithPilot(); + else + aHelper->newTableWithPilot(); + } + } + break; + case E_NONE: + break; + } + + // no need for onDocumentOpened, the table wizard opens the created table by using + // XDatabaseDocumentUI::loadComponent method. +} + +Reference< XComponent > OApplicationController::newElement( ElementType _eType, const ::comphelper::NamedValueCollection& i_rAdditionalArguments, + Reference< XComponent >& o_rDocumentDefinition ) +{ + OSL_ENSURE(getContainer(),"View is NULL! -> GPF"); + + Reference< XComponent > xComponent; + o_rDocumentDefinition.clear(); + + switch ( _eType ) + { + case E_FORM: + case E_REPORT: + { + std::unique_ptr<OLinkedDocumentsAccess> aHelper = getDocumentsAccess( _eType ); + if ( !aHelper->isConnected() ) + break; + + xComponent = aHelper->newDocument( _eType == E_FORM ? ID_FORM_NEW_TEXT : ID_REPORT_NEW_TEXT, i_rAdditionalArguments, o_rDocumentDefinition ); + } + break; + + case E_QUERY: + case E_TABLE: + { + std::unique_ptr< DatabaseObjectView > pDesigner; + SharedConnection xConnection( ensureConnection() ); + if ( !xConnection.is() ) + break; + + if ( _eType == E_TABLE ) + { + pDesigner.reset( new TableDesigner( getORB(), this, getFrame() ) ); + } + else if ( _eType == E_QUERY ) + { + pDesigner.reset( new QueryDesigner( getORB(), this, getFrame(), false ) ); + } + + Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY ); + xComponent = pDesigner->createNew( xDataSource, i_rAdditionalArguments ); + } + break; + + default: + OSL_FAIL( "OApplicationController::newElement: illegal type!" ); + break; + } + + if ( xComponent.is() ) + onDocumentOpened( OUString(), _eType, E_OPEN_DESIGN, xComponent, o_rDocumentDefinition ); + + return xComponent; +} + +void OApplicationController::addContainerListener(const Reference<XNameAccess>& _xCollection) +{ + try + { + Reference< XContainer > xCont(_xCollection, UNO_QUERY); + if ( xCont.is() ) + { + // add as listener to get notified if elements are inserted or removed + TContainerVector::const_iterator aFind = std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xCont); + if ( aFind == m_aCurrentContainers.end() ) + { + xCont->addContainerListener(this); + m_aCurrentContainers.push_back(xCont); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OApplicationController::renameEntry() +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + OSL_ENSURE(getContainer(),"View is NULL! -> GPF"); + std::vector< OUString> aList; + getSelectionElementNames(aList); + + Reference< XNameAccess > xContainer = getElements(getContainer()->getElementType()); + OSL_ENSURE(aList.size() == 1,"Invalid rename call here. More than one element!"); + if ( aList.empty() ) + return; + + try + { + if ( xContainer.is() ) + { + std::unique_ptr< IObjectNameCheck > pNameChecker; + std::unique_ptr<OSaveAsDlg> xDialog; + + Reference<XRename> xRename; + const ElementType eType = getContainer()->getElementType(); + switch( eType ) + { + case E_FORM: + case E_REPORT: + { + Reference<XHierarchicalNameContainer> xHNames(xContainer, UNO_QUERY); + if ( xHNames.is() ) + { + OUString sLabel; + if ( eType == E_FORM ) + sLabel = DBA_RES(STR_FRM_LABEL); + else + sLabel = DBA_RES(STR_RPT_LABEL); + + OUString sName = *aList.begin(); + if ( xHNames->hasByHierarchicalName(sName) ) + { + xRename.set(xHNames->getByHierarchicalName(sName),UNO_QUERY); + Reference<XChild> xChild(xRename,UNO_QUERY); + if ( xChild.is() ) + { + Reference<XHierarchicalNameContainer> xParent(xChild->getParent(),UNO_QUERY); + if ( xParent.is() ) + { + xHNames = xParent; + Reference<XPropertySet>(xRename,UNO_QUERY_THROW)->getPropertyValue(PROPERTY_NAME) >>= sName; + } + } + pNameChecker.reset( new HierarchicalNameCheck( xHNames, OUString() ) ); + xDialog.reset(new OSaveAsDlg( + getFrameWeld(), getORB(), sName, sLabel, *pNameChecker, SADFlags::TitleRename)); + } + } + } + break; + case E_TABLE: + ensureConnection(); + if ( !getConnection().is() ) + break; + [[fallthrough]]; + case E_QUERY: + if ( xContainer->hasByName(*aList.begin()) ) + { + xRename.set(xContainer->getByName(*aList.begin()),UNO_QUERY); + sal_Int32 nCommandType = eType == E_QUERY ? CommandType::QUERY : CommandType::TABLE; + + ensureConnection(); + pNameChecker.reset( new DynamicTableOrQueryNameCheck( getConnection(), nCommandType ) ); + xDialog.reset(new OSaveAsDlg(getFrameWeld(), nCommandType, getORB(), getConnection(), + *aList.begin(), *pNameChecker, SADFlags::TitleRename)); + } + break; + default: + break; + } + + if (xRename.is() && xDialog) + { + + bool bTryAgain = true; + while( bTryAgain ) + { + if (xDialog->run() == RET_OK) + { + try + { + OUString sNewName; + if ( eType == E_TABLE ) + { + OUString sName = xDialog->getName(); + OUString sCatalog = xDialog->getCatalog(); + OUString sSchema = xDialog->getSchema(); + + sNewName = ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sName, false, ::dbtools::EComposeRule::InDataManipulation ); + } + else + sNewName = xDialog->getName(); + + OUString sOldName = *aList.begin(); + if ( eType == E_FORM || eType == E_REPORT ) + { + Reference<XContent> xContent(xRename,UNO_QUERY); + if ( xContent.is() ) + { + sOldName = xContent->getIdentifier()->getContentIdentifier(); + } + } + + xRename->rename(sNewName); + + if ( eType == E_TABLE ) + { + Reference<XPropertySet> xProp(xRename,UNO_QUERY); + sNewName = ::dbaui::composeTableName( m_xMetaData, xProp, ::dbtools::EComposeRule::InDataManipulation, false ); + } + getContainer()->elementReplaced( eType , sOldName, sNewName ); + + bTryAgain = false; + } + catch(const SQLException& ) + { + showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + + } + catch(const ElementExistException& e) + { + OUString sMsg(DBA_RES(STR_NAME_ALREADY_EXISTS)); + showError(SQLExceptionInfo(SQLException(sMsg.replaceAll("#", e.Message), e.Context, "S1000", 0, Any()))); + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + else + bTryAgain = false; + } + } + } + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OApplicationController::onSelectionChanged() +{ + InvalidateAll(); + + SelectionGuard aSelGuard( *m_pSelectionNotifier ); + + OApplicationView* pView = getContainer(); + if ( !pView ) + return; + + if ( pView->getSelectionCount() == 1 ) + { + const ElementType eType = pView->getElementType(); + if ( pView->isALeafSelected() ) + { + const OUString sName = pView->getQualifiedName( nullptr /* means 'first selected' */ ); + showPreviewFor( eType, sName ); + } + } +} + +void OApplicationController::showPreviewFor(const ElementType _eType,const OUString& _sName) +{ + if ( m_ePreviewMode == E_PREVIEWNONE ) + return; + + OApplicationView* pView = getContainer(); + if ( !pView ) + return; + + try + { + switch( _eType ) + { + case E_FORM: + case E_REPORT: + { + Reference< XHierarchicalNameAccess > xContainer( getElements( _eType ), UNO_QUERY_THROW ); + Reference< XContent> xContent( xContainer->getByHierarchicalName( _sName ), UNO_QUERY_THROW ); + pView->showPreview( xContent ); + } + break; + + case E_TABLE: + case E_QUERY: + { + SharedConnection xConnection( ensureConnection() ); + if ( xConnection.is() ) + pView->showPreview( getDatabaseName(), xConnection, _sName, _eType == E_TABLE ); + } + return; + + default: + OSL_FAIL( "OApplicationController::showPreviewFor: unexpected element type!" ); + break; + } + } + catch( const SQLException& ) + { + showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +IMPL_LINK_NOARG(OApplicationController, OnClipboardChanged, TransferableDataHelper*, void) +{ + OnInvalidateClipboard(); +} + +void OApplicationController::OnInvalidateClipboard() +{ + InvalidateFeature(ID_BROWSER_CUT); + InvalidateFeature(ID_BROWSER_COPY); + InvalidateFeature(ID_BROWSER_PASTE); + InvalidateFeature(SID_DB_APP_PASTE_SPECIAL); +} + +void OApplicationController::onCopyEntry() +{ + Execute(ID_BROWSER_COPY,Sequence<PropertyValue>()); +} + +void OApplicationController::onPasteEntry() +{ + Execute(ID_BROWSER_PASTE,Sequence<PropertyValue>()); +} + +void OApplicationController::onDeleteEntry() +{ + ElementType eType = getContainer()->getElementType(); + sal_uInt16 nId = 0; + switch(eType) + { + case E_TABLE: + nId = SID_DB_APP_TABLE_DELETE; + break; + case E_QUERY: + nId = SID_DB_APP_QUERY_DELETE; + break; + case E_FORM: + nId = SID_DB_APP_FORM_DELETE; + break; + case E_REPORT: + nId = SID_DB_APP_REPORT_DELETE; + break; + default: + OSL_FAIL("Invalid ElementType!"); + break; + } + executeChecked(nId,Sequence<PropertyValue>()); +} + +OUString OApplicationController::getContextMenuResourceName() const +{ + return "edit"; +} + +IController& OApplicationController::getCommandController() +{ + return *this; +} + +::comphelper::OInterfaceContainerHelper2* OApplicationController::getContextMenuInterceptors() +{ + return &m_aContextMenuInterceptors; +} + +Any OApplicationController::getCurrentSelection(weld::TreeView& rControl) const +{ + Sequence< NamedDatabaseObject > aSelection; + getContainer()->describeCurrentSelectionForControl(rControl, aSelection); + return Any( aSelection ); +} + +vcl::Window* OApplicationController::getMenuParent() const +{ + return getContainer()->getMenuParent(); +} + +void OApplicationController::adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const +{ + getContainer()->adjustMenuPosition(rControl, rPos); +} + +bool OApplicationController::requestQuickHelp(const void* /*pUserData*/, OUString& /*rText*/) const +{ + return false; +} + +bool OApplicationController::requestDrag(const weld::TreeIter& /*rEntry*/) +{ + bool bSuccess = false; + + OApplicationView* pContainer = getContainer(); + if (pContainer && pContainer->getSelectionCount()) + { + try + { + if (getContainer()->getDetailView()) + { + TreeListBox* pTreeListBox = getContainer()->getDetailView()->getTreeWindow(); + + ElementType eType = getContainer()->getElementType(); + if (eType == E_TABLE || eType == E_QUERY) + { + ODataClipboard& rExchange = static_cast<ODataClipboard&>(pTreeListBox->GetDataTransfer()); + bSuccess = copySQLObject(rExchange); + } + else + { + svx::OComponentTransferable& rExchange = static_cast<svx::OComponentTransferable&>(pTreeListBox->GetDataTransfer()); + bSuccess = copyDocObject(rExchange); + } + } + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + return bSuccess; +} + +sal_Int8 OApplicationController::queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors ) +{ + sal_Int8 nActionAskedFor = _rEvt.mnAction; + // check if we're a table or query container + OApplicationView* pView = getContainer(); + if ( !pView || isDataSourceReadOnly() ) + return DND_ACTION_NONE; + + ElementType eType = pView->getElementType(); + if ( eType == E_NONE || (eType == E_TABLE && isConnectionReadOnly()) ) + return DND_ACTION_NONE; + + // check for the concrete type + if(std::any_of(_rFlavors.begin(),_rFlavors.end(),TAppSupportedSotFunctor(eType))) + return DND_ACTION_COPY; + + if ( eType != E_FORM && eType != E_REPORT ) + return DND_ACTION_NONE; + + sal_Int8 nAction = OComponentTransferable::canExtractComponentDescriptor(_rFlavors,eType == E_FORM) ? DND_ACTION_COPY : DND_ACTION_NONE; + if ( nAction == DND_ACTION_NONE ) + return DND_ACTION_NONE; + + auto xHitEntry = pView->getEntry(_rEvt.maPosPixel); + if (xHitEntry) + { + OUString sName = pView->getQualifiedName(xHitEntry.get()); + if ( !sName.isEmpty() ) + { + Reference< XHierarchicalNameAccess > xContainer(getElements(pView->getElementType()),UNO_QUERY); + if ( xContainer.is() && xContainer->hasByHierarchicalName(sName) ) + { + Reference< XHierarchicalNameAccess > xHitObject(xContainer->getByHierarchicalName(sName),UNO_QUERY); + if ( xHitObject.is() ) + nAction = nActionAskedFor & DND_ACTION_COPYMOVE; + } + else + nAction = DND_ACTION_NONE; + } + } + return nAction; +} + +sal_Int8 OApplicationController::executeDrop( const ExecuteDropEvent& _rEvt ) +{ + OApplicationView* pView = getContainer(); + if ( !pView || pView->getElementType() == E_NONE ) + { + OSL_FAIL("OApplicationController::executeDrop: what the hell did queryDrop do?"); + // queryDrop should not have allowed us to reach this situation... + return DND_ACTION_NONE; + } + + // a TransferableDataHelper for accessing the dropped data + TransferableDataHelper aDroppedData(_rEvt.maDropEvent.Transferable); + + // reset the data of the previous async drop (if any) + if ( m_nAsyncDrop ) + Application::RemoveUserEvent(m_nAsyncDrop); + + m_nAsyncDrop = nullptr; + m_aAsyncDrop.aDroppedData.clear(); + m_aAsyncDrop.nType = pView->getElementType(); + m_aAsyncDrop.nAction = _rEvt.mnAction; + m_aAsyncDrop.bError = false; + m_aAsyncDrop.bHtml = false; + m_aAsyncDrop.aUrl.clear(); + + // loop through the available formats and see what we can do... + // first we have to check if it is our own format, if not we have to copy the stream :-( + if ( ODataAccessObjectTransferable::canExtractObjectDescriptor(aDroppedData.GetDataFlavorExVector()) ) + { + m_aAsyncDrop.aDroppedData = ODataAccessObjectTransferable::extractObjectDescriptor(aDroppedData); + + // asynchron because we some dialogs and we aren't allowed to show them while in D&D + m_nAsyncDrop = Application::PostUserEvent(LINK(this, OApplicationController, OnAsyncDrop)); + return DND_ACTION_COPY; + } + else if ( OComponentTransferable::canExtractComponentDescriptor(aDroppedData.GetDataFlavorExVector(),m_aAsyncDrop.nType == E_FORM) ) + { + m_aAsyncDrop.aDroppedData = OComponentTransferable::extractComponentDescriptor(aDroppedData); + auto xHitEntry = pView->getEntry(_rEvt.maPosPixel); + if ( xHitEntry ) + m_aAsyncDrop.aUrl = pView->getQualifiedName(xHitEntry.get()); + + sal_Int8 nAction = _rEvt.mnAction; + Reference<XContent> xContent; + m_aAsyncDrop.aDroppedData[DataAccessDescriptorProperty::Component] >>= xContent; + if ( xContent.is() ) + { + OUString sName = xContent->getIdentifier()->getContentIdentifier(); + sName = sName.copy(sName.indexOf('/') + 1); + if ( m_aAsyncDrop.aUrl.getLength() >= sName.getLength() && m_aAsyncDrop.aUrl.startsWith(sName) ) + { + m_aAsyncDrop.aDroppedData.clear(); + return DND_ACTION_NONE; + } + + // check if move is allowed, if another object with the same name exists only copy is allowed + Reference< XHierarchicalNameAccess > xContainer(getElements(m_aAsyncDrop.nType),UNO_QUERY); + Reference<XNameAccess> xNameAccess(xContainer,UNO_QUERY); + + if ( !m_aAsyncDrop.aUrl.isEmpty() && xContainer.is() && xContainer->hasByHierarchicalName(m_aAsyncDrop.aUrl) ) + xNameAccess.set(xContainer->getByHierarchicalName(m_aAsyncDrop.aUrl),UNO_QUERY); + + if ( xNameAccess.is() ) + { + Reference<XPropertySet> xProp(xContent,UNO_QUERY); + if ( xProp.is() ) + { + xProp->getPropertyValue(PROPERTY_NAME) >>= sName; + if ( xNameAccess.is() && xNameAccess->hasByName(sName) ) + nAction &= ~DND_ACTION_MOVE; + } + else + nAction &= ~DND_ACTION_MOVE; + } + } + if ( nAction != DND_ACTION_NONE ) + { + m_aAsyncDrop.nAction = nAction; + // asynchron because we some dialogs and we aren't allowed to show them while in D&D + m_nAsyncDrop = Application::PostUserEvent(LINK(this, OApplicationController, OnAsyncDrop)); + } + else + m_aAsyncDrop.aDroppedData.clear(); + return nAction; + } + else + { + SharedConnection xConnection( ensureConnection() ); + if ( xConnection.is() && m_aTableCopyHelper.copyTagTable( aDroppedData, m_aAsyncDrop, xConnection ) ) + { + // asynchron because we some dialogs and we aren't allowed to show them while in D&D + m_nAsyncDrop = Application::PostUserEvent(LINK(this, OApplicationController, OnAsyncDrop)); + return DND_ACTION_COPY; + } + } + + return DND_ACTION_NONE; +} + +Reference< XModel > SAL_CALL OApplicationController::getModel() +{ + return m_xModel; +} + +void OApplicationController::onAttachedFrame() +{ + sal_Int32 nConnectedControllers( 0 ); + try + { + Reference< XModel2 > xModel( m_xModel, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumControllers( xModel->getControllers(), UNO_SET_THROW ); + while ( xEnumControllers->hasMoreElements() ) + { + Reference< XController > xController( xEnumControllers->nextElement(), UNO_QUERY_THROW ); + ++nConnectedControllers; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if ( nConnectedControllers > 1 ) + { // we are not the first connected controller, there were already others + return; + } + + OnFirstControllerConnected(); +} + +void OApplicationController::OnFirstControllerConnected() +{ + if ( !m_xModel.is() ) + { + OSL_FAIL( "OApplicationController::OnFirstControllerConnected: too late!" ); + } + + // if we have forms or reports which contain macros/scripts, then show a warning + // which suggests the user to migrate them to the database document + Reference< XEmbeddedScripts > xDocumentScripts( m_xModel, UNO_QUERY ); + if ( xDocumentScripts.is() ) + { + // no need to show this warning, obviously the document supports embedding scripts + // into itself, so there are no "old-style" forms/reports which have macros/scripts + // themselves + return; + } + + try + { + // If the migration just happened, but was not successful, the document is reloaded. + // In this case, we should not show the warning, again. + if ( ::comphelper::NamedValueCollection::getOrDefault( m_xModel->getArgs(), u"SuppressMigrationWarning", false ) ) + return; + + // also, if the document is read-only, then no migration is possible, and the + // respective menu entry is hidden. So, don't show the warning in this case, too. + if ( Reference< XStorable >( m_xModel, UNO_QUERY_THROW )->isReadonly() ) + return; + + SQLWarning aWarning; + aWarning.Message = DBA_RES(STR_SUB_DOCS_WITH_SCRIPTS); + SQLException aDetail; + aDetail.Message = DBA_RES(STR_SUB_DOCS_WITH_SCRIPTS_DETAIL); + aWarning.NextException <<= aDetail; + + Reference< XExecutableDialog > xDialog = ErrorMessageDialog::create( getORB(), "", nullptr, Any( aWarning ) ); + xDialog->execute(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void SAL_CALL OApplicationController::attachFrame( const Reference< XFrame > & i_rxFrame ) +{ + SolarMutexGuard aSolarGuard; // avoid deadlock in XModel calls + ::osl::MutexGuard aGuard( getMutex() ); + + OGenericUnoController::attachFrame( i_rxFrame ); + if ( getFrame().is() ) + onAttachedFrame(); +} + +sal_Bool SAL_CALL OApplicationController::attachModel(const Reference< XModel > & _rxModel) +{ + ::osl::MutexGuard aGuard( getMutex() ); + const Reference< XOfficeDatabaseDocument > xOfficeDoc( _rxModel, UNO_QUERY ); + const Reference< XModifiable > xDocModify( _rxModel, UNO_QUERY ); + if ( ( !xOfficeDoc.is() || !xDocModify.is() ) && _rxModel.is() ) + { + OSL_FAIL( "OApplicationController::attachModel: invalid model!" ); + return false; + } + + if ( m_xModel.is() && ( m_xModel != _rxModel ) && ( _rxModel.is() ) ) + { + OSL_ENSURE( false, "OApplicationController::attachModel: missing implementation: setting a new model while we have another one!" ); + // we'd need to completely update our view here, close sub components, and the like + return false; + } + + const OUString aPropertyNames[] = + { + OUString(PROPERTY_URL), OUString(PROPERTY_USER) + }; + + // disconnect from old model + try + { + if ( m_xDataSource.is() ) + { + for (const auto & aPropertyName : aPropertyNames) + { + m_xDataSource->removePropertyChangeListener( aPropertyName, this ); + } + } + + Reference< XModifyBroadcaster > xBroadcaster( m_xModel, UNO_QUERY ); + if ( xBroadcaster.is() ) + xBroadcaster->removeModifyListener( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + m_xModel = _rxModel; + m_xDataSource.set( xOfficeDoc.is() ? xOfficeDoc->getDataSource() : Reference< XDataSource >(), UNO_QUERY ); + + // connect to new model + try + { + if ( m_xDataSource.is() ) + { + for (const auto & aPropertyName : aPropertyNames) + { + m_xDataSource->addPropertyChangeListener( aPropertyName, this ); + } + } + + Reference< XModifyBroadcaster > xBroadcaster( m_xModel, UNO_QUERY_THROW ); + xBroadcaster->addModifyListener( this ); + + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + // initial preview mode + if ( !m_xDataSource ) + return true; + + try + { + // to get the 'modified' for the data source + ::comphelper::NamedValueCollection aLayoutInfo( m_xDataSource->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) ); + if ( aLayoutInfo.has( INFO_PREVIEW ) ) + { + const sal_Int32 nPreviewMode( aLayoutInfo.getOrDefault( INFO_PREVIEW, sal_Int32(0) ) ); + m_ePreviewMode = static_cast< PreviewMode >( nPreviewMode ); + if ( getView() ) + getContainer()->switchPreview( m_ePreviewMode ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return true; +} + +void OApplicationController::containerFound( const Reference< XContainer >& _xContainer) +{ + try + { + if ( _xContainer.is() ) + { + m_aCurrentContainers.push_back(_xContainer); + _xContainer->addContainerListener(this); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +OUString OApplicationController::getCurrentlySelectedName(sal_Int32& _rnCommandType) const +{ + _rnCommandType = ( (getContainer()->getElementType() == E_QUERY) + ? CommandType::QUERY : ( (getContainer()->getElementType() == E_TABLE) ? CommandType::TABLE : -1 )); + + OUString sName; + if ( _rnCommandType != -1 ) + { + try + { + sName = getContainer()->getQualifiedName( nullptr ); + OSL_ENSURE( !sName.isEmpty(), "OApplicationController::getCurrentlySelectedName: no name given!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + return sName; +} + +void SAL_CALL OApplicationController::addSelectionChangeListener( const Reference< view::XSelectionChangeListener >& Listener ) +{ + m_pSelectionNotifier->addListener( Listener ); +} + +void SAL_CALL OApplicationController::removeSelectionChangeListener( const Reference< view::XSelectionChangeListener >& Listener ) +{ + m_pSelectionNotifier->removeListener( Listener ); +} + +sal_Bool SAL_CALL OApplicationController::select( const Any& _aSelection ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + Sequence< OUString> aSelection; + if ( !_aSelection.hasValue() || !getView() ) + { + getContainer()->selectElements(aSelection); + return true; + } + + // BEGIN compatibility + Sequence< NamedValue > aCurrentSelection; + if ( (_aSelection >>= aCurrentSelection) && aCurrentSelection.hasElements() ) + { + ElementType eType = E_NONE; + const NamedValue* pIter = aCurrentSelection.getConstArray(); + const NamedValue* pEnd = pIter + aCurrentSelection.getLength(); + for(;pIter != pEnd;++pIter) + { + if ( pIter->Name == "Type" ) + { + sal_Int32 nType = 0; + pIter->Value >>= nType; + if ( nType < DatabaseObject::TABLE || nType > DatabaseObject::REPORT ) + throw IllegalArgumentException(); + eType = static_cast< ElementType >( nType ); + } + else if ( pIter->Name == "Selection" ) + pIter->Value >>= aSelection; + } + + m_aSelectContainerEvent.CancelCall(); // just in case the async select request was running + getContainer()->selectContainer(eType); + getContainer()->selectElements(aSelection); + return true; + } + // END compatibility + + Sequence< NamedDatabaseObject > aSelectedObjects; + if ( !( _aSelection >>= aSelectedObjects ) ) + { + aSelectedObjects.realloc( 1 ); + if ( !( _aSelection >>= aSelectedObjects.getArray()[0] ) ) + throw IllegalArgumentException(); + } + + SelectionByElementType aSelectedElements; + ElementType eSelectedCategory = E_NONE; + for ( const NamedDatabaseObject* pObject = aSelectedObjects.getConstArray(); + pObject != aSelectedObjects.getConstArray() + aSelectedObjects.getLength(); + ++pObject + ) + { + switch ( pObject->Type ) + { + case DatabaseObject::TABLE: + case DatabaseObjectContainer::SCHEMA: + case DatabaseObjectContainer::CATALOG: + aSelectedElements[ E_TABLE ].push_back( pObject->Name ); + break; + case DatabaseObject::QUERY: + aSelectedElements[ E_QUERY ].push_back( pObject->Name ); + break; + case DatabaseObject::FORM: + case DatabaseObjectContainer::FORMS_FOLDER: + aSelectedElements[ E_FORM ].push_back( pObject->Name ); + break; + case DatabaseObject::REPORT: + case DatabaseObjectContainer::REPORTS_FOLDER: + aSelectedElements[ E_REPORT ].push_back( pObject->Name ); + break; + case DatabaseObjectContainer::TABLES: + case DatabaseObjectContainer::QUERIES: + case DatabaseObjectContainer::FORMS: + case DatabaseObjectContainer::REPORTS: + if ( eSelectedCategory != E_NONE ) + throw IllegalArgumentException( + DBA_RES(RID_STR_NO_DIFF_CAT), + *this, sal_Int16( pObject - aSelectedObjects.getConstArray() ) ); + eSelectedCategory = + ( pObject->Type == DatabaseObjectContainer::TABLES ) ? E_TABLE + : ( pObject->Type == DatabaseObjectContainer::QUERIES ) ? E_QUERY + : ( pObject->Type == DatabaseObjectContainer::FORMS ) ? E_FORM + : ( pObject->Type == DatabaseObjectContainer::REPORTS ) ? E_REPORT + : E_NONE; + break; + + default: + case DatabaseObjectContainer::DATA_SOURCE: + { + OUString sMessage( + DBA_RES(RID_STR_UNSUPPORTED_OBJECT_TYPE). + replaceFirst("$type$", OUString::number(pObject->Type))); + throw IllegalArgumentException(sMessage, *this, sal_Int16( pObject - aSelectedObjects.getConstArray() )); + } + } + } + for (auto const& selectedElement : aSelectedElements) + { + if ( selectedElement.first == m_eCurrentType ) + { + getContainer()->selectElements( comphelper::containerToSequence(selectedElement.second) ); + } + else + { + m_aPendingSelection[ selectedElement.first ] = selectedElement.second; + } + } + + m_aSelectContainerEvent.CancelCall(); // just in case the async select request was running + getContainer()->selectContainer( eSelectedCategory ); + + return true; +} + +Any SAL_CALL OApplicationController::getSelection( ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + Sequence< NamedDatabaseObject > aCurrentSelection; + const ElementType eType( getContainer()->getElementType() ); + if ( eType != E_NONE ) + { + getContainer()->describeCurrentSelectionForType( eType, aCurrentSelection ); + if ( !aCurrentSelection.hasElements() ) + { // if no objects are selected, add an entry to the sequence which describes the overall category + // which is selected currently + aCurrentSelection.realloc(1); + auto pCurrentSelection = aCurrentSelection.getArray(); + pCurrentSelection[0].Name = getDatabaseName(); + switch ( eType ) + { + case E_TABLE: pCurrentSelection[0].Type = DatabaseObjectContainer::TABLES; break; + case E_QUERY: pCurrentSelection[0].Type = DatabaseObjectContainer::QUERIES; break; + case E_FORM: pCurrentSelection[0].Type = DatabaseObjectContainer::FORMS; break; + case E_REPORT: pCurrentSelection[0].Type = DatabaseObjectContainer::REPORTS; break; + default: + OSL_FAIL( "OApplicationController::getSelection: unexpected current element type!" ); + break; + } + } + } + return Any( aCurrentSelection ); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppController.hxx b/dbaccess/source/ui/app/AppController.hxx new file mode 100644 index 000000000..b7579c0cf --- /dev/null +++ b/dbaccess/source/ui/app/AppController.hxx @@ -0,0 +1,540 @@ +/* -*- 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 <AppElementType.hxx> +#include <callbacks.hxx> +#include <commontypes.hxx> +#include <dsntypes.hxx> +#include <dbaccess/genericcontroller.hxx> +#include <linkeddocuments.hxx> +#include <TableCopyHelper.hxx> + +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/container/XContainerListener.hpp> +#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp> +#include <com/sun/star/ui/XContextMenuInterception.hpp> + +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/uno3.hxx> +#include <cppuhelper/implbase5.hxx> +#include <comphelper/interfacecontainer2.hxx> +#include <vcl/transfer.hxx> +#include <svx/dataaccessdescriptor.hxx> + +#include <memory> + +class TransferableHelper; +class TransferableClipboardListener; + +namespace com::sun::star { + namespace container { + class XNameContainer; + class XContainer; + } + namespace ucb { + class XContent; + } +} + +namespace svx +{ + class OComponentTransferable; +} + +namespace weld +{ + class TreeView; +} + +namespace dbaui +{ + class ODataClipboard; + class TreeListBox; + class SubComponentManager; + class OApplicationController; + class OApplicationView; + class OLinkedDocumentsAccess; + class SelectionNotifier; + + typedef ::cppu::ImplHelper5 < css::container::XContainerListener + , css::beans::XPropertyChangeListener + , css::sdb::application::XDatabaseDocumentUI + , css::ui::XContextMenuInterception + , css::view::XSelectionSupplier + > OApplicationController_Base; + + + class OApplicationController + :public OGenericUnoController + ,public OApplicationController_Base + ,public IControlActionListener + ,public IContextMenuProvider + { + public: + typedef std::vector< css::uno::Reference< css::container::XContainer > > TContainerVector; + + private: + + OTableCopyHelper::DropDescriptor m_aAsyncDrop; + + SharedConnection m_xDataSourceConnection; + css::uno::Reference< css::sdbc::XDatabaseMetaData > + m_xMetaData; + + TransferableDataHelper m_aSystemClipboard; // content of the clipboard + css::uno::Reference< css::beans::XPropertySet > + m_xDataSource; + css::uno::Reference< css::frame::XModel > + m_xModel; + ::comphelper::OInterfaceContainerHelper2 + m_aContextMenuInterceptors; + + TContainerVector m_aCurrentContainers; // the containers where we are listener on + ::rtl::Reference< SubComponentManager > + m_pSubComponentManager; + ::dbaccess::ODsnTypeCollection + m_aTypeCollection; + OTableCopyHelper m_aTableCopyHelper; + rtl::Reference<TransferableClipboardListener> + m_pClipboardNotifier; // notifier for changes in the clipboard + ImplSVEvent * m_nAsyncDrop; + OAsynchronousLink m_aSelectContainerEvent; + PreviewMode m_ePreviewMode; // the mode of the preview + ElementType m_eCurrentType; + bool m_bNeedToReconnect; // true when the settings of the data source were modified and the connection is no longer up to date + bool m_bSuspended; // is true when the controller was already suspended + + std::unique_ptr< SelectionNotifier > + m_pSelectionNotifier; + typedef std::map< ElementType, std::vector< OUString > > SelectionByElementType; + SelectionByElementType m_aPendingSelection; + + private: + + OApplicationView* getContainer() const; + + /** returns the database name + @return + the database name + */ + OUString getDatabaseName() const; + + /** returns the stripped database name. + @return + The stripped database name either the registered name or if it is a file url the last segment. + */ + OUString getStrippedDatabaseName() const; + + /** return the element type for given container + @param _xContainer The container where the element type has to be found + @return the element type corresponding to the given container + */ + static ElementType getElementType(const css::uno::Reference< css::container::XContainer >& _xContainer); + + /** opens a new sub frame with a table/query/form/report/view, passing additional arguments + */ + css::uno::Reference< css::lang::XComponent > openElementWithArguments( + const OUString& _sName, + ElementType _eType, + ElementOpenMode _eOpenMode, + sal_uInt16 _nInstigatorCommand, + const ::comphelper::NamedValueCollection& _rAdditionalArguments + ); + + /** opens a new frame for creation or auto pilot + @param _eType + Defines the type to open + @param i_rAdditionalArguments + Additional arguments to pass when creating the component + */ + css::uno::Reference< css::lang::XComponent > + newElement( + ElementType _eType, + const ::comphelper::NamedValueCollection& i_rAdditionalArguments, + css::uno::Reference< css::lang::XComponent >& o_rDocumentDefinition + ); + + /** creates a new database object, using an auto pilot + @param _eType + Defines the type of the object to create + @precond + Our mutex must not be locked. + @since #i39203# + */ + void newElementWithPilot( ElementType _eType ); + + /** converts the query to a view + @param _sName + The name of the query. + */ + void convertToView(const OUString& _sName); + + /** checks if the connection for the selected data source is read only. If the connection doesn't exist, <TRUE/> will be returned. + @return + <TRUE/> if read only or doesn't exist, otherwise <FALSE/> + */ + bool isConnectionReadOnly() const; + + /// fills the list with the selected entries. + void getSelectionElementNames( std::vector< OUString>& _rNames ) const; + + /// deletes the entries selected. + void deleteEntries(); + + /// renames the selected entry in the detail page + void renameEntry(); + + /** deletes queries, forms, or reports + @param _eType + the type of the objects + @param _rList + The names of the elements to delete + @param _bConfirm + determines whether the user must confirm the deletion + */ + void deleteObjects( ElementType _eType, + const std::vector< OUString>& _rList, + bool _bConfirm ); + + /** deletes tables. + @param _rList + The list of tables. + */ + void deleteTables(const std::vector< OUString>& _rList); + + /// copies the current object into clipboard + rtl::Reference<TransferableHelper> copyObject(); + + /// fills rExchange with current object if it's a Table or Query + bool copySQLObject(ODataClipboard& rExchange); + + /// fills rExchange with current object if it's a Form or Report + bool copyDocObject(svx::OComponentTransferable& rExchange); + + /// returns the nameaccess + css::uno::Reference< css::container::XNameAccess > getElements(ElementType _eType); + + /** returns the document access for the specific type + @param _eType + the type + @return std::unique_ptr<OLinkedDocumentsAccess> + */ + std::unique_ptr<OLinkedDocumentsAccess> getDocumentsAccess(ElementType _eType); + + /// returns the query definitions of the active data source. + css::uno::Reference< css::container::XNameContainer> getQueryDefinitions() const; + + /** pastes a special format from the system clipboard to the currently selected object types + @param _nFormatId + The format to be copied. + */ + void pasteFormat(SotClipboardFormatId _nFormatId); + + /** pastes a query, form or report into the data source + @param _eType + The type of the object to paste. + @param _rPasteData + The data descriptor. + @param _sParentFolder + The name of the parent folder if it exists. + @param _bMove + if <TRUE/> the name of the content must be inserted without any change, otherwise not. + @return + <TRUE/> if the paste operations was successful, otherwise <FALSE/>. + */ + bool paste( ElementType _eType, const svx::ODataAccessDescriptor& _rPasteData, const OUString& _sParentFolder = OUString(), bool _bMove = false); + + /// returns the system clipboard. + const TransferableDataHelper& getViewClipboard() const { return m_aSystemClipboard; } + + /// returns <TRUE/> if the clipboard supports a table format, otherwise <FALSE/>. + bool isTableFormat() const; + + /** fills the vector with all supported formats + @param _eType + The type for which we need the formats + @param _rFormatIds + The vector to be filled up. + */ + static void getSupportedFormats(ElementType _eType,std::vector<SotClipboardFormatId>& _rFormatIds); + + /** adds a listener to the current name access. + @param _xCollection + The collection where we want to listen on. + */ + void addContainerListener(const css::uno::Reference< css::container::XNameAccess>& _xCollection); + + /** opens a uno dialog with the currently selected data source as initialize argument + @param _sServiceName + The service name of the dialog to be executed. + */ + void openDialog(const OUString& _sServiceName); + + /** when the settings of the data source changed, + it opens a dialog which ask to close all depending documents, then recreate the connection. + The SolarMutex has to be locked before calling this. + */ + void askToReconnect(); + + /** remember a newly opened sub document for later access + */ + void onDocumentOpened( + const OUString& _rName, + const sal_Int32 _nType, + const ElementOpenMode _eMode, + const css::uno::Reference< css::lang::XComponent >& _xDocument, + const css::uno::Reference< css::lang::XComponent >& _xDefinition + ); + + /** Inserts a new object into the hierarchy given be the type. + @param _eType + Where to insert the new item. + @param _sParentFolder + The name of the parent folder if it exists. + @param _xContent + The content to insert. + @param _bMove + if <TRUE/> the name of the content must be inserted without any change, otherwise not. + @return + <TRUE/> if the insert operations was successful, otherwise <FALSE/>. + */ + bool insertHierarchyElement( ElementType _eType + ,const OUString& _sParentFolder + ,bool _bCollection = true + ,const css::uno::Reference< css::ucb::XContent>& _xContent = css::uno::Reference< css::ucb::XContent>() + ,bool _bMove = false); + /** checks if delete command or rename command is allowed + @param _eType + The element type. + @param _bDelete + If <TRUE> then the delete command should be checked. + @return + <TRUE> if the command is allowed + */ + bool isRenameDeleteAllowed(ElementType _eType, bool _bDelete) const; + /** all selected entries will be opened, or edited, or converted to a view + @param _nId + The slot which should be executed. + @param _eOpenMode + Defines the mode of opening. @see ElementOpenMode + */ + void doAction(sal_uInt16 _nId, ElementOpenMode _eOpenMode); + + /** returns the currently selected table or query name. + * + * \return the name of the currently table or query. If the tables or query container is selected otherwise an empty string will be returned. + */ + OUString getCurrentlySelectedName(sal_Int32& _rnCommandType) const; + + /** shows the preview for the given entry + */ + void showPreviewFor( const ElementType _eType,const OUString& _sName ); + + /** called we were attached to a frame + + In particular, this is called *after* the controller has been announced to the model + (XModel::connectController) + */ + void onAttachedFrame(); + + /// determines whether the given table name denotes a view which can be altered + bool impl_isAlterableView_nothrow( const OUString& _rTableOrViewName ) const; + + /** verifies the object type denotes a valid DatabaseObject, and the object name denotes an existing + object of this type. Throws if not. + */ + void impl_validateObjectTypeAndName_throw( const sal_Int32 _nObjectType, const ::std::optional< OUString >& i_rObjectName ); + + protected: + // initializing members + + // state of a feature. 'feature' may be the handle of a css::util::URL somebody requested a dispatch interface for OR a toolbar slot. + virtual FeatureState GetState(sal_uInt16 nId) const override; + // execute a feature + virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override; + + // OGenericUnoController + virtual void onLoadedMenu( const css::uno::Reference< css::frame::XLayoutManager >& _xLayoutManager ) override; + + virtual css::uno::Reference< css::frame::XModel > getPrivateModel() const override + { + return m_xModel; + } + + virtual ~OApplicationController() override; + + public: + explicit OApplicationController(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + + DECLARE_XINTERFACE( ) + DECLARE_XTYPEPROVIDER( ) + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString> SAL_CALL getSupportedServiceNames() override; + + // css::frame::XController + virtual void SAL_CALL attachFrame(const css::uno::Reference< css::frame::XFrame > & xFrame) override; + virtual sal_Bool SAL_CALL suspend(sal_Bool bSuspend) override; + virtual sal_Bool SAL_CALL attachModel(const css::uno::Reference< css::frame::XModel > & xModel) override; + virtual css::uno::Reference< css::frame::XModel > SAL_CALL getModel() override; + + // css::container::XContainerListener + virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& Event) override; + virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& Event) override; + virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& Event) override; + + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + // XDatabaseDocumentUI + virtual css::uno::Reference< css::sdbc::XDataSource > SAL_CALL getDataSource() override; + virtual css::uno::Reference< css::awt::XWindow > SAL_CALL getApplicationMainWindow() override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getActiveConnection() override; + virtual css::uno::Sequence< css::uno::Reference< css::lang::XComponent > > SAL_CALL getSubComponents() override; + virtual sal_Bool SAL_CALL isConnected( ) override; + // DO NOT CALL with getMutex() held!! + virtual void SAL_CALL connect( ) override; + virtual css::beans::Pair< ::sal_Int32, OUString > SAL_CALL identifySubComponent( const css::uno::Reference< css::lang::XComponent >& SubComponent ) override; + virtual sal_Bool SAL_CALL closeSubComponents( ) override; + virtual css::uno::Reference< css::lang::XComponent > SAL_CALL loadComponent( ::sal_Int32 ObjectType, const OUString& ObjectName, sal_Bool ForEditing ) override; + virtual css::uno::Reference< css::lang::XComponent > SAL_CALL loadComponentWithArguments( ::sal_Int32 ObjectType, const OUString& ObjectName, sal_Bool ForEditing, const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override; + virtual css::uno::Reference< css::lang::XComponent > SAL_CALL createComponent( ::sal_Int32 ObjectType, css::uno::Reference< css::lang::XComponent >& o_DocumentDefinition ) override; + virtual css::uno::Reference< css::lang::XComponent > SAL_CALL createComponentWithArguments( ::sal_Int32 ObjectType, const css::uno::Sequence< css::beans::PropertyValue >& Arguments, css::uno::Reference< css::lang::XComponent >& o_DocumentDefinition ) override; + + // XContextMenuInterception + virtual void SAL_CALL registerContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor >& Interceptor ) override; + virtual void SAL_CALL releaseContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor >& Interceptor ) override; + + // XSelectionSupplier + virtual sal_Bool SAL_CALL select( const css::uno::Any& xSelection ) override; + virtual css::uno::Any SAL_CALL getSelection( ) override; + virtual void SAL_CALL addSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override; + virtual void SAL_CALL removeSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override; + + /** retrieves the current connection, creates it if necessary + + If an error occurs, then this is either stored in the location pointed to by <arg>_pErrorInfo</arg>, + or, if <code>_pErrorInfo</code> is <NULL/>, then the error is displayed to the user. + + DO NOT CALL with getMutex() held!! + */ + const SharedConnection& ensureConnection( ::dbtools::SQLExceptionInfo* _pErrorInfo = nullptr ); + + /** retrieves the current connection + */ + const SharedConnection& getConnection() const { return m_xDataSourceConnection; } + + /// determines whether we're currently connected to the database + bool isConnected() const { return m_xDataSourceConnection.is(); } + + /** refreshes the tables + */ + void refreshTables(); + + /** called when an entry in a tree list box has been double-clicked + @param _rTree + The tree list box. + @return + <TRUE/> if the double click event has been handled by the called, and should not + be processed further. + */ + bool onEntryDoubleClick(const weld::TreeView& rTree); + + /** called when a container (category) in the application view has been selected + @param _pTree + The tree list box. + @return + <TRUE/> if the container could be changed otherwise <FALSE/> + */ + bool onContainerSelect(ElementType _eType); + + /** called when an entry in a tree view has been selected + @param _pEntry + the selected entry + */ + void onSelectionChanged(); + + /** called when a "Copy" command is executed in a tree view + */ + void onCopyEntry(); + + /** called when a "Paste" command is executed in a tree view + */ + void onPasteEntry(); + + /** called when a "Delete" command is executed in a tree view + */ + void onDeleteEntry(); + + /// called when the preview mode was changed + void previewChanged( sal_Int32 _nMode); + + /// called when an object container of any kind was found during enumerating tree view elements + void containerFound( const css::uno::Reference< css::container::XContainer >& _xContainer); + + // IController + virtual bool isDataSourceReadOnly() const override; + + // IControlActionListener overridables + virtual bool requestQuickHelp(const void* pUserData, OUString& rText) const override; + virtual bool requestDrag(const weld::TreeIter& rEntry) override; + virtual sal_Int8 queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors ) override; + virtual sal_Int8 executeDrop( const ExecuteDropEvent& _rEvt ) override; + + // IContextMenuProvider + virtual OUString getContextMenuResourceName() const override; + virtual IController& getCommandController() override; + virtual ::comphelper::OInterfaceContainerHelper2* + getContextMenuInterceptors() override; + virtual css::uno::Any getCurrentSelection(weld::TreeView& rControl) const override; + virtual vcl::Window* getMenuParent() const override; + virtual void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const override; + + void OnInvalidateClipboard(); + DECL_LINK( OnClipboardChanged, TransferableDataHelper*, void ); + DECL_LINK( OnAsyncDrop, void*, void ); + DECL_LINK( OnCreateWithPilot, void*, void ); + DECL_LINK( OnSelectContainer, void*, void ); + void OnFirstControllerConnected(); + + protected: + using OGenericUnoController::connect; + + /** disconnects from our XConnection, and cleans up this connection + */ + void disconnect(); + + // late construction + virtual bool Construct(vcl::Window* pParent) override; + virtual void describeSupportedFeatures() override; + + protected: + // XEventListener + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppControllerDnD.cxx b/dbaccess/source/ui/app/AppControllerDnD.cxx new file mode 100644 index 000000000..3cc758acd --- /dev/null +++ b/dbaccess/source/ui/app/AppControllerDnD.cxx @@ -0,0 +1,869 @@ +/* -*- 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 <memory> +#include "AppController.hxx" +#include <comphelper/property.hxx> +#include <core_resource.hxx> +#include <strings.hxx> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/container/XHierarchicalNameContainer.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp> +#include <com/sun/star/sdbcx/XDrop.hpp> +#include <dlgsave.hxx> +#include <vcl/weld.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <connectivity/dbexception.hxx> +#include <sal/log.hxx> +#include "AppView.hxx" +#include <svx/dataaccessdescriptor.hxx> +#include <svx/dbaobjectex.hxx> +#include <strings.hrc> +#include <vcl/svapp.hxx> +#include <linkeddocuments.hxx> +#include <connectivity/dbtools.hxx> +#include <dbexchange.hxx> +#include <UITools.hxx> +#include <com/sun/star/sdb/XReportDocumentsSupplier.hpp> +#include <com/sun/star/sdb/XFormDocumentsSupplier.hpp> +#include <svtools/querydelete.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <defaultobjectnamecheck.hxx> +#include <osl/mutex.hxx> +#include "subcomponentmanager.hxx" +#include <set> + +namespace dbaui +{ +using namespace ::dbtools; +using namespace ::svx; +using namespace ::svtools; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::beans; +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::frame; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::util; + +void OApplicationController::deleteTables(const std::vector< OUString>& _rList) +{ + SharedConnection xConnection( ensureConnection() ); + + Reference<XTablesSupplier> xSup(xConnection,UNO_QUERY); + OSL_ENSURE(xSup.is(),"OApplicationController::deleteTable: no XTablesSupplier!"); + if ( !xSup.is() ) + return; + + Reference<XNameAccess> xTables = xSup->getTables(); + Reference<XDrop> xDrop(xTables,UNO_QUERY); + if ( xDrop.is() ) + { + bool bConfirm = true; + std::vector< OUString>::const_iterator aEnd = _rList.end(); + for (std::vector< OUString>::const_iterator aIter = _rList.begin(); aIter != aEnd; ++aIter) + { + OUString sTableName = *aIter; + + sal_Int32 nResult = RET_YES; + if ( bConfirm ) + nResult = ::dbaui::askForUserAction(getFrameWeld(), STR_TITLE_CONFIRM_DELETION, STR_QUERY_DELETE_TABLE, _rList.size() > 1 && (aIter+1) != _rList.end(), sTableName); + + bool bUserConfirmedDelete = + ( RET_YES == nResult ) + || ( RET_ALL == nResult ); + if ( bUserConfirmedDelete && m_pSubComponentManager->closeSubFrames( sTableName, E_TABLE ) ) + { + SQLExceptionInfo aErrorInfo; + try + { + if ( xTables->hasByName(sTableName) ) + xDrop->dropByName(sTableName); + else + {// could be a view + Reference<XViewsSupplier> xViewsSup(xConnection,UNO_QUERY); + + Reference<XNameAccess> xViews; + if ( xViewsSup.is() ) + { + xViews = xViewsSup->getViews(); + if ( xViews.is() && xViews->hasByName(sTableName) ) + { + xDrop.set(xViews,UNO_QUERY); + if ( xDrop.is() ) + xDrop->dropByName(sTableName); + } + } + } + } + catch(SQLContext& e) { aErrorInfo = e; } + catch(SQLWarning& e) { aErrorInfo = e; } + catch(SQLException& e) { aErrorInfo = e; } + catch(WrappedTargetException& e) + { + SQLException aSql; + if(e.TargetException >>= aSql) + aErrorInfo = aSql; + else + OSL_FAIL("OApplicationController::implDropTable: something strange happened!"); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if ( aErrorInfo.isValid() ) + showError(aErrorInfo); + + if ( RET_ALL == nResult ) + bConfirm = false; + } + else + break; + } + } + else + { + OUString sMessage(DBA_RES(STR_MISSING_TABLES_XDROP)); + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(getFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + sMessage)); + xError->run(); + } +} + +void OApplicationController::deleteObjects( ElementType _eType, const std::vector< OUString>& _rList, bool _bConfirm ) +{ + Reference< XNameContainer > xNames( getElements( _eType ), UNO_QUERY ); + Reference< XHierarchicalNameContainer > xHierarchyName( xNames, UNO_QUERY ); + if ( !xNames.is() ) + return; + + short eResult = _bConfirm ? svtools::QUERYDELETE_YES : svtools::QUERYDELETE_ALL; + + // The list of elements to delete is allowed to contain related elements: A given element may + // be the ancestor or child of another element from the list. + // We want to ensure that ancestors get deleted first, so we normalize the list in this respect. + // #i33353# + // Note that this implicitly uses std::less< OUString > a comparison operation, which + // results in lexicographical order, which is exactly what we need, because "foo" is *before* + // any "foo/bar" in this order. + std::set< OUString > aDeleteNames(_rList.begin(), _rList.end()); + + std::set< OUString >::size_type nCount = aDeleteNames.size(); + for ( std::set< OUString >::size_type nObjectsLeft = nCount; !aDeleteNames.empty(); ) + { + std::set< OUString >::const_iterator aThisRound = aDeleteNames.begin(); + + if ( eResult != svtools::QUERYDELETE_ALL ) + { + svtools::QueryDeleteDlg_Impl aDlg(getFrameWeld(), *aThisRound); + + if ( nObjectsLeft > 1 ) + aDlg.EnableAllButton(); + + eResult = aDlg.run(); + } + + bool bSuccess = false; + + bool bUserConfirmedDelete = + ( eResult == svtools::QUERYDELETE_ALL ) + || ( eResult == svtools::QUERYDELETE_YES ); + + if ( bUserConfirmedDelete + && ( _eType != E_QUERY || m_pSubComponentManager->closeSubFrames( *aThisRound, _eType ) ) + ) + { + try + { + if ( xHierarchyName.is() ) + xHierarchyName->removeByHierarchicalName( *aThisRound ); + else + xNames->removeByName( *aThisRound ); + + bSuccess = true; + + // now that we removed the element, care for all its child elements + // which may also be a part of the list + // #i33353# + OSL_ENSURE( aThisRound->getLength() - 1 >= 0, "OApplicationController::deleteObjects: empty name?" ); + OUString sSmallestSiblingName = *aThisRound + OUStringChar( sal_Unicode( '/' + 1) ); + + std::set< OUString >::const_iterator aUpperChildrenBound = aDeleteNames.lower_bound( sSmallestSiblingName ); + for ( std::set< OUString >::const_iterator aObsolete = aThisRound; + aObsolete != aUpperChildrenBound; + ) + { + std::set< OUString >::const_iterator aNextObsolete = aObsolete; ++aNextObsolete; + aDeleteNames.erase( aObsolete ); + --nObjectsLeft; + aObsolete = aNextObsolete; + } + } + catch(const SQLException&) + { + showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch(const WrappedTargetException& e) + { + SQLException aSql; + if ( e.TargetException >>= aSql ) + showError( SQLExceptionInfo( e.TargetException ) ); + else + OSL_FAIL( "OApplicationController::deleteObjects: something strange happened!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + if ( !bSuccess ) + { + // okay, this object could not be deleted (or the user did not want to delete it), + // but continue with the rest + aDeleteNames.erase( aThisRound ); + --nObjectsLeft; + } + } +} + +void OApplicationController::deleteEntries() +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + if ( !getContainer() ) + return; + + std::vector< OUString> aList; + getSelectionElementNames(aList); + ElementType eType = getContainer()->getElementType(); + switch(eType) + { + case E_TABLE: + deleteTables(aList); + break; + case E_QUERY: + deleteObjects( E_QUERY, aList, true ); + break; + case E_FORM: + deleteObjects( E_FORM, aList, true ); + break; + case E_REPORT: + deleteObjects( E_REPORT, aList, true ); + break; + case E_NONE: + break; + } +} + +// DO NOT CALL with getMutex() held!! +const SharedConnection& OApplicationController::ensureConnection( ::dbtools::SQLExceptionInfo* _pErrorInfo ) +{ + + // This looks like double checked locking, but it is not, + // because every access (read *or* write) to m_xDataSourceConnection + // is mutexed. + // See http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html + // for what I'm referring to. + // We cannot use the TLS (thread-local storage) solution + // since support for TLS is not up to the snuff on Windows :-( + + { + ::osl::MutexGuard aGuard( getMutex() ); + + if ( m_xDataSourceConnection.is() ) + return m_xDataSourceConnection; + } + + weld::WaitObject aWO(getFrameWeld()); + Reference<XConnection> conn; + { + SolarMutexGuard aSolarGuard; + + OUString sConnectingContext(DBA_RES(STR_COULDNOTCONNECT_DATASOURCE)); + sConnectingContext = sConnectingContext.replaceFirst("$name$", getStrippedDatabaseName()); + + // do the connection *without* holding getMutex() to avoid deadlock + // when we are not in the main thread and we need username/password + // (and thus to display a dialog, which will be done by the main thread) + // and there is an event that needs getMutex() *before* us in the main thread's queue + // See fdo#63391 + conn.set( connect( getDatabaseName(), sConnectingContext, _pErrorInfo ) ); + } + + if (conn.is()) + { + ::osl::MutexGuard aGuard( getMutex() ); + if ( m_xDataSourceConnection.is() ) + { + Reference< XComponent > comp (conn, UNO_QUERY); + if(comp.is()) + { + try + { + comp->dispose(); + } + catch( const Exception& ) + { + OSL_FAIL( "dbaui::OApplicationController::ensureConnection could not dispose of temporary unused connection" ); + } + } + conn.clear(); + } + else + { + m_xDataSourceConnection.reset(conn); + SQLExceptionInfo aError; + try + { + m_xMetaData = m_xDataSourceConnection->getMetaData(); + } + catch( const SQLException& ) + { + aError = ::cppu::getCaughtException(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + if ( aError.isValid() ) + { + if ( _pErrorInfo ) + { + *_pErrorInfo = aError; + } + else + { + SolarMutexGuard aSolarGuard; + showError( aError ); + } + } + } + } + + return m_xDataSourceConnection; +} + +bool OApplicationController::isDataSourceReadOnly() const +{ + Reference<XStorable> xStore(m_xModel,UNO_QUERY); + return !xStore.is() || xStore->isReadonly(); +} + +bool OApplicationController::isConnectionReadOnly() const +{ + bool bIsConnectionReadOnly = true; + if ( m_xMetaData.is() ) + { + try + { + bIsConnectionReadOnly = m_xMetaData->isReadOnly(); + } + catch(const SQLException&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + // TODO check configuration + return bIsConnectionReadOnly; +} + +Reference< XNameAccess > OApplicationController::getElements( ElementType _eType ) +{ + Reference< XNameAccess > xElements; + try + { + switch ( _eType ) + { + case E_REPORT: + { + Reference< XReportDocumentsSupplier > xSupp( m_xModel, UNO_QUERY_THROW ); + xElements.set( xSupp->getReportDocuments(), UNO_SET_THROW ); + } + break; + + case E_FORM: + { + Reference< XFormDocumentsSupplier > xSupp( m_xModel, UNO_QUERY_THROW ); + xElements.set( xSupp->getFormDocuments(), UNO_SET_THROW ); + } + break; + + case E_QUERY: + { + xElements.set( getQueryDefinitions(), UNO_QUERY_THROW ); + } + break; + + case E_TABLE: + { + if ( m_xDataSourceConnection.is() ) + { + Reference< XTablesSupplier > xSup( getConnection(), UNO_QUERY_THROW ); + xElements.set( xSup->getTables(), UNO_SET_THROW ); + } + } + break; + + default: + break; + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return xElements; +} + +void OApplicationController::getSelectionElementNames(std::vector< OUString>& _rNames) const +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + OSL_ENSURE(getContainer(),"View isn't valid! -> GPF"); + + getContainer()->getSelectionElementNames( _rNames ); +} + +std::unique_ptr< OLinkedDocumentsAccess > OApplicationController::getDocumentsAccess( ElementType _eType ) +{ + OSL_ENSURE( ( _eType == E_TABLE ) || ( _eType == E_QUERY ) || ( _eType == E_FORM ) || ( _eType == E_REPORT ), + "OApplicationController::getDocumentsAccess: only forms and reports are supported here!" ); + + SharedConnection xConnection( ensureConnection() ); + Reference< XNameAccess > xDocContainer; + + if ( ( _eType == E_FORM ) || ( _eType == E_REPORT ) ) + { + xDocContainer.set( getElements( _eType ) ); + OSL_ENSURE( xDocContainer.is(), "OApplicationController::getDocumentsAccess: invalid container!" ); + } + + std::unique_ptr< OLinkedDocumentsAccess > pDocuments( new OLinkedDocumentsAccess( + getFrameWeld(), this, getORB(), xDocContainer, xConnection, getDatabaseName() + ) ); + return pDocuments; +} + +bool OApplicationController::copySQLObject(ODataClipboard& rExchange) +{ + bool bSuccess = false; + try + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + ElementType eType = getContainer()->getElementType(); + switch( eType ) + { + case E_TABLE: + case E_QUERY: + { + SharedConnection xConnection( ensureConnection() ); + Reference< XDatabaseMetaData> xMetaData; + if ( xConnection.is() ) + xMetaData = xConnection->getMetaData(); + + OUString sName = getContainer()->getQualifiedName( nullptr ); + if ( !sName.isEmpty() ) + { + OUString sDataSource = getDatabaseName(); + + if ( eType == E_TABLE ) + { + rExchange.Update(sDataSource, CommandType::TABLE, sName, xConnection, getNumberFormatter(xConnection, getORB()), getORB()); + } + else + { + rExchange.Update(sDataSource, CommandType::QUERY, sName, getNumberFormatter(xConnection, getORB()), getORB()); + } + bSuccess = true; + } + break; + } + default: + break; + } + } + catch(const SQLException&) + { + showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bSuccess; +} + +bool OApplicationController::copyDocObject(svx::OComponentTransferable& rExchange) +{ + bool bSuccess = false; + try + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + ElementType eType = getContainer()->getElementType(); + switch( eType ) + { + case E_FORM: + case E_REPORT: + { + std::vector< OUString> aList; + getSelectionElementNames(aList); + Reference< XHierarchicalNameAccess > xElements(getElements(eType),UNO_QUERY); + if ( xElements.is() && !aList.empty() ) + { + Reference< XContent> xContent(xElements->getByHierarchicalName(*aList.begin()),UNO_QUERY); + rExchange.Update(getDatabaseName(), xContent); + bSuccess = true; + } + break; + } + default: + break; + } + } + catch(const SQLException&) + { + showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bSuccess; +} + +rtl::Reference<TransferableHelper> OApplicationController::copyObject() +{ + try + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + ElementType eType = getContainer()->getElementType(); + switch( eType ) + { + case E_TABLE: + case E_QUERY: + { + rtl::Reference<ODataClipboard> xExchange(new ODataClipboard); + if (copySQLObject(*xExchange)) + return xExchange; + break; + } + case E_FORM: + case E_REPORT: + { + rtl::Reference<svx::OComponentTransferable> xExchange(new svx::OComponentTransferable); + if (copyDocObject(*xExchange)) + return xExchange; + break; + } + break; + default: + break; + } + } + catch(const SQLException&) + { + showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return nullptr; +} + +bool OApplicationController::paste( ElementType _eType, const svx::ODataAccessDescriptor& _rPasteData, const OUString& _sParentFolder, bool _bMove) +{ + try + { + if ( _eType == E_QUERY ) + { + sal_Int32 nCommandType = CommandType::TABLE; + if ( _rPasteData.has(DataAccessDescriptorProperty::CommandType) ) + _rPasteData[DataAccessDescriptorProperty::CommandType] >>= nCommandType; + + if ( CommandType::QUERY == nCommandType || CommandType::COMMAND == nCommandType ) + { + // read all necessary data + + OUString sCommand; + bool bEscapeProcessing = true; + + _rPasteData[DataAccessDescriptorProperty::Command] >>= sCommand; + if ( _rPasteData.has(DataAccessDescriptorProperty::EscapeProcessing) ) + _rPasteData[DataAccessDescriptorProperty::EscapeProcessing] >>= bEscapeProcessing; + + // plausibility check + bool bValidDescriptor = false; + OUString sDataSourceName = _rPasteData.getDataSource(); + if (CommandType::QUERY == nCommandType) + bValidDescriptor = sDataSourceName.getLength() && sCommand.getLength(); + else if (CommandType::COMMAND == nCommandType) + bValidDescriptor = !sCommand.isEmpty(); + if (!bValidDescriptor) + { + OSL_FAIL("OApplicationController::paste: invalid descriptor!"); + return false; + } + + // the target object name (as we'll suggest it to the user) + OUString sTargetName; + try + { + if ( CommandType::QUERY == nCommandType ) + sTargetName = sCommand; + + if ( sTargetName.isEmpty() ) + { + OUString sDefaultName = DBA_RES(STR_QRY_TITLE); + sDefaultName = sDefaultName.getToken( 0, ' ' ); + + Reference< XNameAccess > xQueries( getQueryDefinitions(), UNO_QUERY_THROW ); + sTargetName = ::dbtools::createUniqueName( xQueries, sDefaultName, false ); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + Reference< XPropertySet > xQuery; + if (CommandType::QUERY == nCommandType) + { + // need to extract the statement and the escape processing flag from the query object + bool bSuccess = false; + try + { + // the concrete query + Reference< XQueryDefinitionsSupplier > xSourceQuerySup( + getDataSourceByName( sDataSourceName, getFrameWeld(), getORB(), nullptr ), + UNO_QUERY_THROW ); + Reference< XNameAccess > xQueries( xSourceQuerySup->getQueryDefinitions(), UNO_SET_THROW ); + if ( xQueries->hasByName( sCommand ) ) + { + xQuery.set( xQueries->getByName(sCommand), UNO_QUERY_THROW ); + bSuccess = true; + } + } + catch(SQLException&) { throw; } // caught and handled by the outer catch + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if (!bSuccess) + { + OSL_FAIL("OApplicationController::paste: could not extract the source query object!"); + // TODO: maybe this is worth an error message to be displayed to the user... + return false; + } + } + + Reference< XNameContainer > xDestQueries = getQueryDefinitions(); + Reference< XSingleServiceFactory > xQueryFactory(xDestQueries, UNO_QUERY); + if (!xQueryFactory.is()) + { + OSL_FAIL("OApplicationController::paste: invalid destination query container!"); + return false; + } + + // here we have everything needed to create a new query object... + // ... ehm, except a new name + ensureConnection(); + + DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::QUERY ); + ::dbtools::SQLExceptionInfo aDummy; + bool bNeedAskForName = ( sCommand.isEmpty() ) + /* we did not have a source name, so the target name was auto-generated */ + || ( !aNameChecker.isNameValid( sTargetName, aDummy ) ); + /* name is invalid in the target DB (e.g. because it already + has a /table/ with that name) */ + if ( bNeedAskForName ) + { + OSaveAsDlg aAskForName(getFrameWeld(), + CommandType::QUERY, + getORB(), + getConnection(), + sTargetName, + aNameChecker, + SADFlags::AdditionalDescription | SADFlags::TitlePasteAs ); + if ( RET_OK != aAskForName.run() ) + // cancelled by the user + return false; + sTargetName = aAskForName.getName(); + } + + // create a new object + Reference< XPropertySet > xNewQuery(xQueryFactory->createInstance(), UNO_QUERY); + OSL_ENSURE(xNewQuery.is(), "OApplicationController::paste: invalid object created by factory!"); + if (xNewQuery.is()) + { + // initialize + if ( xQuery.is() ) + ::comphelper::copyProperties(xQuery,xNewQuery); + else + { + xNewQuery->setPropertyValue(PROPERTY_COMMAND,Any(sCommand)); + xNewQuery->setPropertyValue(PROPERTY_ESCAPE_PROCESSING,Any(bEscapeProcessing)); + } + // insert + xDestQueries->insertByName( sTargetName, Any(xNewQuery) ); + xNewQuery.set(xDestQueries->getByName( sTargetName),UNO_QUERY); + if ( xQuery.is() && xNewQuery.is() ) + { + Reference<XColumnsSupplier> xSrcColSup(xQuery,UNO_QUERY); + Reference<XColumnsSupplier> xDstColSup(xNewQuery,UNO_QUERY); + if ( xSrcColSup.is() && xDstColSup.is() ) + { + Reference<XNameAccess> xSrcNameAccess = xSrcColSup->getColumns(); + Reference<XNameAccess> xDstNameAccess = xDstColSup->getColumns(); + Reference<XDataDescriptorFactory> xFac(xDstNameAccess,UNO_QUERY); + Reference<XAppend> xAppend(xFac,UNO_QUERY); + if ( xSrcNameAccess.is() && xDstNameAccess.is() && xSrcNameAccess->hasElements() && xAppend.is() ) + { + Reference<XPropertySet> xDstProp(xFac->createDataDescriptor()); + + Sequence< OUString> aSeq = xSrcNameAccess->getElementNames(); + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + for( ; pIter != pEnd ; ++pIter) + { + Reference<XPropertySet> xSrcProp(xSrcNameAccess->getByName(*pIter),UNO_QUERY); + ::comphelper::copyProperties(xSrcProp,xDstProp); + xAppend->appendByDescriptor(xDstProp); + } + } + } + } + } + } + else + SAL_WARN("dbaccess", "There should be a sequence in it!"); + return true; + } + else if ( _rPasteData.has(DataAccessDescriptorProperty::Component) ) // forms or reports + { + Reference<XContent> xContent; + _rPasteData[DataAccessDescriptorProperty::Component] >>= xContent; + return insertHierarchyElement(_eType,_sParentFolder,Reference<XNameAccess>(xContent,UNO_QUERY).is(),xContent,_bMove); + } + } + catch(const SQLException&) { showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return false; +} + +Reference<XNameContainer> OApplicationController::getQueryDefinitions() const +{ + Reference<XQueryDefinitionsSupplier> xSet(m_xDataSource,UNO_QUERY); + Reference<XNameContainer> xNames; + if ( xSet.is() ) + { + xNames.set(xSet->getQueryDefinitions(),UNO_QUERY); + } + return xNames; +} + +void OApplicationController::getSupportedFormats(ElementType _eType,std::vector<SotClipboardFormatId>& _rFormatIds) +{ + switch( _eType ) + { + case E_TABLE: + _rFormatIds.push_back(SotClipboardFormatId::DBACCESS_TABLE); + _rFormatIds.push_back(SotClipboardFormatId::RTF); + _rFormatIds.push_back(SotClipboardFormatId::HTML); + [[fallthrough]]; + case E_QUERY: + _rFormatIds.push_back(SotClipboardFormatId::DBACCESS_QUERY); + break; + default: + break; + } +} + +bool OApplicationController::isTableFormat() const +{ + return OTableCopyHelper::isTableFormat(getViewClipboard()); +} + +IMPL_LINK_NOARG( OApplicationController, OnAsyncDrop, void*, void ) +{ + m_nAsyncDrop = nullptr; + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + if ( m_aAsyncDrop.nType == E_TABLE ) + { + SharedConnection xConnection( ensureConnection() ); + if ( xConnection.is() ) + m_aTableCopyHelper.asyncCopyTagTable( m_aAsyncDrop, getDatabaseName(), xConnection ); + } + else + { + if ( paste(m_aAsyncDrop.nType,m_aAsyncDrop.aDroppedData,m_aAsyncDrop.aUrl,m_aAsyncDrop.nAction == DND_ACTION_MOVE) + && m_aAsyncDrop.nAction == DND_ACTION_MOVE ) + { + Reference<XContent> xContent; + m_aAsyncDrop.aDroppedData[DataAccessDescriptorProperty::Component] >>= xContent; + std::vector< OUString> aList; + sal_Int32 nIndex = 0; + OUString sName = xContent->getIdentifier()->getContentIdentifier(); + std::u16string_view sErase = o3tl::getToken(sName,0,'/',nIndex); // we don't want to have the "private:forms" part + if ( nIndex != -1 ) + { + aList.push_back(sName.copy(sErase.size() + 1)); + deleteObjects( m_aAsyncDrop.nType, aList, false ); + } + } + } + + m_aAsyncDrop.aDroppedData.clear(); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppControllerGen.cxx b/dbaccess/source/ui/app/AppControllerGen.cxx new file mode 100644 index 000000000..22dfb3663 --- /dev/null +++ b/dbaccess/source/ui/app/AppControllerGen.cxx @@ -0,0 +1,736 @@ +/* -*- 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 "AppController.hxx" +#include "AppDetailView.hxx" +#include "AppView.hxx" +#include <core_resource.hxx> +#include <dbaccess_slotid.hrc> +#include <strings.hrc> +#include <strings.hxx> +#include <defaultobjectnamecheck.hxx> +#include <dlgsave.hxx> +#include <UITools.hxx> +#include "subcomponentmanager.hxx" + +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/container/XHierarchicalNameContainer.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/sdbcx/XRename.hpp> +#include <com/sun/star/sdb/ErrorCondition.hpp> +#include <com/sun/star/sdb/application/DatabaseObject.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/util/XRefreshable.hpp> + +#include <cppuhelper/exc_hlp.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/sqlerror.hxx> +#include <sfx2/mailmodelapi.hxx> +#include <svx/dbaexchange.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <vcl/mnemonic.hxx> +#include <vcl/svapp.hxx> +#include <vcl/syswin.hxx> +#include <vcl/weld.hxx> +#include <osl/mutex.hxx> + +namespace dbaui +{ +using namespace ::dbtools; +using namespace ::connectivity; +using namespace ::svx; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ui::dialogs; +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::ucb; + +using ::com::sun::star::ui::XContextMenuInterceptor; + +namespace DatabaseObject = ::com::sun::star::sdb::application::DatabaseObject; +namespace ErrorCondition = ::com::sun::star::sdb::ErrorCondition; + +void OApplicationController::convertToView(const OUString& _sName) +{ + try + { + SharedConnection xConnection( getConnection() ); + Reference< XQueriesSupplier > xSup( xConnection, UNO_QUERY_THROW ); + Reference< XNameAccess > xQueries( xSup->getQueries(), UNO_SET_THROW ); + Reference< XPropertySet > xSourceObject( xQueries->getByName( _sName ), UNO_QUERY_THROW ); + + Reference< XTablesSupplier > xTablesSup( xConnection, UNO_QUERY_THROW ); + Reference< XNameAccess > xTables( xTablesSup->getTables(), UNO_SET_THROW ); + + Reference< XDatabaseMetaData > xMeta = xConnection->getMetaData(); + + const OUString aDefaultName = ::dbaui::createDefaultName(xMeta, xTables, DBA_RES(STR_TBL_TITLE).getToken(0, ' ')); + + DynamicTableOrQueryNameCheck aNameChecker( xConnection, CommandType::TABLE ); + OSaveAsDlg aDlg(getFrameWeld(), CommandType::TABLE, getORB(), xConnection, aDefaultName, aNameChecker, SADFlags::NONE); + if (aDlg.run() == RET_OK) + { + OUString sName = aDlg.getName(); + OUString sCatalog = aDlg.getCatalog(); + OUString sSchema = aDlg.getSchema(); + OUString sNewName( + ::dbtools::composeTableName( xMeta, sCatalog, sSchema, sName, false, ::dbtools::EComposeRule::InTableDefinitions ) ); + Reference<XPropertySet> xView = ::dbaui::createView(sNewName,xConnection,xSourceObject); + if ( !xView.is() ) + throw SQLException(DBA_RES(STR_NO_TABLE_FORMAT_INSIDE),*this, "S1000",0,Any()); + getContainer()->elementAdded(E_TABLE,sNewName,Any(xView)); + } + } + catch(const SQLException& ) + { + showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OApplicationController::pasteFormat(SotClipboardFormatId _nFormatId) +{ + if ( _nFormatId == SotClipboardFormatId::NONE ) + return; + + try + { + const TransferableDataHelper& rClipboard = getViewClipboard(); + ElementType eType = getContainer()->getElementType(); + if ( eType == E_TABLE ) + { + m_aTableCopyHelper.pasteTable( _nFormatId, rClipboard, getDatabaseName(), ensureConnection() ); + } + else + paste( eType, ODataAccessObjectTransferable::extractObjectDescriptor( rClipboard ) ); + + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OApplicationController::openDialog( const OUString& _sServiceName ) +{ + try + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + weld::WaitObject aWO(getFrameWeld()); + + Sequence< Any > aArgs(3); + auto pArgs = aArgs.getArray(); + sal_Int32 nArgPos = 0; + + Reference< css::awt::XWindow> xWindow = getTopMostContainerWindow(); + if ( !xWindow.is() ) + { + OSL_ENSURE( getContainer(), "OApplicationController::Construct: have no view!" ); + if ( getContainer() ) + xWindow = VCLUnoHelper::GetInterface(getView()->Window::GetParent()); + } + // the parent window + pArgs[nArgPos++] <<= PropertyValue( "ParentWindow", + 0, + Any(xWindow), + PropertyState_DIRECT_VALUE); + + // the initial selection + OUString sInitialSelection; + if ( getContainer() ) + sInitialSelection = getDatabaseName(); + if ( !sInitialSelection.isEmpty() ) + { + pArgs[ nArgPos++ ] <<= PropertyValue( + "InitialSelection", 0, + Any( sInitialSelection ), PropertyState_DIRECT_VALUE ); + } + + SharedConnection xConnection( getConnection() ); + if ( xConnection.is() ) + { + pArgs[ nArgPos++ ] <<= PropertyValue( + PROPERTY_ACTIVE_CONNECTION, 0, + makeAny( xConnection ), PropertyState_DIRECT_VALUE ); + } + aArgs.realloc( nArgPos ); + + // create the dialog + Reference< XExecutableDialog > xAdminDialog; + xAdminDialog.set( + getORB()->getServiceManager()->createInstanceWithArgumentsAndContext(_sServiceName, aArgs, getORB()), + UNO_QUERY); + + // execute it + if (xAdminDialog.is()) + xAdminDialog->execute(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OApplicationController::refreshTables() +{ + if ( !(getContainer() && getContainer()->getDetailView()) ) + return; + + weld::WaitObject aWO(getFrameWeld()); + OSL_ENSURE(getContainer()->getElementType() == E_TABLE,"Only allowed when the tables container is selected!"); + try + { + Reference<XRefreshable> xRefresh(getElements(E_TABLE),UNO_QUERY); + if ( xRefresh.is() ) + xRefresh->refresh(); + } + catch(const Exception&) + { + OSL_FAIL("Could not refresh tables!"); + } + + getContainer()->getDetailView()->clearPages(false); + getContainer()->getDetailView()->createTablesPage( ensureConnection() ); +} + +void SAL_CALL OApplicationController::propertyChange( const PropertyChangeEvent& evt ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + if ( evt.PropertyName == PROPERTY_USER ) + { + m_bNeedToReconnect = true; + InvalidateFeature(SID_DB_APP_STATUS_USERNAME); + } + else if ( evt.PropertyName == PROPERTY_URL ) + { + m_bNeedToReconnect = true; + InvalidateFeature(SID_DB_APP_STATUS_DBNAME); + InvalidateFeature(SID_DB_APP_STATUS_TYPE); + InvalidateFeature(SID_DB_APP_STATUS_HOSTNAME); + } + else if ( PROPERTY_NAME == evt.PropertyName ) + { + const ElementType eType = getContainer()->getElementType(); + if ( eType == E_FORM || eType == E_REPORT ) + { + OUString sOldName,sNewName; + evt.OldValue >>= sOldName; + evt.NewValue >>= sNewName; + + // if the old name is empty, then this is a newly inserted content. We're notified of it via the + // elementInserted method, so there's no need to handle it here. + + if ( !sOldName.isEmpty() ) + { + Reference<XChild> xChild(evt.Source,UNO_QUERY); + if ( xChild.is() ) + { + Reference<XContent> xContent(xChild->getParent(),UNO_QUERY); + if ( xContent.is() ) + sOldName = xContent->getIdentifier()->getContentIdentifier() + "/" + sOldName; + } + + getContainer()->elementReplaced( eType , sOldName, sNewName ); + } + } + } + + EventObject aEvt; + aEvt.Source = m_xModel; + modified(aEvt); +} + +Reference< XDataSource > SAL_CALL OApplicationController::getDataSource() +{ + ::osl::MutexGuard aGuard( getMutex() ); + Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY ); + return xDataSource; +} + +Reference< XWindow > SAL_CALL OApplicationController::getApplicationMainWindow() +{ + ::osl::MutexGuard aGuard( getMutex() ); + Reference< XFrame > xFrame( getFrame(), UNO_SET_THROW ); + Reference< XWindow > xWindow( xFrame->getContainerWindow(), UNO_SET_THROW ); + return xWindow; +} + +Sequence< Reference< XComponent > > SAL_CALL OApplicationController::getSubComponents() +{ + ::osl::MutexGuard aGuard( getMutex() ); + return m_pSubComponentManager->getSubComponents(); +} + +Reference< XConnection > SAL_CALL OApplicationController::getActiveConnection() +{ + ::osl::MutexGuard aGuard( getMutex() ); + return m_xDataSourceConnection.getTyped(); +} + +sal_Bool SAL_CALL OApplicationController::isConnected( ) +{ + ::osl::MutexGuard aGuard( getMutex() ); + return m_xDataSourceConnection.is(); +} + +void SAL_CALL OApplicationController::connect( ) +{ + SQLExceptionInfo aError; + SharedConnection xConnection = ensureConnection( &aError ); + if ( !xConnection.is() ) + { + if ( aError.isValid() ) + aError.doThrow(); + + // no particular error, but nonetheless could not connect -> throw a generic exception + OUString sConnectingContext( DBA_RES( STR_COULDNOTCONNECT_DATASOURCE ) ); + ::dbtools::throwGenericSQLException( sConnectingContext.replaceFirst( "$name$", getStrippedDatabaseName() ), *this ); + } +} + +beans::Pair< ::sal_Int32, OUString > SAL_CALL OApplicationController::identifySubComponent( const Reference< XComponent >& i_rSubComponent ) +{ + ::osl::MutexGuard aGuard( getMutex() ); + + sal_Int32 nType = -1; + OUString sName; + + if ( !m_pSubComponentManager->lookupSubComponent( i_rSubComponent, sName, nType ) ) + throw IllegalArgumentException( OUString(), *this, 1 ); + + if ( nType == SID_DB_APP_DSRELDESIGN ) + // this is somewhat hacky ... we're expected to return a DatabaseObject value. However, there is no such + // value for the relation design. /me thinks we should change the API definition here ... + nType = -1; + + return beans::Pair< ::sal_Int32, OUString >( nType, sName ); +} + +sal_Bool SAL_CALL OApplicationController::closeSubComponents( ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + return m_pSubComponentManager->closeSubComponents(); +} + +namespace +{ + ElementType lcl_objectType2ElementType( const sal_Int32 _nObjectType ) + { + ElementType eType( E_NONE ); + switch ( _nObjectType ) + { + case DatabaseObject::TABLE: eType = E_TABLE; break; + case DatabaseObject::QUERY: eType = E_QUERY; break; + case DatabaseObject::FORM: eType = E_FORM; break; + case DatabaseObject::REPORT: eType = E_REPORT; break; + default: + OSL_FAIL( "lcl_objectType2ElementType: unsupported object type!" ); + // this should have been caught earlier + } + return eType; + } +} + +void OApplicationController::impl_validateObjectTypeAndName_throw( const sal_Int32 _nObjectType, const ::std::optional< OUString >& i_rObjectName ) +{ + // ensure we're connected + if ( !isConnected() ) + { + SQLError aError; + aError.raiseException( ErrorCondition::DB_NOT_CONNECTED, *this ); + } + + // ensure a proper object type + if ( ( _nObjectType != DatabaseObject::TABLE ) + && ( _nObjectType != DatabaseObject::QUERY ) + && ( _nObjectType != DatabaseObject::FORM ) + && ( _nObjectType != DatabaseObject::REPORT ) + ) + throw IllegalArgumentException( OUString(), *this, 1 ); + + if ( !i_rObjectName ) + return; + + // ensure an existing object + Reference< XNameAccess > xContainer( getElements( lcl_objectType2ElementType( _nObjectType ) ) ); + if ( !xContainer.is() ) + // all possible reasons for this (e.g. not being connected currently) should + // have been handled before + throw RuntimeException( OUString(), *this ); + + bool bExistentObject = false; + switch ( _nObjectType ) + { + case DatabaseObject::TABLE: + case DatabaseObject::QUERY: + bExistentObject = xContainer->hasByName( *i_rObjectName ); + break; + case DatabaseObject::FORM: + case DatabaseObject::REPORT: + { + Reference< XHierarchicalNameAccess > xHierarchy( xContainer, UNO_QUERY_THROW ); + bExistentObject = xHierarchy->hasByHierarchicalName( *i_rObjectName ); + } + break; + } + + if ( !bExistentObject ) + throw NoSuchElementException( *i_rObjectName, *this ); +} + +Reference< XComponent > SAL_CALL OApplicationController::loadComponent( ::sal_Int32 ObjectType, + const OUString& ObjectName, sal_Bool ForEditing ) +{ + return loadComponentWithArguments( ObjectType, ObjectName, ForEditing, Sequence< PropertyValue >() ); +} + +Reference< XComponent > SAL_CALL OApplicationController::loadComponentWithArguments( ::sal_Int32 ObjectType, + const OUString& ObjectName, sal_Bool ForEditing, const Sequence< PropertyValue >& Arguments ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + impl_validateObjectTypeAndName_throw( ObjectType, ObjectName ); + + Reference< XComponent > xComponent( openElementWithArguments( + ObjectName, + lcl_objectType2ElementType( ObjectType ), + ForEditing ? E_OPEN_DESIGN : E_OPEN_NORMAL, + ForEditing ? SID_DB_APP_EDIT : SID_DB_APP_OPEN, + ::comphelper::NamedValueCollection( Arguments ) + ) ); + + return xComponent; +} + +Reference< XComponent > SAL_CALL OApplicationController::createComponent( ::sal_Int32 i_nObjectType, Reference< XComponent >& o_DocumentDefinition ) +{ + return createComponentWithArguments( i_nObjectType, Sequence< PropertyValue >(), o_DocumentDefinition ); +} + +Reference< XComponent > SAL_CALL OApplicationController::createComponentWithArguments( ::sal_Int32 i_nObjectType, const Sequence< PropertyValue >& i_rArguments, Reference< XComponent >& o_DocumentDefinition ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + impl_validateObjectTypeAndName_throw( i_nObjectType, ::std::optional< OUString >() ); + + Reference< XComponent > xComponent( newElement( + lcl_objectType2ElementType( i_nObjectType ), + ::comphelper::NamedValueCollection( i_rArguments ), + o_DocumentDefinition + ) ); + + return xComponent; +} + +void SAL_CALL OApplicationController::registerContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor ) +{ + if ( Interceptor.is() ) + m_aContextMenuInterceptors.addInterface( Interceptor ); +} + +void SAL_CALL OApplicationController::releaseContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor ) +{ + m_aContextMenuInterceptors.removeInterface( Interceptor ); +} + +void OApplicationController::previewChanged( sal_Int32 _nMode ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + if ( m_xDataSource.is() && !isDataSourceReadOnly() ) + { + try + { + ::comphelper::NamedValueCollection aLayoutInfo( m_xDataSource->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) ); + sal_Int32 nOldMode = aLayoutInfo.getOrDefault( "Preview", _nMode ); + if ( nOldMode != _nMode ) + { + aLayoutInfo.put( "Preview", _nMode ); + m_xDataSource->setPropertyValue( PROPERTY_LAYOUTINFORMATION, Any( aLayoutInfo.getPropertyValues() ) ); + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + InvalidateFeature(SID_DB_APP_DISABLE_PREVIEW); + InvalidateFeature(SID_DB_APP_VIEW_DOCINFO_PREVIEW); + InvalidateFeature(SID_DB_APP_VIEW_DOC_PREVIEW); +} + +void OApplicationController::askToReconnect() +{ + if ( !m_bNeedToReconnect ) + return; + + m_bNeedToReconnect = false; + bool bClear = true; + if ( !m_pSubComponentManager->empty() ) + { + std::unique_ptr<weld::MessageDialog> xQry(Application::CreateMessageDialog(getFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + DBA_RES(STR_QUERY_CLOSEDOCUMENTS))); + switch (xQry->run()) + { + case RET_YES: + closeSubComponents(); + break; + default: + bClear = false; + break; + } + } + if ( bClear ) + { + ElementType eType = getContainer()->getElementType(); + disconnect(); + getContainer()->getDetailView()->clearPages(false); + getContainer()->selectContainer(E_NONE); // invalidate the old selection + m_eCurrentType = E_NONE; + getContainer()->selectContainer(eType); // reselect the current one again + } +} + +OUString OApplicationController::getDatabaseName() const +{ + OUString sDatabaseName; + try + { + if ( m_xDataSource.is() ) + { + OSL_VERIFY( m_xDataSource->getPropertyValue( PROPERTY_NAME ) >>= sDatabaseName ); + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return sDatabaseName; +} + +OUString OApplicationController::getStrippedDatabaseName() const +{ + OUString sDatabaseName; + return ::dbaui::getStrippedDatabaseName( m_xDataSource, sDatabaseName ); +} + +void OApplicationController::onDocumentOpened( const OUString& _rName, const sal_Int32 _nType, + const ElementOpenMode _eMode, const Reference< XComponent >& _xDocument, const Reference< XComponent >& _rxDefinition ) +{ + if ( !_xDocument.is() ) + return; + + try + { + OSL_ENSURE( _xDocument.is(), "OApplicationController::onDocumentOpened: is there any *valid* scenario where this fails?" ); + m_pSubComponentManager->onSubComponentOpened( _rName, _nType, _eMode, _xDocument.is() ? _xDocument : _rxDefinition ); + + if ( _rxDefinition.is() ) + { + Reference< XPropertySet > xProp( _rxDefinition, UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xPSI( xProp->getPropertySetInfo(), UNO_SET_THROW ); + xProp->addPropertyChangeListener( PROPERTY_NAME, static_cast< XPropertyChangeListener* >( this ) ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +bool OApplicationController::insertHierarchyElement(ElementType _eType, const OUString& _sParentFolder, bool _bCollection, const Reference<XContent>& _xContent, bool _bMove) +{ + Reference<XHierarchicalNameContainer> xNames(getElements(_eType), UNO_QUERY); + return dbaui::insertHierarchyElement(getFrameWeld() + ,getORB() + ,xNames + ,_sParentFolder + ,_eType == E_FORM + ,_bCollection + ,_xContent + ,_bMove); +} + +bool OApplicationController::isRenameDeleteAllowed(ElementType _eType, bool _bDelete) const +{ + ElementType eType = getContainer()->getElementType(); + bool bEnabled = !isDataSourceReadOnly() && eType == _eType; + if ( bEnabled ) + { + + if ( E_TABLE == eType ) + bEnabled = !isConnectionReadOnly() && getContainer()->isALeafSelected(); + + bool bCompareRes = false; + if ( _bDelete ) + bCompareRes = getContainer()->getSelectionCount() > 0; + else + { + bCompareRes = getContainer()->getSelectionCount() == 1; + if ( bEnabled && bCompareRes && E_TABLE == eType ) + { + std::vector< OUString> aList; + getSelectionElementNames(aList); + + try + { + Reference< XNameAccess > xContainer = const_cast<OApplicationController*>(this)->getElements(eType); + bEnabled = (xContainer.is() && xContainer->hasByName(*aList.begin())); + if ( bEnabled ) + bEnabled = Reference<XRename>(xContainer->getByName(*aList.begin()),UNO_QUERY).is(); + } + catch(Exception&) + { + bEnabled = false; + } + } + } + + bEnabled = bEnabled && bCompareRes; + } + return bEnabled; +} + +void OApplicationController::onLoadedMenu(const Reference< css::frame::XLayoutManager >& _xLayoutManager) +{ + + if ( !_xLayoutManager.is() ) + return; + + static constexpr OUStringLiteral s_sStatusbar = u"private:resource/statusbar/statusbar"; + _xLayoutManager->createElement( s_sStatusbar ); + _xLayoutManager->requestElement( s_sStatusbar ); + + if ( getContainer() ) + { + // we need to share the "mnemonic space": + MnemonicGenerator aMnemonicGenerator; + // - the menu already has mnemonics + if (SystemWindow* pSystemWindow = getContainer()->GetSystemWindow()) + pSystemWindow->CollectMenuBarMnemonics(aMnemonicGenerator); + // - the icons should use automatic ones + getContainer()->createIconAutoMnemonics( aMnemonicGenerator ); + // - as well as the entries in the task pane + getContainer()->setTaskExternalMnemonics( aMnemonicGenerator ); + } + + Execute( SID_DB_APP_VIEW_FORMS, Sequence< PropertyValue >() ); + InvalidateAll(); +} + +void OApplicationController::doAction(sal_uInt16 _nId, const ElementOpenMode _eOpenMode) +{ + std::vector< OUString> aList; + getSelectionElementNames(aList); + ElementType eType = getContainer()->getElementType(); + ::comphelper::NamedValueCollection aArguments; + ElementOpenMode eOpenMode = _eOpenMode; + if ( eType == E_REPORT && E_OPEN_FOR_MAIL == _eOpenMode ) + { + aArguments.put("Hidden",true); + eOpenMode = E_OPEN_NORMAL; + } + + std::vector< std::pair< OUString ,Reference< XModel > > > aComponents; + for (auto const& elem : aList) + { + if ( SID_DB_APP_CONVERTTOVIEW == _nId ) + convertToView(elem); + else + { + Reference< XModel > xModel( openElementWithArguments( elem, eType, eOpenMode, _nId,aArguments ), UNO_QUERY ); + aComponents.emplace_back( elem, xModel ); + } + } + + // special handling for mail, if more than one document is selected attach them all + if ( _eOpenMode != E_OPEN_FOR_MAIL ) + return; + + + SfxMailModel aSendMail; + SfxMailModel::SendMailResult eResult = SfxMailModel::SEND_MAIL_OK; + for (auto const& component : aComponents) + { + try + { + Reference< XModel > xModel = component.second; + + // Send document as e-Mail using stored/default type + eResult = aSendMail.AttachDocument(xModel,component.first); + ::comphelper::disposeComponent(xModel); + if (eResult != SfxMailModel::SEND_MAIL_OK) + break; + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + if ( !aSendMail.IsEmpty() ) + aSendMail.Send( getFrame() ); +} + +ElementType OApplicationController::getElementType(const Reference< XContainer >& _xContainer) +{ + ElementType eRet = E_NONE; + Reference<XServiceInfo> xServiceInfo(_xContainer,UNO_QUERY); + if ( xServiceInfo.is() ) + { + if ( xServiceInfo->supportsService(SERVICE_SDBCX_TABLES) ) + eRet = E_TABLE; + else if ( xServiceInfo->supportsService(SERVICE_NAME_FORM_COLLECTION) ) + eRet = E_FORM; + else if ( xServiceInfo->supportsService(SERVICE_NAME_REPORT_COLLECTION) ) + eRet = E_REPORT; + else + eRet = E_QUERY; + } + return eRet; +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppDetailPageHelper.cxx b/dbaccess/source/ui/app/AppDetailPageHelper.cxx new file mode 100644 index 000000000..b7506744d --- /dev/null +++ b/dbaccess/source/ui/app/AppDetailPageHelper.cxx @@ -0,0 +1,1221 @@ +/* -*- 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 "AppDetailPageHelper.hxx" +#include <tools/diagnose_ex.h> +#include <tabletree.hxx> +#include <dbtreelistbox.hxx> +#include <com/sun/star/awt/PopupMenu.hpp> +#include <com/sun/star/awt/XTabController.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/form/XLoadable.hpp> +#include <com/sun/star/frame/thePopupMenuControllerFactory.hpp> +#include <com/sun/star/frame/XLayoutManager.hpp> +#include <com/sun/star/frame/Frame.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/frame/XFrames.hpp> +#include <com/sun/star/frame/XFramesSupplier.hpp> +#include <com/sun/star/frame/XPopupMenuController.hpp> +#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp> +#include <com/sun/star/sdb/application/DatabaseObject.hpp> +#include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/ucb/Command.hpp> +#include <com/sun/star/util/XCloseable.hpp> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/string.hxx> +#include <o3tl/string_view.hxx> +#include "AppView.hxx" +#include <helpids.h> +#include <strings.hxx> +#include <dbaccess_slotid.hrc> +#include <databaseobjectview.hxx> +#include <imageprovider.hxx> +#include <vcl/commandinfoprovider.hxx> +#include <vcl/cvtgrf.hxx> +#include <tools/stream.hxx> +#include "AppController.hxx" + +#include <com/sun/star/document/XDocumentProperties.hpp> + +#include <memory> + +using namespace ::dbaui; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdb::application; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star; +using ::com::sun::star::awt::XTabController; + +namespace dbaui +{ + namespace DatabaseObject = css::sdb::application::DatabaseObject; + namespace DatabaseObjectContainer = css::sdb::application::DatabaseObjectContainer; +} + +namespace +{ + bool lcl_findEntry_impl(const TreeListBox& rTree, std::u16string_view rName, weld::TreeIter& rIter) + { + bool bReturn = false; + sal_Int32 nIndex = 0; + std::u16string_view sName( o3tl::getToken(rName,0,'/',nIndex) ); + + const weld::TreeView& rTreeView = rTree.GetWidget(); + bool bEntry = true; + do + { + if (rTreeView.get_text(rIter) == sName) + { + if ( nIndex != -1 ) + { + sName = o3tl::getToken(rName,0,'/',nIndex); + bEntry = rTreeView.iter_children(rIter); + } + else + { + bReturn = true; + break; + } + } + else + bEntry = rTreeView.iter_next_sibling(rIter); + } + while (bEntry); + + return bReturn; + } + + bool lcl_findEntry(const TreeListBox& rTree, std::u16string_view rName, weld::TreeIter& rIter) + { + sal_Int32 nIndex = 0; + std::u16string_view sErase = o3tl::getToken(rName,0,'/',nIndex); // we don't want to have the "private:forms" part + return nIndex != -1 && lcl_findEntry_impl(rTree, rName.substr(sErase.size() + 1), rIter); + } +} + +OAppDetailPageHelper::OAppDetailPageHelper(weld::Container* pParent, OAppBorderWindow& rBorderWin, PreviewMode ePreviewMode) + : OChildWindow(pParent, "dbaccess/ui/detailwindow.ui", "DetailWindow") + , m_rBorderWin(rBorderWin) + , m_xBox(m_xBuilder->weld_container("box")) + , m_xFL(m_xBuilder->weld_widget("separator")) + , m_xMBPreview(m_xBuilder->weld_menu_button("disablepreview")) + , m_xPreview(new OPreviewWindow) + , m_xPreviewWin(new weld::CustomWeld(*m_xBuilder, "preview", *m_xPreview)) + , m_xDocumentInfo(new ODocumentInfoPreview) + , m_xDocumentInfoWin(new weld::CustomWeld(*m_xBuilder, "infopreview", *m_xDocumentInfo)) + , m_xTablePreview(m_xBuilder->weld_container("tablepreview")) + , m_ePreviewMode(ePreviewMode) +{ + m_xContainer->set_stack_background(); + + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:DBDisablePreview", + "com.sun.star.sdb.OfficeDatabaseDocument"); + m_xMBPreview->set_label(vcl::CommandInfoProvider::GetLabelForCommand(aProperties)); + m_xMBPreview->set_help_id(HID_APP_VIEW_PREVIEW_CB); + + m_xMBPreview->connect_selected(LINK(this, OAppDetailPageHelper, MenuSelectHdl)); + m_xMBPreview->connect_toggled(LINK(this, OAppDetailPageHelper, OnDropdownClickHdl)); + + m_xPreview->SetHelpId(HID_APP_VIEW_PREVIEW_1); + + m_xTablePreview->set_help_id(HID_APP_VIEW_PREVIEW_2); + m_xDocumentInfo->SetHelpId(HID_APP_VIEW_PREVIEW_3); + + m_xWindow = m_xTablePreview->CreateChildFrame(); +} + +OAppDetailPageHelper::~OAppDetailPageHelper() +{ + try + { + Reference< ::util::XCloseable> xCloseable(m_xFrame,UNO_QUERY); + if ( xCloseable.is() ) + xCloseable->close(true); + m_xFrame.clear(); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "dbaccess", "Exception thrown while disposing preview frame!"); + } + + for (auto& rpBox : m_aLists) + { + if (!rpBox) + continue; + rpBox.reset(); + } + + m_xWindow->dispose(); + m_xWindow.clear(); + + m_xTablePreview.reset(); + m_xDocumentInfoWin.reset(); + m_xDocumentInfo.reset(); + m_xPreviewWin.reset(); + m_xPreview.reset(); + m_xMBPreview.reset(); + m_xFL.reset(); + m_xBox.reset(); +} + +int OAppDetailPageHelper::getVisibleControlIndex() const +{ + int i = 0; + for (; i < E_ELEMENT_TYPE_COUNT ; ++i) + { + if (m_aLists[i] && m_aLists[i]->get_visible()) + break; + } + return i; +} + +void OAppDetailPageHelper::selectAll() +{ + int nPos = getVisibleControlIndex(); + if (nPos < E_ELEMENT_TYPE_COUNT) + { + m_aLists[nPos]->GetWidget().select_all(); + } +} + +void OAppDetailPageHelper::GrabFocus() +{ + int nPos = getVisibleControlIndex(); + if (nPos < E_ELEMENT_TYPE_COUNT) + m_aLists[nPos]->GetWidget().grab_focus(); + else if (m_xMBPreview && m_xMBPreview->get_visible()) + m_xMBPreview->grab_focus(); +} + +bool OAppDetailPageHelper::HasChildPathFocus() const +{ + int nPos = getVisibleControlIndex(); + if (nPos < E_ELEMENT_TYPE_COUNT && m_aLists[nPos]->GetWidget().has_focus()) + return true; + return m_xMBPreview && m_xMBPreview->has_focus(); +} + +void OAppDetailPageHelper::sort(int nPos, bool bAscending) +{ + assert(m_aLists[nPos] && "List can not be NULL! ->GPF"); + m_aLists[nPos]->GetWidget().set_sort_order(bAscending); +} + +bool OAppDetailPageHelper::isSortUp() const +{ + bool bAscending = false; + + int nPos = getVisibleControlIndex(); + if (nPos < E_ELEMENT_TYPE_COUNT) + bAscending = m_aLists[nPos]->GetWidget().get_sort_order(); + + return bAscending; +} + +void OAppDetailPageHelper::sortDown() +{ + int nPos = getVisibleControlIndex(); + if ( nPos < E_ELEMENT_TYPE_COUNT ) + sort(nPos, false); +} + +void OAppDetailPageHelper::sortUp() +{ + int nPos = getVisibleControlIndex(); + if ( nPos < E_ELEMENT_TYPE_COUNT ) + sort(nPos, true); +} + +void OAppDetailPageHelper::getSelectionElementNames(std::vector<OUString>& rNames) const +{ + int nPos = getVisibleControlIndex(); + if ( nPos >= E_ELEMENT_TYPE_COUNT ) + return; + + DBTreeViewBase& rTree = *m_aLists[nPos]; + weld::TreeView& rTreeView = rTree.GetWidget(); + sal_Int32 nCount = rTreeView.n_children(); + rNames.reserve(nCount); + ElementType eType = getElementType(); + + rTreeView.selected_foreach([this, eType, &rTreeView, &rNames](weld::TreeIter& rEntry){ + if ( eType == E_TABLE ) + { + if (!rTreeView.iter_has_child(rEntry)) + rNames.push_back(getQualifiedName(&rEntry)); + } + else + { + OUString sName = rTreeView.get_text(rEntry); + std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator(&rEntry)); + bool bParent = rTreeView.iter_parent(*xParent); + while (bParent) + { + sName = rTreeView.get_text(*xParent) + "/" + sName; + bParent = rTreeView.iter_parent(*xParent); + } + rNames.push_back(sName); + } + + return false; + }); +} + +void OAppDetailPageHelper::describeCurrentSelectionForControl(const weld::TreeView& rControl, Sequence< NamedDatabaseObject >& out_rSelectedObjects) +{ + for (size_t i=0; i < E_ELEMENT_TYPE_COUNT; ++i) + { + if (&m_aLists[i]->GetWidget() == &rControl) + { + describeCurrentSelectionForType(static_cast<ElementType>(i), out_rSelectedObjects); + return; + } + } + OSL_FAIL( "OAppDetailPageHelper::describeCurrentSelectionForControl: invalid control!" ); +} + +void OAppDetailPageHelper::describeCurrentSelectionForType(const ElementType eType, Sequence< NamedDatabaseObject >& _out_rSelectedObjects) +{ + OSL_ENSURE( eType < E_ELEMENT_TYPE_COUNT, "OAppDetailPageHelper::describeCurrentSelectionForType: invalid type!" ); + DBTreeViewBase* pList = ( eType < E_ELEMENT_TYPE_COUNT ) ? m_aLists[eType].get() : nullptr; + OSL_ENSURE( pList, "OAppDetailPageHelper::describeCurrentSelectionForType: " + "You really should ensure this type has already been viewed before!" ); + if ( !pList ) + return; + + std::vector< NamedDatabaseObject > aSelected; + + weld::TreeView& rTreeView = pList->GetWidget(); + rTreeView.selected_foreach([pList, eType, &rTreeView, &aSelected](weld::TreeIter& rEntry){ + NamedDatabaseObject aObject; + switch (eType) + { + case E_TABLE: + { + OTableTreeListBox& rTableTree = static_cast<OTableTreeListBox&>(pList->getListBox()); + aObject = rTableTree.describeObject(rEntry); + break; + } + case E_QUERY: + aObject.Type = DatabaseObject::QUERY; + aObject.Name = rTreeView.get_text(rEntry); + break; + case E_FORM: + case E_REPORT: + { + OUString sName = rTreeView.get_text(rEntry); + std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator(&rEntry)); + bool bParent = rTreeView.iter_parent(*xParent); + while (bParent) + { + sName = rTreeView.get_text(*xParent) + "/" + sName; + bParent = rTreeView.iter_parent(*xParent); + } + + if (isLeaf(rTreeView, rEntry)) + aObject.Type = (eType == E_FORM) ? DatabaseObject::FORM : DatabaseObject::REPORT; + else + aObject.Type = (eType == E_FORM) ? DatabaseObjectContainer::FORMS_FOLDER : DatabaseObjectContainer::REPORTS_FOLDER; + aObject.Name = sName; + break; + } + default: + OSL_FAIL( "OAppDetailPageHelper::describeCurrentSelectionForType: unexpected type!" ); + break; + } + + if (!aObject.Name.isEmpty()) + aSelected.push_back(aObject); + + return false; + }); + + _out_rSelectedObjects = comphelper::containerToSequence(aSelected); +} + +vcl::Window* OAppDetailPageHelper::getMenuParent() const +{ + return &m_rBorderWin; +} + +void OAppDetailPageHelper::adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const +{ + int x, y, width, height; + if (rControl.get_extents_relative_to(m_rBorderWin.getTopLevel(), x, y, width, height)) + { + rPos.AdjustX(x); + rPos.AdjustY(y); + } +} + +void OAppDetailPageHelper::selectElements(const Sequence< OUString>& _aNames) +{ + int nPos = getVisibleControlIndex(); + if ( nPos >= E_ELEMENT_TYPE_COUNT ) + return; + + DBTreeViewBase& rTree = *m_aLists[nPos]; + weld::TreeView& rTreeView = rTree.GetWidget(); + rTreeView.unselect_all(); + const OUString* pIter = _aNames.getConstArray(); + const OUString* pEnd = pIter + _aNames.getLength(); + for(;pIter != pEnd;++pIter) + { + auto xEntry = rTree.getListBox().GetEntryPosByName(*pIter); + if (!xEntry) + continue; + rTreeView.select(*xEntry); + } +} + +OUString OAppDetailPageHelper::getQualifiedName(const weld::TreeIter* _pEntry) const +{ + int nPos = getVisibleControlIndex(); + OUString sComposedName; + + if ( nPos >= E_ELEMENT_TYPE_COUNT ) + return sComposedName; + + OSL_ENSURE(m_aLists[nPos],"Tables tree view is NULL! -> GPF"); + DBTreeViewBase& rTree = *m_aLists[nPos]; + weld::TreeView& rTreeView = rTree.GetWidget(); + + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator(_pEntry)); + if (!_pEntry) + { + if (!rTreeView.get_selected(xEntry.get())) + xEntry.reset(); + } + + if (!xEntry) + return sComposedName; + + if ( getElementType() == E_TABLE ) + { + const OTableTreeListBox& rTableTreeListBox = static_cast<const OTableTreeListBox&>(m_aLists[nPos]->getListBox()); + sComposedName = rTableTreeListBox.getQualifiedTableName(*xEntry); + } + else + { + sComposedName = rTreeView.get_text(*xEntry); + bool bParent = rTreeView.iter_parent(*xEntry); + while (bParent) + { + sComposedName = rTreeView.get_text(*xEntry) + "/" + sComposedName; + bParent = rTreeView.iter_parent(*xEntry); + } + } + + return sComposedName; +} + +ElementType OAppDetailPageHelper::getElementType() const +{ + int nPos = getVisibleControlIndex(); + return static_cast<ElementType>(nPos); +} + +sal_Int32 OAppDetailPageHelper::getSelectionCount() +{ + sal_Int32 nCount = 0; + int nPos = getVisibleControlIndex(); + if ( nPos < E_ELEMENT_TYPE_COUNT ) + { + DBTreeViewBase& rTree = *m_aLists[nPos]; + weld::TreeView& rTreeView = rTree.GetWidget(); + nCount = rTreeView.count_selected_rows(); + } + return nCount; +} + +sal_Int32 OAppDetailPageHelper::getElementCount() const +{ + sal_Int32 nCount = 0; + int nPos = getVisibleControlIndex(); + if ( nPos < E_ELEMENT_TYPE_COUNT ) + { + DBTreeViewBase& rTree = *m_aLists[nPos]; + weld::TreeView& rTreeView = rTree.GetWidget(); + nCount = rTreeView.n_children(); + } + return nCount; +} + +bool OAppDetailPageHelper::isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry) +{ + sal_Int32 nEntryType = rTreeView.get_id(rEntry).toInt32(); + return !( ( nEntryType == DatabaseObjectContainer::TABLES ) + || ( nEntryType == DatabaseObjectContainer::CATALOG ) + || ( nEntryType == DatabaseObjectContainer::SCHEMA ) + || ( nEntryType == DatabaseObjectContainer::FORMS_FOLDER ) + || ( nEntryType == DatabaseObjectContainer::REPORTS_FOLDER )); +} + +bool OAppDetailPageHelper::isALeafSelected() const +{ + int nPos = getVisibleControlIndex(); + bool bLeafSelected = false; + if ( nPos < E_ELEMENT_TYPE_COUNT ) + { + DBTreeViewBase& rTree = *m_aLists[nPos]; + weld::TreeView& rTreeView = rTree.GetWidget(); + rTreeView.selected_foreach([&rTreeView, &bLeafSelected](weld::TreeIter& rEntry){ + bLeafSelected = isLeaf(rTreeView, rEntry); + return bLeafSelected; + }); + } + return bLeafSelected; +} + +std::unique_ptr<weld::TreeIter> OAppDetailPageHelper::getEntry( const Point& _aPosPixel) const +{ + std::unique_ptr<weld::TreeIter> xReturn; + int nPos = getVisibleControlIndex(); + if ( nPos < E_ELEMENT_TYPE_COUNT ) + { + DBTreeViewBase& rTree = *m_aLists[nPos]; + weld::TreeView& rTreeView = rTree.GetWidget(); + xReturn = rTreeView.make_iterator(); + if (!rTreeView.get_dest_row_at_pos(_aPosPixel, xReturn.get(), false)) + xReturn.reset(); + } + return xReturn; +} + +void OAppDetailPageHelper::createTablesPage(const Reference< XConnection>& _xConnection) +{ + OSL_ENSURE(_xConnection.is(),"Connection is NULL! -> GPF"); + + if ( !m_aLists[E_TABLE] ) + { + m_aLists[E_TABLE].reset(new DBTableTreeView(m_xBox.get())); + setupTree(*m_aLists[E_TABLE]); + m_aLists[E_TABLE]->GetWidget().set_help_id(HID_APP_TABLE_TREE); + } + + weld::TreeView& rTreeView = m_aLists[E_TABLE]->GetWidget(); + if (!rTreeView.n_children()) + { + static_cast<OTableTreeListBox&>(m_aLists[E_TABLE]->getListBox()).UpdateTableList(_xConnection); + + std::unique_ptr<weld::TreeIter> xFirst(rTreeView.make_iterator()); + if (rTreeView.get_iter_first(*xFirst)) + rTreeView.expand_row(*xFirst); + rTreeView.unselect_all(); + } + + setDetailPage(*m_aLists[E_TABLE]); +} + +OUString OAppDetailPageHelper::getElementIcons(ElementType _eType) +{ + sal_Int32 nDatabaseObjectType( 0 ); + switch(_eType ) + { + case E_FORM: nDatabaseObjectType = DatabaseObject::FORM; break; + case E_REPORT: nDatabaseObjectType = DatabaseObject::REPORT; break; + case E_QUERY: nDatabaseObjectType = DatabaseObject::QUERY; break; + default: + OSL_FAIL( "OAppDetailPageHelper::GetElementIcons: invalid element type!" ); + return OUString(); + } + + return ImageProvider::getDefaultImageResourceID(nDatabaseObjectType); +} + +void OAppDetailPageHelper::createPage(ElementType _eType,const Reference< XNameAccess >& _xContainer) +{ + OSL_ENSURE(E_TABLE != _eType,"E_TABLE isn't allowed."); + + OString sHelpId; + switch( _eType ) + { + case E_FORM: + sHelpId = HID_APP_FORM_TREE; + break; + case E_REPORT: + sHelpId = HID_APP_REPORT_TREE; + break; + case E_QUERY: + sHelpId = HID_APP_QUERY_TREE; + break; + default: + OSL_FAIL("Illegal call!"); + } + OUString sImageId = getElementIcons(_eType); + + if ( !m_aLists[_eType] ) + { + m_aLists[_eType] = createSimpleTree(sHelpId, _eType); + } + + if ( !m_aLists[_eType] ) + return; + + weld::TreeView& rTreeView = m_aLists[_eType]->GetWidget(); + if (!rTreeView.n_children() && _xContainer.is()) + { + rTreeView.make_unsorted(); + fillNames( _xContainer, _eType, sImageId, nullptr ); + rTreeView.make_sorted(); + + rTreeView.unselect_all(); + } + setDetailPage(*m_aLists[_eType]); +} + +void OAppDetailPageHelper::setDetailPage(DBTreeViewBase& rTreeView) +{ + bool bHasFocus = false; + + DBTreeViewBase* pCurrent = getCurrentView(); + if (pCurrent) + { + weld::Widget& rCurrent = pCurrent->GetWidget(); + bHasFocus = rCurrent.has_focus(); + pCurrent->hide(); + } + + showPreview(nullptr); + m_xFL->show(); + rTreeView.show(); + m_xMBPreview->show(); + switchPreview(m_ePreviewMode,true); + + if (bHasFocus) + rTreeView.GetWidget().grab_focus(); +} + +namespace +{ + namespace DatabaseObjectContainer = ::com::sun::star::sdb::application::DatabaseObjectContainer; + + sal_Int32 lcl_getFolderIndicatorForType( const ElementType _eType ) + { + const sal_Int32 nFolderIndicator = + ( _eType == E_FORM ) ? DatabaseObjectContainer::FORMS_FOLDER + : ( _eType == E_REPORT ) ? DatabaseObjectContainer::REPORTS_FOLDER : -1; + return nFolderIndicator; + } +} + +void OAppDetailPageHelper::fillNames( const Reference< XNameAccess >& _xContainer, const ElementType _eType, + const OUString& rImageId, const weld::TreeIter* _pParent ) +{ + OSL_ENSURE(_xContainer.is(),"Data source is NULL! -> GPF"); + OSL_ENSURE( ( _eType >= E_TABLE ) && ( _eType < E_ELEMENT_TYPE_COUNT ), "OAppDetailPageHelper::fillNames: invalid type!" ); + + DBTreeViewBase* pList = m_aLists[_eType].get(); + OSL_ENSURE( pList, "OAppDetailPageHelper::fillNames: you really should create the list before calling this!" ); + if ( !pList ) + return; + + if ( !(_xContainer.is() && _xContainer->hasElements()) ) + return; + + weld::TreeView& rTreeView = pList->GetWidget(); + + std::unique_ptr<weld::TreeIter> xRet = rTreeView.make_iterator(); + const sal_Int32 nFolderIndicator = lcl_getFolderIndicatorForType( _eType ); + + Sequence< OUString> aSeq = _xContainer->getElementNames(); + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + for(;pIter != pEnd;++pIter) + { + Reference<XNameAccess> xSubElements(_xContainer->getByName(*pIter),UNO_QUERY); + if ( xSubElements.is() ) + { + OUString sId(OUString::number(nFolderIndicator)); + + rTreeView.insert(_pParent, -1, nullptr, &sId, nullptr, nullptr, false, xRet.get()); + rTreeView.set_text(*xRet, *pIter, 0); + rTreeView.set_text_emphasis(*xRet, false, 0); + getBorderWin().getView()->getAppController().containerFound( Reference< XContainer >( xSubElements, UNO_QUERY ) ); + fillNames( xSubElements, _eType, rImageId, xRet.get()); + } + else + { + rTreeView.insert(_pParent, -1, nullptr, nullptr, nullptr, nullptr, false, xRet.get()); + rTreeView.set_text(*xRet, *pIter, 0); + rTreeView.set_text_emphasis(*xRet, false, 0); + rTreeView.set_image(*xRet, rImageId); + } + } +} + +std::unique_ptr<DBTreeViewBase> OAppDetailPageHelper::createSimpleTree(const OString& rHelpId, ElementType eType) +{ + const bool bSQLType = eType == E_TABLE || eType == E_QUERY; + std::unique_ptr<DBTreeViewBase> xTreeView(new DBTreeView(m_xBox.get(), bSQLType)); + xTreeView->GetWidget().set_help_id(rHelpId); + setupTree(*xTreeView); + return xTreeView; +} + +void OAppDetailPageHelper::setupTree(DBTreeViewBase& rDBTreeView) +{ + weld::WaitObject aWaitCursor(m_rBorderWin.GetFrameWeld()); + + rDBTreeView.getListBox().setCopyHandler(LINK(this, OAppDetailPageHelper, OnCopyEntry)); + rDBTreeView.getListBox().setPasteHandler(LINK(this, OAppDetailPageHelper, OnPasteEntry)); + rDBTreeView.getListBox().setDeleteHandler(LINK(this, OAppDetailPageHelper, OnDeleteEntry)); + + weld::TreeView& rTreeView = rDBTreeView.GetWidget(); + rTreeView.make_sorted(); + rTreeView.set_selection_mode(SelectionMode::Multiple); + // an arbitrary small size it's allowed to shrink to + rTreeView.set_size_request(42, 42); + + rTreeView.connect_row_activated(LINK(this, OAppDetailPageHelper, OnEntryDoubleClick)); + + rDBTreeView.getListBox().SetSelChangeHdl(LINK(this, OAppDetailPageHelper, OnEntrySelChange)); + + rDBTreeView.getListBox().setControlActionListener(&getBorderWin().getView()->getAppController()); + rDBTreeView.getListBox().setContextMenuProvider(&getBorderWin().getView()->getAppController()); +} + +void OAppDetailPageHelper::clearPages() +{ + showPreview(nullptr); + for (auto& rpBox : m_aLists) + { + if ( rpBox ) + rpBox->GetWidget().clear(); + } +} + +bool OAppDetailPageHelper::isFilled() const +{ + size_t i = 0; + for (; i < E_ELEMENT_TYPE_COUNT && !m_aLists[i]; ++i) + ; + return i != E_ELEMENT_TYPE_COUNT; +} + +void OAppDetailPageHelper::elementReplaced(ElementType eType, + const OUString& rOldName, + const OUString& rNewName) +{ + DBTreeViewBase* pTreeView = getCurrentView(); + if (!pTreeView) + return; + + weld::TreeView& rTreeView = pTreeView->GetWidget(); + rTreeView.make_unsorted(); + + switch (eType) + { + case E_TABLE: + static_cast<OTableTreeListBox&>(pTreeView->getListBox()).removedTable(rOldName); + static_cast<OTableTreeListBox&>(pTreeView->getListBox()).addedTable(rNewName); + break; + case E_QUERY: + { + std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator()); + if (rTreeView.get_iter_first(*xIter) && lcl_findEntry_impl(pTreeView->getListBox(), rOldName, *xIter)) + rTreeView.set_text(*xIter, rNewName); + break; + } + case E_FORM: + case E_REPORT: + { + std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator()); + if (rTreeView.get_iter_first(*xIter) && lcl_findEntry(pTreeView->getListBox(), rOldName, *xIter)) + rTreeView.set_text(*xIter, rNewName); + break; + } + default: + OSL_FAIL("Invalid element type"); + } + + rTreeView.make_sorted(); +} + +std::unique_ptr<weld::TreeIter> OAppDetailPageHelper::elementAdded(ElementType _eType,const OUString& _rName, const Any& _rObject ) +{ + std::unique_ptr<weld::TreeIter> xRet; + DBTreeViewBase* pTreeView = m_aLists[_eType].get(); + if (!pTreeView) + return xRet; + weld::TreeView& rTreeView = pTreeView->GetWidget(); + rTreeView.make_unsorted(); + if (_eType == E_TABLE) + { + xRet = static_cast<OTableTreeListBox&>(pTreeView->getListBox()).addedTable( _rName ); + } + else + { + std::unique_ptr<weld::TreeIter> xEntry; + Reference<XChild> xChild(_rObject,UNO_QUERY); + if ( xChild.is() && E_QUERY != _eType ) + { + Reference<XContent> xContent(xChild->getParent(),UNO_QUERY); + if ( xContent.is() ) + { + OUString sName = xContent->getIdentifier()->getContentIdentifier(); + std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator()); + if (rTreeView.get_iter_first(*xIter) && lcl_findEntry(pTreeView->getListBox(), sName, *xIter)) + xEntry = std::move(xIter); + } + } + + OUString sImageId = getElementIcons(_eType); + Reference<XNameAccess> xContainer(_rObject,UNO_QUERY); + if ( xContainer.is() ) + { + const sal_Int32 nFolderIndicator = lcl_getFolderIndicatorForType( _eType ); + OUString sId(OUString::number(nFolderIndicator)); + + xRet = rTreeView.make_iterator(); + rTreeView.insert(xEntry.get(), -1, nullptr, &sId, nullptr, nullptr, false, xRet.get()); + rTreeView.set_text(*xRet, _rName, 0); + rTreeView.set_text_emphasis(*xRet, false, 0); + fillNames(xContainer, _eType, sImageId, xRet.get()); + } + else + { + xRet = rTreeView.make_iterator(); + rTreeView.insert(xEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xRet.get()); + rTreeView.set_text(*xRet, _rName, 0); + rTreeView.set_text_emphasis(*xRet, false, 0); + rTreeView.set_image(*xRet, sImageId); + } + } + rTreeView.make_sorted(); + return xRet; +} + +void OAppDetailPageHelper::elementRemoved( ElementType _eType,const OUString& _rName ) +{ + DBTreeViewBase* pTreeView = getCurrentView(); + if ( !pTreeView ) + return; + + weld::TreeView& rTreeView = pTreeView->GetWidget(); + + switch( _eType ) + { + case E_TABLE: + // we don't need to clear the table here, it is already done by the dispose listener + static_cast<OTableTreeListBox&>(pTreeView->getListBox()).removedTable(_rName); + break; + case E_QUERY: + { + std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator()); + if (rTreeView.get_iter_first(*xIter) && lcl_findEntry_impl(pTreeView->getListBox(), _rName, *xIter)) + rTreeView.remove(*xIter); + break; + } + case E_FORM: + case E_REPORT: + { + std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator()); + if (rTreeView.get_iter_first(*xIter) && lcl_findEntry(pTreeView->getListBox(), _rName, *xIter)) + rTreeView.remove(*xIter); + break; + } + default: + OSL_FAIL("Invalid element type"); + } + if (!rTreeView.n_children()) + showPreview(nullptr); +} + +IMPL_LINK(OAppDetailPageHelper, OnEntryDoubleClick, weld::TreeView&, rTreeView, bool) +{ + return getBorderWin().getView()->getAppController().onEntryDoubleClick(rTreeView); +} + +IMPL_LINK_NOARG(OAppDetailPageHelper, OnEntrySelChange, LinkParamNone*, void) +{ + getBorderWin().getView()->getAppController().onSelectionChanged(); +} + +IMPL_LINK_NOARG( OAppDetailPageHelper, OnCopyEntry, LinkParamNone*, void ) +{ + getBorderWin().getView()->getAppController().onCopyEntry(); +} + +IMPL_LINK_NOARG( OAppDetailPageHelper, OnPasteEntry, LinkParamNone*, void ) +{ + getBorderWin().getView()->getAppController().onPasteEntry(); +} + +IMPL_LINK_NOARG( OAppDetailPageHelper, OnDeleteEntry, LinkParamNone*, void ) +{ + getBorderWin().getView()->getAppController().onDeleteEntry(); +} + +bool OAppDetailPageHelper::isPreviewEnabled() const +{ + return m_ePreviewMode != E_PREVIEWNONE; +} + +namespace +{ + OUString stripTrailingDots(std::u16string_view rStr) + { + return OUString(comphelper::string::stripEnd(rStr, '.')); + } +} + +void OAppDetailPageHelper::switchPreview(PreviewMode _eMode,bool _bForce) +{ + if ( !(m_ePreviewMode != _eMode || _bForce) ) + return; + + m_ePreviewMode = _eMode; + + getBorderWin().getView()->getAppController().previewChanged(static_cast<sal_Int32>(m_ePreviewMode)); + + OUString aCommand; + switch ( m_ePreviewMode ) + { + case E_PREVIEWNONE: + aCommand = ".uno:DBDisablePreview"; + break; + case E_DOCUMENT: + aCommand = ".uno:DBShowDocPreview"; + break; + case E_DOCUMENTINFO: + if ( getBorderWin().getView()->getAppController().isCommandEnabled(SID_DB_APP_VIEW_DOCINFO_PREVIEW) ) + aCommand = ".uno:DBShowDocInfoPreview"; + else + { + m_ePreviewMode = E_PREVIEWNONE; + aCommand = ".uno:DBDisablePreview"; + } + break; + } + + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommand, "com.sun.star.sdb.OfficeDatabaseDocument"); + OUString aCommandLabel = vcl::CommandInfoProvider::GetLabelForCommand(aProperties); + m_xMBPreview->set_label(stripTrailingDots(aCommandLabel)); + + // simulate a selectionChanged event at the controller, to force the preview to be updated + if ( isPreviewEnabled() ) + { + DBTreeViewBase* pCurrent = getCurrentView(); + if (pCurrent && pCurrent->GetWidget().get_selected(nullptr)) + { + getBorderWin().getView()->getAppController().onSelectionChanged(); + } + } + else + { + m_xTablePreview->hide(); + m_xPreview->Hide(); + m_xDocumentInfo->Hide(); + } +} + +void OAppDetailPageHelper::showPreview(const Reference< XContent >& _xContent) +{ + if ( !isPreviewEnabled() ) + return; + + m_xTablePreview->hide(); + + weld::WaitObject aWaitCursor(m_rBorderWin.GetFrameWeld()); + try + { + Reference<XCommandProcessor> xContent(_xContent,UNO_QUERY); + if ( xContent.is() ) + { + css::ucb::Command aCommand; + if ( m_ePreviewMode == E_DOCUMENT ) + aCommand.Name = "preview"; + else + aCommand.Name = "getDocumentInfo"; + + Any aPreview = xContent->execute(aCommand,xContent->createCommandIdentifier(),Reference< XCommandEnvironment >()); + if ( m_ePreviewMode == E_DOCUMENT ) + { + m_xDocumentInfo->Hide(); + m_xPreview->Show(); + + Graphic aGraphic; + Sequence < sal_Int8 > aBmpSequence; + if ( aPreview >>= aBmpSequence ) + { + SvMemoryStream aData( aBmpSequence.getArray(), + aBmpSequence.getLength(), + StreamMode::READ ); + + GraphicConverter::Import(aData,aGraphic); + } + m_xPreview->setGraphic( aGraphic ); + m_xPreview->Invalidate(); + } + else + { + m_xPreview->Hide(); + m_xDocumentInfo->clear(); + m_xDocumentInfo->Show(); + Reference<document::XDocumentProperties> xProp( + aPreview, UNO_QUERY); + if ( xProp.is() ) + m_xDocumentInfo->fill(xProp); + } + } + else + { + m_xPreview->Hide(); + m_xDocumentInfo->Hide(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OAppDetailPageHelper::showPreview( const OUString& _sDataSourceName, + const OUString& _sName, + bool _bTable) +{ + if ( !isPreviewEnabled() ) + return; + + weld::WaitObject aWaitCursor(m_rBorderWin.GetFrameWeld()); + m_xPreview->Hide(); + m_xDocumentInfo->Hide(); + m_xTablePreview->show(); + if ( !m_xFrame.is() ) + { + try + { + m_xFrame = Frame::create( getBorderWin().getView()->getORB() ); + m_xFrame->initialize( m_xWindow ); + + // no layout manager (and thus no toolbars) in the preview + // Must be called after initialize ... but before any other call to this frame. + // Otherwise frame throws "life time exceptions" as e.g. NON_INITIALIZED + m_xFrame->setLayoutManager( Reference< XLayoutManager >() ); + + Reference<XFramesSupplier> xSup(getBorderWin().getView()->getAppController().getXController()->getFrame(),UNO_QUERY); + if ( xSup.is() ) + { + Reference<XFrames> xFrames = xSup->getFrames(); + xFrames->append( Reference<XFrame>(m_xFrame,UNO_QUERY_THROW)); + } + } + catch(const Exception&) + { + } + } + + Reference< XDatabaseDocumentUI > xApplication( getBorderWin().getView()->getAppController().getXController(), UNO_QUERY ); + std::unique_ptr< DatabaseObjectView > pDispatcher( new ResultSetBrowser( + getBorderWin().getView()->getORB(), + xApplication, nullptr, _bTable + ) ); + pDispatcher->setTargetFrame( Reference<XFrame>(m_xFrame,UNO_QUERY_THROW) ); + + ::comphelper::NamedValueCollection aArgs; + aArgs.put( "Preview", true ); + aArgs.put( "ReadOnly", true ); + aArgs.put( "AsTemplate", false ); + aArgs.put( PROPERTY_SHOWMENU, false ); + + Reference< XController > xPreview( pDispatcher->openExisting( Any( _sDataSourceName ), _sName, aArgs ), UNO_QUERY ); + bool bClearPreview = !xPreview.is(); + + // clear the preview when the query or table could not be loaded + if ( !bClearPreview ) + { + Reference< XTabController > xTabController( xPreview, UNO_QUERY ); + bClearPreview = !xTabController.is(); + if ( !bClearPreview ) + { + Reference< XLoadable > xLoadable( xTabController->getModel(), UNO_QUERY ); + bClearPreview = !( xLoadable.is() && xLoadable->isLoaded() ); + } + } + if ( bClearPreview ) + showPreview(nullptr); +} + +namespace +{ + class MenuStatusListener final : public ::cppu::WeakImplHelper<css::frame::XStatusListener> + { + weld::MenuButton& m_rMBPreview; + public: + MenuStatusListener(weld::MenuButton& rMBPreview) + : m_rMBPreview(rMBPreview) + { + } + + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent &rEvent) override + { + if (!rEvent.IsEnabled) + { + const OUString &rURL = rEvent.FeatureURL.Complete; + m_rMBPreview.remove_item(rURL.toUtf8()); + } + } + + virtual void SAL_CALL disposing( const css::lang::EventObject& /*rSource*/) override + { + } + }; +}; + +IMPL_LINK_NOARG(OAppDetailPageHelper, OnDropdownClickHdl, weld::Toggleable&, void) +{ + if (!m_xMBPreview->get_active()) + return; + + m_xMBPreview->clear(); + + // execute the menu + css::uno::Reference<css::uno::XComponentContext> xContext(getBorderWin().getView()->getORB()); + css::uno::Reference<css::frame::XUIControllerFactory> xPopupMenuFactory(css::frame::thePopupMenuControllerFactory::get(xContext)); + if (!xPopupMenuFactory.is()) + return; + + auto xFrame = getBorderWin().getView()->getAppController().getFrame(); + + css::uno::Sequence<css::uno::Any> aArgs { + css::uno::Any(comphelper::makePropertyValue("InToolbar", true)), + css::uno::Any(comphelper::makePropertyValue("ModuleIdentifier", OUString("com.sun.star.sdb.OfficeDatabaseDocument"))), + css::uno::Any(comphelper::makePropertyValue("Frame", xFrame)) }; + + css::uno::Reference<css::frame::XPopupMenuController> xPopupController + (xPopupMenuFactory->createInstanceWithArgumentsAndContext(".uno:DBPreview", aArgs, xContext), css::uno::UNO_QUERY); + + if (!xPopupController.is()) + return; + + css::uno::Reference<css::awt::XPopupMenu> xPopupMenu(css::awt::PopupMenu::create(xContext)); + xPopupController->setPopupMenu(xPopupMenu); + + css::util::URL aTargetURL; + Reference<XDispatchProvider> xDispatchProvider(xFrame, css::uno::UNO_QUERY); + + css::uno::Reference<css::frame::XStatusListener> xStatusListener(new MenuStatusListener(*m_xMBPreview)); + + for (int i = 0, nCount = xPopupMenu->getItemCount(); i < nCount; ++i) + { + auto nItemId = xPopupMenu->getItemId(i); + // in practice disabled items are initially enabled so this doesn't have an effect and + // an status update is needed to query the enabled/disabled state + if (!xPopupMenu->isItemEnabled(nItemId)) + continue; + + aTargetURL.Complete = xPopupMenu->getCommand(nItemId); + + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aTargetURL.Complete, + "com.sun.star.sdb.OfficeDatabaseDocument"); + m_xMBPreview->append_item(aTargetURL.Complete, vcl::CommandInfoProvider::GetLabelForCommand(aProperties)); + + // Add/remove status listener to get a status update once so we can remove any disabled items from the menu + auto xDispatch = xDispatchProvider->queryDispatch(aTargetURL, "_self", + css::frame::FrameSearchFlag::SELF); + if (xDispatch.is()) + { + xDispatch->addStatusListener(xStatusListener, aTargetURL); + xDispatch->removeStatusListener(xStatusListener, aTargetURL); + } + } + + css::uno::Reference<css::lang::XComponent> xComponent(xPopupController, css::uno::UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); +} + +IMPL_LINK(OAppDetailPageHelper, MenuSelectHdl, const OString&, rIdent, void) +{ + if (rIdent.isEmpty()) + return; + + css::util::URL aURL; + aURL.Complete = OUString::fromUtf8(rIdent); + + Reference<XDispatchProvider> xProvider(getBorderWin().getView()->getAppController().getFrame(), UNO_QUERY); + Reference<XDispatch> xDisp = xProvider->queryDispatch(aURL, "_self", 0); + xDisp->dispatch(aURL, css::uno::Sequence<css::beans::PropertyValue>()); + + m_xMBPreview->set_label(stripTrailingDots(m_xMBPreview->get_item_label(rIdent))); +} + +OPreviewWindow::OPreviewWindow() +{ +} + +bool OPreviewWindow::ImplGetGraphicCenterRect(const vcl::RenderContext& rRenderContext, const Graphic& rGraphic, tools::Rectangle& rResultRect) const +{ + const Size aWinSize( GetOutputSizePixel() ); + Size aNewSize(rRenderContext.LogicToPixel(rGraphic.GetPrefSize(), rGraphic.GetPrefMapMode())); + bool bRet = false; + + if( aNewSize.Width() && aNewSize.Height() ) + { + // scale to fit window + const double fGrfWH = static_cast<double>(aNewSize.Width()) / aNewSize.Height(); + const double fWinWH = static_cast<double>(aWinSize.Width()) / aWinSize.Height(); + + if ( fGrfWH < fWinWH ) + { + aNewSize.setWidth( static_cast<tools::Long>( aWinSize.Height() * fGrfWH ) ); + aNewSize.setHeight( aWinSize.Height() ); + } + else + { + aNewSize.setWidth( aWinSize.Width() ); + aNewSize.setHeight( static_cast<tools::Long>( aWinSize.Width() / fGrfWH) ); + } + + const Point aNewPos( ( aWinSize.Width() - aNewSize.Width() ) >> 1, + ( aWinSize.Height() - aNewSize.Height() ) >> 1 ); + + rResultRect = tools::Rectangle( aNewPos, aNewSize ); + bRet = true; + } + + return bRet; +} + +void OPreviewWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/) +{ + if (ImplGetGraphicCenterRect(rRenderContext, m_aGraphicObj.GetGraphic(), m_aPreviewRect)) + { + const Point aPos(m_aPreviewRect.TopLeft()); + const Size aSize(m_aPreviewRect.GetSize()); + + if (m_aGraphicObj.IsAnimated()) + m_aGraphicObj.StartAnimation(rRenderContext, aPos, aSize); + else + m_aGraphicObj.Draw(rRenderContext, aPos, aSize); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppDetailPageHelper.hxx b/dbaccess/source/ui/app/AppDetailPageHelper.hxx new file mode 100644 index 000000000..25cc3229a --- /dev/null +++ b/dbaccess/source/ui/app/AppDetailPageHelper.hxx @@ -0,0 +1,349 @@ +/* -*- 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 <vector> + +#include <rtl/ustring.hxx> +#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <vcl/graph.hxx> +#include <vcl/GraphicObject.hxx> +#include <vcl/customweld.hxx> +#include <vcl/weld.hxx> +#include <AppElementType.hxx> +#include <ChildWindow.hxx> +#include "DocumentInfoPreview.hxx" + +namespace com::sun::star::awt { class XWindow; } +namespace com::sun::star::frame { class XFrame2; } +namespace com::sun::star::io { class XPersist; } + +namespace dbaui +{ + class OAppBorderWindow; + class ODocumentInfoPreview; + class DBTreeViewBase; + class TreeListBox; + + class OPreviewWindow final : public weld::CustomWidgetController + { + GraphicObject m_aGraphicObj; + tools::Rectangle m_aPreviewRect; + + /** gets the graphic center rect + @param rRenderContext + the context to which we are drawing + @param rGraphic + the graphic + @param rResultRect + the resulting rectangle + + @return + <TRUE/> when successful + */ + bool ImplGetGraphicCenterRect(const vcl::RenderContext& rRenderContext, const Graphic& rGraphic, tools::Rectangle& rResultRect) const; + + public: + OPreviewWindow(); + + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + + void setGraphic(const Graphic& _rGraphic ) { m_aGraphicObj.SetGraphic(_rGraphic); } + }; + + // A helper class for the controls in the detail page. + // Combines general functionality. + class OAppDetailPageHelper final : public OChildWindow + { + std::unique_ptr<DBTreeViewBase> m_aLists[size_t(E_ELEMENT_TYPE_COUNT)]; + OAppBorderWindow& m_rBorderWin; + std::unique_ptr<weld::Container> m_xBox; + std::unique_ptr<weld::Widget> m_xFL; + std::unique_ptr<weld::MenuButton> m_xMBPreview; + + std::unique_ptr<OPreviewWindow> m_xPreview; + std::unique_ptr<weld::CustomWeld> m_xPreviewWin; + + std::unique_ptr<ODocumentInfoPreview> m_xDocumentInfo; + std::unique_ptr<weld::CustomWeld> m_xDocumentInfoWin; + + std::unique_ptr<weld::Container> m_xTablePreview; + + PreviewMode m_ePreviewMode; + css::uno::Reference < css::frame::XFrame2 > + m_xFrame; + css::uno::Reference< css::awt::XWindow > + m_xWindow; + + /// returns the index of the visible control + int getVisibleControlIndex() const; + + /** sorts the entries in the tree list box. + @param nPos + Which list should be sorted. + @param bAscending + If sort should be Ascending of Descending + */ + void sort(int nPos, bool bAscending); + + /** retrieves the resource ids of the images representing elements of the given type + */ + static OUString getElementIcons(ElementType _eType); + + /** fills the names in the listbox + @param _xContainer + This can either be the queries, forms or report names. + @param _eType + the type of elements which are being filled + @param _nImageId + the resource id of the image to use for non-container entries + @param _pParent + The parent of the entries to be inserted. + */ + void fillNames( const css::uno::Reference< css::container::XNameAccess >& _xContainer, + const ElementType _eType, + const OUString& rImageId, + const weld::TreeIter* _pParent ); + + /** sets the detail page + @param rTreeView + The control which should be visible. + */ + void setDetailPage(DBTreeViewBase& rTreeView); + + /** sets all HandleCallbacks + @param rTreeView + The newly created DBTreeViewBase + */ + void setupTree(DBTreeViewBase& rTreeView); + + /** creates the tree and sets all HandleCallbacks + @param nHelpId + The help id of the control + @param eType + The element type of the control + @return + The new tree. + */ + std::unique_ptr<DBTreeViewBase> createSimpleTree(const OString& rHelpId, ElementType eType); + + DECL_LINK( OnEntryDoubleClick, weld::TreeView&, bool ); + DECL_LINK( OnEntrySelChange, LinkParamNone*, void ); + + DECL_LINK( OnCopyEntry, LinkParamNone*, void ); + DECL_LINK( OnPasteEntry, LinkParamNone*, void ); + DECL_LINK( OnDeleteEntry, LinkParamNone*, void ); + + DECL_LINK(OnDropdownClickHdl, weld::Toggleable&, void); + DECL_LINK(MenuSelectHdl, const OString&, void); + + OAppBorderWindow& getBorderWin() const { return m_rBorderWin; } + + public: + OAppDetailPageHelper(weld::Container* pParent, OAppBorderWindow& rBorderWin, PreviewMode ePreviewMode); + virtual ~OAppDetailPageHelper() override; + + virtual void GrabFocus() override; + virtual bool HasChildPathFocus() const override; + + /** creates the tables page + @param _xConnection + The connection to get the table names + */ + void createTablesPage(const css::uno::Reference< css::sdbc::XConnection>& _xConnection); + + /** creates the page for the specific type. + @param _eType + The type which should be created. E_TABLE isn't allowed. + @param _xContainer + The container of the elements to be inserted. + */ + void createPage(ElementType _eType,const css::uno::Reference< css::container::XNameAccess >& _xContainer); + + /** returns the current visible tree list box + */ + DBTreeViewBase* getCurrentView() const + { + ElementType eType = getElementType(); + return (eType != E_NONE ) ? m_aLists[static_cast<sal_Int32>(eType)].get() : nullptr; + } + + /// select all entries in the visible control + void selectAll(); + + /// returns <TRUE/> if it sorts ascending + bool isSortUp() const; + + /// sorts all entries ascending + void sortDown(); + + /// sorts all entries descending + void sortUp(); + + /** returns the element names which are selected + @param _rNames + The list will be filled. + */ + void getSelectionElementNames( std::vector< OUString>& _rNames ) const; + + /** describes the current selection for the given control + */ + void describeCurrentSelectionForControl( + const weld::TreeView& rControl, + css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects + ); + + /** describes the current selection for the given ElementType + */ + void describeCurrentSelectionForType( + const ElementType _eType, + css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects + ); + + /** get the menu parent window for the given control + */ + vcl::Window* getMenuParent() const; + void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const; + + /** select all names on the currently selected container. Non existence names where ignored. + * + * \param _aNames the element names + */ + void selectElements(const css::uno::Sequence< OUString>& _aNames); + + /** return the qualified name. + @param _pEntry + The entry of a table, or query, form, report to get the qualified name. + If the entry is <NULL/>, the first selected is chosen. + @return + the qualified name + */ + OUString getQualifiedName( const weld::TreeIter* _pEntry ) const; + + /// return the element of currently select entry + ElementType getElementType() const; + + /// returns the count of selected entries + sal_Int32 getSelectionCount(); + + /// returns the count of entries + sal_Int32 getElementCount() const; + + /** returns if an entry is a leaf + @param rTreeView + The TreeView rEntry belongs to + @param rEntry + The entry to check + @return + <TRUE/> if the entry is a leaf, otherwise <FALSE/> + */ + static bool isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry); + + /** returns if one of the selected entries is a leaf + @return + <TRUE/> if the entry is a leaf, otherwise <FALSE/> + */ + bool isALeafSelected() const; + + std::unique_ptr<weld::TreeIter> getEntry(const Point& rPosPixel) const; + + /// clears the detail pages + void clearPages(); + + /// returns <TRUE/> when a detail page was filled + bool isFilled() const; + + /** adds a new object to the detail page. + @param _eType + The type where the entry should be appended. + @param _rName + The name of the object to be inserted + @param _rObject + The object to add. + @param _rxConn + If we insert a table, the connection must be set. + */ + std::unique_ptr<weld::TreeIter> elementAdded(ElementType eType, + const OUString& rName, + const css::uno::Any& rObject); + + /** replaces an objects name with a new one + @param _eType + The type where the entry should be appended. + @param _rOldName + The old name of the object to be replaced + @param _rNewName + The new name of the object to be replaced + @param _rxConn + If we insert a table, the connection must be set. + */ + void elementReplaced(ElementType eType + ,const OUString& _rOldName + ,const OUString& _rNewName ); + + /** removes an element from the detail page. + @param _eType + The type where the entry should be appended. + @param _rName + The name of the element to be removed. + @param _rxConn + If we remove a table, the connection must be set. + */ + void elementRemoved(ElementType _eType + ,const OUString& _rName ); + + /// returns the preview mode + PreviewMode getPreviewMode() const { return m_ePreviewMode;} + + /// <TRUE/> if the preview is enabled + bool isPreviewEnabled() const; + + /** switches to the given preview mode + @param _eMode + the mode to set for the preview + @param _bForce + Force the preview to be reset + */ + void switchPreview(PreviewMode _eMode,bool _bForce = false); + + /** shows the Preview of the content when it is enabled. + @param _xContent + The content which must support the "preview" command. + */ + void showPreview(const css::uno::Reference< css::ucb::XContent >& _xContent); + + /** shows the Preview of a table or query + @param _sDataSourceName + the name of the data source + @param _sName + the name of table or query + @param _bTable + <TRUE/> if it is a table, otherwise <FALSE/> + @return void + */ + void showPreview( const OUString& _sDataSourceName, + const OUString& _sName, + bool _bTable); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppDetailView.cxx b/dbaccess/source/ui/app/AppDetailView.cxx new file mode 100644 index 000000000..63a9f7f39 --- /dev/null +++ b/dbaccess/source/ui/app/AppDetailView.cxx @@ -0,0 +1,510 @@ +/* -*- 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 "AppDetailView.hxx" +#include <osl/diagnose.h> +#include <helpids.h> +#include <strings.hrc> +#include "AppView.hxx" +#include <com/sun/star/ui/XUIConfigurationManager.hpp> +#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/ui/XImageManager.hpp> +#include <com/sun/star/ui/ImageType.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/util/URL.hpp> +#include <core_resource.hxx> +#include <vcl/svapp.hxx> +#include "AppDetailPageHelper.hxx" +#include <dbaccess/IController.hxx> +#include <algorithm> +#include <dbtreelistbox.hxx> +#include "AppController.hxx" + +using namespace ::dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::graphic; +using namespace ::com::sun::star::ui; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using ::com::sun::star::util::URL; +using ::com::sun::star::sdb::application::NamedDatabaseObject; + +TaskEntry::TaskEntry( const char* _pAsciiUNOCommand, TranslateId _pHelpID, TranslateId pTitleResourceID, bool _bHideWhenDisabled ) + :sUNOCommand( OUString::createFromAscii( _pAsciiUNOCommand ) ) + ,pHelpID( _pHelpID ) + ,sTitle( DBA_RES(pTitleResourceID) ) + ,bHideWhenDisabled( _bHideWhenDisabled ) +{ +} + +void OTasksWindow::updateHelpText() +{ + TranslateId pHelpTextId; + int nCurEntry = m_xTreeView->get_selected_index(); + if (nCurEntry != -1) + pHelpTextId = weld::fromId<TaskEntry*>(m_xTreeView->get_id(nCurEntry))->pHelpID; + setHelpText(pHelpTextId); +} + +IMPL_LINK(OTasksWindow, onSelected, weld::TreeView&, rTreeView, bool) +{ + m_nCursorIndex = rTreeView.get_cursor_index(); + if (m_nCursorIndex != -1) + { + URL aCommand; + aCommand.Complete = weld::fromId<TaskEntry*>(rTreeView.get_id(m_nCursorIndex))->sUNOCommand; + getDetailView()->getBorderWin().getView()->getAppController().executeChecked( aCommand, Sequence< PropertyValue >() ); + } + return true; +} + +void OTasksWindow::GrabFocus() +{ + if (!m_xTreeView) + return; + m_xTreeView->grab_focus(); +} + +bool OTasksWindow::HasChildPathFocus() const +{ + return m_xTreeView && m_xTreeView->has_focus(); +} + +IMPL_LINK_NOARG(OTasksWindow, FocusInHdl, weld::Widget&, void) +{ + m_xTreeView->select(m_nCursorIndex != -1 ? m_nCursorIndex : 0); +} + +IMPL_LINK_NOARG(OTasksWindow, FocusOutHdl, weld::Widget&, void) +{ + m_nCursorIndex = m_xTreeView->get_cursor_index(); + m_xTreeView->unselect_all(); +} + +IMPL_LINK_NOARG(OTasksWindow, OnEntrySelectHdl, weld::TreeView&, void) +{ + m_nCursorIndex = m_xTreeView->get_cursor_index(); + updateHelpText(); +} + +OTasksWindow::OTasksWindow(weld::Container* pParent, OApplicationDetailView* pDetailView) + : OChildWindow(pParent, "dbaccess/ui/taskwindow.ui", "TaskWindow") + , m_xTreeView(m_xBuilder->weld_tree_view("treeview")) + , m_xDescription(m_xBuilder->weld_label("description")) + , m_xHelpText(m_xBuilder->weld_text_view("helptext")) + , m_pDetailView(pDetailView) + , m_nCursorIndex(-1) +{ + m_xContainer->set_stack_background(); + + m_xTreeView->set_help_id(HID_APP_CREATION_LIST); + m_xTreeView->connect_row_activated(LINK(this, OTasksWindow, onSelected)); + m_xTreeView->connect_changed(LINK(this, OTasksWindow, OnEntrySelectHdl)); + m_xTreeView->connect_focus_in(LINK(this, OTasksWindow, FocusInHdl)); + m_xTreeView->connect_focus_out(LINK(this, OTasksWindow, FocusOutHdl)); + // an arbitrary small size it's allowed to shrink to + m_xTreeView->set_size_request(42, 42); + + m_xHelpText->set_help_id(HID_APP_HELP_TEXT); + m_xDescription->set_help_id(HID_APP_DESCRIPTION_TEXT); +} + +OTasksWindow::~OTasksWindow() +{ + Clear(); +} + +void OTasksWindow::setHelpText(TranslateId pId) +{ + if (pId) + m_xHelpText->set_text(DBA_RES(pId)); + else + m_xHelpText->set_text(OUString()); +} + +void OTasksWindow::fillTaskEntryList( const TaskEntryList& _rList ) +{ + Clear(); + + try + { + Reference< XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier = + theModuleUIConfigurationManagerSupplier::get( getDetailView()->getBorderWin().getView()->getORB() ); + Reference< XUIConfigurationManager > xUIConfigMgr = xModuleCfgMgrSupplier->getUIConfigurationManager( + "com.sun.star.sdb.OfficeDatabaseDocument" + ); + Reference< XImageManager > xImageMgr( xUIConfigMgr->getImageManager(), UNO_QUERY ); + + // copy the commands so we can use them with the config managers + Sequence< OUString > aCommands( _rList.size() ); + OUString* pCommands = aCommands.getArray(); + for (auto const& copyTask : _rList) + { + *pCommands = copyTask.sUNOCommand; + ++pCommands; + } + + Sequence< Reference< XGraphic> > aImages = xImageMgr->getImages( + ImageType::SIZE_DEFAULT | ImageType::COLOR_NORMAL , + aCommands + ); + + const Reference< XGraphic >* pImages( aImages.getConstArray() ); + + size_t nIndex = 0; + for (auto const& task : _rList) + { + OUString sId = weld::toId(new TaskEntry(task)); + m_xTreeView->append(sId, task.sTitle); + m_xTreeView->set_image(nIndex++, *pImages++); + } + } + catch(Exception&) + { + } + + m_xTreeView->unselect_all(); + updateHelpText(); + Enable(!_rList.empty()); +} + +void OTasksWindow::Clear() +{ + m_xTreeView->all_foreach([this](weld::TreeIter& rEntry){ + TaskEntry* pUserData = weld::fromId<TaskEntry*>(m_xTreeView->get_id(rEntry)); + delete pUserData; + return false; + }); + + m_xTreeView->clear(); +} + +OApplicationDetailView::OApplicationDetailView(weld::Container* pParent, OAppBorderWindow& rBorder, + PreviewMode ePreviewMode) + : m_xBuilder(Application::CreateBuilder(pParent, "dbaccess/ui/appdetailwindow.ui")) + , m_xContainer(m_xBuilder->weld_container("AppDetailWindow")) + , m_xHorzSplitter(m_xBuilder->weld_paned("splitter")) + , m_xTasksParent(m_xBuilder->weld_container("tasks")) + , m_xContainerParent(m_xBuilder->weld_container("container")) + , m_xTasks(new dbaui::OTitleWindow(m_xTasksParent.get(), STR_TASKS)) + , m_xTitleContainer(new dbaui::OTitleWindow(m_xContainerParent.get(), TranslateId())) + , m_rBorderWin(rBorder) +{ + m_xControlHelper = std::make_shared<OAppDetailPageHelper>(m_xTitleContainer->getChildContainer(), m_rBorderWin, ePreviewMode); + m_xTitleContainer->setChildWindow(m_xControlHelper); + + std::shared_ptr<OChildWindow> xTasks = std::make_shared<OTasksWindow>(m_xTasks->getChildContainer(), this); + xTasks->Enable(!m_rBorderWin.getView()->getCommandController().isDataSourceReadOnly()); + m_xTasks->setChildWindow(xTasks); +} + +OApplicationDetailView::~OApplicationDetailView() +{ +} + +void OApplicationDetailView::setTaskExternalMnemonics( MnemonicGenerator const & rMnemonics ) +{ + m_aExternalMnemonics = rMnemonics; +} + +void OApplicationDetailView::createTablesPage(const Reference< XConnection >& _xConnection ) +{ + impl_createPage( E_TABLE, _xConnection, nullptr ); +} + +void OApplicationDetailView::createPage( ElementType _eType,const Reference< XNameAccess >& _xContainer ) +{ + impl_createPage( _eType, nullptr, _xContainer ); +} + +void OApplicationDetailView::impl_createPage( ElementType _eType, const Reference< XConnection >& _rxConnection, + const Reference< XNameAccess >& _rxNonTableElements ) +{ + // get the data for the pane + const TaskPaneData& rData = impl_getTaskPaneData( _eType ); + getTasksWindow().fillTaskEntryList( rData.aTasks ); + + // enable the pane as a whole, depending on the availability of the first command + OSL_ENSURE( !rData.aTasks.empty(), "OApplicationDetailView::impl_createPage: no tasks at all!?" ); + bool bEnabled = !rData.aTasks.empty() + && getBorderWin().getView()->getCommandController().isCommandEnabled( rData.aTasks[0].sUNOCommand ); + getTasksWindow().Enable( bEnabled ); + m_xTitleContainer->setTitle(rData.pTitleId); + + // let our helper create the object list + if ( _eType == E_TABLE ) + GetControlHelper()->createTablesPage( _rxConnection ); + else + GetControlHelper()->createPage( _eType, _rxNonTableElements ); +} + +void OApplicationDetailView::impl_fillTaskPaneData(ElementType _eType, TaskPaneData& _rData) const +{ + TaskEntryList& rList( _rData.aTasks ); + rList.clear(); rList.reserve( 4 ); + + switch ( _eType ) + { + case E_TABLE: + rList.emplace_back( ".uno:DBNewTable", RID_STR_TABLES_HELP_TEXT_DESIGN, RID_STR_NEW_TABLE ); + rList.emplace_back( ".uno:DBNewTableAutoPilot", RID_STR_TABLES_HELP_TEXT_WIZARD, RID_STR_NEW_TABLE_AUTO ); + rList.emplace_back( ".uno:DBNewView", RID_STR_VIEWS_HELP_TEXT_DESIGN, RID_STR_NEW_VIEW, true ); + _rData.pTitleId = RID_STR_TABLES_CONTAINER; + break; + + case E_FORM: + rList.emplace_back( ".uno:DBNewForm", RID_STR_FORMS_HELP_TEXT, RID_STR_NEW_FORM ); + rList.emplace_back( ".uno:DBNewFormAutoPilot", RID_STR_FORMS_HELP_TEXT_WIZARD, RID_STR_NEW_FORM_AUTO ); + _rData.pTitleId = RID_STR_FORMS_CONTAINER; + break; + + case E_REPORT: + rList.emplace_back( ".uno:DBNewReport", RID_STR_REPORT_HELP_TEXT, RID_STR_NEW_REPORT, true ); + rList.emplace_back( ".uno:DBNewReportAutoPilot", RID_STR_REPORTS_HELP_TEXT_WIZARD, RID_STR_NEW_REPORT_AUTO ); + _rData.pTitleId = RID_STR_REPORTS_CONTAINER; + break; + + case E_QUERY: + rList.emplace_back( ".uno:DBNewQuery", RID_STR_QUERIES_HELP_TEXT, RID_STR_NEW_QUERY ); + rList.emplace_back( ".uno:DBNewQueryAutoPilot", RID_STR_QUERIES_HELP_TEXT_WIZARD, RID_STR_NEW_QUERY_AUTO ); + rList.emplace_back( ".uno:DBNewQuerySql", RID_STR_QUERIES_HELP_TEXT_SQL, RID_STR_NEW_QUERY_SQL ); + _rData.pTitleId = RID_STR_QUERIES_CONTAINER; + break; + + default: + OSL_FAIL( "OApplicationDetailView::impl_fillTaskPaneData: illegal element type!" ); + } + + // remove the entries which are not enabled currently + for (TaskEntryList::iterator pTask = rList.begin(); pTask != rList.end();) + { + if ( pTask->bHideWhenDisabled + && !getBorderWin().getView()->getCommandController().isCommandEnabled( pTask->sUNOCommand ) + ) + pTask = rList.erase( pTask ); + else + { + ++pTask; + } + } +} + +const TaskPaneData& OApplicationDetailView::impl_getTaskPaneData( ElementType _eType ) +{ + if ( m_aTaskPaneData.empty() ) + m_aTaskPaneData.resize( size_t(E_ELEMENT_TYPE_COUNT) ); + OSL_ENSURE( ( _eType >= 0 ) && ( _eType < E_ELEMENT_TYPE_COUNT ), "OApplicationDetailView::impl_getTaskPaneData: illegal element type!" ); + TaskPaneData& rData = m_aTaskPaneData[ _eType ]; + + //oj: do not check, otherwise extensions will only be visible after a reload. + impl_fillTaskPaneData( _eType, rData ); + + return rData; +} + +OUString OApplicationDetailView::getQualifiedName(const weld::TreeIter* _pEntry) const +{ + return GetControlHelper()->getQualifiedName( _pEntry ); +} + +bool OApplicationDetailView::isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry) +{ + return OAppDetailPageHelper::isLeaf(rTreeView, rEntry); +} + +bool OApplicationDetailView::isALeafSelected() const +{ + return GetControlHelper()->isALeafSelected(); +} + +void OApplicationDetailView::selectAll() +{ + GetControlHelper()->selectAll(); +} + +void OApplicationDetailView::sortDown() +{ + GetControlHelper()->sortDown(); +} + +void OApplicationDetailView::sortUp() +{ + GetControlHelper()->sortUp(); +} + +bool OApplicationDetailView::isFilled() const +{ + return GetControlHelper()->isFilled(); +} + +ElementType OApplicationDetailView::getElementType() const +{ + return GetControlHelper()->getElementType(); +} + +void OApplicationDetailView::clearPages(bool _bTaskAlso) +{ + if ( _bTaskAlso ) + getTasksWindow().Clear(); + GetControlHelper()->clearPages(); +} + +sal_Int32 OApplicationDetailView::getSelectionCount() +{ + return GetControlHelper()->getSelectionCount(); +} + +sal_Int32 OApplicationDetailView::getElementCount() const +{ + return GetControlHelper()->getElementCount(); +} + +void OApplicationDetailView::getSelectionElementNames( std::vector< OUString>& _rNames ) const +{ + GetControlHelper()->getSelectionElementNames( _rNames ); +} + +void OApplicationDetailView::describeCurrentSelectionForControl(const weld::TreeView& rControl, Sequence< NamedDatabaseObject >& out_rSelectedObjects) +{ + GetControlHelper()->describeCurrentSelectionForControl(rControl, out_rSelectedObjects); +} + +void OApplicationDetailView::describeCurrentSelectionForType( const ElementType _eType, Sequence< NamedDatabaseObject >& _out_rSelectedObjects ) +{ + GetControlHelper()->describeCurrentSelectionForType( _eType, _out_rSelectedObjects ); +} + +vcl::Window* OApplicationDetailView::getMenuParent() const +{ + return GetControlHelper()->getMenuParent(); +} + +void OApplicationDetailView::adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const +{ + return GetControlHelper()->adjustMenuPosition(rControl, rPos); +} + +void OApplicationDetailView::selectElements(const Sequence< OUString>& _aNames) +{ + GetControlHelper()->selectElements( _aNames ); +} + +std::unique_ptr<weld::TreeIter> OApplicationDetailView::getEntry(const Point& rPoint) const +{ + return GetControlHelper()->getEntry(rPoint); +} + +bool OApplicationDetailView::isCutAllowed() +{ + return false; +} + +bool OApplicationDetailView::isCopyAllowed() +{ + return true; +} + +bool OApplicationDetailView::isPasteAllowed() { return true; } + +void OApplicationDetailView::copy() { } + +void OApplicationDetailView::cut() { } + +void OApplicationDetailView::paste() { } + +std::unique_ptr<weld::TreeIter> OApplicationDetailView::elementAdded(ElementType _eType,const OUString& _rName, const Any& _rObject ) +{ + return GetControlHelper()->elementAdded(_eType, _rName, _rObject); +} + +void OApplicationDetailView::elementRemoved(ElementType _eType,const OUString& _rName ) +{ + GetControlHelper()->elementRemoved(_eType,_rName ); +} + +void OApplicationDetailView::elementReplaced(ElementType _eType + ,const OUString& _rOldName + ,const OUString& _rNewName ) +{ + GetControlHelper()->elementReplaced( _eType, _rOldName, _rNewName ); +} + +PreviewMode OApplicationDetailView::getPreviewMode() const +{ + return GetControlHelper()->getPreviewMode(); +} + +bool OApplicationDetailView::isPreviewEnabled() const +{ + return GetControlHelper()->isPreviewEnabled(); +} + +void OApplicationDetailView::switchPreview(PreviewMode _eMode) +{ + GetControlHelper()->switchPreview(_eMode); +} + +void OApplicationDetailView::showPreview(const Reference< XContent >& _xContent) +{ + GetControlHelper()->showPreview(_xContent); +} + +void OApplicationDetailView::showPreview( const OUString& _sDataSourceName, + const OUString& _sName, + bool _bTable) +{ + GetControlHelper()->showPreview(_sDataSourceName,_sName,_bTable); +} + +bool OApplicationDetailView::isSortUp() const +{ + return GetControlHelper()->isSortUp(); +} + +TreeListBox* OApplicationDetailView::getTreeWindow() const +{ + DBTreeViewBase* pCurrent = GetControlHelper()->getCurrentView(); + if (!pCurrent) + return nullptr; + return &pCurrent->getListBox(); +} + +OAppDetailPageHelper* OApplicationDetailView::GetControlHelper() +{ + return static_cast<OAppDetailPageHelper*>(m_xControlHelper.get()); +} + +const OAppDetailPageHelper* OApplicationDetailView::GetControlHelper() const +{ + return static_cast<const OAppDetailPageHelper*>(m_xControlHelper.get()); +} + +bool OApplicationDetailView::HasChildPathFocus() const +{ + return m_xHorzSplitter->has_focus() || + m_xTasks->HasChildPathFocus() || + m_xTitleContainer->HasChildPathFocus(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppDetailView.hxx b/dbaccess/source/ui/app/AppDetailView.hxx new file mode 100644 index 000000000..f074df440 --- /dev/null +++ b/dbaccess/source/ui/app/AppDetailView.hxx @@ -0,0 +1,318 @@ +/* -*- 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> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp> +#include <vcl/mnemonic.hxx> +#include <IClipBoardTest.hxx> +#include "AppTitleWindow.hxx" +#include <AppElementType.hxx> + +#include <vector> + +namespace dbaui +{ + class OAppBorderWindow; + class OApplicationDetailView; + class OAppDetailPageHelper; + class OTasksWindow; + class TreeListBox; + + struct TaskEntry + { + OUString sUNOCommand; + TranslateId pHelpID; + OUString sTitle; + bool bHideWhenDisabled; + // TODO: we should be consistent in the task pane and the menus/toolbars: + // If an entry is disabled in the latter, it should also be disabled in the former. + // If an entry is *hidden* in the former, it should also be hidden in the latter. + + TaskEntry( const char* _pAsciiUNOCommand, TranslateId pHelpID, TranslateId pTitleResourceID, bool _bHideWhenDisabled = false ); + }; + typedef std::vector< TaskEntry > TaskEntryList; + + struct TaskPaneData + { + /// the tasks available in the pane + TaskEntryList aTasks; + /// the resource ID for the title of the pane + TranslateId pTitleId; + }; + + class OTasksWindow final : public OChildWindow + { + std::unique_ptr<weld::TreeView> m_xTreeView; + std::unique_ptr<weld::Label> m_xDescription; + std::unique_ptr<weld::TextView> m_xHelpText; + OApplicationDetailView* m_pDetailView; + + int m_nCursorIndex; + + DECL_LINK(onSelected, weld::TreeView&, bool); + DECL_LINK(OnEntrySelectHdl, weld::TreeView&, void); + DECL_LINK(FocusInHdl, weld::Widget&, void); + DECL_LINK(FocusOutHdl, weld::Widget&, void); + + void updateHelpText(); + + public: + OTasksWindow(weld::Container* pParent, OApplicationDetailView* pDetailView); + ~OTasksWindow(); + + virtual void GrabFocus() override; + + virtual bool HasChildPathFocus() const override; + + OApplicationDetailView* getDetailView() const { return m_pDetailView; } + + /// fills the Creation listbox with the necessary strings and images + void fillTaskEntryList( const TaskEntryList& _rList ); + + void Clear(); + void setHelpText(TranslateId pId); + }; + + class OApplicationDetailView final : public IClipboardTest + { + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Container> m_xContainer; + std::unique_ptr<weld::Paned> m_xHorzSplitter; + std::unique_ptr<weld::Container> m_xTasksParent; + std::unique_ptr<weld::Container> m_xContainerParent; + std::unique_ptr<OTitleWindow> m_xTasks; + std::unique_ptr<OTitleWindow> m_xTitleContainer; + OAppBorderWindow& m_rBorderWin; // my parent + std::shared_ptr<OChildWindow> m_xControlHelper; + std::vector< TaskPaneData > m_aTaskPaneData; + MnemonicGenerator m_aExternalMnemonics; + + const OAppDetailPageHelper* GetControlHelper() const; + OAppDetailPageHelper* GetControlHelper(); + + public: + OApplicationDetailView(weld::Container* pParent, OAppBorderWindow& rBorder, PreviewMode ePreviewMode); + ~OApplicationDetailView(); + + /** creates the tables page + @param _xConnection + The connection to get the table names + */ + void createTablesPage(const css::uno::Reference< css::sdbc::XConnection>& _xConnection); + + /** creates the page for the specific type. + @param _eType + The type which should be created. E_TABLE isn't allowed. + @param _xContainer + The container of the elements to be inserted. + */ + void createPage(ElementType _eType,const css::uno::Reference< css::container::XNameAccess >& _xContainer); + + void setTaskExternalMnemonics( MnemonicGenerator const & _rMnemonics ); + + OAppBorderWindow& getBorderWin() const { return m_rBorderWin; } + OTasksWindow& getTasksWindow() const { return *static_cast< OTasksWindow* >( m_xTasks->getChildWindow() ); } + + bool isCutAllowed() override ; + bool isCopyAllowed() override ; + bool isPasteAllowed() override; + void copy() override; + void cut() override; + void paste() override; + + /** return the qualified name. + @param _pEntry + The entry of a table, or query, form, report to get the qualified name. + If the entry is <NULL/>, the first selected is chosen. + @return + the qualified name + */ + OUString getQualifiedName(const weld::TreeIter* _pEntry) const; + + /** returns if an entry is a leaf + @param rTreeView + The TreeView pEntry belongs to + @param rEntry + The entry to check + @return + <TRUE/> if the entry is a leaf, otherwise <FALSE/> + */ + static bool isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry); + + /** returns if one of the selected entries is a leaf + @return + <TRUE/> if the entry is a leaf, otherwise <FALSE/> + */ + bool isALeafSelected() const; + + /** select all entries in the detail page + */ + void selectAll(); + + /// returns <TRUE/> if it sorts ascending + bool isSortUp() const; + + /// sort the entries in the detail page down + void sortDown(); + + /// sort the entries in the detail page up + void sortUp(); + + /// returns <TRUE/> when a detail page was filled + bool isFilled() const; + + /// return the element of currently select entry + ElementType getElementType() const; + + /** clears the detail pages. + @param _bTaskAlso + If <TRUE/> the task window will also be cleared. + */ + void clearPages(bool _bTaskAlso = true); + + /// returns the count of entries + sal_Int32 getElementCount() const; + + /// returns the count of selected entries + sal_Int32 getSelectionCount(); + + /** returns the element names which are selected + @param _rNames + The list will be filled. + */ + void getSelectionElementNames(std::vector< OUString>& _rNames ) const; + + /** describes the current selection for the given control + */ + void describeCurrentSelectionForControl( + const weld::TreeView& rControl, + css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects + ); + + /** describes the current selection for the given ElementType + */ + void describeCurrentSelectionForType( + const ElementType _eType, + css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects + ); + + /** get the menu parent window for the given control + */ + vcl::Window* getMenuParent() const; + void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const; + + /** select all names on the currently selected container. Non existence names where ignored. + * + * \param _aNames the element names + */ + void selectElements(const css::uno::Sequence< OUString>& _aNames); + + /** adds a new object to the detail page. + @param _eType + The type where the entry should be appended. + @param _rName + The name of the object to be inserted + @param _rObject + The object to add. + @param _rxConn + If we insert a table, the connection must be set. + */ + std::unique_ptr<weld::TreeIter> elementAdded(ElementType eType, + const OUString& rName, + const css::uno::Any& rObject); + + /** replaces an objects name with a new one + @param _eType + The type where the entry should be appended. + @param _rOldName + The old name of the object to be replaced + @param _rNewName + The new name of the object to be replaced + @param _rxConn + If we insert a table, the connection must be set. + @param _xObject + The object which was replaced + */ + void elementReplaced(ElementType eType + ,const OUString& _rOldName + ,const OUString& _rNewName ); + + /** removes an element from the detail page. + @param _eType + The type where the entry should be appended. + @param _rName + The name of the element to be removed. + @param _rxConn + If we remove a table, the connection must be set. + */ + void elementRemoved(ElementType _eType + ,const OUString& _rName ); + + /// returns the preview mode + PreviewMode getPreviewMode() const; + + /// <TRUE/> if the preview is enabled + bool isPreviewEnabled() const; + + /** switches to the given preview mode + @param _eMode + the mode to set for the preview + */ + void switchPreview(PreviewMode _eMode); + + /** shows the Preview of the content when it is enabled. + @param _xContent + The content which must support the "preview" command. + */ + void showPreview(const css::uno::Reference< css::ucb::XContent >& _xContent); + + /** shows the Preview of a table or query + @param _sDataSourceName + the name of the data source + @param _sName + the name of table or query + @param _bTable + <TRUE/> if it is a table, otherwise <FALSE/> + @return void + */ + void showPreview( const OUString& _sDataSourceName, + const OUString& _sName, + bool _bTable); + + std::unique_ptr<weld::TreeIter> getEntry(const Point& rPosPixel) const; + + TreeListBox* getTreeWindow() const; + + bool HasChildPathFocus() const; + private: + void impl_createPage( + ElementType _eType, + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + const css::uno::Reference< css::container::XNameAccess >& _rxNonTableElements + ); + + const TaskPaneData& impl_getTaskPaneData( ElementType _eType ); + void impl_fillTaskPaneData( ElementType _eType, TaskPaneData& _rData ) const; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppIconControl.cxx b/dbaccess/source/ui/app/AppIconControl.cxx new file mode 100644 index 000000000..1448c4015 --- /dev/null +++ b/dbaccess/source/ui/app/AppIconControl.cxx @@ -0,0 +1,238 @@ +/* -*- 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 "AppIconControl.hxx" +#include <core_resource.hxx> +#include <strings.hrc> +#include <bitmaps.hlst> +#include <sfx2/thumbnailviewitem.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/event.hxx> +#include <vcl/i18nhelp.hxx> +#include <vcl/mnemonic.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <callbacks.hxx> +#include <AppElementType.hxx> + +namespace dbaui +{ +class OApplicationIconControlDropTarget final : public DropTargetHelper +{ +private: + OApplicationIconControl& m_rControl; + +public: + OApplicationIconControlDropTarget(OApplicationIconControl& rControl) + : DropTargetHelper(rControl.GetDrawingArea()->get_drop_target()) + , m_rControl(rControl) + { + } + + virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override + { + return m_rControl.AcceptDrop(rEvt); + } + + virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override + { + return m_rControl.ExecuteDrop(rEvt); + } +}; + +OApplicationIconControl::OApplicationIconControl(std::unique_ptr<weld::ScrolledWindow> xScroll) + : ThumbnailView(std::move(xScroll), nullptr) + , m_pActionListener(nullptr) + , m_nMaxWidth(0) + , m_nMaxHeight(0) +{ + mnVItemSpace = 6; // row spacing + mbSelectOnFocus = false; + DrawMnemonics(true); +} + +void OApplicationIconControl::Fill() +{ + static const struct CategoryDescriptor + { + TranslateId pLabelResId; + ElementType eType; + rtl::OUStringConstExpr aImageResId; + } aCategories[] = { { RID_STR_TABLES_CONTAINER, E_TABLE, BMP_TABLEFOLDER_TREE_L }, + { RID_STR_QUERIES_CONTAINER, E_QUERY, BMP_QUERYFOLDER_TREE_L }, + { RID_STR_FORMS_CONTAINER, E_FORM, BMP_FORMFOLDER_TREE_L }, + { RID_STR_REPORTS_CONTAINER, E_REPORT, BMP_REPORTFOLDER_TREE_L } }; + + for (const CategoryDescriptor& aCategorie : aCategories) + { + // E_TABLE is 0, but 0 means void so use id of enum + 1 + std::unique_ptr<ThumbnailViewItem> xItem( + new ThumbnailViewItem(*this, aCategorie.eType + 1)); + xItem->mbBorder = false; + xItem->maPreview1 = BitmapEx(aCategorie.aImageResId); + const Size& rSize = xItem->maPreview1.GetSizePixel(); + m_nMaxWidth = std::max(m_nMaxWidth, rSize.Width()); + m_nMaxHeight = std::max(m_nMaxHeight, rSize.Height()); + xItem->maTitle = DBA_RES(aCategorie.pLabelResId); + m_nMaxWidth = std::max<tools::Long>(m_nMaxWidth, GetTextWidth(xItem->maTitle)); + AppendItem(std::move(xItem)); + } + + const int nMargin = 12; + const int nWidthRequest = m_nMaxWidth + 2 * nMargin; + set_size_request(nWidthRequest, -1); + // we expect a Resize at which point we'll set the item sizes based on our final size +} + +ElementType OApplicationIconControl::GetSelectedItem() const +{ + for (const auto& rItem : mItemList) + { + if (!rItem->mbSelected) + continue; + return static_cast<ElementType>(rItem->mnId - 1); + } + return E_NONE; +} + +void OApplicationIconControl::createIconAutoMnemonics(MnemonicGenerator& rMnemonics) +{ + for (const auto& rItem : mItemList) + rMnemonics.RegisterMnemonic(rItem->maTitle); + + // exchange texts with generated mnemonics + for (auto& rItem : mItemList) + rItem->maTitle = rMnemonics.CreateMnemonic(rItem->maTitle); +} + +void OApplicationIconControl::Resize() +{ + // fill the full width of the allocated area and give two lines of space to + // center the title in + setItemDimensions(GetOutputSizePixel().Width(), m_nMaxHeight, GetTextHeight() * 2, 0); + ThumbnailView::Resize(); +} + +bool OApplicationIconControl::IsMnemonicChar(sal_Unicode cChar, ElementType& rType) const +{ + bool bRet = false; + + const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper(); + for (const auto& rItem : mItemList) + { + if (rI18nHelper.MatchMnemonic(rItem->maTitle, cChar)) + { + bRet = true; + rType = static_cast<ElementType>(rItem->mnId - 1); + break; + } + } + + return bRet; +} + +bool OApplicationIconControl::DoKeyShortCut(const KeyEvent& rKEvt) +{ + bool bMod2 = rKEvt.GetKeyCode().IsMod2(); + sal_Unicode cChar = rKEvt.GetCharCode(); + ElementType eType(E_NONE); + if (bMod2 && cChar && IsMnemonicChar(cChar, eType)) + { + // shortcut is clicked + deselectItems(); + SelectItem(eType + 1); + return true; + } + + return false; +} + +bool OApplicationIconControl::KeyInput(const KeyEvent& rKEvt) +{ + return DoKeyShortCut(rKEvt) || ThumbnailView::KeyInput(rKEvt); +} + +void OApplicationIconControl::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + ThumbnailView::SetDrawingArea(pDrawingArea); + m_xDropTarget.reset(new OApplicationIconControlDropTarget(*this)); +} + +sal_Int8 OApplicationIconControl::AcceptDrop(const AcceptDropEvent& rEvt) +{ + sal_Int8 nDropOption = DND_ACTION_NONE; + if (m_pActionListener) + { + sal_uInt16 nEntry = GetItemId(rEvt.maPosPixel); + if (nEntry) + { + deselectItems(); + SelectItem(nEntry); + nDropOption + = m_pActionListener->queryDrop(rEvt, m_xDropTarget->GetDataFlavorExVector()); + } + } + return nDropOption; +} + +sal_Int8 OApplicationIconControl::ExecuteDrop(const ExecuteDropEvent& rEvt) +{ + if (m_pActionListener) + m_pActionListener->executeDrop(rEvt); + return DND_ACTION_NONE; +} + +OApplicationIconControl::~OApplicationIconControl() {} + +void OApplicationIconControl::GetFocus() +{ + ThumbnailView::GetFocus(); + Invalidate(); // redraw focus rect +} + +void OApplicationIconControl::LoseFocus() +{ + ThumbnailView::LoseFocus(); + Invalidate(); // redraw focus rect +} + +tools::Rectangle OApplicationIconControl::GetFocusRect() +{ + if (HasFocus()) + { + // Get the last selected item in the list + for (tools::Long i = mFilteredItemList.size() - 1; i >= 0; --i) + { + ThumbnailViewItem* pItem = mFilteredItemList[i]; + if (pItem->isSelected()) + { + tools::Rectangle aRet(pItem->getDrawArea()); + aRet.AdjustLeft(THUMBNAILVIEW_ITEM_CORNER); + aRet.AdjustTop(1); + aRet.AdjustRight(-THUMBNAILVIEW_ITEM_CORNER); + aRet.AdjustBottom(-2); + return aRet; + } + } + } + return tools::Rectangle(); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppIconControl.hxx b/dbaccess/source/ui/app/AppIconControl.hxx new file mode 100644 index 000000000..1146a77a1 --- /dev/null +++ b/dbaccess/source/ui/app/AppIconControl.hxx @@ -0,0 +1,67 @@ +/* -*- 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 <sfx2/thumbnailview.hxx> +#include <vcl/transfer.hxx> +#include <vcl/weld.hxx> +#include <AppElementType.hxx> + +class MnemonicGenerator; + +namespace dbaui +{ + class IControlActionListener; + class IconControl; + class OApplicationIconControlDropTarget; + + class OApplicationIconControl final : public ThumbnailView + { + std::unique_ptr<OApplicationIconControlDropTarget> m_xDropTarget; + IControlActionListener* m_pActionListener; + + tools::Long m_nMaxWidth; + tools::Long m_nMaxHeight; + + bool IsMnemonicChar(sal_Unicode cChar, ElementType& rType) const; + + public: + explicit OApplicationIconControl(std::unique_ptr<weld::ScrolledWindow> xScroll); + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + virtual void Resize() override; + virtual tools::Rectangle GetFocusRect() override; + virtual void GetFocus() override; + virtual void LoseFocus() override; + bool DoKeyShortCut(const KeyEvent& rKEvt); + virtual bool KeyInput(const KeyEvent& rKEvt) override; + virtual ~OApplicationIconControl() override; + + ElementType GetSelectedItem() const; + + void setControlActionListener( IControlActionListener* _pListener ) { m_pActionListener = _pListener; } + void Fill(); + + void createIconAutoMnemonics(MnemonicGenerator& rMnemonics); + + sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt); + sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppSwapWindow.cxx b/dbaccess/source/ui/app/AppSwapWindow.cxx new file mode 100644 index 000000000..ea2066c72 --- /dev/null +++ b/dbaccess/source/ui/app/AppSwapWindow.cxx @@ -0,0 +1,133 @@ +/* -*- 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 "AppSwapWindow.hxx" +#include <helpids.h> +#include "AppView.hxx" +#include <sfx2/thumbnailviewitem.hxx> +#include <vcl/event.hxx> +#include <vcl/mnemonic.hxx> +#include <vcl/svapp.hxx> +#include "AppController.hxx" + +using namespace ::dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; + +OApplicationSwapWindow::OApplicationSwapWindow(weld::Container* pParent, + OAppBorderWindow& rBorderWindow) + : OChildWindow(pParent, "dbaccess/ui/appswapwindow.ui", "AppSwapWindow") + , m_xIconControl(new OApplicationIconControl(m_xBuilder->weld_scrolled_window("scroll", true))) + , m_xIconControlWin(new weld::CustomWeld(*m_xBuilder, "valueset", *m_xIconControl)) + , m_eLastType(E_NONE) + , m_rBorderWin(rBorderWindow) + , m_nChangeEvent(nullptr) +{ + m_xContainer->set_stack_background(); + + m_xIconControl->SetHelpId(HID_APP_SWAP_ICONCONTROL); + m_xIconControl->Fill(); + m_xIconControl->setItemStateHdl(LINK(this, OApplicationSwapWindow, OnContainerSelectHdl)); + m_xIconControl->setControlActionListener(&m_rBorderWin.getView()->getAppController()); +} + +void OApplicationSwapWindow::GrabFocus() +{ + if (m_xIconControl) + m_xIconControl->GrabFocus(); +} + +bool OApplicationSwapWindow::HasChildPathFocus() const +{ + return m_xIconControl && m_xIconControl->HasFocus(); +} + +OApplicationSwapWindow::~OApplicationSwapWindow() +{ + if (m_nChangeEvent) + Application::RemoveUserEvent(m_nChangeEvent); +} + +void OApplicationSwapWindow::clearSelection() +{ + m_xIconControl->deselectItems(); + onContainerSelected(E_NONE); +} + +void OApplicationSwapWindow::createIconAutoMnemonics(MnemonicGenerator& rMnemonics) +{ + m_xIconControl->createIconAutoMnemonics(rMnemonics); +} + +bool OApplicationSwapWindow::interceptKeyInput(const KeyEvent& _rEvent) +{ + const vcl::KeyCode& rKeyCode = _rEvent.GetKeyCode(); + if (rKeyCode.GetModifier() == KEY_MOD2) + return m_xIconControl->DoKeyShortCut(_rEvent); + // not handled + return false; +} + +ElementType OApplicationSwapWindow::getElementType() const +{ + return m_xIconControl->GetSelectedItem(); +} + +bool OApplicationSwapWindow::onContainerSelected(ElementType _eType) +{ + if (m_eLastType == _eType) + return true; + + if (m_rBorderWin.getView()->getAppController().onContainerSelect(_eType)) + { + if (_eType != E_NONE) + m_eLastType = _eType; + return true; + } + + if (!m_nChangeEvent) + m_nChangeEvent + = Application::PostUserEvent(LINK(this, OApplicationSwapWindow, ChangeToLastSelected)); + return false; +} + +IMPL_LINK(OApplicationSwapWindow, OnContainerSelectHdl, const ThumbnailViewItem*, pEntry, void) +{ + if (pEntry->mbSelected) + { + ElementType eType = static_cast<ElementType>(pEntry->mnId - 1); + onContainerSelected(eType); // i87582 + } +} + +IMPL_LINK_NOARG(OApplicationSwapWindow, ChangeToLastSelected, void*, void) +{ + m_nChangeEvent = nullptr; + selectContainer(m_eLastType); +} + +void OApplicationSwapWindow::selectContainer(ElementType eType) +{ + m_xIconControl->deselectItems(); + m_xIconControl->SelectItem(eType + 1); // will trigger onContainerSelected +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppSwapWindow.hxx b/dbaccess/source/ui/app/AppSwapWindow.hxx new file mode 100644 index 000000000..1ce972e3b --- /dev/null +++ b/dbaccess/source/ui/app/AppSwapWindow.hxx @@ -0,0 +1,88 @@ +/* -*- 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 <IClipBoardTest.hxx> +#include "AppIconControl.hxx" +#include <AppElementType.hxx> +#include <ChildWindow.hxx> + +struct ImplSVEvent; +class MnemonicGenerator; + +namespace dbaui +{ + class OAppBorderWindow; + class OApplicationSwapWindow : public OChildWindow + , public IClipboardTest + { + std::unique_ptr<OApplicationIconControl> m_xIconControl; + std::unique_ptr<weld::CustomWeld> m_xIconControlWin; + ElementType m_eLastType; + OAppBorderWindow& m_rBorderWin; + ImplSVEvent* m_nChangeEvent; + + DECL_LINK( OnContainerSelectHdl, const ThumbnailViewItem*, void ); + DECL_LINK( ChangeToLastSelected, void*, void ); + + public: + OApplicationSwapWindow(weld::Container* pParent, OAppBorderWindow& rBorderWindow); + virtual ~OApplicationSwapWindow() override; + + virtual void GrabFocus() override; + virtual bool HasChildPathFocus() const override; + + bool isCutAllowed() override { return false; } + bool isCopyAllowed() override { return false; } + bool isPasteAllowed() override { return false; } + void copy() override { } + void cut() override { } + void paste() override { } + + /** automatically creates mnemonics for the icon/texts in our left hand side panel + */ + void createIconAutoMnemonics( MnemonicGenerator& _rMnemonics ); + + /** called to give the window the chance to intercept key events, while it has not + the focus + + @return <TRUE/> if and only if the event has been handled, and should not + not be further processed + */ + bool interceptKeyInput( const KeyEvent& _rEvent ); + + /// return the element of currently select entry + ElementType getElementType() const; + + /** clears the selection in the icon choice control and calls the handler + */ + void clearSelection(); + + /** changes the container which should be displayed. The select handler will also be called. + @param _eType + Which container to show. + */ + void selectContainer(ElementType _eType); + + private: + bool onContainerSelected( ElementType _eType ); + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppTitleWindow.cxx b/dbaccess/source/ui/app/AppTitleWindow.cxx new file mode 100644 index 000000000..d5e604394 --- /dev/null +++ b/dbaccess/source/ui/app/AppTitleWindow.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 <core_resource.hxx> +#include <vcl/svapp.hxx> +#include "AppTitleWindow.hxx" + +namespace dbaui +{ +OTitleWindow::OTitleWindow(weld::Container* pParent, TranslateId pTitleId) + : m_xBuilder(Application::CreateBuilder(pParent, "dbaccess/ui/titlewindow.ui")) + , m_xContainer(m_xBuilder->weld_container("TitleWindow")) + , m_xTitleFrame(m_xBuilder->weld_container("titleparent")) + , m_xTitle(m_xBuilder->weld_label("title")) + , m_xChildContainer(m_xBuilder->weld_container("box")) +{ + setTitle(pTitleId); + + m_xContainer->set_stack_background(); + m_xTitleFrame->set_title_background(); + m_xTitle->set_label_type(weld::LabelType::Title); +} + +OTitleWindow::~OTitleWindow() {} + +weld::Container* OTitleWindow::getChildContainer() { return m_xChildContainer.get(); } + +void OTitleWindow::setChildWindow(const std::shared_ptr<OChildWindow>& rChild) +{ + m_xChild = rChild; +} + +void OTitleWindow::setTitle(TranslateId pTitleId) +{ + if (!pTitleId) + return; + m_xTitle->set_label(DBA_RES(pTitleId)); +} + +void OTitleWindow::GrabFocus() +{ + if (m_xChild) + m_xChild->GrabFocus(); +} + +bool OTitleWindow::HasChildPathFocus() const { return m_xChild && m_xChild->HasChildPathFocus(); } + +} // namespace dbaui +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppTitleWindow.hxx b/dbaccess/source/ui/app/AppTitleWindow.hxx new file mode 100644 index 000000000..d57f52416 --- /dev/null +++ b/dbaccess/source/ui/app/AppTitleWindow.hxx @@ -0,0 +1,67 @@ +/* -*- 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 <ChildWindow.hxx> +#include <unotools/resmgr.hxx> + +namespace dbaui +{ + class OTitleWindow final + { + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Container> m_xContainer; + std::unique_ptr<weld::Container> m_xTitleFrame; + std::unique_ptr<weld::Label> m_xTitle; + std::unique_ptr<weld::Container> m_xChildContainer; + std::shared_ptr<OChildWindow> m_xChild; + + public: + OTitleWindow(weld::Container* pParent, TranslateId pTitleId); + ~OTitleWindow(); + + void GrabFocus(); + + bool HasChildPathFocus() const; + + /** gets the window which should be used as a child's parent */ + weld::Container* getChildContainer(); + + /** sets the child window which should be displayed below the title. It will be destroyed at the end. + @param _pChild + The child window. + */ + void setChildWindow(const std::shared_ptr<OChildWindow>& rChild); + + /** gets the child window. + + @return + The child window. + */ + OChildWindow* getChildWindow() const { return m_xChild.get(); } + + /** sets the title text out of the resource + @param pTitleId + The resource id of the title text. + */ + void setTitle(TranslateId pTitleId); + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppView.cxx b/dbaccess/source/ui/app/AppView.cxx new file mode 100644 index 000000000..b300df8df --- /dev/null +++ b/dbaccess/source/ui/app/AppView.cxx @@ -0,0 +1,473 @@ +/* -*- 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 "AppView.hxx" +#include <strings.hrc> +#include <tools/diagnose_ex.h> +#include <vcl/event.hxx> +#include <vcl/weld.hxx> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include "AppDetailView.hxx" +#include "AppSwapWindow.hxx" +#include <vcl/settings.hxx> +#include "AppTitleWindow.hxx" +#include "AppController.hxx" + +using namespace ::dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::datatransfer::clipboard; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using ::com::sun::star::sdb::application::NamedDatabaseObject; + +OAppBorderWindow::OAppBorderWindow(OApplicationView* pParent, PreviewMode ePreviewMode) + : InterimItemWindow(pParent, "dbaccess/ui/appborderwindow.ui", "AppBorderWindow", false) + , m_xPanelParent(m_xBuilder->weld_container("panel")) + , m_xDetailViewParent(m_xBuilder->weld_container("detail")) + , m_xView(pParent) +{ + SetStyle(GetStyle() | WB_DIALOGCONTROL); + + m_xPanel.reset(new OTitleWindow(m_xPanelParent.get(), STR_DATABASE)); + std::shared_ptr<OChildWindow> xSwap = std::make_shared<OApplicationSwapWindow>(m_xPanel->getChildContainer(), *this); + + m_xPanel->setChildWindow(xSwap); + + m_xDetailView.reset(new OApplicationDetailView(m_xDetailViewParent.get(), *this, ePreviewMode)); + + ImplInitSettings(); +} + +OAppBorderWindow::~OAppBorderWindow() +{ + disposeOnce(); +} + +void OAppBorderWindow::dispose() +{ + // destroy children + m_xPanel.reset(); + m_xDetailView.reset(); + m_xPanelParent.reset(); + m_xDetailViewParent.reset(); + m_xView.clear(); + InterimItemWindow::dispose(); +} + +void OAppBorderWindow::GetFocus() +{ + if (m_xPanel) + m_xPanel->GrabFocus(); +} + +OApplicationSwapWindow* OAppBorderWindow::getPanel() const +{ + return static_cast<OApplicationSwapWindow*>(m_xPanel->getChildWindow()); +} + +OApplicationView::OApplicationView( vcl::Window* pParent + ,const Reference< XComponentContext >& _rxOrb + ,OApplicationController& _rAppController + ,PreviewMode _ePreviewMode + ) : + ODataView( pParent, _rAppController, _rxOrb, WB_DIALOGCONTROL ) + ,m_rAppController( _rAppController ) +{ + m_pWin = VclPtr<OAppBorderWindow>::Create(this,_ePreviewMode); + m_pWin->Show(); + + ImplInitSettings(); +} + +OApplicationView::~OApplicationView() +{ + disposeOnce(); +} + +void OApplicationView::dispose() +{ + stopComponentListening(m_xObject); + m_xObject.clear(); + m_pWin->Hide(); + m_pWin.disposeAndClear(); + ODataView::dispose(); +} + +void OApplicationView::createIconAutoMnemonics( MnemonicGenerator& _rMnemonics ) +{ + if ( m_pWin && m_pWin->getPanel() ) + m_pWin->getPanel()->createIconAutoMnemonics( _rMnemonics ); +} + +void OApplicationView::setTaskExternalMnemonics( MnemonicGenerator const & _rMnemonics ) +{ + if ( m_pWin && m_pWin->getDetailView() ) + m_pWin->getDetailView()->setTaskExternalMnemonics( _rMnemonics ); +} + +void OApplicationView::DataChanged( const DataChangedEvent& rDCEvt ) +{ + ODataView::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) || + (rDCEvt.GetType() == DataChangedEventType::DISPLAY) || + (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) ) + { + ImplInitSettings(); + Invalidate(); + } +} + +void OApplicationView::resizeDocumentView(tools::Rectangle& _rPlayground) +{ + if ( m_pWin && !_rPlayground.IsEmpty() ) + { + Size aFLSize = LogicToPixel(Size(3, 3), MapMode(MapUnit::MapAppFont)); + _rPlayground.Move( aFLSize.Width(),aFLSize.Height() ); + Size aOldSize = _rPlayground.GetSize(); + _rPlayground.SetSize( Size(aOldSize.Width() - 2*aFLSize.Width(), aOldSize.Height() - 2*aFLSize.Height()) ); + + m_pWin->SetPosSizePixel(_rPlayground.TopLeft() , _rPlayground.GetSize() ); + } + // just for completeness: there is no space left, we occupied it all ... + _rPlayground.SetPos( _rPlayground.BottomRight() ); + _rPlayground.SetSize( Size( 0, 0 ) ); +} + +OApplicationView::ChildFocusState OApplicationView::getChildFocus() const +{ + ChildFocusState eChildFocus; + if( m_pWin && getPanel() && getPanel()->HasChildPathFocus() ) + eChildFocus = PANELSWAP; + else if ( m_pWin && getDetailView() && getDetailView()->HasChildPathFocus() ) + eChildFocus = DETAIL; + else + eChildFocus = NONE; + return eChildFocus; +} + +bool OApplicationView::PreNotify( NotifyEvent& rNEvt ) +{ + switch(rNEvt.GetType()) + { + case MouseNotifyEvent::KEYINPUT: + { + const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); + // give the pane the chance to intercept mnemonic accelerators + // #i34790# + if ( getPanel() && getPanel()->interceptKeyInput( *pKeyEvent ) ) + return true; + } + break; + default: + break; + } + + return ODataView::PreNotify(rNEvt); +} + +IClipboardTest* OApplicationView::getActiveChild() const +{ + IClipboardTest* pTest = nullptr; + if (getChildFocus() == DETAIL) + pTest = getDetailView(); + return pTest; +} + +bool OApplicationView::isCopyAllowed() +{ + IClipboardTest* pTest = getActiveChild(); + return pTest && pTest->isCopyAllowed(); +} + +bool OApplicationView::isCutAllowed() +{ + IClipboardTest* pTest = getActiveChild(); + return pTest && pTest->isCutAllowed(); +} + +bool OApplicationView::isPasteAllowed() +{ + IClipboardTest* pTest = getActiveChild(); + return pTest && pTest->isPasteAllowed(); +} + +void OApplicationView::copy() +{ + IClipboardTest* pTest = getActiveChild(); + if ( pTest ) + pTest->copy(); +} + +void OApplicationView::cut() +{ + IClipboardTest* pTest = getActiveChild(); + if ( pTest ) + pTest->cut(); +} + +void OApplicationView::paste() +{ + IClipboardTest* pTest = getActiveChild(); + if ( pTest ) + pTest->paste(); +} + +OUString OApplicationView::getQualifiedName(const weld::TreeIter* _pEntry) const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->getQualifiedName( _pEntry ); +} + +bool OApplicationView::isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry) const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return OApplicationDetailView::isLeaf(rTreeView, rEntry); +} + +bool OApplicationView::isALeafSelected() const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->isALeafSelected(); +} + +void OApplicationView::selectAll() +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + getDetailView()->selectAll(); +} + +bool OApplicationView::isSortUp() const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->isSortUp(); +} + +void OApplicationView::sortDown() +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + getDetailView()->sortDown(); +} + +void OApplicationView::sortUp() +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + getDetailView()->sortUp(); +} + +bool OApplicationView::isFilled() const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->isFilled(); +} + +ElementType OApplicationView::getElementType() const +{ + OSL_ENSURE(m_pWin && getDetailView() && getPanel(),"Detail view is NULL! -> GPF"); + return getDetailView()->HasChildPathFocus() ? getDetailView()->getElementType() : getPanel()->getElementType(); +} + +sal_Int32 OApplicationView::getSelectionCount() const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->getSelectionCount(); +} + +sal_Int32 OApplicationView::getElementCount() const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->getElementCount(); +} + +void OApplicationView::getSelectionElementNames( std::vector< OUString>& _rNames ) const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + getDetailView()->getSelectionElementNames( _rNames ); +} + +void OApplicationView::describeCurrentSelectionForControl(const weld::TreeView& rControl, Sequence<NamedDatabaseObject>& out_rSelectedObjects) +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + getDetailView()->describeCurrentSelectionForControl(rControl, out_rSelectedObjects); +} + +vcl::Window* OApplicationView::getMenuParent() const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->getMenuParent(); +} + +void OApplicationView::adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->adjustMenuPosition(rControl, rPos); +} + +void OApplicationView::describeCurrentSelectionForType( const ElementType _eType, Sequence< NamedDatabaseObject >& _out_rSelectedObjects ) +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + getDetailView()->describeCurrentSelectionForType( _eType, _out_rSelectedObjects ); +} + +void OApplicationView::selectElements(const Sequence< OUString>& _aNames) +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + getDetailView()->selectElements( _aNames ); +} + +std::unique_ptr<weld::TreeIter> OApplicationView::elementAdded(ElementType eType,const OUString& _rName, const Any& _rObject ) +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->elementAdded(eType,_rName,_rObject); +} + +void OApplicationView::elementRemoved(ElementType eType,const OUString& _rName ) +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + getDetailView()->elementRemoved(eType,_rName); +} + +void OApplicationView::elementReplaced(ElementType _eType + ,const OUString& _rOldName + ,const OUString& _rNewName ) +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + getDetailView()->elementReplaced(_eType, _rOldName, _rNewName ); +} + +void OApplicationView::clearPages() +{ + OSL_ENSURE(m_pWin && getDetailView() && getPanel(),"Detail view is NULL! -> GPF"); + getPanel()->clearSelection(); + getDetailView()->clearPages(); +} + +void OApplicationView::selectContainer(ElementType _eType) +{ + OSL_ENSURE(m_pWin && getPanel(),"Detail view is NULL! -> GPF"); + weld::WaitObject aWO(GetFrameWeld()); + getPanel()->selectContainer(_eType); +} + +std::unique_ptr<weld::TreeIter> OApplicationView::getEntry(const Point& rPosPixel) const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->getEntry(rPosPixel); +} + +PreviewMode OApplicationView::getPreviewMode() const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->getPreviewMode(); +} + +bool OApplicationView::isPreviewEnabled() const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->isPreviewEnabled(); +} + +void OApplicationView::switchPreview(PreviewMode _eMode) +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + getDetailView()->switchPreview(_eMode); +} + +void OApplicationView::showPreview(const Reference< XContent >& _xContent) +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + stopComponentListening(m_xObject); + m_xObject = nullptr; + getDetailView()->showPreview(_xContent); +} + +void OApplicationView::showPreview( const OUString& _sDataSourceName, + const css::uno::Reference< css::sdbc::XConnection>& _xConnection, + const OUString& _sName, + bool _bTable) +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + if ( !isPreviewEnabled() ) + return; + + stopComponentListening(m_xObject); + m_xObject = nullptr; + try + { + Reference<XNameAccess> xNameAccess; + if ( _bTable ) + { + Reference<XTablesSupplier> xSup(_xConnection,UNO_QUERY); + if ( xSup.is() ) + xNameAccess = xSup->getTables(); + } + else + { + Reference<XQueriesSupplier> xSup(_xConnection,UNO_QUERY); + if ( xSup.is() ) + xNameAccess = xSup->getQueries(); + } + if ( xNameAccess.is() && xNameAccess->hasByName(_sName) ) + m_xObject.set(xNameAccess->getByName(_sName),UNO_QUERY); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + if ( m_xObject.is() ) + startComponentListening(m_xObject); + getDetailView()->showPreview(_sDataSourceName,_sName,_bTable); +} + +void OApplicationView::GetFocus() +{ + if (m_pWin && getChildFocus() == NONE) + m_pWin->GrabFocus(); +} + +void OApplicationView::_disposing( const css::lang::EventObject& /*_rSource*/ ) +{ + if ( m_pWin && getDetailView() ) + showPreview(nullptr); +} + +void OApplicationView::ImplInitSettings() +{ + // FIXME RenderContext + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + vcl::Font aFont = rStyleSettings.GetFieldFont(); + aFont.SetColor( rStyleSettings.GetWindowTextColor() ); + SetPointFont(*GetOutDev(), aFont); + + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetTextFillColor(); + + SetBackground( rStyleSettings.GetFieldColor() ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppView.hxx b/dbaccess/source/ui/app/AppView.hxx new file mode 100644 index 000000000..59a6d477a --- /dev/null +++ b/dbaccess/source/ui/app/AppView.hxx @@ -0,0 +1,302 @@ +/* -*- 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 <dbaccess/dataview.hxx> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <unotools/eventlisteneradapter.hxx> +#include <vcl/InterimItemWindow.hxx> +#include <vcl/weld.hxx> +#include <IClipBoardTest.hxx> +#include <AppElementType.hxx> + +namespace com::sun::star::beans { class XPropertySet; } + +class MnemonicGenerator; + +namespace dbaui +{ + class OApplicationView; + class OApplicationDetailView; + class OApplicationSwapWindow; + class OTitleWindow; + class OApplicationController; + + class OAppBorderWindow final : public InterimItemWindow + { + std::unique_ptr<weld::Container> m_xPanelParent; + std::unique_ptr<weld::Container> m_xDetailViewParent; + std::unique_ptr<OTitleWindow> m_xPanel; + std::unique_ptr<OApplicationDetailView> m_xDetailView; + VclPtr<OApplicationView> m_xView; + + public: + OAppBorderWindow(OApplicationView* pParent, PreviewMode ePreviewMode); + virtual ~OAppBorderWindow() override; + virtual void dispose() override; + + // Window overrides + virtual void GetFocus() override; + + OApplicationView* getView() const { return m_xView.get(); } + OApplicationSwapWindow* getPanel() const; + OApplicationDetailView* getDetailView() const { return m_xDetailView.get(); } + weld::Container& getTopLevel() { return *m_xContainer; } + }; + + class OApplicationView : public ODataView + ,public IClipboardTest + ,public ::utl::OEventListenerAdapter + { + enum ChildFocusState + { + PANELSWAP, + DETAIL, + NONE + }; + private: + css::uno::Reference< css::lang::XComponent > + m_xObject; + VclPtr<OAppBorderWindow> m_pWin; + OApplicationController& m_rAppController; + + ChildFocusState getChildFocus() const; + IClipboardTest* getActiveChild() const; + + void ImplInitSettings(); + protected: + + // return the Rectangle where I can paint myself + virtual void resizeDocumentView(tools::Rectangle& rRect) override; + + // OEventListenerAdapter + virtual void _disposing( const css::lang::EventObject& _rSource ) override; + + // Window + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + public: + OApplicationView( vcl::Window* pParent + ,const css::uno::Reference< css::uno::XComponentContext >& + ,OApplicationController& _rAppController + ,PreviewMode _ePreviewMode + ); + virtual ~OApplicationView() override; + virtual void dispose() override; + + /// automatically creates mnemonics for the icon/texts in our left hand side panel + void createIconAutoMnemonics( MnemonicGenerator& _rMnemonics ); + + /// automatically creates mnemonics for the texts in our task pane + void setTaskExternalMnemonics( MnemonicGenerator const & _rMnemonics ); + + // Window overrides + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + virtual void GetFocus() override; + + OApplicationController& getAppController() const { return m_rAppController; } + + // IClipboardTest + virtual bool isCutAllowed() override; + virtual bool isCopyAllowed() override; + virtual bool isPasteAllowed() override; + virtual void copy() override; + virtual void cut() override; + virtual void paste() override; + + /// get the left panel + OApplicationSwapWindow* getPanel() const { return m_pWin->getPanel(); } + /// get the detail page + OApplicationDetailView* getDetailView() const { return m_pWin->getDetailView(); } + + /** return the qualified name. + @param _pEntry + The entry of a table, or query, form, report to get the qualified name. + If the entry is <NULL/>, the first selected is chosen. + @return + the qualified name + */ + OUString getQualifiedName(const weld::TreeIter* _pEntry) const; + + /** returns if an entry is a leaf + @param rTreeView + The TreeView rEntry belongs to + @param rEntry + The entry to check + @return + <TRUE/> if the entry is a leaf, otherwise <FALSE/> + */ + bool isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry) const; + + /** returns if one of the selected entries is a leaf + @return + <TRUE/> if the entry is a leaf, otherwise <FALSE/> + */ + bool isALeafSelected() const; + + /** select all entries in the detail page + */ + void selectAll(); + + /// returns <TRUE/> if it sorts ascending + bool isSortUp() const; + + /// sort the entries in the detail page down + void sortDown(); + + /// sort the entries in the detail page up + void sortUp(); + + /// returns <TRUE/> when a detail page was filled + bool isFilled() const; + + /// return the element of currently select entry + ElementType getElementType() const; + + /// returns the count of entries + sal_Int32 getElementCount() const; + + /// returns the count of selected entries + sal_Int32 getSelectionCount() const; + + /** clears the detail page and the selection on the left side. + The task window will also be cleared. + */ + void clearPages(); + + /** returns the element names which are selected + @param _rNames + The list will be filled. + */ + void getSelectionElementNames( std::vector< OUString>& _rNames ) const; + + /** describes the current selection for the given control + */ + void describeCurrentSelectionForControl( + const weld::TreeView& rControl, + css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects + ); + + /** describes the current selection for the given ElementType + */ + void describeCurrentSelectionForType( + const ElementType _eType, + css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects + ); + + /** get the menu parent window for the given control + */ + vcl::Window* getMenuParent() const; + + /** adjust rPos relative to rControl to instead relative to getMenuParent */ + void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const; + + /** select all names on the currently selected container. Non existence names where ignored. + * + * \param _aNames the element names + */ + void selectElements(const css::uno::Sequence< OUString>& _aNames); + + /** adds a new object to the detail page. + @param _eType + The type where the entry should be appended. + @param _rName + The name of the object to be inserted + @param _rObject + The object to add. + @param _rxConn + If we insert a table, the connection must be set. + */ + std::unique_ptr<weld::TreeIter> elementAdded(ElementType eType, + const OUString& rName, + const css::uno::Any& rObject); + + /** replaces an objects name with a new one + @param _eType + The type where the entry should be appended. + @param _rOldName + The old name of the object to be replaced + @param _rNewName + The new name of the object to be replaced + @param _rxConn + If we insert a table, the connection must be set. + @param _xObject + The object which was replaced + */ + void elementReplaced(ElementType eType + ,const OUString& _rOldName + ,const OUString& _rNewName ); + + /** removes an element from the detail page. + @param _eType + The type where the entry should be appended. + @param _rName + The name of the element to be removed. + @param _rxConn + If we remove a table, the connection must be set. + */ + void elementRemoved(ElementType _eType + ,const OUString& _rName ); + + /** changes the container which should be displayed. The select handler will also be called. + @param _eType + Which container to show. + */ + void selectContainer(ElementType _eType); + + /// returns the preview mode + PreviewMode getPreviewMode() const; + + /// <TRUE/> if the preview is enabled + bool isPreviewEnabled() const; + + /** switches to the given preview mode + @param _eMode + the mode to set for the preview + */ + void switchPreview(PreviewMode _eMode); + + /** shows the Preview of the content when it is enabled. + @param _xContent + The content which must support the "preview" command. + */ + void showPreview(const css::uno::Reference< css::ucb::XContent >& _xContent); + + /** shows the Preview of a table or query + @param _sDataSourceName + the name of the data source + @param _xConnection + the connection which will be shared + @param _sName + the name of table or query + @param _bTable + <TRUE/> if it is a table, otherwise <FALSE/> + @return void + */ + void showPreview( const OUString& _sDataSourceName, + const css::uno::Reference< css::sdbc::XConnection>& _xConnection, + const OUString& _sName, + bool _bTable); + + std::unique_ptr<weld::TreeIter> getEntry(const Point& rPosPixel) const; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/ChildWindow.cxx b/dbaccess/source/ui/app/ChildWindow.cxx new file mode 100644 index 000000000..a8091c863 --- /dev/null +++ b/dbaccess/source/ui/app/ChildWindow.cxx @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#include <vcl/svapp.hxx> +#include <ChildWindow.hxx> + +namespace dbaui +{ +OChildWindow::OChildWindow(weld::Container* pParent, const OUString& rUIXMLDescription, + const OString& rID) + : m_xBuilder(Application::CreateBuilder(pParent, rUIXMLDescription)) + , m_xContainer(m_xBuilder->weld_container(rID)) +{ +} + +OChildWindow::~OChildWindow() {} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/dbaccess/source/ui/app/DocumentInfoPreview.cxx b/dbaccess/source/ui/app/DocumentInfoPreview.cxx new file mode 100644 index 000000000..7220eb2bd --- /dev/null +++ b/dbaccess/source/ui/app/DocumentInfoPreview.cxx @@ -0,0 +1,164 @@ +/* -*- 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 <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/script/CannotConvertException.hpp> +#include <com/sun/star/script/Converter.hpp> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/string.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/wghtitem.hxx> +#include <rtl/ustring.hxx> +#include "DocumentInfoPreview.hxx" +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <svl/itemset.hxx> +#include <tools/datetime.hxx> +#include <tools/diagnose_ex.h> +#include <unotools/localedatawrapper.hxx> + +#include <templwin.hrc> +#include "templwin.hxx" + +namespace dbaui { + +ODocumentInfoPreview::ODocumentInfoPreview() +{ +} + +void ODocumentInfoPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + WeldEditView::SetDrawingArea(pDrawingArea); + m_xEditView->HideCursor(); + m_xEditView->SetReadOnly(true); +} + +ODocumentInfoPreview::~ODocumentInfoPreview() +{ +} + +void ODocumentInfoPreview::clear() { + m_xEditEngine->SetText(OUString()); +} + +void ODocumentInfoPreview::fill( + css::uno::Reference< css::document::XDocumentProperties > const & xDocProps) +{ + assert(xDocProps.is()); + + insertNonempty(DI_TITLE, xDocProps->getTitle()); + insertNonempty(DI_FROM, xDocProps->getAuthor()); + insertDateTime(DI_DATE, xDocProps->getCreationDate()); + insertNonempty(DI_MODIFIEDBY, xDocProps->getModifiedBy()); + insertDateTime(DI_MODIFIEDDATE, xDocProps->getModificationDate()); + insertNonempty(DI_PRINTBY, xDocProps->getPrintedBy()); + insertDateTime(DI_PRINTDATE, xDocProps->getPrintDate()); + insertNonempty(DI_THEME, xDocProps->getSubject()); + insertNonempty( + DI_KEYWORDS, + comphelper::string::convertCommaSeparated(xDocProps->getKeywords())); + insertNonempty(DI_DESCRIPTION, xDocProps->getDescription()); + + // User-defined (custom) properties: + css::uno::Reference< css::beans::XPropertySet > user( + xDocProps->getUserDefinedProperties(), css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::beans::XPropertySetInfo > info( + user->getPropertySetInfo()); + const css::uno::Sequence< css::beans::Property > props(info->getProperties()); + for (const auto& rProp : props) { + OUString name(rProp.Name); + css::uno::Any aAny(user->getPropertyValue(name)); + css::uno::Reference< css::script::XTypeConverter > conv( + css::script::Converter::create( + comphelper::getProcessComponentContext())); + OUString value; + try { + value = conv->convertToSimpleType(aAny, css::uno::TypeClass_STRING). + get< OUString >(); + } catch (css::script::CannotConvertException &) { + TOOLS_INFO_EXCEPTION("svtools.contnr", "ignored"); + } + if (!value.isEmpty()) { + insertEntry(name, value); + } + } + + m_xEditView->SetSelection(ESelection(0, 0, 0, 0)); +} + +namespace +{ + ESelection InsertAtEnd(const EditEngine& rEditEngine) + { + const sal_uInt32 nPara = rEditEngine.GetParagraphCount() -1; + sal_Int32 nLastLen = rEditEngine.GetText(nPara).getLength(); + return ESelection(nPara, nLastLen, nPara, nLastLen); + } +} + +void ODocumentInfoPreview::insertEntry( + std::u16string_view title, OUString const & value) +{ + if (!m_xEditEngine->GetText().isEmpty()) { + m_xEditEngine->QuickInsertText("\n\n", InsertAtEnd(*m_xEditEngine)); + } + + OUString caption(OUString::Concat(title) + ":\n"); + m_xEditEngine->QuickInsertText(caption, InsertAtEnd(*m_xEditEngine)); + + SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet()); + aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT)); + aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT_CJK)); + aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT_CTL)); + int nCaptionPara = m_xEditEngine->GetParagraphCount() - 2; + m_xEditEngine->QuickSetAttribs(aSet, ESelection(nCaptionPara, 0, nCaptionPara, caption.getLength() - 1)); + + m_xEditEngine->QuickInsertText(value, InsertAtEnd(*m_xEditEngine)); +} + +void ODocumentInfoPreview::insertNonempty(tools::Long id, OUString const & value) +{ + if (!value.isEmpty()) { + insertEntry(SvtDocInfoTable_Impl::GetString(id), value); + } +} + +void ODocumentInfoPreview::insertDateTime( + tools::Long id, css::util::DateTime const & value) +{ + DateTime aToolsDT( + Date(value.Day, value.Month, value.Year), + tools::Time( + value.Hours, value.Minutes, value.Seconds, value.NanoSeconds)); + if (aToolsDT.IsValidAndGregorian()) { + const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() ); + OUString buf = rLocaleWrapper.getDate(aToolsDT) + + ", " + + rLocaleWrapper.getTime(aToolsDT); + insertEntry(SvtDocInfoTable_Impl::GetString(id), buf); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/DocumentInfoPreview.hxx b/dbaccess/source/ui/app/DocumentInfoPreview.hxx new file mode 100644 index 000000000..0c9548d0a --- /dev/null +++ b/dbaccess/source/ui/app/DocumentInfoPreview.hxx @@ -0,0 +1,59 @@ +/* -*- 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 <string_view> + +#include <svx/weldeditview.hxx> + +namespace com :: sun :: star :: uno { template <typename > class Reference; } + +namespace com::sun::star { + namespace document { class XDocumentProperties; } + namespace util { struct DateTime; } +} + +namespace dbaui { + +class ODocumentInfoPreview final : public WeldEditView { +public: + ODocumentInfoPreview(); + + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + + virtual ~ODocumentInfoPreview() override; + + void clear(); + + void fill(css::uno::Reference< css::document::XDocumentProperties > const & xDocProps); + +private: + void insertEntry(std::u16string_view title, OUString const & value); + + void insertNonempty(tools::Long id, OUString const & value); + + void insertDateTime(tools::Long id, css::util::DateTime const & value); +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/subcomponentmanager.cxx b/dbaccess/source/ui/app/subcomponentmanager.cxx new file mode 100644 index 000000000..bf92f2400 --- /dev/null +++ b/dbaccess/source/ui/app/subcomponentmanager.cxx @@ -0,0 +1,551 @@ +/* -*- 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 "subcomponentmanager.hxx" +#include "AppController.hxx" +#include <strings.hxx> + +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XModel2.hpp> +#include <com/sun/star/util/XCloseable.hpp> +#include <com/sun/star/awt/XTopWindow.hpp> +#include <com/sun/star/embed/XComponentSupplier.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/document/XDocumentEventBroadcaster.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <tools/diagnose_ex.h> +#include <dbaccess/dataview.hxx> +#include <vcl/svapp.hxx> +#include <osl/mutex.hxx> + +#include <algorithm> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::frame::XFrame; + using ::com::sun::star::frame::XController; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::lang::XComponent; + using ::com::sun::star::frame::XModel2; + using ::com::sun::star::container::XEnumeration; + using ::com::sun::star::util::XCloseable; + using ::com::sun::star::awt::XTopWindow; + using ::com::sun::star::embed::XComponentSupplier; + using ::com::sun::star::ucb::XCommandProcessor; + using ::com::sun::star::ucb::Command; + using ::com::sun::star::document::XDocumentEventBroadcaster; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::beans::PropertyChangeEvent; + + // helper structs + namespace + { + struct SubComponentDescriptor + { + /// the name of the sub component, empty if it is yet unsaved + OUString sName; + /// type of the component - an ElementType value, except for relation design + sal_Int32 nComponentType; + /// the mode in which the sub component has been opened + ElementOpenMode eOpenMode; + /// the frame which the component resides in. Must not be <NULL/> + Reference< XFrame > xFrame; + /// the controller of the sub component. Must not be <NULL/> + Reference< XController > xController; + /// the model of the sub component. Might be <NULL/> + Reference< XModel > xModel; + /// the document definition which holds the component, if any; as CommandProcessor + Reference< XCommandProcessor > xComponentCommandProcessor; + /// the document definition which holds the component, if any; as PropertySet + Reference< XPropertySet > xDocumentDefinitionProperties; + + SubComponentDescriptor() + :nComponentType( -1 ) + ,eOpenMode( E_OPEN_NORMAL ) + { + } + + SubComponentDescriptor( const OUString& i_rName, const sal_Int32 i_nComponentType, + const ElementOpenMode i_eOpenMode, const Reference< XComponent >& i_rComponent ) + :sName( i_rName ) + ,nComponentType( i_nComponentType ) + ,eOpenMode( i_eOpenMode ) + { + if ( !impl_constructFrom( i_rComponent ) ) + { + // i_rComponent is neither a model, nor a controller, nor a frame + // => it must be a css.sdb.DocumentDefinition + Reference< XComponentSupplier > xCompSupp( i_rComponent, UNO_QUERY_THROW ); + Reference< XComponent > xComponent( xCompSupp->getComponent(), UNO_QUERY_THROW ); + if ( !impl_constructFrom( xComponent ) ) + throw RuntimeException("Illegal component type." ); + xComponentCommandProcessor.set( i_rComponent, UNO_QUERY_THROW ); + xDocumentDefinitionProperties.set( i_rComponent, UNO_QUERY_THROW ); + } + } + + bool is() const { return xFrame.is(); } + + private: + bool impl_constructFrom( const Reference< XComponent >& _rxComponent ) + { + // is it a model? + xModel.set( _rxComponent, UNO_QUERY ); + if ( xModel.is() ) + { + xController.set( xModel->getCurrentController() ); + if ( xController.is() ) + xFrame.set( xController->getFrame(), UNO_SET_THROW ); + } + else + { + // is it a controller? + xController.set( _rxComponent, UNO_QUERY ); + if ( xController.is() ) + { + xFrame.set( xController->getFrame(), UNO_SET_THROW ); + } + else + { + // is it a frame? + xFrame.set( _rxComponent, UNO_QUERY ); + if ( !xFrame.is() ) + return false; + + // ensure we have a controller + xController.set( xFrame->getController(), UNO_SET_THROW ); + } + + // check whether there is a model (not required) + xModel.set( xController->getModel() ); + } + + return true; + } + }; + + struct SelectSubComponent + { + Reference< XComponent > operator()( const SubComponentDescriptor &_desc ) const + { + if ( _desc.xModel.is() ) + return _desc.xModel; + OSL_ENSURE( _desc.xController.is(), "SelectSubComponent::operator(): illegal component!" ); + return _desc.xController; + } + }; + + typedef std::vector< SubComponentDescriptor > SubComponents; + + struct SubComponentMatch + { + public: + SubComponentMatch( const OUString& i_rName, const sal_Int32 i_nComponentType, + const ElementOpenMode i_eOpenMode ) + :m_sName( i_rName ) + ,m_nComponentType( i_nComponentType ) + ,m_eOpenMode( i_eOpenMode ) + { + } + + bool operator()( const SubComponentDescriptor& i_rCompareWith ) const + { + return ( m_sName == i_rCompareWith.sName ) + && ( m_nComponentType == i_rCompareWith.nComponentType ) + && ( m_eOpenMode == i_rCompareWith.eOpenMode ); + } + private: + const OUString m_sName; + const sal_Int32 m_nComponentType; + const ElementOpenMode m_eOpenMode; + }; + } + + // SubComponentManager_Data + struct SubComponentManager_Data + { + SubComponentManager_Data( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex ) + :m_rController( _rController ) + ,m_aMutex( _rMutex ) + { + } + + OApplicationController& m_rController; + mutable ::comphelper::SharedMutex m_aMutex; + SubComponents m_aComponents; + + ::osl::Mutex& getMutex() const { return m_aMutex; } + }; + + // SubComponentManager + SubComponentManager::SubComponentManager( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex ) + :m_pData( new SubComponentManager_Data( _rController, _rMutex ) ) + { + } + + SubComponentManager::~SubComponentManager() + { + } + + void SubComponentManager::disposing() + { + ::osl::MutexGuard aGuard( m_pData->getMutex() ); + m_pData->m_aComponents.clear(); + } + + namespace + { + bool lcl_fallbackToAnotherController( SubComponentDescriptor& _rCompDesc ) + { + Reference< XController > xFallback; + OSL_PRECOND( _rCompDesc.xModel.is(), "lcl_fallbackToAnotherController: illegal call!" ); + if ( !_rCompDesc.xModel.is() ) + return false; + + xFallback.set( _rCompDesc.xModel->getCurrentController() ); + if ( xFallback == _rCompDesc.xController ) + // don't accept the very same controller as fallback + xFallback.clear(); + + if ( !xFallback.is() ) + { + // perhaps XModel2 can be of help here + Reference< XModel2 > xModel2( _rCompDesc.xModel, UNO_QUERY ); + Reference< XEnumeration > xControllerEnum; + if ( xModel2.is() ) + xControllerEnum = xModel2->getControllers(); + while ( xControllerEnum.is() && xControllerEnum->hasMoreElements() ) + { + xFallback.set( xControllerEnum->nextElement(), UNO_QUERY ); + if ( xFallback == _rCompDesc.xController ) + xFallback.clear(); + } + } + + if ( xFallback.is() ) + { + _rCompDesc.xController = xFallback; + _rCompDesc.xFrame.set( xFallback->getFrame(), UNO_SET_THROW ); + return true; + } + + return false; + } + + bool lcl_closeComponent( const Reference< XCommandProcessor >& _rxCommandProcessor ) + { + bool bSuccess = false; + try + { + sal_Int32 nCommandIdentifier = _rxCommandProcessor->createCommandIdentifier(); + + Command aCommand; + aCommand.Name = "close"; + _rxCommandProcessor->execute( aCommand, nCommandIdentifier, nullptr ); + bSuccess = true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bSuccess; + } + + bool lcl_closeComponent( const SubComponentDescriptor& _rComponent ) + { + if ( _rComponent.xComponentCommandProcessor.is() ) + return lcl_closeComponent( _rComponent.xComponentCommandProcessor ); + + Reference< XController > xController( _rComponent.xController ); + OSL_ENSURE( xController.is(), "lcl_closeComponent: invalid controller!" ); + + // suspend the controller in the document + if ( xController.is() ) + if ( !xController->suspend( true ) ) + return false; + + bool bSuccess = false; + try + { + Reference< XCloseable > xCloseable( _rComponent.xFrame, UNO_QUERY_THROW ); + xCloseable->close( true ); + bSuccess = true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bSuccess; + } + + void lcl_notifySubComponentEvent( const SubComponentManager_Data& _rData, const char* _pAsciiEventName, + const SubComponentDescriptor& _rComponent ) + { + try + { + Reference< XDocumentEventBroadcaster > xBroadcaster( _rData.m_rController.getModel(), UNO_QUERY_THROW ); + xBroadcaster->notifyDocumentEvent( + OUString::createFromAscii( _pAsciiEventName ), + &_rData.m_rController, + Any( _rComponent.xFrame ) + ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + + void SAL_CALL SubComponentManager::propertyChange( const PropertyChangeEvent& i_rEvent ) + { + if ( i_rEvent.PropertyName != PROPERTY_NAME ) + // by definition, it's allowed to broadcast more than what we've registered for + return; + + // find the sub component whose name changed + for (auto & component : m_pData->m_aComponents) + { + if ( component.xDocumentDefinitionProperties != i_rEvent.Source ) + continue; + + OUString sNewName; + OSL_VERIFY( i_rEvent.NewValue >>= sNewName ); + + #if OSL_DEBUG_LEVEL > 0 + OUString sOldKnownName( component.sName ); + OUString sOldName; + OSL_VERIFY( i_rEvent.OldValue >>= sOldName ); + OSL_ENSURE( sOldName == sOldKnownName, "SubComponentManager::propertyChange: inconsistency in the old names!" ); + #endif + + component.sName = sNewName; + break; + } + } + + void SAL_CALL SubComponentManager::disposing( const EventObject& _rSource ) + { + ::osl::ClearableMutexGuard aGuard( m_pData->getMutex() ); + + SubComponentDescriptor aClosedComponent; + + for ( SubComponents::iterator comp = m_pData->m_aComponents.begin(); + comp != m_pData->m_aComponents.end(); + ++comp + ) + { + bool bRemove = false; + + if ( comp->xController == _rSource.Source ) + { + if ( !comp->xModel.is() ) + { + bRemove = true; + } + else + { + // maybe this is just one view to the sub document, and only this view is closed + if ( !lcl_fallbackToAnotherController( *comp ) ) + { + bRemove = true; + } + } + } + else if ( comp->xModel == _rSource.Source ) + { + bRemove = true; + } + + if ( bRemove ) + { + aClosedComponent = *comp; + m_pData->m_aComponents.erase( comp ); + break; + } + } + + if ( aClosedComponent.is() ) + { + aGuard.clear(); + lcl_notifySubComponentEvent( *m_pData, "OnSubComponentClosed", aClosedComponent ); + } + } + + Sequence< Reference< XComponent> > SubComponentManager::getSubComponents() const + { + ::osl::MutexGuard aGuard( m_pData->getMutex() ); + + Sequence< Reference< XComponent > > aComponents( m_pData->m_aComponents.size() ); + std::transform( + m_pData->m_aComponents.begin(), + m_pData->m_aComponents.end(), + aComponents.getArray(), + SelectSubComponent() + ); + return aComponents; + } + + bool SubComponentManager::closeSubComponents() + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_pData->getMutex() ); + + try + { + SubComponents aWorkingCopy( m_pData->m_aComponents ); + for (auto const& elem : aWorkingCopy) + { + lcl_closeComponent(elem); + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return empty(); + } + + bool SubComponentManager::empty() const + { + ::osl::MutexGuard aGuard( m_pData->getMutex() ); + return m_pData->m_aComponents.empty(); + } + + void SubComponentManager::onSubComponentOpened( const OUString& _rName, const sal_Int32 _nComponentType, + const ElementOpenMode _eOpenMode, const Reference< XComponent >& _rxComponent ) + { + ::osl::ClearableMutexGuard aGuard( m_pData->getMutex() ); + +#if OSL_DEBUG_LEVEL > 0 + if ( !_rName.isEmpty() ) + { + // check there does not already exist such a component + auto subComponentNotExists = std::none_of( + m_pData->m_aComponents.begin(), + m_pData->m_aComponents.end(), + SubComponentMatch( _rName, _nComponentType, _eOpenMode ) + ); + OSL_ENSURE( subComponentNotExists, "already existent!" ); + } +#endif + SubComponentDescriptor aElement( _rName, _nComponentType, _eOpenMode, _rxComponent ); + ENSURE_OR_THROW( aElement.xModel.is() || aElement.xController.is(), "illegal component" ); + + m_pData->m_aComponents.push_back( aElement ); + + // add as listener + if ( aElement.xController.is() ) + aElement.xController->addEventListener( this ); + if ( aElement.xModel.is() ) + aElement.xModel->addEventListener( this ); + if ( aElement.xDocumentDefinitionProperties.is() ) + aElement.xDocumentDefinitionProperties->addPropertyChangeListener( PROPERTY_NAME, this ); + + // notify this to interested parties + aGuard.clear(); + lcl_notifySubComponentEvent( *m_pData, "OnSubComponentOpened", aElement ); + } + + bool SubComponentManager::activateSubFrame( const OUString& _rName, const sal_Int32 _nComponentType, + const ElementOpenMode _eOpenMode, Reference< XComponent >& o_rComponent ) const + { + ::osl::MutexGuard aGuard( m_pData->getMutex() ); + + SubComponents::const_iterator pos = std::find_if( + m_pData->m_aComponents.begin(), + m_pData->m_aComponents.end(), + SubComponentMatch( _rName, _nComponentType, _eOpenMode ) + ); + if ( pos == m_pData->m_aComponents.end() ) + // no component with this name/type/open mode + return false; + + const Reference< XFrame > xFrame( pos->xFrame, UNO_SET_THROW ); + const Reference< XTopWindow > xTopWindow( xFrame->getContainerWindow(), UNO_QUERY_THROW ); + xTopWindow->toFront(); + + if ( pos->xModel.is() ) + o_rComponent = pos->xModel.get(); + else if ( pos->xController.is() ) + o_rComponent = pos->xController.get(); + else + o_rComponent = pos->xFrame.get(); + + return true; + } + + bool SubComponentManager::closeSubFrames( std::u16string_view i_rName, const sal_Int32 _nComponentType ) + { + ::osl::MutexGuard aGuard( m_pData->getMutex() ); + ENSURE_OR_RETURN_FALSE( !i_rName.empty(), "SubComponentManager::closeSubFrames: illegal name!" ); + + SubComponents aWorkingCopy( m_pData->m_aComponents ); + for (auto const& elem : aWorkingCopy) + { + if ( ( elem.sName != i_rName ) || ( elem.nComponentType != _nComponentType ) ) + continue; + + if ( !lcl_closeComponent(elem) ) + return false; + } + + return true; + } + + bool SubComponentManager::lookupSubComponent( const Reference< XComponent >& i_rComponent, + OUString& o_rName, sal_Int32& o_rComponentType ) + { + for (auto const& component : m_pData->m_aComponents) + { + if ( ( component.xModel.is() + && ( component.xModel == i_rComponent ) + ) + || ( component.xController.is() + && ( component.xController == i_rComponent ) + ) + || ( component.xFrame.is() + && ( component.xFrame == i_rComponent ) + ) + ) + { + o_rName = component.sName; + o_rComponentType = component.nComponentType; + return true; + } + } + return false; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/subcomponentmanager.hxx b/dbaccess/source/ui/app/subcomponentmanager.hxx new file mode 100644 index 000000000..402a3d593 --- /dev/null +++ b/dbaccess/source/ui/app/subcomponentmanager.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 <AppElementType.hxx> + +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/lang/XComponent.hpp> + +#include <comphelper/sharedmutex.hxx> +#include <cppuhelper/implbase.hxx> + +#include <memory> + +namespace dbaui +{ + + struct SubComponentManager_Data; + class OApplicationController; + + // SubComponentManager + typedef ::cppu::WeakImplHelper< css::beans::XPropertyChangeListener + > SubComponentManager_Base; + class SubComponentManager : public SubComponentManager_Base + { + public: + SubComponentManager( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex ); + virtual ~SubComponentManager() override; + + void disposing(); + + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // XDatabaseDocumentUI helpers + css::uno::Sequence< css::uno::Reference< css::lang::XComponent> > + getSubComponents() const; + bool closeSubComponents(); + + // container access + void onSubComponentOpened( + const OUString& _rName, + const sal_Int32 _nComponentType, + const ElementOpenMode _eOpenMode, + const css::uno::Reference< css::lang::XComponent >& + _rxComponent + ); + bool empty() const; + + /** activates (i.e. brings to top) the frame in which the given component is loaded, if any + + @return + <TRUE/> if any only of such a frame was found, i.e. the component had already been loaded + previously + */ + bool activateSubFrame( + const OUString& _rName, + const sal_Int32 _nComponentType, + const ElementOpenMode _eOpenMode, + css::uno::Reference< css::lang::XComponent >& o_rComponent + ) const; + + /** closes all frames of the given component + + If a view for the component (given by name and type) has been loaded into one or more + frames (with potentially different OpenModes), then those frames are gracefully closed. + + @return + <TRUE/> if and only if closing those frames was successful, or frames for the given sub component + exist. + */ + bool closeSubFrames( + std::u16string_view _rName, + const sal_Int32 _nComponentType + ); + + /** searches for the given sub component + + @param i_rComponent + the sub component to look up + @param o_rName + contains, upon successful return, the name of the sub component + @param o_nComponentType + contains, upon successful return, the type of the sub component + @return + <TRUE/> if and only if the component was found + */ + bool lookupSubComponent( + const css::uno::Reference< css::lang::XComponent >& i_rComponent, + OUString& o_rName, + sal_Int32& o_rComponentType + ); + + private: + std::unique_ptr< SubComponentManager_Data > m_pData; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/templwin.cxx b/dbaccess/source/ui/app/templwin.cxx new file mode 100644 index 000000000..e9940782d --- /dev/null +++ b/dbaccess/source/ui/app/templwin.cxx @@ -0,0 +1,38 @@ +/* -*- 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 <core_resource.hxx> +#include <templwin.hrc> +#include "templwin.hxx" + +namespace SvtDocInfoTable_Impl +{ + OUString GetString(int nId) + { + for (size_t i = 0; i < SAL_N_ELEMENTS(STRARY_SVT_DOCINFO); ++i) + { + if (STRARY_SVT_DOCINFO[i].second == nId) + return DBA_RES(STRARY_SVT_DOCINFO[i].first); + } + + return OUString(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/templwin.hxx b/dbaccess/source/ui/app/templwin.hxx new file mode 100644 index 000000000..8978a6ea3 --- /dev/null +++ b/dbaccess/source/ui/app/templwin.hxx @@ -0,0 +1,28 @@ +/* -*- 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 <rtl/ustring.hxx> + +namespace SvtDocInfoTable_Impl +{ +OUString GetString(int nId); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/window_layout.txt b/dbaccess/source/ui/app/window_layout.txt new file mode 100644 index 000000000..abb15f00b --- /dev/null +++ b/dbaccess/source/ui/app/window_layout.txt @@ -0,0 +1,49 @@ +# +# 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 . +# + +(still unfinished) + +OApplicationView +| ++-OAppBorderWindow + | + +-OTitleWindow "Database" + | | + | +-OApplicationSwapWindow + | | + | +-OApplicationIconControl + | + +-OApplicationDetailView + | + +-OTitleWindow "Tasks" + | | + | +-OTasksWindow + | | + | +-OCreationList + | + +-OTitleWindow "Forms" "Tables" "Queries" "Reports" + | + +-OAppDetailPageHelper + | + +-SvTreeListBox* + | + +-FixedLine + | + +-Window (Border) + | + +-OPreviewWindow diff --git a/dbaccess/source/ui/browser/AsynchronousLink.cxx b/dbaccess/source/ui/browser/AsynchronousLink.cxx new file mode 100644 index 000000000..e4dcdb2f9 --- /dev/null +++ b/dbaccess/source/ui/browser/AsynchronousLink.cxx @@ -0,0 +1,81 @@ +/* -*- 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 <dbaccess/AsynchronousLink.hxx> +#include <vcl/svapp.hxx> + +// OAsynchronousLink +using namespace dbaui; +OAsynchronousLink::OAsynchronousLink(const Link<void*, void>& _rHandler) + : m_aHandler(_rHandler) + , m_nEventId(nullptr) +{ +} + +OAsynchronousLink::~OAsynchronousLink() +{ + { + ::osl::MutexGuard aEventGuard(m_aEventSafety); + if (m_nEventId) + Application::RemoveUserEvent(m_nEventId); + m_nEventId = nullptr; + } + + { + ::osl::MutexGuard aDestructionGuard(m_aDestructionSafety); + // this is just for the case we're deleted while another thread just handled the event : + // if this other thread called our link while we were deleting the event here, the + // link handler blocked. With leaving the above block it continued, but now we are prevented + // to leave this destructor 'til the link handler recognizes that nEvent == 0 and leaves. + } +} + +void OAsynchronousLink::Call(void* _pArgument) +{ + ::osl::MutexGuard aEventGuard(m_aEventSafety); + if (m_nEventId) + Application::RemoveUserEvent(m_nEventId); + m_nEventId = Application::PostUserEvent(LINK(this, OAsynchronousLink, OnAsyncCall), _pArgument); +} + +void OAsynchronousLink::CancelCall() +{ + ::osl::MutexGuard aEventGuard(m_aEventSafety); + if (m_nEventId) + Application::RemoveUserEvent(m_nEventId); + m_nEventId = nullptr; +} + +IMPL_LINK(OAsynchronousLink, OnAsyncCall, void*, _pArg, void) +{ + { + ::osl::MutexGuard aDestructionGuard(m_aDestructionSafety); + { + ::osl::MutexGuard aEventGuard(m_aEventSafety); + if (!m_nEventId) + // our destructor deleted the event just while we are waiting for m_aEventSafety + // -> get outta here + return; + m_nEventId = nullptr; + } + } + m_aHandler.Call(_pArg); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/brwctrlr.cxx b/dbaccess/source/ui/browser/brwctrlr.cxx new file mode 100644 index 000000000..b8387b203 --- /dev/null +++ b/dbaccess/source/ui/browser/brwctrlr.cxx @@ -0,0 +1,2616 @@ +/* -*- 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 <browserids.hxx> +#include <brwctrlr.hxx> +#include <brwview.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <core_resource.hxx> +#include <queryfilter.hxx> +#include <queryorder.hxx> +#include <sqlmessage.hxx> + +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/form/XBoundControl.hpp> +#include <com/sun/star/form/XDatabaseParameterBroadcaster.hpp> +#include <com/sun/star/form/XLoadable.hpp> +#include <com/sun/star/form/XReset.hpp> +#include <com/sun/star/form/XResetListener.hpp> +#include <com/sun/star/form/runtime/XFormController.hpp> +#include <com/sun/star/form/runtime/FormOperations.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/ErrorCondition.hpp> +#include <com/sun/star/sdb/ParametersRequest.hpp> +#include <com/sun/star/sdb/XInteractionSupplyParameters.hpp> +#include <com/sun/star/sdb/XSQLErrorBroadcaster.hpp> +#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> +#include <com/sun/star/sdb/SQLFilterOperator.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/util/NumberFormatter.hpp> + +#include <comphelper/enumhelper.hxx> +#include <comphelper/extract.hxx> +#include <comphelper/interaction.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/string.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/sqlerror.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/implbase2.hxx> +#include <osl/mutex.hxx> +#include <sal/log.hxx> +#include <svx/fmsearch.hxx> +#include <svx/svxdlg.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +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 ::com::sun::star::beans; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::form::runtime; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::dbtools; +using namespace ::comphelper; +using namespace ::svt; + +namespace dbaui +{ + +namespace { + +// OParameterContinuation +class OParameterContinuation : public OInteraction< XInteractionSupplyParameters > +{ + Sequence< PropertyValue > m_aValues; + +public: + OParameterContinuation() { } + + const Sequence< PropertyValue >& getValues() const { return m_aValues; } + +// XInteractionSupplyParameters + virtual void SAL_CALL setParameters( const Sequence< PropertyValue >& _rValues ) override; +}; + +} + +void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues ) +{ + m_aValues = _rValues; +} + +// a helper class implementing a runtime::XFormController, will be aggregated by SbaXDataBrowserController +// (we can't derive from XFormController as it's base class is XTabController and the XTabController::getModel collides +// with the XController::getModel implemented in our base class SbaXDataBrowserController) +class SbaXDataBrowserController::FormControllerImpl + : public ::cppu::WeakAggImplHelper2< css::form::runtime::XFormController, + css::frame::XFrameActionListener > +{ + friend class SbaXDataBrowserController; + ::comphelper::OInterfaceContainerHelper3<css::form::XFormControllerListener> m_aActivateListeners; + SbaXDataBrowserController* m_pOwner; + +public: + explicit FormControllerImpl(SbaXDataBrowserController* pOwner); + + // XFormController + virtual css::uno::Reference< css::form::runtime::XFormOperations > SAL_CALL getFormOperations() override; + virtual css::uno::Reference< css::awt::XControl > SAL_CALL getCurrentControl() override; + virtual void SAL_CALL addActivateListener(const css::uno::Reference< css::form::XFormControllerListener > & l) override; + virtual void SAL_CALL removeActivateListener(const css::uno::Reference< css::form::XFormControllerListener > & l) override; + virtual void SAL_CALL addChildController( const css::uno::Reference< css::form::runtime::XFormController >& ChildController ) override; + virtual css::uno::Reference< css::form::runtime::XFormControllerContext > SAL_CALL getContext() override; + virtual void SAL_CALL setContext( const css::uno::Reference< css::form::runtime::XFormControllerContext >& _context ) override; + virtual css::uno::Reference< css::task::XInteractionHandler > SAL_CALL getInteractionHandler() override; + virtual void SAL_CALL setInteractionHandler( const css::uno::Reference< css::task::XInteractionHandler >& _interactionHandler ) override; + + // XChild, base of XFormController + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override; + virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override; + + // XComponent, base of XFormController + virtual void SAL_CALL dispose( ) override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + // XIndexAccess, base of XFormController + virtual ::sal_Int32 SAL_CALL getCount( ) override; + virtual css::uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override; + + // XElementAccess, base of XIndexAccess + virtual css::uno::Type SAL_CALL getElementType( ) override; + virtual sal_Bool SAL_CALL hasElements( ) override; + + // XEnumerationAccess, base of XElementAccess + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration( ) override; + + // XModifyBroadcaster, base of XFormController + virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + // XConfirmDeleteBroadcaster, base of XFormController + virtual void SAL_CALL addConfirmDeleteListener( const css::uno::Reference< css::form::XConfirmDeleteListener >& aListener ) override; + virtual void SAL_CALL removeConfirmDeleteListener( const css::uno::Reference< css::form::XConfirmDeleteListener >& aListener ) override; + + // XSQLErrorBroadcaster, base of XFormController + virtual void SAL_CALL addSQLErrorListener( const css::uno::Reference< css::sdb::XSQLErrorListener >& Listener ) override; + virtual void SAL_CALL removeSQLErrorListener( const css::uno::Reference< css::sdb::XSQLErrorListener >& Listener ) override; + + // XRowSetApproveBroadcaster, base of XFormController + virtual void SAL_CALL addRowSetApproveListener( const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener ) override; + virtual void SAL_CALL removeRowSetApproveListener( const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener ) override; + + // XDatabaseParameterBroadcaster2, base of XFormController + virtual void SAL_CALL addDatabaseParameterListener( const css::uno::Reference< css::form::XDatabaseParameterListener >& aListener ) override; + virtual void SAL_CALL removeDatabaseParameterListener( const css::uno::Reference< css::form::XDatabaseParameterListener >& aListener ) override; + + // XDatabaseParameterBroadcaster, base of XDatabaseParameterBroadcaster2 + virtual void SAL_CALL addParameterListener( const css::uno::Reference< css::form::XDatabaseParameterListener >& aListener ) override; + virtual void SAL_CALL removeParameterListener( const css::uno::Reference< css::form::XDatabaseParameterListener >& aListener ) override; + + // XModeSelector, base of XFormController + virtual void SAL_CALL setMode( const OUString& aMode ) override; + virtual OUString SAL_CALL getMode( ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedModes( ) override; + virtual sal_Bool SAL_CALL supportsMode( const OUString& aMode ) override; + + // XTabController, base of XFormController + virtual void SAL_CALL setModel(const css::uno::Reference< css::awt::XTabControllerModel > & Model) override; + virtual css::uno::Reference< css::awt::XTabControllerModel > SAL_CALL getModel() override; + virtual void SAL_CALL setContainer(const css::uno::Reference< css::awt::XControlContainer > & Container) override; + virtual css::uno::Reference< css::awt::XControlContainer > SAL_CALL getContainer() override; + virtual css::uno::Sequence< css::uno::Reference< css::awt::XControl > > SAL_CALL getControls() override; + virtual void SAL_CALL autoTabOrder() override; + virtual void SAL_CALL activateTabOrder() override; + virtual void SAL_CALL activateFirst() override; + virtual void SAL_CALL activateLast() override; + + // XFrameActionListener + virtual void SAL_CALL frameAction(const css::frame::FrameActionEvent& aEvent) override; + + // XEventListener + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + +protected: + virtual ~FormControllerImpl() override; +}; + +SbaXDataBrowserController::FormControllerImpl::FormControllerImpl(SbaXDataBrowserController* _pOwner) + :m_aActivateListeners(_pOwner->getMutex()) + ,m_pOwner(_pOwner) +{ + + OSL_ENSURE(m_pOwner, "SbaXDataBrowserController::FormControllerImpl::FormControllerImpl : invalid Owner !"); +} + +SbaXDataBrowserController::FormControllerImpl::~FormControllerImpl() +{ + +} + +Reference< runtime::XFormOperations > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getFormOperations() +{ + return FormOperations::createWithFormController( m_pOwner->m_xContext, this ); +} + +Reference< css::awt::XControl > SbaXDataBrowserController::FormControllerImpl::getCurrentControl() +{ + return m_pOwner->getBrowserView() ? m_pOwner->getBrowserView()->getGridControl() : Reference< css::awt::XControl > (); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addActivateListener(const Reference< css::form::XFormControllerListener > & l) +{ + m_aActivateListeners.addInterface(l); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeActivateListener(const Reference< css::form::XFormControllerListener > & l) +{ + m_aActivateListeners.removeInterface(l); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addChildController( const Reference< runtime::XFormController >& ) +{ + // not supported + throw IllegalArgumentException( OUString(), *this, 1 ); +} + +Reference< runtime::XFormControllerContext > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getContext() +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::getContext: no support!!" ); + return nullptr; +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::setContext( const Reference< runtime::XFormControllerContext >& /*_context*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::setContext: no support!!" ); +} + +Reference< XInteractionHandler > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getInteractionHandler() +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::getInteractionHandler: no support!!" ); + return nullptr; +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::setInteractionHandler( const Reference< XInteractionHandler >& /*_interactionHandler*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::setInteractionHandler: no support!!" ); +} + +Reference< XInterface > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getParent( ) +{ + // don't have any parent form controllers + return nullptr; +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::setParent( const Reference< XInterface >& /*Parent*/ ) +{ + throw NoSupportException( OUString(), *this ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::dispose( ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::dispose: no, you do *not* want to do this!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addEventListener( const Reference< XEventListener >& /*xListener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addEventListener: no support!!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeEventListener( const Reference< XEventListener >& /*aListener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeEventListener: no support!!" ); +} + +::sal_Int32 SAL_CALL SbaXDataBrowserController::FormControllerImpl::getCount( ) +{ + // no sub controllers, never + return 0; +} + +Any SAL_CALL SbaXDataBrowserController::FormControllerImpl::getByIndex( ::sal_Int32 /*Index*/ ) +{ + // no sub controllers, never + throw IndexOutOfBoundsException( OUString(), *this ); +} + +Type SAL_CALL SbaXDataBrowserController::FormControllerImpl::getElementType( ) +{ + return ::cppu::UnoType< runtime::XFormController >::get(); +} + +sal_Bool SAL_CALL SbaXDataBrowserController::FormControllerImpl::hasElements( ) +{ + // no sub controllers, never + return false; +} + +Reference< XEnumeration > SAL_CALL SbaXDataBrowserController::FormControllerImpl::createEnumeration( ) +{ + return new ::comphelper::OEnumerationByIndex( this ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addModifyListener( const Reference< XModifyListener >& /*_Listener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addModifyListener: no support!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeModifyListener( const Reference< XModifyListener >& /*_Listener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeModifyListener: no support!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addConfirmDeleteListener( const Reference< XConfirmDeleteListener >& /*_Listener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addConfirmDeleteListener: no support!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeConfirmDeleteListener( const Reference< XConfirmDeleteListener >& /*_Listener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeConfirmDeleteListener: no support!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addSQLErrorListener( const Reference< XSQLErrorListener >& /*_Listener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addSQLErrorListener: no support!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeSQLErrorListener( const Reference< XSQLErrorListener >& /*_Listener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeSQLErrorListener: no support!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addRowSetApproveListener( const Reference< XRowSetApproveListener >& /*_Listener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addRowSetApproveListener: no support!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeRowSetApproveListener( const Reference< XRowSetApproveListener >& /*_Listener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeRowSetApproveListener: no support!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addDatabaseParameterListener( const Reference< XDatabaseParameterListener >& /*_Listener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addDatabaseParameterListener: no support!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeDatabaseParameterListener( const Reference< XDatabaseParameterListener >& /*_Listener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeDatabaseParameterListener: no support!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addParameterListener( const Reference< XDatabaseParameterListener >& /*_Listener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addParameterListener: no support!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeParameterListener( const Reference< XDatabaseParameterListener >& /*_Listener*/ ) +{ + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeParameterListener: no support!" ); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::setMode( const OUString& _rMode ) +{ + if ( !supportsMode( _rMode ) ) + throw NoSupportException(); +} + +OUString SAL_CALL SbaXDataBrowserController::FormControllerImpl::getMode( ) +{ + return "DataMode"; +} + +Sequence< OUString > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getSupportedModes( ) +{ + Sequence< OUString > aModes { "DataMode" }; + return aModes; +} + +sal_Bool SAL_CALL SbaXDataBrowserController::FormControllerImpl::supportsMode( const OUString& aMode ) +{ + return aMode == "DataMode"; +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::setModel(const Reference< css::awt::XTabControllerModel > & /*Model*/) +{ + SAL_WARN("dbaccess.ui","SbaXDataBrowserController::FormControllerImpl::setModel : invalid call, can't change my model !"); +} + +Reference< css::awt::XTabControllerModel > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getModel() +{ + return Reference< XTabControllerModel >(m_pOwner->getRowSet(), UNO_QUERY); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::setContainer(const Reference< css::awt::XControlContainer > &) +{ + SAL_WARN("dbaccess.ui","SbaXDataBrowserController::FormControllerImpl::setContainer : invalid call, can't change my container !"); +} + +Reference< css::awt::XControlContainer > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getContainer() +{ + if (m_pOwner->getBrowserView()) + return m_pOwner->getBrowserView()->getContainer(); + return Reference< css::awt::XControlContainer > (); +} + +Sequence< Reference< css::awt::XControl > > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getControls() +{ + if (m_pOwner->getBrowserView()) + { + Reference< css::awt::XControl > xGrid = m_pOwner->getBrowserView()->getGridControl(); + return Sequence< Reference< css::awt::XControl > >(&xGrid, 1); + } + return Sequence< Reference< css::awt::XControl > >(); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::autoTabOrder() +{ + SAL_WARN("dbaccess.ui","SbaXDataBrowserController::FormControllerImpl::autoTabOrder : nothing to do (always have only one control) !"); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::activateTabOrder() +{ + SAL_WARN("dbaccess.ui","SbaXDataBrowserController::FormControllerImpl::activateTabOrder : nothing to do (always have only one control) !"); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::activateFirst() +{ + if (m_pOwner->getBrowserView()) + m_pOwner->getBrowserView()->getVclControl()->ActivateCell(); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::activateLast() +{ + if (m_pOwner->getBrowserView()) + m_pOwner->getBrowserView()->getVclControl()->ActivateCell(); +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::frameAction(const css::frame::FrameActionEvent& /*aEvent*/) +{ +} + +void SAL_CALL SbaXDataBrowserController::FormControllerImpl::disposing(const css::lang::EventObject& /*Source*/) +{ + // nothing to do + // we don't add ourself as listener to any broadcasters, so we are not responsible for removing us +} + +// SbaXDataBrowserController +Sequence< Type > SAL_CALL SbaXDataBrowserController::getTypes( ) +{ + return ::comphelper::concatSequences( + SbaXDataBrowserController_Base::getTypes(), + m_xFormControllerImpl->getTypes() + ); +} + +Sequence< sal_Int8 > SAL_CALL SbaXDataBrowserController::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any SAL_CALL SbaXDataBrowserController::queryInterface(const Type& _rType) +{ + // check for our additional interfaces + Any aRet = SbaXDataBrowserController_Base::queryInterface(_rType); + + // check for our aggregate (implementing the XFormController) + if (!aRet.hasValue()) + aRet = m_xFormControllerImpl->queryAggregation(_rType); + + // no more to offer + return aRet; +} + +SbaXDataBrowserController::SbaXDataBrowserController(const Reference< css::uno::XComponentContext >& _rM) + :SbaXDataBrowserController_Base(_rM) + ,m_nRowSetPrivileges(0) + ,m_aInvalidateClipboard("dbaui::SbaXDataBrowserController m_aInvalidateClipboard") + ,m_aAsyncGetCellFocus(LINK(this, SbaXDataBrowserController, OnAsyncGetCellFocus)) + ,m_aAsyncDisplayError( LINK( this, SbaXDataBrowserController, OnAsyncDisplayError ) ) + ,m_sStateSaveRecord(DBA_RES(RID_STR_SAVE_CURRENT_RECORD)) + ,m_sStateUndoRecord(DBA_RES(RID_STR_UNDO_MODIFY_RECORD)) + ,m_sModuleIdentifier( OUString( "com.sun.star.sdb.DataSourceBrowser" ) ) + ,m_nFormActionNestingLevel(0) + ,m_bLoadCanceled( false ) + ,m_bCannotSelectUnfiltered( true ) +{ + // create the form controller aggregate + osl_atomic_increment(&m_refCount); + { + m_xFormControllerImpl = new FormControllerImpl(this); + m_xFormControllerImpl->setDelegator(*this); + } + osl_atomic_decrement(&m_refCount); + + m_aInvalidateClipboard.SetInvokeHandler(LINK(this, SbaXDataBrowserController, OnInvalidateClipboard)); + m_aInvalidateClipboard.SetTimeout(300); +} + +SbaXDataBrowserController::~SbaXDataBrowserController() +{ + // deleteView(); + // release the aggregated form controller + if (m_xFormControllerImpl.is()) + { + Reference< XInterface > xEmpty; + m_xFormControllerImpl->setDelegator(xEmpty); + } + +} + +void SbaXDataBrowserController::startFrameListening( const Reference< XFrame >& _rxFrame ) +{ + SbaXDataBrowserController_Base::startFrameListening( _rxFrame ); + + Reference< XFrameActionListener > xAggListener; + if ( m_xFormControllerImpl.is() ) + m_xFormControllerImpl->queryAggregation( cppu::UnoType<XFrameActionListener>::get() ) >>= xAggListener; + + if ( _rxFrame.is() && xAggListener.is() ) + _rxFrame->addFrameActionListener( xAggListener ); +} + +void SbaXDataBrowserController::stopFrameListening( const Reference< XFrame >& _rxFrame ) +{ + SbaXDataBrowserController_Base::stopFrameListening( _rxFrame ); + + Reference< XFrameActionListener > xAggListener; + if ( m_xFormControllerImpl.is() ) + m_xFormControllerImpl->queryAggregation( cppu::UnoType<XFrameActionListener>::get() ) >>= xAggListener; + + if ( _rxFrame.is() && xAggListener.is() ) + _rxFrame->removeFrameActionListener( xAggListener ); +} + +void SbaXDataBrowserController::onStartLoading( const Reference< XLoadable >& _rxLoadable ) +{ + m_bLoadCanceled = false; + m_bCannotSelectUnfiltered = false; + + Reference< XWarningsSupplier > xWarnings( _rxLoadable, UNO_QUERY ); + if ( xWarnings.is() ) + { + try + { + xWarnings->clearWarnings(); + } + catch(const SQLException& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } +} + +void SbaXDataBrowserController::impl_checkForCannotSelectUnfiltered( const SQLExceptionInfo& _rError ) +{ + ::connectivity::ErrorCode nErrorCode( connectivity::SQLError::getErrorCode( sdb::ErrorCondition::DATA_CANNOT_SELECT_UNFILTERED ) ); + if ( static_cast<const SQLException*>(_rError)->ErrorCode == nErrorCode ) + { + m_bCannotSelectUnfiltered = true; + InvalidateFeature( ID_BROWSER_FILTERCRIT ); + } +} + +bool SbaXDataBrowserController::reloadForm( const Reference< XLoadable >& _rxLoadable ) +{ + weld::WaitObject aWO(getFrameWeld()); + + onStartLoading( _rxLoadable ); + + FormErrorHelper aReportError(this); + if (_rxLoadable->isLoaded()) + _rxLoadable->reload(); + else + _rxLoadable->load(); + + m_xParser.clear(); + const Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY); + if (::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ESCAPE_PROCESSING))) + xFormSet->getPropertyValue(PROPERTY_SINGLESELECTQUERYCOMPOSER) >>= m_xParser; +#if 0 + { + const Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY ); + const Reference< XSingleSelectQueryAnalyzer > xAnalyzer( xRowSetProps->getPropertyValue( PROPERTY_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY ); + if ( xAnalyzer.is() ) + { + const Reference< XIndexAccess > xOrderColumns( xAnalyzer->getOrderColumns(), UNO_SET_THROW ); + const sal_Int32 nOrderColumns( xOrderColumns->getCount() ); + for ( sal_Int32 c=0; c<nOrderColumns; ++c ) + { + const Reference< XPropertySet > xOrderColumn( xOrderColumns->getByIndex(c), UNO_QUERY_THROW ); + OUString sColumnName; + OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumnName); + OUString sTableName; + OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_TABLENAME ) >>= sTableName); + (void)sColumnName; + (void)sTableName; + } + } + } +#endif + + Reference< XWarningsSupplier > xWarnings( _rxLoadable, UNO_QUERY ); + if ( xWarnings.is() ) + { + try + { + SQLExceptionInfo aInfo( xWarnings->getWarnings() ); + if ( aInfo.isValid() ) + { + showError( aInfo ); + impl_checkForCannotSelectUnfiltered( aInfo ); + } + } + catch(const SQLException& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + return _rxLoadable->isLoaded(); +} + +void SbaXDataBrowserController::initFormatter() +{ + // create a formatter working with the connections format supplier + Reference< css::util::XNumberFormatsSupplier > xSupplier(::dbtools::getNumberFormats(::dbtools::getConnection(m_xRowSet), true, getORB())); + + if(xSupplier.is()) + { + // create a new formatter + m_xFormatter.set(util::NumberFormatter::create(getORB()), UNO_QUERY_THROW); + m_xFormatter->attachNumberFormatsSupplier(xSupplier); + } + else // clear the formatter + m_xFormatter = nullptr; +} + +void SbaXDataBrowserController::describeSupportedFeatures() +{ + SbaXDataBrowserController_Base::describeSupportedFeatures(); + implDescribeSupportedFeature( ".uno:FormSlots/undoRecord", ID_BROWSER_UNDORECORD, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:FormController/undoRecord", ID_BROWSER_UNDORECORD, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:RecUndo", ID_BROWSER_UNDORECORD, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:FormSlots/saveRecord", ID_BROWSER_SAVERECORD, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:FormController/saveRecord", ID_BROWSER_SAVERECORD, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:RecSave", ID_BROWSER_SAVERECORD, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVERECORD, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:RecSearch", SID_FM_SEARCH, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:AutoFilter", SID_FM_AUTOFILTER, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:Refresh", SID_FM_REFRESH, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:OrderCrit", SID_FM_ORDERCRIT, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:RemoveFilterSort", SID_FM_REMOVE_FILTER_SORT,CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:FormFiltered", SID_FM_FORM_FILTERED, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:FilterCrit", SID_FM_FILTERCRIT, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:Sortup", ID_BROWSER_SORTUP, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:SortDown", ID_BROWSER_SORTDOWN, CommandGroup::CONTROLS ); + implDescribeSupportedFeature( ".uno:FormSlots/deleteRecord", SID_FM_DELETEROWS, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:FormSlots/insertRecord", ID_BROWSER_INSERT_ROW, CommandGroup::INSERT ); +} + +bool SbaXDataBrowserController::Construct(vcl::Window* pParent) +{ + // create/initialize the form and the grid model + m_xRowSet = CreateForm(); + if (!m_xRowSet.is()) + return false; + + m_xColumnsSupplier.set(m_xRowSet,UNO_QUERY); + m_xLoadable.set(m_xRowSet,UNO_QUERY); + + Reference< XPropertySet > xFormProperties( m_xRowSet, UNO_QUERY ); + if ( !InitializeForm( xFormProperties ) ) + return false; + + m_xGridModel = CreateGridModel(); + if (!m_xGridModel.is()) + return false; + + // set the formatter if available + initFormatter(); + + // we want to have a grid with a "flat" border + Reference< XPropertySet > xGridSet(m_xGridModel, UNO_QUERY); + if ( xGridSet.is() ) + xGridSet->setPropertyValue(PROPERTY_BORDER, Any(sal_Int16(2))); + + + // marry them + Reference< css::container::XNameContainer > xNameCont(m_xRowSet, UNO_QUERY); + { + OUString sText(DBA_RES(STR_DATASOURCE_GRIDCONTROL_NAME)); + xNameCont->insertByName(sText, Any(m_xGridModel)); + } + + // create the view + setView( VclPtr<UnoDataBrowserView>::Create( pParent, *this, getORB() ) ); + if (!getBrowserView()) + return false; + + // late construction + bool bSuccess = false; + try + { + getBrowserView()->Construct(getControlModel()); + bSuccess = true; + } + catch(SQLException&) + { + } + catch(Exception&) + { + SAL_WARN("dbaccess.ui","SbaXDataBrowserController::Construct : the construction of UnoDataBrowserView failed !"); + } + + if (!bSuccess) + { + // deleteView(); + return false; + } + + // now that we have a view we can create the clipboard listener + m_aSystemClipboard = TransferableDataHelper::CreateFromSystemClipboard( getView() ); + m_aSystemClipboard.StartClipboardListening( ); + + m_pClipboardNotifier = new TransferableClipboardListener( LINK( this, SbaXDataBrowserController, OnClipboardChanged ) ); + m_pClipboardNotifier->AddListener( getView() ); + + // this call create the toolbox + SbaXDataBrowserController_Base::Construct(pParent); + + getBrowserView()->Show(); + + // set the callbacks for the grid control + SbaGridControl* pVclGrid = getBrowserView()->getVclControl(); + OSL_ENSURE(pVclGrid, "SbaXDataBrowserController::Construct : have no VCL control !"); + pVclGrid->SetMasterListener(this); + + // add listeners... + + // ... to the form model + Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY); + if (xFormSet.is()) + { + xFormSet->addPropertyChangeListener(PROPERTY_ISNEW, static_cast<XPropertyChangeListener*>(this)); + xFormSet->addPropertyChangeListener(PROPERTY_ISMODIFIED, static_cast<XPropertyChangeListener*>(this)); + xFormSet->addPropertyChangeListener(PROPERTY_ROWCOUNT, static_cast<XPropertyChangeListener*>(this)); + xFormSet->addPropertyChangeListener(PROPERTY_ACTIVECOMMAND, static_cast<XPropertyChangeListener*>(this)); + xFormSet->addPropertyChangeListener(PROPERTY_ORDER, static_cast<XPropertyChangeListener*>(this)); + xFormSet->addPropertyChangeListener(PROPERTY_FILTER, static_cast<XPropertyChangeListener*>(this)); + xFormSet->addPropertyChangeListener(PROPERTY_HAVING_CLAUSE, static_cast<XPropertyChangeListener*>(this)); + xFormSet->addPropertyChangeListener(PROPERTY_APPLYFILTER, static_cast<XPropertyChangeListener*>(this)); + } + Reference< css::sdb::XSQLErrorBroadcaster > xFormError(getRowSet(), UNO_QUERY); + if (xFormError.is()) + xFormError->addSQLErrorListener(static_cast<css::sdb::XSQLErrorListener*>(this)); + + if (m_xLoadable.is()) + m_xLoadable->addLoadListener(this); + + Reference< css::form::XDatabaseParameterBroadcaster > xFormParameter(getRowSet(), UNO_QUERY); + if (xFormParameter.is()) + xFormParameter->addParameterListener(static_cast<css::form::XDatabaseParameterListener*>(this)); + + addModelListeners(getControlModel()); + addControlListeners(getBrowserView()->getGridControl()); + + // load the form + return LoadForm(); +} + +bool SbaXDataBrowserController::LoadForm() +{ + reloadForm( m_xLoadable ); + return true; +} + +void SbaXDataBrowserController::AddColumnListener(const Reference< XPropertySet > & /*xCol*/) +{ + // we're not interested in any column properties... +} + +void SbaXDataBrowserController::RemoveColumnListener(const Reference< XPropertySet > & /*xCol*/) +{ +} + +Reference< XRowSet > SbaXDataBrowserController::CreateForm() +{ + return Reference< XRowSet > ( + getORB()->getServiceManager()->createInstanceWithContext("com.sun.star.form.component.Form", getORB()), + UNO_QUERY); +} + +Reference< css::form::XFormComponent > SbaXDataBrowserController::CreateGridModel() +{ + return Reference< css::form::XFormComponent > ( + getORB()->getServiceManager()->createInstanceWithContext("com.sun.star.form.component.GridControl", getORB()), + UNO_QUERY); +} + +void SbaXDataBrowserController::addModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel) +{ + // ... all the grid columns + addColumnListeners(_xGridControlModel); + + // (we are interested in all columns the grid has (and only in these) so we have to listen to the container, too) + Reference< css::container::XContainer > xColContainer(_xGridControlModel, UNO_QUERY); + if (xColContainer.is()) + xColContainer->addContainerListener(static_cast<css::container::XContainerListener*>(this)); + + Reference< css::form::XReset > xReset(_xGridControlModel, UNO_QUERY); + if (xReset.is()) + xReset->addResetListener(static_cast<css::form::XResetListener*>(this)); +} + +void SbaXDataBrowserController::removeModelListeners(const Reference< XControlModel > & _xGridControlModel) +{ + // every single column model + Reference< XIndexContainer > xColumns(_xGridControlModel, UNO_QUERY); + if (xColumns.is()) + { + sal_Int32 nCount = xColumns->getCount(); + for (sal_Int32 i=0; i < nCount; ++i) + { + Reference< XPropertySet > xCol(xColumns->getByIndex(i),UNO_QUERY); + RemoveColumnListener(xCol); + } + } + + Reference< XContainer > xColContainer(_xGridControlModel, UNO_QUERY); + if (xColContainer.is()) + xColContainer->removeContainerListener( this ); + + Reference< XReset > xReset(_xGridControlModel, UNO_QUERY); + if (xReset.is()) + xReset->removeResetListener( this ); +} + +void SbaXDataBrowserController::addControlListeners(const Reference< css::awt::XControl > & _xGridControl) +{ + // to ge the 'modified' for the current cell + Reference< XModifyBroadcaster > xBroadcaster(getBrowserView()->getGridControl(), UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addModifyListener(static_cast<XModifyListener*>(this)); + + // introduce ourself as dispatch provider for the grid + Reference< XDispatchProviderInterception > xInterception(getBrowserView()->getGridControl(), UNO_QUERY); + if (xInterception.is()) + xInterception->registerDispatchProviderInterceptor(static_cast<XDispatchProviderInterceptor*>(this)); + + // add as focus listener to the control (needed for the form controller functionality) + Reference< XWindow > xWindow(_xGridControl, UNO_QUERY); + if (xWindow.is()) + xWindow->addFocusListener(this); +} + +void SbaXDataBrowserController::removeControlListeners(const Reference< css::awt::XControl > & _xGridControl) +{ + Reference< XModifyBroadcaster > xBroadcaster(_xGridControl, UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeModifyListener(static_cast<XModifyListener*>(this)); + + Reference< XDispatchProviderInterception > xInterception(_xGridControl, UNO_QUERY); + if (xInterception.is()) + xInterception->releaseDispatchProviderInterceptor(static_cast<XDispatchProviderInterceptor*>(this)); + + Reference< XWindow > xWindow(_xGridControl, UNO_QUERY); + if (xWindow.is()) + xWindow->removeFocusListener(this); +} + +void SAL_CALL SbaXDataBrowserController::focusGained(const FocusEvent& /*e*/) +{ + // notify our activate listeners (registered on the form controller aggregate) + EventObject aEvt(*this); + m_xFormControllerImpl->m_aActivateListeners.notifyEach( &css::form::XFormControllerListener::formActivated, aEvt ); +} + +void SAL_CALL SbaXDataBrowserController::focusLost(const FocusEvent& e) +{ + // some general checks + if (!getBrowserView() || !getBrowserView()->getGridControl().is()) + return; + Reference< XVclWindowPeer > xMyGridPeer(getBrowserView()->getGridControl()->getPeer(), UNO_QUERY); + if (!xMyGridPeer.is()) + return; + Reference< XWindowPeer > xNextControlPeer(e.NextFocus, UNO_QUERY); + if (!xNextControlPeer.is()) + return; + + // don't do a notification if it remains in the family (i.e. a child of the grid control gets the focus) + if (xMyGridPeer->isChild(xNextControlPeer)) + return; + + if (xMyGridPeer == xNextControlPeer) + return; + + // notify the listeners that the "form" we represent has been deactivated + EventObject aEvt(*this); + m_xFormControllerImpl->m_aActivateListeners.notifyEach( &css::form::XFormControllerListener::formDeactivated, aEvt ); + + // commit the changes of the grid control (as we're deactivated) + Reference< XBoundComponent > xCommitable(getBrowserView()->getGridControl(), UNO_QUERY); + if (xCommitable.is()) + xCommitable->commit(); + else + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::focusLost : why is my control not committable?"); +} + +void SbaXDataBrowserController::disposingFormModel(const css::lang::EventObject& Source) +{ + Reference< XPropertySet > xSourceSet(Source.Source, UNO_QUERY); + if (xSourceSet.is()) + { + xSourceSet->removePropertyChangeListener(PROPERTY_ISNEW, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_ISMODIFIED, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_ROWCOUNT, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_ACTIVECOMMAND, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_ORDER, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_FILTER, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_HAVING_CLAUSE, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_APPLYFILTER, static_cast<XPropertyChangeListener*>(this)); + } + + Reference< css::sdb::XSQLErrorBroadcaster > xFormError(Source.Source, UNO_QUERY); + if (xFormError.is()) + xFormError->removeSQLErrorListener(static_cast<css::sdb::XSQLErrorListener*>(this)); + + if (m_xLoadable.is()) + m_xLoadable->removeLoadListener(this); + + Reference< css::form::XDatabaseParameterBroadcaster > xFormParameter(Source.Source, UNO_QUERY); + if (xFormParameter.is()) + xFormParameter->removeParameterListener(static_cast<css::form::XDatabaseParameterListener*>(this)); +} + +void SbaXDataBrowserController::disposingColumnModel(const css::lang::EventObject& Source) +{ + RemoveColumnListener(Reference< XPropertySet > (Source.Source, UNO_QUERY)); +} + +void SbaXDataBrowserController::disposing(const EventObject& Source) +{ + // if it's a component other than our aggregate, forward it to the aggregate + if ( uno::Reference<XInterface>(static_cast<cppu::OWeakObject*>(m_xFormControllerImpl.get()), UNO_QUERY) != Source.Source ) + { + Reference< XEventListener > xAggListener; + m_xFormControllerImpl->queryAggregation( cppu::UnoType<decltype(xAggListener)>::get() ) >>= xAggListener; + if ( xAggListener.is( )) + xAggListener->disposing( Source ); + } + + // is it the grid control ? + if (getBrowserView()) + { + Reference< css::awt::XControl > xSourceControl(Source.Source, UNO_QUERY); + if (xSourceControl == getBrowserView()->getGridControl()) + removeControlListeners(getBrowserView()->getGridControl()); + } + + // its model (the container of the columns) ? + if (getControlModel() == Source.Source) + removeModelListeners(getControlModel()); + + // the form's model ? + if (getRowSet() == Source.Source) + disposingFormModel(Source); + + // from a single column model ? + Reference< XPropertySet > xSourceSet(Source.Source, UNO_QUERY); + if (xSourceSet.is()) + { + Reference< XPropertySetInfo > xInfo = xSourceSet->getPropertySetInfo(); + // we assume that columns have a Width property and all other sets we are listening to don't have + if (xInfo->hasPropertyByName(PROPERTY_WIDTH)) + disposingColumnModel(Source); + } + SbaXDataBrowserController_Base::OGenericUnoController::disposing( Source ); +} + +void SAL_CALL SbaXDataBrowserController::setIdentifier( const OUString& Identifier ) +{ + ::osl::MutexGuard aGuard( getMutex() ); + m_sModuleIdentifier = Identifier; +} + +OUString SAL_CALL SbaXDataBrowserController::getIdentifier( ) +{ + ::osl::MutexGuard aGuard( getMutex() ); + return m_sModuleIdentifier; +} + +void SbaXDataBrowserController::propertyChange(const PropertyChangeEvent& evt) +{ + Reference< XPropertySet > xSource(evt.Source, UNO_QUERY); + if (!xSource.is()) + return; + + SolarMutexGuard aGuard; + // the IsModified changed to sal_False ? + if ( evt.PropertyName == PROPERTY_ISMODIFIED + && !::comphelper::getBOOL(evt.NewValue) + ) + { // -> the current field isn't modified anymore, too + setCurrentModified( false ); + } + + // switching to a new record ? + if ( evt.PropertyName == PROPERTY_ISNEW + && ::comphelper::getBOOL(evt.NewValue) + ) + { + if (::comphelper::getINT32(xSource->getPropertyValue(PROPERTY_ROWCOUNT)) == 0) + // if we're switching to a new record and didn't have any records before we need to invalidate + // all slots (as the cursor was invalid before the mode change and so the slots were disabled) + InvalidateAll(); + } + + if (evt.PropertyName == PROPERTY_FILTER) + { + InvalidateFeature(ID_BROWSER_REMOVEFILTER); + } + else if (evt.PropertyName == PROPERTY_HAVING_CLAUSE) + { + InvalidateFeature(ID_BROWSER_REMOVEFILTER); + } + else if (evt.PropertyName == PROPERTY_ORDER) + { + InvalidateFeature(ID_BROWSER_REMOVEFILTER); + } + + // a new record count ? -> may be our search availability has changed + if (evt.PropertyName == PROPERTY_ROWCOUNT) + { + sal_Int32 nNewValue = 0, nOldValue = 0; + evt.NewValue >>= nNewValue; + evt.OldValue >>= nOldValue; + if((nOldValue == 0 && nNewValue != 0) || (nOldValue != 0 && nNewValue == 0)) + InvalidateAll(); + } +} + +void SbaXDataBrowserController::modified(const css::lang::EventObject& /*aEvent*/) +{ + setCurrentModified( true ); +} + +void SbaXDataBrowserController::elementInserted(const css::container::ContainerEvent& evt) +{ + OSL_ENSURE(Reference< XInterface >(evt.Source, UNO_QUERY).get() == Reference< XInterface >(getControlModel(), UNO_QUERY).get(), + "SbaXDataBrowserController::elementInserted: where did this come from (not from the grid model)?!"); + Reference< XPropertySet > xNewColumn(evt.Element,UNO_QUERY); + if ( xNewColumn.is() ) + AddColumnListener(xNewColumn); +} + +void SbaXDataBrowserController::elementRemoved(const css::container::ContainerEvent& evt) +{ + OSL_ENSURE(Reference< XInterface >(evt.Source, UNO_QUERY).get() == Reference< XInterface >(getControlModel(), UNO_QUERY).get(), + "SbaXDataBrowserController::elementRemoved: where did this come from (not from the grid model)?!"); + Reference< XPropertySet > xOldColumn(evt.Element,UNO_QUERY); + if ( xOldColumn.is() ) + RemoveColumnListener(xOldColumn); +} + +void SbaXDataBrowserController::elementReplaced(const css::container::ContainerEvent& evt) +{ + OSL_ENSURE(Reference< XInterface >(evt.Source, UNO_QUERY).get() == Reference< XInterface >(getControlModel(), UNO_QUERY).get(), + "SbaXDataBrowserController::elementReplaced: where did this come from (not from the grid model)?!"); + Reference< XPropertySet > xOldColumn(evt.ReplacedElement,UNO_QUERY); + if ( xOldColumn.is() ) + RemoveColumnListener(xOldColumn); + + Reference< XPropertySet > xNewColumn(evt.Element,UNO_QUERY); + if ( xNewColumn.is() ) + AddColumnListener(xNewColumn); +} + +sal_Bool SbaXDataBrowserController::suspend(sal_Bool /*bSuspend*/) +{ + m_aAsyncGetCellFocus.CancelCall(); + m_aAsyncDisplayError.CancelCall(); + m_aAsyncInvalidateAll.CancelCall(); + + bool bSuccess = SaveModified(); + return bSuccess; +} + +void SbaXDataBrowserController::disposing() +{ + // the base class + SbaXDataBrowserController_Base::OGenericUnoController::disposing(); + + // the data source + Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY); + if (xFormSet.is()) + { + xFormSet->removePropertyChangeListener(PROPERTY_ISNEW, static_cast<XPropertyChangeListener*>(this)); + xFormSet->removePropertyChangeListener(PROPERTY_ISMODIFIED, static_cast<XPropertyChangeListener*>(this)); + xFormSet->removePropertyChangeListener(PROPERTY_ROWCOUNT, static_cast<XPropertyChangeListener*>(this)); + xFormSet->removePropertyChangeListener(PROPERTY_ACTIVECOMMAND, static_cast<XPropertyChangeListener*>(this)); + xFormSet->removePropertyChangeListener(PROPERTY_ORDER, static_cast<XPropertyChangeListener*>(this)); + xFormSet->removePropertyChangeListener(PROPERTY_FILTER, static_cast<XPropertyChangeListener*>(this)); + xFormSet->removePropertyChangeListener(PROPERTY_HAVING_CLAUSE, static_cast<XPropertyChangeListener*>(this)); + xFormSet->removePropertyChangeListener(PROPERTY_APPLYFILTER, static_cast<XPropertyChangeListener*>(this)); + } + + Reference< css::sdb::XSQLErrorBroadcaster > xFormError(getRowSet(), UNO_QUERY); + if (xFormError.is()) + xFormError->removeSQLErrorListener(static_cast<css::sdb::XSQLErrorListener*>(this)); + + if (m_xLoadable.is()) + m_xLoadable->removeLoadListener(this); + + Reference< css::form::XDatabaseParameterBroadcaster > xFormParameter(getRowSet(), UNO_QUERY); + if (xFormParameter.is()) + xFormParameter->removeParameterListener(static_cast<css::form::XDatabaseParameterListener*>(this)); + + removeModelListeners(getControlModel()); + + if ( getView() && m_pClipboardNotifier.is() ) + { + m_pClipboardNotifier->ClearCallbackLink(); + m_pClipboardNotifier->RemoveListener( getView() ); + m_pClipboardNotifier.clear(); + } + + if (getBrowserView()) + { + removeControlListeners(getBrowserView()->getGridControl()); + // don't delete explicitly, this is done by the owner (and user) of this controller (me hopes ...) + clearView(); + } + + if(m_aInvalidateClipboard.IsActive()) + m_aInvalidateClipboard.Stop(); + + // dispose the row set + try + { + ::comphelper::disposeComponent(m_xRowSet); + + m_xRowSet = nullptr; + m_xColumnsSupplier = nullptr; + m_xLoadable = nullptr; + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + m_xParser.clear(); + // don't dispose, just reset - it's owned by the RowSet +} + +void SbaXDataBrowserController::frameAction(const css::frame::FrameActionEvent& aEvent) +{ + ::osl::MutexGuard aGuard( getMutex() ); + + SbaXDataBrowserController_Base::frameAction( aEvent ); + + if ( aEvent.Source != getFrame() ) + return; + + switch ( aEvent.Action ) + { + case FrameAction_FRAME_ACTIVATED: + case FrameAction_FRAME_UI_ACTIVATED: + // ensure that the active cell (if any) has the focus + m_aAsyncGetCellFocus.Call(); + // start the clipboard timer + if (getBrowserView() && getBrowserView()->getVclControl() && !m_aInvalidateClipboard.IsActive()) + { + m_aInvalidateClipboard.Start(); + OnInvalidateClipboard( nullptr ); + } + break; + case FrameAction_FRAME_DEACTIVATING: + case FrameAction_FRAME_UI_DEACTIVATING: + // stop the clipboard invalidator + if (getBrowserView() && getBrowserView()->getVclControl() && m_aInvalidateClipboard.IsActive()) + { + m_aInvalidateClipboard.Stop(); + OnInvalidateClipboard( nullptr ); + } + // remove the "get cell focus"-event + m_aAsyncGetCellFocus.CancelCall(); + break; + default: + break; + } +} + +IMPL_LINK_NOARG( SbaXDataBrowserController, OnAsyncDisplayError, void*, void ) +{ + if ( m_aCurrentError.isValid() ) + { + OSQLMessageBox aDlg(getFrameWeld(), m_aCurrentError); + aDlg.run(); + } +} + +void SbaXDataBrowserController::errorOccured(const css::sdb::SQLErrorEvent& aEvent) +{ + ::osl::MutexGuard aGuard( getMutex() ); + + SQLExceptionInfo aInfo( aEvent.Reason ); + if ( !aInfo.isValid() ) + return; + + if ( m_nFormActionNestingLevel ) + { + OSL_ENSURE( !m_aCurrentError.isValid(), "SbaXDataBrowserController::errorOccurred: can handle one error per transaction only!" ); + m_aCurrentError = aInfo; + } + else + { + m_aCurrentError = aInfo; + m_aAsyncDisplayError.Call(); + } +} + +sal_Bool SbaXDataBrowserController::approveParameter(const css::form::DatabaseParameterEvent& aEvent) +{ + if (aEvent.Source != getRowSet()) + { + // not my data source -> allow anything + SAL_WARN("dbaccess.ui","SbaXDataBrowserController::approveParameter : invalid event source !"); + return true; + } + + Reference< css::container::XIndexAccess > xParameters = aEvent.Parameters; + SolarMutexGuard aSolarGuard; + + // default handling: instantiate an interaction handler and let it handle the parameter request + try + { + // two continuations allowed: OK and Cancel + rtl::Reference<OParameterContinuation> pParamValues = new OParameterContinuation; + rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort; + // the request + ParametersRequest aRequest; + aRequest.Parameters = xParameters; + aRequest.Connection = getConnection(Reference< XRowSet >(aEvent.Source, UNO_QUERY)); + rtl::Reference<OInteractionRequest> pParamRequest = new OInteractionRequest(Any(aRequest)); + // some knittings + pParamRequest->addContinuation(pParamValues); + pParamRequest->addContinuation(pAbort); + + // create the handler, let it handle the request + Reference< XInteractionHandler2 > xHandler(InteractionHandler::createWithParent(getORB(), getComponentWindow())); + xHandler->handle(pParamRequest); + + if (!pParamValues->wasSelected()) + { // canceled + setLoadingCancelled(); + return false; + } + + // transfer the values into the parameter supplier + Sequence< PropertyValue > aFinalValues = pParamValues->getValues(); + if (aFinalValues.getLength() != aRequest.Parameters->getCount()) + { + SAL_WARN("dbaccess.ui","SbaXDataBrowserController::approveParameter: the InteractionHandler returned nonsense!"); + setLoadingCancelled(); + return false; + } + const PropertyValue* pFinalValues = aFinalValues.getConstArray(); + for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues) + { + Reference< XPropertySet > xParam( + aRequest.Parameters->getByIndex(i), css::uno::UNO_QUERY); + OSL_ENSURE(xParam.is(), "SbaXDataBrowserController::approveParameter: one of the parameters is no property set!"); + if (xParam.is()) + { +#ifdef DBG_UTIL + OUString sName; + xParam->getPropertyValue(PROPERTY_NAME) >>= sName; + OSL_ENSURE(sName == pFinalValues->Name, "SbaXDataBrowserController::approveParameter: suspicious value names!"); +#endif + try { xParam->setPropertyValue(PROPERTY_VALUE, pFinalValues->Value); } + catch(Exception&) + { + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::approveParameter: setting one of the properties failed!"); + } + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return true; +} + +sal_Bool SbaXDataBrowserController::approveReset(const css::lang::EventObject& /*rEvent*/) +{ + return true; +} + +void SbaXDataBrowserController::resetted(const css::lang::EventObject& rEvent) +{ + OSL_ENSURE(rEvent.Source == getControlModel(), "SbaXDataBrowserController::resetted : where did this come from ?"); + setCurrentModified( false ); +} + +sal_Bool SbaXDataBrowserController::confirmDelete(const css::sdb::RowChangeEvent& /*aEvent*/) +{ + std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(getFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + DBA_RES(STR_QUERY_BRW_DELETE_ROWS))); + if (xQuery->run() != RET_YES) + return false; + return true; +} + +FeatureState SbaXDataBrowserController::GetState(sal_uInt16 nId) const +{ + FeatureState aReturn; + // (disabled automatically) + + try + { + // no chance without a view + if (!getBrowserView() || !getBrowserView()->getVclControl()) + return aReturn; + + switch (nId) + { + case ID_BROWSER_REMOVEFILTER: + if (!m_xParser.is()) + { + aReturn.bEnabled = false; + return aReturn; + } + // any filter or sort order set ? + aReturn.bEnabled = m_xParser->getFilter().getLength() || m_xParser->getHavingClause().getLength() || m_xParser->getOrder().getLength(); + return aReturn; + } + // no chance without valid models + if (isValid() && !isValidCursor()) + return aReturn; + + switch (nId) + { + case ID_BROWSER_SEARCH: + { + Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY); + sal_Int32 nCount = ::comphelper::getINT32(xFormSet->getPropertyValue(PROPERTY_ROWCOUNT)); + aReturn.bEnabled = nCount != 0; + } + break; + case ID_BROWSER_INSERT_ROW: + { + // check if it is available + bool bInsertPrivilege = ( m_nRowSetPrivileges & Privilege::INSERT) != 0; + bool bAllowInsertions = true; + try + { + Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY_THROW ); + OSL_VERIFY( xRowSetProps->getPropertyValue("AllowInserts") >>= bAllowInsertions ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + aReturn.bEnabled = bInsertPrivilege && bAllowInsertions; + } + break; + case SID_FM_DELETEROWS: + { + // check if it is available + bool bDeletePrivilege = ( m_nRowSetPrivileges & Privilege::INSERT) != 0; + bool bAllowDeletions = true; + sal_Int32 nRowCount = 0; + bool bInsertionRow = false; + try + { + Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY_THROW ); + OSL_VERIFY( xRowSetProps->getPropertyValue("AllowDeletes") >>= bAllowDeletions ); + OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ROWCOUNT ) >>= nRowCount ); + OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ISNEW ) >>= bInsertionRow ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + aReturn.bEnabled = bDeletePrivilege && bAllowDeletions && ( nRowCount != 0 ) && !bInsertionRow; + } + break; + + case ID_BROWSER_COPY: + if ( getBrowserView()->getVclControl()->GetSelectRowCount() ) + { + aReturn.bEnabled = m_aCurrentFrame.isActive(); + break; + } + [[fallthrough]]; + case ID_BROWSER_PASTE: + case ID_BROWSER_CUT: + { + CellControllerRef xCurrentController = getBrowserView()->getVclControl()->Controller(); + if (const EditCellController* pController = dynamic_cast<const EditCellController*>(xCurrentController.get())) + { + const IEditImplementation* pEditImplementation = pController->GetEditImplementation(); + bool bHasLen = pEditImplementation->GetSelection().Len() != 0; + bool bIsReadOnly = pEditImplementation->IsReadOnly(); + switch (nId) + { + case ID_BROWSER_CUT: aReturn.bEnabled = m_aCurrentFrame.isActive() && bHasLen && !bIsReadOnly; break; + case SID_COPY : aReturn.bEnabled = m_aCurrentFrame.isActive() && bHasLen; break; + case ID_BROWSER_PASTE: + aReturn.bEnabled = m_aCurrentFrame.isActive() && !bIsReadOnly; + if(aReturn.bEnabled) + { + aReturn.bEnabled = IsFormatSupported( m_aSystemClipboard.GetDataFlavorExVector(), SotClipboardFormatId::STRING ); + } + break; + } + } + } + break; + + case ID_BROWSER_SORTUP: + case ID_BROWSER_SORTDOWN: + case ID_BROWSER_AUTOFILTER: + { + // a native statement can't be filtered or sorted + const Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY); + if ( !::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ESCAPE_PROCESSING)) || !m_xParser.is() ) + break; + + Reference< XPropertySet > xCurrentField = getBoundField(); + if (!xCurrentField.is()) + break; + + aReturn.bEnabled = ::comphelper::getBOOL(xCurrentField->getPropertyValue(PROPERTY_ISSEARCHABLE)); + const Reference< XRowSet > xRow = getRowSet(); + aReturn.bEnabled = aReturn.bEnabled + && xRow.is() + && !xRow->isBeforeFirst() + && !xRow->isAfterLast() + && !xRow->rowDeleted() + && ( ::comphelper::getINT32( xFormSet->getPropertyValue( PROPERTY_ROWCOUNT ) ) != 0 ); + } + break; + + case ID_BROWSER_FILTERCRIT: + if ( m_bCannotSelectUnfiltered && m_xParser.is() ) + { + aReturn.bEnabled = true; + break; + } + [[fallthrough]]; + case ID_BROWSER_ORDERCRIT: + { + const Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY); + if ( !::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ESCAPE_PROCESSING)) || !m_xParser.is() ) + break; + + aReturn.bEnabled = getRowSet().is() + && ( ::comphelper::getINT32( xFormSet->getPropertyValue( PROPERTY_ROWCOUNT ) ) != 0 ); + } + break; + + case ID_BROWSER_REFRESH: + aReturn.bEnabled = true; + break; + + case ID_BROWSER_REDO: + aReturn.bEnabled = false; // simply forget it ;). no redo possible. + break; + + case ID_BROWSER_UNDORECORD: + case ID_BROWSER_SAVERECORD: + { + if (!m_bCurrentlyModified) + { + Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY); + if (xFormSet.is()) + aReturn.bEnabled = ::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ISMODIFIED)); + } + else + aReturn.bEnabled = true; + + aReturn.sTitle = (ID_BROWSER_UNDORECORD == nId) ? m_sStateUndoRecord : m_sStateSaveRecord; + } + break; + case ID_BROWSER_EDITDOC: + { + // check if it is available + Reference< XPropertySet > xDataSourceSet(getRowSet(), UNO_QUERY); + if (!xDataSourceSet.is()) + break; // no datasource -> no edit mode + + sal_Int32 nDataSourcePrivileges = ::comphelper::getINT32(xDataSourceSet->getPropertyValue(PROPERTY_PRIVILEGES)); + bool bInsertAllowedAndPossible = ((nDataSourcePrivileges & css::sdbcx::Privilege::INSERT) != 0) && ::comphelper::getBOOL(xDataSourceSet->getPropertyValue("AllowInserts")); + bool bUpdateAllowedAndPossible = ((nDataSourcePrivileges & css::sdbcx::Privilege::UPDATE) != 0) && ::comphelper::getBOOL(xDataSourceSet->getPropertyValue("AllowUpdates")); + bool bDeleteAllowedAndPossible = ((nDataSourcePrivileges & css::sdbcx::Privilege::DELETE) != 0) && ::comphelper::getBOOL(xDataSourceSet->getPropertyValue("AllowDeletes")); + if (!bInsertAllowedAndPossible && !bUpdateAllowedAndPossible && !bDeleteAllowedAndPossible) + break; // no insert/update/delete -> no edit mode + + if (!isValidCursor() || !isLoaded()) + break; // no cursor -> no edit mode + + aReturn.bEnabled = true; + + DbGridControlOptions nGridMode = getBrowserView()->getVclControl()->GetOptions(); + aReturn.bChecked = nGridMode > DbGridControlOptions::Readonly; + } + break; + case ID_BROWSER_FILTERED: + { + aReturn.bEnabled = false; + Reference< XPropertySet > xActiveSet(getRowSet(), UNO_QUERY); + OUString aFilter = ::comphelper::getString(xActiveSet->getPropertyValue(PROPERTY_FILTER)); + OUString aHaving = ::comphelper::getString(xActiveSet->getPropertyValue(PROPERTY_HAVING_CLAUSE)); + if ( !(aFilter.isEmpty() && aHaving.isEmpty()) ) + { + xActiveSet->getPropertyValue( PROPERTY_APPLYFILTER ) >>= aReturn.bChecked; + aReturn.bEnabled = true; + } + else + { + aReturn.bChecked = false; + aReturn.bEnabled = false; + } + } + break; + default: + return SbaXDataBrowserController_Base::GetState(nId); + } + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return aReturn; +} + +void SbaXDataBrowserController::applyParserOrder(const OUString& _rOldOrder,const Reference< XSingleSelectQueryComposer >& _xParser) +{ + Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY); + if (!m_xLoadable.is()) + { + SAL_WARN("dbaccess.ui","SbaXDataBrowserController::applyParserOrder: invalid row set!"); + return; + } + + sal_uInt16 nPos = getCurrentColumnPosition(); + bool bSuccess = false; + try + { + xFormSet->setPropertyValue(PROPERTY_ORDER, Any(_xParser->getOrder())); + bSuccess = reloadForm(m_xLoadable); + } + catch(Exception&) + { + } + + if (!bSuccess) + { + xFormSet->setPropertyValue(PROPERTY_ORDER, Any(_rOldOrder)); + + try + { + if (loadingCancelled() || !reloadForm(m_xLoadable)) + criticalFail(); + } + catch(Exception&) + { + criticalFail(); + } + InvalidateAll(); + } + InvalidateFeature(ID_BROWSER_REMOVEFILTER); + + setCurrentColumnPosition(nPos); +} + +void SbaXDataBrowserController::applyParserFilter(const OUString& _rOldFilter, bool _bOldFilterApplied,const ::OUString& _sOldHaving,const Reference< XSingleSelectQueryComposer >& _xParser) +{ + Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY); + if (!m_xLoadable.is()) + { + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::applyParserFilter: invalid row set!"); + return; + } + + sal_uInt16 nPos = getCurrentColumnPosition(); + + bool bSuccess = false; + try + { + FormErrorHelper aError(this); + xFormSet->setPropertyValue(PROPERTY_FILTER, Any(_xParser->getFilter())); + xFormSet->setPropertyValue(PROPERTY_HAVING_CLAUSE, Any(_xParser->getHavingClause())); + xFormSet->setPropertyValue(PROPERTY_APPLYFILTER, css::uno::Any(true)); + + bSuccess = reloadForm(m_xLoadable); + } + catch(Exception&) + { + } + + if (!bSuccess) + { + xFormSet->setPropertyValue(PROPERTY_FILTER, Any(_rOldFilter)); + xFormSet->setPropertyValue(PROPERTY_HAVING_CLAUSE, Any(_sOldHaving)); + xFormSet->setPropertyValue(PROPERTY_APPLYFILTER, css::uno::Any(_bOldFilterApplied)); + + try + { + if (loadingCancelled() || !reloadForm(m_xLoadable)) + criticalFail(); + } + catch(Exception&) + { + criticalFail(); + } + InvalidateAll(); + } + InvalidateFeature(ID_BROWSER_REMOVEFILTER); + + setCurrentColumnPosition(nPos); +} + +Reference< XSingleSelectQueryComposer > SbaXDataBrowserController::createParser_nothrow() +{ + Reference< XSingleSelectQueryComposer > xComposer; + try + { + const Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY_THROW ); + const Reference< XMultiServiceFactory > xFactory( + xRowSetProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ), UNO_QUERY_THROW ); + xComposer.set( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW ); + + OUString sActiveCommand; + OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sActiveCommand ); + if ( !sActiveCommand.isEmpty() ) + { + xComposer->setElementaryQuery( sActiveCommand ); + } + else + { + OUString sCommand; + OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand ); + sal_Int32 nCommandType = CommandType::COMMAND; + OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_COMMAND_TYPE ) >>= nCommandType ); + xComposer->setCommand( sCommand, nCommandType ); + } + + OUString sFilter; + OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_FILTER ) >>= sFilter ); + xComposer->setFilter( sFilter ); + + OUString sHavingClause; + OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_HAVING_CLAUSE ) >>= sHavingClause ); + xComposer->setHavingClause( sHavingClause ); + + OUString sOrder; + OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ORDER ) >>= sOrder ); + xComposer->setOrder( sOrder ); + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return xComposer; +} + +void SbaXDataBrowserController::ExecuteFilterSortCrit(bool bFilter) +{ + if (!SaveModified()) + return; + + Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY); + + const OUString sOldVal = bFilter ? m_xParser->getFilter() : m_xParser->getOrder(); + const OUString sOldHaving = m_xParser->getHavingClause(); + Reference< XSingleSelectQueryComposer > xParser = createParser_nothrow(); + try + { + Reference< XConnection> xCon(xFormSet->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY); + if(bFilter) + { + DlgFilterCrit aDlg(getFrameWeld(), getORB(), xCon, xParser, m_xColumnsSupplier->getColumns()); + if (!aDlg.run()) + return; // if so we don't need to update the grid + aDlg.BuildWherePart(); + } + else + { + DlgOrderCrit aDlg(getFrameWeld(), xCon, xParser, m_xColumnsSupplier->getColumns()); + if (!aDlg.run()) + { + return; // if so we don't need to actualize the grid + } + aDlg.BuildOrderPart(); + } + } + catch(const SQLException& ) + { + SQLExceptionInfo aError( ::cppu::getCaughtException() ); + showError( aError ); + return; + } + catch(Exception&) + { + return; + } + + OUString sNewVal = bFilter ? xParser->getFilter() : xParser->getOrder(); + bool bOldFilterApplied(false); + if (bFilter) + { + try { bOldFilterApplied = ::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_APPLYFILTER)); } catch(Exception&) { } ; + } + + OUString sNewHaving = xParser->getHavingClause(); + if ( sOldVal == sNewVal && (!bFilter || sOldHaving == sNewHaving) ) + // nothing to be done + return; + + if (bFilter) + applyParserFilter(sOldVal, bOldFilterApplied,sOldHaving,xParser); + else + applyParserOrder(sOldVal,xParser); + + ::comphelper::disposeComponent(xParser); +} + +void SbaXDataBrowserController::ExecuteSearch() +{ + // calculate the control source of the active field + Reference< css::form::XGrid > xGrid(getBrowserView()->getGridControl(), UNO_QUERY); + OSL_ENSURE(xGrid.is(), "SbaXDataBrowserController::ExecuteSearch : the control should have a css::form::XGrid interface !"); + + Reference< css::form::XGridPeer > xGridPeer(getBrowserView()->getGridControl()->getPeer(), UNO_QUERY); + Reference< css::container::XIndexContainer > xColumns = xGridPeer->getColumns(); + OSL_ENSURE(xGridPeer.is() && xColumns.is(), "SbaXDataBrowserController::ExecuteSearch : invalid peer !"); + + sal_Int16 nViewCol = xGrid->getCurrentColumnPosition(); + sal_Int16 nModelCol = getBrowserView()->View2ModelPos(nViewCol); + + Reference< XPropertySet > xCurrentCol(xColumns->getByIndex(nModelCol),UNO_QUERY); + OUString sActiveField = ::comphelper::getString(xCurrentCol->getPropertyValue(PROPERTY_CONTROLSOURCE)); + + // the text within the current cell + OUString sInitialText; + Reference< css::container::XIndexAccess > xColControls(xGridPeer, UNO_QUERY); + Reference< XInterface > xCurControl(xColControls->getByIndex(nViewCol),UNO_QUERY); + OUString aInitialText; + if (IsSearchableControl(xCurControl, &aInitialText)) + sInitialText = aInitialText; + + // prohibit the synchronization of the grid's display with the cursor's position + Reference< XPropertySet > xModelSet(getControlModel(), UNO_QUERY); + OSL_ENSURE(xModelSet.is(), "SbaXDataBrowserController::ExecuteSearch : no model set ?!"); + xModelSet->setPropertyValue("DisplayIsSynchron", css::uno::Any(false)); + xModelSet->setPropertyValue("AlwaysShowCursor", css::uno::Any(true)); + xModelSet->setPropertyValue("CursorColor", Any(COL_LIGHTRED)); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + VclPtr<AbstractFmSearchDialog> pDialog; + std::vector< OUString > aContextNames; + aContextNames.emplace_back("Standard" ); + pDialog = pFact->CreateFmSearchDialog(getFrameWeld(), sInitialText, aContextNames, 0, LINK(this, SbaXDataBrowserController, OnSearchContextRequest)); + pDialog->SetActiveField( sActiveField ); + pDialog->SetFoundHandler( LINK( this, SbaXDataBrowserController, OnFoundData ) ); + pDialog->SetCanceledNotFoundHdl( LINK( this, SbaXDataBrowserController, OnCanceledNotFound ) ); + pDialog->Execute(); + pDialog.disposeAndClear(); + + // restore the grid's normal operating state + xModelSet->setPropertyValue("DisplayIsSynchron", css::uno::Any(true)); + xModelSet->setPropertyValue("AlwaysShowCursor", css::uno::Any(false)); + xModelSet->setPropertyValue("CursorColor", Any()); +} + +void SbaXDataBrowserController::Execute(sal_uInt16 nId, const Sequence< PropertyValue >& _rArgs) +{ + bool bSortUp = true; + + switch (nId) + { + default: + SbaXDataBrowserController_Base::Execute( nId, _rArgs ); + return; + + case ID_BROWSER_INSERT_ROW: + try + { + if (SaveModified()) + { + getRowSet()->afterLast(); + // check if it is available + Reference< XResultSetUpdate > xUpdateCursor(getRowSet(), UNO_QUERY_THROW); + xUpdateCursor->moveToInsertRow(); + } + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION("dbaccess.ui", "" ); + } + break; + case SID_FM_DELETEROWS: + + if (SaveModified()) + { + SbaGridControl* pVclGrid = getBrowserView()->getVclControl(); + if ( pVclGrid ) + { + if( !pVclGrid->GetSelectRowCount() ) + { + pVclGrid->DeactivateCell(); + pVclGrid->SelectRow(pVclGrid->GetCurRow()); + } + pVclGrid->DeleteSelectedRows(); + } + } + break; + + case ID_BROWSER_FILTERED: + if (SaveModified()) + { + Reference< XPropertySet > xActiveSet(getRowSet(), UNO_QUERY); + bool bApplied = ::comphelper::getBOOL(xActiveSet->getPropertyValue(PROPERTY_APPLYFILTER)); + xActiveSet->setPropertyValue(PROPERTY_APPLYFILTER, css::uno::Any(!bApplied)); + reloadForm(m_xLoadable); + } + InvalidateFeature(ID_BROWSER_FILTERED); + break; + case ID_BROWSER_EDITDOC: + { + DbGridControlOptions nGridMode = getBrowserView()->getVclControl()->GetOptions(); + if (nGridMode == DbGridControlOptions::Readonly) + getBrowserView()->getVclControl()->SetOptions(DbGridControlOptions::Update | DbGridControlOptions::Insert | DbGridControlOptions::Delete); + // the options not supported by the data source will be removed automatically + else + { + if ( !SaveModified( ) ) + // give the user a chance to save the current record (if necessary) + break; + + // maybe the user wanted to reject the modified record ? + if (GetState(ID_BROWSER_UNDORECORD).bEnabled) + Execute(ID_BROWSER_UNDORECORD,Sequence<PropertyValue>()); + + getBrowserView()->getVclControl()->SetOptions(DbGridControlOptions::Readonly); + } + InvalidateFeature(ID_BROWSER_EDITDOC); + } + break; + + case ID_BROWSER_SEARCH: + if ( SaveModified( ) ) + ExecuteSearch(); + break; + + case ID_BROWSER_COPY: + if ( getBrowserView()->getVclControl()->GetSelectRowCount() > 0 ) + { + getBrowserView()->getVclControl()->CopySelectedRowsToClipboard(); + break; + } + [[fallthrough]]; + case ID_BROWSER_CUT: + case ID_BROWSER_PASTE: + { + CellControllerRef xCurrentController = getBrowserView()->getVclControl()->Controller(); + if (EditCellController* pController = dynamic_cast<EditCellController*>(xCurrentController.get())) + { + IEditImplementation* pEditImplementation = pController->GetEditImplementation(); + switch (nId) + { + case ID_BROWSER_CUT: + pEditImplementation->Cut(); + break; + case SID_COPY: + pEditImplementation->Copy(); + break; + case ID_BROWSER_PASTE: + pEditImplementation->Paste(); + break; + } + if (ID_BROWSER_CUT == nId || ID_BROWSER_PASTE == nId) + pController->Modify(); + } + } + break; + + case ID_BROWSER_SORTDOWN: + bSortUp = false; + [[fallthrough]]; + case ID_BROWSER_SORTUP: + { + if (!SaveModified()) + break; + + if (!isValidCursor()) + break; + + // only one sort order + Reference< XPropertySet > xField = getBoundField(); + if (!xField.is()) + break; + + Reference< XSingleSelectQueryComposer > xParser = createParser_nothrow(); + const OUString sOldSort = xParser->getOrder(); + bool bParserSuccess = false; + try + { + bParserSuccess = false; + xParser->setOrder(OUString()); + xParser->appendOrderByColumn(xField, bSortUp); + bParserSuccess = true; + } + catch(SQLException& e) + { + SQLException aError = ::dbtools::prependErrorInfo(e, *this, DBA_RES(SBA_BROWSER_SETTING_ORDER)); + css::sdb::SQLErrorEvent aEvent; + aEvent.Reason <<= aError; + errorOccured(aEvent); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess", "SbaXDataBrowserController::Execute : caught an exception while composing the new filter !"); + } + + if (bParserSuccess) + applyParserOrder(sOldSort,xParser); + } + break; + + case ID_BROWSER_AUTOFILTER: + { + if (!SaveModified()) + break; + + if (!isValidCursor()) + break; + + Reference< XPropertySet > xField = getBoundField(); + if (!xField.is()) + break; + + // check if the column is an aggregate function + const bool bHaving(isAggregateColumn(m_xParser, xField)); + + Reference< XSingleSelectQueryComposer > xParser = createParser_nothrow(); + const OUString sOldFilter = xParser->getFilter(); + const OUString sOldHaving = xParser->getHavingClause(); + + Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY); + bool bApplied = ::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_APPLYFILTER)); + // do we have a filter but it's not applied ? + // -> completely overwrite it, else append one + if (!bApplied) + { + try + { + xParser->setFilter(OUString()); + } + catch(Exception&) + { + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::Execute : caught an exception while resetting unapplied filter !"); + } + try + { + xParser->setHavingClause(OUString()); + } + catch(Exception&) + { + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::Execute : caught an exception while resetting unapplied HAVING clause !"); + } + } + + bool bParserSuccess = false; + + const sal_Int32 nOp = SQLFilterOperator::EQUAL; + + if ( bHaving ) + { + try + { + bParserSuccess = false; + xParser->appendHavingClauseByColumn(xField,true,nOp); + bParserSuccess = true; + } + catch(SQLException& e) + { + SQLException aError = ::dbtools::prependErrorInfo(e, *this, DBA_RES(SBA_BROWSER_SETTING_FILTER)); + css::sdb::SQLErrorEvent aEvent; + aEvent.Reason <<= aError; + errorOccured(aEvent); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess", "SbaXDataBrowserController::Execute : caught an exception while composing the new filter !"); + } + } + else + { + try + { + bParserSuccess = false; + xParser->appendFilterByColumn(xField,true,nOp); + bParserSuccess = true; + } + catch(SQLException& e) + { + SQLException aError = ::dbtools::prependErrorInfo(e, *this, DBA_RES(SBA_BROWSER_SETTING_FILTER)); + css::sdb::SQLErrorEvent aEvent; + aEvent.Reason <<= aError; + errorOccured(aEvent); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess", "SbaXDataBrowserController::Execute : caught an exception while composing the new filter !"); + } + } + + if (bParserSuccess) + applyParserFilter(sOldFilter, bApplied,sOldHaving,xParser); + + InvalidateFeature(ID_BROWSER_REMOVEFILTER); + InvalidateFeature(ID_BROWSER_FILTERED); + } + break; + + case ID_BROWSER_ORDERCRIT: + ExecuteFilterSortCrit(false); + break; + + case ID_BROWSER_FILTERCRIT: + ExecuteFilterSortCrit(true); + InvalidateFeature(ID_BROWSER_FILTERED); + break; + + case ID_BROWSER_REMOVEFILTER: + { + if (!SaveModified()) + break; + + bool bNeedPostReload = preReloadForm(); + // reset the filter and the sort property simultaneously so only _one_ new statement has to be + // sent + Reference< XPropertySet > xSet(getRowSet(), UNO_QUERY); + if ( xSet.is() ) + { + xSet->setPropertyValue(PROPERTY_FILTER,Any(OUString())); + xSet->setPropertyValue(PROPERTY_HAVING_CLAUSE,Any(OUString())); + xSet->setPropertyValue(PROPERTY_ORDER,Any(OUString())); + } + try + { + reloadForm(m_xLoadable); + if ( bNeedPostReload ) + postReloadForm(); + } + catch(Exception&) + { + } + InvalidateFeature(ID_BROWSER_REMOVEFILTER); + InvalidateFeature(ID_BROWSER_FILTERED); + } + break; + + case ID_BROWSER_REFRESH: + if ( SaveModified( ) ) + { + if (!reloadForm(m_xLoadable)) + criticalFail(); + } + break; + + case ID_BROWSER_SAVERECORD: + if ( SaveModified( false ) ) + setCurrentModified( false ); + break; + + case ID_BROWSER_UNDORECORD: + { + try + { + // restore the cursor state + Reference< XResultSetUpdate > xCursor(getRowSet(), UNO_QUERY); + Reference< XPropertySet > xSet(xCursor, UNO_QUERY); + Any aVal = xSet->getPropertyValue(PROPERTY_ISNEW); + if (aVal.hasValue() && ::comphelper::getBOOL(aVal)) + { + xCursor->moveToInsertRow(); + // no need to reset the grid model after we moved to the insert row, this is done implicitly by the + // form + // (and in some cases it may be deadly to do the reset explicitly after the form did it implicitly, + // cause the form's reset may be async, and this leads to some nice deadlock scenarios...) + } + else + { + xCursor->cancelRowUpdates(); + + // restore the grids state + Reference< css::form::XReset > xReset(getControlModel(), UNO_QUERY); + if (xReset.is()) + xReset->reset(); + } + } + catch(SQLException&) + { + } + + setCurrentModified( false ); + } + } +} + +bool SbaXDataBrowserController::SaveModified(bool bAskFor) +{ + if ( bAskFor && GetState(ID_BROWSER_SAVERECORD).bEnabled ) + { + getBrowserView()->getVclControl()->GrabFocus(); + + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/savemodifieddialog.ui")); + std::unique_ptr<weld::MessageDialog> xQry(xBuilder->weld_message_dialog("SaveModifiedDialog")); + switch (xQry->run()) + { + case RET_NO: + Execute(ID_BROWSER_UNDORECORD,Sequence<PropertyValue>()); + return true; + case RET_CANCEL: + return false; + } + } + + if ( !CommitCurrent() ) // Commit the current control + return false; + + Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY); + bool bResult = false; + try + { + if (::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ISMODIFIED))) + { + Reference< XResultSetUpdate > xCursor(getRowSet(), UNO_QUERY); + if (::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ISNEW))) + xCursor->insertRow(); + else + xCursor->updateRow(); + } + bResult = true; + } + catch(SQLException&) + { + } + catch(Exception&) + { + SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::SaveModified : could not save the current record !"); + bResult = false; + } + + InvalidateFeature(ID_BROWSER_SAVERECORD); + InvalidateFeature(ID_BROWSER_UNDORECORD); + return bResult; +} + +bool SbaXDataBrowserController::CommitCurrent() +{ + if (!getBrowserView()) + return true; + + Reference< css::awt::XControl > xActiveControl(getBrowserView()->getGridControl()); + Reference< css::form::XBoundControl > xLockingTest(xActiveControl, UNO_QUERY); + bool bControlIsLocked = xLockingTest.is() && xLockingTest->getLock(); + if (xActiveControl.is() && !bControlIsLocked) + { + // At first check Control if it supports the IFace + Reference< css::form::XBoundComponent > xBoundControl(xActiveControl, UNO_QUERY); + if (!xBoundControl.is()) + xBoundControl.set(xActiveControl->getModel(), UNO_QUERY); + if (xBoundControl.is() && !xBoundControl->commit()) + return false; + } + return true; +} + +void SbaXDataBrowserController::setCurrentModified( bool _bSet ) +{ + m_bCurrentlyModified = _bSet; + InvalidateFeature( ID_BROWSER_SAVERECORD ); + InvalidateFeature( ID_BROWSER_UNDORECORD ); +} + +void SbaXDataBrowserController::RowChanged() +{ + setCurrentModified( false ); +} + +void SbaXDataBrowserController::ColumnChanged() +{ + InvalidateFeature(ID_BROWSER_SORTUP); + InvalidateFeature(ID_BROWSER_SORTDOWN); + InvalidateFeature(ID_BROWSER_ORDERCRIT); + InvalidateFeature(ID_BROWSER_FILTERCRIT); + InvalidateFeature(ID_BROWSER_AUTOFILTER); + InvalidateFeature(ID_BROWSER_REMOVEFILTER); + + setCurrentModified( false ); +} + +void SbaXDataBrowserController::SelectionChanged() +{ + // not interested in +} + +void SbaXDataBrowserController::CellActivated() +{ + m_aInvalidateClipboard.Start(); + OnInvalidateClipboard( nullptr ); +} + +void SbaXDataBrowserController::CellDeactivated() +{ + m_aInvalidateClipboard.Stop(); + OnInvalidateClipboard( nullptr ); +} + +IMPL_LINK_NOARG(SbaXDataBrowserController, OnClipboardChanged, TransferableDataHelper*, void) +{ + SolarMutexGuard aGuard; + OnInvalidateClipboard( nullptr ); +} + +IMPL_LINK(SbaXDataBrowserController, OnInvalidateClipboard, Timer*, _pTimer, void) +{ + InvalidateFeature(ID_BROWSER_CUT); + InvalidateFeature(ID_BROWSER_COPY); + + // if the invalidation was triggered by the timer, we do not need to invalidate PASTE. + // The timer is only for checking the CUT/COPY slots regularly, which depend on the + // selection state of the active cell + // TODO: get a callback at the Edit which allows to be notified when the selection + // changes. This would be much better than this cycle-eating polling mechanism here... + if ( _pTimer != &m_aInvalidateClipboard ) + InvalidateFeature(ID_BROWSER_PASTE); +} + +Reference< XPropertySet > SbaXDataBrowserController::getBoundField() const +{ + Reference< XPropertySet > xEmptyReturn; + + // get the current column from the grid + Reference< css::form::XGrid > xGrid(getBrowserView()->getGridControl(), UNO_QUERY); + if (!xGrid.is()) + return xEmptyReturn; + sal_uInt16 nViewPos = xGrid->getCurrentColumnPosition(); + sal_uInt16 nCurrentCol = getBrowserView()->View2ModelPos(nViewPos); + if (nCurrentCol == sal_uInt16(-1)) + return xEmptyReturn; + + // get the according column from the model + Reference< css::container::XIndexContainer > xCols(getControlModel(), UNO_QUERY); + Reference< XPropertySet > xCurrentCol(xCols->getByIndex(nCurrentCol),UNO_QUERY); + if (!xCurrentCol.is()) + return xEmptyReturn; + + xEmptyReturn.set(xCurrentCol->getPropertyValue(PROPERTY_BOUNDFIELD) ,UNO_QUERY); + return xEmptyReturn; +} + +IMPL_LINK(SbaXDataBrowserController, OnSearchContextRequest, FmSearchContext&, rContext, sal_uInt32) +{ + Reference< css::container::XIndexAccess > xPeerContainer(getBrowserView()->getGridControl(), UNO_QUERY); + + // check all grid columns for their control source + Reference< css::container::XIndexAccess > xModelColumns(getFormComponent(), UNO_QUERY); + OSL_ENSURE(xModelColumns.is(), "SbaXDataBrowserController::OnSearchContextRequest : there is a grid control without columns !"); + // the case 'no columns' should be indicated with an empty container, I think ... + OSL_ENSURE(xModelColumns->getCount() >= xPeerContainer->getCount(), "SbaXDataBrowserController::OnSearchContextRequest : impossible : have more view than model columns !"); + + OUString sFieldList; + for (sal_Int32 nViewPos=0; nViewPos<xPeerContainer->getCount(); ++nViewPos) + { + Reference< XInterface > xCurrentColumn(xPeerContainer->getByIndex(nViewPos),UNO_QUERY); + if (!xCurrentColumn.is()) + continue; + + // can we use this column control for searching ? + if (!IsSearchableControl(xCurrentColumn)) + continue; + + sal_uInt16 nModelPos = getBrowserView()->View2ModelPos(static_cast<sal_uInt16>(nViewPos)); + Reference< XPropertySet > xCurrentColModel(xModelColumns->getByIndex(nModelPos),UNO_QUERY); + OUString aName = ::comphelper::getString(xCurrentColModel->getPropertyValue(PROPERTY_CONTROLSOURCE)); + + sFieldList += aName + ";"; + + rContext.arrFields.push_back(xCurrentColumn); + } + sFieldList = comphelper::string::stripEnd(sFieldList, ';'); + + rContext.xCursor = getRowSet(); + rContext.strUsedFields = sFieldList; + + // if the cursor is in a mode other than STANDARD -> reset + Reference< XPropertySet > xCursorSet(rContext.xCursor, UNO_QUERY); + OSL_ENSURE(xCursorSet.is() && !::comphelper::getBOOL(xCursorSet->getPropertyValue(PROPERTY_ISMODIFIED)), + "SbaXDataBrowserController::OnSearchContextRequest : please do not call for cursors with modified rows !"); + if (xCursorSet.is() && ::comphelper::getBOOL(xCursorSet->getPropertyValue(PROPERTY_ISNEW))) + { + Reference< XResultSetUpdate > xUpdateCursor(rContext.xCursor, UNO_QUERY); + xUpdateCursor->moveToCurrentRow(); + } + return rContext.arrFields.size(); +} + +IMPL_LINK(SbaXDataBrowserController, OnFoundData, FmFoundRecordInformation&, rInfo, void) +{ + Reference< css::sdbcx::XRowLocate > xCursor(getRowSet(), UNO_QUERY); + OSL_ENSURE(xCursor.is(), "SbaXDataBrowserController::OnFoundData : xCursor is empty"); + + // move the cursor + xCursor->moveToBookmark(rInfo.aPosition); + + // let the grid sync its display with the cursor + Reference< XPropertySet > xModelSet(getControlModel(), UNO_QUERY); + OSL_ENSURE(xModelSet.is(), "SbaXDataBrowserController::OnFoundData : no model set ?!"); + Any aOld = xModelSet->getPropertyValue("DisplayIsSynchron"); + xModelSet->setPropertyValue("DisplayIsSynchron", css::uno::Any(true)); + xModelSet->setPropertyValue("DisplayIsSynchron", aOld); + + // and move to the field + Reference< css::container::XIndexAccess > aColumnControls(getBrowserView()->getGridControl()->getPeer(), UNO_QUERY); + sal_Int32 nViewPos; + + for ( nViewPos = 0; nViewPos < aColumnControls->getCount(); ++nViewPos ) + { + Reference< XInterface > xCurrent(aColumnControls->getByIndex(nViewPos),UNO_QUERY); + if (IsSearchableControl(xCurrent)) + { + if (rInfo.nFieldPos) + --rInfo.nFieldPos; + else + break; + } + } + + Reference< css::form::XGrid > xGrid(getBrowserView()->getGridControl(), UNO_QUERY); + xGrid->setCurrentColumnPosition(nViewPos); //TODO: sal_Int32 -> sal_Int16! +} + +IMPL_LINK(SbaXDataBrowserController, OnCanceledNotFound, FmFoundRecordInformation&, rInfo, void) +{ + Reference< css::sdbcx::XRowLocate > xCursor(getRowSet(), UNO_QUERY); + + try + { + OSL_ENSURE(xCursor.is(), "SbaXDataBrowserController::OnCanceledNotFound : xCursor is empty"); + // move the cursor + xCursor->moveToBookmark(rInfo.aPosition); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + try + { + // let the grid sync its display with the cursor + Reference< XPropertySet > xModelSet(getControlModel(), UNO_QUERY); + OSL_ENSURE(xModelSet.is(), "SbaXDataBrowserController::OnCanceledNotFound : no model set ?!"); + Any aOld = xModelSet->getPropertyValue("DisplayIsSynchron"); + xModelSet->setPropertyValue("DisplayIsSynchron", css::uno::Any(true)); + xModelSet->setPropertyValue("DisplayIsSynchron", aOld); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +IMPL_LINK_NOARG(SbaXDataBrowserController, OnAsyncGetCellFocus, void*, void) +{ + SbaGridControl* pVclGrid = getBrowserView() ? getBrowserView()->getVclControl() : nullptr; + // if we have a controller, but the window for the controller doesn't have the focus, we correct this + if (pVclGrid && pVclGrid->IsEditing() && pVclGrid->HasChildPathFocus()) + pVclGrid->Controller()->GetWindow().GrabFocus(); +} + +void SbaXDataBrowserController::criticalFail() +{ + InvalidateAll(); + m_nRowSetPrivileges = 0; +} + +void SbaXDataBrowserController::LoadFinished(bool /*bWasSynch*/) +{ + m_nRowSetPrivileges = 0; + + if (!isValid() || loadingCancelled()) + return; + + // obtain cached values + try + { + Reference< XPropertySet > xFormProps( m_xLoadable, UNO_QUERY_THROW ); + OSL_VERIFY( xFormProps->getPropertyValue( PROPERTY_PRIVILEGES ) >>= m_nRowSetPrivileges ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + // switch the control to alive mode + getBrowserView()->getGridControl()->setDesignMode(false); + + initializeParser(); + + InvalidateAll(); + + m_aAsyncGetCellFocus.Call(); +} + +void SbaXDataBrowserController::initializeParser() const +{ + if ( m_xParser.is() ) + return; + + // create a parser (needed for filtering/sorting) + try + { + const Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY); + if (::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ESCAPE_PROCESSING))) + { // (only if the statement isn't native) + // (it is allowed to use the PROPERTY_ISPASSTHROUGH : _after_ loading a form it is valid) + xFormSet->getPropertyValue(PROPERTY_SINGLESELECTQUERYCOMPOSER) >>= m_xParser; + } + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + m_xParser = nullptr; + // no further handling, we ignore the error + } +} + +void SbaXDataBrowserController::loaded(const EventObject& /*aEvent*/) +{ + // not interested in + // we're loading within a separated thread and have a handling for its "finished event" +} + +void SbaXDataBrowserController::unloading(const EventObject& /*aEvent*/) +{ + // not interested in +} + +void SbaXDataBrowserController::unloaded(const EventObject& /*aEvent*/) +{ + m_xParser.clear(); + InvalidateAll(); + // do this asynchronously, there are other listeners reacting on this message ... + // (it's a little hack : the grid columns are listening to this event, too, and their bound field may + // change as a reaction on that event. as we have no chance to be notified of this change (which is + // the one we're interested in) we give them time to do what they want to before invalidating our + // bound-field-dependent slots... +} + +void SbaXDataBrowserController::reloading(const EventObject& /*aEvent*/) +{ + // not interested in +} + +void SbaXDataBrowserController::reloaded(const EventObject& /*aEvent*/) +{ + InvalidateAll(); + // do this asynchronously, there are other listeners reacting on this message ... + // (it's a little hack : the grid columns are listening to this event, too, and their bound field may + // change as a reaction on that event. as we have no chance to be notified of this change (which is + // the one we're interested in) we give them time to do what they want to before invalidating our + // bound-field-dependent slots... +} + +void SbaXDataBrowserController::enterFormAction() +{ + if ( !m_nFormActionNestingLevel ) + // first action -> reset + m_aCurrentError.clear(); + + ++m_nFormActionNestingLevel; +} + +void SbaXDataBrowserController::leaveFormAction() +{ + OSL_ENSURE( m_nFormActionNestingLevel > 0, "SbaXDataBrowserController::leaveFormAction : invalid call !" ); + if ( --m_nFormActionNestingLevel > 0 ) + return; + + if ( !m_aCurrentError.isValid() ) + return; + + m_aAsyncDisplayError.Call(); +} + +bool SbaXDataBrowserController::isLoaded() const +{ + return m_xLoadable.is() && m_xLoadable->isLoaded(); +} + +bool SbaXDataBrowserController::isValidCursor() const +{ + if (!m_xColumnsSupplier.is()) + return false; + Reference< css::container::XNameAccess > xCols = m_xColumnsSupplier->getColumns(); + if (!xCols.is() || !xCols->hasElements()) + return false; + + bool bIsValid = !(m_xRowSet->isBeforeFirst() || m_xRowSet->isAfterLast()); + if ( !bIsValid ) + { + Reference<XPropertySet> xProp(m_xRowSet,UNO_QUERY); + bIsValid = ::cppu::any2bool(xProp->getPropertyValue(PROPERTY_ISNEW)); + if ( !bIsValid ) + { + bIsValid = m_xParser.is(); + } + } + return bIsValid; +} + +sal_Int16 SbaXDataBrowserController::getCurrentColumnPosition() const +{ + Reference< css::form::XGrid > xGrid(getBrowserView()->getGridControl(), UNO_QUERY); + sal_Int16 nViewPos = -1; + try + { + if ( xGrid.is() ) + nViewPos = xGrid->getCurrentColumnPosition(); + } + catch(Exception&) {} + return nViewPos; +} + +void SbaXDataBrowserController::setCurrentColumnPosition( sal_Int16 _nPos ) +{ + Reference< css::form::XGrid > xGrid(getBrowserView()->getGridControl(), UNO_QUERY); + try + { + if ( -1 != _nPos ) + xGrid->setCurrentColumnPosition(_nPos); + } + catch(Exception&) {} +} + +void SbaXDataBrowserController::BeforeDrop() +{ + Reference< css::sdb::XSQLErrorBroadcaster > xFormError(getRowSet(), UNO_QUERY); + if (xFormError.is()) + xFormError->removeSQLErrorListener(static_cast<css::sdb::XSQLErrorListener*>(this)); +} + +void SbaXDataBrowserController::AfterDrop() +{ + Reference< css::sdb::XSQLErrorBroadcaster > xFormError(getRowSet(), UNO_QUERY); + if (xFormError.is()) + xFormError->addSQLErrorListener(static_cast<css::sdb::XSQLErrorListener*>(this)); +} + +void SbaXDataBrowserController::addColumnListeners(const Reference< css::awt::XControlModel > & _xGridControlModel) +{ +// ... all the grid columns + Reference< css::container::XIndexContainer > xColumns(_xGridControlModel, UNO_QUERY); + if (xColumns.is()) + { + sal_Int32 nCount = xColumns->getCount(); + for (sal_Int32 i=0; i < nCount; ++i) + { + Reference< XPropertySet > xCol(xColumns->getByIndex(i),UNO_QUERY); + AddColumnListener(xCol); + } + } +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/brwview.cxx b/dbaccess/source/ui/browser/brwview.cxx new file mode 100644 index 000000000..b68819d67 --- /dev/null +++ b/dbaccess/source/ui/browser/brwview.cxx @@ -0,0 +1,333 @@ +/* -*- 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 <brwview.hxx> +#include <sbagrid.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <comphelper/types.hxx> +#include <vcl/split.hxx> +#include <strings.hxx> +#include <com/sun/star/form/XLoadable.hpp> +#include <com/sun/star/awt/XControlContainer.hpp> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <osl/diagnose.h> + +using namespace dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +namespace +{ + bool isGrabVclControlFocusAllowed(const UnoDataBrowserView* _pView) + { + bool bGrabFocus = false; + SbaGridControl* pVclControl = _pView->getVclControl(); + const Reference< css::awt::XControl >& xGrid = _pView->getGridControl(); + if (pVclControl && xGrid.is()) + { + bGrabFocus = true; + if(!pVclControl->HasChildPathFocus()) + { + Reference<XChild> xChild(xGrid->getModel(),UNO_QUERY); + Reference<XLoadable> xLoad; + if(xChild.is()) + xLoad.set(xChild->getParent(),UNO_QUERY); + bGrabFocus = xLoad.is() && xLoad->isLoaded(); + } + } + return bGrabFocus; + } +} + +// UnoDataBrowserView + +UnoDataBrowserView::UnoDataBrowserView( vcl::Window* pParent, + IController& _rController, + const Reference< css::uno::XComponentContext >& _rxContext) + :ODataView(pParent,_rController,_rxContext) + ,m_pTreeView(nullptr) + ,m_pSplitter(nullptr) + ,m_pVclControl(nullptr) +{ + +} + +void UnoDataBrowserView::Construct(const Reference< css::awt::XControlModel >& xModel) +{ + try + { + ODataView::Construct(); + + // our UNO representation + m_xMe = VCLUnoHelper::CreateControlContainer(this); + + // create the (UNO-) control + m_xGrid = new SbaXGridControl( getORB() ); + OSL_ENSURE(m_xGrid.is(), "UnoDataBrowserView::Construct : could not create a grid control !"); + // in design mode (for the moment) + m_xGrid->setDesignMode(true); + + Reference< css::awt::XWindow > xGridWindow(m_xGrid, UNO_QUERY); + xGridWindow->setVisible(true); + xGridWindow->setEnable(true); + + // introduce the model to the grid + m_xGrid->setModel(xModel); + // introduce the container (me) to the grid + Reference< css::beans::XPropertySet > xModelSet(xModel, UNO_QUERY); + getContainer()->addControl(::comphelper::getString(xModelSet->getPropertyValue(PROPERTY_NAME)), m_xGrid); + + // get the VCL-control + m_pVclControl = nullptr; + getVclControl(); + + OSL_ENSURE(m_pVclControl != nullptr, "UnoDataBrowserView::Construct : no real grid control !"); + } + catch(const Exception&) + { + ::comphelper::disposeComponent(m_xGrid); + throw; + } +} + +UnoDataBrowserView::~UnoDataBrowserView() +{ + disposeOnce(); +} + +void UnoDataBrowserView::dispose() +{ + m_pSplitter.disposeAndClear(); + setTreeView(nullptr); + + try + { + ::comphelper::disposeComponent(m_xGrid); + ::comphelper::disposeComponent(m_xMe); + } + catch(const Exception&) + {} + m_pTreeView.clear(); + m_pVclControl.clear(); + ODataView::dispose(); +} + +IMPL_LINK_NOARG( UnoDataBrowserView, SplitHdl, Splitter*, void ) +{ + tools::Long nYPos = m_pSplitter->GetPosPixel().Y(); + m_pSplitter->SetPosPixel( Point( m_pSplitter->GetSplitPosPixel(), nYPos ) ); + Resize(); +} + +void UnoDataBrowserView::setSplitter(Splitter* _pSplitter) +{ + m_pSplitter = _pSplitter; + m_pSplitter->SetSplitHdl( LINK( this, UnoDataBrowserView, SplitHdl ) ); + LINK( this, UnoDataBrowserView, SplitHdl ).Call(m_pSplitter); +} + +void UnoDataBrowserView::setTreeView(InterimDBTreeListBox* pTreeView) +{ + if (m_pTreeView.get() != pTreeView) + { + m_pTreeView.disposeAndClear(); + m_pTreeView = pTreeView; + } +} + +void UnoDataBrowserView::showStatus( const OUString& _rStatus ) +{ + if (_rStatus.isEmpty()) + hideStatus(); + else + { + if (!m_pTreeView) + return; + weld::Label& rLabel = m_pTreeView->GetStatusBar(); + rLabel.set_label(_rStatus); + rLabel.show(); + Resize(); + PaintImmediately(); + } +} + +void UnoDataBrowserView::hideStatus() +{ + if (!m_pTreeView) + return; + weld::Label& rLabel = m_pTreeView->GetStatusBar(); + if (!rLabel.get_visible()) + { + // nothing to do + return; + } + rLabel.hide(); + Resize(); + PaintImmediately(); +} + +void UnoDataBrowserView::resizeDocumentView(tools::Rectangle& _rPlayground) +{ + Point aSplitPos; + Size aSplitSize; + Point aPlaygroundPos( _rPlayground.TopLeft() ); + Size aPlaygroundSize( _rPlayground.GetSize() ); + + if (m_pTreeView && m_pTreeView->IsVisible() && m_pSplitter) + { + // calculate the splitter pos and size + aSplitPos = m_pSplitter->GetPosPixel(); + aSplitPos.setY( aPlaygroundPos.Y() ); + aSplitSize = m_pSplitter->GetOutputSizePixel(); + aSplitSize.setHeight( aPlaygroundSize.Height() ); + + if( ( aSplitPos.X() + aSplitSize.Width() ) > ( aPlaygroundSize.Width() )) + aSplitPos.setX( aPlaygroundSize.Width() - aSplitSize.Width() ); + + if( aSplitPos.X() <= aPlaygroundPos.X() ) + aSplitPos.setX( aPlaygroundPos.X() + sal_Int32(aPlaygroundSize.Width() * 0.2) ); + + // the tree pos and size + Point aTreeViewPos( aPlaygroundPos ); + Size aTreeViewSize( aSplitPos.X(), aPlaygroundSize.Height() ); + + // set the size of treelistbox + m_pTreeView->SetPosSizePixel( aTreeViewPos, aTreeViewSize ); + // Call this to trigger InterimItemWindow::Layout immediately, and + // not later on idle so the statusbar will be shown to explain + // a long delay on opening databases + m_pTreeView->Resize(); + + //set the size of the splitter + m_pSplitter->SetPosSizePixel( aSplitPos, Size( aSplitSize.Width(), aPlaygroundSize.Height() ) ); + m_pSplitter->SetDragRectPixel( _rPlayground ); + } + + // set the size of grid control + Reference< css::awt::XWindow > xGridAsWindow(m_xGrid, UNO_QUERY); + if (xGridAsWindow.is()) + xGridAsWindow->setPosSize( aSplitPos.X() + aSplitSize.Width(), aPlaygroundPos.Y(), + aPlaygroundSize.Width() - aSplitSize.Width() - aSplitPos.X(), aPlaygroundSize.Height(), css::awt::PosSize::POSSIZE); + + // just for completeness: there is no space left, we occupied it all ... + _rPlayground.SetPos( _rPlayground.BottomRight() ); + _rPlayground.SetSize( Size( 0, 0 ) ); +} + +sal_uInt16 UnoDataBrowserView::View2ModelPos(sal_uInt16 nPos) const +{ + return m_pVclControl ? m_pVclControl->GetModelColumnPos(m_pVclControl->GetColumnIdFromViewPos(nPos)) : -1; +} + +SbaGridControl* UnoDataBrowserView::getVclControl() const +{ + if ( !m_pVclControl ) + { + OSL_ENSURE(m_xGrid.is(),"Grid not set!"); + if ( m_xGrid.is() ) + { + Reference< css::awt::XWindowPeer > xPeer = m_xGrid->getPeer(); + if ( xPeer.is() ) + { + SbaXGridPeer* pPeer = comphelper::getFromUnoTunnel<SbaXGridPeer>(xPeer); + UnoDataBrowserView* pTHIS = const_cast<UnoDataBrowserView*>(this); + if ( pPeer ) + { + m_pVclControl = static_cast<SbaGridControl*>(pPeer->GetWindow()); + pTHIS->startComponentListening(VCLUnoHelper::GetInterface(m_pVclControl)); + } + } + } + } + return m_pVclControl; +} + +void UnoDataBrowserView::GetFocus() +{ + ODataView::GetFocus(); + if( m_pTreeView && m_pTreeView->IsVisible() && !m_pTreeView->HasChildPathFocus()) + m_pTreeView->GrabFocus(); + else if (m_pVclControl && m_xGrid.is()) + { + bool bGrabFocus = false; + if(!m_pVclControl->HasChildPathFocus()) + { + bGrabFocus = isGrabVclControlFocusAllowed(this); + if( bGrabFocus ) + m_pVclControl->GrabFocus(); + } + if(!bGrabFocus && m_pTreeView && m_pTreeView->IsVisible() ) + m_pTreeView->GrabFocus(); + } +} + +void UnoDataBrowserView::_disposing( const css::lang::EventObject& /*_rSource*/ ) +{ + stopComponentListening(VCLUnoHelper::GetInterface(m_pVclControl)); + m_pVclControl = nullptr; +} + +bool UnoDataBrowserView::PreNotify( NotifyEvent& rNEvt ) +{ + bool bDone = false; + if(rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) + { + bool bGrabAllowed = isGrabVclControlFocusAllowed(this); + if ( bGrabAllowed ) + { + const KeyEvent* pKeyEvt = rNEvt.GetKeyEvent(); + const vcl::KeyCode& rKeyCode = pKeyEvt->GetKeyCode(); + if ( ( rKeyCode == vcl::KeyCode( KEY_E, true, true, false, false ) ) + || ( rKeyCode == vcl::KeyCode( KEY_TAB, true, false, false, false ) ) + ) + { + if ( m_pTreeView && m_pVclControl && m_pTreeView->HasChildPathFocus() ) + m_pVclControl->GrabFocus(); + else if ( m_pTreeView && m_pVclControl && m_pVclControl->HasChildPathFocus() ) + m_pTreeView->GrabFocus(); + + bDone = true; + } + } + } + return bDone || ODataView::PreNotify(rNEvt); +} + +BrowserViewStatusDisplay::BrowserViewStatusDisplay( UnoDataBrowserView* _pView, const OUString& _rStatus ) + :m_pView(_pView) +{ + + if (m_pView) + m_pView->showStatus(_rStatus); +} + +BrowserViewStatusDisplay::~BrowserViewStatusDisplay( ) +{ + if (m_pView) + m_pView->showStatus(OUString()); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dataview.cxx b/dbaccess/source/ui/browser/dataview.cxx new file mode 100644 index 000000000..74ceea688 --- /dev/null +++ b/dbaccess/source/ui/browser/dataview.cxx @@ -0,0 +1,154 @@ +/* -*- 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 <com/sun/star/frame/XController.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <dbaccess/dataview.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <dbaccess/IController.hxx> +#include <svtools/acceleratorexecute.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/event.hxx> +#include <vcl/settings.hxx> + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::frame; + + ODataView::ODataView( vcl::Window* pParent, + IController& _rController, + const Reference< XComponentContext >& _rxContext, + WinBits nStyle) + :Window(pParent,nStyle) + ,m_xContext(_rxContext) + ,m_xController( &_rController ) + { + m_pAccel = ::svt::AcceleratorExecute::createAcceleratorHelper(); + } + + void ODataView::Construct() + { + } + + ODataView::~ODataView() + { + disposeOnce(); + } + + void ODataView::dispose() + { + m_xController.clear(); + m_pAccel.reset(); + vcl::Window::dispose(); + } + + void ODataView::resizeDocumentView(tools::Rectangle& /*_rPlayground*/) + { + } + + void ODataView::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& _rRect) + { + // draw the background + { + rRenderContext.Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR); + rRenderContext.SetLineColor(COL_TRANSPARENT); + rRenderContext.SetFillColor(GetSettings().GetStyleSettings().GetFaceColor()); + rRenderContext.DrawRect(_rRect); + rRenderContext.Pop(); + } + + // let the base class do anything it needs + Window::Paint(rRenderContext, _rRect); + } + + void ODataView::resizeAll(const tools::Rectangle& rPlayground) + { + // position the controls of the document's view + tools::Rectangle aPlayground(rPlayground); + resizeDocumentView(aPlayground); + } + + void ODataView::Resize() + { + Window::Resize(); + resizeAll( tools::Rectangle( Point( 0, 0), GetSizePixel() ) ); + } + bool ODataView::PreNotify( NotifyEvent& _rNEvt ) + { + bool bHandled = false; + switch ( _rNEvt.GetType() ) + { + case MouseNotifyEvent::KEYINPUT: + { + const KeyEvent* pKeyEvent = _rNEvt.GetKeyEvent(); + const vcl::KeyCode& aKeyCode = pKeyEvent->GetKeyCode(); + if ( m_pAccel && m_pAccel->execute( aKeyCode ) ) + // the accelerator consumed the event + return true; + [[fallthrough]]; + } + case MouseNotifyEvent::KEYUP: + case MouseNotifyEvent::MOUSEBUTTONDOWN: + case MouseNotifyEvent::MOUSEBUTTONUP: + bHandled = m_xController->interceptUserInput( _rNEvt ); + break; + default: + break; + } + return bHandled || Window::PreNotify( _rNEvt ); + } + void ODataView::StateChanged( StateChangedType nType ) + { + Window::StateChanged( nType ); + + if ( nType != StateChangedType::InitShow ) + return; + + // now that there's a view which is finally visible, remove the "Hidden" value from the + // model's arguments. + try + { + Reference< XController > xController( m_xController->getXController(), UNO_SET_THROW ); + Reference< XModel > xModel = xController->getModel(); + if ( xModel.is() ) + { + ::comphelper::NamedValueCollection aArgs( xModel->getArgs() ); + aArgs.remove( "Hidden" ); + xModel->attachResource( xModel->getURL(), aArgs.getPropertyValues() ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void ODataView::attachFrame(const Reference< XFrame >& _xFrame) + { + m_pAccel->init(m_xContext, _xFrame); + } +} + +// namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dbexchange.cxx b/dbaccess/source/ui/browser/dbexchange.cxx new file mode 100644 index 000000000..dc6398f48 --- /dev/null +++ b/dbaccess/source/ui/browser/dbexchange.cxx @@ -0,0 +1,251 @@ +/* -*- 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 <dbexchange.hxx> +#include <sot/formats.hxx> +#include <sot/storage.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/XResultSetAccess.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <TokenWriter.hxx> +#include <svx/dataaccessdescriptor.hxx> +#include <UITools.hxx> + +namespace dbaui +{ + constexpr sal_uInt32 FORMAT_OBJECT_ID_RTF = 1; + constexpr sal_uInt32 FORMAT_OBJECT_ID_HTML = 2; + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::datatransfer; + using namespace ::svx; + + namespace + { + template<class T > void lcl_setListener(const Reference<T>& _xComponent, const Reference< XEventListener >& i_rListener, const bool i_bAdd ) + { + if ( !_xComponent.is() ) + return; + + Reference< XComponent> xCom( _xComponent, UNO_QUERY ); + OSL_ENSURE( xCom.is(), "lcl_setListener: no component!" ); + if ( !xCom.is() ) + return; + + i_bAdd ? xCom->addEventListener( i_rListener ) : xCom->removeEventListener( i_rListener ); + } + } + + ODataClipboard::ODataClipboard() + { + } + + void ODataClipboard::Update( + const OUString& rDatasource, + const sal_Int32 nCommandType, + const OUString& rCommand, + const Reference< XConnection >& rxConnection, + const Reference< XNumberFormatter >& rxFormatter, + const Reference< XComponentContext >& rxORB) + { + ClearFormats(); + + ODataAccessObjectTransferable::Update(rDatasource, nCommandType, rCommand, rxConnection); + + lcl_setListener(rxConnection, this, true); + + m_pHtml.set(new OHTMLImportExport(getDescriptor(), rxORB, rxFormatter)); + m_pRtf.set(new ORTFImportExport(getDescriptor(), rxORB, rxFormatter)); + + AddSupportedFormats(); + } + + void ODataClipboard::Update( + const OUString& rDatasource, + const sal_Int32 nCommandType, + const OUString& rCommand, + const Reference< XNumberFormatter >& rxFormatter, + const Reference< XComponentContext >& rxORB) + { + ClearFormats(); + + ODataAccessObjectTransferable::Update(rDatasource, nCommandType, rCommand); + + m_pHtml.set(new OHTMLImportExport(getDescriptor(), rxORB, rxFormatter)); + m_pRtf.set(new ORTFImportExport(getDescriptor(), rxORB, rxFormatter)); + + AddSupportedFormats(); + } + + ODataClipboard::ODataClipboard( const Reference< XPropertySet >& i_rAliveForm, + const Sequence< Any >& i_rSelectedRows, + const bool i_bBookmarkSelection, + const Reference< XComponentContext >& i_rORB ) + :ODataAccessObjectTransferable( i_rAliveForm ) + { + OSL_PRECOND( i_rORB.is(), "ODataClipboard::ODataClipboard: having no factory is not good ..." ); + + osl_atomic_increment( &m_refCount ); + + Reference<XConnection> xConnection; + getDescriptor()[ DataAccessDescriptorProperty::Connection ] >>= xConnection; + lcl_setListener( xConnection, this, true ); + + // do not pass the form itself as source result set, since the client might operate on the form, which + // might lead to undesired effects. Instead, use a clone. + Reference< XResultSet > xResultSetClone; + Reference< XResultSetAccess > xResultSetAccess( i_rAliveForm, UNO_QUERY ); + if ( xResultSetAccess.is() ) + xResultSetClone = xResultSetAccess->createResultSet(); + OSL_ENSURE( xResultSetClone.is(), "ODataClipboard::ODataClipboard: could not clone the form's result set" ); + lcl_setListener( xResultSetClone, this, true ); + + getDescriptor()[DataAccessDescriptorProperty::Cursor] <<= xResultSetClone; + getDescriptor()[DataAccessDescriptorProperty::Selection] <<= i_rSelectedRows; + getDescriptor()[DataAccessDescriptorProperty::BookmarkSelection]<<= i_bBookmarkSelection; + addCompatibleSelectionDescription( i_rSelectedRows ); + + if ( xConnection.is() && i_rORB.is() ) + { + Reference< XNumberFormatter > xFormatter( getNumberFormatter( xConnection, i_rORB ) ); + if ( xFormatter.is() ) + { + m_pHtml.set( new OHTMLImportExport( getDescriptor(), i_rORB, xFormatter ) ); + m_pRtf.set( new ORTFImportExport( getDescriptor(), i_rORB, xFormatter ) ); + } + } + + osl_atomic_decrement( &m_refCount ); + } + + bool ODataClipboard::WriteObject( ::tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor& /*rFlavor*/ ) + { + if (nUserObjectId == FORMAT_OBJECT_ID_RTF || nUserObjectId == FORMAT_OBJECT_ID_HTML ) + { + ODatabaseImportExport* pExport = static_cast<ODatabaseImportExport*>(pUserObject); + if ( pExport && rxOStm.is() ) + { + pExport->setStream(rxOStm.get()); + return pExport->Write(); + } + } + return false; + } + + void ODataClipboard::AddSupportedFormats() + { + if ( m_pRtf.is() ) + AddFormat( SotClipboardFormatId::RTF ); + + if ( m_pHtml.is() ) + AddFormat( SotClipboardFormatId::HTML ); + + ODataAccessObjectTransferable::AddSupportedFormats(); + } + + bool ODataClipboard::GetData( const DataFlavor& rFlavor, const OUString& rDestDoc ) + { + const SotClipboardFormatId nFormat = SotExchange::GetFormat(rFlavor); + switch (nFormat) + { + case SotClipboardFormatId::RTF: + if ( m_pRtf.is() ) + m_pRtf->initialize(getDescriptor()); + return m_pRtf.is() && SetObject( m_pRtf.get(), FORMAT_OBJECT_ID_RTF, rFlavor ); + + case SotClipboardFormatId::HTML: + if ( m_pHtml.is() ) + m_pHtml->initialize(getDescriptor()); + return m_pHtml.is() && SetObject( m_pHtml.get(), FORMAT_OBJECT_ID_HTML, rFlavor ); + + default: break; + } + + return ODataAccessObjectTransferable::GetData(rFlavor, rDestDoc); + } + + void ODataClipboard::ObjectReleased() + { + if ( m_pHtml.is() ) + { + m_pHtml->dispose(); + m_pHtml.clear(); + } + + if ( m_pRtf.is() ) + { + m_pRtf->dispose(); + m_pRtf.clear(); + } + + if ( getDescriptor().has( DataAccessDescriptorProperty::Connection ) ) + { + Reference<XConnection> xConnection( getDescriptor()[DataAccessDescriptorProperty::Connection], UNO_QUERY ); + lcl_setListener( xConnection, this, false ); + } + + if ( getDescriptor().has( DataAccessDescriptorProperty::Cursor ) ) + { + Reference< XResultSet > xResultSet( getDescriptor()[ DataAccessDescriptorProperty::Cursor ], UNO_QUERY ); + lcl_setListener( xResultSet, this, false ); + } + + ODataAccessObjectTransferable::ObjectReleased( ); + } + + void SAL_CALL ODataClipboard::disposing( const css::lang::EventObject& i_rSource ) + { + ODataAccessDescriptor& rDescriptor( getDescriptor() ); + + if ( rDescriptor.has( DataAccessDescriptorProperty::Connection ) ) + { + Reference< XConnection > xConnection( rDescriptor[DataAccessDescriptorProperty::Connection], UNO_QUERY ); + if ( xConnection == i_rSource.Source ) + { + rDescriptor.erase( DataAccessDescriptorProperty::Connection ); + } + } + + if ( rDescriptor.has( DataAccessDescriptorProperty::Cursor ) ) + { + Reference< XResultSet > xResultSet( rDescriptor[ DataAccessDescriptorProperty::Cursor ], UNO_QUERY ); + if ( xResultSet == i_rSource.Source ) + { + rDescriptor.erase( DataAccessDescriptorProperty::Cursor ); + // Selection and BookmarkSelection are meaningless without a result set + if ( rDescriptor.has( DataAccessDescriptorProperty::Selection ) ) + rDescriptor.erase( DataAccessDescriptorProperty::Selection ); + if ( rDescriptor.has( DataAccessDescriptorProperty::BookmarkSelection ) ) + rDescriptor.erase( DataAccessDescriptorProperty::BookmarkSelection ); + } + } + + // no matter whether it was the source connection or the source result set which died, + // we cannot provide the data anymore. + ClearFormats(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dbloader.cxx b/dbaccess/source/ui/browser/dbloader.cxx new file mode 100644 index 000000000..330d23a12 --- /dev/null +++ b/dbaccess/source/ui/browser/dbloader.cxx @@ -0,0 +1,269 @@ +/* -*- 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 <strings.hxx> +#include <UITools.hxx> + +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/frame/XController2.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/XFrameLoader.hpp> +#include <com/sun/star/frame/XLoadEventListener.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdb/ReportDesign.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/frame/XModule.hpp> + +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <tools/diagnose_ex.h> +#include <tools/urlobj.hxx> +#include <vcl/svapp.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace dbaui; + +namespace { + +class DBContentLoader : public ::cppu::WeakImplHelper< XFrameLoader, XServiceInfo> +{ +private: + Sequence< PropertyValue> m_aArgs; + Reference< XLoadEventListener > m_xListener; + Reference< XComponentContext > m_xContext; +public: + explicit DBContentLoader(const Reference< XComponentContext >&); + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XLoader + virtual void SAL_CALL load( const Reference< XFrame > & _rFrame, const OUString& _rURL, + const Sequence< PropertyValue >& _rArgs, + const Reference< XLoadEventListener > & _rListener) override; + virtual void SAL_CALL cancel() override; +}; + +} + +DBContentLoader::DBContentLoader(const Reference< XComponentContext >& _rxContext) + :m_xContext(_rxContext) +{ + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_DBContentLoader_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new DBContentLoader(context)); +} + +// XServiceInfo +OUString SAL_CALL DBContentLoader::getImplementationName() +{ + return "org.openoffice.comp.dbu.DBContentLoader"; +} + +// XServiceInfo +sal_Bool SAL_CALL DBContentLoader::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > SAL_CALL DBContentLoader::getSupportedServiceNames() +{ + return { "com.sun.star.frame.FrameLoader", "com.sun.star.sdb.ContentLoader" }; +} + +void SAL_CALL DBContentLoader::load(const Reference< XFrame > & rFrame, const OUString& rURL, + const Sequence< PropertyValue >& rArgs, + const Reference< XLoadEventListener > & rListener) +{ + m_xListener = rListener; + m_aArgs = rArgs; + + static constexpr struct ServiceNameToImplName + { + rtl::OUStringConstExpr sServiceName; + const char* pAsciiImplementationName; + } aImplementations[] = { + { URL_COMPONENT_FORMGRIDVIEW, "org.openoffice.comp.dbu.OFormGridView" }, + { URL_COMPONENT_DATASOURCEBROWSER, "org.openoffice.comp.dbu.ODatasourceBrowser" }, + { URL_COMPONENT_QUERYDESIGN, "org.openoffice.comp.dbu.OQueryDesign" }, + { URL_COMPONENT_TABLEDESIGN, "org.openoffice.comp.dbu.OTableDesign" }, + { URL_COMPONENT_RELATIONDESIGN, "org.openoffice.comp.dbu.ORelationDesign" }, + { URL_COMPONENT_VIEWDESIGN, "org.openoffice.comp.dbu.OViewDesign" } + }; + + INetURLObject aParser( rURL ); + Reference< XController2 > xController; + + const OUString sComponentURL( aParser.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ) ); + for (const ServiceNameToImplName& aImplementation : aImplementations) + { + if ( sComponentURL == aImplementation.sServiceName ) + { + xController.set( m_xContext->getServiceManager()-> + createInstanceWithContext( OUString::createFromAscii( aImplementation.pAsciiImplementationName ), m_xContext), UNO_QUERY_THROW ); + break; + } + } + + // if a data source browser is loaded without its tree pane, then we assume it to be a + // table data view, effectively. In this case, we need to adjust the module identifier. + // #i85879# + ::comphelper::NamedValueCollection aLoadArgs( rArgs ); + + if ( sComponentURL == URL_COMPONENT_DATASOURCEBROWSER ) + { + bool bDisableBrowser = !aLoadArgs.getOrDefault( "ShowTreeViewButton", true ) // compatibility name + || !aLoadArgs.getOrDefault( PROPERTY_ENABLE_BROWSER, true ); + + if ( bDisableBrowser ) + { + try + { + Reference< XModule > xModule( xController, UNO_QUERY_THROW ); + xModule->setIdentifier( "com.sun.star.sdb.TableDataView" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + + if ( sComponentURL == URL_COMPONENT_REPORTDESIGN ) + { + bool bPreview = aLoadArgs.getOrDefault( "Preview", false ); + if ( bPreview ) + { // report designs cannot be previewed + if ( rListener.is() ) + rListener->loadCancelled( this ); + return; + } + Reference< XModel > xReportModel( aLoadArgs.getOrDefault( "Model", Reference< XModel >() ) ); + if ( xReportModel.is() ) + { + xController.set( ReportDesign::create( m_xContext ) ); + xController->attachModel( xReportModel ); + xReportModel->connectController( xController ); + xReportModel->setCurrentController( xController ); + } + } + + bool bSuccess = xController.is(); + Reference< XModel > xDatabaseDocument; + if ( bSuccess ) + { + Reference< XDataSource > xDataSource ( aLoadArgs.getOrDefault( "DataSource", Reference< XDataSource >() ) ); + OUString sDataSourceName( aLoadArgs.getOrDefault( "DataSourceName", OUString() ) ); + Reference< XConnection > xConnection ( aLoadArgs.getOrDefault( "ActiveConnection", Reference< XConnection >() ) ); + if ( xDataSource.is() ) + { + xDatabaseDocument.set( getDataSourceOrModel( xDataSource ), UNO_QUERY ); + } + else if ( !sDataSourceName.isEmpty() ) + { + ::dbtools::SQLExceptionInfo aError; + xDataSource.set( getDataSourceByName( sDataSourceName, nullptr, m_xContext, &aError ) ); + xDatabaseDocument.set( getDataSourceOrModel( xDataSource ), UNO_QUERY ); + } + else if ( xConnection.is() ) + { + Reference< XChild > xAsChild( xConnection, UNO_QUERY ); + if ( xAsChild.is() ) + { + OSL_ENSURE( Reference< XDataSource >( xAsChild->getParent(), UNO_QUERY ).is(), + "DBContentLoader::load: a connection whose parent is no data source?" ); + xDatabaseDocument.set( getDataSourceOrModel( xAsChild->getParent() ), UNO_QUERY ); + } + } + + // init controller + SolarMutexGuard aGuard; + try + { + Reference<XInitialization > xIni(xController,UNO_QUERY); + PropertyValue aFrame("Frame",0,Any(rFrame),PropertyState_DIRECT_VALUE); + Sequence< Any > aInitArgs(m_aArgs.getLength()+1); + + Any* pBegin = aInitArgs.getArray(); + Any* pEnd = pBegin + aInitArgs.getLength(); + *pBegin <<= aFrame; + const PropertyValue* pIter = m_aArgs.getConstArray(); + for(++pBegin;pBegin != pEnd;++pBegin,++pIter) + { + *pBegin <<= *pIter; + } + + xIni->initialize(aInitArgs); + } + catch(const Exception&) + { + // Does this need to be shown to the user? + bSuccess = false; + try + { + ::comphelper::disposeComponent( xController ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + + // assign controller and frame + if ( bSuccess ) + { + if ( xController.is() && rFrame.is() ) + { + rFrame->setComponent( xController->getComponentWindow(), xController ); + xController->attachFrame(rFrame); + } + + if ( rListener.is() ) + rListener->loadFinished( this ); + } + else + if ( rListener.is() ) + rListener->loadCancelled( this ); +} + +void DBContentLoader::cancel() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dbtreemodel.cxx b/dbaccess/source/ui/browser/dbtreemodel.cxx new file mode 100644 index 000000000..88a9faeb0 --- /dev/null +++ b/dbaccess/source/ui/browser/dbtreemodel.cxx @@ -0,0 +1,33 @@ +/* -*- 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 "dbtreemodel.hxx" + +namespace dbaui +{ + DBTreeListUserData::DBTreeListUserData() + :eType(SbaTableQueryBrowser::etQuery) + { + } + DBTreeListUserData::~DBTreeListUserData() + { + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dbtreemodel.hxx b/dbaccess/source/ui/browser/dbtreemodel.hxx new file mode 100644 index 000000000..2ea11b900 --- /dev/null +++ b/dbaccess/source/ui/browser/dbtreemodel.hxx @@ -0,0 +1,57 @@ +/* -*- 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 <unodatbr.hxx> +#include <commontypes.hxx> + +// syntax of the tree userdata +// datasource holds the connection +// queries holds the nameaccess for the queries +// query holds the query +// tables holds the nameaccess for the tables +// table holds the table + +#define CONTAINER_QUERIES sal_uLong( 0 ) +#define CONTAINER_TABLES sal_uLong( 1 ) + +namespace com::sun::star::lang { class XMultiServiceFactory; } + +namespace dbaui +{ + struct DBTreeListUserData + { + /// if the entry denotes a table or query, this is the respective UNO object + css::uno::Reference< css::beans::XPropertySet > + xObjectProperties; + /// if the entry denotes an object container, this is the UNO interface for this container + css::uno::Reference< css::uno::XInterface > + xContainer; + /// if the entry denotes a data source, this is the connection for this data source (if already connection) + SharedConnection xConnection; + SbaTableQueryBrowser::EntryType eType; + OUString sAccessor; + + DBTreeListUserData(); + ~DBTreeListUserData(); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dsEntriesNoExp.cxx b/dbaccess/source/ui/browser/dsEntriesNoExp.cxx new file mode 100644 index 000000000..b31261df1 --- /dev/null +++ b/dbaccess/source/ui/browser/dsEntriesNoExp.cxx @@ -0,0 +1,154 @@ +/* -*- 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 <memory> + +#include <unodatbr.hxx> +#include <browserids.hxx> +#include <osl/diagnose.h> +#include <dbtreelistbox.hxx> +#include "dbtreemodel.hxx" + +using namespace ::com::sun::star::frame; +using namespace ::dbtools; +using namespace ::svx; + +namespace dbaui +{ +SbaTableQueryBrowser::EntryType SbaTableQueryBrowser::getChildType(const weld::TreeIter& rEntry) const +{ + OSL_ENSURE(isContainer(rEntry), "SbaTableQueryBrowser::getChildType: invalid entry!"); + switch (getEntryType(rEntry)) + { + case etTableContainer: + return etTableOrView; + case etQueryContainer: + return etQuery; + default: + break; + } + return etUnknown; +} + +OUString SbaTableQueryBrowser::GetEntryText(const weld::TreeIter& rEntry) const +{ + return m_pTreeView->GetWidget().get_text(rEntry); +} + +SbaTableQueryBrowser::EntryType SbaTableQueryBrowser::getEntryType(const weld::TreeIter& rEntry) const +{ + const weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rEntry)); + return pEntryData ? pEntryData->eType : etUnknown; +} + +void SbaTableQueryBrowser::select(const weld::TreeIter* pEntry, bool bSelect) +{ + if (pEntry) + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + rTreeView.set_text_emphasis(*pEntry, bSelect, 0); + } + else + { + OSL_FAIL("SbaTableQueryBrowser::select: invalid entry!"); + } +} + +void SbaTableQueryBrowser::selectPath(const weld::TreeIter* pEntry, bool bSelect) +{ + if (!pEntry) + return; + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator(pEntry)); + do + { + select(xEntry.get(), bSelect); + } + while (rTreeView.iter_parent(*xEntry)); +} + +bool SbaTableQueryBrowser::isSelected(const weld::TreeIter& rEntry) const +{ + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + return rTreeView.get_text_emphasis(rEntry, 0); +} + +void SbaTableQueryBrowser::SelectionChanged() +{ + if ( !m_bShowMenu ) + { + InvalidateFeature(ID_BROWSER_INSERTCOLUMNS); + InvalidateFeature(ID_BROWSER_INSERTCONTENT); + InvalidateFeature(ID_BROWSER_FORMLETTER); + } + InvalidateFeature(ID_BROWSER_COPY); + InvalidateFeature(ID_BROWSER_CUT); +} + +void SbaTableQueryBrowser::describeSupportedFeatures() +{ + SbaXDataBrowserController::describeSupportedFeatures(); + + implDescribeSupportedFeature( ".uno:Title", ID_BROWSER_TITLE ); + if ( !m_bShowMenu ) + { + implDescribeSupportedFeature( ".uno:DSBEditDB", ID_TREE_EDIT_DATABASE ); + implDescribeSupportedFeature( ".uno:DSBCloseConnection", ID_TREE_CLOSE_CONN ); + implDescribeSupportedFeature( ".uno:DSBAdministrate", ID_TREE_ADMINISTRATE ); + + implDescribeSupportedFeature( ".uno:DSBrowserExplorer", ID_BROWSER_EXPLORER, CommandGroup::VIEW ); + + implDescribeSupportedFeature( ".uno:DSBFormLetter", ID_BROWSER_FORMLETTER, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:DSBInsertColumns", ID_BROWSER_INSERTCOLUMNS, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DSBInsertContent", ID_BROWSER_INSERTCONTENT, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DSBDocumentDataSource", ID_BROWSER_DOCUMENT_DATASOURCE, CommandGroup::VIEW ); + + implDescribeSupportedFeature( ".uno:DataSourceBrowser/FormLetter", ID_BROWSER_FORMLETTER ); + implDescribeSupportedFeature( ".uno:DataSourceBrowser/InsertColumns", ID_BROWSER_INSERTCOLUMNS ); + implDescribeSupportedFeature( ".uno:DataSourceBrowser/InsertContent", ID_BROWSER_INSERTCONTENT ); + implDescribeSupportedFeature( ".uno:DataSourceBrowser/DocumentDataSource", ID_BROWSER_DOCUMENT_DATASOURCE ); + } + + implDescribeSupportedFeature( ".uno:CloseWin", ID_BROWSER_CLOSE, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:DBRebuildData", ID_BROWSER_REFRESH_REBUILD, CommandGroup::DATA ); +} + +sal_Int32 SbaTableQueryBrowser::getDatabaseObjectType( EntryType _eType ) +{ + switch ( _eType ) + { + case etQuery: + case etQueryContainer: + return css::sdb::application::DatabaseObject::QUERY; + case etTableOrView: + case etTableContainer: + return css::sdb::application::DatabaseObject::TABLE; + default: + break; + } + OSL_FAIL( "SbaTableQueryBrowser::getDatabaseObjectType: folder types and 'Unknown' not allowed here!" ); + return css::sdb::application::DatabaseObject::TABLE; +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dsbrowserDnD.cxx b/dbaccess/source/ui/browser/dsbrowserDnD.cxx new file mode 100644 index 000000000..961fd731a --- /dev/null +++ b/dbaccess/source/ui/browser/dsbrowserDnD.cxx @@ -0,0 +1,258 @@ +/* -*- 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 <dbexchange.hxx> +#include <dbtreelistbox.hxx> +#include "dbtreemodel.hxx" +#include <UITools.hxx> +#include <unodatbr.hxx> + +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <svx/dataaccessdescriptor.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <vcl/svapp.hxx> + +#include <algorithm> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + 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::util; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::io; + using namespace ::com::sun::star::i18n; + using namespace ::com::sun::star::task; + using namespace ::com::sun::star::datatransfer; + using namespace ::dbtools; + using namespace ::svx; + + bool SbaTableQueryBrowser::implCopyObject(ODataClipboard& rExchange, const weld::TreeIter& rApplyTo, sal_Int32 nCommandType) + { + try + { + OUString aName = GetEntryText(rApplyTo); + std::unique_ptr<weld::TreeIter> xRootEntry(m_pTreeView->GetRootLevelParent(&rApplyTo)); + OUString aDSName = getDataSourceAccessor(*xRootEntry); + + SharedConnection xConnection; + if ( CommandType::QUERY != nCommandType ) + { + if (!ensureConnection(&rApplyTo, xConnection)) + return false; + rExchange.Update(aDSName, nCommandType, aName, xConnection, getNumberFormatter(), getORB()); + } + else + rExchange.Update(aDSName, nCommandType, aName, getNumberFormatter(), getORB()); + + // the ownership goes to ODataClipboards + return true; + } + catch(const SQLException& ) + { + showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return false; + } + + sal_Int8 SbaTableQueryBrowser::queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors ) + { + // check if we're a table or query container + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xHitEntry(rTreeView.make_iterator()); + // get_dest_row_at_pos with false cause no drop if no entry was hit exactly + if (rTreeView.get_dest_row_at_pos(_rEvt.maPosPixel, xHitEntry.get(), false)) + { + // it must be a container + EntryType eEntryType = getEntryType(*xHitEntry); + SharedConnection xConnection; + if ( eEntryType == etTableContainer && ensureConnection(xHitEntry.get(), xConnection ) && xConnection.is()) + { + Reference<XChild> xChild(xConnection,UNO_QUERY); + Reference<XStorable> xStore; + if ( xChild.is() ) + xStore.set( getDataSourceOrModel(xChild->getParent()), UNO_QUERY ); + // check for the concrete type + if ( xStore.is() && !xStore->isReadonly() && std::any_of(_rFlavors.begin(),_rFlavors.end(),TAppSupportedSotFunctor(E_TABLE)) ) + return DND_ACTION_COPY; + } + } + + return DND_ACTION_NONE; + } + sal_Int8 SbaTableQueryBrowser::executeDrop( const ExecuteDropEvent& _rEvt ) + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xHitEntry(rTreeView.make_iterator()); + // get_dest_row_at_pos with false cause no drop if no entry was hit exactly + if (!rTreeView.get_dest_row_at_pos(_rEvt.maPosPixel, xHitEntry.get(), false)) + return DND_ACTION_NONE; + EntryType eEntryType = getEntryType(*xHitEntry); + if (!isContainer(eEntryType)) + { + OSL_FAIL("SbaTableQueryBrowser::executeDrop: what the hell did queryDrop do?"); + // queryDrop should not have allowed us to reach this situation... + return DND_ACTION_NONE; + } + // a TransferableDataHelper for accessing the dropped data + TransferableDataHelper aDroppedData(_rEvt.maDropEvent.Transferable); + + // reset the data of the previous async drop (if any) + if ( m_nAsyncDrop ) + Application::RemoveUserEvent(m_nAsyncDrop); + + m_nAsyncDrop = nullptr; + m_aAsyncDrop.aDroppedData.clear(); + m_aAsyncDrop.nType = E_TABLE; + m_aAsyncDrop.nAction = _rEvt.mnAction; + m_aAsyncDrop.bError = false; + m_aAsyncDrop.bHtml = false; + m_aAsyncDrop.xDroppedAt.reset(); + m_aAsyncDrop.aUrl.clear(); + + // loop through the available formats and see what we can do ... + // first we have to check if it is our own format, if not we have to copy the stream :-( + if ( ODataAccessObjectTransferable::canExtractObjectDescriptor(aDroppedData.GetDataFlavorExVector()) ) + { + m_aAsyncDrop.aDroppedData = ODataAccessObjectTransferable::extractObjectDescriptor(aDroppedData); + m_aAsyncDrop.xDroppedAt = std::move(xHitEntry); + + // asynchron because we some dialogs and we aren't allowed to show them while in D&D + m_nAsyncDrop = Application::PostUserEvent(LINK(this, SbaTableQueryBrowser, OnAsyncDrop)); + return DND_ACTION_COPY; + } + else + { + SharedConnection xDestConnection; + if ( ensureConnection( xHitEntry.get(), xDestConnection ) + && xDestConnection.is() + && m_aTableCopyHelper.copyTagTable( aDroppedData, m_aAsyncDrop, xDestConnection ) + ) + { + m_aAsyncDrop.xDroppedAt = std::move(xHitEntry); + + // asynchron because we some dialogs and we aren't allowed to show them while in D&D + m_nAsyncDrop = Application::PostUserEvent(LINK(this, SbaTableQueryBrowser, OnAsyncDrop)); + return DND_ACTION_COPY; + } + } + + return DND_ACTION_NONE; + } + + bool SbaTableQueryBrowser::requestDrag(const weld::TreeIter& rEntry) + { + // it must be a query/table + EntryType eEntryType = getEntryType(rEntry); + if (!isObject(eEntryType)) + return false; + + ODataClipboard& rExchange = static_cast<ODataClipboard&>(m_pTreeView->GetDataTransfer()); + return implCopyObject(rExchange, rEntry, (etTableOrView == eEntryType) ? CommandType::TABLE : CommandType::QUERY); + } + + IMPL_LINK_NOARG(SbaTableQueryBrowser, OnCopyEntry, LinkParamNone*, void) + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xSelected = rTreeView.make_iterator(); + if (rTreeView.get_selected(xSelected.get()) && isEntryCopyAllowed(*xSelected)) + copyEntry(*xSelected); + } + + bool SbaTableQueryBrowser::isEntryCopyAllowed(const weld::TreeIter& rEntry) const + { + EntryType eType = getEntryType(rEntry); + return ( eType == etTableOrView || eType == etQuery ); + } + + void SbaTableQueryBrowser::copyEntry(const weld::TreeIter& rEntry) + { + EntryType eType = getEntryType(rEntry); + rtl::Reference<ODataClipboard> xTransfer(new ODataClipboard); + if (implCopyObject(*xTransfer, rEntry, eType == etQuery ? CommandType::QUERY : CommandType::TABLE)) + xTransfer->CopyToClipboard(getView()); + } + + IMPL_LINK_NOARG( SbaTableQueryBrowser, OnAsyncDrop, void*, void ) + { + m_nAsyncDrop = nullptr; + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + if ( m_aAsyncDrop.nType == E_TABLE ) + { + SharedConnection xDestConnection; + if ( ensureConnection(m_aAsyncDrop.xDroppedAt.get(), xDestConnection) && xDestConnection.is()) + { + std::unique_ptr<weld::TreeIter> xDataSourceEntry = + m_pTreeView->GetRootLevelParent(m_aAsyncDrop.xDroppedAt.get()); + m_aTableCopyHelper.asyncCopyTagTable(m_aAsyncDrop, getDataSourceAccessor(*xDataSourceEntry), xDestConnection); + } + } + + m_aAsyncDrop.aDroppedData.clear(); + } + + void SbaTableQueryBrowser::clearTreeModel() + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + rTreeView.all_foreach([this, &rTreeView](weld::TreeIter& rEntryLoop){ + // clear the user data of the tree model + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rEntryLoop)); + if (pData) + { + rTreeView.set_id(rEntryLoop, OUString()); + Reference<XContainer> xContainer(pData->xContainer, UNO_QUERY); + if (xContainer.is()) + xContainer->removeContainerListener(this); + + if (pData->xConnection.is()) + { + // connections are to be stored *only* at the data source entries + impl_releaseConnection(pData->xConnection); + } + + delete pData; + } + return false; + }); + + m_xCurrentlyDisplayed.reset(); + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/exsrcbrw.cxx b/dbaccess/source/ui/browser/exsrcbrw.cxx new file mode 100644 index 000000000..1dd47e73a --- /dev/null +++ b/dbaccess/source/ui/browser/exsrcbrw.cxx @@ -0,0 +1,413 @@ +/* -*- 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 <exsrcbrw.hxx> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/form/XGridColumnFactory.hpp> +#include <com/sun/star/form/XLoadable.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <formadapter.hxx> +#include <strings.hxx> +#include <o3tl/any.hxx> +#include <tools/diagnose_ex.h> +#include <sal/log.hxx> + +using namespace ::com::sun::star::uno; +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::lang; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::frame; +using namespace dbaui; + +// SbaExternalSourceBrowser +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_OFormGridView_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new SbaExternalSourceBrowser(context)); +} + +Any SAL_CALL SbaExternalSourceBrowser::queryInterface(const Type& _rType) +{ + Any aRet = SbaXDataBrowserController::queryInterface(_rType); + if(!aRet.hasValue()) + aRet = ::cppu::queryInterface(_rType, + static_cast<css::util::XModifyBroadcaster*>(this), + static_cast<css::form::XLoadListener*>(this)); + + return aRet; +} + +SbaExternalSourceBrowser::SbaExternalSourceBrowser(const Reference< css::uno::XComponentContext >& _rM) + :SbaXDataBrowserController(_rM) + ,m_aModifyListeners(getMutex()) + ,m_bInQueryDispatch( false ) +{ + +} + +SbaExternalSourceBrowser::~SbaExternalSourceBrowser() +{ +} + +css::uno::Sequence<OUString> SAL_CALL SbaExternalSourceBrowser::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.FormGridView" }; +} + +OUString SAL_CALL SbaExternalSourceBrowser::getImplementationName() +{ + return "org.openoffice.comp.dbu.OFormGridView"; +} + +Reference< XRowSet > SbaExternalSourceBrowser::CreateForm() +{ + m_pDataSourceImpl = new SbaXFormAdapter(); + return m_pDataSourceImpl; +} + +bool SbaExternalSourceBrowser::InitializeForm(const Reference< XPropertySet > & /*i_formProperties*/) +{ + return true; +} + +bool SbaExternalSourceBrowser::LoadForm() +{ + // as we don't have a main form (yet), we have nothing to do + // we don't call FormLoaded, because this expects a working data source + return true; +} + +void SbaExternalSourceBrowser::modified(const css::lang::EventObject& aEvent) +{ + SbaXDataBrowserController::modified(aEvent); + + // multiplex this event to all my listeners + css::lang::EventObject aEvt(*this); + m_aModifyListeners.notifyEach( &css::util::XModifyListener::modified, aEvt ); +} + +void SAL_CALL SbaExternalSourceBrowser::dispatch(const css::util::URL& aURL, const Sequence< css::beans::PropertyValue>& aArgs) +{ + if ( aURL.Complete == ".uno:FormSlots/AddGridColumn" ) + { + // search the argument describing the column to create + OUString sControlType; + sal_Int32 nControlPos = -1; + Sequence< css::beans::PropertyValue> aControlProps; + for ( const css::beans::PropertyValue& rArgument : aArgs ) + { + if ( rArgument.Name == "ColumnType" ) + { + auto s = o3tl::tryAccess<OUString>(rArgument.Value); + OSL_ENSURE(s, "invalid type for argument \"ColumnType\" !"); + if (s) + sControlType = *s; + } + else if ( rArgument.Name == "ColumnPosition" ) + { + auto n = o3tl::tryAccess<sal_Int16>(rArgument.Value); + OSL_ENSURE(n, "invalid type for argument \"ColumnPosition\" !"); + if (n) + nControlPos = *n; + } + else if ( rArgument.Name == "ColumnProperties" ) + { + auto s = o3tl::tryAccess<Sequence<css::beans::PropertyValue>>( + rArgument.Value); + OSL_ENSURE(s, "invalid type for argument \"ColumnProperties\" !"); + if (s) + aControlProps = *s; + } + else + SAL_WARN("dbaccess.ui", "SbaExternalSourceBrowser::dispatch(AddGridColumn) : unknown argument (" << rArgument.Name << ") !"); + } + if (sControlType.isEmpty()) + { + SAL_WARN("dbaccess.ui", "SbaExternalSourceBrowser::dispatch(AddGridColumn) : missing argument (ColumnType) !"); + sControlType = "TextField"; + } + OSL_ENSURE(aControlProps.hasElements(), "SbaExternalSourceBrowser::dispatch(AddGridColumn) : missing argument (ColumnProperties) !"); + + // create the col + Reference< css::form::XGridColumnFactory > xColFactory(getControlModel(), UNO_QUERY); + Reference< css::beans::XPropertySet > xNewCol = xColFactory->createColumn(sControlType); + Reference< XPropertySetInfo > xNewColProperties; + if (xNewCol.is()) + xNewColProperties = xNewCol->getPropertySetInfo(); + // set its properties + if (xNewColProperties.is()) + { + for (const css::beans::PropertyValue& rControlProp : std::as_const(aControlProps)) + { + try + { + if (xNewColProperties->hasPropertyByName(rControlProp.Name)) + xNewCol->setPropertyValue(rControlProp.Name, rControlProp.Value); + } + catch (const Exception&) + { + SAL_WARN("dbaccess.ui", "SbaExternalSourceBrowser::dispatch : could not set a column property (" << rControlProp.Name << ")!"); + } + } + } + + // correct the position + Reference< css::container::XIndexContainer > xColContainer(getControlModel(), UNO_QUERY); + + if (nControlPos > xColContainer->getCount()) + nControlPos = xColContainer->getCount(); + if (nControlPos < 0) + nControlPos = 0; + + // append the column + xColContainer->insertByIndex(nControlPos, Any(xNewCol)); + } + else if ( aURL.Complete == ".uno:FormSlots/ClearView" ) + { + ClearView(); + } + else if ( aURL.Complete == ".uno:FormSlots/AttachToForm" ) + { + if (!m_pDataSourceImpl) + return; + + Reference< XRowSet > xMasterForm; + // search the arguments for the master form + for (const css::beans::PropertyValue& rArgument : aArgs) + { + if ( (rArgument.Name == "MasterForm") && (rArgument.Value.getValueTypeClass() == TypeClass_INTERFACE) ) + { + xMasterForm.set(rArgument.Value, UNO_QUERY); + break; + } + } + if (!xMasterForm.is()) + { + SAL_WARN("dbaccess.ui", "SbaExternalSourceBrowser::dispatch(FormSlots/AttachToForm) : please specify a form to attach to as argument !"); + return; + } + + Attach(xMasterForm); + } + else + SbaXDataBrowserController::dispatch(aURL, aArgs); +} + +Reference< css::frame::XDispatch > SAL_CALL SbaExternalSourceBrowser::queryDispatch(const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags) +{ + Reference< css::frame::XDispatch > xReturn; + if (m_bInQueryDispatch) + return xReturn; + + m_bInQueryDispatch = true; + + if ( ( aURL.Complete == ".uno:FormSlots/AttachToForm" ) + // attach a new external form + || ( aURL.Complete == ".uno:FormSlots/AddGridColumn" ) + // add a column to the grid + || ( aURL.Complete == ".uno:FormSlots/ClearView" ) + // clear the grid + ) + xReturn = static_cast<css::frame::XDispatch*>(this); + + if ( !xReturn.is() + && ( (aURL.Complete == ".uno:FormSlots/moveToFirst" ) || (aURL.Complete == ".uno:FormSlots/moveToPrev" ) + || (aURL.Complete == ".uno:FormSlots/moveToNext" ) || (aURL.Complete == ".uno:FormSlots/moveToLast" ) + || (aURL.Complete == ".uno:FormSlots/moveToNew" ) || (aURL.Complete == ".uno:FormSlots/undoRecord" ) + ) + ) + { + OSL_ENSURE(aURL.Mark.isEmpty(), "SbaExternalSourceBrowser::queryDispatch : the css::util::URL shouldn't have a mark !"); + css::util::URL aNewUrl = aURL; + + // split the css::util::URL + OSL_ENSURE( m_xUrlTransformer.is(), "SbaExternalSourceBrowser::queryDispatch : could not create a URLTransformer !" ); + if ( m_xUrlTransformer.is() ) + m_xUrlTransformer->parseStrict( aNewUrl ); + + // set a new mark + aNewUrl.Mark = "DB/FormGridView"; + // this controller is instantiated when somebody dispatches the ".component:DB/FormGridView" in any + // frame, so we use "FormGridView" as mark that a dispatch request came from this view + + if (m_xUrlTransformer.is()) + m_xUrlTransformer->assemble(aNewUrl); + + Reference< XDispatchProvider > xFrameDispatcher( getFrame(), UNO_QUERY ); + if (xFrameDispatcher.is()) + xReturn = xFrameDispatcher->queryDispatch(aNewUrl, aTargetFrameName, FrameSearchFlag::PARENT); + + } + + if (!xReturn.is()) + xReturn = SbaXDataBrowserController::queryDispatch(aURL, aTargetFrameName, nSearchFlags); + + m_bInQueryDispatch = false; + return xReturn; +} + +void SAL_CALL SbaExternalSourceBrowser::disposing() +{ + // say our modify listeners goodbye + css::lang::EventObject aEvt; + aEvt.Source = static_cast<XWeak*>(this); + m_aModifyListeners.disposeAndClear(aEvt); + + stopListening(); + + SbaXDataBrowserController::disposing(); +} + +void SAL_CALL SbaExternalSourceBrowser::addModifyListener(const Reference< css::util::XModifyListener > & aListener) +{ + m_aModifyListeners.addInterface(aListener); +} + +void SAL_CALL SbaExternalSourceBrowser::removeModifyListener(const Reference< css::util::XModifyListener > & aListener) +{ + m_aModifyListeners.removeInterface(aListener); +} + +void SAL_CALL SbaExternalSourceBrowser::unloading(const css::lang::EventObject& aEvent) +{ + if (m_pDataSourceImpl && (m_pDataSourceImpl->getAttachedForm() == aEvent.Source)) + { + ClearView(); + } + + SbaXDataBrowserController::unloading(aEvent); +} + +void SbaExternalSourceBrowser::Attach(const Reference< XRowSet > & xMaster) +{ + Any aOldPos; + bool bWasInsertRow = false; + bool bBeforeFirst = true; + bool bAfterLast = true; + Reference< XRowLocate > xCursor(xMaster, UNO_QUERY); + Reference< XPropertySet > xMasterProps(xMaster, UNO_QUERY); + + try + { + // switch the control to design mode + if (getBrowserView() && getBrowserView()->getGridControl().is()) + getBrowserView()->getGridControl()->setDesignMode(true); + + // the grid will move the form's cursor to the first record, but we want the form to remain unchanged + // restore the old position + if (xCursor.is() && xMaster.is()) + { + bBeforeFirst = xMaster->isBeforeFirst(); + bAfterLast = xMaster->isAfterLast(); + if(!bBeforeFirst && !bAfterLast) + aOldPos = xCursor->getBookmark(); + } + + if (xMasterProps.is()) + xMasterProps->getPropertyValue(PROPERTY_ISNEW) >>= bWasInsertRow; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + onStartLoading( Reference< XLoadable >( xMaster, UNO_QUERY ) ); + + stopListening(); + m_pDataSourceImpl->AttachForm(xMaster); + startListening(); + + if (!xMaster.is()) + return; + + // at this point we have to reset the formatter for the new form + initFormatter(); + // assume that the master form is already loaded +#if OSL_DEBUG_LEVEL > 0 + { + Reference< XLoadable > xLoadable( xMaster, UNO_QUERY ); + OSL_ENSURE( xLoadable.is() && xLoadable->isLoaded(), "SbaExternalSourceBrowser::Attach: master is not loaded!" ); + } +#endif + + LoadFinished(true); + + Reference< XResultSetUpdate > xUpdate(xMaster, UNO_QUERY); + try + { + if (bWasInsertRow && xUpdate.is()) + xUpdate->moveToInsertRow(); + else if (xCursor.is() && aOldPos.hasValue()) + xCursor->moveToBookmark(aOldPos); + else if(bBeforeFirst && xMaster.is()) + xMaster->beforeFirst(); + else if(bAfterLast && xMaster.is()) + xMaster->afterLast(); + } + catch(Exception&) + { + SAL_WARN("dbaccess.ui", "SbaExternalSourceBrowser::Attach : couldn't restore the cursor position !"); + } +} + +void SbaExternalSourceBrowser::ClearView() +{ + // set a new (empty) datasource + Attach(Reference< XRowSet > ()); + + // clear all cols in the grid + Reference< css::container::XIndexContainer > xColContainer(getControlModel(), UNO_QUERY); + while (xColContainer->getCount() > 0) + xColContainer->removeByIndex(0); +} + +void SAL_CALL SbaExternalSourceBrowser::disposing(const css::lang::EventObject& Source) +{ + if (m_pDataSourceImpl && (m_pDataSourceImpl->getAttachedForm() == Source.Source)) + { + ClearView(); + } + + SbaXDataBrowserController::disposing(Source); +} + +void SbaExternalSourceBrowser::startListening() +{ + if (m_pDataSourceImpl && m_pDataSourceImpl->getAttachedForm().is()) + { + Reference< css::form::XLoadable > xLoadable(m_pDataSourceImpl->getAttachedForm(), UNO_QUERY); + xLoadable->addLoadListener(static_cast<css::form::XLoadListener*>(this)); + } +} + +void SbaExternalSourceBrowser::stopListening() +{ + if (m_pDataSourceImpl && m_pDataSourceImpl->getAttachedForm().is()) + { + Reference< css::form::XLoadable > xLoadable(m_pDataSourceImpl->getAttachedForm(), UNO_QUERY); + xLoadable->removeLoadListener(static_cast<css::form::XLoadListener*>(this)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/formadapter.cxx b/dbaccess/source/ui/browser/formadapter.cxx new file mode 100644 index 000000000..9f439acd2 --- /dev/null +++ b/dbaccess/source/ui/browser/formadapter.cxx @@ -0,0 +1,1877 @@ +/* -*- 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 <formadapter.hxx> +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> +#include <comphelper/types.hxx> +#include <comphelper/enumhelper.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <strings.hxx> +#include <connectivity/dbexception.hxx> +#include <comphelper/sequence.hxx> + +using namespace dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; + +// SbaXFormAdapter + +SbaXFormAdapter::SbaXFormAdapter() + :m_aLoadListeners(*this, m_aMutex) + ,m_aRowSetListeners(*this, m_aMutex) + ,m_aRowSetApproveListeners(*this, m_aMutex) + ,m_aErrorListeners(*this, m_aMutex) + ,m_aParameterListeners(*this, m_aMutex) + ,m_aSubmitListeners(*this, m_aMutex) + ,m_aResetListeners(*this, m_aMutex) + ,m_aPropertyChangeListeners(*this, m_aMutex) + ,m_aVetoablePropertyChangeListeners(*this, m_aMutex) + ,m_aPropertiesChangeListeners(*this, m_aMutex) + ,m_aDisposeListeners(m_aMutex) + ,m_aContainerListeners(m_aMutex) + ,m_nNamePropHandle(-1) +{ + +} + +SbaXFormAdapter::~SbaXFormAdapter() +{ + +} + +Sequence< Type > SAL_CALL SbaXFormAdapter::getTypes( ) +{ + return ::comphelper::concatSequences( + SbaXFormAdapter_BASE1::getTypes(), + SbaXFormAdapter_BASE2::getTypes(), + SbaXFormAdapter_BASE3::getTypes() + ); +} + +Sequence< sal_Int8 > SAL_CALL SbaXFormAdapter::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any SAL_CALL SbaXFormAdapter::queryInterface(const Type& _rType) +{ + Any aReturn = SbaXFormAdapter_BASE1::queryInterface( _rType ); + + if (!aReturn.hasValue()) + aReturn = SbaXFormAdapter_BASE2::queryInterface( _rType ); + + if (!aReturn.hasValue()) + aReturn = SbaXFormAdapter_BASE3::queryInterface( _rType ); + + return aReturn; +} + +void SbaXFormAdapter::StopListening() +{ + // log off all our multiplexers + if (m_aLoadListeners.getLength()) + { + css::uno::Reference< css::form::XLoadable > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeLoadListener(&m_aLoadListeners); + } + if (m_aRowSetListeners.getLength()) + { + css::uno::Reference< css::sdbc::XRowSet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeRowSetListener(&m_aRowSetListeners); + } + if (m_aRowSetApproveListeners.getLength()) + { + css::uno::Reference< css::sdb::XRowSetApproveBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeRowSetApproveListener(&m_aRowSetApproveListeners); + } + if (m_aErrorListeners.getLength()) + { + css::uno::Reference< css::sdb::XSQLErrorBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeSQLErrorListener(&m_aErrorListeners); + } + if (m_aSubmitListeners.getLength()) + { + css::uno::Reference< css::form::XSubmit > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeSubmitListener(&m_aSubmitListeners); + } + if (m_aResetListeners.getLength()) + { + css::uno::Reference< css::form::XReset > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeResetListener(&m_aResetListeners); + } + if (m_aParameterListeners.getLength()) + { + Reference< css::form::XDatabaseParameterBroadcaster > xBroadcaster(m_xMainForm, UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeParameterListener(&m_aParameterListeners); + } + + if (m_aPropertyChangeListeners.getOverallLen()) + { + css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removePropertyChangeListener(OUString(), &m_aPropertyChangeListeners); + } + + if (m_aVetoablePropertyChangeListeners.getOverallLen()) + { + css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeVetoableChangeListener(OUString(), &m_aVetoablePropertyChangeListeners); + } + + if (m_aPropertiesChangeListeners.getLength()) + { + Reference< css::beans::XMultiPropertySet > xBroadcaster(m_xMainForm, UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removePropertiesChangeListener(&m_aPropertiesChangeListeners); + } + + // log off ourself + Reference< css::lang::XComponent > xComp(m_xMainForm, UNO_QUERY); + if (xComp.is()) + xComp->removeEventListener(static_cast<css::lang::XEventListener*>(static_cast<css::beans::XPropertyChangeListener*>(this))); +} + +void SbaXFormAdapter::StartListening() +{ + // log off all our multiplexers + if (m_aLoadListeners.getLength()) + { + css::uno::Reference< css::form::XLoadable > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addLoadListener(&m_aLoadListeners); + } + if (m_aRowSetListeners.getLength()) + { + css::uno::Reference< css::sdbc::XRowSet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addRowSetListener(&m_aRowSetListeners); + } + if (m_aRowSetApproveListeners.getLength()) + { + css::uno::Reference< css::sdb::XRowSetApproveBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addRowSetApproveListener(&m_aRowSetApproveListeners); + } + if (m_aErrorListeners.getLength()) + { + css::uno::Reference< css::sdb::XSQLErrorBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addSQLErrorListener(&m_aErrorListeners); + } + if (m_aSubmitListeners.getLength()) + { + css::uno::Reference< css::form::XSubmit > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addSubmitListener(&m_aSubmitListeners); + } + if (m_aResetListeners.getLength()) + { + css::uno::Reference< css::form::XReset > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addResetListener(&m_aResetListeners); + } + + if (m_aParameterListeners.getLength()) + { + Reference< css::form::XDatabaseParameterBroadcaster > xBroadcaster(m_xMainForm, UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addParameterListener(&m_aParameterListeners); + } + + if (m_aPropertyChangeListeners.getOverallLen()) + { + css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addPropertyChangeListener(OUString(), &m_aPropertyChangeListeners); + } + + if (m_aVetoablePropertyChangeListeners.getOverallLen()) + { + css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addVetoableChangeListener(OUString(), &m_aVetoablePropertyChangeListeners); + } + + if (m_aPropertiesChangeListeners.getLength()) + { + Reference< css::beans::XMultiPropertySet > xBroadcaster(m_xMainForm, UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addPropertiesChangeListener(css::uno::Sequence<OUString>{""}, &m_aPropertiesChangeListeners); + } + + // log off ourself + Reference< css::lang::XComponent > xComp(m_xMainForm, UNO_QUERY); + if (xComp.is()) + xComp->addEventListener(static_cast<css::lang::XEventListener*>(static_cast<css::beans::XPropertyChangeListener*>(this))); +} + +void SbaXFormAdapter::AttachForm(const Reference< css::sdbc::XRowSet >& xNewMaster) +{ + if (xNewMaster == m_xMainForm) + return; + + OSL_ENSURE(xNewMaster.get() != static_cast< css::sdbc::XRowSet* >(this), "SbaXFormAdapter::AttachForm : invalid argument !"); + + if (m_xMainForm.is()) + { + StopListening(); + + // if our old master is loaded we have to send an 'unloaded' event + Reference< css::form::XLoadable > xLoadable(m_xMainForm, UNO_QUERY); + if (xLoadable->isLoaded()) + { + css::lang::EventObject aEvt(*this); + m_aLoadListeners.notifyEach( &css::form::XLoadListener::unloaded, aEvt ); + } + } + + m_xMainForm = xNewMaster; + + if (!m_xMainForm.is()) + return; + + StartListening(); + + // if our new master is loaded we have to send an 'loaded' event + Reference< css::form::XLoadable > xLoadable(m_xMainForm, UNO_QUERY); + if (xLoadable->isLoaded()) + { + css::lang::EventObject aEvt(*this); + m_aLoadListeners.notifyEach( &css::form::XLoadListener::loaded, aEvt ); + } + + // TODO : perhaps _all_ of our listeners should be notified about our new state + // (nearly every aspect of us may have changed with new master form) +} + +// css::sdbc::XCloseable +void SAL_CALL SbaXFormAdapter::close() +{ + Reference< css::sdbc::XCloseable > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->close(); +} + +// css::sdbc::XResultSetMetaDataSupplier +Reference< css::sdbc::XResultSetMetaData > SAL_CALL SbaXFormAdapter::getMetaData() +{ + Reference< css::sdbc::XResultSetMetaDataSupplier > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getMetaData(); + return Reference< css::sdbc::XResultSetMetaData > (); +} + +// css::sdbc::XColumnLocate +sal_Int32 SAL_CALL SbaXFormAdapter::findColumn(const OUString& columnName) +{ + Reference< css::sdbc::XColumnLocate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->findColumn(columnName); + + ::dbtools::throwInvalidColumnException( columnName, *this ); + assert(false); + return 0; // Never reached +} + +// css::sdbcx::XColumnsSupplier +Reference< css::container::XNameAccess > SAL_CALL SbaXFormAdapter::getColumns() +{ + Reference< css::sdbcx::XColumnsSupplier > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getColumns(); + return Reference< css::container::XNameAccess > (); +} + +// css::sdbc::XRow +sal_Bool SAL_CALL SbaXFormAdapter::wasNull() +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->wasNull(); + return true; +} + +OUString SAL_CALL SbaXFormAdapter::getString(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getString(columnIndex); + return OUString(); +} + +sal_Bool SAL_CALL SbaXFormAdapter::getBoolean(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getBoolean(columnIndex); + return false; +} + +sal_Int8 SAL_CALL SbaXFormAdapter::getByte(sal_Int32 columnIndex) + +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getByte(columnIndex); + return 0; +} + +sal_Int16 SAL_CALL SbaXFormAdapter::getShort(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getShort(columnIndex); + return 0; +} + +sal_Int32 SAL_CALL SbaXFormAdapter::getInt(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getInt(columnIndex); + return 0; +} + +sal_Int64 SAL_CALL SbaXFormAdapter::getLong(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getLong(columnIndex); + return 0; +} + +float SAL_CALL SbaXFormAdapter::getFloat(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getFloat(columnIndex); + return 0.0; +} + +double SAL_CALL SbaXFormAdapter::getDouble(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getDouble(columnIndex); + return 0.0; +} + +Sequence< sal_Int8 > SAL_CALL SbaXFormAdapter::getBytes(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getBytes(columnIndex); + return Sequence <sal_Int8> (); +} + +css::util::Date SAL_CALL SbaXFormAdapter::getDate(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getDate(columnIndex); + return css::util::Date(); +} + +css::util::Time SAL_CALL SbaXFormAdapter::getTime(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getTime(columnIndex); + return css::util::Time(); +} + +css::util::DateTime SAL_CALL SbaXFormAdapter::getTimestamp(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getTimestamp(columnIndex); + return css::util::DateTime(); +} + +Reference< css::io::XInputStream > SAL_CALL SbaXFormAdapter::getBinaryStream(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getBinaryStream(columnIndex); + return Reference< css::io::XInputStream > (); +} + +Reference< css::io::XInputStream > SAL_CALL SbaXFormAdapter::getCharacterStream(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getCharacterStream(columnIndex); + return Reference< css::io::XInputStream > (); +} + +Any SAL_CALL SbaXFormAdapter::getObject(sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& typeMap) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getObject(columnIndex, typeMap); + return Any(); +} + +Reference< css::sdbc::XRef > SAL_CALL SbaXFormAdapter::getRef(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getRef(columnIndex); + return Reference< css::sdbc::XRef > (); +} + +Reference< css::sdbc::XBlob > SAL_CALL SbaXFormAdapter::getBlob(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getBlob(columnIndex); + return Reference< css::sdbc::XBlob > (); +} + +Reference< css::sdbc::XClob > SAL_CALL SbaXFormAdapter::getClob(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getClob(columnIndex); + return Reference< css::sdbc::XClob > (); +} + +Reference< css::sdbc::XArray > SAL_CALL SbaXFormAdapter::getArray(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getArray(columnIndex); + return Reference< css::sdbc::XArray > (); +} + +// css::sdbcx::XRowLocate +Any SAL_CALL SbaXFormAdapter::getBookmark() +{ + Reference< css::sdbcx::XRowLocate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getBookmark(); + return Any(); +} + +sal_Bool SAL_CALL SbaXFormAdapter::moveToBookmark(const Any& bookmark) +{ + Reference< css::sdbcx::XRowLocate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->moveToBookmark(bookmark); + return false; +} + +sal_Bool SAL_CALL SbaXFormAdapter::moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows) +{ + Reference< css::sdbcx::XRowLocate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->moveRelativeToBookmark(bookmark,rows); + return false; +} + +sal_Int32 SAL_CALL SbaXFormAdapter::compareBookmarks(const Any& _first, const Any& _second) +{ + Reference< css::sdbcx::XRowLocate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->compareBookmarks(_first, _second); + return 0; +} + +sal_Bool SAL_CALL SbaXFormAdapter::hasOrderedBookmarks() +{ + Reference< css::sdbcx::XRowLocate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->hasOrderedBookmarks(); + return false; +} + +sal_Int32 SAL_CALL SbaXFormAdapter::hashBookmark(const Any& bookmark) +{ + Reference< css::sdbcx::XRowLocate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->hashBookmark(bookmark); + return 0; +} + +// css::sdbc::XRowUpdate +void SAL_CALL SbaXFormAdapter::updateNull(sal_Int32 columnIndex) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateNull(columnIndex); +} + +void SAL_CALL SbaXFormAdapter::updateBoolean(sal_Int32 columnIndex, sal_Bool x) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateBoolean(columnIndex, x); +} + +void SAL_CALL SbaXFormAdapter::updateByte(sal_Int32 columnIndex, sal_Int8 x) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateByte(columnIndex, x); +} + +void SAL_CALL SbaXFormAdapter::updateShort(sal_Int32 columnIndex, sal_Int16 x) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateShort(columnIndex, x); +} + +void SAL_CALL SbaXFormAdapter::updateInt(sal_Int32 columnIndex, sal_Int32 x) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateInt(columnIndex, x); +} + +void SAL_CALL SbaXFormAdapter::updateLong(sal_Int32 columnIndex, sal_Int64 x) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateLong(columnIndex, x); +} + +void SAL_CALL SbaXFormAdapter::updateFloat(sal_Int32 columnIndex, float x) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateFloat(columnIndex, x); +} + +void SAL_CALL SbaXFormAdapter::updateDouble(sal_Int32 columnIndex, double x) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateDouble(columnIndex, x); +} + +void SAL_CALL SbaXFormAdapter::updateString(sal_Int32 columnIndex, const OUString& x) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateString(columnIndex, x); +} + +void SAL_CALL SbaXFormAdapter::updateBytes(sal_Int32 columnIndex, const Sequence< sal_Int8 >& x) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateBytes(columnIndex, x); +} + +void SAL_CALL SbaXFormAdapter::updateDate(sal_Int32 columnIndex, const css::util::Date& x) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateDate(columnIndex, x); +} + +void SAL_CALL SbaXFormAdapter::updateTime(sal_Int32 columnIndex, const css::util::Time& x) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateTime(columnIndex, x); +} + +void SAL_CALL SbaXFormAdapter::updateTimestamp(sal_Int32 columnIndex, const css::util::DateTime& x) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateTimestamp(columnIndex, x); +} + +void SAL_CALL SbaXFormAdapter::updateBinaryStream(sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateBinaryStream(columnIndex, x, length); +} + +void SAL_CALL SbaXFormAdapter::updateCharacterStream(sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateCharacterStream(columnIndex, x, length); +} + +void SAL_CALL SbaXFormAdapter::updateObject(sal_Int32 columnIndex, const Any& x) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateObject(columnIndex, x); +} + +void SAL_CALL SbaXFormAdapter::updateNumericObject(sal_Int32 columnIndex, const Any& x, sal_Int32 scale) +{ + Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateNumericObject(columnIndex, x, scale); +} + +// css::sdbc::XResultSet +sal_Bool SAL_CALL SbaXFormAdapter::next() +{ + if (m_xMainForm.is()) + return m_xMainForm->next(); + return false; +} + +sal_Bool SAL_CALL SbaXFormAdapter::isBeforeFirst() +{ + if (m_xMainForm.is()) + return m_xMainForm->isBeforeFirst(); + return false; +} + +sal_Bool SAL_CALL SbaXFormAdapter::isAfterLast() +{ + if (m_xMainForm.is()) + return m_xMainForm->isAfterLast(); + return false; +} + +sal_Bool SAL_CALL SbaXFormAdapter::isFirst() +{ + if (m_xMainForm.is()) + return m_xMainForm->isFirst(); + return false; +} + +sal_Bool SAL_CALL SbaXFormAdapter::isLast() +{ + if (m_xMainForm.is()) + return m_xMainForm->isLast(); + return false; +} + +void SAL_CALL SbaXFormAdapter::beforeFirst() +{ + if (m_xMainForm.is()) + m_xMainForm->beforeFirst(); +} + +void SAL_CALL SbaXFormAdapter::afterLast() +{ + if (m_xMainForm.is()) + m_xMainForm->afterLast(); +} + +sal_Bool SAL_CALL SbaXFormAdapter::first() +{ + if (m_xMainForm.is()) + return m_xMainForm->first(); + return false; +} + +sal_Bool SAL_CALL SbaXFormAdapter::last() +{ + if (m_xMainForm.is()) + return m_xMainForm->last(); + return false; +} + +sal_Int32 SAL_CALL SbaXFormAdapter::getRow() +{ + if (m_xMainForm.is()) + return m_xMainForm->getRow(); + return 0; +} + +sal_Bool SAL_CALL SbaXFormAdapter::absolute(sal_Int32 row) +{ + if (m_xMainForm.is()) + return m_xMainForm->absolute(row); + return false; +} + +sal_Bool SAL_CALL SbaXFormAdapter::relative(sal_Int32 rows) +{ + if (m_xMainForm.is()) + return m_xMainForm->relative(rows); + return false; +} + +sal_Bool SAL_CALL SbaXFormAdapter::previous() +{ + if (m_xMainForm.is()) + return m_xMainForm->previous(); + return false; +} + +void SAL_CALL SbaXFormAdapter::refreshRow() +{ + if (m_xMainForm.is()) + m_xMainForm->refreshRow(); +} + +sal_Bool SAL_CALL SbaXFormAdapter::rowUpdated() +{ + if (m_xMainForm.is()) + return m_xMainForm->rowUpdated(); + return false; +} + +sal_Bool SAL_CALL SbaXFormAdapter::rowInserted() +{ + if (m_xMainForm.is()) + return m_xMainForm->rowInserted(); + return false; +} + +sal_Bool SAL_CALL SbaXFormAdapter::rowDeleted() +{ + if (m_xMainForm.is()) + return m_xMainForm->rowDeleted(); + return false; +} + +Reference< XInterface > SAL_CALL SbaXFormAdapter::getStatement() +{ + if (m_xMainForm.is()) + return m_xMainForm->getStatement(); + return nullptr; +} + +// css::sdbc::XResultSetUpdate +void SAL_CALL SbaXFormAdapter::insertRow() +{ + Reference< css::sdbc::XResultSetUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->insertRow(); +} + +void SAL_CALL SbaXFormAdapter::updateRow() +{ + Reference< css::sdbc::XResultSetUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->updateRow(); +} + +void SAL_CALL SbaXFormAdapter::deleteRow() +{ + Reference< css::sdbc::XResultSetUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->deleteRow(); +} + +void SAL_CALL SbaXFormAdapter::cancelRowUpdates() +{ + Reference< css::sdbc::XResultSetUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->cancelRowUpdates(); +} + +void SAL_CALL SbaXFormAdapter::moveToInsertRow() +{ + Reference< css::sdbc::XResultSetUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->moveToInsertRow(); +} + +void SAL_CALL SbaXFormAdapter::moveToCurrentRow() +{ + Reference< css::sdbc::XResultSetUpdate > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->moveToCurrentRow(); +} + +// css::sdbc::XRowSet +void SAL_CALL SbaXFormAdapter::execute() +{ + if (m_xMainForm.is()) + m_xMainForm->execute(); +} + +void SAL_CALL SbaXFormAdapter::addRowSetListener(const css::uno::Reference< css::sdbc::XRowSetListener >& l) +{ + m_aRowSetListeners.addInterface(l); + if (m_aRowSetListeners.getLength() == 1) + { + css::uno::Reference< css::sdbc::XRowSet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addRowSetListener(&m_aRowSetListeners); + } +} +void SAL_CALL SbaXFormAdapter::removeRowSetListener(const css::uno::Reference< css::sdbc::XRowSetListener >& l) +{ + if (m_aRowSetListeners.getLength() == 1) + { + css::uno::Reference< css::sdbc::XRowSet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeRowSetListener(&m_aRowSetListeners); + } + m_aRowSetListeners.removeInterface(l); +} + +// css::sdbcx::XDeleteRows +Sequence<sal_Int32> SAL_CALL SbaXFormAdapter::deleteRows(const Sequence< Any >& rows) +{ + Reference< css::sdbcx::XDeleteRows > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->deleteRows(rows); + return Sequence<sal_Int32>(); +} + +// css::sdbc::XWarningsSupplier +Any SAL_CALL SbaXFormAdapter::getWarnings() +{ + Reference< css::sdbc::XWarningsSupplier > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->getWarnings(); + return Any(); +} + +void SAL_CALL SbaXFormAdapter::clearWarnings() +{ + Reference< css::sdbc::XWarningsSupplier > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->clearWarnings(); +} + +// css::sdb::XRowSetApproveBroadcaster +void SAL_CALL SbaXFormAdapter::addRowSetApproveListener(const css::uno::Reference< css::sdb::XRowSetApproveListener >& l) +{ + m_aRowSetApproveListeners.addInterface(l); + if (m_aRowSetApproveListeners.getLength() == 1) + { + css::uno::Reference< css::sdb::XRowSetApproveBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addRowSetApproveListener(&m_aRowSetApproveListeners); + } +} +void SAL_CALL SbaXFormAdapter::removeRowSetApproveListener(const css::uno::Reference< css::sdb::XRowSetApproveListener >& l) +{ + if (m_aRowSetApproveListeners.getLength() == 1) + { + css::uno::Reference< css::sdb::XRowSetApproveBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeRowSetApproveListener(&m_aRowSetApproveListeners); + } + m_aRowSetApproveListeners.removeInterface(l); +} + +// css::sdbc::XSQLErrorBroadcaster +void SAL_CALL SbaXFormAdapter::addSQLErrorListener(const css::uno::Reference< css::sdb::XSQLErrorListener >& l) +{ + m_aErrorListeners.addInterface(l); + if (m_aErrorListeners.getLength() == 1) + { + css::uno::Reference< css::sdb::XSQLErrorBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addSQLErrorListener(&m_aErrorListeners); + } +} +void SAL_CALL SbaXFormAdapter::removeSQLErrorListener(const css::uno::Reference< css::sdb::XSQLErrorListener >& l) +{ + if (m_aErrorListeners.getLength() == 1) + { + css::uno::Reference< css::sdb::XSQLErrorBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeSQLErrorListener(&m_aErrorListeners); + } + m_aErrorListeners.removeInterface(l); +} + +// css::sdb::XResultSetAccess +Reference< css::sdbc::XResultSet > SAL_CALL SbaXFormAdapter::createResultSet() +{ + Reference< css::sdb::XResultSetAccess > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->createResultSet(); + return Reference< css::sdbc::XResultSet > (); +} + +// css::form::XLoadable +void SAL_CALL SbaXFormAdapter::load() +{ + Reference< css::form::XLoadable > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->load(); +} + +void SAL_CALL SbaXFormAdapter::unload() +{ + Reference< css::form::XLoadable > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->unload(); +} + +void SAL_CALL SbaXFormAdapter::reload() +{ + Reference< css::form::XLoadable > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->reload(); +} + +sal_Bool SAL_CALL SbaXFormAdapter::isLoaded() +{ + Reference< css::form::XLoadable > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + return xIface->isLoaded(); + return false; +} + +void SAL_CALL SbaXFormAdapter::addLoadListener(const css::uno::Reference< css::form::XLoadListener>& l) +{ + m_aLoadListeners.addInterface(l); + if (m_aLoadListeners.getLength() == 1) + { + css::uno::Reference< css::form::XLoadable > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addLoadListener(&m_aLoadListeners); + } +} +void SAL_CALL SbaXFormAdapter::removeLoadListener(const css::uno::Reference< css::form::XLoadListener >& l) +{ + if (m_aLoadListeners.getLength() == 1) + { + css::uno::Reference< css::form::XLoadable > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeLoadListener(&m_aLoadListeners); + } + m_aLoadListeners.removeInterface(l); +} + +// css::sdbc::XParameters +void SAL_CALL SbaXFormAdapter::setNull(sal_Int32 parameterIndex, sal_Int32 sqlType) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setNull(parameterIndex, sqlType); +} + +void SAL_CALL SbaXFormAdapter::setObjectNull(sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setObjectNull(parameterIndex, sqlType, typeName); +} + +void SAL_CALL SbaXFormAdapter::setBoolean(sal_Int32 parameterIndex, sal_Bool x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setBoolean(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setByte(sal_Int32 parameterIndex, sal_Int8 x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setByte(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setShort(sal_Int32 parameterIndex, sal_Int16 x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setShort(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setInt(sal_Int32 parameterIndex, sal_Int32 x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setInt(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setLong(sal_Int32 parameterIndex, sal_Int64 x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setLong(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setFloat(sal_Int32 parameterIndex, float x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setFloat(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setDouble(sal_Int32 parameterIndex, double x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setDouble(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setString(sal_Int32 parameterIndex, const OUString& x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setString(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setBytes(sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setBytes(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setDate(sal_Int32 parameterIndex, const css::util::Date& x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setDate(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setTime(sal_Int32 parameterIndex, const css::util::Time& x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setTime(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setTimestamp(sal_Int32 parameterIndex, const css::util::DateTime& x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setTimestamp(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setBinaryStream(sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setBinaryStream(parameterIndex, x, length); +} + +void SAL_CALL SbaXFormAdapter::setCharacterStream(sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setCharacterStream(parameterIndex, x, length); +} + +void SAL_CALL SbaXFormAdapter::setObject(sal_Int32 parameterIndex, const Any& x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setObject(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setObjectWithInfo(sal_Int32 parameterIndex, const Any& x, sal_Int32 targetSqlType, sal_Int32 scale) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setObjectWithInfo(parameterIndex, x, targetSqlType, scale); +} + +void SAL_CALL SbaXFormAdapter::setRef(sal_Int32 parameterIndex, const Reference< css::sdbc::XRef >& x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setRef(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setBlob(sal_Int32 parameterIndex, const Reference< css::sdbc::XBlob >& x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setBlob(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setClob(sal_Int32 parameterIndex, const Reference< css::sdbc::XClob >& x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setClob(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::setArray(sal_Int32 parameterIndex, const Reference< css::sdbc::XArray >& x) +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->setArray(parameterIndex, x); +} + +void SAL_CALL SbaXFormAdapter::clearParameters() +{ + Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY); + if (xIface.is()) + xIface->clearParameters(); +} + +// css::form::XDatabaseParameterBroadcaster +void SAL_CALL SbaXFormAdapter::addParameterListener(const Reference< css::form::XDatabaseParameterListener >& aListener) +{ + m_aParameterListeners.addInterface(aListener); + if (m_aParameterListeners.getLength() == 1) + { + Reference< css::form::XDatabaseParameterBroadcaster > xBroadcaster(m_xMainForm, UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addParameterListener(&m_aParameterListeners); + } +} + +void SAL_CALL SbaXFormAdapter::removeParameterListener(const Reference< css::form::XDatabaseParameterListener >& aListener) +{ + if (m_aParameterListeners.getLength() == 1) + { + Reference< css::form::XDatabaseParameterBroadcaster > xBroadcaster(m_xMainForm, UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeParameterListener(&m_aParameterListeners); + } + m_aParameterListeners.removeInterface(aListener); +} + +// css::container::XChild +Reference< XInterface > SAL_CALL SbaXFormAdapter::getParent() +{ + return m_xParent; +} + +void SAL_CALL SbaXFormAdapter::setParent(const Reference< XInterface >& Parent) +{ + m_xParent = Parent; +} + +// css::form::XSubmit +void SAL_CALL SbaXFormAdapter::submit(const Reference< css::awt::XControl >& aControl, const css::awt::MouseEvent& aMouseEvt) +{ + Reference< css::form::XSubmit > xSubmit(m_xMainForm, UNO_QUERY); + if (xSubmit.is()) + xSubmit->submit(aControl, aMouseEvt); +} + +void SAL_CALL SbaXFormAdapter::addSubmitListener(const css::uno::Reference< css::form::XSubmitListener >& l) +{ + m_aSubmitListeners.addInterface(l); + if (m_aSubmitListeners.getLength() == 1) + { + css::uno::Reference< css::form::XSubmit > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addSubmitListener(&m_aSubmitListeners); + } +} +void SAL_CALL SbaXFormAdapter::removeSubmitListener(const css::uno::Reference< css::form::XSubmitListener >& l) +{ + if (m_aSubmitListeners.getLength() == 1) + { + css::uno::Reference< css::form::XSubmit > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeSubmitListener(&m_aSubmitListeners); + } + m_aSubmitListeners.removeInterface(l); +} + +// css::awt::XTabControllerModel +sal_Bool SAL_CALL SbaXFormAdapter::getGroupControl() +{ + OSL_FAIL("SAL_CALL SbaXFormAdapter::getGroupControl : not supported !"); + return false; +} + +void SAL_CALL SbaXFormAdapter::setGroupControl(sal_Bool /*GroupControl*/) +{ + OSL_FAIL("SAL_CALL SbaXFormAdapter::setGroupControl : not supported !"); +} + +void SAL_CALL SbaXFormAdapter::setControlModels(const Sequence< Reference< css::awt::XControlModel > >& /*Controls*/) +{ + OSL_FAIL("SAL_CALL SbaXFormAdapter::setControlModels : not supported !"); +} + +Sequence< Reference< css::awt::XControlModel > > SAL_CALL SbaXFormAdapter::getControlModels() +{ + OSL_FAIL("SAL_CALL SbaXFormAdapter::getControlModels : not supported !"); + return Sequence< Reference< css::awt::XControlModel > >(); +} + +void SAL_CALL SbaXFormAdapter::setGroup(const Sequence< Reference< css::awt::XControlModel > >& /*_rGroup*/, const OUString& /*GroupName*/) +{ + OSL_FAIL("SAL_CALL SbaXFormAdapter::setGroup : not supported !"); +} + +sal_Int32 SAL_CALL SbaXFormAdapter::getGroupCount() +{ + OSL_FAIL("SAL_CALL SbaXFormAdapter::getGroupCount : not supported !"); + return 0; +} + +void SAL_CALL SbaXFormAdapter::getGroup(sal_Int32 /*nGroup*/, Sequence< Reference< css::awt::XControlModel > >& /*_rGroup*/, OUString& /*Name*/) +{ + OSL_FAIL("SAL_CALL SbaXFormAdapter::getGroup : not supported !"); +} + +void SAL_CALL SbaXFormAdapter::getGroupByName(const OUString& /*Name*/, Sequence< Reference< css::awt::XControlModel > >& /*_rGroup*/) +{ + OSL_FAIL("SAL_CALL SbaXFormAdapter::getGroupByName : not supported !"); +} + +// css::lang::XComponent +void SAL_CALL SbaXFormAdapter::dispose() +{ + // log off all multiplexers + if (m_xMainForm.is()) + StopListening(); + + css::lang::EventObject aEvt(*this); + m_aLoadListeners.disposeAndClear(aEvt); + m_aRowSetListeners.disposeAndClear(aEvt); + m_aRowSetApproveListeners.disposeAndClear(aEvt); + m_aErrorListeners.disposeAndClear(aEvt); + m_aParameterListeners.disposeAndClear(aEvt); + m_aSubmitListeners.disposeAndClear(aEvt); + m_aResetListeners.disposeAndClear(aEvt); + + m_aVetoablePropertyChangeListeners.disposeAndClear(); + m_aPropertyChangeListeners.disposeAndClear(); + m_aPropertiesChangeListeners.disposeAndClear(aEvt); + + m_aDisposeListeners.disposeAndClear(aEvt); + m_aContainerListeners.disposeAndClear(aEvt); + + // dispose all children + for (auto const& child : m_aChildren) + { + Reference< css::beans::XPropertySet > xSet(child, UNO_QUERY); + if (xSet.is()) + xSet->removePropertyChangeListener(PROPERTY_NAME, static_cast<css::beans::XPropertyChangeListener*>(this)); + + Reference< css::container::XChild > xChild(child, UNO_QUERY); + if (xChild.is()) + xChild->setParent(Reference< XInterface > ()); + + Reference< css::lang::XComponent > xComp(child, UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + } + m_aChildren.clear(); +} + +void SAL_CALL SbaXFormAdapter::addEventListener(const Reference< css::lang::XEventListener >& xListener) +{ + m_aDisposeListeners.addInterface(xListener); +} + +void SAL_CALL SbaXFormAdapter::removeEventListener(const Reference< css::lang::XEventListener >& aListener) +{ + m_aDisposeListeners.removeInterface(aListener); +} + +// css::beans::XFastPropertySet +void SAL_CALL SbaXFormAdapter::setFastPropertyValue(sal_Int32 nHandle, const Any& aValue) +{ + Reference< css::beans::XFastPropertySet > xSet(m_xMainForm, UNO_QUERY); + OSL_ENSURE(xSet.is(), "SAL_CALL SbaXFormAdapter::setFastPropertyValue : have no master form !"); + + if (m_nNamePropHandle == nHandle) + { + if (aValue.getValueType().getTypeClass() != TypeClass_STRING) + { + throw css::lang::IllegalArgumentException(); + } + + // for notifying property listeners + css::beans::PropertyChangeEvent aEvt; + aEvt.Source = *this; + aEvt.PropertyName = PROPERTY_NAME; + aEvt.PropertyHandle = m_nNamePropHandle; + aEvt.OldValue <<= m_sName; + aEvt.NewValue = aValue; + + aValue >>= m_sName; + + m_aPropertyChangeListeners.getContainer(PROPERTY_NAME)->notifyEach( + &XPropertyChangeListener::propertyChange, aEvt ); + + return; + } + + xSet->setFastPropertyValue(nHandle, aValue); +} + +Any SAL_CALL SbaXFormAdapter::getFastPropertyValue(sal_Int32 nHandle) +{ + Reference< css::beans::XFastPropertySet > xSet(m_xMainForm, UNO_QUERY); + OSL_ENSURE(xSet.is(), "SAL_CALL SbaXFormAdapter::getFastPropertyValue : have no master form !"); + + if (m_nNamePropHandle == nHandle) + return Any(m_sName); + + return xSet->getFastPropertyValue(nHandle); +} + +// css::container::XNamed +OUString SAL_CALL SbaXFormAdapter::getName() +{ + return ::comphelper::getString(getPropertyValue(PROPERTY_NAME)); +} + +void SAL_CALL SbaXFormAdapter::setName(const OUString& aName) +{ + setPropertyValue(PROPERTY_NAME, Any(aName)); +} + +// css::io::XPersistObject +OUString SAL_CALL SbaXFormAdapter::getServiceName() +{ + Reference< css::io::XPersistObject > xPersist(m_xMainForm, UNO_QUERY); + if (xPersist.is()) + return xPersist->getServiceName(); + return OUString(); +} + +void SAL_CALL SbaXFormAdapter::write(const Reference< css::io::XObjectOutputStream >& _rxOutStream) +{ + Reference< css::io::XPersistObject > xPersist(m_xMainForm, UNO_QUERY); + if (xPersist.is()) + xPersist->write(_rxOutStream); +} + +void SAL_CALL SbaXFormAdapter::read(const Reference< css::io::XObjectInputStream >& _rxInStream) +{ + Reference< css::io::XPersistObject > xPersist(m_xMainForm, UNO_QUERY); + if (xPersist.is()) + xPersist->read(_rxInStream); +} + +// css::beans::XMultiPropertySet +Reference< css::beans::XPropertySetInfo > SAL_CALL SbaXFormAdapter::getPropertySetInfo() +{ + Reference< css::beans::XMultiPropertySet > xSet(m_xMainForm, UNO_QUERY); + if (!xSet.is()) + return Reference< css::beans::XPropertySetInfo > (); + + Reference< css::beans::XPropertySetInfo > xReturn = xSet->getPropertySetInfo(); + if (-1 == m_nNamePropHandle) + { + // we need to determine the handle for the NAME property + const Sequence<css::beans::Property> aProps = xReturn->getProperties(); + for (const css::beans::Property& rProp : aProps) + { + if (rProp.Name == PROPERTY_NAME) + { + m_nNamePropHandle = rProp.Handle; + break; + } + } + } + return xReturn; +} + +void SAL_CALL SbaXFormAdapter::setPropertyValues(const Sequence< OUString >& PropertyNames, const Sequence< Any >& Values) +{ + Reference< css::beans::XMultiPropertySet > xSet(m_xMainForm, UNO_QUERY); + if (xSet.is()) + xSet->setPropertyValues(PropertyNames, Values); +} + +Sequence< Any > SAL_CALL SbaXFormAdapter::getPropertyValues(const Sequence< OUString >& aPropertyNames) +{ + Reference< css::beans::XMultiPropertySet > xSet(m_xMainForm, UNO_QUERY); + if (!xSet.is()) + return Sequence< Any>(aPropertyNames.getLength()); + + Sequence< Any> aReturn = xSet->getPropertyValues(aPropertyNames); + auto aReturnRange = asNonConstRange(aReturn); + + // search for (and fake) the NAME property + OSL_ENSURE(aReturn.getLength() == aPropertyNames.getLength(), "SAL_CALL SbaXFormAdapter::getPropertyValues : the main form returned an invalid-length sequence !"); + for (sal_Int32 i=0; i<aPropertyNames.getLength(); ++i) + if (aPropertyNames[i] == PROPERTY_NAME) + { + aReturnRange[i] <<= m_sName; + break; + } + + return aReturn; +} + +void SAL_CALL SbaXFormAdapter::addPropertiesChangeListener(const Sequence< OUString>& /*aPropertyNames*/, const Reference< css::beans::XPropertiesChangeListener >& xListener) +{ + // we completely ignore the property names, _all_ changes of _all_ properties will be forwarded to _all_ listeners + m_aPropertiesChangeListeners.addInterface(xListener); + if (m_aPropertiesChangeListeners.getLength() == 1) + { + Reference< css::beans::XMultiPropertySet > xBroadcaster(m_xMainForm, UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addPropertiesChangeListener(Sequence< OUString>{""}, &m_aPropertiesChangeListeners); + } +} + +void SAL_CALL SbaXFormAdapter::removePropertiesChangeListener(const Reference< css::beans::XPropertiesChangeListener >& Listener) +{ + if (m_aPropertiesChangeListeners.getLength() == 1) + { + Reference< css::beans::XMultiPropertySet > xBroadcaster(m_xMainForm, UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removePropertiesChangeListener(&m_aPropertiesChangeListeners); + } + m_aPropertiesChangeListeners.removeInterface(Listener); +} + +void SAL_CALL SbaXFormAdapter::firePropertiesChangeEvent(const Sequence< OUString >& aPropertyNames, const Reference< css::beans::XPropertiesChangeListener >& xListener) +{ + Reference< css::beans::XMultiPropertySet > xSet(m_xMainForm, UNO_QUERY); + if (xSet.is()) + xSet->firePropertiesChangeEvent(aPropertyNames, xListener); +} + +// css::beans::XPropertySet +void SAL_CALL SbaXFormAdapter::setPropertyValue(const OUString& aPropertyName, const Any& aValue) +{ + Reference< css::beans::XPropertySet > xSet(m_xMainForm, UNO_QUERY); + if (!xSet.is()) + return; + + // special handling for the "name" property + if (aPropertyName == PROPERTY_NAME) + setFastPropertyValue(m_nNamePropHandle, aValue); + + xSet->setPropertyValue(aPropertyName, aValue); +} + +Any SAL_CALL SbaXFormAdapter::getPropertyValue(const OUString& PropertyName) +{ + Reference< css::beans::XPropertySet > xSet(m_xMainForm, UNO_QUERY); + if (!xSet.is()) + return Any(); + + // special handling for the "name" property + if (PropertyName == PROPERTY_NAME) + return getFastPropertyValue(m_nNamePropHandle); + + return xSet->getPropertyValue(PropertyName); +} + +void SAL_CALL SbaXFormAdapter::addPropertyChangeListener(const OUString& rName, const css::uno::Reference< css::beans::XPropertyChangeListener>& l ) +{ + m_aPropertyChangeListeners.addInterface(rName, l); + if (m_aPropertyChangeListeners.getOverallLen() == 1) + { + css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addPropertyChangeListener(OUString(), &m_aPropertyChangeListeners); + } +} +void SAL_CALL SbaXFormAdapter::removePropertyChangeListener(const OUString& rName, const css::uno::Reference< css::beans::XPropertyChangeListener>& l ) +{ + if (m_aPropertyChangeListeners.getOverallLen() == 1) + { + css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removePropertyChangeListener(OUString(), &m_aPropertyChangeListeners); + } + m_aPropertyChangeListeners.removeInterface(rName, l); +} + +void SAL_CALL SbaXFormAdapter::addVetoableChangeListener(const OUString& rName, const css::uno::Reference< css::beans::XVetoableChangeListener>& l ) +{ + m_aVetoablePropertyChangeListeners.addInterface(rName, l); + if (m_aVetoablePropertyChangeListeners.getOverallLen() == 1) + { + css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addVetoableChangeListener(OUString(), &m_aVetoablePropertyChangeListeners); + } +} +void SAL_CALL SbaXFormAdapter::removeVetoableChangeListener(const OUString& rName, const css::uno::Reference< css::beans::XVetoableChangeListener>& l ) +{ + if (m_aVetoablePropertyChangeListeners.getOverallLen() == 1) + { + css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeVetoableChangeListener(OUString(), &m_aVetoablePropertyChangeListeners); + } + m_aVetoablePropertyChangeListeners.removeInterface(rName, l); +} + + +// css::util::XCancellable +void SAL_CALL SbaXFormAdapter::cancel() +{ + Reference< css::util::XCancellable > xCancel(m_xMainForm, UNO_QUERY); + if (!xCancel.is()) + return; + xCancel->cancel(); +} + +// css::beans::XPropertyState +css::beans::PropertyState SAL_CALL SbaXFormAdapter::getPropertyState(const OUString& PropertyName) +{ + Reference< css::beans::XPropertyState > xState(m_xMainForm, UNO_QUERY); + if (xState.is()) + return xState->getPropertyState(PropertyName); + return css::beans::PropertyState_DEFAULT_VALUE; +} + +Sequence< css::beans::PropertyState> SAL_CALL SbaXFormAdapter::getPropertyStates(const Sequence< OUString >& aPropertyName) +{ + Reference< css::beans::XPropertyState > xState(m_xMainForm, UNO_QUERY); + if (xState.is()) + return xState->getPropertyStates(aPropertyName); + + // set them all to DEFAULT + Sequence< css::beans::PropertyState> aReturn(aPropertyName.getLength()); + for (css::beans::PropertyState& rState : asNonConstRange(aReturn)) + rState = css::beans::PropertyState_DEFAULT_VALUE; + return aReturn; +} + +void SAL_CALL SbaXFormAdapter::setPropertyToDefault(const OUString& PropertyName) +{ + Reference< css::beans::XPropertyState > xState(m_xMainForm, UNO_QUERY); + if (xState.is()) + xState->setPropertyToDefault(PropertyName); +} + +Any SAL_CALL SbaXFormAdapter::getPropertyDefault(const OUString& aPropertyName) +{ + Reference< css::beans::XPropertyState > xState(m_xMainForm, UNO_QUERY); + if (xState.is()) + return xState->getPropertyDefault(aPropertyName); + return Any(); +} + +// css::form::XReset +void SAL_CALL SbaXFormAdapter::reset() +{ + Reference< css::form::XReset > xReset(m_xMainForm, UNO_QUERY); + if (xReset.is()) + xReset->reset(); +} + +void SAL_CALL SbaXFormAdapter::addResetListener(const css::uno::Reference< css::form::XResetListener >& l) +{ + m_aResetListeners.addInterface(l); + if (m_aResetListeners.getLength() == 1) + { + css::uno::Reference< css::form::XReset > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addResetListener(&m_aResetListeners); + } +} +void SAL_CALL SbaXFormAdapter::removeResetListener(const css::uno::Reference< css::form::XResetListener >& l) +{ + if (m_aResetListeners.getLength() == 1) + { + css::uno::Reference< css::form::XReset > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeResetListener(&m_aResetListeners); + } + m_aResetListeners.removeInterface(l); +} + +// css::container::XNameContainer +void SbaXFormAdapter::implInsert(const Any& aElement, sal_Int32 nIndex, const OUString* pNewElName) +{ + // extract the form component + if (aElement.getValueType().getTypeClass() != TypeClass_INTERFACE) + { + throw css::lang::IllegalArgumentException(); + } + + Reference< css::form::XFormComponent > xElement(aElement, UNO_QUERY); + if (!xElement.is()) + { + throw css::lang::IllegalArgumentException(); + } + + // for the name we need the propset + Reference< css::beans::XPropertySet > xElementSet(xElement, UNO_QUERY); + if (!xElementSet.is()) + { + throw css::lang::IllegalArgumentException(); + } + OUString sName; + try + { + if (pNewElName) + xElementSet->setPropertyValue(PROPERTY_NAME, Any(*pNewElName)); + + xElementSet->getPropertyValue(PROPERTY_NAME) >>= sName; + } + catch(Exception&) + { + // the set didn't support the name prop + throw css::lang::IllegalArgumentException(); + } + + // check the index + OSL_ASSERT(nIndex >= 0); + if (sal::static_int_cast< sal_uInt32 >(nIndex) > m_aChildren.size()) + nIndex = m_aChildren.size(); + + OSL_ENSURE(m_aChildren.size() == m_aChildNames.size(), "SAL_CALL SbaXFormAdapter::implInsert : inconsistent container state !"); + m_aChildren.insert(m_aChildren.begin() + nIndex, xElement); + m_aChildNames.insert(m_aChildNames.begin() + nIndex, sName); + + // listen for a change of the name + xElementSet->addPropertyChangeListener(PROPERTY_NAME, static_cast<css::beans::XPropertyChangeListener*>(this)); + + // we are now the parent of the new element + xElement->setParent(static_cast<css::container::XContainer*>(this)); + + // notify the container listeners + css::container::ContainerEvent aEvt; + aEvt.Source = *this; + aEvt.Accessor <<= nIndex; + aEvt.Element <<= xElement; + m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvt ); +} + +sal_Int32 SbaXFormAdapter::implGetPos(const OUString& rName) +{ + std::vector< OUString>::const_iterator aIter = std::find( m_aChildNames.begin(), + m_aChildNames.end(), + rName); + + if(aIter != m_aChildNames.end()) + return aIter - m_aChildNames.begin(); + + return -1; +} + +void SAL_CALL SbaXFormAdapter::insertByName(const OUString& aName, const Any& aElement) +{ + implInsert(aElement, m_aChildren.size(), &aName); +} + +void SAL_CALL SbaXFormAdapter::removeByName(const OUString& Name) +{ + sal_Int32 nPos = implGetPos(Name); + if (-1 == nPos) + { + throw css::container::NoSuchElementException(); + } + removeByIndex(nPos); +} + +// css::container::XNameReplace +void SAL_CALL SbaXFormAdapter::replaceByName(const OUString& aName, const Any& aElement) +{ + sal_Int32 nPos = implGetPos(aName); + if (-1 == nPos) + { + throw css::container::NoSuchElementException(); + } + replaceByIndex(nPos, aElement); +} + +// css::container::XNameAccess +Any SAL_CALL SbaXFormAdapter::getByName(const OUString& aName) +{ + sal_Int32 nPos = implGetPos(aName); + if (-1 == nPos) + { + throw css::container::NoSuchElementException(); + } + return Any(m_aChildren[nPos]); +} + +Sequence< OUString > SAL_CALL SbaXFormAdapter::getElementNames() +{ + return Sequence< OUString >(m_aChildNames.data(), m_aChildNames.size()); +} + +sal_Bool SAL_CALL SbaXFormAdapter::hasByName(const OUString& aName) +{ + return (-1 != implGetPos(aName)); +} + +// css::container::XElementAccess +Type SAL_CALL SbaXFormAdapter::getElementType() +{ + return cppu::UnoType<css::form::XFormComponent>::get(); +} + +sal_Bool SAL_CALL SbaXFormAdapter::hasElements() +{ + return !m_aChildren.empty(); +} + +// css::container::XIndexContainer +void SAL_CALL SbaXFormAdapter::insertByIndex(sal_Int32 _rIndex, const Any& Element) +{ + if ( ( _rIndex < 0 ) || ( o3tl::make_unsigned(_rIndex) >= m_aChildren.size() ) ) + throw css::lang::IndexOutOfBoundsException(); + implInsert(Element, _rIndex); +} + +void SAL_CALL SbaXFormAdapter::removeByIndex(sal_Int32 _rIndex) +{ + if ( ( _rIndex < 0 ) || ( o3tl::make_unsigned(_rIndex) >= m_aChildren.size() ) ) + throw css::lang::IndexOutOfBoundsException(); + + Reference< css::form::XFormComponent > xAffected = *(m_aChildren.begin() + _rIndex); + + OSL_ENSURE(m_aChildren.size() == m_aChildNames.size(), "SAL_CALL SbaXFormAdapter::removeByIndex : inconsistent container state !"); + m_aChildren.erase(m_aChildren.begin() + _rIndex); + m_aChildNames.erase(m_aChildNames.begin() + _rIndex); + + // no need to listen anymore + Reference< css::beans::XPropertySet > xAffectedSet(xAffected, UNO_QUERY); + xAffectedSet->removePropertyChangeListener(PROPERTY_NAME, static_cast<css::beans::XPropertyChangeListener*>(this)); + + // we are no longer the parent + xAffected->setParent(Reference< XInterface > ()); + + // notify container listeners + css::container::ContainerEvent aEvt; + aEvt.Source = *this; + aEvt.Element <<= xAffected; + m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvt ); +} + +// css::container::XIndexReplace +void SAL_CALL SbaXFormAdapter::replaceByIndex(sal_Int32 _rIndex, const Any& Element) +{ + if ( ( _rIndex < 0 ) || ( o3tl::make_unsigned(_rIndex) >= m_aChildren.size() ) ) + throw css::lang::IndexOutOfBoundsException(); + + // extract the form component + if (Element.getValueType().getTypeClass() != TypeClass_INTERFACE) + { + throw css::lang::IllegalArgumentException(); + } + + Reference< css::form::XFormComponent > xElement(Element, UNO_QUERY); + if (!xElement.is()) + { + throw css::lang::IllegalArgumentException(); + } + + // for the name we need the propset + Reference< css::beans::XPropertySet > xElementSet(xElement, UNO_QUERY); + if (!xElementSet.is()) + { + throw css::lang::IllegalArgumentException(); + } + OUString sName; + try + { + xElementSet->getPropertyValue(PROPERTY_NAME) >>= sName; + } + catch(Exception&) + { + // the set didn't support the name prop + throw css::lang::IllegalArgumentException(); + } + + Reference< css::form::XFormComponent > xOld = *(m_aChildren.begin() + _rIndex); + + OSL_ENSURE(m_aChildren.size() == m_aChildNames.size(), "SAL_CALL SbaXFormAdapter::replaceByIndex : inconsistent container state !"); + *(m_aChildren.begin() + _rIndex) = xElement; + *(m_aChildNames.begin() + _rIndex) = sName; + + // correct property change listening + Reference< css::beans::XPropertySet > xOldSet(xOld, UNO_QUERY); + xOldSet->removePropertyChangeListener(PROPERTY_NAME, static_cast<css::beans::XPropertyChangeListener*>(this)); + xElementSet->addPropertyChangeListener(PROPERTY_NAME, static_cast<css::beans::XPropertyChangeListener*>(this)); + + // parent reset + xOld->setParent(Reference< XInterface > ()); + xElement->setParent(static_cast<css::container::XContainer*>(this)); + + // notify container listeners + css::container::ContainerEvent aEvt; + aEvt.Source = *this; + aEvt.Accessor <<= _rIndex; + aEvt.Element <<= xElement; + aEvt.ReplacedElement <<= xOld; + + m_aContainerListeners.notifyEach( &XContainerListener::elementReplaced, aEvt ); +} + +// css::container::XIndexAccess +sal_Int32 SAL_CALL SbaXFormAdapter::getCount() +{ + return m_aChildren.size(); +} + +Any SAL_CALL SbaXFormAdapter::getByIndex(sal_Int32 _rIndex) +{ + if ( ( _rIndex < 0 ) || ( o3tl::make_unsigned(_rIndex) >= m_aChildren.size() ) ) + throw css::lang::IndexOutOfBoundsException(); + + Reference< css::form::XFormComponent > xElement = *(m_aChildren.begin() + _rIndex); + return Any(xElement); +} + +// css::container::XContainer +void SAL_CALL SbaXFormAdapter::addContainerListener(const Reference< css::container::XContainerListener >& xListener) +{ + m_aContainerListeners.addInterface(xListener); +} + +void SAL_CALL SbaXFormAdapter::removeContainerListener(const Reference< css::container::XContainerListener >& xListener) +{ + m_aContainerListeners.removeInterface(xListener); +} + +// css::container::XEnumerationAccess +Reference< css::container::XEnumeration > SAL_CALL SbaXFormAdapter::createEnumeration() +{ + return new ::comphelper::OEnumerationByName(this); +} + +// css::beans::XPropertyChangeListener +void SAL_CALL SbaXFormAdapter::propertyChange(const css::beans::PropertyChangeEvent& evt) +{ + if (evt.PropertyName != PROPERTY_NAME) + return; + + std::vector< css::uno::Reference< css::form::XFormComponent > >::const_iterator aIter = std::find_if( m_aChildren.begin(), + m_aChildren.end(), + [&evt](css::uno::Reference< css::uno::XInterface > const & x) { return x == evt.Source; }); + + if(aIter != m_aChildren.end()) + { + sal_Int32 nPos = aIter - m_aChildren.begin(); + OSL_ENSURE(*(m_aChildNames.begin() + nPos) == ::comphelper::getString(evt.OldValue), "SAL_CALL SbaXFormAdapter::propertyChange : object has a wrong name !"); + *(m_aChildNames.begin() + nPos) = ::comphelper::getString(evt.NewValue); + } +} + +// css::lang::XEventListener +void SAL_CALL SbaXFormAdapter::disposing(const css::lang::EventObject& Source) +{ + // was it our main form ? + if (Source.Source == m_xMainForm) + dispose(); + + std::vector< css::uno::Reference< css::form::XFormComponent > >::const_iterator aIter = std::find_if( m_aChildren.begin(), + m_aChildren.end(), + [&Source](css::uno::Reference< css::uno::XInterface > const & x) { return x == Source.Source; }); + if(aIter != m_aChildren.end()) + removeByIndex(aIter - m_aChildren.begin()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/genericcontroller.cxx b/dbaccess/source/ui/browser/genericcontroller.cxx new file mode 100644 index 000000000..a4b3936b1 --- /dev/null +++ b/dbaccess/source/ui/browser/genericcontroller.cxx @@ -0,0 +1,1217 @@ +/* -*- 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 <dbaccess/genericcontroller.hxx> +#include <browserids.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <dbaccess/dataview.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <vcl/stdtext.hxx> +#include <framework/titlehelper.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/util/URLTransformer.hpp> +#include <com/sun/star/util/XCloseable.hpp> + +#include <com/sun/star/ui/XSidebarProvider.hpp> +#include <sfx2/userinputinterception.hxx> + +#include <datasourceconnector.hxx> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/frame/status/Visibility.hpp> +#include <com/sun/star/frame/XUntitledNumbers.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <limits> +#include <unordered_map> +#include <set> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::frame::status; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::ui; +using namespace ::dbtools; +using namespace ::comphelper; + +#define ALL_FEATURES -1 + +typedef std::unordered_map< sal_Int16, sal_Int16 > CommandHashMap; + +namespace dbaui +{ + +namespace { + +// UserDefinedFeatures +class UserDefinedFeatures +{ +public: + explicit UserDefinedFeatures( const Reference< XController >& _rxController ); + + void execute( const URL& _rFeatureURL, const Sequence< PropertyValue>& _rArgs ); + +private: + css::uno::WeakReference< XController > m_aController; +}; + +} + +UserDefinedFeatures::UserDefinedFeatures( const Reference< XController >& _rxController ) + :m_aController( _rxController ) +{ +} + +void UserDefinedFeatures::execute( const URL& _rFeatureURL, const Sequence< PropertyValue>& _rArgs ) +{ + try + { + Reference< XController > xController( Reference< XController >(m_aController), UNO_SET_THROW ); + Reference< XDispatchProvider > xDispatchProvider( xController->getFrame(), UNO_QUERY_THROW ); + Reference< XDispatch > xDispatch( xDispatchProvider->queryDispatch( + _rFeatureURL, + "_self", + FrameSearchFlag::AUTO + ) ); + + if ( xDispatch == xController ) + { + SAL_WARN("dbaccess.ui", "UserDefinedFeatures::execute: the controller shouldn't be the dispatcher here!" ); + xDispatch.clear(); + } + + if ( xDispatch.is() ) + xDispatch->dispatch( _rFeatureURL, _rArgs ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +// OGenericUnoController_Data +struct OGenericUnoController_Data +{ + ::sfx2::UserInputInterception m_aUserInputInterception; + UserDefinedFeatures m_aUserDefinedFeatures; + + OGenericUnoController_Data( OGenericUnoController& _rController, ::osl::Mutex& _rMutex ) + :m_aUserInputInterception( _rController, _rMutex ) + ,m_aUserDefinedFeatures( _rController.getXController() ) + { + } +}; + +// OGenericUnoController +OGenericUnoController::OGenericUnoController(const Reference< XComponentContext >& _rM) + :OGenericUnoController_Base( getMutex() ) + ,m_pView(nullptr) +#ifdef DBG_UTIL + ,m_bDescribingSupportedFeatures( false ) +#endif + ,m_aAsyncInvalidateAll(LINK(this, OGenericUnoController, OnAsyncInvalidateAll)) + ,m_aAsyncCloseTask(LINK(this, OGenericUnoController, OnAsyncCloseTask)) + ,m_xContext(_rM) + ,m_aCurrentFrame( *this ) + ,m_bPreview(false) + ,m_bReadOnly(false) + ,m_bCurrentlyModified(false) + ,m_bExternalTitle(false) +{ + osl_atomic_increment( &m_refCount ); + { + m_pData.reset( new OGenericUnoController_Data( *this, getMutex() ) ); + } + osl_atomic_decrement( &m_refCount ); + + + try + { + m_xUrlTransformer = URLTransformer::create(_rM); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +OGenericUnoController::~OGenericUnoController() +{ + +} + +bool OGenericUnoController::Construct(vcl::Window* /*pParent*/) +{ + OSL_ENSURE( getView(), "the view is NULL!" ); + + if ( getView() ) + { + getView()->Construct(); + getView()->Show(); + } + + m_aSupportedFeatures.clear(); + fillSupportedFeatures(); + + // create the database context + OSL_ENSURE(getORB().is(), "OGenericUnoController::Construct need a service factory!"); + try + { + m_xDatabaseContext = DatabaseContext::create(getORB()); + } + catch(const Exception&) + { + SAL_WARN("dbaccess.ui","OGenericUnoController::Construct: could not create (or start listening at) the database context!"); + // at least notify the user. Though the whole component does not make any sense without the database context ... + ShowServiceNotAvailableError(getFrameWeld(), u"com.sun.star.sdb.DatabaseContext", true); + } + + return true; +} + +IMPL_LINK_NOARG(OGenericUnoController, OnAsyncInvalidateAll, void*, void) +{ + if ( !OGenericUnoController_Base::rBHelper.bInDispose && !OGenericUnoController_Base::rBHelper.bDisposed ) + InvalidateFeature_Impl(); +} + +void OGenericUnoController::impl_initialize() +{ +} + +void SAL_CALL OGenericUnoController::initialize( const Sequence< Any >& aArguments ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + Reference< XFrame > xFrame; + + PropertyValue aValue; + const Any* pIter = aArguments.getConstArray(); + const Any* pEnd = pIter + aArguments.getLength(); + + for ( ; pIter != pEnd; ++pIter ) + { + if ( ( *pIter >>= aValue ) && aValue.Name == "Frame" ) + { + xFrame.set(aValue.Value,UNO_QUERY_THROW); + } + else if ( ( *pIter >>= aValue ) && aValue.Name == "Preview" ) + { + aValue.Value >>= m_bPreview; + m_bReadOnly = true; + } + } + try + { + if ( !xFrame.is() ) + throw IllegalArgumentException("need a frame", *this, 1 ); + + Reference<XWindow> xParent = xFrame->getContainerWindow(); + VclPtr<vcl::Window> pParentWin = VCLUnoHelper::GetWindow(xParent); + if (!pParentWin) + { + throw IllegalArgumentException("Parent window is null", *this, 1 ); + } + + m_aInitParameters.assign( aArguments ); + Construct( pParentWin ); + + ODataView* pView = getView(); + if ( !pView ) + throw RuntimeException("unable to create a view", *this ); + + if ( m_bReadOnly || m_bPreview ) + pView->EnableInput( false ); + + impl_initialize(); + } + catch(Exception&) + { + // no one clears my view if I won't + m_pView = nullptr; + throw; + } +} + +void SAL_CALL OGenericUnoController::acquire( ) noexcept +{ + OGenericUnoController_Base::acquire(); +} + +void SAL_CALL OGenericUnoController::release( ) noexcept +{ + OGenericUnoController_Base::release(); +} + +void OGenericUnoController::startFrameListening( const Reference< XFrame >& _rxFrame ) +{ + if ( _rxFrame.is() ) + _rxFrame->addFrameActionListener( this ); +} + +void OGenericUnoController::stopFrameListening( const Reference< XFrame >& _rxFrame ) +{ + if ( _rxFrame.is() ) + _rxFrame->removeFrameActionListener( this ); +} + +void OGenericUnoController::disposing(const EventObject& Source) +{ + // our frame ? + if ( Source.Source == getFrame() ) + stopFrameListening( getFrame() ); +} + +void OGenericUnoController::modified(const EventObject& aEvent) +{ + ::osl::MutexGuard aGuard( getMutex() ); + if ( !isDataSourceReadOnly() ) + { + Reference<XModifiable> xModi(aEvent.Source,UNO_QUERY); + if ( xModi.is() ) + m_bCurrentlyModified = xModi->isModified(); // can only be reset by save + else + m_bCurrentlyModified = true; + } + InvalidateFeature(ID_BROWSER_SAVEDOC); + InvalidateFeature(ID_BROWSER_UNDO); +} + +Reference< XWindow > SAL_CALL OGenericUnoController::getComponentWindow() +{ + SolarMutexGuard g; + return VCLUnoHelper::GetInterface( getView() ); +} + +Reference<XSidebarProvider> SAL_CALL OGenericUnoController::getSidebar() +{ + return nullptr; +} + +OUString SAL_CALL OGenericUnoController::getViewControllerName() +{ + return "Default"; +} + +Sequence< PropertyValue > SAL_CALL OGenericUnoController::getCreationArguments() +{ + // currently we do not support any creation args, so anything passed to XModel2::createViewController would be + // lost, so we can equally return an empty sequence here + return Sequence< PropertyValue >(); +} + +void OGenericUnoController::attachFrame( const Reference< XFrame >& _rxFrame ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + stopFrameListening( m_aCurrentFrame.getFrame() ); + Reference< XFrame > xFrame = m_aCurrentFrame.attachFrame( _rxFrame ); + startFrameListening( xFrame ); + + loadMenu( xFrame ); + + if ( getView() ) + getView()->attachFrame( xFrame ); +} + +namespace +{ + typedef std::vector< Any > States; + + void lcl_notifyMultipleStates( XStatusListener& _rListener, FeatureStateEvent& _rEvent, const States& _rStates ) + { + for (auto const& elem : _rStates) + { + _rEvent.State = elem; + _rListener.statusChanged( _rEvent ); + } + } + + void lcl_collectStates( const FeatureState& _rFeatureState, States& _out_rStates ) + { + // order matters, due to a bug in framework which resets the check state when any non-boolean event + // arrives + // #i68215# is the bug to (re-)introduce this "ordered" notification here + // #i67882# is the bug which was caused by the real fix which we did in framework + // #i68216# is the bug which requests to fix the code in Draw which relies on + // framework's implementation details + if ( !!_rFeatureState.sTitle ) + _out_rStates.push_back( Any( *_rFeatureState.sTitle ) ); + if ( !!_rFeatureState.bChecked ) + _out_rStates.push_back( Any( *_rFeatureState.bChecked ) ); + if ( !!_rFeatureState.bInvisible ) + _out_rStates.push_back( Any( Visibility( !*_rFeatureState.bInvisible ) ) ); + if ( _rFeatureState.aValue.hasValue() ) + _out_rStates.push_back( _rFeatureState.aValue ); + if ( _out_rStates.empty() ) + _out_rStates.emplace_back( ); + } +} + +void OGenericUnoController::ImplBroadcastFeatureState(const OUString& _rFeature, const Reference< XStatusListener > & xListener, bool _bIgnoreCache) +{ + sal_uInt16 nFeat = m_aSupportedFeatures[ _rFeature ].nFeatureId; + FeatureState aFeatState( GetState( nFeat ) ); + + FeatureState& rCachedState = m_aStateCache[nFeat]; // creates if necessary + if ( !_bIgnoreCache ) + { + // check if we really need to notify the listeners : this method may be called much more often than needed, so check + // the cached state of the feature + bool bAlreadyCached = ( m_aStateCache.find(nFeat) != m_aStateCache.end() ); + if ( bAlreadyCached ) + if ( ( rCachedState.bEnabled == aFeatState.bEnabled ) + && ( rCachedState.bChecked == aFeatState.bChecked ) + && ( rCachedState.bInvisible == aFeatState.bInvisible ) + && ( rCachedState.sTitle == aFeatState.sTitle ) + ) + return; + } + rCachedState = aFeatState; + + FeatureStateEvent aEvent; + aEvent.FeatureURL.Complete = _rFeature; + if (m_xUrlTransformer.is()) + m_xUrlTransformer->parseStrict(aEvent.FeatureURL); + aEvent.Source = static_cast<XDispatch*>(this); + aEvent.IsEnabled = aFeatState.bEnabled; + + // collect all states to be notified + States aStates; + lcl_collectStates( aFeatState, aStates ); + + // a special listener ? + if ( xListener.is() ) + lcl_notifyMultipleStates( *xListener, aEvent, aStates ); + else + { // no -> iterate through all listeners responsible for the URL + std::set<OUString> aFeatureCommands; + for( const auto& rFeature : m_aSupportedFeatures ) + { + if( rFeature.second.nFeatureId == nFeat ) + aFeatureCommands.insert( rFeature.first ); + } + + // it is possible that listeners are registered or revoked while + // we are notifying them, so we must use a copy of m_arrStatusListener, not + // m_arrStatusListener itself + Dispatch aNotifyLoop( m_arrStatusListener ); + + for (auto const& elem : aNotifyLoop) + { + if ( aFeatureCommands.find( elem.aURL.Complete ) != aFeatureCommands.end() ) + { + aEvent.FeatureURL = elem.aURL; + lcl_notifyMultipleStates( *elem.xListener, aEvent, aStates ); + } + } + } + +} + +bool OGenericUnoController::isFeatureSupported( sal_Int32 _nId ) +{ + SupportedFeatures::const_iterator aFeaturePos = std::find_if( + m_aSupportedFeatures.begin(), + m_aSupportedFeatures.end(), + CompareFeatureById(_nId) + ); + + return ( m_aSupportedFeatures.end() != aFeaturePos && !aFeaturePos->first.isEmpty()); +} + +void OGenericUnoController::InvalidateFeature_Impl() +{ + bool bEmpty = true; + FeatureListener aNextFeature; + { + ::osl::MutexGuard aGuard( m_aFeatureMutex); + bEmpty = m_aFeaturesToInvalidate.empty(); + if (!bEmpty) + aNextFeature = m_aFeaturesToInvalidate.front(); + } + while(!bEmpty) + { + if ( ALL_FEATURES == aNextFeature.nId ) + { + InvalidateAll_Impl(); + break; + } + else + { + SupportedFeatures::const_iterator aFeaturePos = std::find_if( + m_aSupportedFeatures.begin(), + m_aSupportedFeatures.end(), + CompareFeatureById( aNextFeature.nId ) + ); + +#if OSL_DEBUG_LEVEL > 0 + if ( m_aSupportedFeatures.end() == aFeaturePos ) + { + SAL_WARN( "dbaccess.ui", "OGenericUnoController::InvalidateFeature_Impl: feature id " + << aNextFeature.nId + << " has been invalidated, but is not supported!" ); + } +#endif + if ( m_aSupportedFeatures.end() != aFeaturePos ) + // we really know this feature + ImplBroadcastFeatureState( aFeaturePos->first, aNextFeature.xListener, aNextFeature.bForceBroadcast ); + } + + ::osl::MutexGuard aGuard( m_aFeatureMutex); + m_aFeaturesToInvalidate.pop_front(); + bEmpty = m_aFeaturesToInvalidate.empty(); + if (!bEmpty) + aNextFeature = m_aFeaturesToInvalidate.front(); + } +} + +void OGenericUnoController::ImplInvalidateFeature( sal_Int32 _nId, const Reference< XStatusListener >& _xListener, bool _bForceBroadcast ) +{ +#if OSL_DEBUG_LEVEL > 0 + if ( _nId != -1 ) + { + auto isSupportedFeature = std::any_of( + m_aSupportedFeatures.begin(), + m_aSupportedFeatures.end(), + CompareFeatureById( _nId ) + ); + OSL_ENSURE( isSupportedFeature, "OGenericUnoController::ImplInvalidateFeature: invalidating an unsupported feature is suspicious, at least!" ); + } +#endif + + FeatureListener aListener; + aListener.nId = _nId; + aListener.xListener = _xListener; + aListener.bForceBroadcast = _bForceBroadcast; + + bool bWasEmpty; + { + ::osl::MutexGuard aGuard( m_aFeatureMutex ); + bWasEmpty = m_aFeaturesToInvalidate.empty(); + m_aFeaturesToInvalidate.push_back( aListener ); + } + + if ( bWasEmpty ) + m_aAsyncInvalidateAll.Call(); +} + +void OGenericUnoController::InvalidateFeature(sal_uInt16 _nId, const Reference< XStatusListener > & _xListener, bool _bForceBroadcast) +{ + ImplInvalidateFeature( _nId, _xListener, _bForceBroadcast ); +} + +void OGenericUnoController::InvalidateAll() +{ + ImplInvalidateFeature( ALL_FEATURES, nullptr, true ); +} + +void OGenericUnoController::InvalidateAll_Impl() +{ + // invalidate all supported features + for (auto const& supportedFeature : m_aSupportedFeatures) + ImplBroadcastFeatureState( supportedFeature.first, nullptr, true ); + + { + ::osl::MutexGuard aGuard( m_aFeatureMutex); + OSL_ENSURE(m_aFeaturesToInvalidate.size(), "OGenericUnoController::InvalidateAll_Impl: to be called from within InvalidateFeature_Impl only!"); + m_aFeaturesToInvalidate.pop_front(); + if(!m_aFeaturesToInvalidate.empty()) + m_aAsyncInvalidateAll.Call(); + } +} + +Reference< XDispatch > OGenericUnoController::queryDispatch(const URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags) +{ + Reference< XDispatch > xReturn; + + OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::queryDispatch: shouldn't this be filled at construction time?" ); + if ( m_aSupportedFeatures.empty() ) + fillSupportedFeatures(); + + // URL's we can handle ourself? + if ( aURL.Complete == ".uno:FormSlots/ConfirmDeletion" + || ( ( m_aSupportedFeatures.find( aURL.Complete ) != m_aSupportedFeatures.end() ) + && !isUserDefinedFeature( aURL.Complete ) + ) + ) + { + xReturn = this; + } + // no? -> ask the slave dispatcher + else if ( m_xSlaveDispatcher.is() ) + { + xReturn = m_xSlaveDispatcher->queryDispatch(aURL, aTargetFrameName, nSearchFlags); + } + + // outta here + return xReturn; +} + +Sequence< Reference< XDispatch > > OGenericUnoController::queryDispatches(const Sequence< DispatchDescriptor >& aDescripts) +{ + Sequence< Reference< XDispatch > > aReturn; + sal_Int32 nLen = aDescripts.getLength(); + if ( nLen ) + { + aReturn.realloc( nLen ); + Reference< XDispatch >* pReturn = aReturn.getArray(); + const Reference< XDispatch >* pReturnEnd = aReturn.getArray() + nLen; + const DispatchDescriptor* pDescripts = aDescripts.getConstArray(); + + for ( ; pReturn != pReturnEnd; ++ pReturn, ++pDescripts ) + { + *pReturn = queryDispatch( pDescripts->FeatureURL, pDescripts->FrameName, pDescripts->SearchFlags ); + } + } + + return aReturn; +} + +Reference< XDispatchProvider > OGenericUnoController::getSlaveDispatchProvider() +{ + return m_xSlaveDispatcher; +} + +void OGenericUnoController::setSlaveDispatchProvider(const Reference< XDispatchProvider > & _xNewProvider) +{ + m_xSlaveDispatcher = _xNewProvider; +} + +Reference< XDispatchProvider > OGenericUnoController::getMasterDispatchProvider() +{ + return m_xMasterDispatcher; +} + +void OGenericUnoController::setMasterDispatchProvider(const Reference< XDispatchProvider > & _xNewProvider) +{ + m_xMasterDispatcher = _xNewProvider; +} + +void OGenericUnoController::dispatch(const URL& _aURL, const Sequence< PropertyValue >& aArgs) +{ + SolarMutexGuard aSolarGuard; + // The SolarMutex is not locked anymore when the framework calls into + // here. So, lock it ourself. The real solution would be to lock it only in the places + // where it's needed, but a) this might turn out difficult, since we then also need to care + // for locking in the proper order (SolarMutex and m_aMutex), and b) this would be too many places + // for the time frame of the fix. + // #i52602# + executeChecked(_aURL,aArgs); +} + +void OGenericUnoController::addStatusListener(const Reference< XStatusListener > & aListener, const URL& _rURL) +{ + // parse the URL now and here, this saves later parsing in each notification round + URL aParsedURL( _rURL ); + if ( m_xUrlTransformer.is() ) + m_xUrlTransformer->parseStrict( aParsedURL ); + + // remember the listener together with the URL + m_arrStatusListener.insert( m_arrStatusListener.end(), DispatchTarget( aParsedURL, aListener ) ); + + // initially broadcast the state + ImplBroadcastFeatureState( aParsedURL.Complete, aListener, true ); + // force the new state to be broadcast to the new listener +} + +void OGenericUnoController::removeStatusListener(const Reference< XStatusListener > & aListener, const URL& _rURL) +{ + if (_rURL.Complete.isEmpty()) + { + m_arrStatusListener.erase(std::remove_if(m_arrStatusListener.begin(), m_arrStatusListener.end(), + [&aListener](const DispatchTarget& rCurrent) { return rCurrent.xListener == aListener; }), + m_arrStatusListener.end()); + } + else + { + // remove the listener only for the given URL + Dispatch::iterator iterSearch = std::find_if(m_arrStatusListener.begin(), m_arrStatusListener.end(), + [&aListener, &_rURL](const DispatchTarget& rCurrent) { + return (rCurrent.xListener == aListener) && (rCurrent.aURL.Complete == _rURL.Complete); }); + if (iterSearch != m_arrStatusListener.end()) + m_arrStatusListener.erase(iterSearch); + } + + OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::removeStatusListener: shouldn't this be filled at construction time?" ); + if ( m_aSupportedFeatures.empty() ) + fillSupportedFeatures(); + + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find(_rURL.Complete); + if (aIter != m_aSupportedFeatures.end()) + { // clear the cache for that feature + StateCache::const_iterator aCachePos = m_aStateCache.find( aIter->second.nFeatureId ); + if ( aCachePos != m_aStateCache.end() ) + m_aStateCache.erase( aCachePos ); + } + + // now remove the listener from the deque + ::osl::MutexGuard aGuard( m_aFeatureMutex ); + m_aFeaturesToInvalidate.erase( + std::remove_if( m_aFeaturesToInvalidate.begin(), + m_aFeaturesToInvalidate.end(), + FindFeatureListener(aListener)) + ,m_aFeaturesToInvalidate.end()); +} + +void OGenericUnoController::releaseNumberForComponent() +{ + try + { + Reference< XUntitledNumbers > xUntitledProvider(getPrivateModel(), UNO_QUERY ); + if ( xUntitledProvider.is() ) + xUntitledProvider->releaseNumberForComponent(static_cast<XWeak*>(this)); + } + catch( const Exception& ) + { + // NII + } +} + +void OGenericUnoController::disposing() +{ + { + EventObject aDisposeEvent; + aDisposeEvent.Source = static_cast<XWeak*>(this); + Dispatch aStatusListener = m_arrStatusListener; + for (auto const& statusListener : aStatusListener) + { + statusListener.xListener->disposing(aDisposeEvent); + } + m_arrStatusListener.clear(); + } + + m_xDatabaseContext = nullptr; + { + ::osl::MutexGuard aGuard( m_aFeatureMutex); + m_aAsyncInvalidateAll.CancelCall(); + m_aFeaturesToInvalidate.clear(); + } + + releaseNumberForComponent(); + + // check out from all the objects we are listening + // the frame + stopFrameListening( m_aCurrentFrame.getFrame() ); + m_aCurrentFrame.attachFrame( nullptr ); + + m_xMasterDispatcher = nullptr; + m_xSlaveDispatcher = nullptr; + m_xTitleHelper.clear(); + m_xUrlTransformer.clear(); + m_aInitParameters.clear(); +} + +void SAL_CALL OGenericUnoController::addEventListener( const Reference< XEventListener >& xListener ) +{ + // disambiguate + OGenericUnoController_Base::WeakComponentImplHelperBase::addEventListener( xListener ); +} + +void SAL_CALL OGenericUnoController::removeEventListener( const Reference< XEventListener >& xListener ) +{ + // disambiguate + OGenericUnoController_Base::WeakComponentImplHelperBase::removeEventListener( xListener ); +} + +void OGenericUnoController::frameAction(const FrameActionEvent& aEvent) +{ + ::osl::MutexGuard aGuard( getMutex() ); + if ( aEvent.Frame == m_aCurrentFrame.getFrame() ) + m_aCurrentFrame.frameAction( aEvent.Action ); +} + +void OGenericUnoController::implDescribeSupportedFeature( const OUString& _rCommandURL, + sal_uInt16 _nFeatureId, sal_Int16 _nCommandGroup ) +{ +#ifdef DBG_UTIL + OSL_ENSURE( m_bDescribingSupportedFeatures, "OGenericUnoController::implDescribeSupportedFeature: bad timing for this call!" ); +#endif + OSL_PRECOND( _nFeatureId < ( std::numeric_limits< sal_uInt16 >::max() - 1000 ), // FIRST_USER_DEFINED_FEATURE + "OGenericUnoController::implDescribeSupportedFeature: invalid feature id!" ); + + ControllerFeature aFeature; + aFeature.Command = _rCommandURL; + aFeature.nFeatureId = _nFeatureId; + aFeature.GroupId = _nCommandGroup; + +#if OSL_DEBUG_LEVEL > 0 + OSL_ENSURE( m_aSupportedFeatures.find( aFeature.Command ) == m_aSupportedFeatures.end(), + "OGenericUnoController::implDescribeSupportedFeature: this feature is already there!" ); +#endif + m_aSupportedFeatures[ aFeature.Command ] = aFeature; +} + +void OGenericUnoController::describeSupportedFeatures() +{ + // add all supported features + implDescribeSupportedFeature( ".uno:Copy", ID_BROWSER_COPY, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Cut", ID_BROWSER_CUT, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Paste", ID_BROWSER_PASTE, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:ClipboardFormatItems", ID_BROWSER_CLIPBOARD_FORMAT_ITEMS ); + implDescribeSupportedFeature( ".uno:DSBEditDoc", ID_BROWSER_EDITDOC, CommandGroup::DOCUMENT ); +} + +FeatureState OGenericUnoController::GetState( sal_uInt16 _nId ) const +{ + FeatureState aReturn; + // (disabled automatically) + + switch ( _nId ) + { + case ID_BROWSER_UNDO: + case ID_BROWSER_SAVEDOC: + aReturn.bEnabled = true; + break; + default: + // for now, enable all the time + // TODO: we should ask the dispatcher. However, this is laborious, since you cannot ask a dispatcher + // directly, but need to add a status listener. + aReturn.bEnabled = true; + break; + } + + return aReturn; +} + +void OGenericUnoController::Execute( sal_uInt16 _nId, const Sequence< PropertyValue>& _rArgs ) +{ + OSL_ENSURE( isUserDefinedFeature( _nId ), + "OGenericUnoController::Execute: responsible for user defined features only!" ); + + // user defined features can be handled by dispatch interceptors resp. protocol handlers only. + // So, we need to do a queryDispatch, and dispatch the URL + m_pData->m_aUserDefinedFeatures.execute( getURLForId( _nId ), _rArgs ); +} + +URL OGenericUnoController::getURLForId(sal_Int32 _nId) const +{ + URL aReturn; + if ( m_xUrlTransformer.is() ) + { + SupportedFeatures::const_iterator aIter = std::find_if( + m_aSupportedFeatures.begin(), + m_aSupportedFeatures.end(), + CompareFeatureById( _nId ) + ); + + if ( m_aSupportedFeatures.end() != aIter && !aIter->first.isEmpty() ) + { + aReturn.Complete = aIter->first; + m_xUrlTransformer->parseStrict( aReturn ); + } + } + return aReturn; +} + +bool OGenericUnoController::isUserDefinedFeature( const sal_uInt16 _nFeatureId ) +{ + return + (_nFeatureId >= ( std::numeric_limits< sal_uInt16 >::max() - 1000 )) // test if >= FIRST_USER_DEFINED_FEATURE + && + ( _nFeatureId < (std::numeric_limits< sal_uInt16 >::max())) // test if < LAST_USER_DEFINED_FEATURE + ; +} + +bool OGenericUnoController::isUserDefinedFeature( const OUString& _rFeatureURL ) const +{ + SupportedFeatures::const_iterator pos = m_aSupportedFeatures.find( _rFeatureURL ); + OSL_PRECOND( pos != m_aSupportedFeatures.end(), + "OGenericUnoController::isUserDefinedFeature: this is no supported feature at all!" ); + + return ( pos != m_aSupportedFeatures.end() ) && isUserDefinedFeature( pos->second.nFeatureId ); +} + +sal_Bool SAL_CALL OGenericUnoController::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +void OGenericUnoController::startConnectionListening(const Reference< XConnection >& _rxConnection) +{ + // we have to remove ourself before disposing the connection + Reference< XComponent > xComponent(_rxConnection, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(static_cast<XFrameActionListener*>(this)); +} + +void OGenericUnoController::stopConnectionListening(const Reference< XConnection >& _rxConnection) +{ + // we have to remove ourself before disposing the connection + Reference< XComponent > xComponent(_rxConnection, UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener(static_cast<XFrameActionListener*>(this)); +} + +Reference< XConnection > OGenericUnoController::connect( const Reference< XDataSource>& _xDataSource ) +{ + weld::WaitObject aWaitCursor(getFrameWeld()); + + ODatasourceConnector aConnector( getORB(), getFrameWeld(), OUString() ); + Reference< XConnection > xConnection = aConnector.connect( _xDataSource, nullptr ); + startConnectionListening( xConnection ); + + return xConnection; +} + +Reference< XConnection > OGenericUnoController::connect( const OUString& _rDataSourceName, + const OUString& _rContextInformation, ::dbtools::SQLExceptionInfo* _pErrorInfo ) +{ + weld::WaitObject aWaitCursor(getFrameWeld()); + + ODatasourceConnector aConnector( getORB(), getFrameWeld(), _rContextInformation ); + Reference<XConnection> xConnection = aConnector.connect( _rDataSourceName, _pErrorInfo ); + startConnectionListening( xConnection ); + + return xConnection; +} + +void OGenericUnoController::setView( const VclPtr<ODataView> &i_rView ) +{ + m_pView = i_rView; +} + +void OGenericUnoController::clearView() +{ + m_pView = nullptr; +} + +void OGenericUnoController::showError(const SQLExceptionInfo& _rInfo) +{ + ::dbtools::showError(_rInfo,VCLUnoHelper::GetInterface(getView()),getORB()); +} + +Reference< XLayoutManager > OGenericUnoController::getLayoutManager(const Reference< XFrame >& _xFrame) +{ + Reference< XPropertySet > xPropSet( _xFrame, UNO_QUERY ); + Reference< XLayoutManager > xLayoutManager; + if ( xPropSet.is() ) + { + try + { + xLayoutManager.set(xPropSet->getPropertyValue("LayoutManager"),UNO_QUERY); + } + catch ( Exception& ) + { + } + } + return xLayoutManager; +} + +void OGenericUnoController::loadMenu(const Reference< XFrame >& _xFrame) +{ + Reference< XLayoutManager > xLayoutManager = getLayoutManager(_xFrame); + if ( xLayoutManager.is() ) + { + xLayoutManager->lock(); + xLayoutManager->createElement( "private:resource/menubar/menubar" ); + xLayoutManager->createElement( "private:resource/toolbar/toolbar" ); + xLayoutManager->unlock(); + xLayoutManager->doLayout(); + } + + onLoadedMenu( xLayoutManager ); +} + +void OGenericUnoController::onLoadedMenu(const Reference< XLayoutManager >& /*_xLayoutManager*/) +{ + // not interested in +} + +void OGenericUnoController::closeTask() +{ + m_aAsyncCloseTask.Call(); +} + +IMPL_LINK_NOARG(OGenericUnoController, OnAsyncCloseTask, void*, void) +{ + if ( !OGenericUnoController_Base::rBHelper.bInDispose ) + { + try + { + Reference< util::XCloseable > xCloseable( m_aCurrentFrame.getFrame(), UNO_QUERY_THROW ); + xCloseable->close( false ); // false - holds the owner ship for this frame inside this object! + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } +} + +Any SAL_CALL OGenericUnoController::getViewData() +{ + return Any(); +} + +void SAL_CALL OGenericUnoController::restoreViewData(const Any& /*Data*/) +{ +} + +Reference< XModel > SAL_CALL OGenericUnoController::getModel() +{ + return Reference< XModel >(); +} + +Reference< XFrame > SAL_CALL OGenericUnoController::getFrame() +{ + ::osl::MutexGuard aGuard( getMutex() ); + return m_aCurrentFrame.getFrame(); +} + +sal_Bool SAL_CALL OGenericUnoController::attachModel(const Reference< XModel > & /*xModel*/) +{ + SAL_WARN("dbaccess.ui", "OGenericUnoController::attachModel: not supported!" ); + return false; +} + +void OGenericUnoController::executeUnChecked(sal_uInt16 _nCommandId, const Sequence< PropertyValue >& aArgs) +{ + Execute(_nCommandId, aArgs); +} + +void OGenericUnoController::executeUnChecked(const util::URL& _rCommand, const Sequence< PropertyValue >& aArgs) +{ + OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::executeUnChecked: shouldn't this be filled at construction time?" ); + if ( m_aSupportedFeatures.empty() ) + fillSupportedFeatures(); + + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( _rCommand.Complete ); + if (aIter != m_aSupportedFeatures.end()) + Execute( aIter->second.nFeatureId, aArgs ); +} + +void OGenericUnoController::executeChecked(const util::URL& _rCommand, const Sequence< PropertyValue >& aArgs) +{ + OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::executeChecked: shouldn't this be filled at construction time?" ); + if ( m_aSupportedFeatures.empty() ) + fillSupportedFeatures(); + + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( _rCommand.Complete ); + if ( aIter != m_aSupportedFeatures.end() ) + { + sal_uInt16 nFeatureId = aIter->second.nFeatureId; + if ( GetState( nFeatureId ).bEnabled ) + Execute( nFeatureId, aArgs ); + } +} + +Reference< awt::XWindow> OGenericUnoController::getTopMostContainerWindow() const +{ + Reference< css::awt::XWindow> xWindow; + + // get the top most window + Reference< XFrame > xFrame( m_aCurrentFrame.getFrame() ); + if ( xFrame.is() ) + { + xWindow = xFrame->getContainerWindow(); + + while ( xFrame.is() && !xFrame->isTop() ) + { + xFrame = xFrame->getCreator(); + } + if ( xFrame.is() ) + xWindow = xFrame->getContainerWindow(); + } + return xWindow; +} + +Reference< XTitle > OGenericUnoController::impl_getTitleHelper_throw(bool bCreateIfNecessary) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + if (!m_xTitleHelper.is() && bCreateIfNecessary) + { + Reference< XUntitledNumbers > xUntitledProvider(getPrivateModel(), UNO_QUERY ); + + m_xTitleHelper = new ::framework::TitleHelper( m_xContext, Reference< XController >(this), xUntitledProvider ); + } + + return m_xTitleHelper; +} + +// XTitle +OUString SAL_CALL OGenericUnoController::getTitle() +{ + ::osl::MutexGuard aGuard( getMutex() ); + if ( m_bExternalTitle ) + return impl_getTitleHelper_throw()->getTitle (); + return getPrivateTitle() + impl_getTitleHelper_throw()->getTitle (); +} + +// XTitle +void SAL_CALL OGenericUnoController::setTitle(const OUString& sTitle) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + m_bExternalTitle = true; + impl_getTitleHelper_throw()->setTitle (sTitle); +} + +// XTitleChangeBroadcaster +void SAL_CALL OGenericUnoController::addTitleChangeListener(const Reference< XTitleChangeListener >& xListener) +{ + Reference< XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper_throw(), UNO_QUERY); + if (xBroadcaster.is ()) + xBroadcaster->addTitleChangeListener (xListener); +} + +void SAL_CALL OGenericUnoController::removeTitleChangeListener(const Reference< XTitleChangeListener >& xListener) +{ + Reference< XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper_throw(false), UNO_QUERY); + if (xBroadcaster.is ()) + xBroadcaster->removeTitleChangeListener (xListener); +} + +// XUserInputInterception +void SAL_CALL OGenericUnoController::addKeyHandler( const Reference< XKeyHandler >& _rxHandler ) +{ + if ( _rxHandler.is() ) + m_pData->m_aUserInputInterception.addKeyHandler( _rxHandler ); +} + +void SAL_CALL OGenericUnoController::removeKeyHandler( const Reference< XKeyHandler >& _rxHandler ) +{ + m_pData->m_aUserInputInterception.removeKeyHandler( _rxHandler ); +} + +void SAL_CALL OGenericUnoController::addMouseClickHandler( const Reference< XMouseClickHandler >& _rxHandler ) +{ + if ( _rxHandler.is() ) + m_pData->m_aUserInputInterception.addMouseClickHandler( _rxHandler ); +} + +void SAL_CALL OGenericUnoController::removeMouseClickHandler( const Reference< XMouseClickHandler >& _rxHandler ) +{ + m_pData->m_aUserInputInterception.removeMouseClickHandler( _rxHandler ); +} + +void OGenericUnoController::executeChecked(sal_uInt16 _nCommandId, const Sequence< PropertyValue >& aArgs) +{ + if ( isCommandEnabled(_nCommandId) ) + Execute(_nCommandId, aArgs); +} + +bool OGenericUnoController::isCommandEnabled(sal_uInt16 _nCommandId) const +{ + return GetState( _nCommandId ).bEnabled; +} + +bool OGenericUnoController::isDataSourceReadOnly() const +{ + return false; +} + +Reference< XController > OGenericUnoController::getXController() +{ + return this; +} + +bool OGenericUnoController::interceptUserInput( const NotifyEvent& _rEvent ) +{ + return m_pData->m_aUserInputInterception.handleNotifyEvent( _rEvent ); +} + +bool OGenericUnoController::isCommandChecked(sal_uInt16 _nCommandId) const +{ + FeatureState aState = GetState( _nCommandId ); + + return aState.bChecked && *aState.bChecked; +} + +bool OGenericUnoController::isCommandEnabled( const OUString& _rCompleteCommandURL ) const +{ + OSL_ENSURE( !_rCompleteCommandURL.isEmpty(), "OGenericUnoController::isCommandEnabled: Empty command url!" ); + + bool bIsEnabled = false; + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( _rCompleteCommandURL ); + if ( aIter != m_aSupportedFeatures.end() ) + bIsEnabled = isCommandEnabled( aIter->second.nFeatureId ); + + return bIsEnabled; +} + +Sequence< ::sal_Int16 > SAL_CALL OGenericUnoController::getSupportedCommandGroups() +{ + CommandHashMap aCmdHashMap; + for (auto const& supportedFeature : m_aSupportedFeatures) + if ( supportedFeature.second.GroupId != CommandGroup::INTERNAL ) + aCmdHashMap.emplace( supportedFeature.second.GroupId, 0 ); + + return comphelper::mapKeysToSequence( aCmdHashMap ); +} + +Sequence< DispatchInformation > SAL_CALL OGenericUnoController::getConfigurableDispatchInformation( ::sal_Int16 CommandGroup ) +{ + std::vector< DispatchInformation > aInformationVector; + for (auto const& supportedFeature : m_aSupportedFeatures) + { + if ( sal_Int16( supportedFeature.second.GroupId ) == CommandGroup ) + { + aInformationVector.push_back( supportedFeature.second ); + } + } + + return comphelper::containerToSequence( aInformationVector ); +} + +void OGenericUnoController::fillSupportedFeatures() +{ +#ifdef DBG_UTIL + m_bDescribingSupportedFeatures = true; +#endif + describeSupportedFeatures(); +#ifdef DBG_UTIL + m_bDescribingSupportedFeatures = false; +#endif +} + +void SAL_CALL OGenericUnoController::dispose() +{ + SolarMutexGuard aSolarGuard; + OGenericUnoController_Base::dispose(); +} + +weld::Window* OGenericUnoController::getFrameWeld() const +{ + return m_pView ? m_pView->GetFrameWeld() : nullptr; +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/sbagrid.cxx b/dbaccess/source/ui/browser/sbagrid.cxx new file mode 100644 index 000000000..d1adbea01 --- /dev/null +++ b/dbaccess/source/ui/browser/sbagrid.cxx @@ -0,0 +1,1364 @@ +/* -*- 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 <core_resource.hxx> + +#include <sot/exchange.hxx> + +#include <svx/dbaexchange.hxx> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> + +#include <sbagrid.hxx> +#include <dlgsize.hxx> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> + +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/awt/XTextComponent.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <tools/diagnose_ex.h> + +#include <svl/numuno.hxx> +#include <toolkit/helper/vclunohelper.hxx> + +#include <vcl/svapp.hxx> + +#include <cppuhelper/queryinterface.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/types.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <strings.hrc> +#include <strings.hxx> +#include <dbexchange.hxx> +#include <svtools/stringtransfer.hxx> +#include <UITools.hxx> +#include <TokenWriter.hxx> +#include <osl/diagnose.h> +#include <algorithm> + +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::uno; +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::datatransfer; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::view; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::util; +using namespace ::dbaui; +using namespace ::dbtools; +using namespace ::svx; +using namespace ::svt; + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_dbu_SbaXGridControl_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new SbaXGridControl(context)); +} + +css::uno::Sequence<OUString> SAL_CALL SbaXGridControl::getSupportedServiceNames() +{ + return { "com.sun.star.form.control.InteractionGridControl", "com.sun.star.form.control.GridControl", + "com.sun.star.awt.UnoControl" }; +} + + +// SbaXGridControl + +OUString SAL_CALL SbaXGridControl::getImplementationName() +{ + return "com.sun.star.comp.dbu.SbaXGridControl"; +} + +SbaXGridControl::SbaXGridControl(const Reference< XComponentContext >& _rM) + : FmXGridControl(_rM) +{ +} + +SbaXGridControl::~SbaXGridControl() +{ +} + +rtl::Reference<FmXGridPeer> SbaXGridControl::imp_CreatePeer(vcl::Window* pParent) +{ + rtl::Reference<FmXGridPeer> pReturn = new SbaXGridPeer(m_xContext); + + // translate properties into WinBits + WinBits nStyle = WB_TABSTOP; + Reference< XPropertySet > xModelSet(getModel(), UNO_QUERY); + if (xModelSet.is()) + { + try + { + if (::comphelper::getINT16(xModelSet->getPropertyValue(PROPERTY_BORDER))) + nStyle |= WB_BORDER; + } + catch(Exception&) + { + } + + } + + pReturn->Create(pParent, nStyle); + return pReturn; +} + +Any SAL_CALL SbaXGridControl::queryInterface(const Type& _rType) +{ + Any aRet = FmXGridControl::queryInterface(_rType); + return aRet.hasValue() ? aRet : ::cppu::queryInterface(_rType,static_cast<css::frame::XDispatch*>(this)); +} + +Sequence< Type > SAL_CALL SbaXGridControl::getTypes( ) +{ + return comphelper::concatSequences( + FmXGridControl::getTypes(), + Sequence { cppu::UnoType<css::frame::XDispatch>::get() }); +} + +Sequence< sal_Int8 > SAL_CALL SbaXGridControl::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +void SAL_CALL SbaXGridControl::createPeer(const Reference< css::awt::XToolkit > & rToolkit, const Reference< css::awt::XWindowPeer > & rParentPeer) +{ + FmXGridControl::createPeer(rToolkit, rParentPeer); + + OSL_ENSURE(!mbCreatingPeer, "FmXGridControl::createPeer : recursion!"); + // see the base class' createPeer for a comment on this + + // TODO: why the hell this whole class does not use any mutex? + + Reference< css::frame::XDispatch > xDisp(getPeer(), UNO_QUERY); + for (auto const& elem : m_aStatusMultiplexer) + { + if (elem.second.is() && elem.second->getLength()) + xDisp->addStatusListener(elem.second, elem.first); + } +} + +void SAL_CALL SbaXGridControl::dispatch(const css::util::URL& aURL, const Sequence< PropertyValue >& aArgs) +{ + Reference< css::frame::XDispatch > xDisp(getPeer(), UNO_QUERY); + if (xDisp.is()) + xDisp->dispatch(aURL, aArgs); +} + +void SAL_CALL SbaXGridControl::addStatusListener( const Reference< XStatusListener > & _rxListener, const URL& _rURL ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + if ( !_rxListener.is() ) + return; + + rtl::Reference<SbaXStatusMultiplexer>& xMultiplexer = m_aStatusMultiplexer[ _rURL ]; + if ( !xMultiplexer.is() ) + { + xMultiplexer = new SbaXStatusMultiplexer( *this, GetMutex() ); + } + + xMultiplexer->addInterface( _rxListener ); + if ( getPeer().is() ) + { + if ( 1 == xMultiplexer->getLength() ) + { // the first external listener for this URL + Reference< XDispatch > xDisp( getPeer(), UNO_QUERY ); + xDisp->addStatusListener( xMultiplexer, _rURL ); + } + else + { // already have other listeners for this URL + _rxListener->statusChanged( xMultiplexer->getLastEvent() ); + } + } +} + +void SAL_CALL SbaXGridControl::removeStatusListener(const Reference< css::frame::XStatusListener > & _rxListener, const css::util::URL& _rURL) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + + rtl::Reference<SbaXStatusMultiplexer>& xMultiplexer = m_aStatusMultiplexer[_rURL]; + if (!xMultiplexer.is()) + { + xMultiplexer = new SbaXStatusMultiplexer(*this,GetMutex()); + } + + if (getPeer().is() && xMultiplexer->getLength() == 1) + { + Reference< css::frame::XDispatch > xDisp(getPeer(), UNO_QUERY); + xDisp->removeStatusListener(xMultiplexer, _rURL); + } + xMultiplexer->removeInterface( _rxListener ); +} + +void SAL_CALL SbaXGridControl::dispose() +{ + SolarMutexGuard aGuard; + + EventObject aEvt; + aEvt.Source = *this; + + for (auto & elem : m_aStatusMultiplexer) + { + if (elem.second.is()) + { + elem.second->disposeAndClear(aEvt); + elem.second.clear(); + } + } + StatusMultiplexerArray().swap(m_aStatusMultiplexer); + + FmXGridControl::dispose(); +} + +// SbaXGridPeer +SbaXGridPeer::SbaXGridPeer(const Reference< XComponentContext >& _rM) +: FmXGridPeer(_rM) +,m_aStatusListeners(m_aMutex) +{ +} + +SbaXGridPeer::~SbaXGridPeer() +{ +} + +void SAL_CALL SbaXGridPeer::dispose() +{ + EventObject aEvt(*this); + + m_aStatusListeners.disposeAndClear(aEvt); + + FmXGridPeer::dispose(); +} + +void SbaXGridPeer::NotifyStatusChanged(const css::util::URL& _rUrl, const Reference< css::frame::XStatusListener > & xControl) +{ + VclPtr< SbaGridControl > pGrid = GetAs< SbaGridControl >(); + if (!pGrid) + return; + + css::frame::FeatureStateEvent aEvt; + aEvt.Source = *this; + aEvt.IsEnabled = !pGrid->IsReadOnlyDB(); + aEvt.FeatureURL = _rUrl; + + MapDispatchToBool::const_iterator aURLStatePos = m_aDispatchStates.find( classifyDispatchURL( _rUrl ) ); + if ( m_aDispatchStates.end() != aURLStatePos ) + aEvt.State <<= aURLStatePos->second; + else + aEvt.State <<= false; + + if (xControl.is()) + xControl->statusChanged(aEvt); + else + { + ::comphelper::OInterfaceContainerHelper3<css::frame::XStatusListener> * pIter + = m_aStatusListeners.getContainer(_rUrl); + + if (pIter) + { + pIter->notifyEach( &XStatusListener::statusChanged, aEvt ); + } + } +} + +Any SAL_CALL SbaXGridPeer::queryInterface(const Type& _rType) +{ + Any aRet = ::cppu::queryInterface(_rType,static_cast<css::frame::XDispatch*>(this)); + if(aRet.hasValue()) + return aRet; + return FmXGridPeer::queryInterface(_rType); +} + +Reference< css::frame::XDispatch > SAL_CALL SbaXGridPeer::queryDispatch(const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags) +{ + if ( ( aURL.Complete == ".uno:GridSlots/BrowserAttribs" ) || ( aURL.Complete == ".uno:GridSlots/RowHeight" ) + || ( aURL.Complete == ".uno:GridSlots/ColumnAttribs" ) || ( aURL.Complete == ".uno:GridSlots/ColumnWidth" ) + ) + { + return static_cast<css::frame::XDispatch*>(this); + } + + return FmXGridPeer::queryDispatch(aURL, aTargetFrameName, nSearchFlags); +} + +IMPL_LINK_NOARG( SbaXGridPeer, OnDispatchEvent, void*, void ) +{ + VclPtr< SbaGridControl > pGrid = GetAs< SbaGridControl >(); + if ( !pGrid ) // if this fails, we were disposing before arriving here + return; + + if ( !Application::IsMainThread() ) + { + // still not in the main thread (see SbaXGridPeer::dispatch). post an event, again + // without moving the special even to the back of the queue + pGrid->PostUserEvent( LINK( this, SbaXGridPeer, OnDispatchEvent ) ); + } + else + { + DispatchArgs aArgs = m_aDispatchArgs.front(); + m_aDispatchArgs.pop(); + + SbaXGridPeer::dispatch( aArgs.aURL, aArgs.aArgs ); + } +} + +SbaXGridPeer::DispatchType SbaXGridPeer::classifyDispatchURL( const URL& _rURL ) +{ + DispatchType eURLType = dtUnknown; + if ( _rURL.Complete == ".uno:GridSlots/BrowserAttribs" ) + eURLType = dtBrowserAttribs; + else if ( _rURL.Complete == ".uno:GridSlots/RowHeight" ) + eURLType = dtRowHeight; + else if ( _rURL.Complete == ".uno:GridSlots/ColumnAttribs" ) + eURLType = dtColumnAttribs; + else if ( _rURL.Complete == ".uno:GridSlots/ColumnWidth" ) + eURLType = dtColumnWidth; + return eURLType; +} + +void SAL_CALL SbaXGridPeer::dispatch(const URL& aURL, const Sequence< PropertyValue >& aArgs) +{ + VclPtr< SbaGridControl > pGrid = GetAs< SbaGridControl >(); + if (!pGrid) + return; + + if ( !Application::IsMainThread() ) + { + // we're not in the main thread. This is bad, as we want to raise windows here, + // and VCL does not like windows to be opened in non-main threads (at least on Win32). + // Okay, do this async. No problem with this, as XDispatch::dispatch is defined to be + // a one-way method. + + // save the args + DispatchArgs aDispatchArgs; + aDispatchArgs.aURL = aURL; + aDispatchArgs.aArgs = aArgs; + m_aDispatchArgs.push( aDispatchArgs ); + + // post an event + // we use the Window::PostUserEvent here, instead of the application::PostUserEvent + // this saves us from keeping track of these events - as soon as the window dies, + // the events are deleted automatically. For the application way, we would need to + // do this ourself. + // As we use our grid as window, and the grid dies before we die, this should be no problem. + pGrid->PostUserEvent( LINK( this, SbaXGridPeer, OnDispatchEvent ) ); + return; + } + + SolarMutexGuard aGuard; + sal_Int16 nColId = -1; + for (const PropertyValue& rArg : aArgs) + { + if (rArg.Name == "ColumnViewPos") + { + nColId = pGrid->GetColumnIdFromViewPos(::comphelper::getINT16(rArg.Value)); + break; + } + if (rArg.Name == "ColumnModelPos") + { + nColId = pGrid->GetColumnIdFromModelPos(::comphelper::getINT16(rArg.Value)); + break; + } + if (rArg.Name == "ColumnId") + { + nColId = ::comphelper::getINT16(rArg.Value); + break; + } + } + + DispatchType eURLType = classifyDispatchURL( aURL ); + + if ( dtUnknown == eURLType ) + return; + + // notify any status listeners that the dialog is now active (well, about to be active) + MapDispatchToBool::const_iterator aThisURLState = m_aDispatchStates.emplace( eURLType, true ).first; + NotifyStatusChanged( aURL, nullptr ); + + // execute the dialog + switch ( eURLType ) + { + case dtBrowserAttribs: + pGrid->SetBrowserAttrs(); + break; + + case dtRowHeight: + pGrid->SetRowHeight(); + break; + + case dtColumnAttribs: + { + OSL_ENSURE(nColId != -1, "SbaXGridPeer::dispatch : invalid parameter !"); + if (nColId != -1) + break; + pGrid->SetColAttrs(nColId); + } + break; + + case dtColumnWidth: + { + OSL_ENSURE(nColId != -1, "SbaXGridPeer::dispatch : invalid parameter !"); + if (nColId != -1) + break; + pGrid->SetColWidth(nColId); + } + break; + + case dtUnknown: + break; + } + + // notify any status listeners that the dialog vanished + m_aDispatchStates.erase( aThisURLState ); + NotifyStatusChanged( aURL, nullptr ); +} + +void SAL_CALL SbaXGridPeer::addStatusListener(const Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) +{ + ::comphelper::OInterfaceContainerHelper3< css::frame::XStatusListener >* pCont + = m_aStatusListeners.getContainer(aURL); + if (!pCont) + m_aStatusListeners.addInterface(aURL,xControl); + else + pCont->addInterface(xControl); + NotifyStatusChanged(aURL, xControl); +} + +void SAL_CALL SbaXGridPeer::removeStatusListener(const Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) +{ + ::comphelper::OInterfaceContainerHelper3< css::frame::XStatusListener >* pCont = m_aStatusListeners.getContainer(aURL); + if ( pCont ) + pCont->removeInterface(xControl); +} + +Sequence< Type > SAL_CALL SbaXGridPeer::getTypes() +{ + return comphelper::concatSequences( + FmXGridPeer::getTypes(), + Sequence { cppu::UnoType<css::frame::XDispatch>::get() }); +} + +UNO3_GETIMPLEMENTATION2_IMPL(SbaXGridPeer, FmXGridPeer); + +VclPtr<FmGridControl> SbaXGridPeer::imp_CreateControl(vcl::Window* pParent, WinBits nStyle) +{ + return VclPtr<SbaGridControl>::Create( m_xContext, pParent, this, nStyle); +} + +// SbaGridHeader + +SbaGridHeader::SbaGridHeader(BrowseBox* pParent) + :FmGridHeader(pParent, WB_STDHEADERBAR | WB_DRAG) + ,DragSourceHelper(this) +{ +} + +SbaGridHeader::~SbaGridHeader() +{ + disposeOnce(); +} + +void SbaGridHeader::dispose() +{ + DragSourceHelper::dispose(); + FmGridHeader::dispose(); +} + +void SbaGridHeader::StartDrag( sal_Int8 _nAction, const Point& _rPosPixel ) +{ + SolarMutexGuard aGuard; + // in the new DnD API, the solar mutex is not locked when StartDrag is called + + ImplStartColumnDrag( _nAction, _rPosPixel ); +} + +void SbaGridHeader::MouseButtonDown( const MouseEvent& _rMEvt ) +{ + if (_rMEvt.IsLeft()) + if (_rMEvt.GetClicks() != 2) + { + // the base class will start a column move here, which we don't want to allow + // (at the moment. If we store relative positions with the columns, we can allow column moves...) + + } + + FmGridHeader::MouseButtonDown(_rMEvt); +} + +void SbaGridHeader::ImplStartColumnDrag(sal_Int8 _nAction, const Point& _rMousePos) +{ + sal_uInt16 nId = GetItemId(_rMousePos); + bool bResizingCol = false; + if (HEADERBAR_ITEM_NOTFOUND != nId) + { + tools::Rectangle aColRect = GetItemRect(nId); + aColRect.AdjustLeft(nId ? 3 : 0 ); // the handle col (nId == 0) does not have a left margin for resizing + aColRect.AdjustRight( -3 ); + bResizingCol = !aColRect.Contains(_rMousePos); + } + if (bResizingCol) + return; + + // force the base class to end its drag mode + EndTracking(TrackingEventFlags::Cancel | TrackingEventFlags::End); + + // because we have 3d-buttons the select handler is called from MouseButtonUp, but StartDrag + // occurs earlier (while the mouse button is down) + // so for optical reasons we select the column before really starting the drag operation. + notifyColumnSelect(nId); + + static_cast<SbaGridControl*>(GetParent())->StartDrag(_nAction, + Point( + _rMousePos.X() + GetPosPixel().X(), // we aren't left-justified with our parent, in contrast to the data window + _rMousePos.Y() - GetSizePixel().Height() + ) + ); +} + +void SbaGridHeader::PreExecuteColumnContextMenu(sal_uInt16 nColId, weld::Menu& rMenu, + weld::Menu& rInsertMenu, weld::Menu& rChangeMenu, + weld::Menu& rShowMenu) +{ + FmGridHeader::PreExecuteColumnContextMenu(nColId, rMenu, rInsertMenu, rChangeMenu, rShowMenu); + + // some items are valid only if the db isn't readonly + bool bDBIsReadOnly = static_cast<SbaGridControl*>(GetParent())->IsReadOnlyDB(); + + if (bDBIsReadOnly) + { + rMenu.set_visible("hide", false); + rMenu.set_sensitive("hide", false); + rMenu.set_visible("show", false); + rMenu.set_sensitive("show", false); + } + + // prepend some new items + bool bColAttrs = (nColId != sal_uInt16(-1)) && (nColId != 0); + if ( !bColAttrs || bDBIsReadOnly) + return; + + sal_uInt16 nPos = 0; + sal_uInt16 nModelPos = static_cast<SbaGridControl*>(GetParent())->GetModelColumnPos(nColId); + Reference< XPropertySet > xField = static_cast<SbaGridControl*>(GetParent())->getField(nModelPos); + + if ( xField.is() ) + { + switch( ::comphelper::getINT32(xField->getPropertyValue(PROPERTY_TYPE)) ) + { + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::SQLNULL: + case DataType::OBJECT: + case DataType::BLOB: + case DataType::CLOB: + case DataType::REF: + break; + default: + rMenu.insert(nPos++, "colattrset", DBA_RES(RID_STR_COLUMN_FORMAT), + nullptr, nullptr, nullptr, TRISTATE_INDET); + rMenu.insert_separator(nPos++, "separator1"); + } + } + + rMenu.insert(nPos++, "colwidth", DBA_RES(RID_STR_COLUMN_WIDTH), + nullptr, nullptr, nullptr, TRISTATE_INDET); + rMenu.insert_separator(nPos++, "separator2"); +} + +void SbaGridHeader::PostExecuteColumnContextMenu(sal_uInt16 nColId, const weld::Menu& rMenu, const OString& rExecutionResult) +{ + if (rExecutionResult == "colwidth") + static_cast<SbaGridControl*>(GetParent())->SetColWidth(nColId); + else if (rExecutionResult == "colattrset") + static_cast<SbaGridControl*>(GetParent())->SetColAttrs(nColId); + else + FmGridHeader::PostExecuteColumnContextMenu(nColId, rMenu, rExecutionResult); +} + +// SbaGridControl +SbaGridControl::SbaGridControl(Reference< XComponentContext > const & _rM, + vcl::Window* pParent, FmXGridPeer* _pPeer, WinBits nBits) + :FmGridControl(_rM,pParent, _pPeer, nBits) + ,m_pMasterListener(nullptr) + ,m_nAsyncDropEvent(nullptr) + ,m_bActivatingForDrop(false) +{ +} + +SbaGridControl::~SbaGridControl() +{ + disposeOnce(); +} + +void SbaGridControl::dispose() +{ + if (m_nAsyncDropEvent) + Application::RemoveUserEvent(m_nAsyncDropEvent); + m_nAsyncDropEvent = nullptr; + FmGridControl::dispose(); +} + +VclPtr<BrowserHeader> SbaGridControl::imp_CreateHeaderBar(BrowseBox* pParent) +{ + return VclPtr<SbaGridHeader>::Create(pParent); +} + +CellController* SbaGridControl::GetController(sal_Int32 nRow, sal_uInt16 nCol) +{ + if ( m_bActivatingForDrop ) + return nullptr; + + return FmGridControl::GetController(nRow, nCol); +} + +void SbaGridControl::PreExecuteRowContextMenu(weld::Menu& rMenu) +{ + FmGridControl::PreExecuteRowContextMenu(rMenu); + + sal_uInt16 nPos = 0; + + if (!IsReadOnlyDB()) + { + rMenu.insert(nPos++, "tableattr", DBA_RES(RID_STR_TABLE_FORMAT), + nullptr, nullptr, nullptr, TRISTATE_INDET); + rMenu.insert(nPos++, "rowheight", DBA_RES(RID_STR_ROW_HEIGHT), + nullptr, nullptr, nullptr, TRISTATE_INDET); + rMenu.insert_separator(nPos++, "separator1"); + } + + if ( GetSelectRowCount() > 0 ) + { + rMenu.insert(nPos++, "copy", DBA_RES(RID_STR_COPY), + nullptr, nullptr, nullptr, TRISTATE_INDET); + rMenu.insert_separator(nPos++, "separator2"); + } +} + +SvNumberFormatter* SbaGridControl::GetDatasourceFormatter() +{ + Reference< css::util::XNumberFormatsSupplier > xSupplier = ::dbtools::getNumberFormats(::dbtools::getConnection(Reference< XRowSet > (getDataSource(),UNO_QUERY)), true, getContext()); + + SvNumberFormatsSupplierObj* pSupplierImpl = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( xSupplier ); + if ( !pSupplierImpl ) + return nullptr; + + SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter(); + return pFormatter; +} + +void SbaGridControl::SetColWidth(sal_uInt16 nColId) +{ + // get the (UNO) column model + sal_uInt16 nModelPos = GetModelColumnPos(nColId); + Reference< XIndexAccess > xCols = GetPeer()->getColumns(); + Reference< XPropertySet > xAffectedCol; + if (xCols.is() && (nModelPos != sal_uInt16(-1))) + xAffectedCol.set(xCols->getByIndex(nModelPos), css::uno::UNO_QUERY); + + if (!xAffectedCol.is()) + return; + + Any aWidth = xAffectedCol->getPropertyValue(PROPERTY_WIDTH); + sal_Int32 nCurWidth = aWidth.hasValue() ? ::comphelper::getINT32(aWidth) : -1; + + DlgSize aDlgColWidth(GetFrameWeld(), nCurWidth, false); + if (aDlgColWidth.run() != RET_OK) + return; + + sal_Int32 nValue = aDlgColWidth.GetValue(); + Any aNewWidth; + if (-1 == nValue) + { // set to default + Reference< XPropertyState > xPropState(xAffectedCol, UNO_QUERY); + if (xPropState.is()) + { + try { aNewWidth = xPropState->getPropertyDefault(PROPERTY_WIDTH); } catch(Exception&) { } ; + } + } + else + aNewWidth <<= nValue; + try { xAffectedCol->setPropertyValue(PROPERTY_WIDTH, aNewWidth); } catch(Exception&) { } ; +} + +void SbaGridControl::SetRowHeight() +{ + Reference< XPropertySet > xCols(GetPeer()->getColumns(), UNO_QUERY); + if (!xCols.is()) + return; + + Any aHeight = xCols->getPropertyValue(PROPERTY_ROW_HEIGHT); + sal_Int32 nCurHeight = aHeight.hasValue() ? ::comphelper::getINT32(aHeight) : -1; + + DlgSize aDlgRowHeight(GetFrameWeld(), nCurHeight, true); + if (aDlgRowHeight.run() != RET_OK) + return; + + sal_Int32 nValue = aDlgRowHeight.GetValue(); + Any aNewHeight; + if (sal_Int16(-1) == nValue) + { // set to default + Reference< XPropertyState > xPropState(xCols, UNO_QUERY); + if (xPropState.is()) + { + try + { + aNewHeight = xPropState->getPropertyDefault(PROPERTY_ROW_HEIGHT); + } + catch(Exception&) + { } + } + } + else + aNewHeight <<= nValue; + try + { + xCols->setPropertyValue(PROPERTY_ROW_HEIGHT, aNewHeight); + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION( "dbaccess", "setPropertyValue: PROPERTY_ROW_HEIGHT throws an exception"); + } +} + +void SbaGridControl::SetColAttrs(sal_uInt16 nColId) +{ + SvNumberFormatter* pFormatter = GetDatasourceFormatter(); + if (!pFormatter) + return; + + sal_uInt16 nModelPos = GetModelColumnPos(nColId); + + // get the (UNO) column model + Reference< XIndexAccess > xCols = GetPeer()->getColumns(); + Reference< XPropertySet > xAffectedCol; + if (xCols.is() && (nModelPos != sal_uInt16(-1))) + xAffectedCol.set(xCols->getByIndex(nModelPos), css::uno::UNO_QUERY); + + // get the field the column is bound to + Reference< XPropertySet > xField = getField(nModelPos); + ::dbaui::callColumnFormatDialog(xAffectedCol,xField,pFormatter,GetFrameWeld()); +} + +void SbaGridControl::SetBrowserAttrs() +{ + Reference< XPropertySet > xGridModel(GetPeer()->getColumns(), UNO_QUERY); + if (!xGridModel.is()) + return; + + try + { + Reference< XComponentContext > xContext = getContext(); + css::uno::Sequence<css::uno::Any> aArguments{ + Any(comphelper::makePropertyValue("IntrospectedObject", xGridModel)), + Any(comphelper::makePropertyValue("ParentWindow", VCLUnoHelper::GetInterface(this))) + }; + Reference<XExecutableDialog> xExecute(xContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.form.ControlFontDialog", + aArguments, xContext), css::uno::UNO_QUERY_THROW); + xExecute->execute(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void SbaGridControl::PostExecuteRowContextMenu(const OString& rExecutionResult) +{ + if (rExecutionResult == "tableattr") + SetBrowserAttrs(); + else if (rExecutionResult == "rowheight") + SetRowHeight(); + else if (rExecutionResult == "copy") + CopySelectedRowsToClipboard(); + else + FmGridControl::PostExecuteRowContextMenu(rExecutionResult); +} + +void SbaGridControl::Select() +{ + // Some selection has changed ... + FmGridControl::Select(); + + if (m_pMasterListener) + m_pMasterListener->SelectionChanged(); +} + +void SbaGridControl::ActivateCell(sal_Int32 nRow, sal_uInt16 nCol, bool bSetCellFocus /*= sal_True*/ ) +{ + FmGridControl::ActivateCell(nRow, nCol, bSetCellFocus); + if (m_pMasterListener) + m_pMasterListener->CellActivated(); +} + +void SbaGridControl::DeactivateCell(bool bUpdate /*= sal_True*/) +{ + FmGridControl::DeactivateCell(bUpdate); + if (m_pMasterListener) + m_pMasterListener->CellDeactivated(); +} + +void SbaGridControl::onRowChange() +{ + if ( m_pMasterListener ) + m_pMasterListener->RowChanged(); +} + +void SbaGridControl::onColumnChange() +{ + if ( m_pMasterListener ) + m_pMasterListener->ColumnChanged(); +} + +Reference< XPropertySet > SbaGridControl::getField(sal_uInt16 nModelPos) +{ + Reference< XPropertySet > xEmptyReturn; + try + { + // first get the name of the column + Reference< XIndexAccess > xCols = GetPeer()->getColumns(); + if ( xCols.is() && xCols->getCount() > nModelPos ) + { + Reference< XPropertySet > xCol(xCols->getByIndex(nModelPos),UNO_QUERY); + if ( xCol.is() ) + xEmptyReturn.set(xCol->getPropertyValue(PROPERTY_BOUNDFIELD),UNO_QUERY); + } + else + OSL_FAIL("SbaGridControl::getField getColumns returns NULL or ModelPos is > than count!"); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("dbaccess", "SbaGridControl::getField Exception occurred"); + } + + return xEmptyReturn; +} + +bool SbaGridControl::IsReadOnlyDB() const +{ + // assume yes if anything fails + bool bDBIsReadOnly = true; + + try + { + // the db is the implemented by the parent of the grid control's model ... + Reference< XChild > xColumns(GetPeer()->getColumns(), UNO_QUERY); + if (xColumns.is()) + { + Reference< XRowSet > xDataSource(xColumns->getParent(), UNO_QUERY); + ::dbtools::ensureRowSetConnection( xDataSource, getContext(), nullptr ); + Reference< XChild > xConn(::dbtools::getConnection(xDataSource),UNO_QUERY); + if (xConn.is()) + { + // ... and the RO-flag simply is implemented by a property + Reference< XPropertySet > xDbProps(xConn->getParent(), UNO_QUERY); + if (xDbProps.is()) + { + Reference< XPropertySetInfo > xInfo = xDbProps->getPropertySetInfo(); + if (xInfo->hasPropertyByName(PROPERTY_ISREADONLY)) + bDBIsReadOnly = ::comphelper::getBOOL(xDbProps->getPropertyValue(PROPERTY_ISREADONLY)); + } + } + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("dbaccess", "SbaGridControl::IsReadOnlyDB Exception occurred"); + } + + return bDBIsReadOnly; +} + +void SbaGridControl::MouseButtonDown( const BrowserMouseEvent& rMEvt) +{ + sal_Int32 nRow = GetRowAtYPosPixel(rMEvt.GetPosPixel().Y()); + sal_uInt16 nColPos = GetColumnAtXPosPixel(rMEvt.GetPosPixel().X()); + sal_uInt16 nViewPos = (nColPos == BROWSER_INVALIDID) ? sal_uInt16(-1) : nColPos-1; + // 'the handle column' and 'no valid column' will both result in a view position of -1 ! + + bool bHitEmptySpace = (nRow > GetRowCount()) || (nViewPos == sal_uInt16(-1)); + + if (bHitEmptySpace && (rMEvt.GetClicks() == 2) && rMEvt.IsMod1()) + Control::MouseButtonDown(rMEvt); + else + FmGridControl::MouseButtonDown(rMEvt); +} + +void SbaGridControl::StartDrag( sal_Int8 _nAction, const Point& _rPosPixel ) +{ + SolarMutexGuard aGuard; + // in the new DnD API, the solar mutex is not locked when StartDrag is called + + bool bHandled = false; + + do + { + // determine if dragging is allowed + // (Yes, this is controller (not view) functionality. But collecting and evaluating all the + // information necessary via UNO would be quite difficult (if not impossible) so + // my laziness says 'do it here'...) + sal_Int32 nRow = GetRowAtYPosPixel(_rPosPixel.Y()); + sal_uInt16 nColPos = GetColumnAtXPosPixel(_rPosPixel.X()); + sal_uInt16 nViewPos = (nColPos == BROWSER_INVALIDID) ? sal_uInt16(-1) : nColPos-1; + // 'the handle column' and 'no valid column' will both result in a view position of -1 ! + + bool bCurrentRowVirtual = IsCurrentAppending() && IsModified(); + // the current row doesn't really exist: the user's appending a new one and already has entered some data, + // so the row contains data which has no counter part within the data source + + sal_Int32 nCorrectRowCount = GetRowCount(); + if (GetOptions() & DbGridControlOptions::Insert) + --nCorrectRowCount; // there is an empty row for inserting records + if (bCurrentRowVirtual) + --nCorrectRowCount; + + if ((nColPos == BROWSER_INVALIDID) || (nRow >= nCorrectRowCount)) + break; + + bool bHitHandle = (nColPos == 0); + + // check which kind of dragging has to be initiated + if ( bHitHandle // the handle column + // AND + && ( GetSelectRowCount() // at least one row is selected + // OR + || ( (nRow >= 0) // a row below the header + && !bCurrentRowVirtual // we aren't appending a new record + && (nRow != GetCurrentPos()) // a row which is not the current one + ) // OR + || ( (0 == GetSelectRowCount()) // no rows selected + && (-1 == nRow) // hit the header + ) + ) + ) + { // => start dragging the row + if (GetDataWindow().IsMouseCaptured()) + GetDataWindow().ReleaseMouse(); + + if (0 == GetSelectRowCount()) + // no rows selected, but here in this branch + // -> the user started dragging the upper left corner, which symbolizes the whole table + SelectAll(); + + getMouseEvent().Clear(); + implTransferSelectedRows(static_cast<sal_Int16>(nRow), false); + + bHandled = true; + } + else if ( (nRow < 0) // the header + && (!bHitHandle) // non-handle column + && (nViewPos < GetViewColCount()) // valid (existing) column + ) + { // => start dragging the column + if (GetDataWindow().IsMouseCaptured()) + GetDataWindow().ReleaseMouse(); + + getMouseEvent().Clear(); + DoColumnDrag(nViewPos); + + bHandled = true; + } + else if ( !bHitHandle // non-handle column + && (nRow >= 0) // non-header row + ) + { // => start dragging the field content + if (GetDataWindow().IsMouseCaptured()) + GetDataWindow().ReleaseMouse(); + + getMouseEvent().Clear(); + DoFieldDrag(nViewPos, static_cast<sal_Int16>(nRow)); + + bHandled = true; + } + } + while (false); + + if (!bHandled) + FmGridControl::StartDrag(_nAction, _rPosPixel); +} + +void SbaGridControl::DoColumnDrag(sal_uInt16 nColumnPos) +{ + Reference< XPropertySet > xDataSource = getDataSource(); + OSL_ENSURE(xDataSource.is(), "SbaGridControl::DoColumnDrag : invalid data source !"); + ::dbtools::ensureRowSetConnection(Reference< XRowSet >(getDataSource(),UNO_QUERY), getContext(), nullptr); + + Reference< XPropertySet > xAffectedCol; + Reference< XPropertySet > xAffectedField; + Reference< XConnection > xActiveConnection; + + // determine the field to drag + OUString sField; + try + { + xActiveConnection = ::dbtools::getConnection(Reference< XRowSet >(getDataSource(),UNO_QUERY)); + + sal_uInt16 nModelPos = GetModelColumnPos(GetColumnIdFromViewPos(nColumnPos)); + Reference< XIndexContainer > xCols = GetPeer()->getColumns(); + xAffectedCol.set(xCols->getByIndex(nModelPos),UNO_QUERY); + if (xAffectedCol.is()) + { + xAffectedCol->getPropertyValue(PROPERTY_CONTROLSOURCE) >>= sField; + xAffectedField.set(xAffectedCol->getPropertyValue(PROPERTY_BOUNDFIELD),UNO_QUERY); + } + } + catch(Exception&) + { + OSL_FAIL("SbaGridControl::DoColumnDrag : something went wrong while getting the column"); + } + if (sField.isEmpty()) + return; + + rtl::Reference<OColumnTransferable> pDataTransfer = new OColumnTransferable(xDataSource, sField, xAffectedField, xActiveConnection, ColumnTransferFormatFlags::FIELD_DESCRIPTOR | ColumnTransferFormatFlags::COLUMN_DESCRIPTOR); + pDataTransfer->StartDrag(this, DND_ACTION_COPY | DND_ACTION_LINK); +} + +void SbaGridControl::CopySelectedRowsToClipboard() +{ + OSL_ENSURE( GetSelectRowCount() > 0, "SbaGridControl::CopySelectedRowsToClipboard: invalid call!" ); + implTransferSelectedRows( static_cast<sal_Int16>(FirstSelectedRow()), true ); +} + +void SbaGridControl::implTransferSelectedRows( sal_Int16 nRowPos, bool _bTrueIfClipboardFalseIfDrag ) +{ + Reference< XPropertySet > xForm = getDataSource(); + OSL_ENSURE( xForm.is(), "SbaGridControl::implTransferSelectedRows: invalid form!" ); + + // build the sequence of numbers of selected rows + Sequence< Any > aSelectedRows; + bool bSelectionBookmarks = true; + + // collect the affected rows + if ((GetSelectRowCount() == 0) && (nRowPos >= 0)) + { + aSelectedRows = { Any(static_cast<sal_Int32>(nRowPos + 1)) }; + bSelectionBookmarks = false; + } + else if ( !IsAllSelected() && GetSelectRowCount() ) + { + aSelectedRows = getSelectionBookmarks(); + bSelectionBookmarks = true; + } + + try + { + rtl::Reference<ODataClipboard> pTransfer = new ODataClipboard( xForm, aSelectedRows, bSelectionBookmarks, getContext() ); + + if ( _bTrueIfClipboardFalseIfDrag ) + pTransfer->CopyToClipboard( this ); + else + pTransfer->StartDrag(this, DND_ACTION_COPY | DND_ACTION_LINK); + } + catch(Exception&) + { + } +} + +void SbaGridControl::DoFieldDrag(sal_uInt16 nColumnPos, sal_Int16 nRowPos) +{ + // the only thing to do here is dragging the pure cell text + // the old implementation copied a SBA_FIELDDATAEXCHANGE_FORMAT, too, (which was rather expensive to obtain), + // but we have no client for this DnD format anymore (the mail part of SO 5.2 was the only client) + + try + { + OUString sCellText; + Reference< XGridFieldDataSupplier > xFieldData(GetPeer()); + Sequence<sal_Bool> aSupportingText = xFieldData->queryFieldDataType(cppu::UnoType<decltype(sCellText)>::get()); + if (aSupportingText.getConstArray()[nColumnPos]) + { + Sequence< Any> aCellContents = xFieldData->queryFieldData(nRowPos, cppu::UnoType<decltype(sCellText)>::get()); + sCellText = ::comphelper::getString(aCellContents.getConstArray()[nColumnPos]); + ::svt::OStringTransfer::StartStringDrag(sCellText, this, DND_ACTION_COPY); + } + } + catch(Exception&) + { + OSL_FAIL("SbaGridControl::DoFieldDrag : could not retrieve the cell's contents !"); + return; + } + +} + + namespace { + +/// unary_function Functor object for class ZZ returntype is void + struct SbaGridControlPrec + { + bool operator()(const DataFlavorExVector::value_type& _aType) + { + switch (_aType.mnSotId) + { + case SotClipboardFormatId::DBACCESS_TABLE: // table descriptor + case SotClipboardFormatId::DBACCESS_QUERY: // query descriptor + case SotClipboardFormatId::DBACCESS_COMMAND: // SQL command + return true; + default: break; + } + return false; + } + }; + + } + +sal_Int8 SbaGridControl::AcceptDrop( const BrowserAcceptDropEvent& rEvt ) +{ + sal_Int8 nAction = DND_ACTION_NONE; + + // we need a valid connection + if (!::dbtools::getConnection(Reference< XRowSet > (getDataSource(),UNO_QUERY)).is()) + return nAction; + + if ( IsDropFormatSupported( SotClipboardFormatId::STRING ) ) + do + { // odd construction, but spares us a lot of (explicit ;) goto's + + if (!GetEmptyRow().is()) + // without an empty row we're not in update mode + break; + + const sal_Int32 nRow = GetRowAtYPosPixel(rEvt.maPosPixel.Y(), false); + const sal_uInt16 nCol = GetColumnId(GetColumnAtXPosPixel(rEvt.maPosPixel.X())); + + sal_Int32 nCorrectRowCount = GetRowCount(); + if (GetOptions() & DbGridControlOptions::Insert) + --nCorrectRowCount; // there is an empty row for inserting records + if (IsCurrentAppending()) + --nCorrectRowCount; // the current data record doesn't really exist, we are appending a new one + + if ( (nCol == BROWSER_INVALIDID) || (nRow >= nCorrectRowCount) || (nCol == 0) ) + // no valid cell under the mouse cursor + break; + + tools::Rectangle aRect = GetCellRect(nRow, nCol, false); + if (!aRect.Contains(rEvt.maPosPixel)) + // not dropped within a cell (a cell isn't as wide as the column - the are small spaces) + break; + + if ((IsModified() || (GetCurrentRow().is() && GetCurrentRow()->IsModified())) && (GetCurrentPos() != nRow)) + // there is a current and modified row or cell and he text is to be dropped into another one + break; + + CellControllerRef xCurrentController = Controller(); + if (xCurrentController.is() && xCurrentController->IsValueChangedFromSaved() && ((nRow != GetCurRow()) || (nCol != GetCurColumnId()))) + // the current controller is modified and the user wants to drop in another cell -> no chance + // (when leaving the modified cell an error may occur - this is deadly while dragging) + break; + + Reference< XPropertySet > xField = getField(GetModelColumnPos(nCol)); + if (!xField.is()) + // the column is not valid bound (for instance a binary field) + break; + + try + { + if (::comphelper::getBOOL(xField->getPropertyValue(PROPERTY_ISREADONLY))) + break; + } + catch (const Exception& ) + { + // assume RO + break; + } + + try + { + // assume that text can be dropped into a field if the column has a css::awt::XTextComponent interface + Reference< XIndexAccess > xColumnControls(GetPeer()); + if (xColumnControls.is()) + { + Reference< css::awt::XTextComponent > xColControl( + xColumnControls->getByIndex(GetViewColumnPos(nCol)), + css::uno::UNO_QUERY); + if (xColControl.is()) + { + m_bActivatingForDrop = true; + GoToRowColumnId(nRow, nCol); + m_bActivatingForDrop = false; + + nAction = DND_ACTION_COPY; + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + } while (false); + + if(nAction != DND_ACTION_COPY && GetEmptyRow().is()) + { + const DataFlavorExVector& _rFlavors = GetDataFlavors(); + if(std::any_of(_rFlavors.begin(),_rFlavors.end(),SbaGridControlPrec())) + nAction = DND_ACTION_COPY; + } + + return (DND_ACTION_NONE != nAction) ? nAction : FmGridControl::AcceptDrop(rEvt); +} + +sal_Int8 SbaGridControl::ExecuteDrop( const BrowserExecuteDropEvent& rEvt ) +{ + // we need some properties of our data source + Reference< XPropertySet > xDataSource = getDataSource(); + if (!xDataSource.is()) + return DND_ACTION_NONE; + + // we need a valid connection + if (!::dbtools::getConnection(Reference< XRowSet > (xDataSource,UNO_QUERY)).is()) + return DND_ACTION_NONE; + + if ( IsDropFormatSupported( SotClipboardFormatId::STRING ) ) + { + sal_Int32 nRow = GetRowAtYPosPixel(rEvt.maPosPixel.Y(), false); + sal_uInt16 nCol = GetColumnAtXPosPixel(rEvt.maPosPixel.X()); + + sal_Int32 nCorrectRowCount = GetRowCount(); + if (GetOptions() & DbGridControlOptions::Insert) + --nCorrectRowCount; // there is an empty row for inserting records + if (IsCurrentAppending()) + --nCorrectRowCount; // the current data record doesn't really exist, we are appending a new one + + OSL_ENSURE((nCol != BROWSER_INVALIDID) && (nRow < nCorrectRowCount), "SbaGridControl::Drop : dropped on an invalid position !"); + // AcceptDrop should have caught this + + // from now we work with ids instead of positions + nCol = GetColumnId(nCol); + + GoToRowColumnId(nRow, nCol); + if (!IsEditing()) + ActivateCell(); + + CellControllerRef xCurrentController = Controller(); + EditCellController* pController = dynamic_cast<EditCellController*>(xCurrentController.get()); + if (!pController) + return DND_ACTION_NONE; + + // get the dropped string + TransferableDataHelper aDropped( rEvt.maDropEvent.Transferable ); + OUString sDropped; + if ( !aDropped.GetString( SotClipboardFormatId::STRING, sDropped ) ) + return DND_ACTION_NONE; + + IEditImplementation* pEditImplementation = pController->GetEditImplementation(); + pEditImplementation->SetText(sDropped); + // SetText itself doesn't call a Modify as it isn't a user interaction + pController->Modify(); + + return DND_ACTION_COPY; + } + + if(GetEmptyRow().is()) + { + const DataFlavorExVector& _rFlavors = GetDataFlavors(); + if( std::any_of(_rFlavors.begin(),_rFlavors.end(), SbaGridControlPrec()) ) + { + TransferableDataHelper aDropped( rEvt.maDropEvent.Transferable ); + m_aDataDescriptor = ODataAccessObjectTransferable::extractObjectDescriptor(aDropped); + if (m_nAsyncDropEvent) + Application::RemoveUserEvent(m_nAsyncDropEvent); + m_nAsyncDropEvent = Application::PostUserEvent(LINK(this, SbaGridControl, AsynchDropEvent), nullptr, true); + return DND_ACTION_COPY; + } + } + + return DND_ACTION_NONE; +} + +Reference< XPropertySet > SbaGridControl::getDataSource() const +{ + Reference< XPropertySet > xReturn; + + Reference< XChild > xColumns(GetPeer()->getColumns(), UNO_QUERY); + if (xColumns.is()) + xReturn.set(xColumns->getParent(), UNO_QUERY); + + return xReturn; +} + +IMPL_LINK_NOARG(SbaGridControl, AsynchDropEvent, void*, void) +{ + m_nAsyncDropEvent = nullptr; + + Reference< XPropertySet > xDataSource = getDataSource(); + if ( xDataSource.is() ) + { + bool bCountFinal = false; + xDataSource->getPropertyValue(PROPERTY_ISROWCOUNTFINAL) >>= bCountFinal; + if ( !bCountFinal ) + setDataSource(nullptr); // detach from grid control + Reference< XResultSetUpdate > xResultSetUpdate(xDataSource,UNO_QUERY); + rtl::Reference<ODatabaseImportExport> pImExport = new ORowSetImportExport(GetFrameWeld(),xResultSetUpdate,m_aDataDescriptor, getContext()); + Hide(); + try + { + pImExport->initialize(m_aDataDescriptor); + if (m_pMasterListener) + m_pMasterListener->BeforeDrop(); + if(!pImExport->Read()) + { + OUString sError = DBA_RES(STR_NO_COLUMNNAME_MATCHING); + throwGenericSQLException(sError,nullptr); + } + if (m_pMasterListener) + m_pMasterListener->AfterDrop(); + Show(); + } + catch(const SQLException& e) + { + if (m_pMasterListener) + m_pMasterListener->AfterDrop(); + Show(); + ::dbtools::showError( ::dbtools::SQLExceptionInfo(e), VCLUnoHelper::GetInterface(this), getContext() ); + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + if (m_pMasterListener) + m_pMasterListener->AfterDrop(); + Show(); + } + if ( !bCountFinal ) + setDataSource(Reference< XRowSet >(xDataSource,UNO_QUERY)); + } + m_aDataDescriptor.clear(); +} + +OUString SbaGridControl::GetAccessibleObjectDescription( AccessibleBrowseBoxObjType eObjType,sal_Int32 _nPosition) const +{ + OUString sRet; + if ( AccessibleBrowseBoxObjType::BrowseBox == eObjType ) + { + SolarMutexGuard aGuard; + sRet = DBA_RES(STR_DATASOURCE_GRIDCONTROL_DESC); + } + else + sRet = FmGridControl::GetAccessibleObjectDescription( eObjType,_nPosition); + return sRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/sbamultiplex.cxx b/dbaccess/source/ui/browser/sbamultiplex.cxx new file mode 100644 index 000000000..8bf7ed747 --- /dev/null +++ b/dbaccess/source/ui/browser/sbamultiplex.cxx @@ -0,0 +1,528 @@ +/* -*- 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 <sbamultiplex.hxx> +#include <cppuhelper/queryinterface.hxx> + +using namespace dbaui; + +// the listener multiplexers + +// XStatusListener +SbaXStatusMultiplexer::SbaXStatusMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex) + :OSbaWeakSubObject(rSource) + ,OInterfaceContainerHelper3(_rMutex) +{ +} + +css::uno::Any SAL_CALL SbaXStatusMultiplexer::queryInterface(const css::uno::Type& _rType) +{ + css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ::cppu::queryInterface(_rType, + static_cast< css::frame::XStatusListener* >(this), + static_cast< css::lang::XEventListener* >(static_cast< css::frame::XStatusListener* >(this)) + ); + + return aReturn; +} +void SAL_CALL SbaXStatusMultiplexer::disposing(const css::lang::EventObject& ) +{ +} + + +void SAL_CALL SbaXStatusMultiplexer::statusChanged(const css::frame::FeatureStateEvent& e) +{ + m_aLastKnownStatus = e; + m_aLastKnownStatus.Source = &m_rParent; + notifyEach( &XStatusListener::statusChanged, m_aLastKnownStatus ); +} + +// LoadListener +SbaXLoadMultiplexer::SbaXLoadMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex) + :OSbaWeakSubObject(rSource) + ,OInterfaceContainerHelper3(_rMutex) +{ +} + +css::uno::Any SAL_CALL SbaXLoadMultiplexer::queryInterface(const css::uno::Type& _rType) +{ + css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ::cppu::queryInterface(_rType, + static_cast< css::form::XLoadListener* >(this), + static_cast< css::lang::XEventListener* >(static_cast< css::form::XLoadListener* >(this)) + ); + + return aReturn; +} +void SAL_CALL SbaXLoadMultiplexer::disposing(const css::lang::EventObject& ) +{ +} + +void SAL_CALL SbaXLoadMultiplexer::loaded(const css::lang::EventObject& e) +{ + css::lang::EventObject aMulti(e); + aMulti.Source = &m_rParent; + notifyEach( &XLoadListener::loaded, aMulti ); +} +void SAL_CALL SbaXLoadMultiplexer::unloaded(const css::lang::EventObject& e) +{ + css::lang::EventObject aMulti(e); + aMulti.Source = &m_rParent; + notifyEach( &XLoadListener::unloaded, aMulti ); +} + +void SAL_CALL SbaXLoadMultiplexer::unloading(const css::lang::EventObject& e) +{ + css::lang::EventObject aMulti(e); + aMulti.Source = &m_rParent; + notifyEach( &XLoadListener::unloading, aMulti ); +} + +void SAL_CALL SbaXLoadMultiplexer::reloading(const css::lang::EventObject& e) +{ + css::lang::EventObject aMulti(e); + aMulti.Source = &m_rParent; + notifyEach( &XLoadListener::reloading, aMulti ); +} + +void SAL_CALL SbaXLoadMultiplexer::reloaded(const css::lang::EventObject& e) +{ + css::lang::EventObject aMulti(e); + aMulti.Source = &m_rParent; + notifyEach( &XLoadListener::reloaded, aMulti ); +} + + +// css::sdbc::XRowSetListener +SbaXRowSetMultiplexer::SbaXRowSetMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex) + :OSbaWeakSubObject(rSource) + ,OInterfaceContainerHelper3(_rMutex) +{ +} + +css::uno::Any SAL_CALL SbaXRowSetMultiplexer::queryInterface(const css::uno::Type& _rType) +{ + css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ::cppu::queryInterface(_rType, + static_cast< css::sdbc::XRowSetListener* >(this), + static_cast< css::lang::XEventListener* >(static_cast< css::sdbc::XRowSetListener* >(this)) + ); + + return aReturn; +} +void SAL_CALL SbaXRowSetMultiplexer::disposing(const css::lang::EventObject& ) +{ +} + +void SAL_CALL SbaXRowSetMultiplexer::cursorMoved(const css::lang::EventObject& e) +{ + css::lang::EventObject aMulti(e); + aMulti.Source = &m_rParent; + notifyEach( &XRowSetListener::cursorMoved, aMulti ); +} + +void SAL_CALL SbaXRowSetMultiplexer::rowChanged(const css::lang::EventObject& e) +{ + css::lang::EventObject aMulti(e); + aMulti.Source = &m_rParent; + notifyEach( &XRowSetListener::rowChanged, aMulti ); +} + +void SAL_CALL SbaXRowSetMultiplexer::rowSetChanged(const css::lang::EventObject& e) +{ + css::lang::EventObject aMulti(e); + aMulti.Source = &m_rParent; + notifyEach( &XRowSetListener::rowSetChanged, aMulti ); +} + +// css::sdb::XRowSetApproveListener +SbaXRowSetApproveMultiplexer::SbaXRowSetApproveMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex) + :OSbaWeakSubObject(rSource) + ,OInterfaceContainerHelper3(_rMutex) +{ +} + +css::uno::Any SAL_CALL SbaXRowSetApproveMultiplexer::queryInterface(const css::uno::Type& _rType) +{ + css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ::cppu::queryInterface(_rType, + static_cast< css::sdb::XRowSetApproveListener* >(this), + static_cast< css::lang::XEventListener* >(static_cast< css::sdb::XRowSetApproveListener* >(this)) + ); + + return aReturn; +} +void SAL_CALL SbaXRowSetApproveMultiplexer::disposing(const css::lang::EventObject& ) +{ +} + +sal_Bool SAL_CALL SbaXRowSetApproveMultiplexer::approveCursorMove(const css::lang::EventObject& e) +{ + css::lang::EventObject aMulti(e); + aMulti.Source = &m_rParent; + ::comphelper::OInterfaceIteratorHelper3 aIt(*this); + bool bResult = true; + while (bResult && aIt.hasMoreElements()) + bResult = aIt.next()->approveCursorMove(aMulti); + return bResult; +} + +sal_Bool SAL_CALL SbaXRowSetApproveMultiplexer::approveRowChange(const css::sdb::RowChangeEvent& e) +{ + css::sdb::RowChangeEvent aMulti(e); + aMulti.Source = &m_rParent; + ::comphelper::OInterfaceIteratorHelper3 aIt(*this); + bool bResult = true; + while (bResult && aIt.hasMoreElements()) + bResult = aIt.next()->approveRowChange(aMulti); + return bResult; +} + +sal_Bool SAL_CALL SbaXRowSetApproveMultiplexer::approveRowSetChange(const css::lang::EventObject& e) +{ + css::lang::EventObject aMulti(e); + aMulti.Source = &m_rParent; + ::comphelper::OInterfaceIteratorHelper3 aIt(*this); + bool bResult = true; + while (bResult && aIt.hasMoreElements()) + bResult = aIt.next()->approveRowSetChange(aMulti); + return bResult; +} + +// css::sdb::XSQLErrorListener +SbaXSQLErrorMultiplexer::SbaXSQLErrorMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex) + :OSbaWeakSubObject(rSource) + ,OInterfaceContainerHelper3(_rMutex) +{ +} + +css::uno::Any SAL_CALL SbaXSQLErrorMultiplexer::queryInterface(const css::uno::Type& _rType) +{ + css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ::cppu::queryInterface(_rType, + static_cast< css::sdb::XSQLErrorListener* >(this), + static_cast< css::lang::XEventListener* >(static_cast< css::sdb::XSQLErrorListener* >(this)) + ); + + return aReturn; +} +void SAL_CALL SbaXSQLErrorMultiplexer::disposing(const css::lang::EventObject& ) +{ +} + +void SAL_CALL SbaXSQLErrorMultiplexer::errorOccured(const css::sdb::SQLErrorEvent& e) +{ + css::sdb::SQLErrorEvent aMulti(e); + aMulti.Source = &m_rParent; + notifyEach( &XSQLErrorListener::errorOccured, aMulti ); +} + +// css::form::XDatabaseParameterListener +SbaXParameterMultiplexer::SbaXParameterMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex) + :OSbaWeakSubObject(rSource) + ,OInterfaceContainerHelper3(_rMutex) +{ +} + +css::uno::Any SAL_CALL SbaXParameterMultiplexer::queryInterface(const css::uno::Type& _rType) +{ + css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ::cppu::queryInterface(_rType, + static_cast< css::form::XDatabaseParameterListener* >(this), + static_cast< css::lang::XEventListener* >(static_cast< css::form::XDatabaseParameterListener* >(this)) + ); + + return aReturn; +} +void SAL_CALL SbaXParameterMultiplexer::disposing(const css::lang::EventObject& ) +{ +} + +sal_Bool SAL_CALL SbaXParameterMultiplexer::approveParameter(const css::form::DatabaseParameterEvent& e) +{ + css::form::DatabaseParameterEvent aMulti(e); + aMulti.Source = &m_rParent; + ::comphelper::OInterfaceIteratorHelper3 aIt(*this); + bool bResult = true; + while (bResult && aIt.hasMoreElements()) + bResult = aIt.next()->approveParameter(aMulti); + return bResult; +} + +// css::form::XSubmitListener +SbaXSubmitMultiplexer::SbaXSubmitMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex) + :OSbaWeakSubObject(rSource) + ,OInterfaceContainerHelper3(_rMutex) +{ +} + +css::uno::Any SAL_CALL SbaXSubmitMultiplexer::queryInterface(const css::uno::Type& _rType) +{ + css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ::cppu::queryInterface(_rType, + static_cast< css::form::XSubmitListener* >(this), + static_cast< css::lang::XEventListener* >(static_cast< css::form::XSubmitListener* >(this)) + ); + + return aReturn; +} +void SAL_CALL SbaXSubmitMultiplexer::disposing(const css::lang::EventObject& ) +{ +} + + + +sal_Bool SAL_CALL SbaXSubmitMultiplexer::approveSubmit(const css::lang::EventObject& e) +{ + css::lang::EventObject aMulti(e); + aMulti.Source = &m_rParent; + ::comphelper::OInterfaceIteratorHelper3 aIt(*this); + bool bResult = true; + while (bResult && aIt.hasMoreElements()) + bResult = aIt.next()->approveSubmit(aMulti); + return bResult; +} + +// css::form::XResetListener +SbaXResetMultiplexer::SbaXResetMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex) + :OSbaWeakSubObject(rSource) + ,OInterfaceContainerHelper3(_rMutex) +{ +} + +css::uno::Any SAL_CALL SbaXResetMultiplexer::queryInterface(const css::uno::Type& _rType) +{ + css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ::cppu::queryInterface(_rType, + static_cast< css::form::XResetListener* >(this), + static_cast< css::lang::XEventListener* >(static_cast< css::form::XResetListener* >(this)) + ); + + return aReturn; +} +void SAL_CALL SbaXResetMultiplexer::disposing(const css::lang::EventObject& ) +{ +} + + +sal_Bool SAL_CALL SbaXResetMultiplexer::approveReset(const css::lang::EventObject& e) +{ + css::lang::EventObject aMulti(e); + aMulti.Source = &m_rParent; + ::comphelper::OInterfaceIteratorHelper3 aIt(*this); + bool bResult = true; + while (bResult && aIt.hasMoreElements()) + bResult = aIt.next()->approveReset(aMulti); + return bResult; +} + +void SAL_CALL SbaXResetMultiplexer::resetted(const css::lang::EventObject& e) +{ + css::lang::EventObject aMulti(e); + aMulti.Source = &m_rParent; + notifyEach( &XResetListener::resetted, aMulti ); +} + +// css::beans::XPropertyChangeListener +SbaXPropertyChangeMultiplexer::SbaXPropertyChangeMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex) + :OSbaWeakSubObject(rSource) + ,m_aListeners(rMutex) +{ +} + +css::uno::Any SAL_CALL SbaXPropertyChangeMultiplexer::queryInterface(const css::uno::Type& _rType) +{ + css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ::cppu::queryInterface(_rType, + static_cast< css::beans::XPropertyChangeListener* >(this), + static_cast< css::lang::XEventListener* >(static_cast< css::beans::XPropertyChangeListener* >(this)) + ); + + return aReturn; +} +void SAL_CALL SbaXPropertyChangeMultiplexer::disposing(const css::lang::EventObject& ) +{ +} +void SAL_CALL SbaXPropertyChangeMultiplexer::propertyChange(const css::beans::PropertyChangeEvent& e) +{ + ::comphelper::OInterfaceContainerHelper3<XPropertyChangeListener>* pListeners = m_aListeners.getContainer(e.PropertyName); + if (pListeners) + Notify(*pListeners, e); + + /* do the notification for the unspecialized listeners, too */ + pListeners = m_aListeners.getContainer(OUString()); + if (pListeners) + Notify(*pListeners, e); +} + +void SbaXPropertyChangeMultiplexer::addInterface(const OUString& rName, + const css::uno::Reference< css::beans::XPropertyChangeListener > & rListener) +{ + m_aListeners.addInterface(rName, rListener); +} + +void SbaXPropertyChangeMultiplexer::removeInterface(const OUString& rName, + const css::uno::Reference< css::beans::XPropertyChangeListener > & rListener) +{ + m_aListeners.removeInterface(rName, rListener); +} + +void SbaXPropertyChangeMultiplexer::disposeAndClear() +{ + css::lang::EventObject aEvt(m_rParent); + m_aListeners.disposeAndClear(aEvt); +} + +sal_Int32 SbaXPropertyChangeMultiplexer::getOverallLen() const +{ + sal_Int32 nLen = 0; + const std::vector< OUString > aContained = m_aListeners.getContainedTypes(); + for ( OUString const & s : aContained) + { + ::comphelper::OInterfaceContainerHelper3<XPropertyChangeListener>* pListeners = m_aListeners.getContainer(s); + if (!pListeners) + continue; + nLen += pListeners->getLength(); + } + return nLen; +} + +void SbaXPropertyChangeMultiplexer::Notify(::comphelper::OInterfaceContainerHelper3<XPropertyChangeListener>& rListeners, const css::beans::PropertyChangeEvent& e) +{ + css::beans::PropertyChangeEvent aMulti(e); + aMulti.Source = &m_rParent; + rListeners.notifyEach( &XPropertyChangeListener::propertyChange, aMulti ); +} + +// css::beans::XVetoableChangeListener +SbaXVetoableChangeMultiplexer::SbaXVetoableChangeMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex) + :OSbaWeakSubObject(rSource) + ,m_aListeners(rMutex) +{ +} + +css::uno::Any SAL_CALL SbaXVetoableChangeMultiplexer::queryInterface(const css::uno::Type& _rType) +{ + css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ::cppu::queryInterface(_rType, + static_cast< css::beans::XVetoableChangeListener* >(this), + static_cast< css::lang::XEventListener* >(static_cast< css::beans::XVetoableChangeListener* >(this)) + ); + + return aReturn; +} +void SAL_CALL SbaXVetoableChangeMultiplexer::disposing(const css::lang::EventObject& ) +{ +} +void SAL_CALL SbaXVetoableChangeMultiplexer::vetoableChange(const css::beans::PropertyChangeEvent& e) +{ + ::comphelper::OInterfaceContainerHelper3<css::beans::XVetoableChangeListener>* pListeners = m_aListeners.getContainer(e.PropertyName); + if (pListeners) + Notify(*pListeners, e); + + /* do the notification for the unspecialized listeners, too */ + pListeners = m_aListeners.getContainer(OUString()); + if (pListeners) + Notify(*pListeners, e); +} + +void SbaXVetoableChangeMultiplexer::addInterface(const OUString& rName, + const css::uno::Reference< css::beans::XVetoableChangeListener > & rListener) +{ + m_aListeners.addInterface(rName, rListener); +} + +void SbaXVetoableChangeMultiplexer::removeInterface(const OUString& rName, + const css::uno::Reference< css::beans::XVetoableChangeListener > & rListener) +{ + m_aListeners.removeInterface(rName, rListener); +} + +void SbaXVetoableChangeMultiplexer::disposeAndClear() +{ + css::lang::EventObject aEvt(m_rParent); + m_aListeners.disposeAndClear(aEvt); +} + +sal_Int32 SbaXVetoableChangeMultiplexer::getOverallLen() const +{ + sal_Int32 nLen = 0; + const std::vector< OUString > aContained = m_aListeners.getContainedTypes(); + for ( OUString const & s : aContained) + { + ::comphelper::OInterfaceContainerHelper3<XVetoableChangeListener>* pListeners = m_aListeners.getContainer(s); + if (!pListeners) + continue; + nLen += pListeners->getLength(); + } + return nLen; +} + +void SbaXVetoableChangeMultiplexer::Notify(::comphelper::OInterfaceContainerHelper3<XVetoableChangeListener>& rListeners, const css::beans::PropertyChangeEvent& e) +{ + css::beans::PropertyChangeEvent aMulti(e); + aMulti.Source = &m_rParent; + rListeners.notifyEach( &XVetoableChangeListener::vetoableChange, aMulti ); +} + +// css::beans::XPropertiesChangeListener +SbaXPropertiesChangeMultiplexer::SbaXPropertiesChangeMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex) + :OSbaWeakSubObject(rSource) + ,OInterfaceContainerHelper3(_rMutex) +{ +} + +css::uno::Any SAL_CALL SbaXPropertiesChangeMultiplexer::queryInterface(const css::uno::Type& _rType) +{ + css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ::cppu::queryInterface(_rType, + static_cast< css::beans::XPropertiesChangeListener* >(this), + static_cast< css::lang::XEventListener* >(static_cast< css::beans::XPropertiesChangeListener* >(this)) + ); + + return aReturn; +} +void SAL_CALL SbaXPropertiesChangeMultiplexer::disposing(const css::lang::EventObject& ) +{ +} + +void SbaXPropertiesChangeMultiplexer::propertiesChange(const css::uno::Sequence< css::beans::PropertyChangeEvent>& aEvts) +{ + // the SbaXPropertiesChangeMultiplexer doesn't care about the property names a listener logs on for, it simply + // forwards _all_ changes to _all_ listeners + + css::uno::Sequence< css::beans::PropertyChangeEvent> aMulti(aEvts); + for (css::beans::PropertyChangeEvent & rEvent : asNonConstRange(aMulti)) + rEvent.Source = &m_rParent; + + notifyEach( &css::beans::XPropertiesChangeListener::propertiesChange, aMulti ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/unodatbr.cxx b/dbaccess/source/ui/browser/unodatbr.cxx new file mode 100644 index 000000000..b993fac97 --- /dev/null +++ b/dbaccess/source/ui/browser/unodatbr.cxx @@ -0,0 +1,3819 @@ +/* -*- 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 <browserids.hxx> +#include <core_resource.hxx> +#include <helpids.h> +#include <dbtreelistbox.hxx> +#include "dbtreemodel.hxx" +#include <strings.hrc> +#include <imageprovider.hxx> +#include <sbagrid.hxx> +#include <strings.hxx> +#include <UITools.hxx> +#include <unodatbr.hxx> + +#include <com/sun/star/awt/MouseWheelBehavior.hpp> +#include <com/sun/star/awt/TextAlign.hpp> +#include <com/sun/star/awt/VisualEffect.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/form/XGridColumnFactory.hpp> +#include <com/sun/star/form/XLoadable.hpp> +#include <com/sun/star/form/XReset.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/frame/XLayoutManager.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/i18n/Collator.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdb/XDatabaseContext.hpp> +#include <com/sun/star/sdb/XDatabaseRegistrations.hpp> +#include <com/sun/star/sdb/XDocumentDataSource.hpp> +#include <com/sun/star/sdb/XParametersSupplier.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp> +#include <com/sun/star/sdb/XResultSetAccess.hpp> +#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> +#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/util/XFlushable.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/document/MacroExecMode.hpp> +#include <com/sun/star/ui/XContextMenuInterceptor.hpp> + +#include <comphelper/extract.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <svl/filenotation.hxx> +#include <svx/dataaccessdescriptor.hxx> +#include <svx/databaseregistrationui.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <tools/multisel.hxx> +#include <tools/urlobj.hxx> +#include <unotools/confignode.hxx> +#include <vcl/split.hxx> +#include <vcl/svapp.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/settings.hxx> +#include <vcl/weld.hxx> + +#include <memory> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdb::application; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::view; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::ui; +using namespace ::dbtools; +using namespace ::comphelper; +using namespace ::svx; + +// SbaTableQueryBrowser +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_ODatasourceBrowser_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + SolarMutexGuard aGuard; + return cppu::acquire(new ::dbaui::SbaTableQueryBrowser(context)); +} + +namespace dbaui +{ + +namespace DatabaseObject = css::sdb::application::DatabaseObject; +namespace DatabaseObjectContainer = css::sdb::application::DatabaseObjectContainer; + +static void SafeAddPropertyListener(const Reference< XPropertySet > & xSet, const OUString& rPropName, XPropertyChangeListener* pListener) +{ + Reference< XPropertySetInfo > xInfo = xSet->getPropertySetInfo(); + if (xInfo->hasPropertyByName(rPropName)) + xSet->addPropertyChangeListener(rPropName, pListener); +} + +static void SafeRemovePropertyListener(const Reference< XPropertySet > & xSet, const OUString& rPropName, XPropertyChangeListener* pListener) +{ + Reference< XPropertySetInfo > xInfo = xSet->getPropertySetInfo(); + if (xInfo->hasPropertyByName(rPropName)) + xSet->removePropertyChangeListener(rPropName, pListener); +} + +OUString SAL_CALL SbaTableQueryBrowser::getImplementationName() +{ + return "org.openoffice.comp.dbu.ODatasourceBrowser"; +} + +css::uno::Sequence<OUString> SAL_CALL SbaTableQueryBrowser::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.DataSourceBrowser" }; +} + +SbaTableQueryBrowser::SbaTableQueryBrowser(const Reference< XComponentContext >& _rM) + :SbaXDataBrowserController(_rM) + ,m_aSelectionListeners( getMutex() ) + ,m_aContextMenuInterceptors( getMutex() ) + ,m_aTableCopyHelper(this) + ,m_pTreeView(nullptr) + ,m_pSplitter(nullptr) + ,m_nAsyncDrop(nullptr) + ,m_bQueryEscapeProcessing( false ) + ,m_bShowMenu(false) + ,m_bInSuspend(false) + ,m_bEnableBrowser(true) +{ +} + +SbaTableQueryBrowser::~SbaTableQueryBrowser() +{ + if ( !rBHelper.bDisposed && !rBHelper.bInDispose ) + { + SAL_WARN("dbaccess.ui", "Please check who doesn't dispose this component!"); + // increment ref count to prevent double call of Dtor + osl_atomic_increment( &m_refCount ); + dispose(); + } + SolarMutexGuard g; + m_pTreeView.reset(); + m_pSplitter.reset(); +} + +Any SAL_CALL SbaTableQueryBrowser::queryInterface(const Type& _rType) +{ + if ( _rType.equals( cppu::UnoType<XScriptInvocationContext>::get() ) ) + { + OSL_PRECOND( !!m_aDocScriptSupport, "SbaTableQueryBrowser::queryInterface: did not initialize this, yet!" ); + if ( !!m_aDocScriptSupport && *m_aDocScriptSupport ) + return Any( Reference< XScriptInvocationContext >( this ) ); + return Any(); + } + + Any aReturn = SbaXDataBrowserController::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = SbaTableQueryBrowser_Base::queryInterface(_rType); + return aReturn; +} + +Sequence< Type > SAL_CALL SbaTableQueryBrowser::getTypes( ) +{ + Sequence< Type > aTypes( ::comphelper::concatSequences( + SbaXDataBrowserController::getTypes(), + SbaTableQueryBrowser_Base::getTypes() + ) ); + + OSL_PRECOND( !!m_aDocScriptSupport, "SbaTableQueryBrowser::getTypes: did not initialize this, yet!" ); + if ( !m_aDocScriptSupport || !*m_aDocScriptSupport ) + { + auto [begin, end] = asNonConstRange(aTypes); + auto newEnd = std::remove_if( begin, end, + [](const Type& type) + { return type == cppu::UnoType<XScriptInvocationContext>::get(); } ); + aTypes.realloc( std::distance(begin, newEnd) ); + } + return aTypes; +} + +Sequence< sal_Int8 > SAL_CALL SbaTableQueryBrowser::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +void SAL_CALL SbaTableQueryBrowser::disposing() +{ + SolarMutexGuard aGuard; + // doin' a lot of VCL stuff here -> lock the SolarMutex + + // kiss our listeners goodbye + css::lang::EventObject aEvt(*this); + m_aSelectionListeners.disposeAndClear(aEvt); + m_aContextMenuInterceptors.disposeAndClear(aEvt); + + if (getBrowserView()) + { + // Need to do some cleanup of the data pointed to the tree view entries before we remove the treeview + clearTreeModel(); + m_pTreeView = nullptr; + getBrowserView()->setTreeView(nullptr); + } + + // remove ourself as status listener + implRemoveStatusListeners(); + + // check out from all the objects we are listening + // the frame + if (m_xCurrentFrameParent.is()) + m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this)); + + // remove the container listener from the database context + try + { + Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW ); + xDatabaseRegistrations->removeDatabaseRegistrationsListener( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + SbaXDataBrowserController::disposing(); +} + +bool SbaTableQueryBrowser::Construct(vcl::Window* pParent) +{ + if ( !SbaXDataBrowserController::Construct( pParent ) ) + return false; + + try + { + Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW ); + xDatabaseRegistrations->addDatabaseRegistrationsListener( this ); + + // the collator for the string compares + m_xCollator = Collator::create( getORB() ); + m_xCollator->loadDefaultCollator( Application::GetSettings().GetLanguageTag().getLocale(), 0 ); + } + catch(const Exception&) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::Construct: could not create (or start listening at) the database context!"); + } + + // some help ids + if (!getBrowserView() || !getBrowserView()->getVclControl()) + return true; + + // create controls and set sizes + const tools::Long nFrameWidth = getBrowserView()->LogicToPixel(::Size(3, 0), MapMode(MapUnit::MapAppFont)).Width(); + + m_pSplitter = VclPtr<Splitter>::Create(getBrowserView(),WB_HSCROLL); + m_pSplitter->SetPosSizePixel( ::Point(0,0), ::Size(nFrameWidth,0) ); + m_pSplitter->SetBackground( Wallpaper( Application::GetSettings().GetStyleSettings().GetDialogColor() ) ); + + m_pTreeView = VclPtr<InterimDBTreeListBox>::Create(getBrowserView()); + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + rTreeView.connect_expanding(LINK(this, SbaTableQueryBrowser, OnExpandEntry)); + + m_pTreeView->setCopyHandler(LINK(this, SbaTableQueryBrowser, OnCopyEntry)); + + m_pTreeView->setContextMenuProvider( this ); + m_pTreeView->setControlActionListener( this ); + m_pTreeView->SetHelpId(HID_CTL_TREEVIEW); + + // a default pos for the splitter, so that the listbox is about 80 (logical) pixels wide + m_pSplitter->SetSplitPosPixel(getBrowserView()->LogicToPixel(::Size(80, 0), MapMode(MapUnit::MapAppFont)).Width()); + + getBrowserView()->setSplitter(m_pSplitter); + getBrowserView()->setTreeView(m_pTreeView); + + // fill view with data + rTreeView.set_sort_order(true); + rTreeView.set_sort_func([this](const weld::TreeIter& rLeft, const weld::TreeIter& rRight){ + return OnTreeEntryCompare(rLeft, rRight); + }); + rTreeView.make_sorted(); + m_pTreeView->SetSelChangeHdl(LINK(this, SbaTableQueryBrowser, OnSelectionChange)); + m_pTreeView->show_container(); + + // TODO + getBrowserView()->getVclControl()->SetHelpId(HID_CTL_TABBROWSER); + if (getBrowserView()->getVclControl()->GetHeaderBar()) + getBrowserView()->getVclControl()->GetHeaderBar()->SetHelpId(HID_DATABROWSE_HEADER); + InvalidateFeature(ID_BROWSER_EXPLORER); + + return true; +} + +namespace +{ + struct SelectValueByName + { + const Any& operator()( OUString const& i_name ) const + { + return m_rCollection.get( i_name ); + } + + explicit SelectValueByName( ::comphelper::NamedValueCollection const& i_collection ) + :m_rCollection( i_collection ) + { + } + + ::comphelper::NamedValueCollection const& m_rCollection; + }; +} + +void SbaTableQueryBrowser::impl_sanitizeRowSetClauses_nothrow() +{ + try + { + Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY_THROW ); + bool bEscapeProcessing = false; + OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bEscapeProcessing ); + if ( !bEscapeProcessing ) + // don't touch or interpret anything if escape processing is disabled + return; + + Reference< XSingleSelectQueryComposer > xComposer( createParser_nothrow() ); + if ( !xComposer.is() ) + // can't do anything. Already reported via assertion in createParser_nothrow. + return; + + // the tables participating in the statement + const Reference< XTablesSupplier > xSuppTables( xComposer, UNO_QUERY_THROW ); + const Reference< XNameAccess > xTableNames( xSuppTables->getTables(), UNO_SET_THROW ); + + // the columns participating in the statement + const Reference< XColumnsSupplier > xSuppColumns( xComposer, UNO_QUERY_THROW ); + const Reference< XNameAccess > xColumnNames( xSuppColumns->getColumns(), UNO_SET_THROW ); + + // check if the order columns apply to tables which really exist in the statement + const Reference< XIndexAccess > xOrderColumns( xComposer->getOrderColumns(), UNO_SET_THROW ); + const sal_Int32 nOrderColumns( xOrderColumns->getCount() ); + bool invalidColumn = nOrderColumns == 0; + for ( sal_Int32 c=0; ( c < nOrderColumns ) && !invalidColumn; ++c ) + { + const Reference< XPropertySet > xOrderColumn( xOrderColumns->getByIndex(c), UNO_QUERY_THROW ); + OUString sTableName; + OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_TABLENAME ) >>= sTableName ); + OUString sColumnName; + OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumnName ); + + if ( sTableName.isEmpty() ) + { + if ( !xColumnNames->hasByName( sColumnName ) ) + { + invalidColumn = true; + break; + } + } + else + { + if ( !xTableNames->hasByName( sTableName ) ) + { + invalidColumn = true; + break; + } + + const Reference< XColumnsSupplier > xSuppTableColumns( xTableNames->getByName( sTableName ), UNO_QUERY_THROW ); + const Reference< XNameAccess > xTableColumnNames( xSuppTableColumns->getColumns(), UNO_SET_THROW ); + if ( !xTableColumnNames->hasByName( sColumnName ) ) + { + invalidColumn = true; + break; + } + } + } + + if ( invalidColumn ) + { + // reset the complete order statement at both the row set and the parser + xRowSetProps->setPropertyValue( PROPERTY_ORDER, Any( OUString() ) ); + xComposer->setOrder( "" ); + } + + // check if the columns participating in the filter refer to existing tables + // TODO: there's no API at all for this. The method which comes nearest to what we need is + // "getStructuredFilter", but it returns pure column names only. That is, for a statement like + // "SELECT * FROM <table> WHERE <other_table>.<column> = <value>", it will return "<column>". But + // there's no API at all to retrieve the information about "<other_table>" - which is what would + // be needed here. + // That'd be a chance to replace getStructuredFilter with something more reasonable. + // So, what really would be handy, is some + // XNormalizedFilter getNormalizedFilter(); + // with + // interface XDisjunctiveFilterExpression + // { + // XConjunctiveFilterTerm getTerm( int index ); + // } + // interface XConjunctiveFilterTerm + // { + // ComparisonPredicate getPredicate( int index ); + // } + // struct ComparisonPredicate + // { + // XComparisonOperand Lhs; + // SQLFilterOperator Operator; + // XComparisonOperand Rhs; + // } + // interface XComparisonOperand + // { + // SQLFilterOperand Type; + // XPropertySet getColumn(); + // string getLiteral(); + // ... + // } + // enum SQLFilterOperand { Column, Literal, ... } + // ... or something like this... + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +bool SbaTableQueryBrowser::InitializeForm( const Reference< XPropertySet > & i_formProperties ) +{ + if (!m_xCurrentlyDisplayed) + return true; + + // this method set all format settings from the original table or query + try + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed)); + ENSURE_OR_RETURN_FALSE( pData, "SbaTableQueryBrowser::InitializeForm: No user data set at the currently displayed entry!" ); + ENSURE_OR_RETURN_FALSE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeForm: No table available!" ); + + Reference< XPropertySetInfo > xPSI( pData->xObjectProperties->getPropertySetInfo(), UNO_SET_THROW ); + + ::comphelper::NamedValueCollection aPropertyValues; + + const OUString aTransferProperties[] = + { + OUString(PROPERTY_APPLYFILTER), + OUString(PROPERTY_FILTER), + OUString(PROPERTY_HAVING_CLAUSE), + OUString(PROPERTY_ORDER) + }; + for (const auto & aTransferProperty : aTransferProperties) + { + if ( !xPSI->hasPropertyByName( aTransferProperty ) ) + continue; + aPropertyValues.put( aTransferProperty, pData->xObjectProperties->getPropertyValue( aTransferProperty ) ); + } + + std::vector< OUString > aNames( aPropertyValues.getNames() ); + std::sort(aNames.begin(), aNames.end()); + Sequence< OUString > aPropNames( comphelper::containerToSequence(aNames) ); + + Sequence< Any > aPropValues( aNames.size() ); + std::transform( aNames.begin(), aNames.end(), aPropValues.getArray(), SelectValueByName( aPropertyValues ) ); + + Reference< XMultiPropertySet > xFormMultiSet( i_formProperties, UNO_QUERY_THROW ); + xFormMultiSet->setPropertyValues( aPropNames, aPropValues ); + + impl_sanitizeRowSetClauses_nothrow(); + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + return false; + } + + return true; +} + +void SbaTableQueryBrowser::initializePreviewMode() +{ + if ( getBrowserView() && getBrowserView()->getVclControl() ) + { + getBrowserView()->getVclControl()->AlwaysEnableInput( false ); + getBrowserView()->getVclControl()->EnableInput( false ); + getBrowserView()->getVclControl()->ForceHideScrollbars(); + } + Reference< XPropertySet > xDataSourceSet(getRowSet(), UNO_QUERY); + if ( xDataSourceSet.is() ) + { + xDataSourceSet->setPropertyValue("AllowInserts",Any(false)); + xDataSourceSet->setPropertyValue("AllowUpdates",Any(false)); + xDataSourceSet->setPropertyValue("AllowDeletes",Any(false)); + } +} + +void SbaTableQueryBrowser::InitializeGridModel(const Reference< css::form::XFormComponent > & xGrid) +{ + try + { + Reference< css::form::XGridColumnFactory > xColFactory(xGrid, UNO_QUERY); + Reference< XNameContainer > xColContainer(xGrid, UNO_QUERY); + clearGridColumns( xColContainer ); + + Reference< XLoadable > xFormAsLoadable; + if (xGrid.is()) + xFormAsLoadable.set(xGrid->getParent(), css::uno::UNO_QUERY); + if (xFormAsLoadable.is() && xFormAsLoadable->isLoaded()) + { + // set the formats from the table + if (m_xCurrentlyDisplayed) + { + Sequence< OUString> aProperties(6 + ( m_bPreview ? 5 : 0 )); + Sequence< Any> aValues(7 + ( m_bPreview ? 5 : 0 )); + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed)); + OSL_ENSURE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeGridModel: No table available!" ); + if ( !pData->xObjectProperties.is() ) + return; + + OUString* pStringIter = aProperties.getArray(); + Any* pValueIter = aValues.getArray(); + if ( m_bPreview ) + { + *pStringIter++ = "AlwaysShowCursor"; + *pValueIter++ <<= false; + *pStringIter++ = PROPERTY_BORDER; + *pValueIter++ <<= sal_Int16(0); + } + + *pStringIter++ = PROPERTY_FONT; + *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_FONT); + *pStringIter++ = PROPERTY_TEXTEMPHASIS; + *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTEMPHASIS); + *pStringIter++ = PROPERTY_TEXTRELIEF; + *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTRELIEF); + if ( m_bPreview ) + { + *pStringIter++ = "HasNavigationBar"; + *pValueIter++ <<= false; + *pStringIter++ = "HasRecordMarker"; + *pValueIter++ <<= false; + } + *pStringIter++ = PROPERTY_ROW_HEIGHT; + *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_ROW_HEIGHT); + if ( m_bPreview ) + { + *pStringIter++ = "Tabstop"; + *pValueIter++ <<= false; + } + *pStringIter++ = PROPERTY_TEXTCOLOR; + *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTCOLOR); + *pStringIter++ = PROPERTY_TEXTLINECOLOR; + *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTLINECOLOR); + + Reference< XMultiPropertySet > xFormMultiSet(xGrid, UNO_QUERY); + xFormMultiSet->setPropertyValues(aProperties, aValues); + } + + // get the formats supplier of the database we're working with + Reference< css::util::XNumberFormatsSupplier > xSupplier = getNumberFormatter()->getNumberFormatsSupplier(); + + Reference<XConnection> xConnection; + Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY); + xRowSetProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection; + OSL_ENSURE(xConnection.is(),"A ActiveConnection should normally exists!"); + + Reference<XChild> xChild(xConnection,UNO_QUERY); + Reference<XPropertySet> xDataSourceProp(xChild->getParent(),UNO_QUERY); + bool bSuppressVersionCol = false; + OSL_VERIFY( xDataSourceProp->getPropertyValue( PROPERTY_SUPPRESSVERSIONCL ) >>= bSuppressVersionCol ); + + // insert the column into the gridcontrol so that we see something :-) + OUString aCurrentModelType; + Reference<XColumnsSupplier> xSupCols(getRowSet(),UNO_QUERY); + Reference<XNameAccess> xColumns = xSupCols->getColumns(); + + OUString sDefaultProperty; + Reference< XPropertySet > xColumn; + Reference< XPropertySetInfo > xColPSI; + const Sequence<OUString> aColNames = xColumns->getElementNames(); + for (const OUString& rName : aColNames) + { + xColumn.set( xColumns->getByName( rName ), UNO_QUERY_THROW ); + xColPSI.set( xColumn->getPropertySetInfo(), UNO_SET_THROW ); + + // ignore the column when it is a rowversion one + if ( bSuppressVersionCol + && xColPSI->hasPropertyByName( PROPERTY_ISROWVERSION ) + && ::cppu::any2bool( xColumn->getPropertyValue( PROPERTY_ISROWVERSION ) ) + ) + continue; + + // use the result set column's type to determine the type of grid column to create + bool bFormattedIsNumeric = true; + sal_Int32 nType = ::comphelper::getINT32( xColumn->getPropertyValue( PROPERTY_TYPE ) ); + + std::vector< NamedValue > aInitialValues; + std::vector< OUString > aCopyProperties; + Any aDefault; + + switch(nType) + { + case DataType::BIT: + case DataType::BOOLEAN: + { + aCurrentModelType = "CheckBox"; + aInitialValues.emplace_back( "VisualEffect", Any( VisualEffect::FLAT ) ); + sDefaultProperty = PROPERTY_DEFAULTSTATE; + + sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN; + OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_ISNULLABLE ) >>= nNullable ); + aInitialValues.emplace_back( + "TriState", + Any( ColumnValue::NO_NULLS != nNullable ) + ); + if ( ColumnValue::NO_NULLS == nNullable ) + aDefault <<= sal_Int16(TRISTATE_FALSE); + } + break; + + case DataType::LONGVARCHAR: + case DataType::CLOB: + aInitialValues.emplace_back( "MultiLine", Any( true ) ); + [[fallthrough]]; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + aCurrentModelType = "TextField"; + sDefaultProperty = PROPERTY_DEFAULTTEXT; + break; + + case DataType::VARCHAR: + case DataType::CHAR: + bFormattedIsNumeric = false; + [[fallthrough]]; + default: + aCurrentModelType = "FormattedField"; + sDefaultProperty = PROPERTY_EFFECTIVEDEFAULT; + + if ( xSupplier.is() ) + aInitialValues.emplace_back( "FormatsSupplier", Any( xSupplier ) ); + aInitialValues.emplace_back( "TreatAsNumber", Any( bFormattedIsNumeric ) ); + aCopyProperties.emplace_back(PROPERTY_FORMATKEY ); + break; + } + + aInitialValues.emplace_back( PROPERTY_CONTROLSOURCE, Any( rName ) ); + OUString sLabel; + xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel; + if ( !sLabel.isEmpty() ) + aInitialValues.emplace_back( PROPERTY_LABEL, Any( sLabel ) ); + else + aInitialValues.emplace_back( PROPERTY_LABEL, Any( rName ) ); + + Reference< XPropertySet > xGridCol( xColFactory->createColumn( aCurrentModelType ), UNO_SET_THROW ); + Reference< XPropertySetInfo > xGridColPSI( xGridCol->getPropertySetInfo(), UNO_SET_THROW ); + + // calculate the default + if ( xGridColPSI->hasPropertyByName( PROPERTY_CONTROLDEFAULT ) ) + { + aDefault = xColumn->getPropertyValue( PROPERTY_CONTROLDEFAULT ); + // default value + if ( nType == DataType::BIT || nType == DataType::BOOLEAN ) + { + if ( aDefault.hasValue() ) + aDefault <<= (comphelper::getString(aDefault).toInt32() == 0) ? sal_Int16(TRISTATE_FALSE) : sal_Int16(TRISTATE_TRUE); + else + aDefault <<= sal_Int16(TRISTATE_INDET); + } + } + + if ( aDefault.hasValue() ) + aInitialValues.emplace_back( sDefaultProperty, aDefault ); + + // transfer properties from the definition to the UNO-model : + aCopyProperties.emplace_back(PROPERTY_HIDDEN ); + aCopyProperties.emplace_back(PROPERTY_WIDTH ); + + // help text to display for the column + Any aDescription; + if ( xColPSI->hasPropertyByName( PROPERTY_HELPTEXT ) ) + aDescription = xColumn->getPropertyValue( PROPERTY_HELPTEXT ); + OUString sTemp; + aDescription >>= sTemp; + if ( sTemp.isEmpty() ) + xColumn->getPropertyValue( PROPERTY_DESCRIPTION ) >>= sTemp; + + aDescription <<= sTemp; + aInitialValues.emplace_back( PROPERTY_HELPTEXT, aDescription ); + + // ... horizontal justify + Any aAlign; aAlign <<= sal_Int16( 0 ); + Any aColAlign( xColumn->getPropertyValue( PROPERTY_ALIGN ) ); + if ( aColAlign.hasValue() ) + aAlign <<= sal_Int16( ::comphelper::getINT32( aColAlign ) ); + aInitialValues.emplace_back( PROPERTY_ALIGN, aAlign ); + + // don't allow the mouse to scroll in the cells + if ( xGridColPSI->hasPropertyByName( PROPERTY_MOUSE_WHEEL_BEHAVIOR ) ) + aInitialValues.emplace_back( PROPERTY_MOUSE_WHEEL_BEHAVIOR, Any( MouseWheelBehavior::SCROLL_DISABLED ) ); + + // now set all those values + for (auto const& property : aInitialValues) + { + xGridCol->setPropertyValue( property.Name, property.Value ); + } + for (auto const& copyPropertyName : aCopyProperties) + xGridCol->setPropertyValue( copyPropertyName, xColumn->getPropertyValue(copyPropertyName) ); + + xColContainer->insertByName(rName, Any(xGridCol)); + } + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +static Reference<XPropertySet> getColumnHelper(const weld::TreeView& rTreeView, + const weld::TreeIter* pCurrentlyDisplayed, + const Reference<XPropertySet>& rxSource) +{ + Reference<XPropertySet> xRet; + if (pCurrentlyDisplayed) + { + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*pCurrentlyDisplayed)); + Reference<XColumnsSupplier> xColumnsSup(pData->xObjectProperties,UNO_QUERY); + Reference<XNameAccess> xNames = xColumnsSup->getColumns(); + OUString aName; + rxSource->getPropertyValue(PROPERTY_NAME) >>= aName; + if(xNames.is() && xNames->hasByName(aName)) + xRet.set(xNames->getByName(aName),UNO_QUERY); + } + return xRet; +} + +void SbaTableQueryBrowser::transferChangedControlProperty(const OUString& _rProperty, const Any& _rNewValue) +{ + if (m_xCurrentlyDisplayed) + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed)); + Reference< XPropertySet > xObjectProps = pData->xObjectProperties; + OSL_ENSURE(xObjectProps.is(),"SbaTableQueryBrowser::transferChangedControlProperty: no table/query object!"); + if (xObjectProps.is()) + xObjectProps->setPropertyValue(_rProperty, _rNewValue); + } +} + +void SbaTableQueryBrowser::propertyChange(const PropertyChangeEvent& evt) +{ + SbaXDataBrowserController::propertyChange(evt); + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + + try + { + Reference< XPropertySet > xSource(evt.Source, UNO_QUERY); + if (!xSource.is()) + return; + // one of the many properties which require us to update the definition ? + // a column's width ? + else if (evt.PropertyName == PROPERTY_WIDTH) + { // a column width has changed -> update the model + // (the update of the view is done elsewhere) + Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource); + if(xProp.is()) + { + if(!evt.NewValue.hasValue()) + xProp->setPropertyValue(PROPERTY_WIDTH,Any(sal_Int32(227))); + else + xProp->setPropertyValue(PROPERTY_WIDTH,evt.NewValue); + } + } + + // a column's 'visible' state ? + else if (evt.PropertyName == PROPERTY_HIDDEN) + { + Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource); + if(xProp.is()) + xProp->setPropertyValue(PROPERTY_HIDDEN,evt.NewValue); + } + + // a columns alignment ? + else if (evt.PropertyName == PROPERTY_ALIGN) + { + Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource); + try + { + if(xProp.is()) + { + if(evt.NewValue.hasValue()) + { + sal_Int16 nAlign = 0; + if(evt.NewValue >>= nAlign) + xProp->setPropertyValue(PROPERTY_ALIGN,Any(sal_Int32(nAlign))); + else + xProp->setPropertyValue(PROPERTY_ALIGN,evt.NewValue); + } + else + xProp->setPropertyValue(PROPERTY_ALIGN,Any(css::awt::TextAlign::LEFT)); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + // a column's format ? + else if ( evt.PropertyName == PROPERTY_FORMATKEY + && (TypeClass_LONG == evt.NewValue.getValueTypeClass()) + ) + { + // update the model (means the definition object) + Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource); + if(xProp.is()) + xProp->setPropertyValue(PROPERTY_FORMATKEY,evt.NewValue); + } + + // some table definition properties ? + // the height of the rows in the grid ? + else if (evt.PropertyName == PROPERTY_ROW_HEIGHT) + { + if (m_xCurrentlyDisplayed) + { + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed)); + OSL_ENSURE( pData->xObjectProperties.is(), "No table available!" ); + + bool bDefault = !evt.NewValue.hasValue(); + if (bDefault) + pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,Any(sal_Int32(45))); + else + pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,evt.NewValue); + } + } + + else if ( evt.PropertyName == PROPERTY_FONT // the font ? + || evt.PropertyName == PROPERTY_TEXTCOLOR // the text color ? + || evt.PropertyName == PROPERTY_FILTER // the filter ? + || evt.PropertyName == PROPERTY_HAVING_CLAUSE // the having clause ? + || evt.PropertyName == PROPERTY_ORDER // the sort ? + || evt.PropertyName == PROPERTY_APPLYFILTER // the appliance of the filter ? + || evt.PropertyName == PROPERTY_TEXTLINECOLOR // the text line color ? + || evt.PropertyName == PROPERTY_TEXTEMPHASIS // the text emphasis ? + || evt.PropertyName == PROPERTY_TEXTRELIEF // the text relief ? + ) + { + transferChangedControlProperty(evt.PropertyName, evt.NewValue); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +sal_Bool SbaTableQueryBrowser::suspend(sal_Bool bSuspend) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + if ( getView() && getView()->IsInModalMode() ) + return false; + bool bRet = false; + if ( !m_bInSuspend ) + { + m_bInSuspend = true; + if ( rBHelper.bDisposed ) + throw DisposedException( OUString(), *this ); + + bRet = SbaXDataBrowserController::suspend(bSuspend); + if ( bRet && getView() ) + getView()->Hide(); + + m_bInSuspend = false; + } + + return bRet; +} + +void SAL_CALL SbaTableQueryBrowser::statusChanged( const FeatureStateEvent& _rEvent ) +{ + // search the external dispatcher causing this call + Reference< XDispatch > xSource(_rEvent.Source, UNO_QUERY); + bool bFound = false; + for (auto & externalFeature : m_aExternalFeatures) + { + if ( _rEvent.FeatureURL.Complete == externalFeature.second.aURL.Complete) + { + bFound = true; + OSL_ENSURE( xSource.get() == externalFeature.second.xDispatcher.get(), "SbaTableQueryBrowser::statusChanged: inconsistent!" ); + // update the enabled state + externalFeature.second.bEnabled = _rEvent.IsEnabled; + + switch ( externalFeature.first ) + { + case ID_BROWSER_DOCUMENT_DATASOURCE: + { + // if it's the slot for the document data source, remember the state + Sequence< PropertyValue > aDescriptor; + bool bProperFormat = _rEvent.State >>= aDescriptor; + OSL_ENSURE(bProperFormat, "SbaTableQueryBrowser::statusChanged: need a data access descriptor here!"); + m_aDocumentDataSource.initializeFrom(aDescriptor); + + OSL_ENSURE( ( m_aDocumentDataSource.has(DataAccessDescriptorProperty::DataSource) + || m_aDocumentDataSource.has(DataAccessDescriptorProperty::DatabaseLocation) + ) + && m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command) + && m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType), + "SbaTableQueryBrowser::statusChanged: incomplete descriptor!"); + + // check if we know the object which is set as document data source + checkDocumentDataSource(); + } + break; + + default: + // update the toolbox + implCheckExternalSlot( externalFeature.first ); + break; + } + break; + } + } + + OSL_ENSURE(bFound, "SbaTableQueryBrowser::statusChanged: don't know who sent this!"); +} + +void SbaTableQueryBrowser::checkDocumentDataSource() +{ + std::unique_ptr<weld::TreeIter> xDataSourceEntry; + std::unique_ptr<weld::TreeIter> xContainerEntry; + std::unique_ptr<weld::TreeIter> xObjectEntry = getObjectEntry(m_aDocumentDataSource, &xDataSourceEntry, &xContainerEntry); + bool bKnownDocDataSource = static_cast<bool>(xObjectEntry); + if (!bKnownDocDataSource) + { + if (xDataSourceEntry) + { + // at least the data source is known + if (xContainerEntry) + { + bKnownDocDataSource = true; // assume we know it. + // TODO: should we expand the object container? This may be too expensive just for checking... + } + else + { + if (m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType) + && m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command)) + { // maybe we have a command to be displayed ? + sal_Int32 nCommandType = CommandType::TABLE; + m_aDocumentDataSource[DataAccessDescriptorProperty::CommandType] >>= nCommandType; + + OUString sCommand; + m_aDocumentDataSource[DataAccessDescriptorProperty::Command] >>= sCommand; + + bKnownDocDataSource = (CommandType::COMMAND == nCommandType) && (!sCommand.isEmpty()); + } + } + } + } + + if ( !bKnownDocDataSource ) + m_aExternalFeatures[ ID_BROWSER_DOCUMENT_DATASOURCE ].bEnabled = false; + + // update the toolbox + implCheckExternalSlot(ID_BROWSER_DOCUMENT_DATASOURCE); +} + +void SbaTableQueryBrowser::extractDescriptorProps(const svx::ODataAccessDescriptor& _rDescriptor, OUString& _rDataSource, OUString& _rCommand, sal_Int32& _rCommandType, bool& _rEscapeProcessing) +{ + _rDataSource = _rDescriptor.getDataSource(); + if ( _rDescriptor.has(DataAccessDescriptorProperty::Command) ) + _rDescriptor[DataAccessDescriptorProperty::Command] >>= _rCommand; + if ( _rDescriptor.has(DataAccessDescriptorProperty::CommandType) ) + _rDescriptor[DataAccessDescriptorProperty::CommandType] >>= _rCommandType; + + // escape processing is the only one allowed not to be present + _rEscapeProcessing = true; + if (_rDescriptor.has(DataAccessDescriptorProperty::EscapeProcessing)) + _rEscapeProcessing = ::cppu::any2bool(_rDescriptor[DataAccessDescriptorProperty::EscapeProcessing]); +} + +namespace +{ + bool getDataSourceDisplayName_isURL( const OUString& _rDS, OUString& _rDisplayName, OUString& _rUniqueId ) + { + INetURLObject aURL( _rDS ); + if ( aURL.GetProtocol() != INetProtocol::NotValid ) + { + _rDisplayName = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset); + _rUniqueId = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + return true; + } + _rDisplayName = _rDS; + _rUniqueId.clear(); + return false; + } + + struct FilterByEntryDataId : public IEntryFilter + { + OUString sId; + explicit FilterByEntryDataId( const OUString& _rId ) : sId( _rId ) { } + + virtual ~FilterByEntryDataId() {} + + virtual bool includeEntry(const void* pEntry) const override; + }; + + bool FilterByEntryDataId::includeEntry(const void* pUserData) const + { + const DBTreeListUserData* pData = static_cast<const DBTreeListUserData*>(pUserData); + return ( !pData || ( pData->sAccessor == sId ) ); + } +} + +OUString SbaTableQueryBrowser::getDataSourceAccessor(const weld::TreeIter& rDataSourceEntry) const +{ + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rDataSourceEntry)); + OSL_ENSURE( pData, "SbaTableQueryBrowser::getDataSourceAccessor: invalid entry data!" ); + OSL_ENSURE( pData->eType == etDatasource, "SbaTableQueryBrowser::getDataSourceAccessor: entry does not denote a data source!" ); + return !pData->sAccessor.isEmpty() ? pData->sAccessor : GetEntryText(rDataSourceEntry); +} + +std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::getObjectEntry(const OUString& _rDataSource, const OUString& _rCommand, sal_Int32 nCommandType, + std::unique_ptr<weld::TreeIter>* ppDataSourceEntry, std::unique_ptr<weld::TreeIter>* ppContainerEntry, bool bExpandAncestors, + const SharedConnection& _rxConnection ) +{ + if (ppDataSourceEntry) + ppDataSourceEntry->reset(); + if (ppContainerEntry) + ppContainerEntry->reset(); + + std::unique_ptr<weld::TreeIter> xObject; + if ( m_pTreeView ) + { + // look for the data source entry + OUString sDisplayName, sDataSourceId; + bool bIsDataSourceURL = getDataSourceDisplayName_isURL( _rDataSource, sDisplayName, sDataSourceId ); + // the display name may differ from the URL for readability reasons + // #i33699# + + FilterByEntryDataId aFilter( sDataSourceId ); + std::unique_ptr<weld::TreeIter> xDataSource = m_pTreeView->GetEntryPosByName( sDisplayName, nullptr, &aFilter ); + if (!xDataSource) // check if the data source name is a file location + { + if ( bIsDataSourceURL ) + { + // special case, the data source is a URL + // add new entries to the list box model + implAddDatasource( _rDataSource, _rxConnection ); + xDataSource = m_pTreeView->GetEntryPosByName( sDisplayName, nullptr, &aFilter ); + OSL_ENSURE( xDataSource, "SbaTableQueryBrowser::getObjectEntry: hmm - did not find it again!" ); + } + } + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + + if (xDataSource) + { + if (ppDataSourceEntry) + { + // (caller wants to have it...) + *ppDataSourceEntry = rTreeView.make_iterator(xDataSource.get()); + } + + // expand if required so + if (bExpandAncestors) + rTreeView.expand_row(*xDataSource); + + // look for the object container + std::unique_ptr<weld::TreeIter> xCommandType; + if (nCommandType == CommandType::QUERY || nCommandType == CommandType::TABLE) + { + xCommandType = rTreeView.make_iterator(xDataSource.get()); + if (!rTreeView.iter_children(*xCommandType)) + xCommandType.reset(); + else + { + // 1st child is queries, so we're already done if looking for CommandType::QUERY + + // 2nd child is tables + if (nCommandType == CommandType::TABLE && !rTreeView.iter_next_sibling(*xCommandType)) + xCommandType.reset(); + } + } + + if (xCommandType) + { + if (ppContainerEntry) + { + // (caller wants to have it...) + *ppContainerEntry = rTreeView.make_iterator(xCommandType.get()); + } + + rTreeView.make_unsorted(); + + // expand if required so + if (bExpandAncestors) + { + rTreeView.expand_row(*xCommandType); + } + + // look for the object + sal_Int32 nIndex = 0; + do + { + OUString sPath; + switch (nCommandType) + { + case CommandType::TABLE: + sPath = _rCommand; + nIndex = -1; + break; + + case CommandType::QUERY: + sPath = _rCommand.getToken( 0, '/', nIndex ); + break; + + default: + assert(false); + } + xObject = m_pTreeView->GetEntryPosByName(sPath, xCommandType.get()); + if (xObject) + rTreeView.copy_iterator(*xObject, *xCommandType); + else + xCommandType.reset(); + if ( nIndex >= 0 ) + { + if (ensureEntryObject(*xObject)) + { + DBTreeListUserData* pParentData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xObject)); + Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY ); + sal_Int32 nIndex2 = nIndex; + sPath = _rCommand.getToken( 0, '/', nIndex2 ); + try + { + if ( xCollection->hasByName(sPath) ) + { + if(!m_pTreeView->GetEntryPosByName(sPath, xObject.get())) + { + Reference<XNameAccess> xChild(xCollection->getByName(sPath),UNO_QUERY); + DBTreeListUserData* pEntryData = new DBTreeListUserData; + pEntryData->eType = etQuery; + if ( xChild.is() ) + { + pEntryData->eType = etQueryContainer; + } + implAppendEntry(xObject.get(), sPath, pEntryData); + } + } + } + catch(const Exception&) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree"); + } + } + } + } + while ( nIndex >= 0 ); + + rTreeView.make_sorted(); + } + } + } + return xObject; +} + +std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::getObjectEntry(const svx::ODataAccessDescriptor& rDescriptor, + std::unique_ptr<weld::TreeIter>* ppDataSourceEntry, std::unique_ptr<weld::TreeIter>* ppContainerEntry) +{ + // extract the props from the descriptor + OUString sDataSource; + OUString sCommand; + sal_Int32 nCommandType = CommandType::COMMAND; + bool bEscapeProcessing = true; + extractDescriptorProps(rDescriptor, sDataSource, sCommand, nCommandType, bEscapeProcessing); + + return getObjectEntry(sDataSource, sCommand, nCommandType, ppDataSourceEntry, ppContainerEntry, false /*bExpandAncestors*/); +} + +void SbaTableQueryBrowser::connectExternalDispatches() +{ + Reference< XDispatchProvider > xProvider( getFrame(), UNO_QUERY ); + OSL_ENSURE(xProvider.is(), "SbaTableQueryBrowser::connectExternalDispatches: no DispatchProvider !"); + if (!xProvider.is()) + return; + + if ( m_aExternalFeatures.empty() ) + { + const char* pURLs[] = { + ".uno:DataSourceBrowser/DocumentDataSource", + ".uno:DataSourceBrowser/FormLetter", + ".uno:DataSourceBrowser/InsertColumns", + ".uno:DataSourceBrowser/InsertContent", + }; + const sal_uInt16 nIds[] = { + ID_BROWSER_DOCUMENT_DATASOURCE, + ID_BROWSER_FORMLETTER, + ID_BROWSER_INSERTCOLUMNS, + ID_BROWSER_INSERTCONTENT + }; + + for ( size_t i=0; i < SAL_N_ELEMENTS( pURLs ); ++i ) + { + URL aURL; + aURL.Complete = OUString::createFromAscii( pURLs[i] ); + if ( m_xUrlTransformer.is() ) + m_xUrlTransformer->parseStrict( aURL ); + m_aExternalFeatures[ nIds[ i ] ] = ExternalFeature( aURL ); + } + } + + for (auto & externalFeature : m_aExternalFeatures) + { + externalFeature.second.xDispatcher = xProvider->queryDispatch( + externalFeature.second.aURL, "_parent", FrameSearchFlag::PARENT + ); + + if ( externalFeature.second.xDispatcher.get() == static_cast< XDispatch* >( this ) ) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::connectExternalDispatches: this should not happen anymore!" ); + // (nowadays, the URLs aren't in our SupportedFeatures list anymore, so we should + // not supply a dispatcher for this) + externalFeature.second.xDispatcher.clear(); + } + + if ( externalFeature.second.xDispatcher.is() ) + { + try + { + externalFeature.second.xDispatcher->addStatusListener( this, externalFeature.second.aURL ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + implCheckExternalSlot( externalFeature.first ); + } +} + +void SbaTableQueryBrowser::implCheckExternalSlot( sal_uInt16 _nId ) +{ + if ( !m_xMainToolbar.is() ) + return; + + VclPtr<vcl::Window> pToolboxWindow = VCLUnoHelper::GetWindow( m_xMainToolbar ); + ToolBox* pToolbox = dynamic_cast< ToolBox* >( pToolboxWindow.get() ); + OSL_ENSURE( pToolbox, "SbaTableQueryBrowser::implCheckExternalSlot: cannot obtain the toolbox window!" ); + + // check if we have to hide this item from the toolbox + if ( pToolbox ) + { + bool bHaveDispatcher = m_aExternalFeatures[ _nId ].xDispatcher.is(); + if ( bHaveDispatcher != pToolbox->IsItemVisible( ToolBoxItemId(_nId) ) ) + bHaveDispatcher ? pToolbox->ShowItem( ToolBoxItemId(_nId) ) : pToolbox->HideItem( ToolBoxItemId(_nId) ); + } + + // and invalidate this feature in general + InvalidateFeature( _nId ); +} + +void SAL_CALL SbaTableQueryBrowser::disposing( const css::lang::EventObject& _rSource ) +{ + // our frame ? + Reference< css::frame::XFrame > xSourceFrame(_rSource.Source, UNO_QUERY); + if (m_xCurrentFrameParent.is() && (xSourceFrame == m_xCurrentFrameParent)) + m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this)); + else + { + // search the external dispatcher causing this call in our map + Reference< XDispatch > xSource(_rSource.Source, UNO_QUERY); + if(xSource.is()) + { + ExternalFeaturesMap::const_iterator aLoop = m_aExternalFeatures.begin(); + ExternalFeaturesMap::const_iterator aEnd = m_aExternalFeatures.end(); + while (aLoop != aEnd) + { + if ( aLoop->second.xDispatcher.get() == xSource.get() ) + { + sal_uInt16 nSlot = aLoop->first; + + // remove it + aLoop = m_aExternalFeatures.erase(aLoop); + + // maybe update the UI + implCheckExternalSlot(nSlot); + + // continue, the same XDispatch may be responsible for more than one URL + } + ++aLoop; + } + } + else + { + Reference<XConnection> xCon(_rSource.Source, UNO_QUERY); + if ( xCon.is() && m_pTreeView ) + { + // our connection is in dispose so we have to find the entry equal with this connection + // and close it what means to collapse the entry + // get the top-level representing the removed data source + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xDSLoop(rTreeView.make_iterator()); + if (rTreeView.get_iter_first(*xDSLoop)) + { + do + { + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDSLoop)); + if ( pData && pData->xConnection == xCon ) + { + // we set the connection to null to avoid a second disposing of the connection + pData->xConnection.clear(); + closeConnection(*xDSLoop, false); + break; + } + } + while (rTreeView.iter_next_sibling(*xDSLoop)); + } + } + else + SbaXDataBrowserController::disposing(_rSource); + } + } +} + +void SbaTableQueryBrowser::implRemoveStatusListeners() +{ + // clear all old dispatches + for (auto const& externalFeature : m_aExternalFeatures) + { + if ( externalFeature.second.xDispatcher.is() ) + { + try + { + externalFeature.second.xDispatcher->removeStatusListener( this, externalFeature.second.aURL ); + } + catch (Exception&) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::implRemoveStatusListeners: could not remove a status listener!"); + } + } + } + m_aExternalFeatures.clear(); +} + +sal_Bool SAL_CALL SbaTableQueryBrowser::select( const Any& _rSelection ) +{ + SolarMutexGuard aGuard; + // doin' a lot of VCL stuff here -> lock the SolarMutex + + Sequence< PropertyValue > aDescriptorSequence; + if (!(_rSelection >>= aDescriptorSequence)) + throw IllegalArgumentException(OUString(), *this, 1); + // TODO: error message + + ODataAccessDescriptor aDescriptor; + try + { + aDescriptor = ODataAccessDescriptor(aDescriptorSequence); + } + catch(const Exception&) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::select: could not extract the descriptor!"); + } + + // check the presence of the props we need + if ( !(aDescriptor.has(DataAccessDescriptorProperty::DataSource) || aDescriptor.has(DataAccessDescriptorProperty::DatabaseLocation)) || !aDescriptor.has(DataAccessDescriptorProperty::Command) || !aDescriptor.has(DataAccessDescriptorProperty::CommandType)) + throw IllegalArgumentException(OUString(), *this, 1); + // TODO: error message + + return implSelect(aDescriptor,true); +} + +Any SAL_CALL SbaTableQueryBrowser::getSelection( ) +{ + Any aReturn; + + try + { + Reference< XLoadable > xLoadable(getRowSet(), UNO_QUERY); + if (xLoadable.is() && xLoadable->isLoaded()) + { + Reference< XPropertySet > aFormProps(getRowSet(), UNO_QUERY); + ODataAccessDescriptor aDescriptor(aFormProps); + // remove properties which are not part of our "selection" + aDescriptor.erase(DataAccessDescriptorProperty::Connection); + aDescriptor.erase(DataAccessDescriptorProperty::Cursor); + + aReturn <<= aDescriptor.createPropertyValueSequence(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return aReturn; +} + +void SAL_CALL SbaTableQueryBrowser::addSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener ) +{ + m_aSelectionListeners.addInterface(_rxListener); +} + +void SAL_CALL SbaTableQueryBrowser::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener ) +{ + m_aSelectionListeners.removeInterface(_rxListener); +} + +void SbaTableQueryBrowser::attachFrame(const Reference< css::frame::XFrame > & _xFrame) +{ + implRemoveStatusListeners(); + + if (m_xCurrentFrameParent.is()) + m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this)); + + SbaXDataBrowserController::attachFrame(_xFrame); + + Reference< XFrame > xCurrentFrame( getFrame() ); + if ( xCurrentFrame.is() ) + { + m_xCurrentFrameParent = xCurrentFrame->findFrame("_parent",FrameSearchFlag::PARENT); + if ( m_xCurrentFrameParent.is() ) + m_xCurrentFrameParent->addFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this)); + + // obtain our toolbox + try + { + Reference< XPropertySet > xFrameProps( m_aCurrentFrame.getFrame(), UNO_QUERY_THROW ); + Reference< XLayoutManager > xLayouter( + xFrameProps->getPropertyValue("LayoutManager"), + UNO_QUERY ); + + if ( xLayouter.is() ) + { + Reference< XUIElement > xUI( + xLayouter->getElement( "private:resource/toolbar/toolbar" ), + UNO_SET_THROW ); + m_xMainToolbar.set(xUI->getRealInterface(), css::uno::UNO_QUERY); + OSL_ENSURE( m_xMainToolbar.is(), "SbaTableQueryBrowser::attachFrame: where's my toolbox?" ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + // get the dispatchers for the external slots + connectExternalDispatches(); +} + +void SbaTableQueryBrowser::addModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel) +{ + SbaXDataBrowserController::addModelListeners(_xGridControlModel); + Reference< XPropertySet > xSourceSet(_xGridControlModel, UNO_QUERY); + if (xSourceSet.is()) + { + xSourceSet->addPropertyChangeListener(PROPERTY_ROW_HEIGHT, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->addPropertyChangeListener(PROPERTY_FONT, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->addPropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->addPropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->addPropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->addPropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast<XPropertyChangeListener*>(this)); + } + +} + +void SbaTableQueryBrowser::removeModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel) +{ + SbaXDataBrowserController::removeModelListeners(_xGridControlModel); + Reference< XPropertySet > xSourceSet(_xGridControlModel, UNO_QUERY); + if (xSourceSet.is()) + { + xSourceSet->removePropertyChangeListener(PROPERTY_ROW_HEIGHT, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_FONT, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast<XPropertyChangeListener*>(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast<XPropertyChangeListener*>(this)); + } +} + +void SbaTableQueryBrowser::RowChanged() +{ + if(getBrowserView()) + { + SbaGridControl* pControl = getBrowserView()->getVclControl(); + if (!pControl->IsEditing()) + InvalidateFeature(ID_BROWSER_COPY); + } + SbaXDataBrowserController::RowChanged(); +} + +void SbaTableQueryBrowser::ColumnChanged() +{ + if(getBrowserView()) + { + SbaGridControl* pControl = getBrowserView()->getVclControl(); + if (!pControl->IsEditing()) + InvalidateFeature(ID_BROWSER_COPY); + } + SbaXDataBrowserController::ColumnChanged(); +} + +void SbaTableQueryBrowser::AddColumnListener(const Reference< XPropertySet > & xCol) +{ + SbaXDataBrowserController::AddColumnListener(xCol); + SafeAddPropertyListener(xCol, PROPERTY_WIDTH, static_cast<XPropertyChangeListener*>(this)); + SafeAddPropertyListener(xCol, PROPERTY_HIDDEN, static_cast<XPropertyChangeListener*>(this)); + SafeAddPropertyListener(xCol, PROPERTY_ALIGN, static_cast<XPropertyChangeListener*>(this)); + SafeAddPropertyListener(xCol, PROPERTY_FORMATKEY, static_cast<XPropertyChangeListener*>(this)); +} + +void SbaTableQueryBrowser::RemoveColumnListener(const Reference< XPropertySet > & xCol) +{ + SbaXDataBrowserController::RemoveColumnListener(xCol); + SafeRemovePropertyListener(xCol, PROPERTY_WIDTH, static_cast<XPropertyChangeListener*>(this)); + SafeRemovePropertyListener(xCol, PROPERTY_HIDDEN, static_cast<XPropertyChangeListener*>(this)); + SafeRemovePropertyListener(xCol, PROPERTY_ALIGN, static_cast<XPropertyChangeListener*>(this)); + SafeRemovePropertyListener(xCol, PROPERTY_FORMATKEY, static_cast<XPropertyChangeListener*>(this)); +} + +void SbaTableQueryBrowser::criticalFail() +{ + SbaXDataBrowserController::criticalFail(); + unloadAndCleanup( false ); +} + +void SbaTableQueryBrowser::LoadFinished(bool _bWasSynch) +{ + SbaXDataBrowserController::LoadFinished(_bWasSynch); + + m_sQueryCommand.clear(); + m_bQueryEscapeProcessing = false; + + if (isValid() && !loadingCancelled()) + { + // did we load a query? + bool bTemporary; // needed because we m_bQueryEscapeProcessing is only one bit wide (and we want to pass it by reference) + if ( implGetQuerySignature( m_sQueryCommand, bTemporary ) ) + m_bQueryEscapeProcessing = bTemporary; + } + + // if the form has been loaded, this means that our "selection" has changed + css::lang::EventObject aEvent( *this ); + m_aSelectionListeners.notifyEach( &XSelectionChangeListener::selectionChanged, aEvent ); +} + +bool SbaTableQueryBrowser::getExternalSlotState( sal_uInt16 _nId ) const +{ + bool bEnabled = false; + ExternalFeaturesMap::const_iterator aPos = m_aExternalFeatures.find( _nId ); + if ( ( m_aExternalFeatures.end() != aPos ) && aPos->second.xDispatcher.is() ) + bEnabled = aPos->second.bEnabled; + return bEnabled; +} + +FeatureState SbaTableQueryBrowser::GetState(sal_uInt16 nId) const +{ + FeatureState aReturn; + // (disabled automatically) + + // no chance without a view + if (!getBrowserView() || !getBrowserView()->getVclControl()) + return aReturn; + + switch ( nId ) + { + case ID_TREE_ADMINISTRATE: + aReturn.bEnabled = true; + return aReturn; + + case ID_BROWSER_CLOSE: + // the close button should always be enabled + aReturn.bEnabled = !m_bEnableBrowser; + return aReturn; + + // "toggle explorer" is always enabled (if we have an explorer) + case ID_BROWSER_EXPLORER: + aReturn.bEnabled = m_bEnableBrowser; + aReturn.bChecked = haveExplorer(); + return aReturn; + + case ID_BROWSER_REMOVEFILTER: + return SbaXDataBrowserController::GetState( nId ); + + case ID_BROWSER_COPY: + if ( !m_pTreeView->HasChildPathFocus() ) + // handled below + break; + [[fallthrough]]; + case ID_TREE_CLOSE_CONN: + case ID_TREE_EDIT_DATABASE: + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xCurrentEntry(rTreeView.make_iterator()); + if (!rTreeView.get_cursor(xCurrentEntry.get())) + return aReturn; + + EntryType eType = getEntryType(*xCurrentEntry); + if ( eType == etUnknown ) + return aReturn; + + std::unique_ptr<weld::TreeIter> xDataSourceEntry = m_pTreeView->GetRootLevelParent(xCurrentEntry.get()); + DBTreeListUserData* pDSData + = xDataSourceEntry + ? weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDataSourceEntry)) + : nullptr; + + if ( nId == ID_TREE_CLOSE_CONN ) + { + aReturn.bEnabled = ( pDSData != nullptr ) && pDSData->xConnection.is(); + } + else if ( nId == ID_TREE_EDIT_DATABASE ) + { + ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithComponentContext( getORB(), + "/org.openoffice.Office.DataAccess/Policies/Features/Common" ) ); + bool bHaveEditDatabase( true ); + OSL_VERIFY( aConfig.getNodeValue( "EditDatabaseFromDataSourceView" ) >>= bHaveEditDatabase ); + aReturn.bEnabled = getORB().is() && xDataSourceEntry && bHaveEditDatabase; + } + else if ( nId == ID_BROWSER_COPY ) + { + aReturn.bEnabled = isEntryCopyAllowed(*xCurrentEntry); + } + + return aReturn; + } + } + + // all slots not handled above are not available if no form is loaded + if (!isLoaded()) + return aReturn; + + try + { + bool bHandled = false; + switch (nId) + { + case ID_BROWSER_DOCUMENT_DATASOURCE: + // the slot is enabled if we have an external dispatcher able to handle it, + // and the dispatcher must have enabled the slot in general + aReturn.bEnabled = getExternalSlotState( ID_BROWSER_DOCUMENT_DATASOURCE ); + bHandled = true; + break; + case ID_BROWSER_REFRESH: + aReturn.bEnabled = true; + bHandled = true; + break; + } + + if (bHandled) + return aReturn; + + // no chance without valid models + if (isValid() && !isValidCursor() && nId != ID_BROWSER_CLOSE) + return aReturn; + + switch (nId) + { + case ID_BROWSER_INSERTCOLUMNS: + case ID_BROWSER_INSERTCONTENT: + case ID_BROWSER_FORMLETTER: + { + // the slot is enabled if we have an external dispatcher able to handle it, + // and the dispatcher must have enabled the slot in general + aReturn.bEnabled = getExternalSlotState( nId ); + + // for the Insert* slots, we need at least one selected row + if (ID_BROWSER_FORMLETTER != nId) + aReturn.bEnabled = aReturn.bEnabled && getBrowserView()->getVclControl()->GetSelectRowCount(); + + // disabled for native queries which are not saved within the database + Reference< XPropertySet > xDataSource(getRowSet(), UNO_QUERY); + try + { + aReturn.bEnabled = aReturn.bEnabled && xDataSource.is(); + + if (xDataSource.is()) + { + sal_Int32 nType = ::comphelper::getINT32(xDataSource->getPropertyValue(PROPERTY_COMMAND_TYPE)); + aReturn.bEnabled = aReturn.bEnabled && + ( ::comphelper::getBOOL(xDataSource->getPropertyValue(PROPERTY_ESCAPE_PROCESSING)) || + (nType == css::sdb::CommandType::QUERY) ); + } + } + catch(DisposedException&) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::GetState: object already disposed!"); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + break; + + case ID_BROWSER_TITLE: + { + Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY); + sal_Int32 nCommandType = CommandType::TABLE; + xProp->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nCommandType; + OUString sTitle; + switch (nCommandType) + { + case CommandType::TABLE: + sTitle = DBA_RES(STR_TBL_TITLE); break; + case CommandType::QUERY: + case CommandType::COMMAND: + sTitle = DBA_RES(STR_QRY_TITLE); break; + default: + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::GetState: unknown command type!"); + } + OUString aName; + xProp->getPropertyValue(PROPERTY_COMMAND) >>= aName; + OUString sObject(aName); + + aReturn.sTitle = sTitle.replaceFirst("#", sObject); + aReturn.bEnabled = true; + } + break; + case ID_BROWSER_TABLEATTR: + case ID_BROWSER_ROWHEIGHT: + case ID_BROWSER_COLATTRSET: + case ID_BROWSER_COLWIDTH: + aReturn.bEnabled = getBrowserView()->getVclControl() && isValid() && isValidCursor(); + // aReturn.bEnabled &= getDefinition() && !getDefinition()->GetDatabase()->IsReadOnly(); + break; + + case ID_BROWSER_COPY: + OSL_ENSURE( !m_pTreeView->HasChildPathFocus(), "SbaTableQueryBrowser::GetState( ID_BROWSER_COPY ): this should have been handled above!" ); + if (getBrowserView()->getVclControl() && !getBrowserView()->getVclControl()->IsEditing()) + { + SbaGridControl* pControl = getBrowserView()->getVclControl(); + if ( pControl->GetSelectRowCount() ) + { + aReturn.bEnabled = m_aCurrentFrame.isActive(); + break; + } + else + aReturn.bEnabled = pControl->canCopyCellText(pControl->GetCurRow(), pControl->GetCurColumnId()); + break; + } + [[fallthrough]]; + default: + return SbaXDataBrowserController::GetState(nId); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return aReturn; + +} + +void SbaTableQueryBrowser::Execute(sal_uInt16 nId, const Sequence< PropertyValue >& aArgs) +{ + switch (nId) + { + default: + SbaXDataBrowserController::Execute(nId,aArgs); + break; + + case ID_TREE_EDIT_DATABASE: + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator()); + if (rTreeView.get_cursor(xIter.get())) + implAdministrate(*xIter); + break; + } + case ID_TREE_CLOSE_CONN: + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator()); + if (rTreeView.get_cursor(xIter.get())) + { + xIter = m_pTreeView->GetRootLevelParent(xIter.get()); + closeConnection(*xIter); + } + break; + } + case ID_TREE_ADMINISTRATE: + svx::administrateDatabaseRegistration( getFrameWeld() ); + break; + + case ID_BROWSER_REFRESH: + { + if ( !SaveModified( ) ) + // nothing to do + break; + + bool bFullReinit = false; + // check if the query signature (if the form is based on a query) has changed + if ( !m_sQueryCommand.isEmpty() ) + { + OUString sNewQueryCommand; + bool bNewQueryEP; + + bool bIsQuery = + implGetQuerySignature( sNewQueryCommand, bNewQueryEP ); + OSL_ENSURE( bIsQuery, "SbaTableQueryBrowser::Execute: was a query before, but is not anymore?" ); + + bFullReinit = ( sNewQueryCommand != m_sQueryCommand ) || ( m_bQueryEscapeProcessing != bNewQueryEP ); + } + if ( !bFullReinit ) + { + // let the base class do a simple reload + SbaXDataBrowserController::Execute(nId,aArgs); + break; + } + [[fallthrough]]; + } + + case ID_BROWSER_REFRESH_REBUILD: + { + if ( !SaveModified() ) + // nothing to do + break; + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xSelected = m_xCurrentlyDisplayed ? + rTreeView.make_iterator(m_xCurrentlyDisplayed.get()) : nullptr; + + // unload + unloadAndCleanup( false ); + + // reselect the entry + if ( xSelected ) + { + implSelect(xSelected.get()); + } + else + { + Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY); + implSelect(svx::ODataAccessDescriptor(xProp)); + } + } + break; + + case ID_BROWSER_EXPLORER: + toggleExplorer(); + break; + + case ID_BROWSER_DOCUMENT_DATASOURCE: + implSelect(m_aDocumentDataSource); + break; + + case ID_BROWSER_INSERTCOLUMNS: + case ID_BROWSER_INSERTCONTENT: + case ID_BROWSER_FORMLETTER: + if (getBrowserView() && isValidCursor()) + { + // the URL the slot id is assigned to + OSL_ENSURE( m_aExternalFeatures.find( nId ) != m_aExternalFeatures.end(), + "SbaTableQueryBrowser::Execute( ID_BROWSER_?): how could this ever be enabled?" ); + URL aParentUrl = m_aExternalFeatures[ nId ].aURL; + + // let the dispatcher execute the slot + Reference< XDispatch > xDispatch( m_aExternalFeatures[ nId ].xDispatcher ); + if (xDispatch.is()) + { + // set the properties for the dispatch + + // first fill the selection + SbaGridControl* pGrid = getBrowserView()->getVclControl(); + MultiSelection* pSelection = const_cast<MultiSelection*>(pGrid->GetSelection()); + Sequence< Any > aSelection; + if ( !pGrid->IsAllSelected() ) + { // transfer the selected rows only if not all rows are selected + // (all rows means the whole table) + // #i3832# + if (pSelection != nullptr) + { + aSelection.realloc(pSelection->GetSelectCount()); + tools::Long nIdx = pSelection->FirstSelected(); + Any* pSelectionNos = aSelection.getArray(); + while (nIdx != SFX_ENDOFSELECTION) + { + *pSelectionNos++ <<= static_cast<sal_Int32>(nIdx + 1); + nIdx = pSelection->NextSelected(); + } + } + } + + Reference< XResultSet > xCursorClone; + try + { + Reference< XResultSetAccess > xResultSetAccess(getRowSet(),UNO_QUERY); + if (xResultSetAccess.is()) + xCursorClone = xResultSetAccess->createResultSet(); + } + catch(DisposedException&) + { + SAL_WARN("dbaccess.ui", "Object already disposed!"); + } + catch(const Exception&) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::Execute(ID_BROWSER_?): could not clone the cursor!"); + } + + Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY); + + try + { + ODataAccessDescriptor aDescriptor; + OUString sDataSourceName; + xProp->getPropertyValue(PROPERTY_DATASOURCENAME) >>= sDataSourceName; + + aDescriptor.setDataSource(sDataSourceName); + aDescriptor[DataAccessDescriptorProperty::Command] = xProp->getPropertyValue(PROPERTY_COMMAND); + aDescriptor[DataAccessDescriptorProperty::CommandType] = xProp->getPropertyValue(PROPERTY_COMMAND_TYPE); + aDescriptor[DataAccessDescriptorProperty::Connection] = xProp->getPropertyValue(PROPERTY_ACTIVE_CONNECTION); + aDescriptor[DataAccessDescriptorProperty::Cursor] <<= xCursorClone; + if ( aSelection.hasElements() ) + { + aDescriptor[DataAccessDescriptorProperty::Selection] <<= aSelection; + aDescriptor[DataAccessDescriptorProperty::BookmarkSelection] <<= false; + // these are selection indices + // before we change this, all clients have to be adjusted + // so that they recognize the new BookmarkSelection property! + } + + xDispatch->dispatch(aParentUrl, aDescriptor.createPropertyValueSequence()); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + break; + + case ID_BROWSER_CLOSE: + closeTask(); + // if it's not 0, such an async close is already pending + break; + + case ID_BROWSER_COPY: + if(m_pTreeView->HasChildPathFocus()) + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xCursor(rTreeView.make_iterator()); + if (rTreeView.get_cursor(xCursor.get())) + copyEntry(*xCursor); + } + else if (getBrowserView() && getBrowserView()->getVclControl() && !getBrowserView()->getVclControl()->IsEditing() && getBrowserView()->getVclControl()->GetSelectRowCount() < 1) + { + SbaGridControl* pControl = getBrowserView()->getVclControl(); + pControl->copyCellText(pControl->GetCurRow(), pControl->GetCurColumnId()); + } + else + SbaXDataBrowserController::Execute(nId,aArgs); + break; + } +} + +void SbaTableQueryBrowser::implAddDatasource( const OUString& _rDataSourceName, const SharedConnection& _rxConnection ) +{ + OUString a, b, c, d, e; + implAddDatasource( _rDataSourceName, a, d, b, e, c, _rxConnection ); +} + +void SbaTableQueryBrowser::implAddDatasource(const OUString& _rDbName, OUString& _rDbImage, + OUString& _rQueryName, OUString& _rQueryImage, OUString& _rTableName, OUString& _rTableImage, + const SharedConnection& _rxConnection) +{ + SolarMutexGuard aGuard; + // initialize the names/images if necessary + if (_rQueryName.isEmpty()) + _rQueryName = DBA_RES(RID_STR_QUERIES_CONTAINER); + if (_rTableName.isEmpty()) + _rTableName = DBA_RES(RID_STR_TABLES_CONTAINER); + + if (_rQueryImage.isEmpty()) + _rQueryImage = ImageProvider::getFolderImageId(DatabaseObject::QUERY); + if (_rTableImage.isEmpty()) + _rTableImage = ImageProvider::getFolderImageId(DatabaseObject::TABLE); + + if (_rDbImage.isEmpty()) + _rDbImage = ImageProvider::getDatabaseImage(); + + // add the entry for the data source + // special handling for data sources denoted by URLs - we do not want to display this ugly URL, do we? + // #i33699# + OUString sDSDisplayName, sDataSourceId; + getDataSourceDisplayName_isURL( _rDbName, sDSDisplayName, sDataSourceId ); + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pDSData = new DBTreeListUserData; + pDSData->eType = etDatasource; + pDSData->sAccessor = sDataSourceId; + pDSData->xConnection = _rxConnection; + OUString sId(weld::toId(pDSData)); + + std::unique_ptr<weld::TreeIter> xDatasourceEntry(rTreeView.make_iterator()); + rTreeView.insert(nullptr, -1, &sDSDisplayName, &sId, nullptr, nullptr, false, xDatasourceEntry.get()); + rTreeView.set_image(*xDatasourceEntry, _rDbImage); + rTreeView.set_text_emphasis(*xDatasourceEntry, false, 0); + + // the child for the queries container + { + DBTreeListUserData* pQueriesData = new DBTreeListUserData; + pQueriesData->eType = etQueryContainer; + sId = weld::toId(pQueriesData); + + std::unique_ptr<weld::TreeIter> xRet(rTreeView.make_iterator()); + rTreeView.insert(xDatasourceEntry.get(), -1, &_rQueryName, &sId, + nullptr, nullptr, true /*ChildrenOnDemand*/, xRet.get()); + rTreeView.set_image(*xRet, _rQueryImage); + rTreeView.set_text_emphasis(*xRet, false, 0); + } + + // the child for the tables container + { + DBTreeListUserData* pTablesData = new DBTreeListUserData; + pTablesData->eType = etTableContainer; + sId = weld::toId(pTablesData); + + std::unique_ptr<weld::TreeIter> xRet(rTreeView.make_iterator()); + rTreeView.insert(xDatasourceEntry.get(), -1, &_rTableName, &sId, + nullptr, nullptr, true /*ChildrenOnDemand*/, xRet.get()); + rTreeView.set_image(*xRet, _rTableImage); + rTreeView.set_text_emphasis(*xRet, false, 0); + } +} + +void SbaTableQueryBrowser::initializeTreeModel() +{ + if (m_xDatabaseContext.is()) + { + OUString aDBImage, aQueriesImage, aTablesImage; + OUString sQueriesName, sTablesName; + + // fill the model with the names of the registered datasources + const Sequence<OUString> aDatasourceNames = m_xDatabaseContext->getElementNames(); + for (const OUString& rDatasource : aDatasourceNames) + implAddDatasource( rDatasource, aDBImage, sQueriesName, aQueriesImage, sTablesName, aTablesImage, SharedConnection() ); + } +} + +void SbaTableQueryBrowser::populateTree(const Reference<XNameAccess>& _xNameAccess, + const weld::TreeIter& rParent, + EntryType eEntryType) +{ + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + rTreeView.make_unsorted(); + + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rParent)); + if (pData) // don't ask if the nameaccess is already set see OnExpandEntry views and tables + pData->xContainer = _xNameAccess; + + try + { + const Sequence<OUString> aNames = _xNameAccess->getElementNames(); + for (const OUString& rName : aNames) + { + if( !m_pTreeView->GetEntryPosByName(rName, &rParent)) + { + DBTreeListUserData* pEntryData = new DBTreeListUserData; + pEntryData->eType = eEntryType; + if ( eEntryType == etQuery ) + { + Reference<XNameAccess> xChild(_xNameAccess->getByName(rName),UNO_QUERY); + if ( xChild.is() ) + pEntryData->eType = etQueryContainer; + } + implAppendEntry(&rParent, rName, pEntryData); + } + } + } + catch(const Exception&) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree"); + } + + rTreeView.make_sorted(); +} + +std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::implAppendEntry(const weld::TreeIter* pParent, const OUString& rName, const DBTreeListUserData* pUserData) +{ + EntryType eEntryType = pUserData->eType; + + std::unique_ptr<ImageProvider> xImageProvider(getImageProviderFor(pParent)); + + OUString aImage = xImageProvider->getImageId(rName, getDatabaseObjectType(eEntryType)); + + OUString sId(weld::toId(pUserData)); + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xNewEntry(rTreeView.make_iterator()); + rTreeView.insert(pParent, -1, &rName, &sId, nullptr, nullptr, eEntryType == etQueryContainer, xNewEntry.get()); + rTreeView.set_image(*xNewEntry, aImage); + rTreeView.set_text_emphasis(*xNewEntry, false, 0); + + return xNewEntry; +} + +IMPL_LINK(SbaTableQueryBrowser, OnExpandEntry, const weld::TreeIter&, rParent, bool) +{ + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + if (rTreeView.iter_has_child(rParent)) + { + // nothing to do... + return true; + } + + std::unique_ptr<weld::TreeIter> xFirstParent = m_pTreeView->GetRootLevelParent(&rParent); + OSL_ENSURE(xFirstParent,"SbaTableQueryBrowser::OnExpandEntry: No rootlevelparent!"); + + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rParent)); + assert(pData && "SbaTableQueryBrowser::OnExpandEntry: No user data!"); + + if (etTableContainer == pData->eType) + { + weld::WaitObject aWaitCursor(getFrameWeld()); + + // it could be that we already have a connection + SharedConnection xConnection; + ensureConnection(xFirstParent.get(), xConnection); + + if ( xConnection.is() ) + { + SQLExceptionInfo aInfo; + try + { + Reference< XWarningsSupplier > xWarnings(xConnection, UNO_QUERY); + if (xWarnings.is()) + xWarnings->clearWarnings(); + + // first insert the views because the tables can also include + // views but that time the bitmap is the wrong one + // the nameaccess will be overwritten in populateTree + Reference<XViewsSupplier> xViewSup(xConnection,UNO_QUERY); + if(xViewSup.is()) + populateTree( xViewSup->getViews(), rParent, etTableOrView ); + + Reference<XTablesSupplier> xTabSup(xConnection,UNO_QUERY); + if(xTabSup.is()) + { + populateTree( xTabSup->getTables(), rParent, etTableOrView ); + Reference<XContainer> xCont(xTabSup->getTables(),UNO_QUERY); + if(xCont.is()) + // add as listener to know when elements are inserted or removed + xCont->addContainerListener(this); + } + + if (xWarnings.is()) + { +#if 0 + SQLExceptionInfo aWarnings(xWarnings->getWarnings()); +// Obviously this if test is always false. So to avoid a Clang warning +// "use of logical '&&' with constant operand" I put this in #if +// 0. Yeah, I know it is fairly likely nobody will ever read this +// comment and make a decision what to do here, so I could as well +// have just binned this... + if (aWarnings.isValid() && sal_False) + { + SQLContext aContext; + aContext.Message = DBA_RES(STR_OPENTABLES_WARNINGS); + aContext.Details = DBA_RES(STR_OPENTABLES_WARNINGS_DETAILS); + aContext.NextException = aWarnings.get(); + aWarnings = aContext; + showError(aWarnings); + } +#endif + // TODO: we need a better concept for these warnings: + // something like "don't show any warnings for this datasource, again" would be nice + // But this requires an extension of the InteractionHandler and an additional property on the data source + } + } + catch(const SQLContext& e) { aInfo = e; } + catch(const SQLWarning& e) { aInfo = e; } + catch(const SQLException& e) { aInfo = e; } + catch(const WrappedTargetException& e) + { + SQLException aSql; + if(e.TargetException >>= aSql) + aInfo = aSql; + else + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::OnExpandEntry: something strange happened!"); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + if (aInfo.isValid()) + showError(aInfo); + } + else + return false; + // 0 indicates that an error occurred + } + else + { + // we have to expand the queries or bookmarks + if (ensureEntryObject(rParent)) + { + DBTreeListUserData* pParentData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rParent)); + Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY ); + populateTree(xCollection, rParent, etQuery); + } + } + return true; +} + +bool SbaTableQueryBrowser::ensureEntryObject(const weld::TreeIter& rEntry) +{ + EntryType eType = getEntryType(rEntry); + + // the user data of the entry + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rEntry)); + OSL_ENSURE(pEntryData,"ensureEntryObject: user data should already be set!"); + + std::unique_ptr<weld::TreeIter> xDataSourceEntry = m_pTreeView->GetRootLevelParent(&rEntry); + + bool bSuccess = false; + switch (eType) + { + case etQueryContainer: + { + if ( pEntryData->xContainer.is() ) + { + // nothing to do + bSuccess = true; + break; + } + + std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator(&rEntry)); + if (rTreeView.iter_parent(*xParent)) + { + if (rTreeView.iter_compare(*xParent, *xDataSourceEntry) != 0) + { + OUString aName(rTreeView.get_text(rEntry)); + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xParent)); + try + { + Reference< XNameAccess > xNameAccess(pData->xContainer,UNO_QUERY); + if ( xNameAccess.is() ) + pEntryData->xContainer.set(xNameAccess->getByName(aName),UNO_QUERY); + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + bSuccess = pEntryData->xContainer.is(); + } + else + { + try + { + Reference< XQueryDefinitionsSupplier > xQuerySup; + m_xDatabaseContext->getByName(getDataSourceAccessor(*xDataSourceEntry)) >>= xQuerySup; + if (xQuerySup.is()) + { + Reference< XNameAccess > xQueryDefs = xQuerySup->getQueryDefinitions(); + Reference< XContainer > xCont(xQueryDefs, UNO_QUERY); + if (xCont.is()) + // add as listener to get notified if elements are inserted or removed + xCont->addContainerListener(this); + + pEntryData->xContainer = xQueryDefs; + bSuccess = pEntryData->xContainer.is(); + } + else { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::ensureEntryObject: no XQueryDefinitionsSupplier interface!"); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + break; + } + default: + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::ensureEntryObject: ooops ... missing some implementation here!"); + // TODO ... + break; + } + return bSuccess; +} + +bool SbaTableQueryBrowser::implSelect(const svx::ODataAccessDescriptor& _rDescriptor, bool _bSelectDirect) +{ + // extract the props + OUString sDataSource; + OUString sCommand; + sal_Int32 nCommandType = CommandType::COMMAND; + bool bEscapeProcessing = true; + extractDescriptorProps(_rDescriptor, sDataSource, sCommand, nCommandType, bEscapeProcessing); + + // select it + return implSelect( sDataSource, sCommand, nCommandType, bEscapeProcessing, SharedConnection(), _bSelectDirect ); +} + +bool SbaTableQueryBrowser::implLoadAnything(const OUString& _rDataSourceName, const OUString& _rCommand, + const sal_Int32 nCommandType, const bool _bEscapeProcessing, const SharedConnection& _rxConnection) +{ + try + { + Reference<XPropertySet> xProp( getRowSet(), UNO_QUERY_THROW ); + Reference< XLoadable > xLoadable( xProp, UNO_QUERY_THROW ); + // the values allowing the RowSet to re-execute + xProp->setPropertyValue(PROPERTY_DATASOURCENAME, Any(_rDataSourceName)); + if(_rxConnection.is()) + xProp->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( _rxConnection.getTyped() ) ); + + // set this _before_ setting the connection, else the rowset would rebuild it ... + xProp->setPropertyValue(PROPERTY_COMMAND_TYPE, Any(nCommandType)); + xProp->setPropertyValue(PROPERTY_COMMAND, Any(_rCommand)); + xProp->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, css::uno::Any(_bEscapeProcessing)); + if ( m_bPreview ) + { + xProp->setPropertyValue(PROPERTY_FETCHDIRECTION, Any(FetchDirection::FORWARD)); + } + + // the formatter depends on the data source we're working on, so rebuild it here ... + initFormatter(); + + // switch the grid to design mode while loading + getBrowserView()->getGridControl()->setDesignMode(true); + InitializeForm( xProp ); + + bool bSuccess = true; + + { + { + Reference< XNameContainer > xColContainer(getFormComponent(), UNO_QUERY); + // first we have to clear the grid + clearGridColumns(xColContainer); + } + FormErrorHelper aHelper(this); + // load the form + bSuccess = reloadForm(xLoadable); + + // initialize the model + InitializeGridModel(getFormComponent()); + + Any aVal = xProp->getPropertyValue(PROPERTY_ISNEW); + if (aVal.hasValue() && ::comphelper::getBOOL(aVal)) + { + // then set the default values and the parameters given from the parent + Reference< XReset> xReset(xProp, UNO_QUERY); + xReset->reset(); + } + + if ( m_bPreview ) + initializePreviewMode(); + + LoadFinished(true); + } + + InvalidateAll(); + return bSuccess; + } + catch( const SQLException& ) + { + Any aException( ::cppu::getCaughtException() ); + showError( SQLExceptionInfo( aException ) ); + } + catch( const WrappedTargetException& e ) + { + if ( e.TargetException.isExtractableTo( ::cppu::UnoType< SQLException >::get() ) ) + showError( SQLExceptionInfo( e.TargetException ) ); + else + { + TOOLS_WARN_EXCEPTION("dbaccess", ""); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + InvalidateAll(); + return false; +} + +bool SbaTableQueryBrowser::implSelect(const OUString& _rDataSourceName, const OUString& _rCommand, + const sal_Int32 nCommandType, const bool _bEscapeProcessing, + const SharedConnection& _rxConnection, + bool _bSelectDirect) +{ + if (!_rDataSourceName.getLength() || !_rCommand.getLength() || (-1 == nCommandType)) + return false; + + std::unique_ptr<weld::TreeIter> xDataSource; + std::unique_ptr<weld::TreeIter> xCommandType; + std::unique_ptr<weld::TreeIter> xCommand = getObjectEntry( _rDataSourceName, _rCommand, nCommandType, &xDataSource, &xCommandType, true, _rxConnection ); + + if (xCommand) + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + + bool bSuccess = true; + if ( _bSelectDirect ) + { + bSuccess = implSelect(xCommand.get()); + } + else + { + rTreeView.select(*xCommand); + } + + if ( bSuccess ) + { + rTreeView.scroll_to_row(*xCommand); + rTreeView.set_cursor(*xCommand); + } + } + else if (!xCommandType) + { + if (m_xCurrentlyDisplayed) + { + // tell the old entry (if any) it has been deselected + selectPath(m_xCurrentlyDisplayed.get(), false); + m_xCurrentlyDisplayed.reset(); + } + + // we have a command and need to display this in the rowset + return implLoadAnything(_rDataSourceName, _rCommand, nCommandType, _bEscapeProcessing, _rxConnection); + } + return false; +} + +IMPL_LINK_NOARG(SbaTableQueryBrowser, OnSelectionChange, LinkParamNone*, void) +{ + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xSelection(rTreeView.make_iterator()); + if (!rTreeView.get_selected(xSelection.get())) + xSelection.reset(); + implSelect(xSelection.get()); +} + +std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::implGetConnectionEntry(const weld::TreeIter& rEntry) const +{ + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xCurrentEntry(rTreeView.make_iterator(&rEntry)); + DBTreeListUserData* pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xCurrentEntry)); + while (pEntryData->eType != etDatasource) + { + rTreeView.iter_parent(*xCurrentEntry); + pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xCurrentEntry)); + } + return xCurrentEntry; +} + +bool SbaTableQueryBrowser::implSelect(const weld::TreeIter* pEntry) +{ + if ( !pEntry ) + return false; + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*pEntry)); + switch (pEntryData->eType) + { + case etTableOrView: + case etQuery: + break; + default: + // nothing to do + return false; + } + + OSL_ENSURE(rTreeView.get_iter_depth(*pEntry) >= 2, "SbaTableQueryBrowser::implSelect: invalid entry!"); + + // get the entry for the tables or queries + std::unique_ptr<weld::TreeIter> xContainer = rTreeView.make_iterator(pEntry); + rTreeView.iter_parent(*xContainer); + DBTreeListUserData* pContainerData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xContainer)); + + // get the entry for the datasource + std::unique_ptr<weld::TreeIter> xConnection = implGetConnectionEntry(*xContainer); + DBTreeListUserData* pConData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xConnection)); + + // reinitialize the rowset + // but first check if it is necessary + // get all old properties + Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY); + OUString aOldName; + xRowSetProps->getPropertyValue(PROPERTY_COMMAND) >>= aOldName; + sal_Int32 nOldType = 0; + xRowSetProps->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nOldType; + Reference<XConnection> xOldConnection(xRowSetProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY); + + // the name of the table or query + const OUString sSimpleName = rTreeView.get_text(*pEntry); + OUStringBuffer sNameBuffer(sSimpleName); + if ( etQueryContainer == pContainerData->eType ) + { + std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(xContainer.get()); + std::unique_ptr<weld::TreeIter> xNextTemp = rTreeView.make_iterator(xTemp.get()); + if (rTreeView.iter_parent(*xNextTemp)) + { + while (rTreeView.iter_compare(*xNextTemp, *xConnection) != 0) + { + sNameBuffer.insert(0,'/'); + sNameBuffer.insert(0, rTreeView.get_text(*xTemp)); + rTreeView.copy_iterator(*xNextTemp, *xTemp); + if (!rTreeView.iter_parent(*xNextTemp)) + break; + } + } + } + OUString aName = sNameBuffer.makeStringAndClear(); + + sal_Int32 nCommandType = ( etTableContainer == pContainerData->eType) + ? CommandType::TABLE + : CommandType::QUERY; + + // check if need to rebuild the rowset + bool bRebuild = ( xOldConnection != pConData->xConnection ) + || ( nOldType != nCommandType ) + || ( aName != aOldName ); + + Reference< css::form::XLoadable > xLoadable = getLoadable(); + bRebuild |= !xLoadable->isLoaded(); + bool bSuccess = true; + if ( bRebuild ) + { + try + { + weld::WaitObject aWaitCursor(getFrameWeld()); + + // tell the old entry it has been deselected + selectPath(m_xCurrentlyDisplayed.get(), false); + m_xCurrentlyDisplayed.reset(); + + // not really loaded + m_xCurrentlyDisplayed = rTreeView.make_iterator(pEntry); + // tell the new entry it has been selected + selectPath(m_xCurrentlyDisplayed.get()); + + // get the name of the data source currently selected + ensureConnection(m_xCurrentlyDisplayed.get(), pConData->xConnection); + + if ( !pConData->xConnection.is() ) + { + unloadAndCleanup( false ); + return false; + } + + Reference<XNameAccess> xNameAccess; + switch(nCommandType) + { + case CommandType::TABLE: + { + // only for tables + if ( !pContainerData->xContainer.is() ) + { + Reference<XTablesSupplier> xSup( pConData->xConnection, UNO_QUERY ); + if(xSup.is()) + xNameAccess = xSup->getTables(); + + pContainerData->xContainer = xNameAccess; + } + else + xNameAccess.set( pContainerData->xContainer, UNO_QUERY ); + } + break; + case CommandType::QUERY: + { + if ( pContainerData->xContainer.is() ) + xNameAccess.set( pContainerData->xContainer, UNO_QUERY ); + else + { + Reference<XQueriesSupplier> xSup( pConData->xConnection, UNO_QUERY ); + if(xSup.is()) + xNameAccess = xSup->getQueries(); + } + } + break; + } + OUString sStatus(DBA_RES(CommandType::TABLE == nCommandType ? STR_LOADING_TABLE : STR_LOADING_QUERY)); + sStatus = sStatus.replaceFirst("$name$", aName); + BrowserViewStatusDisplay aShowStatus(static_cast<UnoDataBrowserView*>(getView()), sStatus); + + bool bEscapeProcessing = true; + if(xNameAccess.is() && xNameAccess->hasByName(sSimpleName)) + { + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*pEntry)); + if ( !pData->xObjectProperties.is() ) + { + Reference<XInterface> xObject; + if(xNameAccess->getByName(sSimpleName) >>= xObject) // remember the table or query object + { + pData->xObjectProperties.set(xObject, css::uno::UNO_QUERY); + // if the query contains a parameterized statement and preview is enabled we won't get any data. + if ( nCommandType == CommandType::QUERY && xObject.is() ) + { + Reference<XPropertySet> xObjectProps(xObject,UNO_QUERY); + xObjectProps->getPropertyValue(PROPERTY_ESCAPE_PROCESSING) >>= bEscapeProcessing; + if ( m_bPreview ) + { + OUString sSql; + xObjectProps->getPropertyValue(PROPERTY_COMMAND) >>= sSql; + Reference< XMultiServiceFactory > xFactory( pConData->xConnection, UNO_QUERY ); + if (xFactory.is()) + { + try + { + Reference<XSingleSelectQueryAnalyzer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY); + if ( xAnalyzer.is() ) + { + xAnalyzer->setQuery(sSql); + Reference<XParametersSupplier> xParSup(xAnalyzer,UNO_QUERY); + if ( xParSup->getParameters()->getCount() > 0 ) + { + OUString sFilter = " WHERE " + xAnalyzer->getFilter(); + OUString sReplace = sSql.replaceFirst(sFilter, ""); + xAnalyzer->setQuery(sReplace); + Reference<XSingleSelectQueryComposer> xComposer(xAnalyzer,UNO_QUERY); + xComposer->setFilter("0=1"); + aName = xAnalyzer->getQuery(); + nCommandType = CommandType::COMMAND; + } + } + } + catch (Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + } + } + } + } + + OUString sDataSourceName(getDataSourceAccessor(*xConnection)); + bSuccess = implLoadAnything( sDataSourceName, aName, nCommandType, bEscapeProcessing, pConData->xConnection ); + if ( !bSuccess ) + { // clean up + criticalFail(); + } + } + catch(const SQLException& e) + { + showError(SQLExceptionInfo(e)); + // reset the values + xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any()); + xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any()); + bSuccess = false; + } + catch(WrappedTargetException& e) + { + SQLException aSql; + if(e.TargetException >>= aSql) + showError(SQLExceptionInfo(aSql)); + else + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::implSelect: something strange happened!"); + // reset the values + xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any()); + xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any()); + bSuccess = false; + } + catch(const Exception&) + { + // reset the values + xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any()); + xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any()); + bSuccess = false; + } + } + return bSuccess; +} + +std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::getEntryFromContainer(const Reference<XNameAccess>& rxNameAccess) +{ + std::unique_ptr<weld::TreeIter> xContainer; + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xDSLoop(rTreeView.make_iterator(xContainer.get())); + if (rTreeView.get_iter_first(*xDSLoop)) + { + do + { + xContainer = rTreeView.make_iterator(xDSLoop.get()); + if (rTreeView.iter_children(*xContainer)) + { + // 1st child is queries + DBTreeListUserData* pQueriesData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xContainer)); + if (pQueriesData && pQueriesData->xContainer == rxNameAccess) + break; + + if (rTreeView.iter_next_sibling(*xContainer)) + { + // 2nd child is tables + DBTreeListUserData* pTablesData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xContainer)); + if (pTablesData && pTablesData->xContainer == rxNameAccess) + break; + } + } + xContainer.reset(); + } + while (rTreeView.iter_next_sibling(*xDSLoop)); + } + + return xContainer; +} + +void SAL_CALL SbaTableQueryBrowser::elementInserted(const ContainerEvent& rEvent) +{ + SolarMutexGuard aSolarGuard; + + Reference< XNameAccess > xNames(rEvent.Source, UNO_QUERY); + // first search for a definition container where we can insert this element + + std::unique_ptr<weld::TreeIter> xEntry = getEntryFromContainer(xNames); + if (xEntry) // found one + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + rTreeView.make_unsorted(); + + // insert the new entry into the tree + DBTreeListUserData* pContainerData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xEntry)); + OSL_ENSURE(pContainerData, "elementInserted: There must be user data for this type!"); + + DBTreeListUserData* pNewData = new DBTreeListUserData; + bool bIsTable = etTableContainer == pContainerData->eType; + if ( bIsTable ) + { + rEvent.Element >>= pNewData->xObjectProperties;// remember the new element + pNewData->eType = etTableOrView; + } + else + { + if (rTreeView.iter_n_children(*xEntry) < xNames->getElementNames().getLength() - 1) + { + // the item inserts its children on demand, but it has not been expanded yet. So ensure here and + // now that it has all items + populateTree(xNames, *xEntry, etQuery); + } + pNewData->eType = etQuery; + } + implAppendEntry(xEntry.get(), ::comphelper::getString(rEvent.Accessor), pNewData); + + rTreeView.make_sorted(); + } + else + SbaXDataBrowserController::elementInserted(rEvent); +} + +bool SbaTableQueryBrowser::isCurrentlyDisplayedChanged(std::u16string_view rName, const weld::TreeIter& rContainer) +{ + if (!m_xCurrentlyDisplayed) + return false; + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + if (getEntryType(*m_xCurrentlyDisplayed) != getChildType(rContainer)) + return false; + if (rTreeView.get_text(*m_xCurrentlyDisplayed) != rName) + return false; + std::unique_ptr<weld::TreeIter> xParent = rTreeView.make_iterator(m_xCurrentlyDisplayed.get()); + return rTreeView.iter_parent(*xParent) && rTreeView.iter_compare(*xParent, rContainer) == 0; +} + +void SAL_CALL SbaTableQueryBrowser::elementRemoved( const ContainerEvent& _rEvent ) +{ + SolarMutexGuard aSolarGuard; + + Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY); + // get the top-level representing the removed data source + // and search for the queries and tables + std::unique_ptr<weld::TreeIter> xContainer = getEntryFromContainer(xNames); + if (xContainer) + { + // a query or table has been removed + OUString aName = ::comphelper::getString(_rEvent.Accessor); + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + if (isCurrentlyDisplayedChanged(aName, *xContainer)) + { + // the element displayed currently has been replaced + + // we need to remember the old value + std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(m_xCurrentlyDisplayed.get()); + + // unload + unloadAndCleanup( false ); // don't dispose the connection + + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xTemp)); + rTreeView.set_id(*xTemp, OUString()); + delete pData; // the data could be null because we have a table which isn't correct + rTreeView.remove(*xTemp); + } + else + { + // remove the entry from the model + std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xContainer.get())); + if (rTreeView.get_iter_first(*xChild)) + { + do + { + if (rTreeView.get_text(*xChild) == aName) + { + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xChild)); + rTreeView.set_id(*xChild, OUString()); + delete pData; + rTreeView.remove(*xChild); + break; + } + } while (rTreeView.iter_next_sibling(*xChild)); + } + } + + // maybe the object which is part of the document data source has been removed + checkDocumentDataSource(); + } + else + SbaXDataBrowserController::elementRemoved(_rEvent); +} + +void SAL_CALL SbaTableQueryBrowser::elementReplaced( const ContainerEvent& _rEvent ) +{ + SolarMutexGuard aSolarGuard; + + Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY); + std::unique_ptr<weld::TreeIter> xContainer = getEntryFromContainer(xNames); + if (xContainer) + { + // a table or query as been replaced + OUString aName = ::comphelper::getString(_rEvent.Accessor); + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + if (isCurrentlyDisplayedChanged(aName, *xContainer)) + { // the element displayed currently has been replaced + + // we need to remember the old value + std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(m_xCurrentlyDisplayed.get()); + unloadAndCleanup( false ); // don't dispose the connection + + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xTemp)); + if (pData) + { + if ( etTableOrView == pData->eType ) + { + // only insert userdata when we have a table because the query is only a commanddefinition object and not a query + _rEvent.Element >>= pData->xObjectProperties; // remember the new element + } + else + { + rTreeView.set_id(*xTemp, OUString()); + delete pData; + } + } + } + else + { + // find the entry for this name + std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xContainer.get())); + if (rTreeView.get_iter_first(*xChild)) + { + do + { + if (rTreeView.get_text(*xChild) == aName) + { + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xChild)); + if (pData) + { + if ( etTableOrView == pData->eType ) + { + // only insert userdata when we have a table because the query is only a commanddefinition object and not a query + _rEvent.Element >>= pData->xObjectProperties; // remember the new element + } + else + { + rTreeView.set_id(*xChild, OUString()); + delete pData; + } + } + break; + } + } while (rTreeView.iter_next_sibling(*xChild)); + } + } + + // maybe the object which is part of the document data source has been removed + checkDocumentDataSource(); + } + else if (xNames.get() == m_xDatabaseContext.get()) + { // a datasource has been replaced in the context + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::elementReplaced: no support for replaced data sources!"); + // very suspicious: the database context should not allow to replace data source, only to register + // and revoke them + } + else + SbaXDataBrowserController::elementReplaced(_rEvent); +} + +void SbaTableQueryBrowser::impl_releaseConnection( SharedConnection& _rxConnection ) +{ + // remove as event listener + Reference< XComponent > xComponent( _rxConnection, UNO_QUERY ); + if ( xComponent.is() ) + { + Reference< XEventListener > xListener( static_cast< ::cppu::OWeakObject* >( this ), UNO_QUERY ); + xComponent->removeEventListener( xListener ); + } + + try + { + // temporary (hopefully!) hack for #i55274# + Reference< XFlushable > xFlush( _rxConnection, UNO_QUERY ); + if ( xFlush.is() ) + xFlush->flush(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + // clear + _rxConnection.clear(); + // will implicitly dispose if we have the ownership, since xConnection is a SharedConnection +} + +void SbaTableQueryBrowser::disposeConnection(const weld::TreeIter* pDSEntry) +{ + OSL_ENSURE( pDSEntry, "SbaTableQueryBrowser::disposeConnection: invalid entry (NULL)!" ); + OSL_ENSURE( impl_isDataSourceEntry( pDSEntry ), "SbaTableQueryBrowser::disposeConnection: invalid entry (not top-level)!" ); + + if (pDSEntry) + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pTreeListData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*pDSEntry)); + if (pTreeListData) + impl_releaseConnection(pTreeListData->xConnection); + } +} + +void SbaTableQueryBrowser::closeConnection(const weld::TreeIter& rDSEntry, bool _bDisposeConnection) +{ + OSL_ENSURE(impl_isDataSourceEntry(&rDSEntry), "SbaTableQueryBrowser::closeConnection: invalid entry (not top-level)!"); + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + + // if one of the entries of the given DS is displayed currently, unload the form + if (m_xCurrentlyDisplayed) + { + std::unique_ptr<weld::TreeIter> xRoot = m_pTreeView->GetRootLevelParent(m_xCurrentlyDisplayed.get()); + if (rTreeView.iter_compare(*xRoot, rDSEntry) == 0) + unloadAndCleanup(_bDisposeConnection); + } + + // collapse the query/table container + std::unique_ptr<weld::TreeIter> xContainers(rTreeView.make_iterator(&rDSEntry)); + if (rTreeView.iter_children(*xContainers)) + { + do + { + std::unique_ptr<weld::TreeIter> xElements(rTreeView.make_iterator(xContainers.get())); + if (rTreeView.iter_children(*xElements)) + { + rTreeView.collapse_row(*xContainers); + // and delete their children (they are connection-relative) + bool bElements = true; + while (bElements) + { + std::unique_ptr<weld::TreeIter> xRemove(rTreeView.make_iterator(xElements.get())); + bElements = rTreeView.iter_next_sibling(*xElements); + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xRemove)); + rTreeView.set_id(*xRemove, OUString()); + delete pData; + rTreeView.remove(*xRemove); + } + } + } + while (rTreeView.iter_next_sibling(*xContainers)); + } + + // collapse the entry itself + rTreeView.collapse_row(rDSEntry); + + // dispose/reset the connection + if ( _bDisposeConnection ) + disposeConnection(&rDSEntry); +} + +void SbaTableQueryBrowser::unloadAndCleanup( bool _bDisposeConnection ) +{ + if (!m_xCurrentlyDisplayed) + // nothing to do + return; + + std::unique_ptr<weld::TreeIter> xDSEntry = m_pTreeView->GetRootLevelParent(m_xCurrentlyDisplayed.get()); + + // de-select the path for the currently displayed table/query + selectPath(m_xCurrentlyDisplayed.get(), false); + m_xCurrentlyDisplayed.reset(); + + try + { + // get the active connection. We need to dispose it. + + // unload the form + Reference< XLoadable > xLoadable = getLoadable(); + if (xLoadable->isLoaded()) + xLoadable->unload(); + + // clear the grid control + Reference< XNameContainer > xConta(getControlModel(),UNO_QUERY); + clearGridColumns(xConta); + + // dispose the connection + if(_bDisposeConnection) + disposeConnection(xDSEntry.get()); + } + catch(SQLException& e) + { + showError(SQLExceptionInfo(e)); + } + catch(WrappedTargetException& e) + { + SQLException aSql; + if(e.TargetException >>= aSql) + showError(SQLExceptionInfo(aSql)); + else + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::unloadAndCleanup: something strange happened!"); + } + catch(const Exception&) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::unloadAndCleanup: could not reset the form"); + } +} + +namespace +{ + Reference< XInterface > lcl_getDataSource( const Reference< XDatabaseContext >& _rxDatabaseContext, + const OUString& _rDataSourceName, const Reference< XConnection >& _rxConnection ) + { + Reference< XDataSource > xDataSource; + try + { + if ( !_rDataSourceName.isEmpty() && _rxDatabaseContext->hasByName( _rDataSourceName ) ) + xDataSource.set( _rxDatabaseContext->getByName( _rDataSourceName ), UNO_QUERY_THROW ); + + if ( !xDataSource.is() ) + { + Reference< XChild > xConnAsChild( _rxConnection, UNO_QUERY ); + if ( xConnAsChild.is() ) + xDataSource.set( xConnAsChild->getParent(), UNO_QUERY_THROW ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return xDataSource; + } +} + +void SbaTableQueryBrowser::impl_initialize() +{ + SolarMutexGuard aGuard; + // doin' a lot of VCL stuff here -> lock the SolarMutex + + // first initialize the parent + SbaXDataBrowserController::impl_initialize(); + + Reference<XConnection> xForeignConnection; + Reference< XFrame > xFrame; + + OUString aTableName, aCatalogName, aSchemaName; + + bool bEscapeProcessing = true; + sal_Int32 nInitialDisplayCommandType = CommandType::COMMAND; + OUString sInitialDataSourceName; + OUString sInitialCommand; + + const NamedValueCollection& rArguments( getInitParams() ); + + rArguments.get_ensureType( PROPERTY_DATASOURCENAME, sInitialDataSourceName ); + rArguments.get_ensureType( PROPERTY_COMMAND_TYPE, nInitialDisplayCommandType ); + rArguments.get_ensureType( PROPERTY_COMMAND, sInitialCommand ); + rArguments.get_ensureType( PROPERTY_ACTIVE_CONNECTION, xForeignConnection ); + rArguments.get_ensureType( PROPERTY_UPDATE_CATALOGNAME, aCatalogName ); + rArguments.get_ensureType( PROPERTY_UPDATE_SCHEMANAME, aSchemaName ); + rArguments.get_ensureType( PROPERTY_UPDATE_TABLENAME, aTableName ); + rArguments.get_ensureType( PROPERTY_ESCAPE_PROCESSING, bEscapeProcessing ); + rArguments.get_ensureType( "Frame", xFrame ); + rArguments.get_ensureType( PROPERTY_SHOWMENU, m_bShowMenu ); + + // disable the browser if either of ShowTreeViewButton (compatibility name) or EnableBrowser + // is present and set to FALSE + bool bDisableBrowser = !rArguments.getOrDefault( "ShowTreeViewButton", true ) // compatibility name + || !rArguments.getOrDefault( PROPERTY_ENABLE_BROWSER, true ); + OSL_ENSURE( !rArguments.has( "ShowTreeViewButton" ), + "SbaTableQueryBrowser::impl_initialize: ShowTreeViewButton is superseded by EnableBrowser!" ); + m_bEnableBrowser = !bDisableBrowser; + + // hide the tree view it is disabled in general, or if the settings tell to hide it initially + bool bHideTreeView = ( !m_bEnableBrowser ) + || !rArguments.getOrDefault( "ShowTreeView", true ) // compatibility name + || !rArguments.getOrDefault( PROPERTY_SHOW_BROWSER, true ); + OSL_ENSURE( !rArguments.has( "ShowTreeView" ), + "SbaTableQueryBrowser::impl_initialize: ShowTreeView is superseded by ShowBrowser!" ); + + if ( bHideTreeView ) + hideExplorer(); + else + showExplorer(); + + if ( m_bPreview ) + { + try + { + Sequence< OUString> aProperties + { + "AlwaysShowCursor", PROPERTY_BORDER, "HasNavigationBar", "HasRecordMarker", "Tabstop" + }; + Sequence< Any> aValues + { + Any(false), Any(sal_Int16(0)), Any(false), Any(false), Any(false) + }; + Reference< XMultiPropertySet > xFormMultiSet(getFormComponent(), UNO_QUERY); + if ( xFormMultiSet.is() ) + xFormMultiSet->setPropertyValues(aProperties, aValues); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + // are we loaded into a (sub)frame of an embedded document (i.e. a form belonging to a database + // document)? + bool bSubFrameOfEmbeddedDocument = false; + if ( xFrame.is() ) + { + Reference<XFramesSupplier> xSup = xFrame->getCreator(); + Reference<XController> xCont = xSup.is() ? xSup->getController() : Reference<XController>(); + + bSubFrameOfEmbeddedDocument = xCont.is() && ::dbtools::isEmbeddedInDatabase( xCont->getModel(), xForeignConnection ); + } + + // if we have a connection at this point, it was either passed from outside, our + // determined from an outer DB document. In both cases, do not dispose it later on. + SharedConnection xConnection( xForeignConnection, SharedConnection::NoTakeOwnership ); + + // should we display all registered databases in the left hand side tree? + // or only *one* special? + bool bLimitedTreeEntries = false; + // if we're part of a frame which is a secondary frame of a database document, then only + // display the database for this document, not all registered ones + bLimitedTreeEntries |= bSubFrameOfEmbeddedDocument; + // if the tree view is not to be displayed at all, then only display the data source + // which was given as initial selection + bLimitedTreeEntries |= !m_bEnableBrowser; + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + rTreeView.make_unsorted(); + + if ( bLimitedTreeEntries ) + { + if ( xConnection.is() ) + { + startConnectionListening( xConnection ); + + // if no initial name was given, try to obtain one from the data source + if ( sInitialDataSourceName.isEmpty() ) + { + Reference< XChild > xChild( xConnection, UNO_QUERY ); + Reference< XPropertySet > xDataSourceProperties; + if ( xChild.is() ) + xDataSourceProperties.set(xChild->getParent(), css::uno::UNO_QUERY); + if ( xDataSourceProperties.is() ) + { + try + { + OSL_VERIFY( xDataSourceProperties->getPropertyValue( PROPERTY_NAME ) >>= sInitialDataSourceName ); + } + catch( const Exception& ) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::impl_initialize: a connection parent which does not have a 'Name'!??" ); + } + } + } + } + + implAddDatasource( sInitialDataSourceName, xConnection ); + + std::unique_ptr<weld::TreeIter> xFirst(rTreeView.make_iterator()); + if (rTreeView.get_iter_first(*xFirst)) + rTreeView.expand_row(*xFirst); + } + else + initializeTreeModel(); + + rTreeView.make_sorted(); + + if ( m_bEnableBrowser ) + { + m_aDocScriptSupport = ::std::optional< bool >( false ); + } + else + { + // we are not used as "browser", but as mere view for a single table/query/command. In particular, + // there is a specific database document which we belong to. + Reference< XOfficeDatabaseDocument > xDocument( getDataSourceOrModel( + lcl_getDataSource( m_xDatabaseContext, sInitialDataSourceName, xConnection ) ), UNO_QUERY ); + m_aDocScriptSupport = ::std::optional< bool >( Reference< XEmbeddedScripts >( xDocument, UNO_QUERY ).is() ); + } + + if ( implSelect( sInitialDataSourceName, sInitialCommand, nInitialDisplayCommandType, bEscapeProcessing, xConnection, true ) ) + { + try + { + Reference< XPropertySet > xRowSetProps(getRowSet(), UNO_QUERY); + xRowSetProps->setPropertyValue(PROPERTY_UPDATE_CATALOGNAME,Any(aCatalogName)); + xRowSetProps->setPropertyValue(PROPERTY_UPDATE_SCHEMANAME,Any(aSchemaName)); + xRowSetProps->setPropertyValue(PROPERTY_UPDATE_TABLENAME,Any(aTableName)); + + } + catch(const Exception&) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::impl_initialize: could not set the update related names!"); + } + } + + InvalidateAll(); +} + +bool SbaTableQueryBrowser::haveExplorer() const +{ + return m_pTreeView && m_pTreeView->IsVisible(); +} + +void SbaTableQueryBrowser::hideExplorer() +{ + if (!haveExplorer()) + return; + if (!getBrowserView()) + return; + + m_pTreeView->Hide(); + m_pSplitter->Hide(); + getBrowserView()->Resize(); + + InvalidateFeature(ID_BROWSER_EXPLORER); +} + +void SbaTableQueryBrowser::showExplorer() +{ + if (haveExplorer()) + return; + + if (!getBrowserView()) + return; + + m_pTreeView->Show(); + m_pSplitter->Show(); + getBrowserView()->Resize(); + + InvalidateFeature(ID_BROWSER_EXPLORER); +} + +bool SbaTableQueryBrowser::ensureConnection(const weld::TreeIter* pAnyEntry, SharedConnection& rConnection) +{ + std::unique_ptr<weld::TreeIter> xDSEntry = m_pTreeView->GetRootLevelParent(pAnyEntry); + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pDSData = + xDSEntry + ? weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDSEntry)) + : nullptr; + + return ensureConnection(xDSEntry.get(), pDSData, rConnection); +} + +std::unique_ptr< ImageProvider > SbaTableQueryBrowser::getImageProviderFor(const weld::TreeIter* pAnyEntry) +{ + std::unique_ptr<ImageProvider> xImageProvider(new ImageProvider); + SharedConnection xConnection; + if (getExistentConnectionFor(pAnyEntry, xConnection)) + xImageProvider.reset(new ImageProvider(xConnection)); + return xImageProvider; +} + +bool SbaTableQueryBrowser::getExistentConnectionFor(const weld::TreeIter* pAnyEntry, SharedConnection& rConnection) +{ + std::unique_ptr<weld::TreeIter> xDSEntry = m_pTreeView->GetRootLevelParent(pAnyEntry); + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pDSData = + xDSEntry + ? weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDSEntry)) + : nullptr; + if (pDSData) + rConnection = pDSData->xConnection; + return rConnection.is(); +} + +bool SbaTableQueryBrowser::impl_isDataSourceEntry(const weld::TreeIter* pEntry) const +{ + if (!pEntry) + return false; + std::unique_ptr<weld::TreeIter> xRoot(m_pTreeView->GetRootLevelParent(pEntry)); + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + return rTreeView.iter_compare(*xRoot, *pEntry) == 0; +} + +bool SbaTableQueryBrowser::ensureConnection(const weld::TreeIter* pDSEntry, void* pDSData, SharedConnection& rConnection) +{ + OSL_ENSURE( impl_isDataSourceEntry( pDSEntry ), "SbaTableQueryBrowser::ensureConnection: this entry does not denote a data source!" ); + if (pDSEntry) + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + OUString aDSName = rTreeView.get_text(*pDSEntry); + + DBTreeListUserData* pTreeListData = static_cast<DBTreeListUserData*>(pDSData); + if ( pTreeListData ) + rConnection = pTreeListData->xConnection; + + if ( !rConnection.is() && pTreeListData ) + { + // show the "connecting to ..." status + OUString sConnecting(DBA_RES(STR_CONNECTING_DATASOURCE)); + sConnecting = sConnecting.replaceFirst("$name$", aDSName); + BrowserViewStatusDisplay aShowStatus(static_cast<UnoDataBrowserView*>(getView()), sConnecting); + + // build a string showing context information in case of error + OUString sConnectingContext(DBA_RES(STR_COULDNOTCONNECT_DATASOURCE)); + sConnectingContext = sConnectingContext.replaceFirst("$name$", aDSName); + + // connect + rConnection.reset( + connect(getDataSourceAccessor(*pDSEntry), sConnectingContext, nullptr), + SharedConnection::TakeOwnership); + + // remember the connection + pTreeListData->xConnection = rConnection; + } + } + return rConnection.is(); +} + +int SbaTableQueryBrowser::OnTreeEntryCompare(const weld::TreeIter& rLHS, const weld::TreeIter& rRHS) +{ + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + + // we want the table entry and the end so we have to do a check + if (isContainer(rRHS)) + { + // don't use getEntryType (directly or indirectly) for the LHS: + // LHS is currently being inserted, so it is not "completely valid" at the moment + + const EntryType eRight = getEntryType(rRHS); + if (etTableContainer == eRight) + // every other container should be placed _before_ the bookmark container + return -1; + + const OUString sLeft = rTreeView.get_text(rLHS); + + EntryType eLeft = etTableContainer; + if (DBA_RES(RID_STR_TABLES_CONTAINER) == sLeft) + eLeft = etTableContainer; + else if (DBA_RES(RID_STR_QUERIES_CONTAINER) == sLeft) + eLeft = etQueryContainer; + + if ( eLeft == eRight ) + return 0; + + if ( ( eLeft == etTableContainer ) && ( eRight == etQueryContainer ) ) + return 1; + + if ( ( eLeft == etQueryContainer ) && ( eRight == etTableContainer ) ) + return -1; + + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::OnTreeEntryCompare: unexpected case!" ); + return 0; + } + + OUString sLeftText = rTreeView.get_text(rLHS); + OUString sRightText = rTreeView.get_text(rRHS); + + sal_Int32 nCompareResult = 0; // equal by default + + if (m_xCollator.is()) + { + try + { + nCompareResult = m_xCollator->compareString(sLeftText, sRightText); + } + catch(const Exception&) + { + } + } + else + // default behaviour if we do not have a collator -> do the simple string compare + nCompareResult = sLeftText.compareTo(sRightText); + + return nCompareResult; +} + +void SbaTableQueryBrowser::implAdministrate(const weld::TreeIter& rApplyTo) +{ + try + { + // get the desktop object + Reference< XDesktop2 > xFrameLoader = Desktop::create( getORB() ); + + // the initial selection + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xTopLevelSelected(rTreeView.make_iterator(&rApplyTo)); + + while (rTreeView.get_iter_depth(*xTopLevelSelected)) + rTreeView.iter_parent(*xTopLevelSelected); + + OUString sInitialSelection = getDataSourceAccessor(*xTopLevelSelected); + + Reference< XDataSource > xDataSource( getDataSourceByName( sInitialSelection, getFrameWeld(), getORB(), nullptr ) ); + Reference< XModel > xDocumentModel( getDataSourceOrModel( xDataSource ), UNO_QUERY ); + + if ( xDocumentModel.is() ) + { + Reference< XInteractionHandler2 > xInteractionHandler( + InteractionHandler::createWithParent(getORB(), nullptr) ); + + ::comphelper::NamedValueCollection aLoadArgs; + aLoadArgs.put( "Model", xDocumentModel ); + aLoadArgs.put( "InteractionHandler", xInteractionHandler ); + aLoadArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG ); + + Sequence< PropertyValue > aLoadArgPV; + aLoadArgs >>= aLoadArgPV; + + xFrameLoader->loadComponentFromURL( + xDocumentModel->getURL(), + "_default", + FrameSearchFlag::ALL | FrameSearchFlag::GLOBAL, + aLoadArgPV + ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +bool SbaTableQueryBrowser::requestQuickHelp(const void* pUserData, OUString& rText) const +{ + const DBTreeListUserData* pData = static_cast<const DBTreeListUserData*>(pUserData); + if (pData->eType == etDatasource && !pData->sAccessor.isEmpty()) + { + rText = ::svt::OFileNotation(pData->sAccessor).get( ::svt::OFileNotation::N_SYSTEM); + return true; + } + return false; +} + +OUString SbaTableQueryBrowser::getContextMenuResourceName() const +{ + return "explorer"; +} + +IController& SbaTableQueryBrowser::getCommandController() +{ + return *this; +} + +::comphelper::OInterfaceContainerHelper2* SbaTableQueryBrowser::getContextMenuInterceptors() +{ + return &m_aContextMenuInterceptors; +} + +Any SbaTableQueryBrowser::getCurrentSelection(weld::TreeView& rControl) const +{ + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + + OSL_PRECOND( &rTreeView == &rControl, + "SbaTableQueryBrowser::getCurrentSelection: where does this come from?" ); + + if (&rTreeView != &rControl) + return Any(); + + std::unique_ptr<weld::TreeIter> xSelected(rTreeView.make_iterator()); + if (!rTreeView.get_selected(xSelected.get())) + return Any(); + + NamedDatabaseObject aSelectedObject; + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xSelected)); + aSelectedObject.Type = static_cast< sal_Int32 >( pData->eType ); + + switch ( aSelectedObject.Type ) + { + case DatabaseObject::QUERY: + case DatabaseObject::TABLE: + aSelectedObject.Name = rTreeView.get_text(*xSelected); + break; + + case DatabaseObjectContainer::DATA_SOURCE: + case DatabaseObjectContainer::QUERIES: + case DatabaseObjectContainer::TABLES: + aSelectedObject.Name = getDataSourceAccessor(*xSelected); + break; + + default: + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::getCurrentSelection: invalid (unexpected) object type!" ); + break; + } + + return Any( aSelectedObject ); +} + +vcl::Window* SbaTableQueryBrowser::getMenuParent() const +{ + return m_pTreeView; +} + +void SbaTableQueryBrowser::adjustMenuPosition(const weld::TreeView&, ::Point&) const +{ +} + +bool SbaTableQueryBrowser::implGetQuerySignature( OUString& _rCommand, bool& _bEscapeProcessing ) +{ + _rCommand.clear(); + _bEscapeProcessing = false; + + try + { + // contain the dss (data source signature) of the form + OUString sDataSourceName; + OUString sCommand; + sal_Int32 nCommandType = CommandType::COMMAND; + Reference< XPropertySet > xRowsetProps( getRowSet(), UNO_QUERY ); + ODataAccessDescriptor aDesc( xRowsetProps ); + sDataSourceName = aDesc.getDataSource(); + aDesc[ DataAccessDescriptorProperty::Command ] >>= sCommand; + aDesc[ DataAccessDescriptorProperty::CommandType ] >>= nCommandType; + + // do we need to do anything? + if ( CommandType::QUERY != nCommandType ) + return false; + + // get the query object + Reference< XQueryDefinitionsSupplier > xSuppQueries; + Reference< XNameAccess > xQueries; + Reference< XPropertySet > xQuery; + m_xDatabaseContext->getByName( sDataSourceName ) >>= xSuppQueries; + if ( xSuppQueries.is() ) + xQueries = xSuppQueries->getQueryDefinitions(); + if ( xQueries.is() ) + xQueries->getByName( sCommand ) >>= xQuery; + OSL_ENSURE( xQuery.is(), "SbaTableQueryBrowser::implGetQuerySignature: could not retrieve the query object!" ); + + // get the two properties we need + if ( xQuery.is() ) + { + xQuery->getPropertyValue( PROPERTY_COMMAND ) >>= _rCommand; + _bEscapeProcessing = ::cppu::any2bool( xQuery->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) ); + return true; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return false; +} + +void SbaTableQueryBrowser::frameAction(const css::frame::FrameActionEvent& aEvent) +{ + if (aEvent.Frame == m_xCurrentFrameParent) + { + if(aEvent.Action == FrameAction_COMPONENT_DETACHING) + implRemoveStatusListeners(); + else if (aEvent.Action == FrameAction_COMPONENT_REATTACHED) + connectExternalDispatches(); + } + else + SbaXDataBrowserController::frameAction(aEvent); + +} + +void SbaTableQueryBrowser::clearGridColumns(const Reference< XNameContainer >& _xColContainer) +{ + // first we have to clear the grid + Reference< XInterface > xColumn; + const Sequence<OUString> aColNames = _xColContainer->getElementNames(); + for (const OUString& rName : aColNames) + { + _xColContainer->getByName(rName) >>= xColumn; + _xColContainer->removeByName(rName); + ::comphelper::disposeComponent(xColumn); + } +} + +void SbaTableQueryBrowser::loadMenu(const Reference< XFrame >& _xFrame) +{ + if ( m_bShowMenu ) + { + OGenericUnoController::loadMenu(_xFrame); + } + else if ( !m_bPreview ) + { + Reference< css::frame::XLayoutManager > xLayoutManager = getLayoutManager(_xFrame); + + if ( xLayoutManager.is() ) + { + xLayoutManager->lock(); + xLayoutManager->createElement( "private:resource/toolbar/toolbar" ); + xLayoutManager->unlock(); + xLayoutManager->doLayout(); + } + onLoadedMenu( xLayoutManager ); + } +} + +OUString SbaTableQueryBrowser::getPrivateTitle() const +{ + OUString sTitle; + if (m_xCurrentlyDisplayed) + { + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xContainer = rTreeView.make_iterator(m_xCurrentlyDisplayed.get()); + if (!rTreeView.iter_parent(*xContainer)) + return OUString(); + // get the entry for the datasource + std::unique_ptr<weld::TreeIter> xConnection = implGetConnectionEntry(*xContainer); + OUString sName = rTreeView.get_text(*m_xCurrentlyDisplayed); + sTitle = GetEntryText(*xConnection); + INetURLObject aURL(sTitle); + if ( aURL.GetProtocol() != INetProtocol::NotValid ) + sTitle = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset); + if ( !sName.isEmpty() ) + { + sName += " - " + sTitle; + sTitle = sName; + } + } + + return sTitle; +} + +bool SbaTableQueryBrowser::preReloadForm() +{ + bool bIni = false; + if (!m_xCurrentlyDisplayed) + { + // switch the grid to design mode while loading + getBrowserView()->getGridControl()->setDesignMode(true); + // we had an invalid statement so we need to connect the column models + Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY); + svx::ODataAccessDescriptor aDesc(xRowSetProps); + // extract the props + OUString sDataSource; + OUString sCommand; + sal_Int32 nCommandType = CommandType::COMMAND; + bool bEscapeProcessing = true; + extractDescriptorProps(aDesc, sDataSource, sCommand, nCommandType, bEscapeProcessing); + if ( !sDataSource.isEmpty() && !sCommand.isEmpty() && (-1 != nCommandType) ) + { + m_xCurrentlyDisplayed = getObjectEntry(sDataSource, sCommand, nCommandType, nullptr, nullptr); + bIni = true; + } + } + return bIni; +} + +void SbaTableQueryBrowser::postReloadForm() +{ + InitializeGridModel(getFormComponent()); + LoadFinished(true); +} + +Reference< XEmbeddedScripts > SAL_CALL SbaTableQueryBrowser::getScriptContainer() +{ + // update our database document + Reference< XModel > xDocument; + try + { + Reference< XPropertySet > xCursorProps( getRowSet(), UNO_QUERY_THROW ); + Reference< XConnection > xConnection( xCursorProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ), UNO_QUERY ); + if ( xConnection.is() ) + { + Reference< XChild > xChild( xConnection, UNO_QUERY_THROW ); + Reference< XDocumentDataSource > xDataSource( xChild->getParent(), UNO_QUERY_THROW ); + xDocument.set( xDataSource->getDatabaseDocument(), UNO_QUERY_THROW ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + Reference< XEmbeddedScripts > xScripts( xDocument, UNO_QUERY ); + OSL_ENSURE( xScripts.is() || !xDocument.is(), + "SbaTableQueryBrowser::getScriptContainer: invalid database document!" ); + return xScripts; +} + +void SAL_CALL SbaTableQueryBrowser::registerContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor ) +{ + if ( Interceptor.is() ) + m_aContextMenuInterceptors.addInterface( Interceptor ); +} + +void SAL_CALL SbaTableQueryBrowser::releaseContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor ) +{ + if ( Interceptor.is() ) + m_aContextMenuInterceptors.removeInterface( Interceptor ); +} + +void SAL_CALL SbaTableQueryBrowser::registeredDatabaseLocation( const DatabaseRegistrationEvent& Event ) +{ + SolarMutexGuard aGuard; + implAddDatasource( Event.Name, SharedConnection() ); +} + +void SbaTableQueryBrowser::impl_cleanupDataSourceEntry(std::u16string_view rDataSourceName) +{ + // get the top-level representing the removed data source + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr<weld::TreeIter> xDataSourceEntry(rTreeView.make_iterator()); + bool bDataSourceEntry = rTreeView.get_iter_first(*xDataSourceEntry); + while (bDataSourceEntry) + { + if (rTreeView.get_text(*xDataSourceEntry) == rDataSourceName) + break; + bDataSourceEntry = rTreeView.iter_next_sibling(*xDataSourceEntry); + } + + OSL_ENSURE( bDataSourceEntry, "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: do not know this data source!" ); + if (!bDataSourceEntry) + return; + + if (isSelected(*xDataSourceEntry)) + { + // a table or query belonging to the deleted data source is currently being displayed. + unloadAndCleanup(); + } + + std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xDataSourceEntry.get())); + if (rTreeView.iter_children(*xChild)) + { + do + { + // delete any user data of the child entries of the to-be-removed entry + const DBTreeListUserData* pData = weld::fromId<const DBTreeListUserData*>(rTreeView.get_id(*xChild)); + rTreeView.set_id(*xChild, OUString()); + delete pData; + } while (rTreeView.iter_next_sibling(*xChild)); + } + + // remove the entry + DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDataSourceEntry)); + rTreeView.set_id(*xDataSourceEntry, OUString()); + delete pData; + rTreeView.remove(*xDataSourceEntry); +} + +void SAL_CALL SbaTableQueryBrowser::revokedDatabaseLocation( const DatabaseRegistrationEvent& Event ) +{ + SolarMutexGuard aGuard; + + impl_cleanupDataSourceEntry( Event.Name ); + + // maybe the object which is part of the document data source has been removed + checkDocumentDataSource(); +} + +void SAL_CALL SbaTableQueryBrowser::changedDatabaseLocation( const DatabaseRegistrationEvent& Event ) +{ + SolarMutexGuard aGuard; + + // in case the data source was expanded, and connected, we need to clean it up + // for simplicity, just do as if the data source were completely removed and re-added + impl_cleanupDataSourceEntry( Event.Name ); + implAddDatasource( Event.Name, SharedConnection() ); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/ColumnControlWindow.cxx b/dbaccess/source/ui/control/ColumnControlWindow.cxx new file mode 100644 index 000000000..f9f786f22 --- /dev/null +++ b/dbaccess/source/ui/control/ColumnControlWindow.cxx @@ -0,0 +1,182 @@ +/* -*- 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 <ColumnControlWindow.hxx> +#include <unotools/syslocale.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <connectivity/dbtools.hxx> +#include <o3tl/safeint.hxx> +#include <UITools.hxx> +#include <core_resource.hxx> +#include <strings.hrc> +#include <com/sun/star/util/NumberFormatter.hpp> + +using namespace ::dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::lang; + +OColumnControlTopLevel::OColumnControlTopLevel(vcl::Window* pParent, + const Reference<XComponentContext>& _rxContext) + : InterimItemWindow(pParent, "dbaccess/ui/colcontrolbox.ui", "ColControlBox") + , m_xControl(new OColumnControlWindow(m_xContainer.get(), _rxContext)) +{ +} + +void OColumnControlTopLevel::dispose() +{ + m_xControl.reset(); + InterimItemWindow::dispose(); +} + +void OColumnControlTopLevel::GetFocus() +{ + m_xControl->GrabFocus(); +} + +// OColumnControlWindow +OColumnControlWindow::OColumnControlWindow(weld::Container* pParent, + const Reference<XComponentContext>& _rxContext) + : OFieldDescControl(pParent, nullptr) + , m_xContext(_rxContext) + , m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES)) + , m_bAutoIncrementEnabled(true) +{ + m_aLocale = SvtSysLocale().GetLanguageTag().getLocale(); +} + +void OColumnControlWindow::ActivateAggregate( EControlType eType ) +{ + switch(eType ) + { + case tpFormat: + case tpDefault: + case tpColumnName: + break; + default: + OFieldDescControl::ActivateAggregate( eType ); + } +} + +void OColumnControlWindow::DeactivateAggregate( EControlType eType ) +{ + switch(eType ) + { + case tpFormat: + case tpDefault: + case tpColumnName: + break; + default: + OFieldDescControl::DeactivateAggregate( eType ); + } +} + +void OColumnControlWindow::CellModified(sal_Int32 /*nRow*/, sal_uInt16 /*nColId*/ ) +{ + saveCurrentFieldDescData(); +} + +css::lang::Locale OColumnControlWindow::GetLocale() const +{ + return m_aLocale; +} + +Reference< XNumberFormatter > OColumnControlWindow::GetFormatter() const +{ + if ( !m_xFormatter.is() ) + try + { + Reference< XNumberFormatsSupplier > xSupplier(::dbtools::getNumberFormats(m_xConnection, true, m_xContext)); + + if ( xSupplier.is() ) + { + // create a new formatter + m_xFormatter.set( NumberFormatter::create(m_xContext), UNO_QUERY_THROW); + m_xFormatter->attachNumberFormatsSupplier(xSupplier); + } + } + catch(Exception&) + { + } + return m_xFormatter; +} + +TOTypeInfoSP OColumnControlWindow::getTypeInfo(sal_Int32 _nPos) +{ + return ( _nPos >= 0 && o3tl::make_unsigned(_nPos) < m_aDestTypeInfoIndex.size()) ? m_aDestTypeInfoIndex[_nPos]->second : TOTypeInfoSP(); +} + +const OTypeInfoMap* OColumnControlWindow::getTypeInfo() const +{ + return &m_aDestTypeInfo; +} + +Reference< XDatabaseMetaData> OColumnControlWindow::getMetaData() +{ + if ( m_xConnection.is() ) + return m_xConnection->getMetaData(); + return Reference< XDatabaseMetaData>(); +} + +Reference< XConnection> OColumnControlWindow::getConnection() +{ + return m_xConnection; +} + +void OColumnControlWindow::setConnection(const Reference< XConnection>& _xCon) +{ + m_xConnection = _xCon; + m_xFormatter = nullptr; + m_aDestTypeInfoIndex.clear(); + m_aDestTypeInfo.clear(); + + if ( m_xConnection.is() ) + { + Init(); + + ::dbaui::fillTypeInfo(m_xConnection,m_sTypeNames,m_aDestTypeInfo,m_aDestTypeInfoIndex); + // read autoincrement value set in the datasource + ::dbaui::fillAutoIncrementValue(m_xConnection,m_bAutoIncrementEnabled,m_sAutoIncrementValue); + } +} + +bool OColumnControlWindow::isAutoIncrementValueEnabled() const +{ + return m_bAutoIncrementEnabled; +} + +OUString OColumnControlWindow::getAutoIncrementValue() const +{ + return m_sAutoIncrementValue; +} + +TOTypeInfoSP const & OColumnControlWindow::getDefaultTyp() const +{ + if ( !m_pTypeInfo ) + { + m_pTypeInfo = std::make_shared<OTypeInfo>(); + m_pTypeInfo->aUIName = m_sTypeNames.getToken(TYPE_OTHER, ';'); + } + return m_pTypeInfo; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/FieldControls.cxx b/dbaccess/source/ui/control/FieldControls.cxx new file mode 100644 index 000000000..3f3553d56 --- /dev/null +++ b/dbaccess/source/ui/control/FieldControls.cxx @@ -0,0 +1,60 @@ +/* -*- 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 <FieldControls.hxx> +#include <SqlNameEdit.hxx> +#include <core_resource.hxx> + +namespace dbaui { + +OPropColumnEditCtrl::OPropColumnEditCtrl(std::unique_ptr<weld::Entry> xEntry, + OUString const & _rAllowedChars, + TranslateId pHelpId, + short nPosition) + : OSQLNameEntry(std::move(xEntry), _rAllowedChars) + , m_nPos(nPosition) +{ + m_strHelpText = DBA_RES(pHelpId); +} + +OPropEditCtrl::OPropEditCtrl(std::unique_ptr<weld::Entry> xEntry, TranslateId pHelpId, short nPosition) + : OWidgetBase(xEntry.get()) + , m_xEntry(std::move(xEntry)) + , m_nPos(nPosition) +{ + m_strHelpText = DBA_RES(pHelpId); +} + +OPropNumericEditCtrl::OPropNumericEditCtrl(std::unique_ptr<weld::SpinButton> xSpinButton, TranslateId pHelpId, short nPosition) + : OWidgetBase(xSpinButton.get()) + , m_xSpinButton(std::move(xSpinButton)) + , m_nPos(nPosition) +{ + m_strHelpText = DBA_RES(pHelpId); +} + +OPropListBoxCtrl::OPropListBoxCtrl(std::unique_ptr<weld::ComboBox> xComboBox, TranslateId pHelpId, short nPosition) + : OWidgetBase(xComboBox.get()) + , m_xComboBox(std::move(xComboBox)) + , m_nPos(nPosition) +{ + m_strHelpText = DBA_RES(pHelpId); +} + +} // end namespace dbaui diff --git a/dbaccess/source/ui/control/FieldDescControl.cxx b/dbaccess/source/ui/control/FieldDescControl.cxx new file mode 100644 index 000000000..331fbc5cb --- /dev/null +++ b/dbaccess/source/ui/control/FieldDescControl.cxx @@ -0,0 +1,1384 @@ +/* -*- 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 <core_resource.hxx> +#include <FieldDescControl.hxx> +#include <FieldControls.hxx> +#include <tools/diagnose_ex.h> +#include <TableDesignHelpBar.hxx> +#include <vcl/svapp.hxx> +#include <FieldDescriptions.hxx> +#include <svl/numuno.hxx> +#include <vcl/transfer.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/XNumberFormatPreviewer.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <QEnumTypes.hxx> +#include <helpids.h> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbconversion.hxx> +#include <comphelper/numbers.hxx> +#include <comphelper/types.hxx> +#include <UITools.hxx> +#include <strings.hrc> +#include <osl/diagnose.h> + +using namespace dbaui; +using namespace dbtools; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::util; + +namespace +{ + template< typename T1, typename T2> void lcl_HideAndDeleteControl(short& _nPos,std::unique_ptr<T1>& _pControl, std::unique_ptr<T2>& _pControlText) + { + if ( _pControl ) + { + --_nPos; + _pControl->hide(); + _pControlText->hide(); + _pControl.reset(); + _pControlText.reset(); + } + } +} + +OFieldDescControl::OFieldDescControl(weld::Container* pPage, OTableDesignHelpBar* pHelpBar) + : m_xBuilder(Application::CreateBuilder(pPage, "dbaccess/ui/fielddescpage.ui")) + , m_xContainer(m_xBuilder->weld_container("FieldDescPage")) + , m_pHelp( pHelpBar ) + , m_pLastFocusWindow(nullptr) + , m_pActFocusWindow(nullptr) + , m_nPos(-1) + , aYes(DBA_RES(STR_VALUE_YES)) + , aNo(DBA_RES(STR_VALUE_NO)) + , m_nEditWidth(50) + , pActFieldDescr(nullptr) +{ + if (m_pHelp) + m_pHelp->connect_focus_out(LINK(this, OFieldDescControl, HelpFocusOut)); +} + +OFieldDescControl::~OFieldDescControl() +{ + dispose(); +} + +void OFieldDescControl::dispose() +{ + // Destroy children + DeactivateAggregate( tpDefault ); + DeactivateAggregate( tpRequired ); + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpNumType ); + DeactivateAggregate( tpScale ); + DeactivateAggregate( tpLength ); + DeactivateAggregate( tpFormat ); + DeactivateAggregate( tpAutoIncrement ); + DeactivateAggregate( tpBoolDefault ); + DeactivateAggregate( tpColumnName ); + DeactivateAggregate( tpType ); + DeactivateAggregate( tpAutoIncrementValue ); + m_pHelp = nullptr; + m_pLastFocusWindow = nullptr; + m_pActFocusWindow = nullptr; + m_xDefaultText.reset(); + m_xRequiredText.reset(); + m_xAutoIncrementText.reset(); + m_xTextLenText.reset(); + m_xNumTypeText.reset(); + m_xLengthText.reset(); + m_xScaleText.reset(); + m_xFormatText.reset(); + m_xBoolDefaultText.reset(); + m_xColumnNameText.reset(); + m_xTypeText.reset(); + m_xAutoIncrementValueText.reset(); + m_xRequired.reset(); + m_xNumType.reset(); + m_xAutoIncrement.reset(); + m_xDefault.reset(); + m_xTextLen.reset(); + m_xLength.reset(); + m_xScale.reset(); + m_xFormatSample.reset(); + m_xBoolDefault.reset(); + m_xColumnName.reset(); + m_xType.reset(); + m_xAutoIncrementValue.reset(); + m_xFormat.reset(); + m_xContainer.reset(); + m_xBuilder.reset(); +} + +OUString OFieldDescControl::BoolStringPersistent(std::u16string_view rUIString) const +{ + if (rUIString == aNo) + return OUString('0'); + if (rUIString == aYes) + return OUString('1'); + return OUString(); +} + +OUString OFieldDescControl::BoolStringUI(const OUString& rPersistentString) const +{ + // Older versions may store a language dependent string as a default + if (rPersistentString == aYes || rPersistentString == aNo) + return rPersistentString; + + if (rPersistentString == "0") + return aNo; + if (rPersistentString == "1") + return aYes; + + return DBA_RES(STR_VALUE_NONE); +} + +void OFieldDescControl::Init() +{ + Reference< css::util::XNumberFormatter > xFormatter = GetFormatter(); + ::dbaui::setEvalDateFormatForFormatter(xFormatter); +} + +void OFieldDescControl::SetReadOnly( bool bReadOnly ) +{ + // Enable/disable Controls + OWidgetBase* ppAggregates[] = { m_xRequired.get(), m_xNumType.get() + , m_xAutoIncrement.get(), m_xDefault.get() + , m_xTextLen.get(), m_xLength.get() + , m_xScale.get(), m_xColumnName.get() + , m_xType.get(), m_xAutoIncrementValue.get() + }; + weld::Widget* ppAggregatesText[] = { m_xRequiredText.get(), m_xNumTypeText.get() + , m_xAutoIncrementText.get(), m_xDefaultText.get() + , m_xTextLenText.get(), m_xLengthText.get() + , m_xScaleText.get(), m_xColumnNameText.get() + , m_xTypeText.get(), m_xAutoIncrementValueText.get() + }; + + OSL_ENSURE(SAL_N_ELEMENTS(ppAggregates) == SAL_N_ELEMENTS(ppAggregatesText),"Lists are not identical!"); + + for (size_t i=0; i<SAL_N_ELEMENTS(ppAggregates); ++i) + { + if ( ppAggregatesText[i] ) + ppAggregatesText[i]->set_sensitive( !bReadOnly ); + if ( ppAggregates[i] ) + ppAggregates[i]->set_sensitive( !bReadOnly ); + } + + if (m_xFormat) + { + assert(m_xFormatText); + m_xFormat->set_sensitive(!bReadOnly); + m_xFormatText->set_sensitive(!bReadOnly); + } +} + +void OFieldDescControl::SetControlText( sal_uInt16 nControlId, const OUString& rText ) +{ + // Set the Controls' texts + switch( nControlId ) + { + case FIELD_PROPERTY_BOOL_DEFAULT: + if (m_xBoolDefault) + { + OUString sOld = m_xBoolDefault->get_active_text(); + m_xBoolDefault->set_active_text(rText); + if (sOld != rText) + ChangeHdl(m_xBoolDefault->GetComboBox()); + } + break; + case FIELD_PROPERTY_DEFAULT: + if (m_xDefault) + { + m_xDefault->set_text(rText); + UpdateFormatSample(pActFieldDescr); + } + break; + + case FIELD_PROPERTY_REQUIRED: + if (m_xRequired) + m_xRequired->set_active_text(rText); + break; + + case FIELD_PROPERTY_TEXTLEN: + if (m_xTextLen) + m_xTextLen->set_text(rText); + break; + + case FIELD_PROPERTY_NUMTYPE: + if (m_xNumType) + m_xNumType->set_active_text(rText); + break; + + case FIELD_PROPERTY_AUTOINC: + if (m_xAutoIncrement) + { + OUString sOld = m_xAutoIncrement->get_active_text(); + m_xAutoIncrement->set_active_text(rText); + if (sOld != rText) + ChangeHdl(m_xAutoIncrement->GetComboBox()); + } + break; + + case FIELD_PROPERTY_LENGTH: + if (m_xLength) + m_xLength->set_text(rText); + break; + + case FIELD_PROPERTY_SCALE: + if (m_xScale) + m_xScale->set_text(rText); + break; + + case FIELD_PROPERTY_FORMAT: + if (pActFieldDescr) + UpdateFormatSample(pActFieldDescr); + break; + case FIELD_PROPERTY_COLUMNNAME: + if (m_xColumnName) + m_xColumnName->set_text(rText); + break; + case FIELD_PROPERTY_TYPE: + if (m_xType) + m_xType->set_active_text(rText); + break; + case FIELD_PROPERTY_AUTOINCREMENT: + if (m_xAutoIncrementValue) + m_xAutoIncrementValue->set_text(rText); + break; + } +} + +IMPL_LINK_NOARG(OFieldDescControl, FormatClickHdl, weld::Button&, void) +{ + // Create temporary Column, which is used for data exchange with Dialog + if( !pActFieldDescr ) + return; + + sal_Int32 nOldFormatKey(pActFieldDescr->GetFormatKey()); + SvxCellHorJustify rOldJustify = pActFieldDescr->GetHorJustify(); + Reference< XNumberFormatsSupplier > xSupplier = GetFormatter()->getNumberFormatsSupplier(); + SvNumberFormatsSupplierObj* pSupplierImpl = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( xSupplier ); + if (!pSupplierImpl) + return; + + SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter(); + if(!::dbaui::callColumnFormatDialog(m_xContainer.get(),pFormatter,pActFieldDescr->GetType(),nOldFormatKey,rOldJustify,true)) + return; + + bool bModified = false; + if(nOldFormatKey != pActFieldDescr->GetFormatKey()) + { + pActFieldDescr->SetFormatKey( nOldFormatKey ); + bModified = true; + } + if(rOldJustify != pActFieldDescr->GetHorJustify()) + { + pActFieldDescr->SetHorJustify( rOldJustify ); + bModified = true; + } + + if(bModified) + { + SetModified(true); + UpdateFormatSample(pActFieldDescr); + } +} + +void OFieldDescControl::SetModified(bool /*bModified*/) +{ +} + +IMPL_LINK(OFieldDescControl, ChangeHdl, weld::ComboBox&, rListBox, void) +{ + if (!pActFieldDescr) + return; + + if (rListBox.get_value_changed_from_saved()) + SetModified(true); + + // Special treatment for Bool fields + if (m_xRequired && &rListBox == m_xRequired->GetWidget() && m_xBoolDefault) + { + // If m_xRequired = sal_True then the sal_Bool field must NOT contain <<none>> + OUString sDef = BoolStringUI(::comphelper::getString(pActFieldDescr->GetControlDefault())); + + if (m_xRequired->get_active() == 0) // Yes + { + m_xBoolDefault->remove_text(DBA_RES(STR_VALUE_NONE)); + if (sDef != aYes && sDef != aNo) + m_xBoolDefault->set_active(1); // No as a default + else + m_xBoolDefault->set_active_text(sDef); + } + else if (m_xBoolDefault->get_count() < 3) + { + m_xBoolDefault->append_text(DBA_RES(STR_VALUE_NONE)); + m_xBoolDefault->set_active_text(sDef); + } + } + + // A special treatment only for AutoIncrement + if (m_xAutoIncrement && &rListBox == m_xAutoIncrement->GetWidget()) + { + if (rListBox.get_active() == 1) + { // no + DeactivateAggregate( tpAutoIncrementValue ); + if(pActFieldDescr->IsPrimaryKey()) + DeactivateAggregate( tpRequired ); + else if( pActFieldDescr->getTypeInfo()->bNullable ) + { + ActivateAggregate( tpRequired ); + if (m_xRequired) + { + if( pActFieldDescr->IsNullable() ) + m_xRequired->set_active(1); // no + else + m_xRequired->set_active(0); // yes + } + } + ActivateAggregate( tpDefault ); + } + else + { + DeactivateAggregate( tpRequired ); + DeactivateAggregate( tpDefault ); + ActivateAggregate( tpAutoIncrementValue ); + } + } + + if (m_xType && &rListBox == m_xType->GetWidget()) + { + TOTypeInfoSP pTypeInfo = getTypeInfo(m_xType->get_active()); + pActFieldDescr->FillFromTypeInfo(pTypeInfo,true,false); // SetType(pTypeInfo); + + DisplayData(pActFieldDescr); + CellModified(-1, m_xType->GetPos()); + } +} + +void OFieldDescControl::ActivateAggregate( EControlType eType ) +{ + // Create Controls + switch( eType ) + { + case tpDefault: + if (m_xDefault) + return; + m_nPos++; + m_xDefaultText = m_xBuilder->weld_label("DefaultValueText"); + m_xDefaultText->show(); + m_xDefault = std::make_unique<OPropEditCtrl>( + m_xBuilder->weld_entry("DefaultValue"), STR_HELP_DEFAULT_VALUE, FIELD_PROPERTY_DEFAULT); + InitializeControl(m_xDefault->GetWidget(),HID_TAB_ENT_DEFAULT); + m_xDefault->show(); + break; + case tpAutoIncrementValue: + if (m_xAutoIncrementValue || !isAutoIncrementValueEnabled()) + return; + m_nPos++; + m_xAutoIncrementValueText = m_xBuilder->weld_label("AutoIncrementValueText"); + m_xAutoIncrementValueText->show(); + m_xAutoIncrementValue = std::make_unique<OPropEditCtrl>( + m_xBuilder->weld_spin_button("AutoIncrementValue"), STR_HELP_AUTOINCREMENT_VALUE, + FIELD_PROPERTY_AUTOINCREMENT); + m_xAutoIncrementValue->set_text( getAutoIncrementValue() ); + InitializeControl(m_xAutoIncrementValue->GetWidget(),HID_TAB_AUTOINCREMENTVALUE); + m_xAutoIncrementValue->show(); + break; + + case tpRequired: + { + if (m_xRequired) + return; + Reference< XDatabaseMetaData> xMetaData = getMetaData(); + + if(xMetaData.is() && xMetaData->supportsNonNullableColumns()) + { + m_nPos++; + m_xRequiredText = m_xBuilder->weld_label("RequiredText"); + m_xRequiredText->show(); + m_xRequired = std::make_unique<OPropListBoxCtrl>( + m_xBuilder->weld_combo_box("Required"), STR_HELP_AUTOINCREMENT_VALUE, + FIELD_PROPERTY_AUTOINCREMENT); + m_xRequired->append_text(aYes); + m_xRequired->append_text(aNo); + m_xRequired->set_active(1); + + InitializeControl(m_xRequired.get(),HID_TAB_ENT_REQUIRED, true); + m_xRequired->show(); + } + } + break; + case tpAutoIncrement: + { + if (m_xAutoIncrement) + return; + m_nPos++; + m_xAutoIncrementText = m_xBuilder->weld_label("AutoIncrementText"); + m_xAutoIncrementText->show(); + m_xAutoIncrement = std::make_unique<OPropListBoxCtrl>( + m_xBuilder->weld_combo_box("AutoIncrement"), STR_HELP_AUTOINCREMENT, + FIELD_PROPERTY_AUTOINC); + m_xAutoIncrement->append_text(aYes); + m_xAutoIncrement->append_text(aNo); + m_xAutoIncrement->set_active(0); + InitializeControl(m_xAutoIncrement.get(),HID_TAB_ENT_AUTOINCREMENT, true); + m_xAutoIncrement->show(); + } + break; + case tpTextLen: + if (m_xTextLen) + return; + m_nPos++; + m_xTextLenText = m_xBuilder->weld_label("TextLengthText"); + m_xTextLenText->show(); + m_xTextLen = CreateNumericControl("TextLength", STR_HELP_TEXT_LENGTH, FIELD_PROPERTY_TEXTLEN,HID_TAB_ENT_TEXT_LEN); + break; + + case tpType: + if (m_xType) + return; + m_nPos++; + m_xTypeText = m_xBuilder->weld_label("TypeText"); + m_xTypeText->show(); + m_xType = std::make_unique<OPropListBoxCtrl>( + m_xBuilder->weld_combo_box("Type"), STR_HELP_AUTOINCREMENT, FIELD_PROPERTY_TYPE); + { + const OTypeInfoMap* pTypeInfo = getTypeInfo(); + for (auto const& elem : *pTypeInfo) + m_xType->append_text(elem.second->aUIName); + } + m_xType->set_active(0); + InitializeControl(m_xType.get(),HID_TAB_ENT_TYPE, true); + m_xType->show(); + break; + case tpColumnName: + if (m_xColumnName) + return; + m_nPos++; + { + sal_Int32 nMax(0); + OUString aTmpString; + try + { + Reference< XDatabaseMetaData> xMetaData = getMetaData(); + if ( xMetaData.is() ) + { + nMax = xMetaData->getMaxColumnNameLength(); + aTmpString = xMetaData->getExtraNameCharacters(); + } + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + m_xColumnNameText = m_xBuilder->weld_label("ColumnNameText"); + m_xColumnNameText->show(); + m_xColumnName = std::make_unique<OPropColumnEditCtrl>( + m_xBuilder->weld_entry("ColumnName"), aTmpString, + STR_HELP_DEFAULT_VALUE, FIELD_PROPERTY_COLUMNNAME); + m_xColumnName->set_max_length(nMax); + m_xColumnName->setCheck( isSQL92CheckEnabled(getConnection()) ); + } + + InitializeControl(m_xColumnName->GetWidget(),HID_TAB_ENT_COLUMNNAME); + m_xColumnName->show(); + break; + case tpNumType: + if (m_xNumType) + return; + m_nPos++; + m_xNumTypeText = m_xBuilder->weld_label("NumTypeText"); + m_xNumTypeText->show(); + m_xNumType = std::make_unique<OPropListBoxCtrl>( + m_xBuilder->weld_combo_box("NumType"), STR_HELP_NUMERIC_TYPE, FIELD_PROPERTY_NUMTYPE); + m_xNumType->append_text("Byte"); + m_xNumType->append_text("SmallInt"); + m_xNumType->append_text("Integer"); + m_xNumType->append_text("Single"); + m_xNumType->append_text("Double"); + m_xNumType->set_active(2); + InitializeControl(m_xNumType.get(),HID_TAB_ENT_NUMTYP, true); + m_xNumType->show(); + break; + + case tpLength: + if (m_xLength) + return; + m_nPos++; + m_xLengthText = m_xBuilder->weld_label("LengthText"); + m_xLengthText->show(); + m_xLength = CreateNumericControl("Length", STR_HELP_LENGTH, FIELD_PROPERTY_LENGTH,HID_TAB_ENT_LEN); + break; + + case tpScale: + if (m_xScale) + return; + m_nPos++; + m_xScaleText = m_xBuilder->weld_label("ScaleText"); + m_xScaleText->show(); + m_xScale = CreateNumericControl("Scale", STR_HELP_SCALE, FIELD_PROPERTY_SCALE,HID_TAB_ENT_SCALE); + break; + + case tpFormat: + if (!m_xFormat) + { + m_nPos++; + m_xFormatText = m_xBuilder->weld_label("FormatTextText"); + m_xFormatText->show(); + + m_xFormatSample = std::make_unique<OPropEditCtrl>( + m_xBuilder->weld_entry("FormatText"), STR_HELP_FORMAT_CODE, -1); + m_xFormatSample->set_editable(false); + m_xFormatSample->set_sensitive(false); + InitializeControl(m_xFormatSample->GetWidget(),HID_TAB_ENT_FORMAT_SAMPLE); + m_xFormatSample->show(); + + m_xFormat = m_xBuilder->weld_button("FormatButton"); + m_xFormat->connect_clicked( LINK( this, OFieldDescControl, FormatClickHdl ) ); + InitializeControl(m_xFormat.get(),HID_TAB_ENT_FORMAT); + m_xFormat->show(); + } + + UpdateFormatSample(pActFieldDescr); + break; + case tpBoolDefault: + if (m_xBoolDefault) + return; + + m_nPos++; + m_xBoolDefaultText = m_xBuilder->weld_label("BoolDefaultText"); + m_xBoolDefaultText->show(); + m_xBoolDefault = std::make_unique<OPropListBoxCtrl>( + m_xBuilder->weld_combo_box("BoolDefault"), STR_HELP_BOOL_DEFAULT, + FIELD_PROPERTY_BOOL_DEFAULT); + m_xBoolDefault->append_text(DBA_RES(STR_VALUE_NONE)); + m_xBoolDefault->append_text(aYes); + m_xBoolDefault->append_text(aNo); + InitializeControl(m_xBoolDefault->GetWidget(),HID_TAB_ENT_BOOL_DEFAULT); + m_xBoolDefault->show(); + break; + } +} + +void OFieldDescControl::InitializeControl(OPropListBoxCtrl* _pControl,const OString& _sHelpId,bool _bAddChangeHandler) +{ + if ( _bAddChangeHandler ) + _pControl->GetComboBox().connect_changed(LINK(this,OFieldDescControl,ChangeHdl)); + + InitializeControl(_pControl->GetWidget(), _sHelpId); +} + +void OFieldDescControl::InitializeControl(weld::Widget* pControl,const OString& _sHelpId) +{ + pControl->set_help_id(_sHelpId); + pControl->connect_focus_in(LINK(this, OFieldDescControl, OnControlFocusGot)); + pControl->connect_focus_out(LINK(this, OFieldDescControl, OnControlFocusLost)); + + if (dynamic_cast<weld::Entry*>(pControl)) + { + int nWidthRequest = Application::GetDefaultDevice()->LogicToPixel(Size(m_nEditWidth, 0), MapMode(MapUnit::MapAppFont)).Width(); + pControl->set_size_request(nWidthRequest, -1); + } +} + +std::unique_ptr<OPropNumericEditCtrl> OFieldDescControl::CreateNumericControl(const OString& rId, TranslateId pHelpId, short _nProperty, const OString& _sHelpId) +{ + auto xControl = std::make_unique<OPropNumericEditCtrl>( + m_xBuilder->weld_spin_button(rId), pHelpId, _nProperty); + xControl->set_digits(0); + xControl->set_range(0, 0x7FFFFFFF); // Should be changed outside, if needed + xControl->show(); + + InitializeControl(xControl->GetWidget(),_sHelpId); + + return xControl; +} + +void OFieldDescControl::DeactivateAggregate( EControlType eType ) +{ + m_pLastFocusWindow = nullptr; + // Destroy Controls + switch( eType ) + { + case tpDefault: + lcl_HideAndDeleteControl(m_nPos,m_xDefault,m_xDefaultText); + break; + + case tpAutoIncrementValue: + lcl_HideAndDeleteControl(m_nPos,m_xAutoIncrementValue,m_xAutoIncrementValueText); + break; + + case tpColumnName: + lcl_HideAndDeleteControl(m_nPos,m_xColumnName,m_xColumnNameText); + break; + + case tpType: + lcl_HideAndDeleteControl(m_nPos,m_xType,m_xTypeText); + break; + + case tpAutoIncrement: + lcl_HideAndDeleteControl(m_nPos,m_xAutoIncrement,m_xAutoIncrementText); + break; + + case tpRequired: + lcl_HideAndDeleteControl(m_nPos,m_xRequired,m_xRequiredText); + break; + + case tpTextLen: + lcl_HideAndDeleteControl(m_nPos,m_xTextLen,m_xTextLenText); + break; + + case tpNumType: + lcl_HideAndDeleteControl(m_nPos,m_xNumType,m_xNumTypeText); + break; + + case tpLength: + lcl_HideAndDeleteControl(m_nPos,m_xLength,m_xLengthText); + break; + + case tpScale: + lcl_HideAndDeleteControl(m_nPos,m_xScale,m_xScaleText); + break; + + case tpFormat: + // TODO: we have to check if we have to increment m_nPos again + lcl_HideAndDeleteControl(m_nPos,m_xFormat,m_xFormatText); + if (m_xFormatSample) + { + m_xFormatSample->hide(); + m_xFormatSample.reset(); + } + break; + case tpBoolDefault: + lcl_HideAndDeleteControl(m_nPos,m_xBoolDefault,m_xBoolDefaultText); + break; + } +} + +void OFieldDescControl::DisplayData(OFieldDescription* pFieldDescr ) +{ + pActFieldDescr = pFieldDescr; + if(!pFieldDescr) + { + if (m_pHelp) + m_pHelp->SetHelpText( OUString() ); + DeactivateAggregate( tpDefault ); + DeactivateAggregate( tpRequired ); + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpNumType ); + DeactivateAggregate( tpScale ); + DeactivateAggregate( tpLength ); + DeactivateAggregate( tpFormat ); + DeactivateAggregate( tpAutoIncrement ); + DeactivateAggregate( tpBoolDefault ); + DeactivateAggregate( tpColumnName ); + DeactivateAggregate( tpType ); + DeactivateAggregate( tpAutoIncrementValue ); + m_pPreviousType = TOTypeInfoSP(); + // Reset the saved focus' pointer + m_pLastFocusWindow = nullptr; + return; + } + + TOTypeInfoSP pFieldType(pFieldDescr->getTypeInfo()); + + ActivateAggregate( tpColumnName ); + ActivateAggregate( tpType ); + + OSL_ENSURE(pFieldType,"We need a type information here!"); + // If the type has changed, substitute Controls + if( m_pPreviousType != pFieldType ) + { + // Reset the saved focus' pointer + m_pLastFocusWindow = nullptr; + + // Controls, which must NOT be displayed again + DeactivateAggregate( tpNumType ); + + // determine which controls we should show and which not + + // 1. the required control + if ( pFieldType->bNullable ) + ActivateAggregate( tpRequired ); + else + DeactivateAggregate( tpRequired ); + + // 2. the autoincrement + if ( pFieldType->bAutoIncrement ) + { + DeactivateAggregate( tpRequired ); + DeactivateAggregate( tpDefault ); + ActivateAggregate( tpAutoIncrement ); + ActivateAggregate( tpAutoIncrementValue ); + } + else + { + DeactivateAggregate( tpAutoIncrement ); + DeactivateAggregate( tpAutoIncrementValue ); + if(pFieldType->bNullable) + ActivateAggregate( tpRequired ); + else + DeactivateAggregate( tpRequired ); + ActivateAggregate( tpDefault ); + } + // 3. the scale and precision + if (pFieldType->nPrecision) + { + ActivateAggregate( tpLength ); + m_xLength->set_max(std::max<sal_Int32>(pFieldType->nPrecision,pFieldDescr->GetPrecision())); + m_xLength->set_editable(!pFieldType->aCreateParams.isEmpty()); + } + else + DeactivateAggregate( tpLength ); + + if (pFieldType->nMaximumScale) + { + ActivateAggregate( tpScale ); + m_xScale->set_range(pFieldType->nMinimumScale, + std::max<sal_Int32>(pFieldType->nMaximumScale,pFieldDescr->GetScale())); + m_xScale->set_editable(!pFieldType->aCreateParams.isEmpty() && pFieldType->aCreateParams != "PRECISION"); + } + else + DeactivateAggregate( tpScale ); + + // and now look for type specific things + switch( pFieldType->nType ) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + DeactivateAggregate( tpLength ); + DeactivateAggregate( tpBoolDefault ); + + ActivateAggregate( tpDefault ); + ActivateAggregate( tpFormat ); + if (pFieldType->nPrecision) + { + ActivateAggregate( tpTextLen ); + m_xTextLen->set_max(std::max<sal_Int32>(pFieldType->nPrecision,pFieldDescr->GetPrecision())); + m_xTextLen->set_editable(!pFieldType->aCreateParams.isEmpty()); + } + else + DeactivateAggregate( tpTextLen ); + break; + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + DeactivateAggregate( tpLength ); // we don't need a length for date types + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpBoolDefault ); + + ActivateAggregate( tpDefault ); + ActivateAggregate( tpFormat ); + break; + case DataType::BIT: + if ( !pFieldType->aCreateParams.isEmpty() ) + { + DeactivateAggregate( tpFormat ); + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpBoolDefault ); + break; + } + [[fallthrough]]; + case DataType::BOOLEAN: + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpFormat ); + DeactivateAggregate( tpDefault ); + + ActivateAggregate( tpBoolDefault ); + break; + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::BIGINT: + case DataType::FLOAT: + case DataType::DOUBLE: + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::REAL: + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpBoolDefault ); + + ActivateAggregate( tpFormat ); + break; + case DataType::BINARY: + case DataType::VARBINARY: + DeactivateAggregate( tpDefault ); + DeactivateAggregate( tpRequired ); + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpBoolDefault ); + + ActivateAggregate( tpFormat ); + break; + case DataType::LONGVARBINARY: + case DataType::SQLNULL: + case DataType::OBJECT: + case DataType::DISTINCT: + case DataType::STRUCT: + case DataType::ARRAY: + case DataType::BLOB: + case DataType::CLOB: + case DataType::REF: + case DataType::OTHER: + DeactivateAggregate( tpFormat ); + DeactivateAggregate( tpTextLen ); + DeactivateAggregate( tpBoolDefault ); + + break; + default: + OSL_FAIL("Unknown type"); + } + m_pPreviousType = pFieldType; + } + + if (pFieldDescr->IsPrimaryKey()) + { + DeactivateAggregate(tpRequired); + } + else if (!m_xAutoIncrement && pFieldType) + { + if (pFieldType->bNullable) + ActivateAggregate(tpRequired); + else + DeactivateAggregate(tpRequired); + } + // Initialize Controls + if (m_xAutoIncrement) + { + if ( pFieldDescr->IsAutoIncrement() ) + { + m_xAutoIncrement->set_active(0); // yes + ActivateAggregate( tpAutoIncrementValue ); + if (m_xAutoIncrementValue) + m_xAutoIncrementValue->set_text(pFieldDescr->GetAutoIncrementValue()); + DeactivateAggregate( tpRequired ); + DeactivateAggregate( tpDefault ); + } + else + { + // disable autoincrement value because it should only be visible when autoincrement is to true + DeactivateAggregate( tpAutoIncrementValue ); + m_xAutoIncrement->set_active(1); // no + ActivateAggregate( tpDefault ); + // Affects pRequired + if(!pFieldDescr->IsPrimaryKey()) + ActivateAggregate( tpRequired ); + } + } + + if (m_xDefault) + { + m_xDefault->set_text(getControlDefault(pFieldDescr)); + m_xDefault->save_value(); + } + + if (m_xBoolDefault) + { + // If m_xRequired = sal_True then the sal_Bool field must NOT contain <<none>> + OUString sValue; + pFieldDescr->GetControlDefault() >>= sValue; + OUString sDef = BoolStringUI(sValue); + + // Make sure that <<none>> is only present if the field can be NULL + if ( ( pFieldType && !pFieldType->bNullable ) || !pFieldDescr->IsNullable() ) + { + pFieldDescr->SetIsNullable(ColumnValue::NO_NULLS); // The type says so + + m_xBoolDefault->remove_text(DBA_RES(STR_VALUE_NONE)); + if ( sDef != aYes && sDef != aNo ) + m_xBoolDefault->set_active(1); // No as a default + else + m_xBoolDefault->set_active_text(sDef); + + pFieldDescr->SetControlDefault(Any(BoolStringPersistent(m_xBoolDefault->get_active_text()))); + } + else if (m_xBoolDefault->get_count() < 3) + { + m_xBoolDefault->append_text(DBA_RES(STR_VALUE_NONE)); + m_xBoolDefault->set_active_text(sDef); + } + else + m_xBoolDefault->set_active_text(sDef); + } + + if (m_xRequired) + { + if( pFieldDescr->IsNullable() ) + m_xRequired->set_active(1); // no + else + m_xRequired->set_active(0); // yes + } + + if (m_xTextLen) + { + m_xTextLen->set_text(OUString::number(pFieldDescr->GetPrecision())); + m_xTextLen->save_value(); + } + + if( m_xNumType ) + { + OSL_FAIL("OFieldDescControl::DisplayData: invalid num type!"); + } + + if (m_xLength) + m_xLength->set_text(OUString::number(pFieldDescr->GetPrecision())); + + if (m_xScale) + m_xScale->set_text(OUString::number(pFieldDescr->GetScale())); + + if (m_xFormat) + UpdateFormatSample(pFieldDescr); + + if (m_xColumnName) + m_xColumnName->set_text(pFieldDescr->GetName()); + + if (m_xType) + { + sal_Int32 nPos = pFieldType ? m_xType->find_text(pFieldDescr->getTypeInfo()->aUIName) : -1; + if (nPos == -1) + { + const OTypeInfoMap* pMap = getTypeInfo(); + OTypeInfoMap::const_iterator aIter = pMap->find(pFieldType ? pFieldDescr->getTypeInfo()->nType : pFieldDescr->GetType()); + if(aIter == pMap->end() && !pMap->empty()) + { + aIter = pMap->begin(); + if(pFieldDescr->GetPrecision() > aIter->second->nPrecision) + pFieldDescr->SetPrecision(aIter->second->nPrecision); + if(pFieldDescr->GetScale() > aIter->second->nMaximumScale) + pFieldDescr->SetScale(0); + if(!aIter->second->bNullable && pFieldDescr->IsNullable()) + pFieldDescr->SetIsNullable(ColumnValue::NO_NULLS); + if(!aIter->second->bAutoIncrement && pFieldDescr->IsAutoIncrement()) + pFieldDescr->SetAutoIncrement(false); + } + if ( aIter != pMap->end() ) + { + pFieldDescr->SetType(aIter->second); + } + } + m_xType->set_active_text(pFieldDescr->getTypeInfo()->aUIName); + } + + // Enable/disable Controls + bool bRead(IsReadOnly()); + + SetReadOnly( bRead ); +} + +IMPL_LINK(OFieldDescControl, OnControlFocusGot, weld::Widget&, rControl, void ) +{ + OUString strHelpText; + + if (m_xTextLen && &rControl == m_xTextLen->GetWidget()) + { + m_xTextLen->save_value(); + strHelpText = m_xTextLen->GetHelp(); + } + else if (m_xLength && &rControl == m_xLength->GetWidget()) + { + m_xLength->save_value(); + strHelpText = m_xLength->GetHelp(); + } + else if (m_xScale && &rControl == m_xScale->GetWidget()) + { + m_xScale->save_value(); + strHelpText = m_xScale->GetHelp(); + } + else if (m_xColumnName && &rControl == m_xColumnName->GetWidget()) + { + m_xColumnName->save_value(); + strHelpText = m_xColumnName->GetHelp(); + } + else if (m_xDefault && &rControl == m_xDefault->GetWidget()) + { + m_xDefault->save_value(); + strHelpText = m_xDefault->GetHelp(); + } + else if (m_xFormatSample && &rControl == m_xFormatSample->GetWidget()) + { + m_xFormatSample->save_value(); + strHelpText = m_xFormatSample->GetHelp(); + } + else if (m_xAutoIncrementValue && &rControl == m_xAutoIncrementValue->GetWidget()) + { + m_xAutoIncrementValue->save_value(); + strHelpText = m_xAutoIncrementValue->GetHelp(); + } + else if (m_xRequired && &rControl == m_xRequired->GetWidget()) + { + m_xRequired->save_value(); + strHelpText = m_xRequired->GetHelp(); + } + else if (m_xNumType && &rControl == m_xNumType->GetWidget()) + { + m_xNumType->save_value(); + strHelpText = m_xNumType->GetHelp(); + } + else if (m_xAutoIncrement && &rControl == m_xAutoIncrement->GetWidget()) + { + m_xAutoIncrement->save_value(); + strHelpText = m_xAutoIncrement->GetHelp(); + } + else if (m_xBoolDefault && &rControl == m_xBoolDefault->GetWidget()) + { + m_xBoolDefault->save_value(); + strHelpText = m_xBoolDefault->GetHelp(); + } + else if (m_xType && &rControl == m_xType->GetWidget()) + { + m_xType->save_value(); + strHelpText = m_xType->GetHelp(); + } + else if (m_xFormat && &rControl == m_xFormat.get()) + strHelpText = DBA_RES(STR_HELP_FORMAT_BUTTON); + + if (!strHelpText.isEmpty() && m_pHelp) + m_pHelp->SetHelpText(strHelpText); + + m_pActFocusWindow = &rControl; + + m_aControlFocusIn.Call(rControl); +} + +IMPL_LINK(OFieldDescControl, OnControlFocusLost, weld::Widget&, rControl, void ) +{ + if (m_xLength && &rControl == m_xLength->GetWidget() && m_xLength->get_value_changed_from_saved()) + CellModified(-1, m_xLength->GetPos()); + else if (m_xTextLen && &rControl == m_xTextLen->GetWidget() && m_xTextLen->get_value_changed_from_saved()) + CellModified(-1, m_xTextLen->GetPos()); + else if (m_xScale && &rControl == m_xScale->GetWidget() && m_xScale->get_value_changed_from_saved()) + CellModified(-1, m_xScale->GetPos()); + else if (m_xColumnName && &rControl == m_xColumnName->GetWidget() && m_xColumnName->get_value_changed_from_saved()) + CellModified(-1, m_xColumnName->GetPos()); + else if (m_xDefault && &rControl == m_xDefault->GetWidget() && m_xDefault->get_value_changed_from_saved()) + CellModified(-1, m_xDefault->GetPos()); + else if (m_xFormatSample && &rControl == m_xFormatSample->GetWidget() && m_xFormatSample->get_value_changed_from_saved()) + CellModified(-1, m_xFormatSample->GetPos()); + else if (m_xAutoIncrementValue && &rControl == m_xAutoIncrementValue->GetWidget() && m_xAutoIncrementValue->get_value_changed_from_saved()) + CellModified(-1, m_xAutoIncrementValue->GetPos()); + else if (m_xRequired && &rControl == m_xRequired->GetWidget() && m_xRequired->get_value_changed_from_saved()) + CellModified(-1, m_xRequired->GetPos()); + else if (m_xNumType && &rControl == m_xNumType->GetWidget() && m_xNumType->get_value_changed_from_saved()) + CellModified(-1, m_xNumType->GetPos()); + else if (m_xAutoIncrement && &rControl == m_xAutoIncrement->GetWidget() && m_xAutoIncrement->get_value_changed_from_saved()) + CellModified(-1, m_xAutoIncrement->GetPos()); + else if (m_xBoolDefault && &rControl == m_xBoolDefault->GetWidget() && m_xBoolDefault->get_value_changed_from_saved()) + CellModified(-1, m_xBoolDefault->GetPos()); + else if (m_xType && &rControl == m_xType->GetWidget() && m_xType->get_value_changed_from_saved()) + CellModified(-1, m_xType->GetPos()); + else if (m_xDefault && &rControl == m_xDefault->GetWidget()) + UpdateFormatSample(pActFieldDescr); + + implFocusLost(&rControl); +} + +void OFieldDescControl::SaveData( OFieldDescription* pFieldDescr ) +{ + if( !pFieldDescr ) + return; + + // Read out Controls + OUString sDefault; + if (m_xDefault) + { + // tdf#138409 take the control default in the UI Locale format, e.g. 12,34 and return a string + // suitable as the database default, e.g. 12.34 + sDefault = CanonicalizeToControlDefault(pFieldDescr, m_xDefault->get_text()); + } + else if (m_xBoolDefault) + { + sDefault = BoolStringPersistent(m_xBoolDefault->get_active_text()); + } + + if ( !sDefault.isEmpty() ) + pFieldDescr->SetControlDefault(Any(sDefault)); + else + pFieldDescr->SetControlDefault(Any()); + + if((m_xRequired && m_xRequired->get_active() == 0) || pFieldDescr->IsPrimaryKey() || (m_xBoolDefault && m_xBoolDefault->get_count() == 2)) // yes + pFieldDescr->SetIsNullable( ColumnValue::NO_NULLS ); + else + pFieldDescr->SetIsNullable( ColumnValue::NULLABLE ); + + if (m_xAutoIncrement) + pFieldDescr->SetAutoIncrement(m_xAutoIncrement->get_active() == 0); + + if( m_xTextLen ) + pFieldDescr->SetPrecision( static_cast<sal_Int32>(m_xTextLen->get_value()) ); + else if (m_xLength) + pFieldDescr->SetPrecision( static_cast<sal_Int32>(m_xLength->get_value()) ); + if (m_xScale) + pFieldDescr->SetScale( static_cast<sal_Int32>(m_xScale->get_value()) ); + + if (m_xColumnName) + pFieldDescr->SetName(m_xColumnName->get_text()); + + if (m_xAutoIncrementValue && isAutoIncrementValueEnabled()) + pFieldDescr->SetAutoIncrementValue(m_xAutoIncrementValue->get_text()); +} + +void OFieldDescControl::UpdateFormatSample(OFieldDescription const * pFieldDescr) +{ + if (pFieldDescr && m_xFormatSample) + m_xFormatSample->set_text(getControlDefault(pFieldDescr,false)); +} + +void OFieldDescControl::GrabFocus() +{ + m_xContainer->grab_focus(); + + // Set the Focus to the Control that has been active last + if (m_pLastFocusWindow) + { + m_pLastFocusWindow->grab_focus(); + m_pLastFocusWindow = nullptr; + } +} + +void OFieldDescControl::implFocusLost(weld::Widget* _pWhich) +{ + // Remember the active Control + if (!m_pLastFocusWindow) + m_pLastFocusWindow = _pWhich; + + // Reset HelpText + if (m_pHelp && !m_pHelp->HasFocus()) + m_pHelp->SetHelpText( OUString() ); +} + +IMPL_LINK_NOARG(OFieldDescControl, HelpFocusOut, weld::Widget&, void) +{ + m_pHelp->SetHelpText(OUString()); +} + +bool OFieldDescControl::IsFocusInEditableWidget() const +{ + if (m_xDefault && m_pActFocusWindow == m_xDefault->GetWidget()) + return true; + if (m_xFormatSample && m_pActFocusWindow == m_xFormatSample->GetWidget()) + return true; + if (m_xTextLen && m_pActFocusWindow == m_xTextLen->GetWidget()) + return true; + if (m_xLength && m_pActFocusWindow == m_xLength->GetWidget()) + return true; + if (m_xScale && m_pActFocusWindow == m_xScale->GetWidget()) + return true; + if (m_xColumnName && m_pActFocusWindow == m_xColumnName->GetWidget()) + return true; + if (m_xAutoIncrementValue && m_pActFocusWindow == m_xAutoIncrementValue->GetWidget()) + return true; + return false; +} + +bool OFieldDescControl::HasChildPathFocus() const +{ + return m_xContainer && m_xContainer->has_child_focus(); +} + +bool OFieldDescControl::isCopyAllowed() +{ + int nStartPos, nEndPos; + bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget() && + dynamic_cast<weld::Entry&>(*m_pActFocusWindow).get_selection_bounds(nStartPos, nEndPos); + return bAllowed; +} + +bool OFieldDescControl::isCutAllowed() +{ + int nStartPos, nEndPos; + bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget() && + dynamic_cast<weld::Entry&>(*m_pActFocusWindow).get_selection_bounds(nStartPos, nEndPos); + return bAllowed; +} + +bool OFieldDescControl::isPasteAllowed() +{ + bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget(); + if ( bAllowed ) + { + TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromClipboard(m_pActFocusWindow->get_clipboard())); + bAllowed = aTransferData.HasFormat(SotClipboardFormatId::STRING); + } + return bAllowed; +} + +void OFieldDescControl::cut() +{ + if (isCutAllowed()) + dynamic_cast<weld::Entry&>(*m_pActFocusWindow).cut_clipboard(); +} + +void OFieldDescControl::copy() +{ + if (isCopyAllowed()) // this only checks if the focus window is valid + dynamic_cast<weld::Entry&>(*m_pActFocusWindow).copy_clipboard(); +} + +void OFieldDescControl::paste() +{ + if (m_pActFocusWindow) // this only checks if the focus window is valid + dynamic_cast<weld::Entry&>(*m_pActFocusWindow).paste_clipboard(); +} + +bool OFieldDescControl::isTextFormat(const OFieldDescription* _pFieldDescr, sal_uInt32& _nFormatKey) const +{ + _nFormatKey = _pFieldDescr->GetFormatKey(); + bool bTextFormat = true; + + try + { + if (!_nFormatKey) + { + Reference< css::util::XNumberFormatTypes> xNumberTypes(GetFormatter()->getNumberFormatsSupplier()->getNumberFormats(),UNO_QUERY); + OSL_ENSURE(xNumberTypes.is(),"XNumberFormatTypes is null!"); + + _nFormatKey = ::dbtools::getDefaultNumberFormat( _pFieldDescr->GetType(), + _pFieldDescr->GetScale(), + _pFieldDescr->IsCurrency(), + xNumberTypes, + GetLocale()); + } + sal_Int32 nNumberFormat = ::comphelper::getNumberFormatType(GetFormatter(),_nFormatKey); + bTextFormat = (nNumberFormat == css::util::NumberFormat::TEXT); + } + catch(const Exception&) + { + + } + + return bTextFormat; +} + +OUString OFieldDescControl::getControlDefault( const OFieldDescription* _pFieldDescr, bool _bCheck) const +{ + OUString sDefault; + bool bCheck = !_bCheck || _pFieldDescr->GetControlDefault().hasValue(); + if ( bCheck ) + { + try + { + double nValue = 0.0; + sal_uInt32 nFormatKey; + bool bTextFormat = isTextFormat(_pFieldDescr,nFormatKey); + if ( _pFieldDescr->GetControlDefault() >>= sDefault ) + { + if ( !bTextFormat ) + { + if ( !sDefault.isEmpty() ) + { + try + { + nValue = GetFormatter()->convertStringToNumber(nFormatKey,sDefault); + } + catch(const Exception&) + { + return OUString(); // return empty string for format example + } + } + } + } + else + _pFieldDescr->GetControlDefault() >>= nValue; + + Reference< css::util::XNumberFormatter> xNumberFormatter = GetFormatter(); + Reference<XPropertySet> xFormSet = xNumberFormatter->getNumberFormatsSupplier()->getNumberFormats()->getByKey(nFormatKey); + OSL_ENSURE(xFormSet.is(),"XPropertySet is null!"); + OUString sFormat; + xFormSet->getPropertyValue("FormatString") >>= sFormat; + + if ( !bTextFormat ) + { + Locale aLocale; + ::comphelper::getNumberFormatProperty(xNumberFormatter,nFormatKey,"Locale") >>= aLocale; + + sal_Int32 nNumberFormat = ::comphelper::getNumberFormatType(xNumberFormatter,nFormatKey); + if( (nNumberFormat & css::util::NumberFormat::DATE) == css::util::NumberFormat::DATE + || (nNumberFormat & css::util::NumberFormat::DATETIME) == css::util::NumberFormat::DATETIME ) + { + nValue = DBTypeConversion::toNullDate(DBTypeConversion::getNULLDate(xNumberFormatter->getNumberFormatsSupplier()),nValue); + } + + Reference< css::util::XNumberFormatPreviewer> xPreviewer(xNumberFormatter,UNO_QUERY); + OSL_ENSURE(xPreviewer.is(),"XNumberFormatPreviewer is null!"); + sDefault = xPreviewer->convertNumberToPreviewString(sFormat,nValue,aLocale,true); + } + else if ( !(_bCheck && sDefault.isEmpty()) ) + sDefault = xNumberFormatter->formatString(nFormatKey, sDefault.isEmpty() ? sFormat : sDefault); + } + catch(const Exception&) + { + + } + } + + return sDefault; +} + +// tdf#138409 intended to be effectively the reverse of getControlDefault to +// turn a user's possibly 12,34 format into 12.34 format for numerical types +OUString OFieldDescControl::CanonicalizeToControlDefault(const OFieldDescription* pFieldDescr, const OUString& rDefault) const +{ + if (rDefault.isEmpty()) + return rDefault; + + bool bIsNumericalType = false; + switch (pFieldDescr->GetType()) + { + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::BIGINT: + case DataType::FLOAT: + case DataType::REAL: + case DataType::DOUBLE: + case DataType::NUMERIC: + case DataType::DECIMAL: + bIsNumericalType = true; + break; + } + + if (!bIsNumericalType) + return rDefault; + + try + { + sal_uInt32 nFormatKey; + bool bTextFormat = isTextFormat(pFieldDescr, nFormatKey); + if (bTextFormat) + return rDefault; + double nValue = GetFormatter()->convertStringToNumber(nFormatKey, rDefault); + return OUString::number(nValue); + } + catch(const Exception&) + { + } + + return rDefault; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/RelationControl.cxx b/dbaccess/source/ui/control/RelationControl.cxx new file mode 100644 index 000000000..fc8bca178 --- /dev/null +++ b/dbaccess/source/ui/control/RelationControl.cxx @@ -0,0 +1,695 @@ +/* -*- 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 <RelationControl.hxx> + +#include <svtools/editbrowsebox.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <tools/diagnose_ex.h> +#include <toolkit/helper/vclunohelper.hxx> +#include <TableConnectionData.hxx> +#include <TableConnection.hxx> +#include <TableWindow.hxx> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <RelControliFace.hxx> +#include <helpids.h> +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> + +#include <vector> +#include <utility> +using std::pair; +using std::make_pair; + +#define SOURCE_COLUMN 1 +#define DEST_COLUMN 2 + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + 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 svt; + + typedef ::svt::EditBrowseBox ORelationControl_Base; + class ORelationControl : public ORelationControl_Base + { + friend class OTableListBoxControl; + + VclPtr< ::svt::ListBoxControl> m_pListCell; + TTableConnectionData::value_type m_pConnData; + OTableListBoxControl* m_pBoxControl; + tools::Long m_nDataPos; + Reference< XPropertySet> m_xSourceDef; + Reference< XPropertySet> m_xDestDef; + enum opcode { DELETE, INSERT, MODIFY }; + typedef std::vector< pair < opcode, pair < OConnectionLineDataVec::size_type, OConnectionLineDataVec::size_type> > > ops_type; + ops_type m_ops; + + void fillListBox(const Reference< XPropertySet>& _xDest); + /** returns the column id for the editbrowsebox + @param _nColId + the column id SOURCE_COLUMN or DEST_COLUMN + + @return the current column id either SOURCE_COLUMN or DEST_COLUMN depends on the connection data + */ + sal_uInt16 getColumnIdent( sal_uInt16 _nColId ) const; + public: + explicit ORelationControl(const css::uno::Reference<css::awt::XWindow>& rParent); + void SetController(OTableListBoxControl* pController) + { + m_pBoxControl = pController; + } + + /** searches for a connection between these two tables + @param _pSource + the left table + @param _pDest + the right window + */ + void setWindowTables(const OTableWindow* _pSource,const OTableWindow* _pDest); + + /** allows to access the connection data from outside + + @return the connection data + */ + const TTableConnectionData::value_type& getData() const { return m_pConnData; } + + void lateInit(); + + protected: + virtual ~ORelationControl() override { disposeOnce(); } + virtual void dispose() override { m_pListCell.disposeAndClear(); ORelationControl_Base::dispose(); } + virtual void Resize() override; + virtual Size GetOptimalSize() const override; + virtual bool PreNotify(NotifyEvent& rNEvt ) override; + + virtual bool IsTabAllowed(bool bForward) const override; + + void Init(const TTableConnectionData::value_type& _pConnData); + using ORelationControl_Base::Init; + virtual void InitController( ::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol ) override; + virtual ::svt::CellController* GetController( sal_Int32 nRow, sal_uInt16 nCol ) override; + virtual void PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColId ) const override; + virtual bool SeekRow( sal_Int32 nRow ) override; + virtual bool SaveModified() override; + virtual OUString GetCellText( sal_Int32 nRow, sal_uInt16 nColId ) const override; + + virtual void CellModified() override; + + DECL_LINK( AsynchDeactivate, void*, void ); + private: + + DECL_LINK( AsynchActivate, void*, void ); + + }; + + ORelationControl::ORelationControl(const css::uno::Reference<css::awt::XWindow>& rParent) + : EditBrowseBox(VCLUnoHelper::GetWindow(rParent), + EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT, + WB_TABSTOP | WB_BORDER, + BrowserMode::AUTOSIZE_LASTCOL) + , m_pBoxControl(nullptr) + , m_nDataPos(0) + { + } + + void ORelationControl::Init(const TTableConnectionData::value_type& _pConnData) + { + + m_pConnData = _pConnData; + OSL_ENSURE(m_pConnData, "No data supplied!"); + + m_pConnData->normalizeLines(); + } + + void ORelationControl::lateInit() + { + if ( !m_pConnData ) + return; + m_xSourceDef = m_pConnData->getReferencingTable()->getTable(); + m_xDestDef = m_pConnData->getReferencedTable()->getTable(); + + if ( ColCount() == 0 ) + { + InsertDataColumn( SOURCE_COLUMN, m_pConnData->getReferencingTable()->GetWinName(), 100); + InsertDataColumn( DEST_COLUMN, m_pConnData->getReferencedTable()->GetWinName(), 100); + // If the Defs do not yet exits, we need to set them with SetSource-/-DestDef + + m_pListCell.reset( VclPtr<ListBoxControl>::Create( &GetDataWindow() ) ); + + // set browse mode + SetMode( BrowserMode::COLUMNSELECTION | + BrowserMode::HLINES | + BrowserMode::VLINES | + BrowserMode::HIDECURSOR | + BrowserMode::HIDESELECT | + BrowserMode::AUTO_HSCROLL | + BrowserMode::AUTO_VSCROLL); + } + else + // not the first call + RowRemoved(0, GetRowCount()); + + RowInserted(0, m_pConnData->GetConnLineDataList().size() + 1); // add one extra row + } + + void ORelationControl::Resize() + { + EditBrowseBox::Resize(); + tools::Long nOutputWidth = GetOutputSizePixel().Width() - 1; + SetColumnWidth(1, (nOutputWidth / 2)); + SetColumnWidth(2, (nOutputWidth / 2)); + } + + bool ORelationControl::PreNotify(NotifyEvent& rNEvt) + { + if (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS && !HasChildPathFocus() && !ControlHasFocus()) + PostUserEvent(LINK(this, ORelationControl, AsynchDeactivate), nullptr, true); + else if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + PostUserEvent(LINK(this, ORelationControl, AsynchActivate), nullptr, true); + + return EditBrowseBox::PreNotify(rNEvt); + } + + IMPL_LINK_NOARG(ORelationControl, AsynchActivate, void*, void) + { + ActivateCell(); + } + + IMPL_LINK_NOARG(ORelationControl, AsynchDeactivate, void*, void) + { + DeactivateCell(); + } + + bool ORelationControl::IsTabAllowed(bool bForward) const + { + sal_Int32 nRow = GetCurRow(); + sal_uInt16 nCol = GetCurColumnId(); + + bool bRet = !( ( bForward && (nCol == DEST_COLUMN) && (nRow == GetRowCount() - 1)) + || (!bForward && (nCol == SOURCE_COLUMN) && (nRow == 0))); + + return bRet && EditBrowseBox::IsTabAllowed(bForward); + } + + bool ORelationControl::SaveModified() + { + sal_Int32 nRow = GetCurRow(); + if ( nRow != BROWSER_ENDOFSELECTION ) + { + weld::ComboBox& rListBox = m_pListCell->get_widget(); + OUString sFieldName(rListBox.get_active_text()); + OConnectionLineDataVec& rLines = m_pConnData->GetConnLineDataList(); + if ( rLines.size() <= o3tl::make_unsigned(nRow) ) + { + rLines.push_back(new OConnectionLineData()); + nRow = rLines.size() - 1; + // add new past-rLines row + m_ops.emplace_back(INSERT, make_pair(nRow+1, nRow+2)); + } + + OConnectionLineDataRef pConnLineData = rLines[nRow]; + + switch( getColumnIdent( GetCurColumnId() ) ) + { + case SOURCE_COLUMN: + pConnLineData->SetSourceFieldName( sFieldName ); + break; + case DEST_COLUMN: + pConnLineData->SetDestFieldName( sFieldName ); + break; + } + // the modification we just did does *not* need to be registered in m_ops; + // it is already taken into account (by the codepath that called us) + //m_ops.push_back(make_pair(MODIFY, make_pair(nRow, nRow+1))); + } + + const OConnectionLineDataVec::size_type oldSize = m_pConnData->GetConnLineDataList().size(); + OConnectionLineDataVec::size_type line = m_pConnData->normalizeLines(); + const OConnectionLineDataVec::size_type newSize = m_pConnData->GetConnLineDataList().size(); + assert(newSize <= oldSize); + m_ops.emplace_back(MODIFY, make_pair(line, newSize)); + m_ops.emplace_back(DELETE, make_pair(newSize, oldSize)); + + return true; + } + + sal_uInt16 ORelationControl::getColumnIdent( sal_uInt16 _nColId ) const + { + sal_uInt16 nId = _nColId; + if ( m_pConnData->getReferencingTable() != m_pBoxControl->getReferencingTable() ) + nId = ( _nColId == SOURCE_COLUMN) ? DEST_COLUMN : SOURCE_COLUMN; + return nId; + } + + OUString ORelationControl::GetCellText( sal_Int32 nRow, sal_uInt16 nColId ) const + { + OUString sText; + if ( m_pConnData->GetConnLineDataList().size() > o3tl::make_unsigned(nRow) ) + { + OConnectionLineDataRef pConnLineData = m_pConnData->GetConnLineDataList()[nRow]; + switch( getColumnIdent( nColId ) ) + { + case SOURCE_COLUMN: + sText = pConnLineData->GetSourceFieldName(); + break; + case DEST_COLUMN: + sText = pConnLineData->GetDestFieldName(); + break; + } + } + return sText; + } + + void ORelationControl::InitController( CellControllerRef& /*rController*/, sal_Int32 nRow, sal_uInt16 nColumnId ) + { + + OString sHelpId( HID_RELATIONDIALOG_LEFTFIELDCELL ); + + Reference< XPropertySet> xDef; + switch ( getColumnIdent(nColumnId) ) + { + case SOURCE_COLUMN: + xDef = m_xSourceDef; + sHelpId = HID_RELATIONDIALOG_LEFTFIELDCELL; + break; + case DEST_COLUMN: + xDef = m_xDestDef; + sHelpId = HID_RELATIONDIALOG_RIGHTFIELDCELL; + break; + default: + // ????????? + break; + } + + if ( !xDef.is() ) + return; + + fillListBox(xDef); + OUString sName = GetCellText( nRow, nColumnId ); + weld::ComboBox& rList = m_pListCell->get_widget(); + rList.set_active_text(sName); + if (rList.get_active_text() != sName) + { + rList.append_text(sName); + rList.set_active_text(sName); + } + + rList.set_help_id(sHelpId); + } + + CellController* ORelationControl::GetController( sal_Int32 /*nRow*/, sal_uInt16 /*nColumnId*/ ) + { + return new ListBoxCellController( m_pListCell.get() ); + } + + bool ORelationControl::SeekRow( sal_Int32 nRow ) + { + m_nDataPos = nRow; + return true; + } + + void ORelationControl::PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const + { + OUString aText = GetCellText( m_nDataPos, nColumnId ); + + Point aPos( rRect.TopLeft() ); + Size aTextSize( GetDataWindow().GetTextWidth( aText ), GetDataWindow().GetTextHeight() ); + + if( aPos.X() < rRect.Left() || aPos.X() + aTextSize.Width() > rRect.Right() || + aPos.Y() < rRect.Top() || aPos.Y() + aTextSize.Height() > rRect.Bottom() ) + { + rDev.SetClipRegion(vcl::Region(rRect)); + } + + rDev.DrawText( aPos, aText ); + + if( rDev.IsClipRegion() ) + rDev.SetClipRegion(); + } + void ORelationControl::fillListBox(const Reference< XPropertySet>& _xDest) + { + weld::ComboBox& rList = m_pListCell->get_widget(); + rList.clear(); + try + { + if ( _xDest.is() ) + { + //sal_Int32 nRows = GetRowCount(); + Reference<XColumnsSupplier> xSup(_xDest,UNO_QUERY); + Reference<XNameAccess> xColumns = xSup->getColumns(); + Sequence< OUString> aNames = xColumns->getElementNames(); + const OUString* pIter = aNames.getConstArray(); + const OUString* pEnd = pIter + aNames.getLength(); + for(;pIter != pEnd;++pIter) + { + rList.append_text(*pIter); + } + rList.insert_text(0, OUString()); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + void ORelationControl::setWindowTables(const OTableWindow* _pSource,const OTableWindow* _pDest) + { + // If I edit here, hide + bool bWasEditing = IsEditing(); + if ( bWasEditing ) + DeactivateCell(); + + if ( _pSource && _pDest ) + { + m_xSourceDef = _pSource->GetTable(); + SetColumnTitle(1, _pSource->GetName()); + + m_xDestDef = _pDest->GetTable(); + SetColumnTitle(2, _pDest->GetName()); + + const OJoinTableView* pView = _pSource->getTableView(); + OTableConnection* pConn = pView->GetTabConn(_pSource,_pDest); + if ( pConn && !m_pConnData->GetConnLineDataList().empty() ) + { + m_pConnData->CopyFrom(*pConn->GetData()); + m_pBoxControl->getContainer()->notifyConnectionChange(); + } + else + { + // no connection found so we clear our data + OConnectionLineDataVec& rLines = m_pConnData->GetConnLineDataList(); + for( const auto& rLine : rLines ) + { + rLine->Reset(); + } + + m_pConnData->setReferencingTable(_pSource->GetData()); + m_pConnData->setReferencedTable(_pDest->GetData()); + } + m_pConnData->normalizeLines(); + + } + // Repaint + Invalidate(); + + if ( bWasEditing ) + { + GoToRow(0); + ActivateCell(); + } + } + + void ORelationControl::CellModified() + { + EditBrowseBox::CellModified(); + SaveModified(); + assert(m_pBoxControl); + m_pBoxControl->NotifyCellChange(); + } + + Size ORelationControl::GetOptimalSize() const + { + return LogicToPixel(Size(140, 80), MapMode(MapUnit::MapAppFont)); + } + + OTableListBoxControl::OTableListBoxControl(weld::Builder* _pParent, + const OJoinTableView::OTableWindowMap* _pTableMap, + IRelationControlInterface* _pParentDialog) + : m_xLeftTable(_pParent->weld_combo_box("table1")) + , m_xRightTable(_pParent->weld_combo_box("table2")) + , m_xTable(_pParent->weld_container("relations")) + , m_xTableCtrlParent(m_xTable->CreateChildFrame()) + , m_xRC_Tables(VclPtr<ORelationControl>::Create(m_xTableCtrlParent)) + , m_pTableMap(_pTableMap) + , m_pParentDialog(_pParentDialog) + { + Size aPrefSize = m_xRC_Tables->GetOptimalSize(); + m_xTable->set_size_request(aPrefSize.Width(), aPrefSize.Height()); + + m_xRC_Tables->SetController(this); + m_xRC_Tables->Init(); + + lateUIInit(); + + Link<weld::ComboBox&,void> aLink(LINK(this, OTableListBoxControl, OnTableChanged)); + m_xLeftTable->connect_changed(aLink); + m_xRightTable->connect_changed(aLink); + } + + OTableListBoxControl::~OTableListBoxControl() + { + m_xRC_Tables.disposeAndClear(); + m_xTableCtrlParent->dispose(); + m_xTableCtrlParent.clear(); + } + + void OTableListBoxControl::fillListBoxes() + { + OSL_ENSURE( !m_pTableMap->empty(), "OTableListBoxControl::fillListBoxes: no table window!"); + OTableWindow* pInitialLeft = nullptr; + OTableWindow* pInitialRight = nullptr; + + // Collect the names of all TabWins + for (auto const& elem : *m_pTableMap) + { + m_xLeftTable->append_text(elem.first); + m_xRightTable->append_text(elem.first); + + if (!pInitialLeft) + { + pInitialLeft = elem.second; + m_strCurrentLeft = elem.first; + } + else if (!pInitialRight) + { + pInitialRight = elem.second; + m_strCurrentRight = elem.first; + } + } + + if ( !pInitialRight ) + { + pInitialRight = pInitialLeft; + m_strCurrentRight = m_strCurrentLeft; + } + + // The corresponding Defs for my Controls + m_xRC_Tables->setWindowTables(pInitialLeft,pInitialRight); + + // The table selected in a ComboBox must not be available in the other + + if ( m_pTableMap->size() > 2 ) + { + m_xLeftTable->remove_text(m_strCurrentRight); + m_xRightTable->remove_text(m_strCurrentLeft); + } + + // Select the first one on the left side and on the right side, + // select the second one + m_xLeftTable->set_active_text(m_strCurrentLeft); + m_xRightTable->set_active_text(m_strCurrentRight); + + m_xLeftTable->grab_focus(); + } + + IMPL_LINK(OTableListBoxControl, OnTableChanged, weld::ComboBox&, rListBox, void) + { + OUString strSelected(rListBox.get_active_text()); + OTableWindow* pLeft = nullptr; + OTableWindow* pRight = nullptr; + + // Special treatment: If there are only two tables, we need to switch the other one too when changing in a LB + if ( m_pTableMap->size() == 2 ) + { + weld::ComboBox* pOther; + if (&rListBox == m_xLeftTable.get()) + pOther = m_xRightTable.get(); + else + pOther = m_xLeftTable.get(); + pOther->set_active(1 - pOther->get_active()); + + OJoinTableView::OTableWindowMap::const_iterator aIter = m_pTableMap->begin(); + OTableWindow* pFirst = aIter->second; + ++aIter; + OTableWindow* pSecond = aIter->second; + + if (m_xLeftTable->get_active_text() == pFirst->GetName()) + { + pLeft = pFirst; + pRight = pSecond; + } + else + { + pLeft = pSecond; + pRight = pFirst; + } + } + else + { + // First we need the TableDef to the Table and with it the TabWin + OJoinTableView::OTableWindowMap::const_iterator aFind = m_pTableMap->find(strSelected); + OTableWindow* pLoop = nullptr; + if( aFind != m_pTableMap->end() ) + pLoop = aFind->second; + OSL_ENSURE(pLoop != nullptr, "ORelationDialog::OnTableChanged: invalid ListBox entry!"); + // We need to find strSelect, because we filled the ListBoxes with the table names with which we compare now + if (&rListBox == m_xLeftTable.get()) + { + // Insert the previously selected Entry on the left side on the right side + m_xRightTable->append_text(m_strCurrentLeft); + // Remove the currently selected Entry + m_xRightTable->remove_text(strSelected); + m_strCurrentLeft = strSelected; + + pLeft = pLoop; + + OJoinTableView::OTableWindowMap::const_iterator aIter = m_pTableMap->find(m_xRightTable->get_active_text()); + OSL_ENSURE( aIter != m_pTableMap->end(), "Invalid name"); + if ( aIter != m_pTableMap->end() ) + pRight = aIter->second; + + m_xLeftTable->grab_focus(); + } + else + { + // Insert the previously selected Entry on the right side on the left side + m_xLeftTable->append_text(m_strCurrentRight); + // Remove the currently selected Entry + m_xLeftTable->remove_text(strSelected); + m_strCurrentRight = strSelected; + + pRight = pLoop; + OJoinTableView::OTableWindowMap::const_iterator aIter = m_pTableMap->find(m_xLeftTable->get_active_text()); + OSL_ENSURE( aIter != m_pTableMap->end(), "Invalid name"); + if ( aIter != m_pTableMap->end() ) + pLeft = aIter->second; + } + } + + rListBox.grab_focus(); + + m_xRC_Tables->setWindowTables(pLeft,pRight); + + NotifyCellChange(); + } + + void OTableListBoxControl::NotifyCellChange() + { + // Enable/disable the OK button, depending on having a valid situation + TTableConnectionData::value_type pConnData = m_xRC_Tables->getData(); + const OConnectionLineDataVec& rLines = pConnData->GetConnLineDataList(); + bool bValid = !rLines.empty(); + if (bValid) + { + for (auto const& line : rLines) + { + bValid = ! (line->GetSourceFieldName().isEmpty() || line->GetDestFieldName().isEmpty()); + if (!bValid) + break; + } + } + m_pParentDialog->setValid(bValid); + + m_xRC_Tables->DeactivateCell(); + for (auto const& elem : m_xRC_Tables->m_ops) + { + switch(elem.first) + { + case ORelationControl::DELETE: + m_xRC_Tables->RowRemoved(elem.second.first, elem.second.second - elem.second.first); + break; + case ORelationControl::INSERT: + m_xRC_Tables->RowInserted(elem.second.first, elem.second.second - elem.second.first); + break; + case ORelationControl::MODIFY: + for(OConnectionLineDataVec::size_type j = elem.second.first; j < elem.second.second; ++j) + m_xRC_Tables->RowModified(j); + break; + } + } + m_xRC_Tables->ActivateCell(); + m_xRC_Tables->m_ops.clear(); + } + + static void fillEntryAndDisable(weld::ComboBox& _rListBox,const OUString& _sEntry) + { + _rListBox.append_text(_sEntry); + _rListBox.set_active(0); + _rListBox.set_sensitive(false); + } + + void OTableListBoxControl::fillAndDisable(const TTableConnectionData::value_type& _pConnectionData) + { + fillEntryAndDisable(*m_xLeftTable, _pConnectionData->getReferencingTable()->GetWinName()); + fillEntryAndDisable(*m_xRightTable, _pConnectionData->getReferencedTable()->GetWinName()); + } + + void OTableListBoxControl::Init(const TTableConnectionData::value_type& _pConnData) + { + m_xRC_Tables->Init(_pConnData); + } + + void OTableListBoxControl::lateUIInit() + { + m_xRC_Tables->Show(); + lateInit(); + } + + void OTableListBoxControl::lateInit() + { + m_xRC_Tables->lateInit(); + } + + void OTableListBoxControl::Disable() + { + m_xLeftTable->set_sensitive(false); + m_xRightTable->set_sensitive(false); + m_xRC_Tables->Disable(); + } + + void OTableListBoxControl::Invalidate() + { + m_xRC_Tables->Invalidate(); + } + + void OTableListBoxControl::SaveModified() + { + m_xRC_Tables->SaveModified(); + } + + TTableWindowData::value_type const & OTableListBoxControl::getReferencingTable() const + { + return m_xRC_Tables->getData()->getReferencingTable(); + } + + void OTableListBoxControl::enableRelation(bool _bEnable) + { + if ( !_bEnable ) + m_xRC_Tables->PostUserEvent(LINK(m_xRC_Tables, ORelationControl, AsynchDeactivate)); + m_xRC_Tables->Enable(_bEnable); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/SqlNameEdit.cxx b/dbaccess/source/ui/control/SqlNameEdit.cxx new file mode 100644 index 000000000..9d968a0fd --- /dev/null +++ b/dbaccess/source/ui/control/SqlNameEdit.cxx @@ -0,0 +1,85 @@ +/* -*- 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 <SqlNameEdit.hxx> + +namespace dbaui +{ + static bool isCharOk(sal_Unicode _cChar,bool _bFirstChar, std::u16string_view _sAllowedChars) + { + return ( + (_cChar >= 'A' && _cChar <= 'Z') || + _cChar == '_' || + _sAllowedChars.find(_cChar) != std::u16string_view::npos || + (!_bFirstChar && (_cChar >= '0' && _cChar <= '9')) || + (_cChar >= 'a' && _cChar <= 'z') + ); + } + bool OSQLNameChecker::checkString(const OUString& _sToCheck, + OUString& _rsCorrected) + { + bool bCorrected = false; + if ( m_bCheck ) + { + sal_Int32 nMatch = 0; + for (sal_Int32 i = nMatch; i < _sToCheck.getLength(); ++i) + { + if ( !isCharOk( _sToCheck[i], i == 0, m_sAllowedChars ) ) + { + _rsCorrected += _sToCheck.subView(nMatch, i - nMatch); + bCorrected = true; + nMatch = i + 1; + } + } + _rsCorrected += _sToCheck.subView( nMatch ); + } + return bCorrected; + } + + namespace + { + void checkName(OSQLNameChecker& rChecker, weld::Entry& rEntry) + { + OUString sCorrected; + if (rChecker.checkString(rEntry.get_text(), sCorrected)) + { + int nStartPos, nEndPos; + rEntry.get_selection_bounds(nStartPos, nEndPos); + int nMin = std::min(nStartPos, nEndPos); + rEntry.set_text(sCorrected); + rEntry.select_region(nMin, nMin); + + rEntry.save_value(); + } + } + } + + IMPL_LINK(OSQLNameEditControl, ModifyHdl, weld::Entry&, rEntry, void) + { + checkName(*this, rEntry); + m_ChainChangedHdl.Call(rEntry); + } + + IMPL_LINK(OSQLNameEntry, ModifyHdl, weld::Entry&, rEntry, void) + { + checkName(*this, rEntry); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/TableGrantCtrl.cxx b/dbaccess/source/ui/control/TableGrantCtrl.cxx new file mode 100644 index 000000000..f4826e96d --- /dev/null +++ b/dbaccess/source/ui/control/TableGrantCtrl.cxx @@ -0,0 +1,476 @@ +/* -*- 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 <TableGrantCtrl.hxx> +#include <core_resource.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/sdbcx/PrivilegeObject.hpp> +#include <com/sun/star/sdbcx/XUsersSupplier.hpp> +#include <com/sun/star/sdbcx/XAuthorizable.hpp> +#include <connectivity/dbtools.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/svapp.hxx> +#include <osl/diagnose.h> +#include <strings.hrc> + +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; +using namespace ::dbaui; +using namespace ::svt; + +const sal_uInt16 COL_TABLE_NAME = 1; +const sal_uInt16 COL_SELECT = 2; +const sal_uInt16 COL_INSERT = 3; +const sal_uInt16 COL_DELETE = 4; +const sal_uInt16 COL_UPDATE = 5; +const sal_uInt16 COL_ALTER = 6; +const sal_uInt16 COL_REF = 7; +const sal_uInt16 COL_DROP = 8; + + +// OTableGrantControl +OTableGrantControl::OTableGrantControl(const css::uno::Reference<css::awt::XWindow> &rParent) + :EditBrowseBox(VCLUnoHelper::GetWindow(rParent), EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT, WB_TABSTOP) + ,m_pCheckCell( nullptr ) + ,m_pEdit( nullptr ) + ,m_nDataPos( 0 ) + ,m_nDeactivateEvent(nullptr) +{ + // insert columns + sal_uInt16 i=1; + InsertDataColumn( i, DBA_RES(STR_TABLE_PRIV_NAME), 75); + FreezeColumn(i++); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_SELECT), 75); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_INSERT), 75); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_DELETE), 75); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_UPDATE), 75); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_ALTER), 75); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_REFERENCE), 75); + InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_DROP), 75); + + while(--i) + SetColumnWidth(i,GetAutoColumnWidth(i)); +} + +OTableGrantControl::~OTableGrantControl() +{ + disposeOnce(); +} + +void OTableGrantControl::dispose() +{ + if (m_nDeactivateEvent) + { + Application::RemoveUserEvent(m_nDeactivateEvent); + m_nDeactivateEvent = nullptr; + } + + m_pCheckCell.disposeAndClear(); + m_pEdit.disposeAndClear(); + + m_xTables = nullptr; + ::svt::EditBrowseBox::dispose(); +} + +void OTableGrantControl::setTablesSupplier(const Reference< XTablesSupplier >& _xTablesSup) +{ + // first we need the users + Reference< XUsersSupplier> xUserSup(_xTablesSup,UNO_QUERY); + if(xUserSup.is()) + m_xUsers = xUserSup->getUsers(); + + // second we need the tables to determine which privileges the user has + if(_xTablesSup.is()) + m_xTables = _xTablesSup->getTables(); + + if(m_xTables.is()) + m_aTableNames = m_xTables->getElementNames(); + + OSL_ENSURE(m_xUsers.is(),"No user access supported!"); + OSL_ENSURE(m_xTables.is(),"No tables supported!"); +} + +void OTableGrantControl::setComponentContext(const Reference< css::uno::XComponentContext>& _rxContext) +{ + m_xContext = _rxContext; +} + +void OTableGrantControl::UpdateTables() +{ + RemoveRows(); + + if(m_xTables.is()) + RowInserted(0, m_aTableNames.getLength()); + // m_bEnable = m_xDb->GetUser() != ((OUserAdmin*)GetParent())->GetUser(); +} + +void OTableGrantControl::Init() +{ + EditBrowseBox::Init(); + + // instantiate ComboBox + if(!m_pCheckCell) + { + m_pCheckCell = VclPtr<CheckBoxControl>::Create( &GetDataWindow() ); + m_pCheckCell->EnableTriState(false); + + m_pEdit = VclPtr<EditControl>::Create(&GetDataWindow()); + weld::Entry& rEntry = m_pEdit->get_widget(); + rEntry.set_editable(false); + rEntry.set_sensitive(false); + } + + UpdateTables(); + // set browser mode + BrowserMode const nMode = BrowserMode::COLUMNSELECTION | BrowserMode::HLINES | BrowserMode::VLINES | + BrowserMode::HIDECURSOR | BrowserMode::HIDESELECT; + + SetMode(nMode); +} + +bool OTableGrantControl::PreNotify(NotifyEvent& rNEvt) +{ + if (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS) + if (!HasChildPathFocus()) + { + if (m_nDeactivateEvent) + Application::RemoveUserEvent(m_nDeactivateEvent); + m_nDeactivateEvent = Application::PostUserEvent(LINK(this, OTableGrantControl, AsynchDeactivate), nullptr, true); + } + if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + { + if (m_nDeactivateEvent) + Application::RemoveUserEvent(m_nDeactivateEvent); + m_nDeactivateEvent = Application::PostUserEvent(LINK(this, OTableGrantControl, AsynchActivate), nullptr, true); + } + return EditBrowseBox::PreNotify(rNEvt); +} + +IMPL_LINK_NOARG(OTableGrantControl, AsynchActivate, void*, void) +{ + m_nDeactivateEvent = nullptr; + ActivateCell(); +} + +IMPL_LINK_NOARG(OTableGrantControl, AsynchDeactivate, void*, void) +{ + m_nDeactivateEvent = nullptr; + DeactivateCell(); +} + +bool OTableGrantControl::IsTabAllowed(bool bForward) const +{ + sal_Int32 nRow = GetCurRow(); + sal_uInt16 nCol = GetCurColumnId(); + + if (bForward && (nCol == 2) && (nRow == GetRowCount() - 1)) + return false; + + if (!bForward && (nCol == 1) && (nRow == 0)) + return false; + + return EditBrowseBox::IsTabAllowed(bForward); +} + +bool OTableGrantControl::SaveModified() +{ + + sal_Int32 nRow = GetCurRow(); + if(nRow == -1 || nRow >= m_aTableNames.getLength()) + return false; + + OUString sTableName = m_aTableNames[nRow]; + bool bErg = true; + try + { + + if ( m_xUsers->hasByName(m_sUserName) ) + { + Reference<XAuthorizable> xAuth(m_xUsers->getByName(m_sUserName),UNO_QUERY); + if ( xAuth.is() ) + { + switch( GetCurColumnId() ) + { + case COL_INSERT: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::INSERT); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::INSERT); + break; + case COL_DELETE: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::DELETE); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::DELETE); + break; + case COL_UPDATE: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::UPDATE); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::UPDATE); + break; + case COL_ALTER: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::ALTER); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::ALTER); + break; + case COL_SELECT: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::SELECT); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::SELECT); + break; + case COL_REF: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::REFERENCE); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::REFERENCE); + break; + case COL_DROP: + if (m_pCheckCell->GetBox().get_active()) + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::DROP); + else + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::DROP); + break; + } + fillPrivilege(nRow); + } + } + } + catch(SQLException& e) + { + bErg = false; + ::dbtools::showError(::dbtools::SQLExceptionInfo(e),VCLUnoHelper::GetInterface(GetParent()),m_xContext); + } + if(bErg && Controller().is()) + Controller()->SaveValue(); + if(!bErg) + UpdateTables(); + + return bErg; +} + +OUString OTableGrantControl::GetCellText( sal_Int32 nRow, sal_uInt16 nColId ) const +{ + if(COL_TABLE_NAME == nColId) + return m_aTableNames[nRow]; + + sal_Int32 nPriv = 0; + TTablePrivilegeMap::const_iterator aFind = findPrivilege(nRow); + if(aFind != m_aPrivMap.end()) + nPriv = aFind->second.nRights; + + return OUString::number(isAllowed(nColId,nPriv) ? 1 :0); +} + +void OTableGrantControl::InitController( CellControllerRef& /*rController*/, sal_Int32 nRow, sal_uInt16 nColumnId ) +{ + OUString sTablename = m_aTableNames[nRow]; + // special case for tablename + if (nColumnId == COL_TABLE_NAME) + m_pEdit->get_widget().set_text(sTablename); + else + { + // get the privileges from the user + TTablePrivilegeMap::const_iterator aFind = findPrivilege(nRow); + m_pCheckCell->GetBox().set_active(aFind != m_aPrivMap.end() && isAllowed(nColumnId,aFind->second.nRights)); + } +} + +void OTableGrantControl::fillPrivilege(sal_Int32 _nRow) const +{ + + if ( !m_xUsers->hasByName(m_sUserName) ) + return; + + try + { + Reference<XAuthorizable> xAuth(m_xUsers->getByName(m_sUserName),UNO_QUERY); + if ( xAuth.is() ) + { + // get the privileges + TPrivileges nRights; + nRights.nRights = xAuth->getPrivileges(m_aTableNames[_nRow],PrivilegeObject::TABLE); + if(m_xGrantUser.is()) + nRights.nWithGrant = m_xGrantUser->getGrantablePrivileges(m_aTableNames[_nRow],PrivilegeObject::TABLE); + else + nRights.nWithGrant = 0; + + m_aPrivMap[m_aTableNames[_nRow]] = nRights; + } + } + catch(SQLException& e) + { + ::dbtools::showError(::dbtools::SQLExceptionInfo(e),VCLUnoHelper::GetInterface(GetParent()),m_xContext); + } + catch(Exception& ) + { + } +} + +bool OTableGrantControl::isAllowed(sal_uInt16 _nColumnId,sal_Int32 _nPrivilege) +{ + bool bAllowed = false; + switch (_nColumnId) + { + case COL_INSERT: + bAllowed = (Privilege::INSERT & _nPrivilege) == Privilege::INSERT; + break; + case COL_DELETE: + bAllowed = (Privilege::DELETE & _nPrivilege) == Privilege::DELETE; + break; + case COL_UPDATE: + bAllowed = (Privilege::UPDATE & _nPrivilege) == Privilege::UPDATE; + break; + case COL_ALTER: + bAllowed = (Privilege::ALTER & _nPrivilege) == Privilege::ALTER; + break; + case COL_SELECT: + bAllowed = (Privilege::SELECT & _nPrivilege) == Privilege::SELECT; + break; + case COL_REF: + bAllowed = (Privilege::REFERENCE & _nPrivilege) == Privilege::REFERENCE; + break; + case COL_DROP: + bAllowed = (Privilege::DROP & _nPrivilege) == Privilege::DROP; + break; + } + return bAllowed; +} + +void OTableGrantControl::setUserName(const OUString& _sUserName) +{ + m_sUserName = _sUserName; + m_aPrivMap = TTablePrivilegeMap(); +} + +void OTableGrantControl::setGrantUser(const Reference< XAuthorizable>& _xGrantUser) +{ + OSL_ENSURE(_xGrantUser.is(),"OTableGrantControl::setGrantUser: GrantUser is null!"); + m_xGrantUser = _xGrantUser; +} + +CellController* OTableGrantControl::GetController( sal_Int32 nRow, sal_uInt16 nColumnId ) +{ + + CellController* pController = nullptr; + switch( nColumnId ) + { + case COL_TABLE_NAME: + break; + case COL_INSERT: + case COL_DELETE: + case COL_UPDATE: + case COL_ALTER: + case COL_SELECT: + case COL_REF: + case COL_DROP: + { + TTablePrivilegeMap::const_iterator aFind = findPrivilege(nRow); + if(aFind != m_aPrivMap.end() && isAllowed(nColumnId,aFind->second.nWithGrant)) + pController = new CheckBoxCellController( m_pCheckCell ); + } + break; + default: + ; + } + return pController; +} + +bool OTableGrantControl::SeekRow( sal_Int32 nRow ) +{ + m_nDataPos = nRow; + + return (nRow <= m_aTableNames.getLength()); +} + +void OTableGrantControl::PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const +{ + + if(nColumnId != COL_TABLE_NAME) + { + TTablePrivilegeMap::const_iterator aFind = findPrivilege(m_nDataPos); + if(aFind != m_aPrivMap.end()) + PaintTristate(rRect, isAllowed(nColumnId,aFind->second.nRights) ? TRISTATE_TRUE : TRISTATE_FALSE,isAllowed(nColumnId,aFind->second.nWithGrant)); + else + PaintTristate(rRect, TRISTATE_FALSE, false); + } + else + { + OUString aText(GetCellText( m_nDataPos, nColumnId )); + Point aPos( rRect.TopLeft() ); + sal_Int32 nWidth = GetDataWindow().GetTextWidth( aText ); + sal_Int32 nHeight = GetDataWindow().GetTextHeight(); + + if( aPos.X() < rRect.Left() || aPos.X() + nWidth > rRect.Right() || + aPos.Y() < rRect.Top() || aPos.Y() + nHeight > rRect.Bottom() ) + { + rDev.SetClipRegion(vcl::Region(rRect)); + } + + rDev.DrawText( aPos, aText ); + } + + if( rDev.IsClipRegion() ) + rDev.SetClipRegion(); +} + +void OTableGrantControl::CellModified() +{ + EditBrowseBox::CellModified(); + SaveModified(); +} + +OTableGrantControl::TTablePrivilegeMap::const_iterator OTableGrantControl::findPrivilege(sal_Int32 _nRow) const +{ + TTablePrivilegeMap::const_iterator aFind = m_aPrivMap.find(m_aTableNames[_nRow]); + if(aFind == m_aPrivMap.end()) + { + fillPrivilege(_nRow); + aFind = m_aPrivMap.find(m_aTableNames[_nRow]); + } + return aFind; +} + +Reference< XAccessible > OTableGrantControl::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos ) +{ + sal_uInt16 nColumnId = GetColumnId( _nColumnPos ); + if(nColumnId != COL_TABLE_NAME) + { + TriState eState = TRISTATE_FALSE; + TTablePrivilegeMap::const_iterator aFind = findPrivilege(_nRow); + if(aFind != m_aPrivMap.end()) + { + eState = isAllowed(nColumnId,aFind->second.nRights) ? TRISTATE_TRUE : TRISTATE_FALSE; + } + else + eState = TRISTATE_FALSE; + + return EditBrowseBox::CreateAccessibleCheckBoxCell( _nRow, _nColumnPos,eState ); + } + return EditBrowseBox::CreateAccessibleCell( _nRow, _nColumnPos ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/charsetlistbox.cxx b/dbaccess/source/ui/control/charsetlistbox.cxx new file mode 100644 index 000000000..8915b65c9 --- /dev/null +++ b/dbaccess/source/ui/control/charsetlistbox.cxx @@ -0,0 +1,69 @@ +/* -*- 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 <charsetlistbox.hxx> + +#include <svl/itemset.hxx> +#include <svl/stritem.hxx> +#include <osl/diagnose.h> + +namespace dbaui +{ + CharSetListBox::CharSetListBox(std::unique_ptr<weld::ComboBox> xControl) + : m_xControl(std::move(xControl)) + { + for (auto const& charset : m_aCharSets) + { + m_xControl->append_text(charset.getDisplayName()); + } + } + + void CharSetListBox::SelectEntryByIanaName( const OUString& _rIanaName ) + { + OCharsetDisplay::const_iterator aFind = m_aCharSets.findIanaName( _rIanaName ); + if (aFind == m_aCharSets.end()) + { + OSL_FAIL( "CharSetListBox::SelectEntryByIanaName: unknown charset falling back to system language!" ); + aFind = m_aCharSets.findEncoding( RTL_TEXTENCODING_DONTKNOW ); + } + + if (aFind == m_aCharSets.end()) + m_xControl->set_active(-1); + else + m_xControl->set_active_text((*aFind).getDisplayName()); + } + + bool CharSetListBox::StoreSelectedCharSet( SfxItemSet& _rSet, const sal_uInt16 _nItemId ) + { + bool bChangedSomething = false; + if (m_xControl->get_value_changed_from_saved()) + { + OCharsetDisplay::const_iterator aFind = m_aCharSets.findDisplayName(m_xControl->get_active_text()); + OSL_ENSURE( aFind != m_aCharSets.end(), "CharSetListBox::StoreSelectedCharSet: could not translate the selected character set!" ); + if ( aFind != m_aCharSets.end() ) + { + _rSet.Put( SfxStringItem( _nItemId, (*aFind).getIanaName() ) ); + bChangedSomething = true; + } + } + return bChangedSomething; + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/curledit.cxx b/dbaccess/source/ui/control/curledit.cxx new file mode 100644 index 000000000..9cccde370 --- /dev/null +++ b/dbaccess/source/ui/control/curledit.cxx @@ -0,0 +1,89 @@ +/* -*- 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 <curledit.hxx> + +namespace dbaui +{ + +OConnectionURLEdit::OConnectionURLEdit(std::unique_ptr<weld::Entry> xEntry, std::unique_ptr<weld::Label> xForcedPrefix) + : m_pTypeCollection(nullptr) + , m_bShowPrefix(false) + , m_xEntry(std::move(xEntry)) + , m_xForcedPrefix(std::move(xForcedPrefix)) +{ +} + +OConnectionURLEdit::~OConnectionURLEdit() +{ +} + +void OConnectionURLEdit::SetTextNoPrefix(const OUString& _rText) +{ + m_xEntry->set_text(_rText); +} + +OUString OConnectionURLEdit::GetTextNoPrefix() const +{ + return m_xEntry->get_text(); +} + +void OConnectionURLEdit::SetText(const OUString& _rStr) +{ + Selection aNoSelection(0,0); + SetText(_rStr, aNoSelection); +} + +void OConnectionURLEdit::SetText(const OUString& _rStr, const Selection& /*_rNewSelection*/) +{ + m_xForcedPrefix->set_visible(m_bShowPrefix); + + bool bIsEmpty = _rStr.isEmpty(); + // calc the prefix + OUString sPrefix; + if (!bIsEmpty) + { + // determine the type of the new URL described by the new text + sPrefix = m_pTypeCollection->getPrefix(_rStr); + } + + // the fixed text gets the prefix + m_xForcedPrefix->set_label(sPrefix); + + // do the real SetText + OUString sNewText( _rStr ); + if ( !bIsEmpty ) + sNewText = m_pTypeCollection->cutPrefix( _rStr ); + m_xEntry->set_text(sNewText); +} + +OUString OConnectionURLEdit::GetText() const +{ + return m_xForcedPrefix->strip_mnemonic(m_xForcedPrefix->get_label()) + m_xEntry->get_text(); +} + +void OConnectionURLEdit::ShowPrefix(bool _bShowPrefix) +{ + m_bShowPrefix = _bShowPrefix; + m_xForcedPrefix->set_visible(m_bShowPrefix); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/dbtreelistbox.cxx b/dbaccess/source/ui/control/dbtreelistbox.cxx new file mode 100644 index 000000000..eb89e1fdb --- /dev/null +++ b/dbaccess/source/ui/control/dbtreelistbox.cxx @@ -0,0 +1,512 @@ +/* -*- 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 <dbtreelistbox.hxx> +#include <dbexchange.hxx> +#include <callbacks.hxx> + +#include <com/sun/star/awt/PopupMenuDirection.hpp> +#include <com/sun/star/ui/XContextMenuInterceptor.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/frame/XPopupMenuController.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <cppuhelper/implbase.hxx> +#include <comphelper/interfacecontainer2.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> +#include <dbaccess/IController.hxx> +#include <framework/actiontriggerhelper.hxx> +#include <toolkit/awt/vclxmenu.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <svx/dbaobjectex.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> + +#include <memory> + +namespace dbaui +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::ui; +using namespace ::com::sun::star::view; + +InterimDBTreeListBox::InterimDBTreeListBox(vcl::Window* pParent) + : InterimItemWindow(pParent, "dbaccess/ui/dbtreelist.ui", "DBTreeList") + , TreeListBox(m_xBuilder->weld_tree_view("treeview"), true) + , m_xStatusBar(m_xBuilder->weld_label("statusbar")) +{ + InitControlBase(&GetWidget()); +} + +InterimDBTreeListBox::~InterimDBTreeListBox() +{ + disposeOnce(); +} + +void InterimDBTreeListBox::dispose() +{ + implStopSelectionTimer(); + m_xStatusBar.reset(); + m_xTreeView.reset(); + InterimItemWindow::dispose(); +} + +bool InterimDBTreeListBox::DoChildKeyInput(const KeyEvent& rKEvt) +{ + return ChildKeyInput(rKEvt); +} + +TreeListBoxDropTarget::TreeListBoxDropTarget(TreeListBox& rTreeView) + : DropTargetHelper(rTreeView.GetWidget().get_drop_target()) + , m_rTreeView(rTreeView) +{ +} + +sal_Int8 TreeListBoxDropTarget::AcceptDrop(const AcceptDropEvent& rEvt) +{ + sal_Int8 nAccept = m_rTreeView.AcceptDrop(rEvt); + + if (nAccept != DND_ACTION_NONE) + { + // to enable the autoscroll when we're close to the edges + weld::TreeView& rWidget = m_rTreeView.GetWidget(); + rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true); + } + + return nAccept; +} + +sal_Int8 TreeListBoxDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt) +{ + return m_rTreeView.ExecuteDrop(rEvt); +} + +TreeListBox::TreeListBox(std::unique_ptr<weld::TreeView> xTreeView, bool bSQLType) + : m_xTreeView(std::move(xTreeView)) + , m_aDropTargetHelper(*this) + , m_pActionListener(nullptr) + , m_pContextMenuProvider(nullptr) + , m_aTimer("dbaccess TreeListBox m_aTimer") +{ + m_xTreeView->connect_key_press(LINK(this, TreeListBox, KeyInputHdl)); + m_xTreeView->connect_changed(LINK(this, TreeListBox, SelectHdl)); + m_xTreeView->connect_query_tooltip(LINK(this, TreeListBox, QueryTooltipHdl)); + m_xTreeView->connect_popup_menu(LINK(this, TreeListBox, CommandHdl)); + + if (bSQLType) + m_xHelper.set(new ODataClipboard); + else + m_xHelper.set(new svx::OComponentTransferable); + m_xTreeView->enable_drag_source(m_xHelper, DND_ACTION_COPY); + m_xTreeView->connect_drag_begin(LINK(this, TreeListBox, DragBeginHdl)); + + m_aTimer.SetTimeout(900); + m_aTimer.SetInvokeHandler(LINK(this, TreeListBox, OnTimeOut)); +} + +bool TreeListBox::DoChildKeyInput(const KeyEvent& /*rKEvt*/) +{ + // nothing by default + return false; +} + +IMPL_LINK(TreeListBox, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction(); + bool bHandled = false; + + switch (eFunc) + { + case KeyFuncType::COPY: + bHandled = m_aCopyHandler.IsSet() && !m_xTreeView->get_selected(nullptr); + if (bHandled) + m_aCopyHandler.Call(nullptr); + break; + case KeyFuncType::PASTE: + bHandled = m_aPasteHandler.IsSet() && !m_xTreeView->get_selected(nullptr); + if (bHandled) + m_aPasteHandler.Call(nullptr); + break; + case KeyFuncType::DELETE: + bHandled = m_aDeleteHandler.IsSet() && !m_xTreeView->get_selected(nullptr); + if (bHandled) + m_aDeleteHandler.Call(nullptr); + break; + default: + break; + } + + return bHandled || DoChildKeyInput(rKEvt); +} + +void TreeListBox::implStopSelectionTimer() +{ + if ( m_aTimer.IsActive() ) + m_aTimer.Stop(); +} + +void TreeListBox::implStartSelectionTimer() +{ + implStopSelectionTimer(); + m_aTimer.Start(); +} + +IMPL_LINK_NOARG(TreeListBox, SelectHdl, weld::TreeView&, void) +{ + implStartSelectionTimer(); +} + +TreeListBox::~TreeListBox() +{ +} + +std::unique_ptr<weld::TreeIter> TreeListBox::GetEntryPosByName(std::u16string_view aName, const weld::TreeIter* pStart, const IEntryFilter* _pFilter) const +{ + auto xEntry(m_xTreeView->make_iterator(pStart)); + if (pStart) + { + if (!m_xTreeView->iter_children(*xEntry)) + return nullptr; + } + else + { + if (!m_xTreeView->get_iter_first(*xEntry)) + return nullptr; + } + + do + { + if (m_xTreeView->get_text(*xEntry) == aName) + { + if (!_pFilter || _pFilter->includeEntry(weld::fromId<void*>(m_xTreeView->get_id(*xEntry)))) + { + // found + return xEntry; + } + } + } while (m_xTreeView->iter_next_sibling(*xEntry)); + + return nullptr; +} + +IMPL_LINK(TreeListBox, DragBeginHdl, bool&, rUnsetDragIcon, bool) +{ + rUnsetDragIcon = false; + + if (m_pActionListener) + { + m_xDragedEntry = m_xTreeView->make_iterator(); + if (!m_xTreeView->get_selected(m_xDragedEntry.get())) + m_xDragedEntry.reset(); + if (m_xDragedEntry && m_pActionListener->requestDrag(*m_xDragedEntry)) + { + // if the (asynchronous) drag started, stop the selection timer + implStopSelectionTimer(); + return false; + } + } + + return true; +} + +sal_Int8 TreeListBox::AcceptDrop(const AcceptDropEvent& rEvt) +{ + sal_Int8 nDropOption = DND_ACTION_NONE; + if ( m_pActionListener ) + { + ::Point aDropPos = rEvt.maPosPixel; + std::unique_ptr<weld::TreeIter> xDropTarget(m_xTreeView->make_iterator()); + if (!m_xTreeView->get_dest_row_at_pos(aDropPos, xDropTarget.get(), true)) + xDropTarget.reset(); + + // check if drag is on child entry, which is not allowed + std::unique_ptr<weld::TreeIter> xParent; + if (rEvt.mnAction & DND_ACTION_MOVE) + { + if (!m_xDragedEntry) // no entry to move + return m_pActionListener->queryDrop(rEvt, m_aDropTargetHelper.GetDataFlavorExVector()); + + if (xDropTarget) + { + xParent = m_xTreeView->make_iterator(xDropTarget.get()); + if (!m_xTreeView->iter_parent(*xParent)) + xParent.reset(); + } + while (xParent && m_xTreeView->iter_compare(*xParent, *m_xDragedEntry) != 0) + { + if (!m_xTreeView->iter_parent(*xParent)) + xParent.reset(); + } + } + + if (!xParent) + { + nDropOption = m_pActionListener->queryDrop(rEvt, m_aDropTargetHelper.GetDataFlavorExVector()); + // check if move is allowed + if ( nDropOption & DND_ACTION_MOVE ) + { + if (!m_xDragedEntry || !xDropTarget || + m_xTreeView->iter_compare(*m_xDragedEntry, *xDropTarget) == 0 || + GetEntryPosByName(m_xTreeView->get_text(*m_xDragedEntry), xDropTarget.get())) + { + nDropOption = nDropOption & ~DND_ACTION_MOVE;//DND_ACTION_NONE; + } + } + } + } + + return nDropOption; +} + +sal_Int8 TreeListBox::ExecuteDrop(const ExecuteDropEvent& rEvt) +{ + if (m_pActionListener) + m_pActionListener->executeDrop(rEvt); + m_xTreeView->unset_drag_dest_row(); + return DND_ACTION_NONE; +} + +IMPL_LINK(TreeListBox, QueryTooltipHdl, const weld::TreeIter&, rIter, OUString) +{ + OUString sQuickHelpText; + if (m_pActionListener && + m_pActionListener->requestQuickHelp(weld::fromId<void*>(m_xTreeView->get_id(rIter)), sQuickHelpText)) + { + return sQuickHelpText; + } + return m_xTreeView->get_tooltip_text(); +} + +namespace +{ + // SelectionSupplier + typedef ::cppu::WeakImplHelper< XSelectionSupplier + > SelectionSupplier_Base; + class SelectionSupplier : public SelectionSupplier_Base + { + public: + explicit SelectionSupplier( const Any& _rSelection ) + :m_aSelection( _rSelection ) + { + } + + virtual sal_Bool SAL_CALL select( const Any& xSelection ) override; + virtual Any SAL_CALL getSelection( ) override; + virtual void SAL_CALL addSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) override; + virtual void SAL_CALL removeSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) override; + + protected: + virtual ~SelectionSupplier() override + { + } + + private: + Any m_aSelection; + }; + + sal_Bool SAL_CALL SelectionSupplier::select( const Any& /*_Selection*/ ) + { + throw IllegalArgumentException(); + // API bug: this should be a NoSupportException + } + + Any SAL_CALL SelectionSupplier::getSelection( ) + { + return m_aSelection; + } + + void SAL_CALL SelectionSupplier::addSelectionChangeListener( const Reference< XSelectionChangeListener >& /*_Listener*/ ) + { + OSL_FAIL( "SelectionSupplier::removeSelectionChangeListener: no support!" ); + // API bug: this should be a NoSupportException + } + + void SAL_CALL SelectionSupplier::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& /*_Listener*/ ) + { + OSL_FAIL( "SelectionSupplier::removeSelectionChangeListener: no support!" ); + // API bug: this should be a NoSupportException + } +} + +IMPL_LINK(TreeListBox, CommandHdl, const CommandEvent&, rCEvt, bool) +{ + if (rCEvt.GetCommand() != CommandEventId::ContextMenu) + return false; + + ::Point aPos = rCEvt.GetMousePosPixel(); + + std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator()); + if (m_xTreeView->get_dest_row_at_pos(aPos, xIter.get(), false) && !m_xTreeView->is_selected(*xIter)) + { + m_xTreeView->unselect_all(); + m_xTreeView->set_cursor(*xIter); + m_xTreeView->select(*xIter); + SelectHdl(*m_xTreeView); + } + + if (!m_pContextMenuProvider) + return false; + + OUString aResourceName(m_pContextMenuProvider->getContextMenuResourceName()); + if (aResourceName.isEmpty()) + return false; + + css::uno::Sequence< css::uno::Any > aArgs{ + css::uno::Any(comphelper::makePropertyValue( "Value", aResourceName )), + css::uno::Any(comphelper::makePropertyValue( "Frame", m_pContextMenuProvider->getCommandController().getXController()->getFrame() )), + css::uno::Any(comphelper::makePropertyValue( "IsContextMenu", true )) + }; + + css::uno::Reference< css::uno::XComponentContext > xContext = comphelper::getProcessComponentContext(); + css::uno::Reference<css::frame::XPopupMenuController> xMenuController + (xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.framework.ResourceMenuController", aArgs, xContext), css::uno::UNO_QUERY); + + if (!xMenuController.is()) + return false; + + VclPtr<vcl::Window> xMenuParent = m_pContextMenuProvider->getMenuParent(); + + css::uno::Reference< css::awt::XWindow> xSourceWindow = VCLUnoHelper::GetInterface(xMenuParent); + + rtl::Reference xPopupMenu( new VCLXPopupMenu ); + xMenuController->setPopupMenu( xPopupMenu ); + + // allow context menu interception + ::comphelper::OInterfaceContainerHelper2* pInterceptors = m_pContextMenuProvider->getContextMenuInterceptors(); + if (pInterceptors && pInterceptors->getLength()) + { + OUString aMenuIdentifier( "private:resource/popupmenu/" + aResourceName ); + + ContextMenuExecuteEvent aEvent; + aEvent.SourceWindow = xSourceWindow; + aEvent.ExecutePosition.X = -1; + aEvent.ExecutePosition.Y = -1; + aEvent.ActionTriggerContainer = ::framework::ActionTriggerHelper::CreateActionTriggerContainerFromMenu( + xPopupMenu, &aMenuIdentifier ); + aEvent.Selection = new SelectionSupplier(m_pContextMenuProvider->getCurrentSelection(*m_xTreeView)); + + ::comphelper::OInterfaceIteratorHelper2 aIter( *pInterceptors ); + bool bModifiedMenu = false; + bool bAskInterceptors = true; + while ( aIter.hasMoreElements() && bAskInterceptors ) + { + Reference< XContextMenuInterceptor > xInterceptor( aIter.next(), UNO_QUERY ); + if ( !xInterceptor.is() ) + continue; + + try + { + ContextMenuInterceptorAction eAction = xInterceptor->notifyContextMenuExecute( aEvent ); + switch ( eAction ) + { + case ContextMenuInterceptorAction_CANCELLED: + return false; + + case ContextMenuInterceptorAction_EXECUTE_MODIFIED: + bModifiedMenu = true; + bAskInterceptors = false; + break; + + case ContextMenuInterceptorAction_CONTINUE_MODIFIED: + bModifiedMenu = true; + bAskInterceptors = true; + break; + + default: + OSL_FAIL( "DBTreeListBox::CreateContextMenu: unexpected return value of the interceptor call!" ); + [[fallthrough]]; + case ContextMenuInterceptorAction_IGNORED: + break; + } + } + catch( const DisposedException& e ) + { + if ( e.Context == xInterceptor ) + aIter.remove(); + } + } + + if ( bModifiedMenu ) + { + xPopupMenu->clear(); + ::framework::ActionTriggerHelper::CreateMenuFromActionTriggerContainer( + xPopupMenu, aEvent.ActionTriggerContainer ); + aEvent.ActionTriggerContainer.clear(); + } + } + + // adjust pos relative to m_xTreeView to relative to xMenuParent + m_pContextMenuProvider->adjustMenuPosition(*m_xTreeView, aPos); + + // do action for selected entry in popup menu + css::uno::Reference<css::awt::XWindowPeer> xParent(xSourceWindow, css::uno::UNO_QUERY); + xPopupMenu->execute(xParent, css::awt::Rectangle(aPos.X(), aPos.Y(), 1, 1), css::awt::PopupMenuDirection::EXECUTE_DOWN); + + css::uno::Reference<css::lang::XComponent> xComponent(xMenuController, css::uno::UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); + xMenuController.clear(); + + return true; +} + +IMPL_LINK_NOARG(TreeListBox, OnTimeOut, Timer*, void) +{ + implStopSelectionTimer(); + + m_aSelChangeHdl.Call( nullptr ); +} + +std::unique_ptr<weld::TreeIter> TreeListBox::GetRootLevelParent(const weld::TreeIter* pEntry) const +{ + if (!pEntry) + return nullptr; + std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pEntry)); + while (m_xTreeView->get_iter_depth(*xEntry)) + m_xTreeView->iter_parent(*xEntry); + return xEntry; +} + +DBTreeViewBase::DBTreeViewBase(weld::Container* pContainer) + : m_xBuilder(Application::CreateBuilder(pContainer, "dbaccess/ui/dbtreelist.ui")) + , m_xContainer(m_xBuilder->weld_container("DBTreeList")) +{ +} + +DBTreeViewBase::~DBTreeViewBase() +{ +} + +DBTreeView::DBTreeView(weld::Container* pContainer, bool bSQLType) + : DBTreeViewBase(pContainer) +{ + m_xTreeListBox.reset(new TreeListBox(m_xBuilder->weld_tree_view("treeview"), bSQLType)); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/opendoccontrols.cxx b/dbaccess/source/ui/control/opendoccontrols.cxx new file mode 100644 index 000000000..2fb86bdca --- /dev/null +++ b/dbaccess/source/ui/control/opendoccontrols.cxx @@ -0,0 +1,194 @@ +/* -*- 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 <opendoccontrols.hxx> + +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/ui/XUIConfigurationManager.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/ui/XImageManager.hpp> + +#include <comphelper/processfactory.hxx> +#include <vcl/commandinfoprovider.hxx> +#include <unotools/historyoptions.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <tools/urlobj.hxx> +#include <osl/diagnose.h> + +namespace dbaui +{ + + namespace + { + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::container::XNameAccess; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::ui::theModuleUIConfigurationManagerSupplier; + using ::com::sun::star::ui::XModuleUIConfigurationManagerSupplier; + using ::com::sun::star::ui::XUIConfigurationManager; + using ::com::sun::star::ui::XImageManager; + using ::com::sun::star::graphic::XGraphic; + + Reference< XGraphic> GetCommandIcon( const char* _pCommandURL, const OUString& _rModuleName ) + { + if ( !_pCommandURL || !*_pCommandURL ) + return nullptr; + + OUString sCommandURL = OUString::createFromAscii( _pCommandURL ); + try + { + do + { + // Retrieve popup menu labels + Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + if ( !xContext.is() ) + break; + + Reference< XModuleUIConfigurationManagerSupplier > xSupplier( + theModuleUIConfigurationManagerSupplier::get(xContext) ); + + Reference< XUIConfigurationManager > xManager( xSupplier->getUIConfigurationManager( _rModuleName ) ); + Reference< XImageManager > xImageManager; + if ( xManager.is() ) + xImageManager.set(xManager->getImageManager(), css::uno::UNO_QUERY); + if ( !xImageManager.is() ) + break; + + Sequence< OUString > aCommandList( &sCommandURL, 1 ); + Sequence<Reference< XGraphic> > xIconList( xImageManager->getImages( 0, aCommandList ) ); + if ( !xIconList.hasElements() ) + break; + + return xIconList[0]; + } + while ( false ); + } + catch ( Exception& ) {} + + return nullptr; + } + } + + // OpenButton + + OpenDocumentButton::OpenDocumentButton(std::unique_ptr<weld::Button> xControl, const char* _pAsciiModuleName) + : m_xControl(std::move(xControl)) + { + impl_init( _pAsciiModuleName ); + } + + void OpenDocumentButton::impl_init( const char* _pAsciiModuleName ) + { + OSL_ENSURE( _pAsciiModuleName, "OpenDocumentButton::impl_init: invalid module name!" ); + m_sModule = OUString::createFromAscii( _pAsciiModuleName ); + + // our label should equal the UI text of the "Open" command + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:Open", m_sModule); + OUString sLabel(vcl::CommandInfoProvider::GetLabelForCommand(aProperties)); + m_xControl->set_label(" " + sLabel.replaceAll("~", "")); + + // Place icon left of text and both centered in the button. + m_xControl->set_image(GetCommandIcon(".uno:Open", m_sModule)); + } + + // OpenDocumentListBox + + OpenDocumentListBox::OpenDocumentListBox(std::unique_ptr<weld::ComboBox> xControl, const char* _pAsciiModuleName ) + : m_xControl(std::move(xControl)) + { + // we need to limit the max auto width feature of the filter box + int nWidth = m_xControl->get_approximate_digit_width() * 50; + m_xControl->set_size_request(nWidth, -1); + + impl_init( _pAsciiModuleName ); + } + + void OpenDocumentListBox::impl_init( const char* _pAsciiModuleName ) + { + OSL_ENSURE( _pAsciiModuleName, "OpenDocumentListBox::impl_init: invalid module name!" ); + + std::vector< SvtHistoryOptions::HistoryItem > aHistory = SvtHistoryOptions::GetList( EHistoryType::PickList ); + Reference< XNameAccess > xFilterFactory; + xFilterFactory.set(::comphelper::getProcessServiceFactory()->createInstance( + "com.sun.star.document.FilterFactory" ), css::uno::UNO_QUERY); + + for ( const SvtHistoryOptions::HistoryItem& rHistoryItem : aHistory ) + { + try + { + // Get the current history item's properties. + OUString sURL = rHistoryItem.sURL; + OUString sFilter = rHistoryItem.sFilter; + OUString sTitle = rHistoryItem.sTitle; + OUString sPassword = rHistoryItem.sPassword; + + // If the entry is a Base file then insert it into the + // history list and the list box. + Sequence< PropertyValue > aProps; + xFilterFactory->getByName( sFilter ) >>= aProps; + + ::comphelper::SequenceAsHashMap aFilterProperties( aProps ); + OUString sDocumentService = aFilterProperties.getUnpackedValueOrDefault( + "DocumentService", OUString() ); + if ( sDocumentService.equalsAscii( _pAsciiModuleName ) ) + { + // yes, it's a Base document + INetURLObject aURL; + aURL.SetSmartURL( sURL ); + // The password is set only when it is not empty. + if ( !sPassword.isEmpty() ) + aURL.SetPass( sPassword ); + + if ( sTitle.isEmpty() ) + sTitle = aURL.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous ); + + OUString sDecodedURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + + m_xControl->append_text(sTitle); + m_aURLs.emplace_back(sDecodedURL, sFilter); + } + } + catch( Exception& ) {} + } + } + + OUString OpenDocumentListBox::GetSelectedDocumentURL() const + { + OUString sURL; + sal_Int32 nSelected = m_xControl->get_active(); + if (nSelected != -1) + sURL = impl_getDocumentAtIndex( nSelected ).first; + return sURL; + } + + const OpenDocumentListBox::StringPair & OpenDocumentListBox::impl_getDocumentAtIndex( sal_uInt16 _nListIndex ) const + { + return m_aURLs[_nListIndex]; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/sqledit.cxx b/dbaccess/source/ui/control/sqledit.cxx new file mode 100644 index 000000000..49758289e --- /dev/null +++ b/dbaccess/source/ui/control/sqledit.cxx @@ -0,0 +1,515 @@ +/* -*- 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 <cassert> + +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XPropertiesChangeListener.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <officecfg/Office/Common.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/wghtitem.hxx> +#include <sqledit.hxx> +#include <cppuhelper/implbase.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <svl/itempool.hxx> +#include <svl/itemset.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/settings.hxx> +#include <vcl/specialchars.hxx> +#include <vcl/svapp.hxx> + +using namespace dbaui; + +class SQLEditView::ChangesListener: + public cppu::WeakImplHelper< css::beans::XPropertiesChangeListener > +{ +public: + explicit ChangesListener(SQLEditView& editor): editor_(editor) {} + +private: + virtual ~ChangesListener() override {} + + virtual void SAL_CALL disposing(css::lang::EventObject const &) override + { + osl::MutexGuard g(editor_.m_mutex); + editor_.m_notifier.clear(); + } + + virtual void SAL_CALL propertiesChange( + css::uno::Sequence< css::beans::PropertyChangeEvent > const &) override + { + SolarMutexGuard g; + editor_.ImplSetFont(); + } + + SQLEditView& editor_; +}; + +SQLEditView::SQLEditView(std::unique_ptr<weld::ScrolledWindow> xScrolledWindow) + : m_xScrolledWindow(std::move(xScrolledWindow)) + , m_aUpdateDataTimer("dbaccess SQLEditView m_aUpdateDataTimer") + , m_aHighlighter(HighlighterLanguage::SQL) + , m_bInUpdate(false) + , m_bDisableInternalUndo(false) +{ + m_xScrolledWindow->connect_vadjustment_changed(LINK(this, SQLEditView, ScrollHdl)); +} + +void SQLEditView::DisableInternalUndo() +{ + GetEditEngine()->EnableUndo(false); + m_bDisableInternalUndo = true; +} + +void SQLEditView::SetItemPoolFont(SfxItemPool* pItemPool) +{ + OUString sFontName(officecfg::Office::Common::Font::SourceViewFont::FontName::get().value_or(OUString())); + if (sFontName.isEmpty()) + { + vcl::Font aTmpFont(OutputDevice::GetDefaultFont(DefaultFontType::FIXED, Application::GetSettings().GetUILanguageTag().getLanguageType(), GetDefaultFontFlags::OnlyOne)); + sFontName = aTmpFont.GetFamilyName(); + } + + Size aFontSize(0, officecfg::Office::Common::Font::SourceViewFont::FontHeight::get()); + vcl::Font aAppFont(sFontName, aFontSize); + + pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(), + "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, + EE_CHAR_FONTINFO)); + pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(), + "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, + EE_CHAR_FONTINFO_CJK)); + pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(), + "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, + EE_CHAR_FONTINFO_CTL)); + + pItemPool->SetPoolDefaultItem( + SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT)); + pItemPool->SetPoolDefaultItem( + SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT_CJK)); + pItemPool->SetPoolDefaultItem( + SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT_CTL)); +} + +void SQLEditView::makeEditEngine() +{ + assert(!m_pItemPool); + m_pItemPool = EditEngine::CreatePool(); + SetItemPoolFont(m_pItemPool.get()); + m_xEditEngine.reset(new EditEngine(m_pItemPool.get())); +} + +void SQLEditView::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + WeldEditView::SetDrawingArea(pDrawingArea); + + EditEngine& rEditEngine = *GetEditEngine(); + + rEditEngine.SetDefaultHorizontalTextDirection(EEHorizontalTextDirection::L2R); + rEditEngine.SetModifyHdl(LINK(this, SQLEditView, ModifyHdl)); + rEditEngine.SetStatusEventHdl(LINK(this, SQLEditView, EditStatusHdl)); + + m_aUpdateDataTimer.SetTimeout(150); + m_aUpdateDataTimer.SetInvokeHandler(LINK(this, SQLEditView, ImplUpdateDataHdl)); + + ImplSetFont(); + + // Listen for change of Font and Color Settings: + // Using "this" in ctor is a little fishy, but should work here at least as + // long as there are no derivations: + m_listener = new ChangesListener(*this); + css::uno::Reference< css::beans::XMultiPropertySet > n( + officecfg::Office::Common::Font::SourceViewFont::get(), + css::uno::UNO_QUERY_THROW); + { + osl::MutexGuard g(m_mutex); + m_notifier = n; + } + css::uno::Sequence< OUString > s { "FontHeight", "FontName" }; + n->addPropertiesChangeListener(s, m_listener); + m_ColorConfig.AddListener(this); +} + +SQLEditView::~SQLEditView() +{ + css::uno::Reference< css::beans::XMultiPropertySet > n; + { + osl::MutexGuard g(m_mutex); + n = m_notifier; + } + if (n.is()) { + n->removePropertiesChangeListener(m_listener); + } + m_ColorConfig.RemoveListener(this); +} + +void SQLEditView::SetTextAndUpdate(const OUString& rNewText) +{ + SetText(rNewText); + UpdateData(); +} + +IMPL_LINK_NOARG(SQLEditView, ModifyHdl, LinkParamNone*, void) +{ + if (m_bInUpdate) + return; + m_aUpdateDataTimer.Start(); +} + +IMPL_LINK_NOARG(SQLEditView, ImplUpdateDataHdl, Timer*, void) +{ + UpdateData(); +} + +Color SQLEditView::GetColorValue(TokenType aToken) +{ + return GetSyntaxHighlightColor(m_aColorConfig, m_aHighlighter.GetLanguage(), aToken); +} + +void SQLEditView::UpdateData() +{ + m_bInUpdate = true; + EditEngine& rEditEngine = *GetEditEngine(); + + bool bModified = rEditEngine.IsModified(); + bool bUndoEnabled = rEditEngine.IsUndoEnabled(); + rEditEngine.EnableUndo(false); + + // syntax highlighting + for (sal_Int32 nLine=0; nLine < rEditEngine.GetParagraphCount(); ++nLine) + { + OUString aLine( rEditEngine.GetText( nLine ) ); + + ESelection aAllLine(nLine, 0, nLine, EE_TEXTPOS_ALL); + rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_COLOR); + rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_WEIGHT); + rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_WEIGHT_CJK); + rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_WEIGHT_CTL); + + std::vector<HighlightPortion> aPortions; + m_aHighlighter.getHighlightPortions( aLine, aPortions ); + for (auto const& portion : aPortions) + { + SfxItemSet aSet(rEditEngine.GetEmptyItemSet()); + aSet.Put(SvxColorItem(GetColorValue(portion.tokenType), EE_CHAR_COLOR)); + rEditEngine.QuickSetAttribs(aSet, ESelection(nLine, portion.nBegin, nLine, portion.nEnd)); + } + } + + rEditEngine.ClearModifyFlag(); + + m_bInUpdate = false; + + rEditEngine.EnableUndo(bUndoEnabled); + + if (bModified) + m_aModifyLink.Call(nullptr); + + Invalidate(); +} + +void SQLEditView::DoBracketHilight(sal_uInt16 nKey) +{ + ESelection aCurrentPos = m_xEditView->GetSelection(); + sal_Int32 nStartPos = aCurrentPos.nStartPos; + const sal_uInt32 nStartPara = aCurrentPos.nStartPara; + sal_uInt16 nCount = 0; + int nChar = -1; + + switch (nKey) + { + case '\'': // no break + case '"': + { + nChar = nKey; + break; + } + case '}' : + { + nChar = '{'; + break; + } + case ')': + { + nChar = '('; + break; + } + case ']': + { + nChar = '['; + break; + } + } + + if (nChar == -1) + return; + + bool bUndoEnabled = m_xEditEngine->IsUndoEnabled(); + m_xEditEngine->EnableUndo(false); + + sal_uInt32 nPara = nStartPara; + do + { + if (nPara == nStartPara && nStartPos == 0) + continue; + + OUString aLine( m_xEditEngine->GetText( nPara ) ); + + if (aLine.isEmpty()) + continue; + + for (sal_Int32 i = (nPara==nStartPara) ? nStartPos-1 : aLine.getLength()-1; i>0; --i) + { + if (aLine[i] == nChar) + { + if (!nCount) + { + SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet()); + aSet.Put(SvxColorItem(Color(0,0,0), EE_CHAR_COLOR)); + aSet.Put(SvxWeightItem(WEIGHT_ULTRABOLD, EE_CHAR_WEIGHT)); + aSet.Put(SvxWeightItem(WEIGHT_ULTRABOLD, EE_CHAR_WEIGHT_CJK)); + aSet.Put(SvxWeightItem(WEIGHT_ULTRABOLD, EE_CHAR_WEIGHT_CTL)); + + m_xEditEngine->QuickSetAttribs(aSet, ESelection(nPara, i, nPara, i + 1)); + m_xEditEngine->QuickSetAttribs(aSet, ESelection(nStartPara, nStartPos, nStartPara, nStartPos)); + return; + } + else + --nCount; + } + if (aLine[i] == nKey) + ++nCount; + } + } while (nPara--); + + m_xEditEngine->EnableUndo(bUndoEnabled); +} + +Color SQLEditView::GetSyntaxHighlightColor(const svtools::ColorConfig& rColorConfig, HighlighterLanguage eLanguage, TokenType aToken) +{ + Color aColor; + switch (eLanguage) + { + case HighlighterLanguage::SQL: + { + switch (aToken) + { + case TokenType::Identifier: aColor = rColorConfig.GetColorValue(svtools::SQLIDENTIFIER).nColor; break; + case TokenType::Number: aColor = rColorConfig.GetColorValue(svtools::SQLNUMBER).nColor; break; + case TokenType::String: aColor = rColorConfig.GetColorValue(svtools::SQLSTRING).nColor; break; + case TokenType::Operator: aColor = rColorConfig.GetColorValue(svtools::SQLOPERATOR).nColor; break; + case TokenType::Keywords: aColor = rColorConfig.GetColorValue(svtools::SQLKEYWORD).nColor; break; + case TokenType::Parameter: aColor = rColorConfig.GetColorValue(svtools::SQLPARAMETER).nColor; break; + case TokenType::Comment: aColor = rColorConfig.GetColorValue(svtools::SQLCOMMENT).nColor; break; + default: aColor = Color(0,0,0); + } + break; + } + case HighlighterLanguage::Basic: + { + switch (aToken) + { + case TokenType::Identifier: aColor = Color(255,0,0); break; + case TokenType::Comment: aColor = Color(0,0,45); break; + case TokenType::Number: aColor = Color(204,102,204); break; + case TokenType::String: aColor = Color(0,255,45); break; + case TokenType::Operator: aColor = Color(0,0,100); break; + case TokenType::Keywords: aColor = Color(0,0,255); break; + case TokenType::Error : aColor = Color(0,255,255); break; + default: aColor = Color(0,0,0); + } + break; + } + default: aColor = Color(0,0,0); + + } + return aColor; +} + +bool SQLEditView::KeyInput(const KeyEvent& rKEvt) +{ + DoBracketHilight(rKEvt.GetCharCode()); + + if (m_bDisableInternalUndo) + { + KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction(); + if (eFunc == KeyFuncType::UNDO || eFunc == KeyFuncType::REDO) + return false; + } + + return WeldEditView::KeyInput(rKEvt); +} + +bool SQLEditView::Command(const CommandEvent& rCEvt) +{ + if (rCEvt.GetCommand() == CommandEventId::ContextMenu) + { + ::tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1, 1)); + weld::Widget* pPopupParent = GetDrawingArea(); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "vcl/ui/editmenu.ui")); + std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu")); + + bool bEnableCut = true; + bool bEnableCopy = true; + bool bEnableDelete = true; + bool bEnablePaste = true; + bool bEnableSpecialChar = true; + + EditView* pEditView = GetEditView(); + + if (!pEditView->HasSelection()) + { + bEnableCut = false; + bEnableCopy = false; + bEnableDelete = false; + } + + if (pEditView->IsReadOnly()) + { + bEnableCut = false; + bEnablePaste = false; + bEnableDelete = false; + bEnableSpecialChar = false; + } + + xContextMenu->set_sensitive("cut", bEnableCut); + xContextMenu->set_sensitive("copy", bEnableCopy); + xContextMenu->set_sensitive("delete", bEnableDelete); + xContextMenu->set_sensitive("paste", bEnablePaste); + xContextMenu->set_sensitive("specialchar", bEnableSpecialChar); + xContextMenu->set_visible("undo", false); + xContextMenu->set_visible("specialchar", vcl::GetGetSpecialCharsFunction() != nullptr); + + OString sCommand = xContextMenu->popup_at_rect(pPopupParent, aRect); + + if (sCommand == "cut") + pEditView->Cut(); + else if (sCommand == "copy") + pEditView->Copy(); + else if (sCommand == "paste") + pEditView->Paste(); + else if (sCommand == "delete") + pEditView->DeleteSelected(); + else if (sCommand == "selectall") + { + sal_Int32 nPar = m_xEditEngine->GetParagraphCount(); + if (nPar) + { + sal_Int32 nLen = m_xEditEngine->GetTextLen(nPar - 1); + pEditView->SetSelection(ESelection(0, 0, nPar - 1, nLen)); + } + } + else if (sCommand == "specialchar") + { + OUString aChars = vcl::GetGetSpecialCharsFunction()(pPopupParent, m_xEditEngine->GetStandardFont(0)); + if (!aChars.isEmpty()) + { + pEditView->InsertText(aChars); + } + } + + return true; + } + return WeldEditView::Command(rCEvt); +} + +void SQLEditView::EditViewScrollStateChange() +{ + // editengine height has changed or editview scroll pos has changed + SetScrollBarRange(); +} + +void SQLEditView::SetScrollBarRange() +{ + EditEngine *pEditEngine = GetEditEngine(); + if (!pEditEngine) + return; + if (!m_xScrolledWindow) + return; + EditView* pEditView = GetEditView(); + if (!pEditView) + return; + + int nVUpper = pEditEngine->GetTextHeight(); + int nVCurrentDocPos = pEditView->GetVisArea().Top(); + const Size aOut(pEditView->GetOutputArea().GetSize()); + int nVStepIncrement = aOut.Height() * 2 / 10; + int nVPageIncrement = aOut.Height() * 8 / 10; + int nVPageSize = aOut.Height(); + + /* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has + effectively... + + lower = gtk_adjustment_get_lower + upper = gtk_adjustment_get_upper - gtk_adjustment_get_page_size + + and requires that upper > lower or the deceleration animation never ends + */ + nVPageSize = std::min(nVPageSize, nVUpper); + + m_xScrolledWindow->vadjustment_configure(nVCurrentDocPos, 0, nVUpper, + nVStepIncrement, nVPageIncrement, nVPageSize); +} + +IMPL_LINK_NOARG(SQLEditView, ScrollHdl, weld::ScrolledWindow&, void) +{ + DoScroll(); +} + +IMPL_LINK_NOARG(SQLEditView, EditStatusHdl, EditStatus&, void) +{ + Resize(); +} + +void SQLEditView::DoScroll() +{ + if (m_xEditView) + { + auto currentDocPos = m_xEditView->GetVisArea().Top(); + auto nDiff = currentDocPos - m_xScrolledWindow->vadjustment_get_value(); + // we expect SetScrollBarRange callback to be triggered by Scroll + // to set where we ended up + m_xEditView->Scroll(0, nDiff); + } +} + +void SQLEditView::ConfigurationChanged(utl::ConfigurationBroadcaster*, ConfigurationHints) +{ + UpdateData(); +} + +void SQLEditView::ImplSetFont() +{ + // see SmEditWindow::DataChanged for a similar case + SetItemPoolFont(m_pItemPool.get()); // change default font + // re-create with the new font + EditEngine& rEditEngine = *GetEditEngine(); + OUString aTxt(rEditEngine.GetText()); + rEditEngine.Clear(); + SetTextAndUpdate(aTxt); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/tabletree.cxx b/dbaccess/source/ui/control/tabletree.cxx new file mode 100644 index 000000000..2c3f0976f --- /dev/null +++ b/dbaccess/source/ui/control/tabletree.cxx @@ -0,0 +1,707 @@ +/* -*- 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 <core_resource.hxx> +#include <tabletree.hxx> +#include <imageprovider.hxx> +#include <strings.hrc> +#include <connectivity/dbtools.hxx> +#include <com/sun/star/sdb/application/DatabaseObject.hpp> +#include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <connectivity/dbmetadata.hxx> + +#include <algorithm> + +namespace dbaui +{ + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdb::application; + +using namespace ::dbtools; +using namespace ::comphelper; + +namespace DatabaseObject = ::com::sun::star::sdb::application::DatabaseObject; +namespace DatabaseObjectContainer = ::com::sun::star::sdb::application::DatabaseObjectContainer; + +// OTableTreeListBox +OTableTreeListBox::OTableTreeListBox(std::unique_ptr<weld::TreeView> xTreeView, bool bShowToggles) + : TreeListBox(std::move(xTreeView), true) + , m_xImageProvider(new ImageProvider) + , m_bVirtualRoot(false) + , m_bNoEmptyFolders(false) + , m_bShowToggles(bShowToggles) +{ + if (m_bShowToggles) + m_xTreeView->enable_toggle_buttons(weld::ColumnToggleType::Check); +} + +bool OTableTreeListBox::isFolderEntry(const weld::TreeIter& rEntry) const +{ + sal_Int32 nEntryType = m_xTreeView->get_id(rEntry).toInt32(); + return ( nEntryType == DatabaseObjectContainer::TABLES ) + || ( nEntryType == DatabaseObjectContainer::CATALOG ) + || ( nEntryType == DatabaseObjectContainer::SCHEMA ); +} + +void OTableTreeListBox::implOnNewConnection( const Reference< XConnection >& _rxConnection ) +{ + m_xConnection = _rxConnection; + m_xImageProvider.reset( new ImageProvider( m_xConnection ) ); +} + +void OTableTreeListBox::UpdateTableList( const Reference< XConnection >& _rxConnection ) +{ + Sequence< OUString > sTables, sViews; + + OUString sCurrentActionError; + try + { + Reference< XTablesSupplier > xTableSupp( _rxConnection, UNO_QUERY_THROW ); + sCurrentActionError = DBA_RES(STR_NOTABLEINFO); + + Reference< XNameAccess > xTables,xViews; + + Reference< XViewsSupplier > xViewSupp( _rxConnection, UNO_QUERY ); + if ( xViewSupp.is() ) + { + xViews = xViewSupp->getViews(); + if (xViews.is()) + sViews = xViews->getElementNames(); + } + + xTables = xTableSupp->getTables(); + if (xTables.is()) + sTables = xTables->getElementNames(); + } + catch(RuntimeException&) + { + TOOLS_WARN_EXCEPTION( "dbaccess", "OTableTreeListBox::UpdateTableList"); + } + catch ( const SQLException& ) + { + throw; + } + catch(Exception&) + { + css::uno::Any anyEx = cppu::getCaughtException(); + // a non-SQLException exception occurred ... simply throw an SQLException + throw SQLException(sCurrentActionError, nullptr, "", 0, anyEx); + } + + UpdateTableList( _rxConnection, sTables, sViews ); +} + +namespace +{ + struct OViewSetter + { + const Sequence< OUString> m_aViews; + ::comphelper::UStringMixEqual m_aEqualFunctor; + + OViewSetter(const Sequence< OUString>& _rViews,bool _bCase) : m_aViews(_rViews),m_aEqualFunctor(_bCase){} + OTableTreeListBox::TNames::value_type operator() (const OUString& name) + { + OTableTreeListBox::TNames::value_type aRet; + aRet.first = name; + aRet.second = std::any_of(m_aViews.begin(), m_aViews.end(), + [this, &name](const OUString& lhs) + { return m_aEqualFunctor(lhs, name); } ); + + return aRet; + } + }; + +} + +void OTableTreeListBox::UpdateTableList( + const Reference< XConnection >& _rxConnection, + const Sequence< OUString>& _rTables, + const Sequence< OUString>& _rViews + ) +{ + TNames aTables; + aTables.resize(_rTables.getLength()); + try + { + Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData(), UNO_SET_THROW ); + std::transform( _rTables.begin(), _rTables.end(), + aTables.begin(), OViewSetter( _rViews, xMeta->supportsMixedCaseQuotedIdentifiers() ) ); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + UpdateTableList( _rxConnection, aTables ); +} + +namespace +{ + std::vector< OUString > lcl_getMetaDataStrings_throw( const Reference< XResultSet >& _rxMetaDataResult, sal_Int32 _nColumnIndex ) + { + std::vector< OUString > aStrings; + Reference< XRow > xRow( _rxMetaDataResult, UNO_QUERY_THROW ); + while ( _rxMetaDataResult->next() ) + aStrings.push_back( xRow->getString( _nColumnIndex ) ); + return aStrings; + } + + bool lcl_shouldDisplayEmptySchemasAndCatalogs( const Reference< XConnection >& _rxConnection ) + { + ::dbtools::DatabaseMetaData aMetaData( _rxConnection ); + return aMetaData.displayEmptyTableFolders(); + } +} + +void OTableTreeListBox::UpdateTableList( const Reference< XConnection >& _rxConnection, const TNames& _rTables ) +{ + implOnNewConnection( _rxConnection ); + + // throw away all the old stuff + m_xTreeView->clear(); + m_xTreeView->make_unsorted(); + + try + { + if (haveVirtualRoot()) + { + OUString sRootEntryText; + if ( std::none_of(_rTables.begin(),_rTables.end(), + [] (const TNames::value_type& name) { return !name.second; }) ) + sRootEntryText = DBA_RES(STR_ALL_TABLES); + else if ( std::none_of(_rTables.begin(),_rTables.end(), + [] (const TNames::value_type& name) { return name.second; }) ) + sRootEntryText = DBA_RES(STR_ALL_VIEWS); + else + sRootEntryText = DBA_RES(STR_ALL_TABLES_AND_VIEWS); + OUString sId(OUString::number(DatabaseObjectContainer::TABLES)); + OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE); + std::unique_ptr<weld::TreeIter> xRet(m_xTreeView->make_iterator()); + m_xTreeView->insert(nullptr, -1, nullptr, &sId, nullptr, nullptr, false, xRet.get()); + m_xTreeView->set_image(*xRet, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xRet, TRISTATE_FALSE); + m_xTreeView->set_text(*xRet, sRootEntryText, 0); + m_xTreeView->set_text_emphasis(*xRet, false, 0); + } + + if ( _rTables.empty() ) + // nothing to do (besides inserting the root entry) + return; + + // get the table/view names + Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData(), UNO_SET_THROW ); + for (auto const& table : _rTables) + { + // add the entry + implAddEntry(xMeta, table.first, false); + } + + if ( !m_bNoEmptyFolders && lcl_shouldDisplayEmptySchemasAndCatalogs( _rxConnection ) ) + { + bool bSupportsCatalogs = xMeta->supportsCatalogsInDataManipulation(); + bool bSupportsSchemas = xMeta->supportsSchemasInDataManipulation(); + + if ( bSupportsCatalogs || bSupportsSchemas ) + { + // we display empty catalogs if the DB supports catalogs, and they're noted at the beginning of a + // composed name. Otherwise, we display empty schematas. (also see the tree structure explained in + // implAddEntry) + bool bCatalogs = bSupportsCatalogs && xMeta->isCatalogAtStart(); + + std::vector< OUString > aFolderNames( lcl_getMetaDataStrings_throw( + bCatalogs ? xMeta->getCatalogs() : xMeta->getSchemas(), 1 ) ); + sal_Int32 nFolderType = bCatalogs ? DatabaseObjectContainer::CATALOG : DatabaseObjectContainer::SCHEMA; + + OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE); + + std::unique_ptr<weld::TreeIter> xRootEntry(getAllObjectsEntry()); + std::unique_ptr<weld::TreeIter> xRet(m_xTreeView->make_iterator()); + for (auto const& folderName : aFolderNames) + { + std::unique_ptr<weld::TreeIter> xFolder(GetEntryPosByName(folderName, xRootEntry.get())); + if (!xFolder) + { + OUString sId(OUString::number(nFolderType)); + m_xTreeView->insert(xRootEntry.get(), -1, nullptr, &sId, nullptr, nullptr, false, xRet.get()); + m_xTreeView->set_image(*xRet, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xRet, TRISTATE_FALSE); + m_xTreeView->set_text(*xRet, folderName, 0); + m_xTreeView->set_text_emphasis(*xRet, false, 0); + } + } + } + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + m_xTreeView->make_sorted(); +} + +bool OTableTreeListBox::isWildcardChecked(const weld::TreeIter& rEntry) +{ + return m_xTreeView->get_text_emphasis(rEntry, 0); +} + +void OTableTreeListBox::checkWildcard(const weld::TreeIter& rEntry) +{ + if (!m_bShowToggles) + return; + m_xTreeView->set_toggle(rEntry, TRISTATE_TRUE); + checkedButton_noBroadcast(rEntry); +} + +std::unique_ptr<weld::TreeIter> OTableTreeListBox::getAllObjectsEntry() const +{ + if (!haveVirtualRoot()) + return nullptr; + auto xRet = m_xTreeView->make_iterator(); + if (!m_xTreeView->get_iter_first(*xRet)) + return nullptr; + return xRet; +} + +void OTableTreeListBox::checkedButton_noBroadcast(const weld::TreeIter& rEntry) +{ + if (!m_bShowToggles) + return; + TriState eState = m_xTreeView->get_toggle(rEntry); + OSL_ENSURE(TRISTATE_INDET != eState, "OTableTreeListBox::CheckButtonHdl: user action which lead to TRISTATE?"); + + if (m_xTreeView->iter_has_child(rEntry)) // if it has children, check those too + { + std::unique_ptr<weld::TreeIter> xChildEntry(m_xTreeView->make_iterator(&rEntry)); + std::unique_ptr<weld::TreeIter> xSiblingEntry(m_xTreeView->make_iterator(&rEntry)); + bool bChildEntry = m_xTreeView->iter_next(*xChildEntry); + bool bSiblingEntry = m_xTreeView->iter_next_sibling(*xSiblingEntry); + while (bChildEntry && (!bSiblingEntry || !xChildEntry->equal(*xSiblingEntry))) + { + m_xTreeView->set_toggle(*xChildEntry, eState); + bChildEntry = m_xTreeView->iter_next(*xChildEntry); + } + } + + if (m_xTreeView->is_selected(rEntry)) + { + m_xTreeView->selected_foreach([this, eState](weld::TreeIter& rSelected){ + m_xTreeView->set_toggle(rSelected, eState); + if (m_xTreeView->iter_has_child(rSelected)) // if it has children, check those too + { + std::unique_ptr<weld::TreeIter> xChildEntry(m_xTreeView->make_iterator(&rSelected)); + std::unique_ptr<weld::TreeIter> xSiblingEntry(m_xTreeView->make_iterator(&rSelected)); + bool bChildEntry = m_xTreeView->iter_next(*xChildEntry); + bool bSiblingEntry = m_xTreeView->iter_next_sibling(*xSiblingEntry); + while (bChildEntry && (!bSiblingEntry || !xChildEntry->equal(*xSiblingEntry))) + { + m_xTreeView->set_toggle(*xChildEntry, eState); + bChildEntry = m_xTreeView->iter_next(*xChildEntry); + } + } + return false; + }); + } + + CheckButtons(); + + // if an entry has children, it makes a difference if the entry is checked + // because all children are checked or if the user checked it explicitly. + // So we track explicit (un)checking + implEmphasize(rEntry, eState == TRISTATE_TRUE); +} + +void OTableTreeListBox::implEmphasize(const weld::TreeIter& rEntry, bool _bChecked, bool _bUpdateDescendants, bool _bUpdateAncestors) +{ + // special emphasizing handling for the "all objects" entry + bool bAllObjectsEntryAffected = haveVirtualRoot() && (getAllObjectsEntry()->equal(rEntry)); + if ( m_xTreeView->iter_has_child(rEntry) // the entry has children + || bAllObjectsEntryAffected // or it is the "all objects" entry + ) + { + m_xTreeView->set_text_emphasis(rEntry, _bChecked, 0); + } + + if (_bUpdateDescendants) + { + std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rEntry)); + // remove the mark for all children of the checked entry + bool bChildLoop = m_xTreeView->iter_children(*xChild); + while (bChildLoop) + { + if (m_xTreeView->iter_has_child(*xChild)) + implEmphasize(*xChild, false, true, false); + bChildLoop = m_xTreeView->iter_next_sibling(*xChild); + } + } + + if (_bUpdateAncestors) + { + std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry)); + // remove the mark for all ancestors of the entry + if (m_xTreeView->iter_parent(*xParent)) + implEmphasize(*xParent, false, false); + } +} + +std::unique_ptr<weld::TreeIter> OTableTreeListBox::implAddEntry( + const Reference< XDatabaseMetaData >& _rxMeta, + const OUString& _rTableName, + bool _bCheckName + ) +{ + OSL_PRECOND( _rxMeta.is(), "OTableTreeListBox::implAddEntry: invalid meta data!" ); + if ( !_rxMeta.is() ) + return nullptr; + + // split the complete name into its components + OUString sCatalog, sSchema, sName; + qualifiedNameComponents( _rxMeta, _rTableName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation ); + + std::unique_ptr<weld::TreeIter> xParentEntry(getAllObjectsEntry()); + + // if the DB uses catalog at the start of identifiers, then our hierarchy is + // catalog + // +- schema + // +- table + // else it is + // schema + // +- catalog + // +- table + bool bCatalogAtStart = _rxMeta->isCatalogAtStart(); + const OUString& rFirstName = bCatalogAtStart ? sCatalog : sSchema; + const sal_Int32 nFirstFolderType = bCatalogAtStart ? DatabaseObjectContainer::CATALOG : DatabaseObjectContainer::SCHEMA; + const OUString& rSecondName = bCatalogAtStart ? sSchema : sCatalog; + const sal_Int32 nSecondFolderType = bCatalogAtStart ? DatabaseObjectContainer::SCHEMA : DatabaseObjectContainer::CATALOG; + + if ( !rFirstName.isEmpty() ) + { + std::unique_ptr<weld::TreeIter> xFolder(GetEntryPosByName(rFirstName, xParentEntry.get())); + if (!xFolder) + { + xFolder = m_xTreeView->make_iterator(); + OUString sId(OUString::number(nFirstFolderType)); + OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE); + m_xTreeView->insert(xParentEntry.get(), -1, nullptr, &sId, nullptr, nullptr, false, xFolder.get()); + m_xTreeView->set_image(*xFolder, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xFolder, TRISTATE_FALSE); + m_xTreeView->set_text(*xFolder, rFirstName, 0); + m_xTreeView->set_text_emphasis(*xFolder, false, 0); + } + xParentEntry = std::move(xFolder); + } + + if ( !rSecondName.isEmpty() ) + { + std::unique_ptr<weld::TreeIter> xFolder(GetEntryPosByName(rSecondName, xParentEntry.get())); + if (!xFolder) + { + xFolder = m_xTreeView->make_iterator(); + OUString sId(OUString::number(nSecondFolderType)); + OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE); + m_xTreeView->insert(xParentEntry.get(), -1, nullptr, &sId, nullptr, nullptr, false, xFolder.get()); + m_xTreeView->set_image(*xFolder, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xFolder, TRISTATE_FALSE); + m_xTreeView->set_text(*xFolder, rSecondName, 0); + m_xTreeView->set_text_emphasis(*xFolder, false, 0); + } + xParentEntry = std::move(xFolder); + } + + if (!_bCheckName || !GetEntryPosByName(sName, xParentEntry.get())) + { + std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator(); + m_xTreeView->insert(xParentEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xEntry.get()); + + auto xGraphic = m_xImageProvider->getXGraphic(_rTableName, DatabaseObject::TABLE); + if (xGraphic.is()) + m_xTreeView->set_image(*xEntry, xGraphic, -1); + else + { + OUString sImageId(m_xImageProvider->getImageId(_rTableName, DatabaseObject::TABLE)); + m_xTreeView->set_image(*xEntry, sImageId, -1); + } + if (m_bShowToggles) + m_xTreeView->set_toggle(*xEntry, TRISTATE_FALSE); + m_xTreeView->set_text(*xEntry, sName, 0); + m_xTreeView->set_text_emphasis(*xEntry, false, 0); + + return xEntry; + } + + return nullptr; +} + +NamedDatabaseObject OTableTreeListBox::describeObject(const weld::TreeIter& rEntry) +{ + NamedDatabaseObject aObject; + + sal_Int32 nEntryType = m_xTreeView->get_id(rEntry).toInt32(); + + if ( nEntryType == DatabaseObjectContainer::TABLES ) + { + aObject.Type = DatabaseObjectContainer::TABLES; + } + else if ( ( nEntryType == DatabaseObjectContainer::CATALOG ) + || ( nEntryType == DatabaseObjectContainer::SCHEMA ) + ) + { + // nothing useful to be done + } + else + { + aObject.Type = DatabaseObject::TABLE; + aObject.Name = getQualifiedTableName(rEntry); + } + + return aObject; +} + +std::unique_ptr<weld::TreeIter> OTableTreeListBox::addedTable(const OUString& rName) +{ + try + { + Reference< XDatabaseMetaData > xMeta; + if ( impl_getAndAssertMetaData( xMeta ) ) + return implAddEntry( xMeta, rName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return nullptr; +} + +bool OTableTreeListBox::impl_getAndAssertMetaData( Reference< XDatabaseMetaData >& _out_rMetaData ) const +{ + if ( m_xConnection.is() ) + _out_rMetaData = m_xConnection->getMetaData(); + OSL_PRECOND( _out_rMetaData.is(), "OTableTreeListBox::impl_getAndAssertMetaData: invalid current connection!" ); + return _out_rMetaData.is(); +} + +OUString OTableTreeListBox::getQualifiedTableName(const weld::TreeIter& rEntry) const +{ + OSL_PRECOND( !isFolderEntry(rEntry), "OTableTreeListBox::getQualifiedTableName: folder entries not allowed here!" ); + + try + { + Reference< XDatabaseMetaData > xMeta; + if ( !impl_getAndAssertMetaData( xMeta ) ) + return OUString(); + + OUString sCatalog; + OUString sSchema; + OUString sTable; + + std::unique_ptr<weld::TreeIter> xSchema(m_xTreeView->make_iterator(&rEntry)); + bool bSchema = m_xTreeView->iter_parent(*xSchema); + if (bSchema) + { + std::unique_ptr<weld::TreeIter> xCatalog(m_xTreeView->make_iterator(xSchema.get())); + bool bCatalog = m_xTreeView->iter_parent(*xCatalog); + if ( bCatalog + || ( xMeta->supportsCatalogsInDataManipulation() + && !xMeta->supportsSchemasInDataManipulation() + ) // here we support catalog but no schema + ) + { + if (!bCatalog) + { + xCatalog = std::move(xSchema); + bSchema = false; + } + sCatalog = m_xTreeView->get_text(*xCatalog); + } + if (bSchema) + sSchema = m_xTreeView->get_text(*xSchema); + } + sTable = m_xTreeView->get_text(rEntry); + + return ::dbtools::composeTableName( xMeta, sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::InDataManipulation ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return OUString(); +} + +std::unique_ptr<weld::TreeIter> OTableTreeListBox::getEntryByQualifiedName(const OUString& rName) +{ + try + { + Reference< XDatabaseMetaData > xMeta; + if ( !impl_getAndAssertMetaData( xMeta ) ) + return nullptr; + + // split the complete name into its components + OUString sCatalog, sSchema, sName; + qualifiedNameComponents(xMeta, rName, sCatalog, sSchema, sName,::dbtools::EComposeRule::InDataManipulation); + + std::unique_ptr<weld::TreeIter> xParent(getAllObjectsEntry()); + std::unique_ptr<weld::TreeIter> xCat; + std::unique_ptr<weld::TreeIter> xSchema; + if (!sCatalog.isEmpty()) + { + xCat = GetEntryPosByName(sCatalog); + if (xCat) + xParent = std::move(xCat); + } + + if (!sSchema.isEmpty()) + { + xSchema = GetEntryPosByName(sSchema, xParent.get()); + if (xSchema) + xParent = std::move(xSchema); + } + + return GetEntryPosByName(sName, xParent.get()); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return nullptr; +} + +void OTableTreeListBox::removedTable(const OUString& rName) +{ + try + { + std::unique_ptr<weld::TreeIter> xEntry = getEntryByQualifiedName(rName); + if (xEntry) + m_xTreeView->remove(*xEntry); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OTableTreeListBox::CheckButtons() +{ + if (!m_bShowToggles) + return; + + auto xEntry(m_xTreeView->make_iterator()); + if (!m_xTreeView->get_iter_first(*xEntry)) + return; + + do + { + implDetermineState(*xEntry); + } while (m_xTreeView->iter_next_sibling(*xEntry)); +} + +TriState OTableTreeListBox::implDetermineState(const weld::TreeIter& rEntry) +{ + if (!m_bShowToggles) + return TRISTATE_FALSE; + + TriState eState = m_xTreeView->get_toggle(rEntry); + if (!m_xTreeView->iter_has_child(rEntry)) + // nothing to do in this bottom-up routine if there are no children ... + return eState; + + // loop through the children and check their states + sal_uInt16 nCheckedChildren = 0; + sal_uInt16 nChildrenOverall = 0; + + std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rEntry)); + bool bChildLoop = m_xTreeView->iter_children(*xChild); + while (bChildLoop) + { + TriState eChildState = implDetermineState(*xChild); + if (eChildState == TRISTATE_INDET) + break; + if (eChildState == TRISTATE_TRUE) + ++nCheckedChildren; + ++nChildrenOverall; + bChildLoop = m_xTreeView->iter_next_sibling(*xChild); + } + + if (bChildLoop) + { + // we did not finish the loop because at least one of the children is in tristate + eState = TRISTATE_INDET; + + // but this means that we did not finish all the siblings of pChildLoop, + // so their checking may be incorrect at the moment + // -> correct this + while (bChildLoop) + { + implDetermineState(*xChild); + bChildLoop = m_xTreeView->iter_next_sibling(*xChild); + } + } + else + { + // none if the children are in tristate + if (nCheckedChildren) + { + // we have at least one child checked + if (nCheckedChildren != nChildrenOverall) + { + // not all children are checked + eState = TRISTATE_INDET; + } + else + { + // all children are checked + eState = TRISTATE_TRUE; + } + } + else + { + // no children are checked + eState = TRISTATE_FALSE; + } + } + + // finally set the entry to the state we just determined + m_xTreeView->set_toggle(rEntry, eState); + + return eState; +} + +DBTableTreeView::DBTableTreeView(weld::Container* pContainer) + : DBTreeViewBase(pContainer) +{ + m_xTreeListBox.reset(new OTableTreeListBox(m_xBuilder->weld_tree_view("treeview"), /*bShowToggles*/false)); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/undosqledit.cxx b/dbaccess/source/ui/control/undosqledit.cxx new file mode 100644 index 000000000..00a5fd407 --- /dev/null +++ b/dbaccess/source/ui/control/undosqledit.cxx @@ -0,0 +1,34 @@ +/* -*- 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 <undosqledit.hxx> +#include <QueryTextView.hxx> + +namespace dbaui +{ +void OSqlEditUndoAct::ToggleText() +{ + OUString strNext = m_rOwner.GetSQLText(); + m_rOwner.SetSQLText(m_strNextText); + m_strNextText = strNext; +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/CollectionView.cxx b/dbaccess/source/ui/dlg/CollectionView.cxx new file mode 100644 index 000000000..2e02fda50 --- /dev/null +++ b/dbaccess/source/ui/dlg/CollectionView.cxx @@ -0,0 +1,316 @@ +/* -*- 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 <CollectionView.hxx> +#include <tools/diagnose_ex.h> +#include <core_resource.hxx> +#include <strings.hrc> +#include <comphelper/interaction.hxx> +#include <comphelper/propertysequence.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <o3tl/safeint.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <UITools.hxx> +#include <com/sun/star/container/XHierarchicalNameContainer.hpp> +#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> +#include <com/sun/star/ucb/IOErrorCode.hpp> +#include <com/sun/star/ucb/XDynamicResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/task/InteractionClassification.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <comphelper/processfactory.hxx> +#include <ucbhelper/commandenvironment.hxx> +#include <ucbhelper/content.hxx> +#include <connectivity/dbexception.hxx> + +namespace dbaui +{ + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::sdbc; +using namespace comphelper; + +OCollectionView::OCollectionView(weld::Window* pParent, + const Reference< XContent>& _xContent, + const OUString& _sDefaultName, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext) + : GenericDialogController(pParent, "dbaccess/ui/collectionviewdialog.ui", "CollectionView") + , m_xContent(_xContent) + , m_xContext(_rxContext) + , m_bCreateForm(true) + , m_xFTCurrentPath(m_xBuilder->weld_label("currentPathLabel")) + , m_xNewFolder(m_xBuilder->weld_button("newFolderButton")) + , m_xUp(m_xBuilder->weld_button("upButton")) + , m_xView(m_xBuilder->weld_tree_view("viewTreeview")) + , m_xName(m_xBuilder->weld_entry("fileNameEntry")) + , m_xPB_OK(m_xBuilder->weld_button("ok")) +{ + Reference<XInteractionHandler2> xHandler( + InteractionHandler::createWithParent(m_xContext, m_xDialog->GetXWindow())); + m_xCmdEnv = new ::ucbhelper::CommandEnvironment(xHandler, nullptr); + + OSL_ENSURE(m_xContent.is(),"No valid content!"); + m_xView->set_size_request(m_xView->get_approximate_digit_width() * 60, m_xView->get_height_rows(8)); + m_xView->make_sorted(); + Initialize(); + initCurrentPath(); + + m_xName->set_text(_sDefaultName); + m_xName->grab_focus(); + + m_xView->connect_row_activated( LINK( this, OCollectionView, Dbl_Click_FileView ) ); + m_xUp->connect_clicked( LINK( this, OCollectionView, Up_Click ) ); + m_xNewFolder->connect_clicked( LINK( this, OCollectionView, NewFolder_Click ) ); + m_xPB_OK->connect_clicked( LINK( this, OCollectionView, Save_Click ) ); +} + +OCollectionView::~OCollectionView() +{ +} + +IMPL_LINK_NOARG(OCollectionView, Save_Click, weld::Button&, void) +{ + OUString sName = m_xName->get_text(); + if (sName.isEmpty()) + return; + try + { + sal_Int32 nIndex = sName.lastIndexOf('/') + 1; + if ( nIndex ) + { + if ( nIndex == 1 ) // special handling for root + { + Reference<XChild> xChild(m_xContent,UNO_QUERY); + Reference<XNameAccess> xNameAccess(xChild,UNO_QUERY); + while( xNameAccess.is() ) + { + xNameAccess.set(xChild->getParent(),UNO_QUERY); + if ( xNameAccess.is() ) + { + m_xContent.set(xNameAccess,UNO_QUERY); + xChild.set(m_xContent,UNO_QUERY); + } + } + Initialize(); + initCurrentPath(); + } + OUString sSubFolder = sName.copy(0,nIndex-1); + sName = sName.copy(nIndex); + Reference<XHierarchicalNameContainer> xHier(m_xContent,UNO_QUERY); + OSL_ENSURE(xHier.is(),"XHierarchicalNameContainer not supported!"); + if ( !sSubFolder.isEmpty() && xHier.is() ) + { + if ( xHier->hasByHierarchicalName(sSubFolder) ) + { + m_xContent.set(xHier->getByHierarchicalName(sSubFolder),UNO_QUERY); + } + else // sub folder doesn't exist + { + Sequence<Any> aValues(comphelper::InitAnyPropertySequence( + { + {"ResourceName", Any(sSubFolder)}, + {"ResourceType", Any(OUString("folder"))} + })); + InteractiveAugmentedIOException aException(OUString(),Reference<XInterface>(), + InteractionClassification_ERROR, + IOErrorCode_NOT_EXISTING_PATH,aValues); + + Reference<XInteractionHandler2> xHandler( + InteractionHandler::createWithParent(m_xContext, m_xDialog->GetXWindow())); + rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(Any(aException)); + + rtl::Reference<OInteractionApprove> pApprove = new OInteractionApprove; + pRequest->addContinuation(pApprove); + xHandler->handle(pRequest); + + return; + } + } + } + Reference<XNameContainer> xNameContainer(m_xContent,UNO_QUERY); + if ( xNameContainer.is() ) + { + if ( xNameContainer->hasByName(sName) ) + { + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Question, VclButtonsType::YesNo, + DBA_RES(STR_ALREADYEXISTOVERWRITE))); + if (xQueryBox->run() != RET_YES) + return; + } + m_xName->set_text(sName); + m_xDialog->response(RET_OK); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +IMPL_LINK_NOARG(OCollectionView, NewFolder_Click, weld::Button&, void) +{ + try + { + Reference<XHierarchicalNameContainer> xNameContainer(m_xContent,UNO_QUERY); + if ( dbaui::insertHierarchyElement(m_xDialog.get(),m_xContext,xNameContainer,OUString(),m_bCreateForm) ) + Initialize(); + } + catch( const SQLException& ) + { + showError(::dbtools::SQLExceptionInfo(::cppu::getCaughtException()), m_xDialog->GetXWindow(), m_xContext); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +IMPL_LINK_NOARG(OCollectionView, Up_Click, weld::Button&, void) +{ + try + { + Reference<XChild> xChild(m_xContent,UNO_QUERY); + if ( xChild.is() ) + { + Reference<XNameAccess> xNameAccess(xChild->getParent(),UNO_QUERY); + if ( xNameAccess.is() ) + { + m_xContent.set(xNameAccess,UNO_QUERY); + Initialize(); + initCurrentPath(); + } + else + m_xUp->set_sensitive(false); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +IMPL_LINK_NOARG(OCollectionView, Dbl_Click_FileView, weld::TreeView&, bool) +{ + try + { + Reference<XNameAccess> xNameAccess(m_xContent,UNO_QUERY); + if ( xNameAccess.is() ) + { + OUString sSubFolder = m_xView->get_selected_text(); + if (!sSubFolder.isEmpty()) + { + Reference< XContent> xContent; + if ( xNameAccess->hasByName(sSubFolder) ) + xContent.set(xNameAccess->getByName(sSubFolder),UNO_QUERY); + if ( xContent.is() ) + { + m_xContent = xContent; + Initialize(); + initCurrentPath(); + } + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return true; +} + +void OCollectionView::initCurrentPath() +{ + bool bEnable = false; + try + { + if ( m_xContent.is() ) + { + const OUString sCID = m_xContent->getIdentifier()->getContentIdentifier(); + static const char s_sFormsCID[] = "private:forms"; + static const char s_sReportsCID[] = "private:reports"; + m_bCreateForm = s_sFormsCID == sCID; + OUString sPath("/"); + if ( m_bCreateForm && o3tl::make_unsigned(sCID.getLength()) != strlen(s_sFormsCID)) + sPath = sCID.copy(strlen(s_sFormsCID)); + else if ( !m_bCreateForm && o3tl::make_unsigned(sCID.getLength()) != strlen(s_sReportsCID) ) + sPath = sCID.copy(strlen(s_sReportsCID) - 2); + + m_xFTCurrentPath->set_label(sPath); + Reference<XChild> xChild(m_xContent,UNO_QUERY); + bEnable = xChild.is() && Reference<XNameAccess>(xChild->getParent(),UNO_QUERY).is(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + m_xUp->set_sensitive(bEnable); +} + +OUString OCollectionView::getName() const +{ + return m_xName->get_text(); +} + +#define ROW_TITLE 1 +#define ROW_IS_FOLDER 2 + +void OCollectionView::Initialize() +{ + weld::WaitObject aWaitCursor(m_xDialog.get()); + + m_xView->clear(); + + try + { + ::ucbhelper::Content aContent(m_xContent, m_xCmdEnv, comphelper::getProcessComponentContext()); + Sequence<OUString> aProps { "Title", "IsFolder" }; + auto xDynResultSet = aContent.createDynamicCursor(aProps, ucbhelper::INCLUDE_FOLDERS_ONLY); + if (!xDynResultSet.is()) + return; + + Reference<XResultSet> xResultSet = xDynResultSet->getStaticResultSet(); + Reference<XRow> xRow(xResultSet, UNO_QUERY); + while (xResultSet->next()) + { + if (!xRow->getBoolean(ROW_IS_FOLDER)) + continue; + m_xView->append_text(xRow->getString(ROW_TITLE)); + } + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/ConnectionHelper.cxx b/dbaccess/source/ui/dlg/ConnectionHelper.cxx new file mode 100644 index 000000000..6642d2895 --- /dev/null +++ b/dbaccess/source/ui/dlg/ConnectionHelper.cxx @@ -0,0 +1,720 @@ +/* -*- 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 <core_resource.hxx> +#include "dsnItem.hxx" +#include "ConnectionHelper.hxx" +#include <IItemSetHelper.hxx> +#include <strings.hrc> +#include <svl/itemset.hxx> +#include <unotools/moduleoptions.hxx> +#include <unotools/pathoptions.hxx> +#include <svl/stritem.hxx> +#include <dsitems.hxx> +#include <osl/diagnose.h> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <sfx2/filedlghelper.hxx> +#include <vcl/stdtext.hxx> +#include <sqlmessage.hxx> +#include "dsselect.hxx" +#include <svl/filenotation.hxx> +#include <com/sun/star/awt/XSystemDependentWindowPeer.hpp> +#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/lang/SystemDependent.hpp> +#include <com/sun/star/mozilla/MozillaBootstrap.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/ucb/XProgressHandler.hpp> +#include <ucbhelper/commandenvironment.hxx> +#include <ucbhelper/content.hxx> +#include "finteraction.hxx" +#include <tools/urlobj.hxx> +#include <tools/diagnose_ex.h> + +#if defined _WIN32 +#include <rtl/process.h> +#include <vcl/sysdata.hxx> +#include "adodatalinks.hxx" +#endif + +#include <com/sun/star/mozilla/XMozillaBootstrap.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/string.hxx> + +namespace dbaui +{ + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::ucb; + using namespace ::com::sun::star::ui::dialogs; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::mozilla; + using namespace ::dbtools; + using namespace ::svt; + + OConnectionHelper::OConnectionHelper(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const OString& _rId, const SfxItemSet& _rCoreAttrs) + : OGenericAdministrationPage(pPage, pController, _rUIXMLDescription, _rId, _rCoreAttrs) + , m_bUserGrabFocus(false) + , m_pCollection(nullptr) + , m_xFT_Connection(m_xBuilder->weld_label("browseurllabel")) + , m_xPB_Connection(m_xBuilder->weld_button("browse")) + , m_xPB_CreateDB(m_xBuilder->weld_button("create")) + , m_xConnectionURL(new OConnectionURLEdit(m_xBuilder->weld_entry("browseurl"), m_xBuilder->weld_label("browselabel"))) + { + // extract the datasource type collection from the item set + const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>( _rCoreAttrs.GetItem(DSID_TYPECOLLECTION) ); + if (pCollectionItem) + m_pCollection = pCollectionItem->getCollection(); + m_xPB_Connection->connect_clicked(LINK(this, OConnectionHelper, OnBrowseConnections)); + m_xPB_CreateDB->connect_clicked(LINK(this, OConnectionHelper, OnCreateDatabase)); + OSL_ENSURE(m_pCollection, "OConnectionHelper::OConnectionHelper : really need a DSN type collection !"); + m_xConnectionURL->SetTypeCollection(m_pCollection); + + m_xConnectionURL->connect_focus_in(LINK(this, OConnectionHelper, GetFocusHdl)); + m_xConnectionURL->connect_focus_out(LINK(this, OConnectionHelper, LoseFocusHdl)); + } + + OConnectionHelper::~OConnectionHelper() + { + m_xConnectionURL.reset(); + } + + void OConnectionHelper::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + m_xFT_Connection->show(); + m_xConnectionURL->show(); + m_xConnectionURL->ShowPrefix( ::dbaccess::DST_JDBC == m_pCollection->determineType(m_eType) ); + + bool bEnableBrowseButton = m_pCollection->supportsBrowsing( m_eType ); + m_xPB_Connection->set_visible( bEnableBrowseButton ); + + bool bEnableCreateButton = m_pCollection->supportsDBCreation( m_eType ); + m_xPB_CreateDB->set_visible( bEnableCreateButton ); + + const SfxStringItem* pUrlItem = _rSet.GetItem<SfxStringItem>(DSID_CONNECTURL); + + // forward the values to the controls + if ( bValid ) + { + OUString sUrl = pUrlItem->GetValue(); + setURL( sUrl ); + + checkTestConnection(); + m_xConnectionURL->save_value(); + } + + OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue); + } + + void OConnectionHelper::implUpdateURLDependentStates() const + { + OSL_PRECOND( m_pAdminDialog && m_pCollection, "OConnectionHelper::implUpdateURLDependentStates: no admin dialog!" ); + if ( !m_pAdminDialog || !m_pCollection ) + return; + + if ( m_pCollection->isFileSystemBased(m_eType) ) + m_pAdminDialog->enableConfirmSettings( !getURLNoPrefix().isEmpty() ); + } + + IMPL_LINK_NOARG(OConnectionHelper, OnBrowseConnections, weld::Button&, void) + { + OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF"); + const ::dbaccess::DATASOURCE_TYPE eType = m_pCollection->determineType(m_eType); + switch ( eType ) + { + case ::dbaccess::DST_DBASE: + case ::dbaccess::DST_FLAT: + { + try + { + Reference< XFolderPicker2 > xFolderPicker = sfx2::createFolderPicker(m_xORB, GetFrameWeld()); + + bool bDoBrowse = false; + OUString sOldPath = getURLNoPrefix(); + do + { + if (!sOldPath.isEmpty()) + xFolderPicker->setDisplayDirectory(sOldPath); + if (0 == xFolderPicker->execute()) + // cancelled by the user + return; + + sOldPath = xFolderPicker->getDirectory(); + switch (checkPathExistence(sOldPath)) + { + case RET_RETRY: + bDoBrowse = true; + break; + case RET_CANCEL: + return; + default: + break; + } + } + while (bDoBrowse); + + OUString sSelectedDirectory = xFolderPicker->getDirectory(); + INetURLObject aSelectedDirectory( sSelectedDirectory, INetURLObject::EncodeMechanism::WasEncoded, RTL_TEXTENCODING_UTF8 ); + + // for UI purpose, we don't want to have the path encoded + sSelectedDirectory = aSelectedDirectory.GetMainURL( INetURLObject::DecodeMechanism::WithCharset ); + + setURLNoPrefix( sSelectedDirectory ); + SetRoadmapStateValue(true); + callModifiedHdl(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + break; + case ::dbaccess::DST_CALC: + { + SvtModuleOptions aModule; + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION, + FileDialogFlags::NONE, + aModule.GetFactoryEmptyDocumentURL(SvtModuleOptions::EFactory::CALC) + ,SfxFilterFlags::IMPORT, SfxFilterFlags::NONE, GetFrameWeld()); + askForFileName(aFileDlg); + } + break; + case ::dbaccess::DST_WRITER: + { + SvtModuleOptions aModule; + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION, + FileDialogFlags::NONE, + aModule.GetFactoryEmptyDocumentURL(SvtModuleOptions::EFactory::WRITER), + SfxFilterFlags::IMPORT, SfxFilterFlags::NONE, GetFrameWeld()); + askForFileName(aFileDlg); + } + break; + case ::dbaccess::DST_MSACCESS: + { + OUString sFilterName(DBA_RES (STR_MSACCESS_FILTERNAME)); + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION, + FileDialogFlags::NONE, GetFrameWeld()); + aFileDlg.AddFilter(sFilterName,"*.mdb;*.mde"); + aFileDlg.SetCurrentFilter(sFilterName); + askForFileName(aFileDlg); + } + break; + case ::dbaccess::DST_MSACCESS_2007: + { + OUString sFilterName2(DBA_RES (STR_MSACCESS_2007_FILTERNAME)); + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION, + FileDialogFlags::NONE, GetFrameWeld()); + aFileDlg.AddFilter(sFilterName2,"*.accdb;*.accde"); + aFileDlg.SetCurrentFilter(sFilterName2); + askForFileName(aFileDlg); + } + break; + case ::dbaccess::DST_MYSQL_ODBC: + case ::dbaccess::DST_ODBC: + { + // collect all ODBC data source names + OUString sCurrDatasource = getURLNoPrefix(); + OUString sDataSource; + if ( getSelectedDataSource(sDataSource,sCurrDatasource) && !sDataSource.isEmpty() ) + { + setURLNoPrefix(sDataSource); + SetRoadmapStateValue(true); + callModifiedHdl(); + } + else + return; + } + break; +#if defined _WIN32 + case ::dbaccess::DST_ADO: + { + OUString sOldDataSource=getURLNoPrefix(); + OUString sNewDataSource; + HWND hWnd = nullptr; + + weld::Window* pDialog = GetFrameWeld(); + css::uno::Reference<css::awt::XSystemDependentWindowPeer> xSysDepWin(pDialog->GetXWindow(), css::uno::UNO_QUERY); + if (xSysDepWin.is()) + { + css::uno::Sequence<sal_Int8> aProcessIdent(16); + rtl_getGlobalProcessId(reinterpret_cast<sal_uInt8*>(aProcessIdent.getArray())); + css::uno::Any aAny = xSysDepWin->getWindowHandle(aProcessIdent, css::lang::SystemDependent::SYSTEM_WIN32); + sal_Int64 tmp(0); + aAny >>= tmp; + hWnd = reinterpret_cast<HWND>(tmp); + } + + sNewDataSource = getAdoDatalink(reinterpret_cast<sal_IntPtr>(hWnd),sOldDataSource); + if ( !sNewDataSource.isEmpty() ) + { + setURLNoPrefix(sNewDataSource); + SetRoadmapStateValue(true); + callModifiedHdl(); + } + } + break; +#endif + case ::dbaccess::DST_MOZILLA: + case ::dbaccess::DST_THUNDERBIRD: + { + MozillaProductType profileType = MozillaProductType_Mozilla; + if (eType == ::dbaccess::DST_THUNDERBIRD) + profileType = MozillaProductType_Thunderbird; + + Reference<XComponentContext> xContext = ::comphelper::getProcessComponentContext(); + Reference<XMozillaBootstrap> xMozillaBootstrap = MozillaBootstrap::create(xContext); + + // collect all Mozilla Profiles + css::uno::Sequence< OUString > list; + + xMozillaBootstrap->getProfileList( profileType, list ); + const OUString * pArray = list.getConstArray(); + + sal_Int32 count = list.getLength(); + + std::set<OUString> aProfiles; + for (sal_Int32 index=0; index < count; index++) + aProfiles.insert(pArray[index]); + + // execute the select dialog + ODatasourceSelectDialog aSelector(GetFrameWeld(), aProfiles); + OUString sOldProfile=getURLNoPrefix(); + + if (!sOldProfile.isEmpty()) + aSelector.Select(sOldProfile); + else + aSelector.Select(xMozillaBootstrap->getDefaultProfile(profileType)); + + if (RET_OK == aSelector.run()) + setURLNoPrefix(aSelector.GetSelected()); + break; + } + case ::dbaccess::DST_FIREBIRD: + { + OUString sFilterName(DBA_RES (STR_FIREBIRD_FILTERNAME)); + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, GetFrameWeld()); + aFileDlg.AddFilter(sFilterName,"*.fdb"); + aFileDlg.SetCurrentFilter(sFilterName); + askForFileName(aFileDlg); + break; + } + default: + break; + } + + checkTestConnection(); + } + + IMPL_LINK_NOARG(OConnectionHelper, OnCreateDatabase, weld::Button&, void) + { + OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF"); + const ::dbaccess::DATASOURCE_TYPE eType = m_pCollection->determineType(m_eType); + switch ( eType ) + { + case ::dbaccess::DST_FIREBIRD: + { + OUString sFilterName(DBA_RES (STR_FIREBIRD_FILTERNAME)); + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION, + FileDialogFlags::NONE, GetFrameWeld()); + aFileDlg.AddFilter(sFilterName,"*.fdb"); + aFileDlg.SetCurrentFilter(sFilterName); + askForFileName(aFileDlg); + break; + } + default: + break; + } + + checkTestConnection(); + } + + bool OConnectionHelper::checkTestConnection() + { + return true; + } + + void OConnectionHelper::impl_setURL( std::u16string_view _rURL, bool _bPrefix ) + { + OUString sURL( comphelper::string::stripEnd(_rURL, '*') ); + OSL_ENSURE( m_pCollection, "OConnectionHelper::impl_setURL: have no interpreter for the URLs!" ); + + if ( m_pCollection && !sURL.isEmpty() ) + { + if ( m_pCollection->isFileSystemBased( m_eType ) ) + { + // get the two parts: prefix and file URL + OUString sTypePrefix, sFileURLEncoded; + if ( _bPrefix ) + { + sTypePrefix = m_pCollection->getPrefix( m_eType ); + sFileURLEncoded = m_pCollection->cutPrefix( sURL ); + } + else + { + sFileURLEncoded = sURL; + } + + // substitute any variables + sFileURLEncoded = SvtPathOptions().SubstituteVariable( sFileURLEncoded ); + + // decode the URL + sURL = sTypePrefix; + if ( !sFileURLEncoded.isEmpty() ) + { + OFileNotation aFileNotation(sFileURLEncoded); + // set this decoded URL as text + sURL += aFileNotation.get(OFileNotation::N_SYSTEM); + } + } + } + + if ( _bPrefix ) + m_xConnectionURL->SetText( sURL ); + else + m_xConnectionURL->SetTextNoPrefix( sURL ); + + implUpdateURLDependentStates(); + } + + OUString OConnectionHelper::impl_getURL() const + { + // get the pure text + OUString sURL = m_xConnectionURL->GetTextNoPrefix(); + + OSL_ENSURE( m_pCollection, "OConnectionHelper::impl_getURL: have no interpreter for the URLs!" ); + + if ( m_pCollection && !sURL.isEmpty() ) + { + if ( m_pCollection->isFileSystemBased( m_eType ) ) + { + // get the two parts: prefix and file URL + OUString sFileURLDecoded = sURL; + + sURL = OUString(); + if ( !sFileURLDecoded.isEmpty() ) + { + OFileNotation aFileNotation( sFileURLDecoded, OFileNotation::N_SYSTEM ); + sURL += aFileNotation.get( OFileNotation::N_URL ); + } + + // encode the URL + INetURLObject aFileURL( sFileURLDecoded, INetURLObject::EncodeMechanism::All, RTL_TEXTENCODING_UTF8 ); + sFileURLDecoded = aFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + } + } + return sURL; + } + + void OConnectionHelper::setURL( std::u16string_view _rURL ) + { + impl_setURL( _rURL, true ); + } + + OUString OConnectionHelper::getURLNoPrefix( ) const + { + return impl_getURL(); + } + + void OConnectionHelper::setURLNoPrefix( std::u16string_view _rURL ) + { + impl_setURL( _rURL, false ); + } + + sal_Int32 OConnectionHelper::checkPathExistence(const OUString& _rURL) + { + IS_PATH_EXIST e_exists = pathExists(_rURL, false); + if (!m_pCollection->supportsDBCreation(m_eType) && + (( e_exists == PATH_NOT_EXIST) || ( e_exists == PATH_NOT_KNOWN))) + { + OUString sQuery(DBA_RES(STR_ASK_FOR_DIRECTORY_CREATION)); + OFileNotation aTransformer(_rURL); + sQuery = sQuery.replaceFirst("$path$", aTransformer.get(OFileNotation::N_SYSTEM)); + + m_bUserGrabFocus = false; + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + sQuery)); + xQueryBox->set_default_response(RET_YES); + sal_Int32 nQueryResult = xQueryBox->run(); + m_bUserGrabFocus = true; + + switch (nQueryResult) + { + case RET_YES: + { + bool bTryCreate = false; + do + { + if ( !createDirectoryDeep(_rURL) ) + { // could not create the directory + sQuery = DBA_RES(STR_COULD_NOT_CREATE_DIRECTORY); + sQuery = sQuery.replaceFirst("$name$", aTransformer.get(OFileNotation::N_SYSTEM)); + + m_bUserGrabFocus = false; + + std::unique_ptr<weld::MessageDialog> xWhatToDo(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Question, VclButtonsType::NONE, + sQuery)); + xWhatToDo->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY); + xWhatToDo->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL); + xWhatToDo->set_default_response(RET_RETRY); + nQueryResult = xWhatToDo->run(); + m_bUserGrabFocus = true; + + if (RET_RETRY == nQueryResult) + bTryCreate = true; + else + { + SetRoadmapStateValue(false); + callModifiedHdl(); + return RET_RETRY; + } + } + } + while (bTryCreate); + } + break; + + case RET_NO: + callModifiedHdl(); + return RET_OK; + + default: + // cancelled + SetRoadmapStateValue(false); + callModifiedHdl(); + return RET_CANCEL; + } + } +/* else + { + // TODO: error msg + return RET_CANCEL; + } */ + SetRoadmapStateValue(true); + callModifiedHdl(); + return RET_OK; + } + + IS_PATH_EXIST OConnectionHelper::pathExists(const OUString& _rURL, bool bIsFile) const + { + ::ucbhelper::Content aCheckExistence; + IS_PATH_EXIST eExists = PATH_NOT_EXIST; + Reference< css::task::XInteractionHandler > xInteractionHandler = + task::InteractionHandler::createWithParent(m_xORB, nullptr); + rtl::Reference<OFilePickerInteractionHandler> pHandler = new OFilePickerInteractionHandler(xInteractionHandler); + xInteractionHandler = pHandler; + + Reference< XCommandEnvironment > xCmdEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, Reference< XProgressHandler >() ); + try + { + aCheckExistence = ::ucbhelper::Content(_rURL, xCmdEnv, comphelper::getProcessComponentContext()); + const bool bExists = bIsFile? aCheckExistence.isDocument(): aCheckExistence.isFolder(); + eExists = bExists? PATH_EXIST: PATH_NOT_EXIST; + } + catch (const Exception&) + { + eExists = pHandler->isDoesNotExist() ? PATH_NOT_EXIST : (bIsFile ? PATH_NOT_EXIST : PATH_NOT_KNOWN); + } + return eExists; + } + + IMPL_LINK_NOARG(OConnectionHelper, GetFocusHdl, weld::Widget&, void) + { + if (!m_pCollection->isFileSystemBased(m_eType)) + return; + if (!m_bUserGrabFocus) + return; + // URL edit field got the focus + m_xConnectionURL->SaveValueNoPrefix(); + } + + IMPL_LINK_NOARG(OConnectionHelper, LoseFocusHdl, weld::Widget&, void) + { + if (!m_pCollection->isFileSystemBased(m_eType)) + return; + if (!m_bUserGrabFocus) + return; + // URL edit field lost the focus + commitURL(); + } + + bool OConnectionHelper::createDirectoryDeep(std::u16string_view _rPathURL) + { + // get a URL object analyzing the URL for us ... + INetURLObject aParser; + aParser.SetURL(_rPathURL); + + INetProtocol eProtocol = aParser.GetProtocol(); + + std::vector< OUString > aToBeCreated; // the to-be-created levels + + // search a level which exists + IS_PATH_EXIST eParentExists = PATH_NOT_EXIST; + while ( eParentExists == PATH_NOT_EXIST && aParser.getSegmentCount()) + { + aToBeCreated.push_back(aParser.getName()); // remember the local name for creation + aParser.removeSegment(); // cut the local name + eParentExists = pathExists(aParser.GetMainURL(INetURLObject::DecodeMechanism::NONE), false); + } + + if (!aParser.getSegmentCount()) + return false; + + // create all the missing levels + try + { + // the parent content + Reference< XCommandEnvironment > xEmptyEnv; + ::ucbhelper::Content aParent(aParser.GetMainURL(INetURLObject::DecodeMechanism::NONE), xEmptyEnv, comphelper::getProcessComponentContext()); + + OUString sContentType; + if ( INetProtocol::File == eProtocol ) + { + sContentType = "application/vnd.sun.staroffice.fsys-folder"; + // the file UCP currently does not support the ContentType property + } + else + { + Any aContentType = aParent.getPropertyValue("ContentType"); + aContentType >>= sContentType; + } + + // the properties which need to be set on the new content + Sequence< OUString > aNewDirectoryProperties { "Title" }; + + // loop + for ( std::vector< OUString >::const_reverse_iterator aLocalName = aToBeCreated.rbegin(); + aLocalName != aToBeCreated.rend(); + ++aLocalName + ) + { + // the values to be set + Sequence< Any > aNewDirectoryAttributes{ Any(* aLocalName) }; + if (!aParent.insertNewContent(sContentType, aNewDirectoryProperties, aNewDirectoryAttributes, aParent)) + return false; + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + return false; + } + + return true; + } + + void OConnectionHelper::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFT_Connection.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Button>(m_xPB_Connection.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Button>(m_xPB_CreateDB.get())); + } + + void OConnectionHelper::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back( new OSaveValueWidgetWrapper<OConnectionURLEdit>( m_xConnectionURL.get() ) ); + } + + bool OConnectionHelper::commitURL() + { + OUString sOldPath = m_xConnectionURL->GetSavedValueNoPrefix(); + OUString sURL = m_xConnectionURL->GetTextNoPrefix(); + + if ( m_pCollection->isFileSystemBased(m_eType) ) + { + if ( ( sURL != sOldPath ) && !sURL.isEmpty() ) + { // the text changed since entering the control + + // the path may be in system notation... + OFileNotation aTransformer(sURL); + sURL = aTransformer.get(OFileNotation::N_URL); + + const ::dbaccess::DATASOURCE_TYPE eType = m_pCollection->determineType(m_eType); + + if ( ( ::dbaccess::DST_CALC == eType) || ( ::dbaccess::DST_WRITER == eType) || ( ::dbaccess::DST_MSACCESS == eType) || ( ::dbaccess::DST_MSACCESS_2007 == eType) ) + { + if( pathExists(sURL, true) == PATH_NOT_EXIST ) + { + OUString sFile = DBA_RES( STR_FILE_DOES_NOT_EXIST ); + sFile = sFile.replaceFirst("$file$", aTransformer.get(OFileNotation::N_SYSTEM)); + OSQLWarningBox aWarning(GetFrameWeld(), sFile); + aWarning.run(); + setURLNoPrefix(sOldPath); + SetRoadmapStateValue(false); + callModifiedHdl(); + return false; + } + } + else + { + switch (checkPathExistence(sURL)) + { + case RET_RETRY: + m_bUserGrabFocus = false; + m_xConnectionURL->grab_focus(); + m_bUserGrabFocus = true; + return false; + + case RET_CANCEL: + setURLNoPrefix(sOldPath); + return false; + } + } + } + } + + setURLNoPrefix(sURL); + m_xConnectionURL->SaveValueNoPrefix(); + return true; + } + + void OConnectionHelper::askForFileName(::sfx2::FileDialogHelper& _aFileOpen) + { + OUString sOldPath = getURLNoPrefix(); + if ( !sOldPath.isEmpty() ) + _aFileOpen.SetDisplayDirectory(sOldPath); + else + _aFileOpen.SetDisplayDirectory( SvtPathOptions().GetWorkPath() ); + if (ERRCODE_NONE == _aFileOpen.Execute()) + { + setURLNoPrefix(_aFileOpen.GetPath()); + SetRoadmapStateValue(checkTestConnection()); + callModifiedHdl(); + } + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/ConnectionHelper.hxx b/dbaccess/source/ui/dlg/ConnectionHelper.hxx new file mode 100644 index 000000000..b4c00548f --- /dev/null +++ b/dbaccess/source/ui/dlg/ConnectionHelper.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 "adminpages.hxx" +#include <curledit.hxx> +#include <sfx2/filedlghelper.hxx> + +namespace dbaui +{ + + enum IS_PATH_EXIST + { + PATH_NOT_EXIST = 0, + PATH_EXIST, + PATH_NOT_KNOWN + }; + + class OConnectionHelper : public OGenericAdministrationPage + { + bool m_bUserGrabFocus; + + public: + OConnectionHelper(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const OString& _rId, const SfxItemSet& _rCoreAttrs); + virtual ~OConnectionHelper() override; + + OUString m_eType; // the type can't be changed in this class, so we hold it as member. + // setting/retrieving the current connection URL + // necessary because for some types, the URL must be decoded for display purposes + ::dbaccess::ODsnTypeCollection* m_pCollection; /// the DSN type collection instance + + std::unique_ptr<weld::Label> m_xFT_Connection; + std::unique_ptr<weld::Button> m_xPB_Connection; + std::unique_ptr<weld::Button> m_xPB_CreateDB; + std::unique_ptr<OConnectionURLEdit> m_xConnectionURL; + + public: + + // <method>OGenericAdministrationPage::fillControls</method> + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + // <method>OGenericAdministrationPage::fillWindows</method> + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + + // setting/retrieving the current connection URL + // necessary because for some types, the URL must be decoded for display purposes + //String getURL( OConnectionURLEdit* _m_pConnection ) const; + //void setURL( const OUString& _rURL, OConnectionURLEdit* _m_pConnection ); + + OUString getURLNoPrefix( ) const; + void setURLNoPrefix( std::u16string_view _rURL ); + + /** checks if the path is existence + @param _rURL + The URL to check. + */ + sal_Int32 checkPathExistence(const OUString& _rURL); + + IS_PATH_EXIST pathExists(const OUString& _rURL, bool bIsFile) const; + bool createDirectoryDeep(std::u16string_view _rPathNormalized); + bool commitURL(); + + /** opens the FileOpen dialog and asks for a FileName + @param _aFileOpen + Executes the file open dialog, which must be filled from caller. + */ + void askForFileName(::sfx2::FileDialogHelper& _aFileOpen); + + protected: + void setURL( std::u16string_view _rURL ); + virtual bool checkTestConnection(); + + private: + DECL_LINK(OnBrowseConnections, weld::Button&, void); + DECL_LINK(OnCreateDatabase, weld::Button&, void); + DECL_LINK(GetFocusHdl, weld::Widget&, void); + DECL_LINK(LoseFocusHdl, weld::Widget&, void); + OUString impl_getURL() const; + void impl_setURL( std::u16string_view _rURL, bool _bPrefix ); + void implUpdateURLDependentStates() const; + }; + + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/ConnectionPage.cxx b/dbaccess/source/ui/dlg/ConnectionPage.cxx new file mode 100644 index 000000000..7ff32140e --- /dev/null +++ b/dbaccess/source/ui/dlg/ConnectionPage.cxx @@ -0,0 +1,284 @@ +/* -*- 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 <config_java.h> +#include "ConnectionPage.hxx" +#include <core_resource.hxx> +#include <IItemSetHelper.hxx> +#include <strings.hrc> +#include <dsmeta.hxx> +#if HAVE_FEATURE_JAVA +#include <jvmaccess/virtualmachine.hxx> +#endif +#include <svl/itemset.hxx> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> +#include <dsitems.hxx> +#include <helpids.h> +#include <sqlmessage.hxx> +#include <svl/filenotation.hxx> +#include <com/sun/star/ucb/XProgressHandler.hpp> +#include <connectivity/CommonTools.hxx> +#include <o3tl/string_view.hxx> + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::ucb; + using namespace ::com::sun::star::ui::dialogs; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::container; + using namespace ::dbtools; + using namespace ::svt; + + std::unique_ptr<SfxTabPage> OConnectionTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet) + { + return std::make_unique<OConnectionTabPage>(pPage, pController, *_rAttrSet); + } + + // OConnectionTabPage + OConnectionTabPage::OConnectionTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs) + : OConnectionHelper(pPage, pController, "dbaccess/ui/connectionpage.ui", "ConnectionPage", _rCoreAttrs) + , m_xFL2(m_xBuilder->weld_label("userlabel")) + , m_xUserNameLabel(m_xBuilder->weld_label("userNameLabel")) + , m_xUserName(m_xBuilder->weld_entry("userNameEntry")) + , m_xPasswordRequired(m_xBuilder->weld_check_button("passCheckbutton")) + , m_xFL3(m_xBuilder->weld_label("JDBCLabel")) + , m_xJavaDriverLabel(m_xBuilder->weld_label("javaDriverLabel")) + , m_xJavaDriver(m_xBuilder->weld_entry("driverEntry")) + , m_xTestJavaDriver(m_xBuilder->weld_button("driverButton")) + , m_xTestConnection(m_xBuilder->weld_button("connectionButton")) + { + m_xConnectionURL->connect_changed(LINK(this, OConnectionTabPage, OnEditModified)); + m_xJavaDriver->connect_changed(LINK(this, OConnectionTabPage, OnEditModified)); + m_xUserName->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl)); + m_xPasswordRequired->connect_toggled(LINK(this, OGenericAdministrationPage, OnControlModifiedButtonClick)); + + m_xTestConnection->connect_clicked(LINK(this,OGenericAdministrationPage,OnTestConnectionButtonClickHdl)); + m_xTestJavaDriver->connect_clicked(LINK(this,OConnectionTabPage,OnTestJavaClickHdl)); + } + + OConnectionTabPage::~OConnectionTabPage() + { + } + + void OConnectionTabPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + m_eType = m_pAdminDialog->getDatasourceType(_rSet); + OConnectionHelper::implInitControls( _rSet, _bSaveValue); + + ::dbaccess::DATASOURCE_TYPE eType = m_pCollection->determineType(m_eType); + switch( eType ) + { + case ::dbaccess::DST_DBASE: + m_xFT_Connection->set_label(DBA_RES(STR_DBASE_PATH_OR_FILE)); + m_xConnectionURL->set_help_id(HID_DSADMIN_DBASE_PATH); + break; + case ::dbaccess::DST_FLAT: + m_xFT_Connection->set_label(DBA_RES(STR_FLAT_PATH_OR_FILE)); + m_xConnectionURL->set_help_id(HID_DSADMIN_FLAT_PATH); + break; + case ::dbaccess::DST_CALC: + m_xFT_Connection->set_label(DBA_RES(STR_CALC_PATH_OR_FILE)); + m_xConnectionURL->set_help_id(HID_DSADMIN_CALC_PATH); + break; + case ::dbaccess::DST_WRITER: + m_xFT_Connection->set_label(DBA_RES(STR_WRITER_PATH_OR_FILE)); + m_xConnectionURL->set_help_id(HID_DSADMIN_WRITER_PATH); + break; + case ::dbaccess::DST_ADO: + m_xFT_Connection->set_label(DBA_RES(STR_COMMONURL)); + break; + case ::dbaccess::DST_MSACCESS: + case ::dbaccess::DST_MSACCESS_2007: + m_xFT_Connection->set_label(DBA_RES(STR_MSACCESS_MDB_FILE)); + m_xConnectionURL->set_help_id(HID_DSADMIN_MSACCESS_MDB_FILE); + break; + case ::dbaccess::DST_MYSQL_NATIVE: + case ::dbaccess::DST_MYSQL_JDBC: + m_xFT_Connection->set_label(DBA_RES(STR_MYSQL_DATABASE_NAME)); + m_xConnectionURL->set_help_id( HID_DSADMIN_MYSQL_DATABASE ); + break; + case ::dbaccess::DST_ORACLE_JDBC: + m_xFT_Connection->set_label(DBA_RES(STR_ORACLE_DATABASE_NAME)); + m_xConnectionURL->set_help_id(HID_DSADMIN_ORACLE_DATABASE); + break; + case ::dbaccess::DST_MYSQL_ODBC: + case ::dbaccess::DST_ODBC: + m_xFT_Connection->set_label(DBA_RES(STR_NAME_OF_ODBC_DATASOURCE)); + m_xConnectionURL->set_help_id( eType == ::dbaccess::DST_MYSQL_ODBC ? OString(HID_DSADMIN_MYSQL_ODBC_DATASOURCE) : OString(HID_DSADMIN_ODBC_DATASOURCE)); + break; + case ::dbaccess::DST_LDAP: + m_xFT_Connection->set_label(DBA_RES(STR_HOSTNAME)); + m_xConnectionURL->set_help_id( HID_DSADMIN_LDAP_HOSTNAME ); + break; + case ::dbaccess::DST_MOZILLA: + m_xFT_Connection->set_label(DBA_RES(STR_MOZILLA_PROFILE_NAME)); + m_xConnectionURL->set_help_id( HID_DSADMIN_MOZILLA_PROFILE_NAME ); + break; + case ::dbaccess::DST_THUNDERBIRD: + m_xFT_Connection->set_label(DBA_RES(STR_THUNDERBIRD_PROFILE_NAME)); + m_xConnectionURL->set_help_id( HID_DSADMIN_THUNDERBIRD_PROFILE_NAME ); + break; + case ::dbaccess::DST_OUTLOOK: + case ::dbaccess::DST_OUTLOOKEXP: + case ::dbaccess::DST_EVOLUTION: + case ::dbaccess::DST_EVOLUTION_GROUPWISE: + case ::dbaccess::DST_EVOLUTION_LDAP: + case ::dbaccess::DST_KAB: + case ::dbaccess::DST_MACAB: + m_xFT_Connection->set_label(DBA_RES(STR_NO_ADDITIONAL_SETTINGS)); + { + OUString sText = m_xFT_Connection->get_label(); + sText = sText.replaceAll("%test",m_xTestConnection->get_label()); + sText = sText.replaceAll("~",""); + m_xFT_Connection->set_label(sText); + } + m_xConnectionURL->hide(); + break; + case ::dbaccess::DST_JDBC: + default: + m_xFT_Connection->set_label(DBA_RES(STR_COMMONURL)); + break; + } + + AuthenticationMode eAuthMode( DataSourceMetaData::getAuthentication( m_eType ) ); + bool bShowUserAuthenfication = ( eAuthMode != AuthNone ); + bool bShowUser = ( eAuthMode == AuthUserPwd ); + + m_xPB_Connection->set_help_id(HID_DSADMIN_BROWSECONN); + m_xFL2->set_visible( bShowUserAuthenfication ); + m_xUserNameLabel->set_visible( bShowUser && bShowUserAuthenfication ); + m_xUserName->set_visible( bShowUser && bShowUserAuthenfication ); + m_xPasswordRequired->set_visible( bShowUserAuthenfication ); + + // collect the items + const SfxStringItem* pUidItem = _rSet.GetItem<SfxStringItem>(DSID_USER); + + const SfxStringItem* pJdbcDrvItem = _rSet.GetItem<SfxStringItem>(DSID_JDBCDRIVERCLASS); + const SfxStringItem* pUrlItem = _rSet.GetItem<SfxStringItem>(DSID_CONNECTURL); + const SfxBoolItem* pAllowEmptyPwd = _rSet.GetItem<SfxBoolItem>(DSID_PASSWORDREQUIRED); + + // forward the values to the controls + if ( !bValid ) + return; + + m_xUserName->set_text(pUidItem->GetValue()); + m_xPasswordRequired->set_active(pAllowEmptyPwd->GetValue()); + + const OUString& sUrl = pUrlItem->GetValue(); + setURL( sUrl ); + + const bool bEnableJDBC = m_pCollection->determineType(m_eType) == ::dbaccess::DST_JDBC; + if ( !pJdbcDrvItem->GetValue().getLength() ) + { + OUString sDefaultJdbcDriverName = m_pCollection->getJavaDriverClass(m_eType); + if ( !sDefaultJdbcDriverName.isEmpty() ) + m_xJavaDriver->set_text(sDefaultJdbcDriverName); + } + else + m_xJavaDriver->set_text(pJdbcDrvItem->GetValue()); + + m_xJavaDriverLabel->set_visible(bEnableJDBC); + m_xJavaDriver->set_visible(bEnableJDBC); + m_xTestJavaDriver->set_visible(bEnableJDBC); + m_xTestJavaDriver->set_sensitive( !m_xJavaDriver->get_text().trim().isEmpty() ); + m_xFL3->set_visible(bEnableJDBC); + + checkTestConnection(); + + m_xUserName->save_value(); + m_xConnectionURL->save_value(); + m_xJavaDriver->save_value(); + m_xPasswordRequired->save_state(); + } + + bool OConnectionTabPage::FillItemSet(SfxItemSet* _rSet) + { + bool bChangedSomething = false; + + if (m_xUserName->get_value_changed_from_saved()) + { + _rSet->Put(SfxStringItem(DSID_USER, m_xUserName->get_text())); + _rSet->Put(SfxStringItem(DSID_PASSWORD, OUString())); + bChangedSomething = true; + } + + fillBool(*_rSet,m_xPasswordRequired.get(),DSID_PASSWORDREQUIRED,false, bChangedSomething); + + if ( m_pCollection->determineType(m_eType) == ::dbaccess::DST_JDBC ) + { + fillString(*_rSet,m_xJavaDriver.get(), DSID_JDBCDRIVERCLASS, bChangedSomething); + } + + fillString(*_rSet,m_xConnectionURL.get(), DSID_CONNECTURL, bChangedSomething); + + return bChangedSomething; + } + IMPL_LINK_NOARG(OConnectionTabPage, OnTestJavaClickHdl, weld::Button&, void) + { + OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF"); + bool bSuccess = false; +#if HAVE_FEATURE_JAVA + try + { + if ( !m_xJavaDriver->get_text().trim().isEmpty() ) + { + ::rtl::Reference< jvmaccess::VirtualMachine > xJVM = ::connectivity::getJavaVM( m_pAdminDialog->getORB() ); + m_xJavaDriver->set_text(m_xJavaDriver->get_text().trim()); // fdo#68341 + bSuccess = ::connectivity::existsJavaClassByName(xJVM, o3tl::trim(m_xJavaDriver->get_text())); + } + } + catch(Exception&) + { + } +#endif + + TranslateId pMessage = bSuccess ? STR_JDBCDRIVER_SUCCESS : STR_JDBCDRIVER_NO_SUCCESS; + const MessageType mt = bSuccess ? MessageType::Info : MessageType::Error; + OSQLMessageBox aMsg(GetFrameWeld(), DBA_RES(pMessage), OUString(), MessBoxStyle::Ok | MessBoxStyle::DefaultOk, mt); + aMsg.run(); + } + bool OConnectionTabPage::checkTestConnection() + { + OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF"); + bool bEnableTestConnection = !m_xConnectionURL->get_visible() || !m_xConnectionURL->GetTextNoPrefix().isEmpty(); + if ( m_pCollection->determineType(m_eType) == ::dbaccess::DST_JDBC ) + bEnableTestConnection = bEnableTestConnection && (!m_xJavaDriver->get_text().trim().isEmpty()); + m_xTestConnection->set_sensitive(bEnableTestConnection); + return true; + } + IMPL_LINK(OConnectionTabPage, OnEditModified, weld::Entry&, rEdit, void) + { + if (&rEdit == m_xJavaDriver.get()) + m_xTestJavaDriver->set_sensitive( !m_xJavaDriver->get_text().trim().isEmpty() ); + + checkTestConnection(); + // tell the listener we were modified + callModifiedHdl(); + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/ConnectionPage.hxx b/dbaccess/source/ui/dlg/ConnectionPage.hxx new file mode 100644 index 000000000..19e769462 --- /dev/null +++ b/dbaccess/source/ui/dlg/ConnectionPage.hxx @@ -0,0 +1,72 @@ +/* -*- 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 "ConnectionHelper.hxx" + +namespace dbaui +{ + + // OConnectionTabPage + + /** implements the connection page of the data source properties dialog. + */ + class OConnectionTabPage final : public OConnectionHelper + { + private: + // user authentication + std::unique_ptr<weld::Label> m_xFL2; + std::unique_ptr<weld::Label> m_xUserNameLabel; + std::unique_ptr<weld::Entry> m_xUserName; + std::unique_ptr<weld::CheckButton> m_xPasswordRequired; + + // jdbc driver + std::unique_ptr<weld::Label> m_xFL3; + std::unique_ptr<weld::Label> m_xJavaDriverLabel; + std::unique_ptr<weld::Entry> m_xJavaDriver; + std::unique_ptr<weld::Button> m_xTestJavaDriver; + + // connection test + std::unique_ptr<weld::Button> m_xTestConnection; + + // called when the test connection button was clicked + DECL_LINK(OnTestJavaClickHdl, weld::Button&, void); + DECL_LINK(OnEditModified, weld::Entry&, void); + + public: + OConnectionTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs); + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet); + virtual ~OConnectionTabPage() override; + virtual bool FillItemSet (SfxItemSet* _rCoreAttrs) override; + + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + + /** changes the connection URL. + <p>The new URL must be of the type which is currently selected, only the parts which do not + affect the type may be changed (compared to the previous URL).</p> + */ + private: + /** enables the test connection button, if allowed + */ + virtual bool checkTestConnection() override; + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/ConnectionPageSetup.cxx b/dbaccess/source/ui/dlg/ConnectionPageSetup.cxx new file mode 100644 index 000000000..8f57c24f9 --- /dev/null +++ b/dbaccess/source/ui/dlg/ConnectionPageSetup.cxx @@ -0,0 +1,153 @@ +/* -*- 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 "ConnectionPageSetup.hxx" +#include <strings.hrc> +#include <core_resource.hxx> +#include <IItemSetHelper.hxx> +#include <svl/itemset.hxx> +#include <dsitems.hxx> +#include <svl/filenotation.hxx> +#include <com/sun/star/ucb/XProgressHandler.hpp> + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::ucb; + using namespace ::com::sun::star::ui::dialogs; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::container; + using namespace ::svt; + + std::unique_ptr<OGenericAdministrationPage> OConnectionTabPageSetup::CreateDbaseTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique<OConnectionTabPageSetup>( pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, STR_DBASE_HELPTEXT, STR_DBASE_HEADERTEXT, STR_DBASE_PATH_OR_FILE ); + } + + std::unique_ptr<OGenericAdministrationPage> OConnectionTabPageSetup::CreateMSAccessTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique<OConnectionTabPageSetup>( pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, STR_MSACCESS_HELPTEXT, STR_MSACCESS_HEADERTEXT, STR_MSACCESS_MDB_FILE ); + } + + std::unique_ptr<OGenericAdministrationPage> OConnectionTabPageSetup::CreateADOTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique<OConnectionTabPageSetup>( pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, STR_ADO_HELPTEXT, STR_ADO_HEADERTEXT, STR_COMMONURL ); + } + + std::unique_ptr<OGenericAdministrationPage> OConnectionTabPageSetup::CreateODBCTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique<OConnectionTabPageSetup>( pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, STR_ODBC_HELPTEXT, STR_ODBC_HEADERTEXT, STR_NAME_OF_ODBC_DATASOURCE ); + } + + std::unique_ptr<OGenericAdministrationPage> OConnectionTabPageSetup::CreateUserDefinedTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique<OConnectionTabPageSetup>(pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, TranslateId(), TranslateId(), STR_COMMONURL); + } + + OConnectionTabPageSetup::OConnectionTabPageSetup(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const OString& _rId, const SfxItemSet& _rCoreAttrs, TranslateId pHelpTextResId, TranslateId pHeaderResId, TranslateId pUrlResId) + : OConnectionHelper(pPage, pController, _rUIXMLDescription, _rId, _rCoreAttrs) + , m_xHelpText(m_xBuilder->weld_label("helptext")) + , m_xHeaderText(m_xBuilder->weld_label("header")) + { + + if (pHelpTextResId) + { + OUString sHelpText = DBA_RES(pHelpTextResId); + m_xHelpText->set_label(sHelpText); + } + else + m_xHelpText->hide(); + + if (pHeaderResId) + m_xHeaderText->set_label(DBA_RES(pHeaderResId)); + + if (pUrlResId) + { + OUString sLabelText = DBA_RES(pUrlResId); + m_xFT_Connection->set_label(sLabelText); + } + else + m_xFT_Connection->hide(); + + m_xConnectionURL->connect_changed(LINK(this, OConnectionTabPageSetup, OnEditModified)); + + SetRoadmapStateValue(false); + } + + OConnectionTabPageSetup::~OConnectionTabPageSetup() + { + } + + void OConnectionTabPageSetup::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + m_eType = m_pAdminDialog->getDatasourceType(_rSet); + // special handling for oracle, this can only happen + // if the user enters the same url as used for Oracle and we are on the JDBC path + //! TODO + //if ( ::dbaccess::DST_ORACLE_JDBC == m_eType ) + // m_eType = ::dbaccess::DST_JDBC; + if(m_pCollection->determineType(m_eType) == ::dbaccess::DST_POSTGRES){ + SetRoadmapStateValue(true); + } + + OConnectionHelper::implInitControls(_rSet, _bSaveValue); + + //! TODO + //if ( m_eType >= ::dbaccess::DST_USERDEFINE1 ) + //{ + // OUString sDisplayName = m_pCollection->getTypeDisplayName(m_eType); + // FixedText* ppTextControls[] ={&m_aFT_Connection}; + // for (size_t i = 0; i < sizeof(ppTextControls)/sizeof(ppTextControls[0]); ++i) + // { + // ppTextControls[i]->SetText(sDisplayName); + // } + //} + + callModifiedHdl(); + } + + bool OConnectionTabPageSetup::commitPage( ::vcl::WizardTypes::CommitPageReason /*_eReason*/ ) + { + return commitURL(); + } + + bool OConnectionTabPageSetup::FillItemSet(SfxItemSet* _rSet) + { + bool bChangedSomething = false; + fillString(*_rSet,m_xConnectionURL.get(), DSID_CONNECTURL, bChangedSomething); + return bChangedSomething; + } + + bool OConnectionTabPageSetup::checkTestConnection() + { + if ( m_pCollection->determineType(m_eType) == ::dbaccess::DST_POSTGRES ) + return true; + return !m_xConnectionURL->get_visible() || !m_xConnectionURL->GetTextNoPrefix().isEmpty(); + } + + IMPL_LINK_NOARG(OConnectionTabPageSetup, OnEditModified, weld::Entry&, void) + { + SetRoadmapStateValue(checkTestConnection()); + callModifiedHdl(); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/ConnectionPageSetup.hxx b/dbaccess/source/ui/dlg/ConnectionPageSetup.hxx new file mode 100644 index 000000000..0039a7160 --- /dev/null +++ b/dbaccess/source/ui/dlg/ConnectionPageSetup.hxx @@ -0,0 +1,63 @@ +/* -*- 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 "ConnectionHelper.hxx" +#include "adminpages.hxx" +#include <unotools/resmgr.hxx> + +namespace dbaui +{ + + // OConnectionTabPageSetup + + /** implements the connection page of the data source properties dialog. + */ + class OConnectionTabPageSetup : public OConnectionHelper + { + std::unique_ptr<weld::Label> m_xHelpText; + std::unique_ptr<weld::Label> m_xHeaderText; + + // called when the test connection button was clicked + DECL_LINK(OnEditModified, weld::Entry&, void); + + public: + OConnectionTabPageSetup(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const OString& _rId, const SfxItemSet& _rCoreAttrs, TranslateId pHelpTextResId, TranslateId pHeaderResId, TranslateId pUrlResId); + virtual ~OConnectionTabPageSetup() override; + + static std::unique_ptr<OGenericAdministrationPage> CreateDbaseTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet); + static std::unique_ptr<OGenericAdministrationPage> CreateMSAccessTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet); + static std::unique_ptr<OGenericAdministrationPage> CreateADOTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet); + static std::unique_ptr<OGenericAdministrationPage> CreateODBCTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet); + static std::unique_ptr<OGenericAdministrationPage> CreateUserDefinedTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet); + + virtual bool FillItemSet (SfxItemSet* _rCoreAttrs) override; + + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + + protected: + virtual bool checkTestConnection() override; + }; + + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx b/dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx new file mode 100644 index 000000000..ffbde972f --- /dev/null +++ b/dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx @@ -0,0 +1,786 @@ +/* -*- 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 <config_java.h> + +#include "DBSetupConnectionPages.hxx" +#include <core_resource.hxx> +#include <sqlmessage.hxx> +#include <strings.hrc> +#include <svl/itemset.hxx> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <dsitems.hxx> +#include "dsnItem.hxx" + +#if HAVE_FEATURE_JAVA + #include <jvmaccess/virtualmachine.hxx> +#endif + +#include <connectivity/CommonTools.hxx> +#include <dbwizsetup.hxx> +#include "TextConnectionHelper.hxx" +#include <osl/diagnose.h> + +namespace dbaui +{ +using namespace ::com::sun::star; + + std::unique_ptr<OGenericAdministrationPage> OTextConnectionPageSetup::CreateTextTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique<OTextConnectionPageSetup>(pPage, pController, _rAttrSet); + } + + // OTextConnectionPageSetup + OTextConnectionPageSetup::OTextConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs) + : OConnectionTabPageSetup(pPage, pController, "dbaccess/ui/dbwiztextpage.ui", "DBWizTextPage", + rCoreAttrs, STR_TEXT_HELPTEXT, STR_TEXT_HEADERTEXT, STR_TEXT_PATH_OR_FILE) + , m_xSubContainer(m_xBuilder->weld_widget("TextPageContainer")) + , m_xTextConnectionHelper(new OTextConnectionHelper(m_xSubContainer.get(), TC_EXTENSION | TC_SEPARATORS)) + { + m_xTextConnectionHelper->SetClickHandler(LINK( this, OTextConnectionPageSetup, ImplGetExtensionHdl ) ); + } + + OTextConnectionPageSetup::~OTextConnectionPageSetup() + { + m_xTextConnectionHelper.reset(); + } + + IMPL_LINK_NOARG(OTextConnectionPageSetup, ImplGetExtensionHdl, OTextConnectionHelper*, void) + { + SetRoadmapStateValue(!m_xTextConnectionHelper->GetExtension().isEmpty() && OConnectionTabPageSetup::checkTestConnection()); + callModifiedHdl(); + } + + bool OTextConnectionPageSetup::checkTestConnection() + { + bool bDoEnable = OConnectionTabPageSetup::checkTestConnection(); + bDoEnable = !m_xTextConnectionHelper->GetExtension().isEmpty() && bDoEnable; + return bDoEnable; + } + + void OTextConnectionPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + OConnectionTabPageSetup::fillControls(_rControlList); + m_xTextConnectionHelper->fillControls(_rControlList); + } + + void OTextConnectionPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + OConnectionTabPageSetup::fillWindows(_rControlList); + m_xTextConnectionHelper->fillWindows(_rControlList); + } + + void OTextConnectionPageSetup::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // first check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + OConnectionTabPageSetup::implInitControls( _rSet, _bSaveValue); + m_xTextConnectionHelper->implInitControls(_rSet, bValid); + } + + bool OTextConnectionPageSetup::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = OConnectionTabPageSetup::FillItemSet(_rSet); + bChangedSomething = m_xTextConnectionHelper->FillItemSet(*_rSet, bChangedSomething); + return bChangedSomething; + } + + bool OTextConnectionPageSetup::prepareLeave() + { + return m_xTextConnectionHelper->prepareLeave(); + } + + std::unique_ptr<OGenericAdministrationPage> OLDAPConnectionPageSetup::CreateLDAPTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet ) + { + return std::make_unique<OLDAPConnectionPageSetup>(pPage, pController, _rAttrSet); + } + + // OLDAPPageSetup + OLDAPConnectionPageSetup::OLDAPConnectionPageSetup( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs ) + : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/ldapconnectionpage.ui", "LDAPConnectionPage", _rCoreAttrs) + , m_xFTHelpText(m_xBuilder->weld_label("helpLabel")) + , m_xFTHostServer(m_xBuilder->weld_label("hostNameLabel")) + , m_xETHostServer(m_xBuilder->weld_entry("hostNameEntry")) + , m_xFTBaseDN(m_xBuilder->weld_label("baseDNLabel")) + , m_xETBaseDN(m_xBuilder->weld_entry("baseDNEntry")) + , m_xFTPortNumber(m_xBuilder->weld_label("portNumLabel")) + , m_xNFPortNumber(m_xBuilder->weld_spin_button("portNumEntry")) + , m_xFTDefaultPortNumber(m_xBuilder->weld_label("portNumDefLabel")) + , m_xCBUseSSL(m_xBuilder->weld_check_button("useSSLCheckbutton")) + { + m_xETHostServer->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl)); + m_xETBaseDN->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl)); + m_xNFPortNumber->connect_value_changed(LINK(this, OGenericAdministrationPage, OnControlSpinButtonModifyHdl)); + m_xCBUseSSL->connect_toggled( LINK(this, OGenericAdministrationPage, OnControlModifiedButtonClick) ); + SetRoadmapStateValue(false); + } + + OLDAPConnectionPageSetup::~OLDAPConnectionPageSetup() + { + } + + bool OLDAPConnectionPageSetup::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = false; + fillString(*_rSet,m_xETBaseDN.get(),DSID_CONN_LDAP_BASEDN, bChangedSomething); + fillInt32(*_rSet,m_xNFPortNumber.get(),DSID_CONN_LDAP_PORTNUMBER,bChangedSomething); + + if ( m_xETHostServer->get_value_changed_from_saved() ) + { + const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>( _rSet->GetItem(DSID_TYPECOLLECTION) ); + ::dbaccess::ODsnTypeCollection* pCollection = nullptr; + if (pCollectionItem) + pCollection = pCollectionItem->getCollection(); + OSL_ENSURE(pCollection, "OLDAPConnectionPageSetup::FillItemSet : really need a DSN type collection !"); + if (pCollection) + { + OUString sUrl = pCollection->getPrefix( "sdbc:address:ldap:") + m_xETHostServer->get_text(); + _rSet->Put(SfxStringItem(DSID_CONNECTURL, sUrl)); + bChangedSomething = true; + } + } + + fillBool(*_rSet,m_xCBUseSSL.get(),DSID_CONN_LDAP_USESSL,false,bChangedSomething); + return bChangedSomething; + } + void OLDAPConnectionPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETHostServer.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETBaseDN.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::SpinButton>(m_xNFPortNumber.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xCBUseSSL.get())); + } + void OLDAPConnectionPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTHelpText.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTHostServer.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTBaseDN.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTPortNumber.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTDefaultPortNumber.get())); + } + void OLDAPConnectionPageSetup::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + const SfxStringItem* pBaseDN = _rSet.GetItem<SfxStringItem>(DSID_CONN_LDAP_BASEDN); + const SfxInt32Item* pPortNumber = _rSet.GetItem<SfxInt32Item>(DSID_CONN_LDAP_PORTNUMBER); + + if ( bValid ) + { + m_xETBaseDN->set_text(pBaseDN->GetValue()); + m_xNFPortNumber->set_value(pPortNumber->GetValue()); + } + OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue); + callModifiedHdl(); + } + + void OLDAPConnectionPageSetup::callModifiedHdl(weld::Widget*) + { + bool bRoadmapState = ((!m_xETHostServer->get_text().isEmpty() ) && ( !m_xETBaseDN->get_text().isEmpty() ) && (!m_xFTPortNumber->get_label().isEmpty() )); + SetRoadmapStateValue(bRoadmapState); + OGenericAdministrationPage::callModifiedHdl(); + } + + std::unique_ptr<OMySQLIntroPageSetup> OMySQLIntroPageSetup::CreateMySQLIntroTabPage(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& rAttrSet) + { + return std::make_unique<OMySQLIntroPageSetup>(pPage, pController, rAttrSet); + } + + OMySQLIntroPageSetup::OMySQLIntroPageSetup(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rCoreAttrs) + : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/dbwizmysqlintropage.ui", "DBWizMysqlIntroPage", _rCoreAttrs) + , m_xODBCDatabase(m_xBuilder->weld_radio_button("odbc")) + , m_xJDBCDatabase(m_xBuilder->weld_radio_button("jdbc")) + , m_xNATIVEDatabase(m_xBuilder->weld_radio_button("directly")) + { + m_xODBCDatabase->connect_toggled(LINK(this, OMySQLIntroPageSetup, OnSetupModeSelected)); + m_xJDBCDatabase->connect_toggled(LINK(this, OMySQLIntroPageSetup, OnSetupModeSelected)); + m_xNATIVEDatabase->connect_toggled(LINK(this, OMySQLIntroPageSetup, OnSetupModeSelected)); + pController->SetIntroPage(this); + } + + OMySQLIntroPageSetup::~OMySQLIntroPageSetup() + { + } + + IMPL_LINK_NOARG(OMySQLIntroPageSetup, OnSetupModeSelected, weld::Toggleable&, void) + { + maClickHdl.Call( this ); + } + + void OMySQLIntroPageSetup::implInitControls(const SfxItemSet& _rSet, bool /*_bSaveValue*/) + { + // show the "Connect directly" option only if the driver is installed + const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>( _rSet.GetItem(DSID_TYPECOLLECTION) ); + bool bHasMySQLNative = ( pCollectionItem != nullptr ) && pCollectionItem->getCollection()->hasDriver( "sdbc:mysql:mysqlc:" ); + if ( bHasMySQLNative ) + m_xNATIVEDatabase->show(); + + // if any of the options is checked, then there's nothing to do + if ( m_xODBCDatabase->get_active() || m_xJDBCDatabase->get_active() || m_xNATIVEDatabase->get_active() ) + return; + + // prefer "native" or "JDBC" + if ( bHasMySQLNative ) + m_xNATIVEDatabase->set_active(true); + else + m_xJDBCDatabase->set_active(true); + } + + void OMySQLIntroPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& /*_rControlList*/) + { + } + + void OMySQLIntroPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& /*_rControlList*/) + { + } + + bool OMySQLIntroPageSetup::FillItemSet(SfxItemSet* /*_rSet*/) + { + OSL_FAIL("Who called me?! Please ask oj for more information."); + return true; + } + + OMySQLIntroPageSetup::ConnectionType OMySQLIntroPageSetup::getMySQLMode() const + { + if (m_xJDBCDatabase->get_active()) + return VIA_JDBC; + else if (m_xNATIVEDatabase->get_active()) + return VIA_NATIVE; + else + return VIA_ODBC; + } + + // MySQLNativeSetupPage + MySQLNativeSetupPage::MySQLNativeSetupPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs ) + : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/dbwizmysqlnativepage.ui", "DBWizMysqlNativePage", rCoreAttrs) + , m_xHelpText(m_xBuilder->weld_label("helptext")) + , m_xSettingsContainer(m_xBuilder->weld_container("MySQLSettingsContainer")) + , m_xMySQLSettings(new MySQLNativeSettings(m_xSettingsContainer.get(), LINK(this, OGenericAdministrationPage, OnControlModified))) + { + SetRoadmapStateValue(false); + } + + MySQLNativeSetupPage::~MySQLNativeSetupPage() + { + m_xMySQLSettings.reset(); + } + + std::unique_ptr<OGenericAdministrationPage> MySQLNativeSetupPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet) + { + return std::make_unique<MySQLNativeSetupPage>(pPage, pController, rAttrSet); + } + + void MySQLNativeSetupPage::fillControls( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList ) + { + m_xMySQLSettings->fillControls( _rControlList ); + } + + void MySQLNativeSetupPage::fillWindows(std::vector<std::unique_ptr<ISaveValueWrapper>>& rControlList) + { + rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xHelpText.get())); + m_xMySQLSettings->fillWindows(rControlList); + } + + bool MySQLNativeSetupPage::FillItemSet( SfxItemSet* _rSet ) + { + return m_xMySQLSettings->FillItemSet( _rSet ); + } + + void MySQLNativeSetupPage::implInitControls( const SfxItemSet& _rSet, bool _bSaveValue ) + { + m_xMySQLSettings->implInitControls( _rSet ); + + OGenericAdministrationPage::implInitControls( _rSet, _bSaveValue ); + + callModifiedHdl(); + } + + void MySQLNativeSetupPage::callModifiedHdl(weld::Widget*) + { + SetRoadmapStateValue( m_xMySQLSettings->canAdvance() ); + + OGenericAdministrationPage::callModifiedHdl(); + } + + // OMySQLJDBCConnectionPageSetup + OGeneralSpecialJDBCConnectionPageSetup::OGeneralSpecialJDBCConnectionPageSetup( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs ,sal_uInt16 _nPortId, TranslateId pDefaultPortResId, TranslateId pHelpTextResId, TranslateId pHeaderTextResId, TranslateId pDriverClassId) + : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/specialjdbcconnectionpage.ui", "SpecialJDBCConnectionPage", _rCoreAttrs) + , m_nPortId(_nPortId) + , m_xHeaderText(m_xBuilder->weld_label("header")) + , m_xFTHelpText(m_xBuilder->weld_label("helpLabel")) + , m_xFTDatabasename(m_xBuilder->weld_label("dbNameLabel")) + , m_xETDatabasename(m_xBuilder->weld_entry("dbNameEntry")) + , m_xFTHostname(m_xBuilder->weld_label("hostNameLabel")) + , m_xETHostname(m_xBuilder->weld_entry("hostNameEntry")) + , m_xFTPortNumber(m_xBuilder->weld_label("portNumLabel")) + , m_xFTDefaultPortNumber(m_xBuilder->weld_label("portNumDefLabel")) + , m_xNFPortNumber(m_xBuilder->weld_spin_button("portNumEntry")) + , m_xFTDriverClass(m_xBuilder->weld_label("jdbcDriverLabel")) + , m_xETDriverClass(m_xBuilder->weld_entry("jdbcDriverEntry")) + , m_xPBTestJavaDriver(m_xBuilder->weld_button("testDriverButton")) + { + m_xFTDriverClass->set_label(DBA_RES(pDriverClassId)); + + m_xFTDefaultPortNumber->set_label(DBA_RES(pDefaultPortResId)); + OUString sHelpText = DBA_RES(pHelpTextResId); + m_xFTHelpText->set_label(sHelpText); + //TODO this code snippet is redundant + m_xHeaderText->set_label(DBA_RES(pHeaderTextResId)); + + m_xETDatabasename->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl)); + m_xETHostname->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl)); + m_xNFPortNumber->connect_value_changed(LINK(this, OGenericAdministrationPage, OnControlSpinButtonModifyHdl)); + + m_xETDriverClass->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl)); + m_xPBTestJavaDriver->connect_clicked(LINK(this,OGeneralSpecialJDBCConnectionPageSetup,OnTestJavaClickHdl)); + + const SfxStringItem* pUrlItem = _rCoreAttrs.GetItem<SfxStringItem>(DSID_CONNECTURL); + const DbuTypeCollectionItem* pTypesItem = _rCoreAttrs.GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION); + ::dbaccess::ODsnTypeCollection* pTypeCollection = pTypesItem ? pTypesItem->getCollection() : nullptr; + if (pTypeCollection && pUrlItem && pUrlItem->GetValue().getLength() ) + { + m_sDefaultJdbcDriverName = pTypeCollection->getJavaDriverClass(pUrlItem->GetValue()); + } + + SetRoadmapStateValue(false); + } + + OGeneralSpecialJDBCConnectionPageSetup::~OGeneralSpecialJDBCConnectionPageSetup() + { + } + + std::unique_ptr<OGenericAdministrationPage> OGeneralSpecialJDBCConnectionPageSetup::CreateMySQLJDBCTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet ) + { + return std::make_unique<OGeneralSpecialJDBCConnectionPageSetup>(pPage, pController, + _rAttrSet, + DSID_MYSQL_PORTNUMBER , + STR_MYSQL_DEFAULT, + STR_MYSQLJDBC_HELPTEXT, + STR_MYSQLJDBC_HEADERTEXT, + STR_MYSQL_DRIVERCLASSTEXT); + } + + std::unique_ptr<OGenericAdministrationPage> OGeneralSpecialJDBCConnectionPageSetup::CreateOracleJDBCTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet ) + { + return std::make_unique<OGeneralSpecialJDBCConnectionPageSetup>(pPage, pController, + _rAttrSet, + DSID_ORACLE_PORTNUMBER, + STR_ORACLE_DEFAULT, + STR_ORACLE_HELPTEXT, + STR_ORACLE_HEADERTEXT, + STR_ORACLE_DRIVERCLASSTEXT); + } + + void OGeneralSpecialJDBCConnectionPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETDatabasename.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETDriverClass.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETHostname.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::SpinButton>(m_xNFPortNumber.get())); + } + + void OGeneralSpecialJDBCConnectionPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTHelpText.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTDatabasename.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTHostname.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTPortNumber.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTDefaultPortNumber.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTDriverClass.get())); + } + + bool OGeneralSpecialJDBCConnectionPageSetup::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = false; + fillString(*_rSet,m_xETDriverClass.get(),DSID_JDBCDRIVERCLASS,bChangedSomething); + fillString(*_rSet,m_xETHostname.get(),DSID_CONN_HOSTNAME,bChangedSomething); + fillString(*_rSet,m_xETDatabasename.get(),DSID_DATABASENAME,bChangedSomething); + fillInt32(*_rSet,m_xNFPortNumber.get(),m_nPortId,bChangedSomething ); + return bChangedSomething; + } + + void OGeneralSpecialJDBCConnectionPageSetup::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + const SfxStringItem* pDatabaseName = _rSet.GetItem<SfxStringItem>(DSID_DATABASENAME); + const SfxStringItem* pDrvItem = _rSet.GetItem<SfxStringItem>(DSID_JDBCDRIVERCLASS); + const SfxStringItem* pHostName = _rSet.GetItem<SfxStringItem>(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = _rSet.GetItem<SfxInt32Item>(m_nPortId); + + if ( bValid ) + { + m_xETDatabasename->set_text(pDatabaseName->GetValue()); + m_xETDatabasename->save_value(); + + m_xETDriverClass->set_text(pDrvItem->GetValue()); + m_xETDriverClass->save_value(); + + m_xETHostname->set_text(pHostName->GetValue()); + m_xETHostname->save_value(); + + m_xNFPortNumber->set_value(pPortNumber->GetValue()); + m_xNFPortNumber->save_value(); + } + OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue); + + // to get the correct value when saveValue was called by base class + if ( m_xETDriverClass->get_text().trim().isEmpty() ) + { + m_xETDriverClass->set_text(m_sDefaultJdbcDriverName); + m_xETDriverClass->save_value(); + } + callModifiedHdl(); + + bool bRoadmapState = ((!m_xETDatabasename->get_text().isEmpty() ) && (!m_xETHostname->get_text().isEmpty()) && (!m_xNFPortNumber->get_text().isEmpty() ) && ( !m_xETDriverClass->get_text().isEmpty() )); + SetRoadmapStateValue(bRoadmapState); + } + + IMPL_LINK_NOARG(OGeneralSpecialJDBCConnectionPageSetup, OnTestJavaClickHdl, weld::Button&, void) + { + OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF"); + + bool bSuccess = false; +#if HAVE_FEATURE_JAVA + try + { + if ( !m_xETDriverClass->get_text().trim().isEmpty() ) + { +// TODO change jvmaccess + ::rtl::Reference< jvmaccess::VirtualMachine > xJVM = ::connectivity::getJavaVM( m_pAdminDialog->getORB() ); + m_xETDriverClass->set_text(m_xETDriverClass->get_text().trim()); // fdo#68341 + bSuccess = ::connectivity::existsJavaClassByName(xJVM,m_xETDriverClass->get_text()); + } + } + catch(css::uno::Exception&) + { + } +#endif + TranslateId pMessage = bSuccess ? STR_JDBCDRIVER_SUCCESS : STR_JDBCDRIVER_NO_SUCCESS; + const MessageType mt = bSuccess ? MessageType::Info : MessageType::Error; + OSQLMessageBox aMsg(GetFrameWeld(), DBA_RES(pMessage), OUString(), MessBoxStyle::Ok | MessBoxStyle::DefaultOk, mt); + aMsg.run(); + } + + void OGeneralSpecialJDBCConnectionPageSetup::callModifiedHdl(weld::Widget* pControl) + { + if (pControl == m_xETDriverClass.get()) + m_xPBTestJavaDriver->set_sensitive( !m_xETDriverClass->get_text().trim().isEmpty() ); + bool bRoadmapState = ((!m_xETDatabasename->get_text().isEmpty() ) && ( !m_xETHostname->get_text().isEmpty() ) && (!m_xNFPortNumber->get_text().isEmpty() ) && ( !m_xETDriverClass->get_text().trim().isEmpty() )); + SetRoadmapStateValue(bRoadmapState); + OGenericAdministrationPage::callModifiedHdl(); + } + + std::unique_ptr<OGenericAdministrationPage> OJDBCConnectionPageSetup::CreateJDBCTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique<OJDBCConnectionPageSetup>(pPage, pController, _rAttrSet); + } + + // OMySQLJDBCConnectionPageSetup + OJDBCConnectionPageSetup::OJDBCConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs) + : OConnectionTabPageSetup(pPage, pController, "dbaccess/ui/jdbcconnectionpage.ui", "JDBCConnectionPage", rCoreAttrs, + STR_JDBC_HELPTEXT, STR_JDBC_HEADERTEXT, STR_COMMONURL) + , m_xFTDriverClass(m_xBuilder->weld_label("jdbcLabel")) + , m_xETDriverClass(m_xBuilder->weld_entry("jdbcEntry")) + , m_xPBTestJavaDriver(m_xBuilder->weld_button("jdbcButton")) + { + m_xETDriverClass->connect_changed(LINK(this, OJDBCConnectionPageSetup, OnEditModified)); + m_xPBTestJavaDriver->connect_clicked(LINK(this,OJDBCConnectionPageSetup,OnTestJavaClickHdl)); + } + + OJDBCConnectionPageSetup::~OJDBCConnectionPageSetup() + { + } + + void OJDBCConnectionPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETDriverClass.get())); + } + + void OJDBCConnectionPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTDriverClass.get())); + } + + bool OJDBCConnectionPageSetup::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = OConnectionTabPageSetup::FillItemSet(_rSet); + fillString(*_rSet,m_xETDriverClass.get(),DSID_JDBCDRIVERCLASS,bChangedSomething); + return bChangedSomething; + } + + void OJDBCConnectionPageSetup::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + const SfxStringItem* pDrvItem = _rSet.GetItem<SfxStringItem>(DSID_JDBCDRIVERCLASS); + + if ( bValid ) + { + if ( !pDrvItem->GetValue().getLength() ) + { + OUString sDefaultJdbcDriverName = m_pCollection->getJavaDriverClass(m_eType); + if ( !sDefaultJdbcDriverName.isEmpty() ) + { + m_xETDriverClass->set_text(sDefaultJdbcDriverName); + m_xETDriverClass->save_value(); + } + } + else + { + m_xETDriverClass->set_text(pDrvItem->GetValue()); + m_xETDriverClass->save_value(); + } + } + bool bEnable = pDrvItem->GetValue().getLength() != 0; + m_xPBTestJavaDriver->set_sensitive(bEnable); + OConnectionTabPageSetup::implInitControls(_rSet, _bSaveValue); + + SetRoadmapStateValue(checkTestConnection()); + } + + bool OJDBCConnectionPageSetup::checkTestConnection() + { + OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF"); + bool bEnableTestConnection = !m_xConnectionURL->get_visible() || !m_xConnectionURL->GetTextNoPrefix().isEmpty(); + bEnableTestConnection = bEnableTestConnection && (!m_xETDriverClass->get_text().isEmpty()); + return bEnableTestConnection; + } + + IMPL_LINK_NOARG(OJDBCConnectionPageSetup, OnTestJavaClickHdl, weld::Button&, void) + { + OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF"); + bool bSuccess = false; +#if HAVE_FEATURE_JAVA + try + { + if ( !m_xETDriverClass->get_text().isEmpty() ) + { +// TODO change jvmaccess + ::rtl::Reference< jvmaccess::VirtualMachine > xJVM = ::connectivity::getJavaVM( m_pAdminDialog->getORB() ); + m_xETDriverClass->set_text(m_xETDriverClass->get_text().trim()); // fdo#68341 + bSuccess = xJVM.is() && ::connectivity::existsJavaClassByName(xJVM,m_xETDriverClass->get_text()); + } + } + catch(css::uno::Exception&) + { + } +#endif + TranslateId pMessage = bSuccess ? STR_JDBCDRIVER_SUCCESS : STR_JDBCDRIVER_NO_SUCCESS; + const MessageType mt = bSuccess ? MessageType::Info : MessageType::Error; + OSQLMessageBox aMsg(GetFrameWeld(), DBA_RES(pMessage), OUString(), MessBoxStyle::Ok | MessBoxStyle::DefaultOk, mt); + aMsg.run(); + } + + IMPL_LINK(OJDBCConnectionPageSetup, OnEditModified, weld::Entry&, rEdit, void) + { + if (&rEdit == m_xETDriverClass.get()) + m_xPBTestJavaDriver->set_sensitive(!m_xETDriverClass->get_text().isEmpty()); + SetRoadmapStateValue(checkTestConnection()); + // tell the listener we were modified + callModifiedHdl(); + } + + std::unique_ptr<OGenericAdministrationPage> OSpreadSheetConnectionPageSetup::CreateDocumentOrSpreadSheetTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique<OSpreadSheetConnectionPageSetup>(pPage, pController, _rAttrSet); + } + + OSpreadSheetConnectionPageSetup::OSpreadSheetConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs) + : OConnectionTabPageSetup(pPage, pController, "dbaccess/ui/dbwizspreadsheetpage.ui", "DBWizSpreadsheetPage", + rCoreAttrs, STR_SPREADSHEET_HELPTEXT, STR_SPREADSHEET_HEADERTEXT, STR_SPREADSHEETPATH) + , m_xPasswordrequired(m_xBuilder->weld_check_button("passwordrequired")) + { + m_xPasswordrequired->connect_toggled(LINK(this, OGenericAdministrationPage, OnControlModifiedButtonClick)); + } + + OSpreadSheetConnectionPageSetup::~OSpreadSheetConnectionPageSetup() + { + } + + void OSpreadSheetConnectionPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& /*_rControlList*/) + { + } + + void OSpreadSheetConnectionPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + OConnectionTabPageSetup::fillControls(_rControlList); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xPasswordrequired.get())); + + } + + bool OSpreadSheetConnectionPageSetup::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = OConnectionTabPageSetup::FillItemSet(_rSet); + fillBool(*_rSet,m_xPasswordrequired.get(),DSID_PASSWORDREQUIRED,false,bChangedSomething); + return bChangedSomething; + } + + std::unique_ptr<OGenericAdministrationPage> OAuthentificationPageSetup::CreateAuthentificationTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique<OAuthentificationPageSetup>(pPage, pController, _rAttrSet); + } + + OAuthentificationPageSetup::OAuthentificationPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs) + : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/authentificationpage.ui", "AuthentificationPage", _rCoreAttrs) + , m_xFTHelpText(m_xBuilder->weld_label("helptext")) + , m_xFTUserName(m_xBuilder->weld_label("generalUserNameLabel")) + , m_xETUserName(m_xBuilder->weld_entry("generalUserNameEntry")) + , m_xCBPasswordRequired(m_xBuilder->weld_check_button("passRequiredCheckbutton")) + , m_xPBTestConnection(m_xBuilder->weld_button("testConnectionButton")) + { + m_xETUserName->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl)); + m_xCBPasswordRequired->connect_toggled(LINK(this,OGenericAdministrationPage,OnControlModifiedButtonClick)); + m_xPBTestConnection->connect_clicked(LINK(this,OGenericAdministrationPage,OnTestConnectionButtonClickHdl)); + } + + OAuthentificationPageSetup::~OAuthentificationPageSetup() + { + } + + void OAuthentificationPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTHelpText.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTUserName.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Button>(m_xPBTestConnection.get())); + } + + void OAuthentificationPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETUserName.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xCBPasswordRequired.get())); + } + + void OAuthentificationPageSetup::implInitControls(const SfxItemSet& _rSet, bool /*_bSaveValue*/) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + const SfxStringItem* pUidItem = _rSet.GetItem<SfxStringItem>(DSID_USER); + const SfxBoolItem* pAllowEmptyPwd = _rSet.GetItem<SfxBoolItem>(DSID_PASSWORDREQUIRED); + + m_xETUserName->set_text(pUidItem->GetValue()); + m_xCBPasswordRequired->set_active(pAllowEmptyPwd->GetValue()); + + m_xETUserName->save_value(); + } + + bool OAuthentificationPageSetup::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = false; + + if (m_xETUserName->get_value_changed_from_saved()) + { + _rSet->Put(SfxStringItem(DSID_USER, m_xETUserName->get_text())); + _rSet->Put(SfxStringItem(DSID_PASSWORD, OUString())); + bChangedSomething = true; + } + fillBool(*_rSet, m_xCBPasswordRequired.get(), DSID_PASSWORDREQUIRED, false, bChangedSomething); + return bChangedSomething; + } + + std::unique_ptr<OGenericAdministrationPage> OFinalDBPageSetup::CreateFinalDBTabPageSetup(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique<OFinalDBPageSetup>(pPage, pController, _rAttrSet); + } + + OFinalDBPageSetup::OFinalDBPageSetup(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rCoreAttrs) + : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/finalpagewizard.ui", "PageFinal", _rCoreAttrs) + , m_xFTFinalHeader(m_xBuilder->weld_label("headerText")) + , m_xFTFinalHelpText(m_xBuilder->weld_label("helpText")) + , m_xRBRegisterDataSource(m_xBuilder->weld_radio_button("yesregister")) + , m_xRBDontregisterDataSource(m_xBuilder->weld_radio_button("noregister")) + , m_xFTAdditionalSettings(m_xBuilder->weld_label("additionalText")) + , m_xCBOpenAfterwards(m_xBuilder->weld_check_button("openediting")) + , m_xCBStartTableWizard(m_xBuilder->weld_check_button("usewizard")) + , m_xFTFinalText(m_xBuilder->weld_label("finishText")) + { + m_xCBOpenAfterwards->connect_toggled(LINK(this, OFinalDBPageSetup, OnOpenSelected)); + m_xRBRegisterDataSource->set_active(true); + pController->SetFinalPage(this); + } + + OFinalDBPageSetup::~OFinalDBPageSetup() + { + } + + bool OFinalDBPageSetup::IsDatabaseDocumentToBeRegistered() const + { + return m_xRBRegisterDataSource->get_active() && m_xRBRegisterDataSource->get_sensitive(); + } + + bool OFinalDBPageSetup::IsDatabaseDocumentToBeOpened() const + { + return m_xCBOpenAfterwards->get_active() && m_xCBOpenAfterwards->get_sensitive(); + } + + bool OFinalDBPageSetup::IsTableWizardToBeStarted() const + { + return m_xCBStartTableWizard->get_active() && m_xCBStartTableWizard->get_sensitive(); + } + + void OFinalDBPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTFinalHeader.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTFinalHelpText.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTAdditionalSettings.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTFinalText.get())); + } + + void OFinalDBPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xCBOpenAfterwards.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xCBStartTableWizard.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xRBRegisterDataSource.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xRBDontregisterDataSource.get())); + } + + void OFinalDBPageSetup::implInitControls(const SfxItemSet& /*_rSet*/, bool /*_bSaveValue*/) + { + m_xCBOpenAfterwards->set_active(true); + } + + void OFinalDBPageSetup::enableTableWizardCheckBox( bool _bSupportsTableCreation) + { + m_xCBStartTableWizard->set_sensitive(_bSupportsTableCreation); + } + + bool OFinalDBPageSetup::FillItemSet( SfxItemSet* /*_rSet*/ ) + { + return true; + } + + IMPL_LINK(OFinalDBPageSetup, OnOpenSelected, weld::Toggleable&, rBox, void) + { + m_xCBStartTableWizard->set_sensitive(rBox.get_sensitive() && rBox.get_active()); + } +} + +// namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/DBSetupConnectionPages.hxx b/dbaccess/source/ui/dlg/DBSetupConnectionPages.hxx new file mode 100644 index 000000000..8bc367602 --- /dev/null +++ b/dbaccess/source/ui/dlg/DBSetupConnectionPages.hxx @@ -0,0 +1,270 @@ +/* -*- 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 "ConnectionPageSetup.hxx" + +#include "adminpages.hxx" +#include "admincontrols.hxx" +#include "TextConnectionHelper.hxx" + +namespace dbaui +{ + class ODbTypeWizDialogSetup; + + // OSpreadSheetConnectionPageSetup + class OSpreadSheetConnectionPageSetup final : public OConnectionTabPageSetup + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + static std::unique_ptr<OGenericAdministrationPage> CreateDocumentOrSpreadSheetTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet); + OSpreadSheetConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs); + virtual ~OSpreadSheetConnectionPageSetup() override; + + private: + std::unique_ptr<weld::CheckButton> m_xPasswordrequired; + + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + }; + + // OTextConnectionPage + class OTextConnectionPageSetup : public OConnectionTabPageSetup + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + static std::unique_ptr<OGenericAdministrationPage> CreateTextTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet ); + OTextConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs); + virtual ~OTextConnectionPageSetup() override; + protected: + virtual bool prepareLeave() override; + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + bool checkTestConnection() override; + private: + DECL_LINK(ImplGetExtensionHdl, OTextConnectionHelper*, void); + std::unique_ptr<weld::Widget> m_xSubContainer; + std::unique_ptr<OTextConnectionHelper> m_xTextConnectionHelper; + }; + + // OLDAPConnectionPageSetup + class OLDAPConnectionPageSetup : public OGenericAdministrationPage + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + static std::unique_ptr<OGenericAdministrationPage> CreateLDAPTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet ); + OLDAPConnectionPageSetup( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs ); + virtual ~OLDAPConnectionPageSetup() override; + virtual void callModifiedHdl(weld::Widget* pControl = nullptr) override; + + protected: + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + + private: + std::unique_ptr<weld::Label> m_xFTHelpText; + std::unique_ptr<weld::Label> m_xFTHostServer; + std::unique_ptr<weld::Entry> m_xETHostServer; + std::unique_ptr<weld::Label> m_xFTBaseDN; + std::unique_ptr<weld::Entry> m_xETBaseDN; + std::unique_ptr<weld::Label> m_xFTPortNumber; + std::unique_ptr<weld::SpinButton> m_xNFPortNumber; + std::unique_ptr<weld::Label> m_xFTDefaultPortNumber; + std::unique_ptr<weld::CheckButton> m_xCBUseSSL; + }; + + // MySQLNativeSetupPage + class MySQLNativeSetupPage : public OGenericAdministrationPage + { + private: + std::unique_ptr<weld::Label> m_xHelpText; + std::unique_ptr<weld::Container> m_xSettingsContainer; + std::unique_ptr<MySQLNativeSettings> m_xMySQLSettings; + + public: + MySQLNativeSetupPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs); + virtual ~MySQLNativeSetupPage() override; + + static std::unique_ptr<OGenericAdministrationPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet); + + protected: + virtual void fillControls( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList ) override; + virtual void fillWindows( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList ) override; + + virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override; + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + + virtual void callModifiedHdl(weld::Widget* pControl = nullptr) override; + }; + + // OGeneralSpecialJDBCConnectionPageSetup + class OGeneralSpecialJDBCConnectionPageSetup final : public OGenericAdministrationPage + { + public: + OGeneralSpecialJDBCConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController + , const SfxItemSet& _rCoreAttrs + , sal_uInt16 _nPortId + , TranslateId pDefaultPortResId + , TranslateId pHelpTextResId + , TranslateId pHeaderTextResId + , TranslateId pDriverClassId ); + virtual ~OGeneralSpecialJDBCConnectionPageSetup() override; + static std::unique_ptr<OGenericAdministrationPage> CreateMySQLJDBCTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet ); + static std::unique_ptr<OGenericAdministrationPage> CreateOracleJDBCTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet ); + + private: + virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override; + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void callModifiedHdl(weld::Widget* pControl = nullptr) override; + + DECL_LINK(OnTestJavaClickHdl, weld::Button&, void); + + OUString m_sDefaultJdbcDriverName; + sal_uInt16 m_nPortId; + + std::unique_ptr<weld::Label> m_xHeaderText; + std::unique_ptr<weld::Label> m_xFTHelpText; + std::unique_ptr<weld::Label> m_xFTDatabasename; + std::unique_ptr<weld::Entry> m_xETDatabasename; + std::unique_ptr<weld::Label> m_xFTHostname; + std::unique_ptr<weld::Entry> m_xETHostname; + std::unique_ptr<weld::Label> m_xFTPortNumber; + std::unique_ptr<weld::Label> m_xFTDefaultPortNumber; + std::unique_ptr<weld::SpinButton> m_xNFPortNumber; + + std::unique_ptr<weld::Label> m_xFTDriverClass; + std::unique_ptr<weld::Entry> m_xETDriverClass; + std::unique_ptr<weld::Button> m_xPBTestJavaDriver; + }; + + // OJDBCConnectionPageSetup + class OJDBCConnectionPageSetup final : public OConnectionTabPageSetup + { + public: + OJDBCConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs); + virtual ~OJDBCConnectionPageSetup() override; + static std::unique_ptr<OGenericAdministrationPage> CreateJDBCTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet); + + private: + virtual bool checkTestConnection() override; + + virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override; + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + + DECL_LINK(OnTestJavaClickHdl, weld::Button&, void); + DECL_LINK(OnEditModified, weld::Entry&, void); + std::unique_ptr<weld::Label> m_xFTDriverClass; + std::unique_ptr<weld::Entry> m_xETDriverClass; + std::unique_ptr<weld::Button> m_xPBTestJavaDriver; + }; + + // OMySQLIntroPageSetup + class OMySQLIntroPageSetup : public OGenericAdministrationPage + { + public: + enum ConnectionType + { + VIA_ODBC, + VIA_JDBC, + VIA_NATIVE + }; + + OMySQLIntroPageSetup(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& rCoreAttrs); + virtual ~OMySQLIntroPageSetup() override; + + static std::unique_ptr<OMySQLIntroPageSetup> CreateMySQLIntroTabPage(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& rAttrSet); + ConnectionType getMySQLMode() const; + void SetClickHdl( const Link<OMySQLIntroPageSetup *, void>& rLink ) { maClickHdl = rLink; } + + protected: + virtual bool FillItemSet(SfxItemSet* _rSet) override; + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + + private: + std::unique_ptr<weld::RadioButton> m_xODBCDatabase; + std::unique_ptr<weld::RadioButton> m_xJDBCDatabase; + std::unique_ptr<weld::RadioButton> m_xNATIVEDatabase; + Link<OMySQLIntroPageSetup *, void> maClickHdl; + + DECL_LINK(OnSetupModeSelected, weld::Toggleable&, void); + }; + + // OAuthentificationPageSetup + class OAuthentificationPageSetup final : public OGenericAdministrationPage + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + static std::unique_ptr<OGenericAdministrationPage> CreateAuthentificationTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet); + OAuthentificationPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs); + virtual ~OAuthentificationPageSetup() override; + + private: + std::unique_ptr<weld::Label> m_xFTHelpText; + std::unique_ptr<weld::Label> m_xFTUserName; + std::unique_ptr<weld::Entry> m_xETUserName; + std::unique_ptr<weld::CheckButton> m_xCBPasswordRequired; + std::unique_ptr<weld::Button> m_xPBTestConnection; + + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + }; + + // OFinalDBPageSetup + class OFinalDBPageSetup : public OGenericAdministrationPage + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + static std::unique_ptr<OGenericAdministrationPage> CreateFinalDBTabPageSetup(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rAttrSet); + + OFinalDBPageSetup(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rCoreAttrs); + virtual ~OFinalDBPageSetup() override; + bool IsDatabaseDocumentToBeRegistered() const; + bool IsDatabaseDocumentToBeOpened() const; + bool IsTableWizardToBeStarted() const; + void enableTableWizardCheckBox( bool _bSupportsTableCreation); + + DECL_LINK(OnOpenSelected, weld::Toggleable&, void); + protected: + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + private: + std::unique_ptr<weld::Label> m_xFTFinalHeader; + std::unique_ptr<weld::Label> m_xFTFinalHelpText; + std::unique_ptr<weld::RadioButton> m_xRBRegisterDataSource; + std::unique_ptr<weld::RadioButton> m_xRBDontregisterDataSource; + std::unique_ptr<weld::Label> m_xFTAdditionalSettings; + std::unique_ptr<weld::CheckButton> m_xCBOpenAfterwards; + std::unique_ptr<weld::CheckButton> m_xCBStartTableWizard; + std::unique_ptr<weld::Label> m_xFTFinalText; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/DbAdminImpl.cxx b/dbaccess/source/ui/dlg/DbAdminImpl.cxx new file mode 100644 index 000000000..ca20930ef --- /dev/null +++ b/dbaccess/source/ui/dlg/DbAdminImpl.cxx @@ -0,0 +1,1074 @@ +/* -*- 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 "DbAdminImpl.hxx" +#include <dsmeta.hxx> + +#include <svl/poolitem.hxx> +#include <svl/itempool.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <svl/eitem.hxx> +#include <IItemSetHelper.hxx> +#include <UITools.hxx> +#include <core_resource.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <dsitems.hxx> +#include "dsnItem.hxx" +#include "optionalboolitem.hxx" +#include <stringlistitem.hxx> +#include <OAuthenticationContinuation.hxx> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdbc/ConnectionPool.hpp> +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/ucb/AuthenticationRequest.hpp> + +#include <comphelper/interaction.hxx> +#include <comphelper/sequence.hxx> +#include <connectivity/DriversConfig.hxx> +#include <connectivity/dbexception.hxx> +#include <osl/file.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <typelib/typedescription.hxx> +#include <vcl/svapp.hxx> +#include <vcl/stdtext.hxx> +#include <vcl/weld.hxx> + +#include <algorithm> +#include <iterator> +#include <functional> +#include <o3tl/functional.hxx> + +namespace dbaui +{ +using namespace ::dbtools; +using namespace com::sun::star::uno; +using namespace com::sun::star; +using namespace com::sun::star::ucb; +using namespace com::sun::star::task; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::sdb; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::util; +using namespace com::sun::star::container; +using namespace com::sun::star::frame; + +namespace +{ + bool implCheckItemType( SfxItemSet const & _rSet, const sal_uInt16 _nId, const std::function<bool ( const SfxPoolItem* )>& isItemType ) + { + bool bCorrectType = false; + + SfxItemPool* pPool = _rSet.GetPool(); + OSL_ENSURE( pPool, "implCheckItemType: invalid item pool!" ); + if ( pPool ) + { + const SfxPoolItem& rDefItem = pPool->GetDefaultItem( _nId ); + bCorrectType = isItemType(&rDefItem); + } + return bCorrectType; + } + + void lcl_putProperty(const Reference< XPropertySet >& _rxSet, const OUString& _rName, const Any& _rValue) + { + try + { + if ( _rxSet.is() ) + _rxSet->setPropertyValue(_rName, _rValue); + } + catch(Exception&) + { + SAL_WARN("dbaccess", "ODbAdminDialog::implTranslateProperty: could not set the property " + << _rName); + } + + } + + OUString lcl_createHostWithPort(const SfxStringItem* _pHostName,const SfxInt32Item* _pPortNumber) + { + OUString sNewUrl; + + if ( _pHostName && _pHostName->GetValue().getLength() ) + sNewUrl = _pHostName->GetValue(); + + if ( _pPortNumber ) + { + sNewUrl += ":" + OUString::number(_pPortNumber->GetValue()); + } + + return sNewUrl; + } +} + + // ODbDataSourceAdministrationHelper +ODbDataSourceAdministrationHelper::ODbDataSourceAdministrationHelper(const Reference< XComponentContext >& _xORB, weld::Window* pParent, weld::Window* pTopParent, IItemSetHelper* _pItemSetHelper) + : m_xContext(_xORB) + , m_pParent(pParent) + , m_pItemSetHelper(_pItemSetHelper) +{ + /// initialize the property translation map + // direct properties of a data source + m_aDirectPropTranslator.emplace( DSID_CONNECTURL, PROPERTY_URL ); + m_aDirectPropTranslator.emplace( DSID_NAME, PROPERTY_NAME ); + m_aDirectPropTranslator.emplace( DSID_USER, PROPERTY_USER ); + m_aDirectPropTranslator.emplace( DSID_PASSWORD, PROPERTY_PASSWORD ); + m_aDirectPropTranslator.emplace( DSID_PASSWORDREQUIRED, PROPERTY_ISPASSWORDREQUIRED ); + m_aDirectPropTranslator.emplace( DSID_TABLEFILTER, PROPERTY_TABLEFILTER ); + m_aDirectPropTranslator.emplace( DSID_READONLY, PROPERTY_ISREADONLY ); + m_aDirectPropTranslator.emplace( DSID_SUPPRESSVERSIONCL, PROPERTY_SUPPRESSVERSIONCL ); + + // implicit properties, to be found in the direct property "Info" + m_aIndirectPropTranslator.emplace( DSID_JDBCDRIVERCLASS, INFO_JDBCDRIVERCLASS ); + m_aIndirectPropTranslator.emplace( DSID_TEXTFILEEXTENSION, INFO_TEXTFILEEXTENSION ); + m_aIndirectPropTranslator.emplace( DSID_CHARSET, INFO_CHARSET ); + m_aIndirectPropTranslator.emplace( DSID_TEXTFILEHEADER, INFO_TEXTFILEHEADER ); + m_aIndirectPropTranslator.emplace( DSID_FIELDDELIMITER, INFO_FIELDDELIMITER ); + m_aIndirectPropTranslator.emplace( DSID_TEXTDELIMITER, INFO_TEXTDELIMITER ); + m_aIndirectPropTranslator.emplace( DSID_DECIMALDELIMITER, INFO_DECIMALDELIMITER ); + m_aIndirectPropTranslator.emplace( DSID_THOUSANDSDELIMITER, INFO_THOUSANDSDELIMITER ); + m_aIndirectPropTranslator.emplace( DSID_SHOWDELETEDROWS, INFO_SHOWDELETEDROWS ); + m_aIndirectPropTranslator.emplace( DSID_ALLOWLONGTABLENAMES, INFO_ALLOWLONGTABLENAMES ); + m_aIndirectPropTranslator.emplace( DSID_ADDITIONALOPTIONS, INFO_ADDITIONALOPTIONS ); + m_aIndirectPropTranslator.emplace( DSID_SQL92CHECK, PROPERTY_ENABLESQL92CHECK ); + m_aIndirectPropTranslator.emplace( DSID_AUTOINCREMENTVALUE, PROPERTY_AUTOINCREMENTCREATION ); + m_aIndirectPropTranslator.emplace( DSID_AUTORETRIEVEVALUE, INFO_AUTORETRIEVEVALUE ); + m_aIndirectPropTranslator.emplace( DSID_AUTORETRIEVEENABLED, INFO_AUTORETRIEVEENABLED ); + m_aIndirectPropTranslator.emplace( DSID_APPEND_TABLE_ALIAS, INFO_APPEND_TABLE_ALIAS ); + m_aIndirectPropTranslator.emplace( DSID_AS_BEFORE_CORRNAME, INFO_AS_BEFORE_CORRELATION_NAME ); + m_aIndirectPropTranslator.emplace( DSID_CHECK_REQUIRED_FIELDS, INFO_FORMS_CHECK_REQUIRED_FIELDS ); + m_aIndirectPropTranslator.emplace( DSID_ESCAPE_DATETIME, INFO_ESCAPE_DATETIME ); + m_aIndirectPropTranslator.emplace( DSID_PRIMARY_KEY_SUPPORT, OUString("PrimaryKeySupport") ); + m_aIndirectPropTranslator.emplace( DSID_PARAMETERNAMESUBST, INFO_PARAMETERNAMESUBST ); + m_aIndirectPropTranslator.emplace( DSID_IGNOREDRIVER_PRIV, INFO_IGNOREDRIVER_PRIV ); + m_aIndirectPropTranslator.emplace( DSID_BOOLEANCOMPARISON, PROPERTY_BOOLEANCOMPARISONMODE ); + m_aIndirectPropTranslator.emplace( DSID_ENABLEOUTERJOIN, PROPERTY_ENABLEOUTERJOIN ); + m_aIndirectPropTranslator.emplace( DSID_CATALOG, PROPERTY_USECATALOGINSELECT ); + m_aIndirectPropTranslator.emplace( DSID_SCHEMA, PROPERTY_USESCHEMAINSELECT ); + m_aIndirectPropTranslator.emplace( DSID_INDEXAPPENDIX, OUString("AddIndexAppendix") ); + m_aIndirectPropTranslator.emplace( DSID_DOSLINEENDS, OUString("PreferDosLikeLineEnds") ); + m_aIndirectPropTranslator.emplace( DSID_CONN_SOCKET, OUString("LocalSocket") ); + m_aIndirectPropTranslator.emplace( DSID_NAMED_PIPE, OUString("NamedPipe") ); + m_aIndirectPropTranslator.emplace( DSID_RESPECTRESULTSETTYPE, OUString("RespectDriverResultSetType") ); + m_aIndirectPropTranslator.emplace( DSID_MAX_ROW_SCAN, OUString("MaxRowScan") ); + + // extra settings for ODBC + m_aIndirectPropTranslator.emplace( DSID_USECATALOG, INFO_USECATALOG ); + // extra settings for an LDAP address book + m_aIndirectPropTranslator.emplace( DSID_CONN_LDAP_BASEDN, INFO_CONN_LDAP_BASEDN ); + m_aIndirectPropTranslator.emplace( DSID_CONN_LDAP_ROWCOUNT, INFO_CONN_LDAP_ROWCOUNT ); + m_aIndirectPropTranslator.emplace( DSID_CONN_LDAP_USESSL, OUString("UseSSL") ); + m_aIndirectPropTranslator.emplace( DSID_DOCUMENT_URL, PROPERTY_URL ); + + // Oracle + m_aIndirectPropTranslator.emplace( DSID_IGNORECURRENCY, OUString("IgnoreCurrency") ); + + try + { + m_xDatabaseContext = DatabaseContext::create(m_xContext); + } + catch(const Exception&) + { + ShowServiceNotAvailableError(pTopParent, u"com.sun.star.sdb.DatabaseContext", true); + } +} + +bool ODbDataSourceAdministrationHelper::getCurrentSettings(Sequence< PropertyValue >& _rDriverParam) +{ + OSL_ENSURE(m_pItemSetHelper->getOutputSet(), "ODbDataSourceAdministrationHelper::getCurrentSettings : not to be called without an example set!"); + if (!m_pItemSetHelper->getOutputSet()) + return false; + + std::vector< PropertyValue > aReturn; + // collecting this in a vector because it has a push_back, in opposite to sequences + + // user: DSID_USER -> "user" + const SfxStringItem* pUser = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_USER); + if (pUser && pUser->GetValue().getLength()) + aReturn.emplace_back( "user", 0, + Any(pUser->GetValue()), PropertyState_DIRECT_VALUE); + + // check if the connection type requires a password + if (hasAuthentication(*m_pItemSetHelper->getOutputSet())) + { + // password: DSID_PASSWORD -> password + const SfxStringItem* pPassword = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_PASSWORD); + OUString sPassword = pPassword ? pPassword->GetValue() : OUString(); + const SfxBoolItem* pPasswordRequired = m_pItemSetHelper->getOutputSet()->GetItem<SfxBoolItem>(DSID_PASSWORDREQUIRED); + // if the set does not contain a password, but the item set says it requires one, ask the user + if ((!pPassword || !pPassword->GetValue().getLength()) && (pPasswordRequired && pPasswordRequired->GetValue())) + { + const SfxStringItem* pName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_NAME); + + Reference< XModel > xModel( getDataSourceOrModel( m_xDatasource ), UNO_QUERY_THROW ); + ::comphelper::NamedValueCollection aArgs( xModel->getArgs() ); + Reference< XInteractionHandler > xHandler( aArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) ); + + if ( !xHandler.is() ) + { + // instantiate the default SDB interaction handler + xHandler = task::InteractionHandler::createWithParent(m_xContext, m_pParent->GetXWindow()); + } + + OUString sName = pName ? pName->GetValue() : OUString(); + OUString sLoginRequest(DBA_RES(STR_ENTER_CONNECTION_PASSWORD)); + OUString sTemp = sName; + sName = ::dbaui::getStrippedDatabaseName(nullptr,sTemp); + if ( !sName.isEmpty() ) + sLoginRequest = sLoginRequest.replaceAll("$name$", sName); + else + { + sLoginRequest = sLoginRequest.replaceAll("\"$name$\"", ""); + // ensure that in other languages the string will be deleted + sLoginRequest = sLoginRequest.replaceAll("$name$", ""); + } + + // the request + AuthenticationRequest aRequest; + aRequest.ServerName = sName; + aRequest.Diagnostic = sLoginRequest; + aRequest.HasRealm = false; + // aRequest.Realm + aRequest.HasUserName = pUser != nullptr; + aRequest.UserName = pUser ? pUser->GetValue() : OUString(); + aRequest.HasPassword = true; + //aRequest.Password + aRequest.HasAccount = false; + // aRequest.Account + + rtl::Reference<comphelper::OInteractionRequest> pRequest = new comphelper::OInteractionRequest(Any(aRequest)); + + // build an interaction request + // two continuations (Ok and Cancel) + ::rtl::Reference< comphelper::OInteractionAbort > pAbort = new comphelper::OInteractionAbort; + ::rtl::Reference< dbaccess::OAuthenticationContinuation > pAuthenticate = new dbaccess::OAuthenticationContinuation; + pAuthenticate->setCanChangeUserName( false ); + pAuthenticate->setRememberPassword( RememberAuthentication_SESSION ); + + // some knittings + pRequest->addContinuation(pAbort); + pRequest->addContinuation(pAuthenticate); + + // handle the request + try + { + SolarMutexGuard aSolarGuard; + // release the mutex when calling the handler, it may need to lock the SolarMutex + xHandler->handle(pRequest); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + if (!pAuthenticate->wasSelected()) + return false; + + sPassword = pAuthenticate->getPassword(); + if (pAuthenticate->getRememberPassword()) + m_pItemSetHelper->getWriteOutputSet()->Put(SfxStringItem(DSID_PASSWORD, sPassword)); + } + + if (!sPassword.isEmpty()) + aReturn.emplace_back( "password", 0, + Any(sPassword), PropertyState_DIRECT_VALUE); + } + + if ( !aReturn.empty() ) + _rDriverParam = comphelper::containerToSequence(aReturn); + + // append all the other stuff (charset etc.) + fillDatasourceInfo(*m_pItemSetHelper->getOutputSet(), _rDriverParam); + + return true; +} + +void ODbDataSourceAdministrationHelper::successfullyConnected() +{ + OSL_ENSURE(m_pItemSetHelper->getOutputSet(), "ODbDataSourceAdministrationHelper::successfullyConnected: not to be called without an example set!"); + if (!m_pItemSetHelper->getOutputSet()) + return; + + if (hasAuthentication(*m_pItemSetHelper->getOutputSet())) + { + const SfxStringItem* pPassword = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_PASSWORD); + if (pPassword && (0 != pPassword->GetValue().getLength())) + { + OUString sPassword = pPassword->GetValue(); + + Reference< XPropertySet > xCurrentDatasource = getCurrentDataSource(); + lcl_putProperty(xCurrentDatasource,m_aDirectPropTranslator[DSID_PASSWORD], Any(sPassword)); + } + } +} + +void ODbDataSourceAdministrationHelper::clearPassword() +{ + if (m_pItemSetHelper->getWriteOutputSet()) + m_pItemSetHelper->getWriteOutputSet()->ClearItem(DSID_PASSWORD); +} + +std::pair< Reference<XConnection>,bool> ODbDataSourceAdministrationHelper::createConnection() +{ + std::pair< Reference<XConnection>,bool> aRet; + aRet.second = false; + Sequence< PropertyValue > aConnectionParams; + if ( getCurrentSettings(aConnectionParams) ) + { + // the current DSN + // fill the table list with this connection information + SQLExceptionInfo aErrorInfo; + try + { + weld::WaitObject aWaitCursor(m_pParent); + aRet.first = getDriver()->connect(getConnectionURL(), aConnectionParams); + aRet.second = true; + } + catch (const SQLContext& e) { aErrorInfo = SQLExceptionInfo(e); } + catch (const SQLWarning& e) { aErrorInfo = SQLExceptionInfo(e); } + catch (const SQLException& e) { aErrorInfo = SQLExceptionInfo(e); } + + showError(aErrorInfo,m_pParent->GetXWindow(),getORB()); + } + if ( aRet.first.is() ) + successfullyConnected();// notify the admindlg to save the password + + return aRet; +} + +Reference< XDriver > ODbDataSourceAdministrationHelper::getDriver() +{ + return getDriver(getConnectionURL()); +} + +Reference< XDriver > ODbDataSourceAdministrationHelper::getDriver(const OUString& _sURL) +{ + // get the global DriverManager + Reference< XConnectionPool > xDriverManager; + + OUString sCurrentActionError = DBA_RES(STR_COULDNOTCREATE_DRIVERMANAGER); + sCurrentActionError = sCurrentActionError.replaceFirst("#servicename#", "com.sun.star.sdbc.ConnectionPool"); + + try + { + xDriverManager.set( ConnectionPool::create( getORB() ) ); + } + catch (const Exception&) + { + css::uno::Any anyEx = cppu::getCaughtException(); + // wrap the exception into an SQLException + throw SQLException(sCurrentActionError, getORB(), "S1000", 0, anyEx); + } + + Reference< XDriver > xDriver = xDriverManager->getDriverByURL(_sURL); + if (!xDriver.is()) + { + sCurrentActionError = DBA_RES(STR_NOREGISTEREDDRIVER); + sCurrentActionError = sCurrentActionError.replaceFirst("#connurl#", _sURL); + // will be caught and translated into an SQLContext exception + throw SQLException(sCurrentActionError, getORB(), "S1000", 0, Any()); + } + return xDriver; +} + +Reference< XPropertySet > const & ODbDataSourceAdministrationHelper::getCurrentDataSource() +{ + if ( !m_xDatasource.is() ) + { + Reference<XInterface> xIn(m_aDataSourceOrName,UNO_QUERY); + if ( !xIn.is() ) + { + OUString sCurrentDatasource; + m_aDataSourceOrName >>= sCurrentDatasource; + OSL_ENSURE(!sCurrentDatasource.isEmpty(),"No datasource name given!"); + try + { + if ( m_xDatabaseContext.is() ) + m_xDatasource.set(m_xDatabaseContext->getByName(sCurrentDatasource),UNO_QUERY); + xIn = m_xDatasource; + } + catch(const Exception&) + { + } + } + m_xModel.set(getDataSourceOrModel(xIn),UNO_QUERY); + if ( m_xModel.is() ) + m_xDatasource.set(xIn,UNO_QUERY); + else + { + m_xDatasource.set(getDataSourceOrModel(xIn),UNO_QUERY); + m_xModel.set(xIn,UNO_QUERY); + } + } + + OSL_ENSURE(m_xDatasource.is(), "ODbDataSourceAdministrationHelper::getCurrentDataSource: no data source!"); + return m_xDatasource; +} + +OUString ODbDataSourceAdministrationHelper::getDatasourceType( const SfxItemSet& _rSet ) +{ + const SfxStringItem* pConnectURL = _rSet.GetItem<SfxStringItem>(DSID_CONNECTURL); + OSL_ENSURE( pConnectURL , "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!" ); + const DbuTypeCollectionItem* pTypeCollection = _rSet.GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION); + OSL_ENSURE(pTypeCollection, "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!"); + ::dbaccess::ODsnTypeCollection* pCollection = pTypeCollection->getCollection(); + return pCollection->getType(pConnectURL->GetValue()); +} + +bool ODbDataSourceAdministrationHelper::hasAuthentication(const SfxItemSet& _rSet) +{ + return DataSourceMetaData::getAuthentication( getDatasourceType( _rSet ) ) != AuthNone; +} + +OUString ODbDataSourceAdministrationHelper::getConnectionURL() const +{ + OUString sNewUrl; + + OUString eType = getDatasourceType(*m_pItemSetHelper->getOutputSet()); + + const SfxStringItem* pUrlItem = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_CONNECTURL); + const DbuTypeCollectionItem* pTypeCollection = m_pItemSetHelper->getOutputSet()->GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION); + + OSL_ENSURE(pUrlItem,"Connection URL is NULL. -> GPF!"); + OSL_ENSURE(pTypeCollection, "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!"); + ::dbaccess::ODsnTypeCollection* pCollection = pTypeCollection->getCollection(); + OSL_ENSURE(pCollection, "ODbDataSourceAdministrationHelper::getDatasourceType: invalid type collection!"); + + switch( pCollection->determineType(eType) ) + { + case ::dbaccess::DST_DBASE: + case ::dbaccess::DST_FLAT: + case ::dbaccess::DST_CALC: + case ::dbaccess::DST_WRITER: + break; + case ::dbaccess::DST_MSACCESS: + case ::dbaccess::DST_MSACCESS_2007: + { + OUString sFileName = pCollection->cutPrefix(pUrlItem->GetValue()); + OUString sNewFileName; + if ( ::osl::FileBase::getSystemPathFromFileURL( sFileName, sNewFileName ) == ::osl::FileBase::E_None ) + { + sNewUrl += sNewFileName; + } + } + break; + case ::dbaccess::DST_MYSQL_NATIVE: + case ::dbaccess::DST_MYSQL_JDBC: + { + const SfxStringItem* pHostName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_MYSQL_PORTNUMBER); + const SfxStringItem* pDatabaseName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_DATABASENAME); + sNewUrl = lcl_createHostWithPort(pHostName,pPortNumber); + OUString sDatabaseName = pDatabaseName ? pDatabaseName->GetValue() : OUString(); + if ( !sDatabaseName.getLength() && pUrlItem ) + sDatabaseName = pCollection->cutPrefix( pUrlItem->GetValue() ); + // TODO: what's that? Why is the database name transported via the URL Item? + // Huh? Anybody there? + // OJ: It is needed when the connection properties are changed. There the URL is used for every type. + + if ( !sDatabaseName.isEmpty() ) + { + sNewUrl += "/" + sDatabaseName; + } + } + break; + case ::dbaccess::DST_ORACLE_JDBC: + { + const SfxStringItem* pHostName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_ORACLE_PORTNUMBER); + const SfxStringItem* pDatabaseName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_DATABASENAME); + if ( pHostName && pHostName->GetValue().getLength() ) + { + sNewUrl = "@" + lcl_createHostWithPort(pHostName,pPortNumber); + OUString sDatabaseName = pDatabaseName ? pDatabaseName->GetValue() : OUString(); + if ( sDatabaseName.isEmpty() && pUrlItem ) + sDatabaseName = pCollection->cutPrefix( pUrlItem->GetValue() ); + if ( !sDatabaseName.isEmpty() ) + { + sNewUrl += ":" + sDatabaseName; + } + } + else + { // here someone entered a JDBC url which looks like oracle, so we have to use the url property + + } + } + break; + case ::dbaccess::DST_LDAP: + { + const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_CONN_LDAP_PORTNUMBER); + sNewUrl = pCollection->cutPrefix(pUrlItem->GetValue()) + lcl_createHostWithPort(nullptr,pPortNumber); + } + break; + case ::dbaccess::DST_JDBC: + // run through + default: + break; + } + if ( !sNewUrl.isEmpty() ) + sNewUrl = pCollection->getPrefix(eType) + sNewUrl; + else + sNewUrl = pUrlItem->GetValue(); + + return sNewUrl; +} + +namespace { + +struct PropertyValueLess +{ + bool operator() (const PropertyValue& x, const PropertyValue& y) const + { return x.Name < y.Name; } // construct prevents a MSVC6 warning +}; + +} + +typedef std::set<PropertyValue, PropertyValueLess> PropertyValueSet; + +void ODbDataSourceAdministrationHelper::translateProperties(const Reference< XPropertySet >& _rxSource, SfxItemSet& _rDest) +{ + if (_rxSource.is()) + { + for (auto const& elem : m_aDirectPropTranslator) + { + // get the property value + Any aValue; + try + { + aValue = _rxSource->getPropertyValue(elem.second); + } + catch(Exception&) + { + SAL_WARN("dbaccess", "ODbDataSourceAdministrationHelper::translateProperties: could not extract the property " + << elem.second); + } + // transfer it into an item + implTranslateProperty(_rDest, elem.first, aValue); + } + + // get the additional information + Sequence< PropertyValue > aAdditionalInfo; + try + { + _rxSource->getPropertyValue(PROPERTY_INFO) >>= aAdditionalInfo; + } + catch(Exception&) { } + + // collect the names of the additional settings + PropertyValueSet aInfos; + for (const PropertyValue& rAdditionalInfo : std::as_const(aAdditionalInfo)) + { + if( rAdditionalInfo.Name == "JDBCDRV" ) + { // compatibility + PropertyValue aCompatibility(rAdditionalInfo); + aCompatibility.Name = "JavaDriverClass"; + aInfos.insert(aCompatibility); + } + else + aInfos.insert(rAdditionalInfo); + } + + // go through all known translations and check if we have such a setting + if ( !aInfos.empty() ) + { + PropertyValue aSearchFor; + for (auto const& elem : m_aIndirectPropTranslator) + { + aSearchFor.Name = elem.second; + PropertyValueSet::const_iterator aInfoPos = aInfos.find(aSearchFor); + if (aInfos.end() != aInfoPos) + // the property is contained in the info sequence + // -> transfer it into an item + implTranslateProperty(_rDest, elem.first, aInfoPos->Value); + } + } + + convertUrl(_rDest); + } + + try + { + Reference<XStorable> xStore(getDataSourceOrModel(_rxSource),UNO_QUERY); + _rDest.Put(SfxBoolItem(DSID_READONLY, !xStore.is() || xStore->isReadonly() )); + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION("dbaccess", "IsReadOnly throws"); + } +} + +void ODbDataSourceAdministrationHelper::translateProperties(const SfxItemSet& _rSource, const Reference< XPropertySet >& _rxDest) +{ + OSL_ENSURE(_rxDest.is(), "ODbDataSourceAdministrationHelper::translateProperties: invalid property set!"); + if (!_rxDest.is()) + return; + + // the property set info + Reference< XPropertySetInfo > xInfo; + try { xInfo = _rxDest->getPropertySetInfo(); } + catch(Exception&) { } + + static const OUStringLiteral sUrlProp(u"URL"); + // transfer the direct properties + for (auto const& elem : m_aDirectPropTranslator) + { + const SfxPoolItem* pCurrentItem = _rSource.GetItem(static_cast<sal_uInt16>(elem.first)); + if (pCurrentItem) + { + sal_Int16 nAttributes = PropertyAttribute::READONLY; + if (xInfo.is()) + { + try { nAttributes = xInfo->getPropertyByName(elem.second).Attributes; } + catch(Exception&) { } + } + if ((nAttributes & PropertyAttribute::READONLY) == 0) + { + if ( sUrlProp == elem.second ) + { + Any aValue(getConnectionURL()); + // aValue <<= OUString(); + lcl_putProperty(_rxDest, elem.second,aValue); + } + else + implTranslateProperty(_rxDest, elem.second, pCurrentItem); + } + } + } + + // now for the indirect properties + + Sequence< PropertyValue > aInfo; + // the original properties + try + { + _rxDest->getPropertyValue(PROPERTY_INFO) >>= aInfo; + } + catch(Exception&) { } + + // overwrite and extend them + fillDatasourceInfo(_rSource, aInfo); + // and propagate the (newly composed) sequence to the set + lcl_putProperty(_rxDest,PROPERTY_INFO, Any(aInfo)); +} + +void ODbDataSourceAdministrationHelper::fillDatasourceInfo(const SfxItemSet& _rSource, Sequence< css::beans::PropertyValue >& _rInfo) +{ + // within the current "Info" sequence, replace the ones we can examine from the item set + // (we don't just fill a completely new sequence with our own items, but we preserve any properties unknown to + // us) + + // first determine which of all the items are relevant for the data source (depends on the connection url) + const OUString eType = getDatasourceType(_rSource); + const ::connectivity::DriversConfig aDriverConfig(getORB()); + const ::comphelper::NamedValueCollection& aProperties = aDriverConfig.getProperties(eType); + + // collect the translated property values for the relevant items + PropertyValueSet aRelevantSettings; + MapInt2String::const_iterator aTranslation; + for (ItemID detailId = DSID_FIRST_ITEM_ID ; detailId <= DSID_LAST_ITEM_ID; ++detailId) + { + const SfxPoolItem* pCurrent = _rSource.GetItem(static_cast<sal_uInt16>(detailId)); + aTranslation = m_aIndirectPropTranslator.find(detailId); + if ( pCurrent && (m_aIndirectPropTranslator.end() != aTranslation) && + aProperties.has(aTranslation->second) ) + { + if ( aTranslation->second == INFO_CHARSET ) + { + OUString sCharSet; + implTranslateProperty(pCurrent) >>= sCharSet; + if ( !sCharSet.isEmpty() ) + aRelevantSettings.insert(PropertyValue(aTranslation->second, 0, Any(sCharSet), PropertyState_DIRECT_VALUE)); + } + else + aRelevantSettings.insert(PropertyValue(aTranslation->second, 0, implTranslateProperty(pCurrent), PropertyState_DIRECT_VALUE)); + } + } + + // settings to preserve + MapInt2String aPreservedSettings; + + // now aRelevantSettings contains all the property values relevant for the current data source type, + // check the original sequence if it already contains any of these values (which have to be overwritten, then) + PropertyValue* pInfo = _rInfo.getArray(); + PropertyValue aSearchFor; + sal_Int32 nObsoleteSetting = -1; + sal_Int32 nCount = _rInfo.getLength(); + for (sal_Int32 i = 0; i < nCount; ++i, ++pInfo) + { + aSearchFor.Name = pInfo->Name; + PropertyValueSet::const_iterator aOverwrittenSetting = aRelevantSettings.find(aSearchFor); + if (aRelevantSettings.end() != aOverwrittenSetting) + { // the setting was present in the original sequence, and it is to be overwritten -> replace it + if ( pInfo->Value != aOverwrittenSetting->Value ) + *pInfo = *aOverwrittenSetting; + aRelevantSettings.erase(aOverwrittenSetting); + } + else if( pInfo->Name == "JDBCDRV" ) + { // this is a compatibility setting, remove it from the sequence (it's replaced by JavaDriverClass) + nObsoleteSetting = i; + } + else + aPreservedSettings[i] = pInfo->Name; + } + if (-1 != nObsoleteSetting) + ::comphelper::removeElementAt(_rInfo, nObsoleteSetting); + + if ( !aPreservedSettings.empty() ) + { // check if there are settings which + // * are known as indirect properties + // * but not relevant for the current data source type + // These settings have to be removed: If they're not relevant, we have no UI for changing them. + + // for this, we need a string-controlled quick access to m_aIndirectPropTranslator + std::set<OUString> aIndirectProps; + std::transform(m_aIndirectPropTranslator.begin(), + m_aIndirectPropTranslator.end(), + std::inserter(aIndirectProps,aIndirectProps.begin()), + ::o3tl::select2nd< MapInt2String::value_type >()); + + // now check the to-be-preserved props + std::vector< sal_Int32 > aRemoveIndexes; + sal_Int32 nPositionCorrector = 0; + for (auto const& preservedSetting : aPreservedSettings) + { + if (aIndirectProps.end() != aIndirectProps.find(preservedSetting.second)) + { + aRemoveIndexes.push_back(preservedSetting.first - nPositionCorrector); + ++nPositionCorrector; + } + } + // now finally remove all such props + for (auto const& removeIndex : aRemoveIndexes) + ::comphelper::removeElementAt(_rInfo, removeIndex); + } + + Sequence< Any> aTypeSettings; + aTypeSettings = aProperties.getOrDefault("TypeInfoSettings",aTypeSettings); + // here we have a special entry for types from oracle + if ( aTypeSettings.hasElements() ) + { + aRelevantSettings.insert(PropertyValue("TypeInfoSettings", 0, Any(aTypeSettings), PropertyState_DIRECT_VALUE)); + } + + // check which values are still left ('cause they were not present in the original sequence, but are to be set) + if ( aRelevantSettings.empty() ) + return; + + sal_Int32 nOldLength = _rInfo.getLength(); + _rInfo.realloc(nOldLength + aRelevantSettings.size()); + PropertyValue* pAppendValues = _rInfo.getArray() + nOldLength; + for (auto const& relevantSetting : aRelevantSettings) + { + if ( relevantSetting.Name == INFO_CHARSET ) + { + OUString sCharSet; + relevantSetting.Value >>= sCharSet; + if ( !sCharSet.isEmpty() ) + *pAppendValues = relevantSetting; + } + else + *pAppendValues = relevantSetting; + ++pAppendValues; + } +} + +Any ODbDataSourceAdministrationHelper::implTranslateProperty(const SfxPoolItem* _pItem) +{ + // translate the SfxPoolItem + Any aValue; + + const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>( _pItem ); + const SfxBoolItem* pBoolItem = dynamic_cast<const SfxBoolItem*>( _pItem ); + const OptionalBoolItem* pOptBoolItem = dynamic_cast<const OptionalBoolItem*>( _pItem ); + const SfxInt32Item* pInt32Item = dynamic_cast< const SfxInt32Item* >( _pItem ); + const OStringListItem* pStringListItem = dynamic_cast<const OStringListItem*>( _pItem ); + + if ( pStringItem ) + { + aValue <<= pStringItem->GetValue(); + } + else if ( pBoolItem ) + { + aValue <<= pBoolItem->GetValue(); + } + else if ( pOptBoolItem ) + { + if ( !pOptBoolItem->HasValue() ) + aValue.clear(); + else + aValue <<= pOptBoolItem->GetValue(); + } + else if ( pInt32Item ) + { + aValue <<= pInt32Item->GetValue(); + } + else if ( pStringListItem ) + { + aValue <<= pStringListItem->getList(); + } + else + { + OSL_FAIL("ODbDataSourceAdministrationHelper::implTranslateProperty: unsupported item type!"); + return aValue; + } + + return aValue; +} + +void ODbDataSourceAdministrationHelper::implTranslateProperty(const Reference< XPropertySet >& _rxSet, const OUString& _rName, const SfxPoolItem* _pItem) +{ + Any aValue = implTranslateProperty(_pItem); + lcl_putProperty(_rxSet, _rName,aValue); +} + +OString ODbDataSourceAdministrationHelper::translatePropertyId( sal_Int32 _nId ) +{ + OUString aString; + + MapInt2String::const_iterator aPos = m_aDirectPropTranslator.find( _nId ); + if ( m_aDirectPropTranslator.end() != aPos ) + { + aString = aPos->second; + } + else + { + MapInt2String::const_iterator indirectPos = m_aIndirectPropTranslator.find( _nId ); + if ( m_aIndirectPropTranslator.end() != indirectPos ) + aString = indirectPos->second; + } + + OString aReturn( aString.getStr(), aString.getLength(), RTL_TEXTENCODING_ASCII_US ); + return aReturn; +} +template<class T> static bool checkItemType(const SfxPoolItem* pItem){ return dynamic_cast<const T*>(pItem) != nullptr;} + +void ODbDataSourceAdministrationHelper::implTranslateProperty( SfxItemSet& _rSet, sal_Int32 _nId, const Any& _rValue ) +{ + switch ( _rValue.getValueType().getTypeClass() ) + { + case TypeClass_STRING: + if ( implCheckItemType( _rSet, _nId, checkItemType<SfxStringItem> ) ) + { + OUString sValue; + _rValue >>= sValue; + _rSet.Put(SfxStringItem(_nId, sValue)); + } + else { + SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value (" + << translatePropertyId(_nId) << " should be no string)!"); + } + break; + + case TypeClass_BOOLEAN: + if ( implCheckItemType( _rSet, _nId, checkItemType<SfxBoolItem> ) ) + { + bool bVal = false; + _rValue >>= bVal; + _rSet.Put(SfxBoolItem(_nId, bVal)); + } + else if ( implCheckItemType( _rSet, _nId, checkItemType<OptionalBoolItem> ) ) + { + OptionalBoolItem aItem( _nId ); + if ( _rValue.hasValue() ) + { + bool bValue = false; + _rValue >>= bValue; + aItem.SetValue( bValue ); + } + else + aItem.ClearValue(); + _rSet.Put( aItem ); + } + else { + SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value (" + << translatePropertyId(_nId) + << " should be no boolean)!"); + } + break; + + case TypeClass_LONG: + if ( implCheckItemType( _rSet, _nId, checkItemType<SfxInt32Item> ) ) + { + sal_Int32 nValue = 0; + _rValue >>= nValue; + _rSet.Put( SfxInt32Item( _nId, nValue ) ); + } + else { + SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value (" + << translatePropertyId(_nId) + << " should be no int)!"); + } + break; + + case TypeClass_SEQUENCE: + if ( implCheckItemType( _rSet, _nId, checkItemType<OStringListItem> ) ) + { + // determine the element type + TypeDescription aTD(_rValue.getValueType()); + typelib_IndirectTypeDescription* pSequenceTD = + reinterpret_cast< typelib_IndirectTypeDescription* >(aTD.get()); + OSL_ENSURE(pSequenceTD && pSequenceTD->pType, "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid sequence type!"); + + Type aElementType(pSequenceTD->pType); + switch (aElementType.getTypeClass()) + { + case TypeClass_STRING: + { + Sequence< OUString > aStringList; + _rValue >>= aStringList; + _rSet.Put(OStringListItem(_nId, aStringList)); + } + break; + default: + OSL_FAIL("ODbDataSourceAdministrationHelper::implTranslateProperty: unsupported property value type!"); + } + } + else { + SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value (" + << translatePropertyId(_nId) + << " should be no string sequence)!"); + } + break; + + case TypeClass_VOID: + _rSet.ClearItem(_nId); + break; + + default: + OSL_FAIL("ODbDataSourceAdministrationHelper::implTranslateProperty: unsupported property value type!"); + } +} + +OUString ODbDataSourceAdministrationHelper::getDocumentUrl(SfxItemSet const & _rDest) +{ + const SfxStringItem* pUrlItem = _rDest.GetItem<SfxStringItem>(DSID_DOCUMENT_URL); + OSL_ENSURE(pUrlItem,"Document URL is NULL. -> GPF!"); + return pUrlItem->GetValue(); +} + +void ODbDataSourceAdministrationHelper::convertUrl(SfxItemSet& _rDest) +{ + OUString eType = getDatasourceType(_rDest); + + const SfxStringItem* pUrlItem = _rDest.GetItem<SfxStringItem>(DSID_CONNECTURL); + const DbuTypeCollectionItem* pTypeCollection = _rDest.GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION); + + OSL_ENSURE(pUrlItem,"Connection URL is NULL. -> GPF!"); + OSL_ENSURE(pTypeCollection, "ODbAdminDialog::getDatasourceType: invalid items in the source set!"); + ::dbaccess::ODsnTypeCollection* pCollection = pTypeCollection->getCollection(); + OSL_ENSURE(pCollection, "ODbAdminDialog::getDatasourceType: invalid type collection!"); + + sal_uInt16 nPortNumberId = 0; + sal_Int32 nPortNumber = -1; + OUString sNewHostName; + OUString sUrlPart; + + pCollection->extractHostNamePort(pUrlItem->GetValue(),sUrlPart,sNewHostName,nPortNumber); + const ::dbaccess::DATASOURCE_TYPE eTy = pCollection->determineType(eType); + + switch( eTy ) + { + case ::dbaccess::DST_MYSQL_NATIVE: + case ::dbaccess::DST_MYSQL_JDBC: + nPortNumberId = DSID_MYSQL_PORTNUMBER; + break; + case ::dbaccess::DST_ORACLE_JDBC: + nPortNumberId = DSID_ORACLE_PORTNUMBER; + break; + case ::dbaccess::DST_LDAP: + nPortNumberId = DSID_CONN_LDAP_PORTNUMBER; + break; + default: + break; + } + + if ( !sUrlPart.isEmpty() ) + { + if ( eTy == ::dbaccess::DST_MYSQL_NATIVE ) + { + _rDest.Put( SfxStringItem( DSID_DATABASENAME, sUrlPart ) ); + } + else + { + OUString sNewUrl = pCollection->getPrefix(eType) + sUrlPart; + _rDest.Put( SfxStringItem( DSID_CONNECTURL, sNewUrl ) ); + } + } + + if ( !sNewHostName.isEmpty() ) + _rDest.Put(SfxStringItem(DSID_CONN_HOSTNAME, sNewHostName)); + + if ( nPortNumber != -1 && nPortNumberId != 0 ) + _rDest.Put(SfxInt32Item(nPortNumberId, nPortNumber)); + +} + +bool ODbDataSourceAdministrationHelper::saveChanges(const SfxItemSet& _rSource) +{ + // put the remembered settings into the property set + Reference<XPropertySet> xDatasource = getCurrentDataSource(); + if ( !xDatasource.is() ) + return false; + + translateProperties(_rSource,xDatasource ); + + return true; +} + +void ODbDataSourceAdministrationHelper::setDataSourceOrName( const Any& _rDataSourceOrName ) +{ + OSL_ENSURE( !m_aDataSourceOrName.hasValue(), "ODbDataSourceAdministrationHelper::setDataSourceOrName: already have one!" ); + // hmm. We could reset m_xDatasource/m_xModel, probably, and continue working + m_aDataSourceOrName = _rDataSourceOrName; +} + +// DbuTypeCollectionItem +DbuTypeCollectionItem::DbuTypeCollectionItem(sal_Int16 _nWhich, ::dbaccess::ODsnTypeCollection* _pCollection) + :SfxPoolItem(_nWhich) + ,m_pCollection(_pCollection) +{ +} + +DbuTypeCollectionItem::DbuTypeCollectionItem(const DbuTypeCollectionItem& _rSource) + :SfxPoolItem(_rSource) + ,m_pCollection(_rSource.getCollection()) +{ +} + +bool DbuTypeCollectionItem::operator==(const SfxPoolItem& _rItem) const +{ + return SfxPoolItem::operator==(_rItem) && + static_cast<const DbuTypeCollectionItem&>( _rItem ).getCollection() == getCollection(); +} + +DbuTypeCollectionItem* DbuTypeCollectionItem::Clone(SfxItemPool* /*_pPool*/) const +{ + return new DbuTypeCollectionItem(*this); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/DbAdminImpl.hxx b/dbaccess/source/ui/dlg/DbAdminImpl.hxx new file mode 100644 index 000000000..22a61ecee --- /dev/null +++ b/dbaccess/source/ui/dlg/DbAdminImpl.hxx @@ -0,0 +1,167 @@ +/* -*- 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/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/sdb/XDatabaseContext.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XDriver.hpp> +#include <dsntypes.hxx> +#include <svl/itemset.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <svl/poolitem.hxx> +#include <vcl/weld.hxx> + +namespace dbaui +{ + namespace DataSourceInfoConverter + { + void convert(const css::uno::Reference< css::uno::XComponentContext> & xContext, + const ::dbaccess::ODsnTypeCollection* _pCollection, + const OUString& _sOldURLPrefix, + const OUString& _sNewURLPrefix, + const css::uno::Reference< css::beans::XPropertySet >& _xDatasource); + }; + class IItemSetHelper; + // ODbDataSourceAdministrationHelper + class ODbDataSourceAdministrationHelper final + { + public: + typedef std::map<sal_Int32, OUString> MapInt2String; + + private: + css::uno::Reference< css::uno::XComponentContext > + m_xContext; /// service factory + css::uno::Reference< css::sdb::XDatabaseContext > + m_xDatabaseContext; /// database context we're working in + css::uno::Reference< css::beans::XPropertySet > m_xDatasource; + css::uno::Reference< css::frame::XModel > m_xModel; + + css::uno::Any m_aDataSourceOrName; + + MapInt2String m_aDirectPropTranslator; /// translating property id's into names (direct properties of a data source) + MapInt2String m_aIndirectPropTranslator; /// translating property id's into names (indirect properties of a data source) + weld::Window* m_pParent; + IItemSetHelper* m_pItemSetHelper; + public: + + ODbDataSourceAdministrationHelper(const css::uno::Reference< css::uno::XComponentContext >& _xORB, + weld::Window* pParent, weld::Window* pTopParent, + IItemSetHelper* _pItemSetHelper); + + /** translate the current dialog SfxItems into driver relevant PropertyValues + @see successfullyConnected + */ + bool getCurrentSettings(css::uno::Sequence< css::beans::PropertyValue >& _rDriverParams); + + /** to be called if the settings got from getCurrentSettings have been used for successfully connecting + @see getCurrentSettings + */ + void successfullyConnected(); + + /// clear the password in the current data source's item set + void clearPassword(); + + const css::uno::Reference< css::uno::XComponentContext >& getORB() const { return m_xContext; } + + /** creates a new connection. The caller is responsible to dispose it !!!! + */ + std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection(); + + /** return the corresponding driver for the selected URL + */ + css::uno::Reference< css::sdbc::XDriver > getDriver(); + css::uno::Reference< css::sdbc::XDriver > getDriver(const OUString& _sURL); + + /** returns the data source the dialog is currently working with + */ + css::uno::Reference< css::beans::XPropertySet > const & getCurrentDataSource(); + // returns the Url of a database document + static OUString getDocumentUrl(SfxItemSet const & _rDest); + + void setDataSourceOrName( const css::uno::Any& _rDataSourceOrName ); + + /** extracts the connection type from the given set<p/> + The connection type is determined by the value of the DSN item, analyzed by the TypeCollection item. + */ + static OUString getDatasourceType( const SfxItemSet& _rSet ); + + /** returns the connection URL + @return + The connection URL + */ + OUString getConnectionURL() const; + + /// fill the necessary information from the url line + static void convertUrl(SfxItemSet& _rDest); + + const MapInt2String& getIndirectProperties() const { return m_aIndirectPropTranslator; } + + /** translates properties of a UNO data source into SfxItems + @param _rxSource + The data source + @param _rDest + The item set to fill. + */ + void translateProperties( + const css::uno::Reference< css::beans::XPropertySet >& _rxSource, + SfxItemSet& _rDest); + + /** translate SfxItems into properties of a UNO data source + @param _rSource + The item set to read from. + @param _rxDest + The data source to fill. + */ + void translateProperties( + const SfxItemSet& _rSource, + const css::uno::Reference< css::beans::XPropertySet >& _rxDest); + + bool saveChanges(const SfxItemSet& _rSource); + private: + /** fill a data source info array with the settings from a given item set + */ + void fillDatasourceInfo(const SfxItemSet& _rSource, css::uno::Sequence< css::beans::PropertyValue >& _rInfo); + + /// translate the given value into an SfxPoolItem, put this into the given set under the given id + void implTranslateProperty(SfxItemSet& _rSet, sal_Int32 _nId, const css::uno::Any& _rValue); + + /// translate the given SfxPoolItem into an <type scope="com.sun.star.Any">uno</type> + static css::uno::Any implTranslateProperty(const SfxPoolItem* _pItem); + + /// translate the given SfxPoolItem into an <type scope="com.sun.star.Any">uno</type>, set it (under the given name) on the given property set + static void implTranslateProperty(const css::uno::Reference< css::beans::XPropertySet >& _rxSet, const OUString& _rName, const SfxPoolItem* _pItem); + + /** check if the data source described by the given set needs authentication<p/> + The return value depends on the data source type only. + */ + static bool hasAuthentication(const SfxItemSet& _rSet); + + OString translatePropertyId( sal_Int32 _nId ); + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/DriverSettings.hxx b/dbaccess/source/ui/dlg/DriverSettings.hxx new file mode 100644 index 000000000..72ce3d459 --- /dev/null +++ b/dbaccess/source/ui/dlg/DriverSettings.hxx @@ -0,0 +1,78 @@ +/* -*- 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 <sfx2/tabdlg.hxx> + +class SfxTabPage; +namespace dbaui +{ + /// a collection class for all details a driver needs + class ODriversSettings + { + public: + + /** Creates the detail page for ado + */ + static std::unique_ptr<SfxTabPage> CreateDbase( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for ado + */ + static std::unique_ptr<SfxTabPage> CreateAdo( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for ODBC + */ + static std::unique_ptr<SfxTabPage> CreateODBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for user + */ + static std::unique_ptr<SfxTabPage> CreateUser( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for MySQLODBC + */ + static std::unique_ptr<SfxTabPage> CreateMySQLODBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for MySQLJDBC + */ + static std::unique_ptr<SfxTabPage> CreateMySQLJDBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for MySQLNATIVE + */ + static std::unique_ptr<SfxTabPage> CreateMySQLNATIVE( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for Oracle JDBC + */ + static std::unique_ptr<SfxTabPage> CreateOracleJDBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for LDAP + */ + static std::unique_ptr<SfxTabPage> CreateLDAP( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /// Creates the detail page for Text + static std::unique_ptr<SfxTabPage> CreateText( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /// creates the GeneratedValues page + static std::unique_ptr<SfxTabPage> CreateGeneratedValuesPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /// creates the "Special Settings" page of the "Advanced Settings" dialog + static std::unique_ptr<SfxTabPage> CreateSpecialSettingsPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/QueryPropertiesDialog.cxx b/dbaccess/source/ui/dlg/QueryPropertiesDialog.cxx new file mode 100644 index 000000000..df0d38e4b --- /dev/null +++ b/dbaccess/source/ui/dlg/QueryPropertiesDialog.cxx @@ -0,0 +1,60 @@ +/* -*- 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/. + */ + +#include <QueryPropertiesDialog.hxx> +#include <strings.hrc> +#include <core_resource.hxx> + +namespace dbaui +{ + +QueryPropertiesDialog::QueryPropertiesDialog( + weld::Window* pParent, const bool bDistinct, const sal_Int64 nLimit ) + : GenericDialogController(pParent, "dbaccess/ui/querypropertiesdialog.ui", "QueryPropertiesDialog") + , m_xRB_Distinct(m_xBuilder->weld_radio_button("distinct")) + , m_xRB_NonDistinct(m_xBuilder->weld_radio_button("nondistinct")) + , m_xLB_Limit(m_xBuilder->weld_combo_box("limitbox")) +{ + m_xRB_Distinct->set_active(bDistinct); + m_xRB_NonDistinct->set_active(!bDistinct); + + m_xLB_Limit->append(OUString::number(-1), DBA_RES(STR_QUERY_LIMIT_ALL)); // ALL_INT and ALL_STRING + /// Default values + sal_Int64 const aDefLimitAry[] = + { + 5, + 10, + 20, + 50 + }; + for (auto a : aDefLimitAry) + m_xLB_Limit->append(OUString::number(a), OUString::number(a)); + OUString sInitial = OUString::number(nLimit); + auto nPos = m_xLB_Limit->find_id(sInitial); + if (nPos != -1) + m_xLB_Limit->set_active(nPos); + else + m_xLB_Limit->set_entry_text(OUString::number(nLimit)); +} + +sal_Int64 QueryPropertiesDialog::getLimit() const +{ + OUString sSelectedId = m_xLB_Limit->get_active_id(); + if (!sSelectedId.isEmpty()) + return sSelectedId.toInt64(); + return m_xLB_Limit->get_active_text().toInt64(); +} + +QueryPropertiesDialog::~QueryPropertiesDialog() +{ +} + +} ///dbaui namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/RelationDlg.cxx b/dbaccess/source/ui/dlg/RelationDlg.cxx new file mode 100644 index 000000000..cc449d9b7 --- /dev/null +++ b/dbaccess/source/ui/dlg/RelationDlg.cxx @@ -0,0 +1,215 @@ +/* -*- 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 <RelationDlg.hxx> + +#include <com/sun/star/sdbc/KeyRule.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <tools/diagnose_ex.h> +#include <JoinDesignView.hxx> +#include <JoinController.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <RTableConnectionData.hxx> +#include <RelationControl.hxx> +#include <cppuhelper/exc_hlp.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::dbaui; +using namespace ::dbtools; + +ORelationDialog::ORelationDialog( OJoinTableView* pParent, + const TTableConnectionData::value_type& pConnectionData, + bool bAllowTableSelect ) + : GenericDialogController(pParent->GetFrameWeld(), + "dbaccess/ui/relationdialog.ui", "RelationDialog") + , m_pParent(pParent) + , m_pOrigConnData(pConnectionData) + , m_bTriedOneUpdate(false) + , m_xRB_NoCascUpd(m_xBuilder->weld_radio_button("addaction")) + , m_xRB_CascUpd(m_xBuilder->weld_radio_button("addcascade")) + , m_xRB_CascUpdNull(m_xBuilder->weld_radio_button("addnull")) + , m_xRB_CascUpdDefault(m_xBuilder->weld_radio_button("adddefault")) + , m_xRB_NoCascDel(m_xBuilder->weld_radio_button("delaction")) + , m_xRB_CascDel(m_xBuilder->weld_radio_button("delcascade")) + , m_xRB_CascDelNull(m_xBuilder->weld_radio_button("delnull")) + , m_xRB_CascDelDefault(m_xBuilder->weld_radio_button("deldefault")) + , m_xPB_OK(m_xBuilder->weld_button("ok")) +{ + // Copy connection + m_pConnData = pConnectionData->NewInstance(); + m_pConnData->CopyFrom( *pConnectionData ); + + Init(m_pConnData); + m_xTableControl.reset(new OTableListBoxControl(m_xBuilder.get(), &pParent->GetTabWinMap(), this)); + + m_xPB_OK->connect_clicked(LINK(this, ORelationDialog, OKClickHdl)); + + m_xTableControl->Init( m_pConnData ); + if ( bAllowTableSelect ) + m_xTableControl->fillListBoxes(); + else + m_xTableControl->fillAndDisable(pConnectionData); + + m_xTableControl->lateInit(); + + m_xTableControl->NotifyCellChange(); +} + +ORelationDialog::~ORelationDialog() +{ +} + +void ORelationDialog::Init(const TTableConnectionData::value_type& _pConnectionData) +{ + ORelationTableConnectionData* pConnData = static_cast<ORelationTableConnectionData*>(_pConnectionData.get()); + // Update Rules + switch (pConnData->GetUpdateRules()) + { + case KeyRule::NO_ACTION: + case KeyRule::RESTRICT: + m_xRB_NoCascUpd->set_active(true); + break; + + case KeyRule::CASCADE: + m_xRB_CascUpd->set_active(true); + break; + + case KeyRule::SET_NULL: + m_xRB_CascUpdNull->set_active(true); + break; + case KeyRule::SET_DEFAULT: + m_xRB_CascUpdDefault->set_active(true); + break; + } + + // Delete Rules + switch (pConnData->GetDeleteRules()) + { + case KeyRule::NO_ACTION: + case KeyRule::RESTRICT: + m_xRB_NoCascDel->set_active(true); + break; + + case KeyRule::CASCADE: + m_xRB_CascDel->set_active(true); + break; + + case KeyRule::SET_NULL: + m_xRB_CascDelNull->set_active(true); + break; + case KeyRule::SET_DEFAULT: + m_xRB_CascDelDefault->set_active(true); + break; + } +} + +IMPL_LINK_NOARG(ORelationDialog, OKClickHdl, weld::Button&, void) +{ + // Read out RadioButtons + sal_uInt16 nAttrib = 0; + + // Delete Rules + if( m_xRB_NoCascDel->get_active() ) + nAttrib |= KeyRule::NO_ACTION; + if( m_xRB_CascDel->get_active() ) + nAttrib |= KeyRule::CASCADE; + if( m_xRB_CascDelNull->get_active() ) + nAttrib |= KeyRule::SET_NULL; + if( m_xRB_CascDelDefault->get_active() ) + nAttrib |= KeyRule::SET_DEFAULT; + + ORelationTableConnectionData* pConnData = static_cast<ORelationTableConnectionData*>(m_pConnData.get()); + pConnData->SetDeleteRules( nAttrib ); + + // Update Rules + nAttrib = 0; + if( m_xRB_NoCascUpd->get_active() ) + nAttrib |= KeyRule::NO_ACTION; + if( m_xRB_CascUpd->get_active() ) + nAttrib |= KeyRule::CASCADE; + if( m_xRB_CascUpdNull->get_active() ) + nAttrib |= KeyRule::SET_NULL; + if( m_xRB_CascUpdDefault->get_active() ) + nAttrib |= KeyRule::SET_DEFAULT; + pConnData->SetUpdateRules( nAttrib ); + + m_xTableControl->SaveModified(); + + //// if the ComboBoxes for the table selection are enabled (constructor with bAllowTableSelect==sal_True), + //// then I must also put the table names into the connection + //m_pConnData->SetSourceWinName(m_xTableControl->getSourceWinName()); + //m_pConnData->SetDestWinName(m_xTableControl->getDestWinName()); + + // try to create the relation + try + { + ORelationTableConnectionData* pOrigConnData = static_cast<ORelationTableConnectionData*>(m_pOrigConnData.get()); + if ( *pConnData == *pOrigConnData || pConnData->Update()) + { + m_pOrigConnData->CopyFrom( *m_pConnData ); + m_xDialog->response(RET_OK); + return; + } + } + catch( const SQLException& ) + { + ::dbtools::showError(SQLExceptionInfo(::cppu::getCaughtException()), + m_xDialog->GetXWindow(), + m_pParent->getDesignView()->getController().getORB()); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + m_bTriedOneUpdate = true; + // this means that the original connection may be lost (if m_pConnData was not a newly created but an + // existent conn to be modified), which we reflect by returning RET_NO (see ::Execute) + + // try again + Init(m_pConnData); + m_xTableControl->Init( m_pConnData ); + m_xTableControl->lateInit(); +} + +short ORelationDialog::run() +{ + short nResult = GenericDialogController::run(); + if ((nResult != RET_OK) && m_bTriedOneUpdate) + return RET_NO; + + return nResult; +} + +void ORelationDialog::setValid(bool _bValid) +{ + m_xPB_OK->set_sensitive(_bValid); +} + +void ORelationDialog::notifyConnectionChange() +{ + Init(m_pConnData); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/TablesSingleDlg.cxx b/dbaccess/source/ui/dlg/TablesSingleDlg.cxx new file mode 100644 index 000000000..bcf039c5e --- /dev/null +++ b/dbaccess/source/ui/dlg/TablesSingleDlg.cxx @@ -0,0 +1,105 @@ +/* -*- 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 <TablesSingleDlg.hxx> +#include "DbAdminImpl.hxx" +#include "tablespage.hxx" + +namespace dbaui +{ +using namespace com::sun::star::uno; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; + + // OTableSubscriptionDialog +OTableSubscriptionDialog::OTableSubscriptionDialog(weld::Window* pParent + ,const SfxItemSet* _pItems + ,const Reference< XComponentContext >& _rxORB + ,const css::uno::Any& _aDataSourceName) + : SfxSingleTabDialogController(pParent, _pItems, + "dbaccess/ui/tablesfilterdialog.ui", "TablesFilterDialog") + , m_pImpl(new ODbDataSourceAdministrationHelper(_rxORB, m_xDialog.get(), pParent, this)) + , m_bStopExecution(false) +{ + m_pImpl->setDataSourceOrName(_aDataSourceName); + Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource(); + m_pOutSet.reset(new SfxItemSet( *_pItems )); + + m_pImpl->translateProperties(xDatasource, *m_pOutSet); + SetInputSet(m_pOutSet.get()); + + auto xTabPage = std::make_unique<OTableSubscriptionPage>(get_content_area(), this, *m_pOutSet); + xTabPage->SetServiceFactory(_rxORB); + SetTabPage(std::move(xTabPage)); +} + +OTableSubscriptionDialog::~OTableSubscriptionDialog() +{ +} + +short OTableSubscriptionDialog::run() +{ + short nRet = RET_CANCEL; + if ( !m_bStopExecution ) + { + nRet = SfxSingleTabDialogController::run(); + if ( nRet == RET_OK ) + { + m_pOutSet->Put(*GetOutputItemSet()); + m_pImpl->saveChanges(*m_pOutSet); + } + } + return nRet; +} + +bool OTableSubscriptionDialog::getCurrentSettings(Sequence< PropertyValue >& _rDriverParams) +{ + return m_pImpl->getCurrentSettings(_rDriverParams); +} + +void OTableSubscriptionDialog::successfullyConnected() +{ + m_pImpl->successfullyConnected(); +} + +void OTableSubscriptionDialog::clearPassword() +{ + m_pImpl->clearPassword(); +} + +Reference< XPropertySet > const & OTableSubscriptionDialog::getCurrentDataSource() +{ + return m_pImpl->getCurrentDataSource(); +} + +const SfxItemSet* OTableSubscriptionDialog::getOutputSet() const +{ + return m_pOutSet.get(); +} + +SfxItemSet* OTableSubscriptionDialog::getWriteOutputSet() +{ + return m_pOutSet.get(); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/TextConnectionHelper.cxx b/dbaccess/source/ui/dlg/TextConnectionHelper.cxx new file mode 100644 index 000000000..15fa887f7 --- /dev/null +++ b/dbaccess/source/ui/dlg/TextConnectionHelper.cxx @@ -0,0 +1,392 @@ +/* -*- 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 <core_resource.hxx> +#include "TextConnectionHelper.hxx" +#include <strings.hrc> +#include <strings.hxx> +#include <svl/itemset.hxx> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> +#include <dsitems.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <vcl/mnemonic.hxx> +#include <o3tl/string_view.hxx> + +namespace +{ + +OUString lcl_getListEntry(const OUString& rStr, sal_Int32& rIdx) +{ + const OUString sTkn {rStr.getToken( 0, '\t', rIdx )}; + if (rIdx>=0) + { + rIdx = rStr.indexOf('\t', rIdx); + if (rIdx>=0 && ++rIdx>=rStr.getLength()) + rIdx = -1; + } + return sTkn; +} + +} + +namespace dbaui +{ + + OTextConnectionHelper::OTextConnectionHelper(weld::Widget* pParent, const short _nAvailableSections) + : m_aFieldSeparatorList (DBA_RES(STR_AUTOFIELDSEPARATORLIST)) + , m_aTextSeparatorList (STR_AUTOTEXTSEPARATORLIST) + , m_aTextNone (DBA_RES(STR_AUTOTEXT_FIELD_SEP_NONE)) + , m_nAvailableSections( _nAvailableSections ) + , m_xBuilder(Application::CreateBuilder(pParent, "dbaccess/ui/textpage.ui")) + , m_xContainer(m_xBuilder->weld_widget("TextPage")) + , m_xExtensionHeader(m_xBuilder->weld_widget("extensionframe")) + , m_xAccessTextFiles(m_xBuilder->weld_radio_button("textfile")) + , m_xAccessCSVFiles(m_xBuilder->weld_radio_button("csvfile")) + , m_xAccessOtherFiles(m_xBuilder->weld_radio_button("custom")) + , m_xOwnExtension(m_xBuilder->weld_entry("extension")) + , m_xExtensionExample(m_xBuilder->weld_label("example")) + , m_xFormatHeader(m_xBuilder->weld_widget("formatframe")) + , m_xFieldSeparatorLabel(m_xBuilder->weld_label("fieldlabel")) + , m_xFieldSeparator(m_xBuilder->weld_combo_box("fieldseparator")) + , m_xTextSeparatorLabel(m_xBuilder->weld_label("textlabel")) + , m_xTextSeparator(m_xBuilder->weld_combo_box("textseparator")) + , m_xDecimalSeparatorLabel(m_xBuilder->weld_label("decimallabel")) + , m_xDecimalSeparator(m_xBuilder->weld_combo_box("decimalseparator")) + , m_xThousandsSeparatorLabel(m_xBuilder->weld_label("thousandslabel")) + , m_xThousandsSeparator(m_xBuilder->weld_combo_box("thousandsseparator")) + , m_xRowHeader(m_xBuilder->weld_check_button("containsheaders")) + , m_xCharSetHeader(m_xBuilder->weld_widget("charsetframe")) + , m_xCharSetLabel(m_xBuilder->weld_label("charsetlabel")) + , m_xCharSet(new CharSetListBox(m_xBuilder->weld_combo_box("charset"))) + { + for(sal_Int32 nIdx {0}; nIdx>=0;) + m_xFieldSeparator->append_text( lcl_getListEntry(m_aFieldSeparatorList, nIdx) ); + + for(sal_Int32 nIdx {0}; nIdx>=0;) + m_xTextSeparator->append_text( lcl_getListEntry(m_aTextSeparatorList, nIdx) ); + m_xTextSeparator->append_text(m_aTextNone); + + m_xOwnExtension->connect_changed(LINK(this, OTextConnectionHelper, OnEditModified)); + m_xAccessTextFiles->connect_toggled(LINK(this, OTextConnectionHelper, OnSetExtensionHdl)); + m_xAccessCSVFiles->connect_toggled(LINK(this, OTextConnectionHelper, OnSetExtensionHdl)); + m_xAccessOtherFiles->connect_toggled(LINK(this, OTextConnectionHelper, OnSetExtensionHdl)); + m_xAccessCSVFiles->set_active(true); + + struct SectionDescriptor + { + short nFlag; + weld::Widget* pFrame; + } aSections[] = { + { TC_EXTENSION, m_xExtensionHeader.get() }, + { TC_SEPARATORS, m_xFormatHeader.get() }, + { TC_HEADER, m_xRowHeader.get() }, + { TC_CHARSET, m_xCharSetHeader.get() }, + { 0, nullptr } + }; + + for ( size_t section=0; section < SAL_N_ELEMENTS( aSections ) - 1; ++section ) + { + if ( ( m_nAvailableSections & aSections[section].nFlag ) != 0 ) + { + // the section is visible, no need to do anything here + continue; + } + + // hide all elements from this section + aSections[section].pFrame->hide(); + } + + m_xContainer->show(); + } + + IMPL_LINK_NOARG(OTextConnectionHelper, OnEditModified, weld::Entry&, void) + { + m_aGetExtensionHandler.Call(this); + } + + IMPL_LINK_NOARG(OTextConnectionHelper, OnSetExtensionHdl, weld::Toggleable&, void) + { + bool bDoEnable = m_xAccessOtherFiles->get_active(); + m_xOwnExtension->set_sensitive(bDoEnable); + m_xExtensionExample->set_sensitive(bDoEnable); + m_aGetExtensionHandler.Call(this); + } + + void OTextConnectionHelper::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xFieldSeparator.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xTextSeparator.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xDecimalSeparator.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xThousandsSeparator.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xRowHeader.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xCharSet->get_widget())); + } + + void OTextConnectionHelper::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFieldSeparatorLabel.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xTextSeparatorLabel.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xDecimalSeparatorLabel.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xThousandsSeparatorLabel.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Widget>(m_xCharSetHeader.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xCharSetLabel.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::ComboBox>(m_xCharSet->get_widget())); + } + + void OTextConnectionHelper::implInitControls(const SfxItemSet& _rSet, bool _bValid) + { + if ( !_bValid ) + return; + + const SfxStringItem* pDelItem = _rSet.GetItem<SfxStringItem>(DSID_FIELDDELIMITER); + const SfxStringItem* pStrItem = _rSet.GetItem<SfxStringItem>(DSID_TEXTDELIMITER); + const SfxStringItem* pDecdelItem = _rSet.GetItem<SfxStringItem>(DSID_DECIMALDELIMITER); + const SfxStringItem* pThodelItem = _rSet.GetItem<SfxStringItem>(DSID_THOUSANDSDELIMITER); + const SfxStringItem* pExtensionItem = _rSet.GetItem<SfxStringItem>(DSID_TEXTFILEEXTENSION); + const SfxStringItem* pCharsetItem = _rSet.GetItem<SfxStringItem>(DSID_CHARSET); + + if ( ( m_nAvailableSections & TC_EXTENSION ) != 0 ) + { + m_aOldExtension = pExtensionItem->GetValue(); + SetExtension( m_aOldExtension ); + } + + if ( ( m_nAvailableSections & TC_HEADER ) != 0 ) + { + const SfxBoolItem* pHdrItem = _rSet.GetItem<SfxBoolItem>(DSID_TEXTFILEHEADER); + m_xRowHeader->set_active(pHdrItem->GetValue()); + } + + if ( ( m_nAvailableSections & TC_SEPARATORS ) != 0 ) + { + SetSeparator(*m_xFieldSeparator, m_aFieldSeparatorList, pDelItem->GetValue()); + SetSeparator(*m_xTextSeparator, m_aTextSeparatorList, pStrItem->GetValue()); + m_xDecimalSeparator->set_entry_text( pDecdelItem->GetValue() ); + m_xThousandsSeparator->set_entry_text( pThodelItem->GetValue() ); + } + + if ( ( m_nAvailableSections & TC_CHARSET ) != 0 ) + { + m_xCharSet->SelectEntryByIanaName( pCharsetItem->GetValue() ); + } + } + + bool OTextConnectionHelper::prepareLeave() + { + OUString sExtension = GetExtension(); + OUString aErrorText; + weld::Widget* pErrorWin = nullptr; + OUString aDelText(m_xFieldSeparator->get_active_text()); + if(aDelText.isEmpty()) + { // No FieldSeparator + aErrorText = DBA_RES(STR_AUTODELIMITER_MISSING); + aErrorText = aErrorText.replaceFirst("#1",m_xFieldSeparatorLabel->get_label()); + pErrorWin = m_xFieldSeparator.get(); + } + else if (m_xDecimalSeparator->get_active_text().isEmpty()) + { // No DecimalSeparator + aErrorText = DBA_RES(STR_AUTODELIMITER_MISSING); + aErrorText = aErrorText.replaceFirst("#1",m_xDecimalSeparatorLabel->get_label()); + pErrorWin = m_xDecimalSeparator.get(); + } + else if (m_xTextSeparator->get_active_text() == m_xFieldSeparator->get_active_text()) + { // Field and TextSeparator must not be the same + aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER); + aErrorText = aErrorText.replaceFirst("#1",m_xTextSeparatorLabel->get_label()); + aErrorText = aErrorText.replaceFirst("#2",m_xFieldSeparatorLabel->get_label()); + pErrorWin = m_xTextSeparator.get(); + } + else if (m_xDecimalSeparator->get_active_text() == m_xThousandsSeparator->get_active_text()) + { // Thousands and DecimalSeparator must not be the same + aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER); + aErrorText = aErrorText.replaceFirst("#1",m_xDecimalSeparatorLabel->get_label()); + aErrorText = aErrorText.replaceFirst("#2",m_xThousandsSeparatorLabel->get_label()); + pErrorWin = m_xDecimalSeparator.get(); + } + else if (m_xFieldSeparator->get_active_text() == m_xThousandsSeparator->get_active_text()) + { // Thousands and FieldSeparator must not be the same + aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER); + aErrorText = aErrorText.replaceFirst("#1",m_xFieldSeparatorLabel->get_label()); + aErrorText = aErrorText.replaceFirst("#2",m_xThousandsSeparatorLabel->get_label()); + pErrorWin = m_xFieldSeparator.get(); + } + else if (m_xFieldSeparator->get_active_text() == m_xDecimalSeparator->get_active_text()) + { // Tenner and FieldSeparator must not be the same + aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER); + aErrorText = aErrorText.replaceFirst("#1",m_xFieldSeparatorLabel->get_label()); + aErrorText = aErrorText.replaceFirst("#2",m_xDecimalSeparatorLabel->get_label()); + pErrorWin = m_xFieldSeparator.get(); + } + else if (m_xTextSeparator->get_active_text() == m_xThousandsSeparator->get_active_text()) + { // Thousands and TextSeparator must not be the same + aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER); + aErrorText = aErrorText.replaceFirst("#1",m_xTextSeparatorLabel->get_label()); + aErrorText = aErrorText.replaceFirst("#2",m_xThousandsSeparatorLabel->get_label()); + pErrorWin = m_xTextSeparator.get(); + } + else if (m_xTextSeparator->get_active_text() == m_xDecimalSeparator->get_active_text()) + { // Tenner and TextSeparator must not be the same + aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER); + aErrorText = aErrorText.replaceFirst("#1",m_xTextSeparatorLabel->get_label()); + aErrorText = aErrorText.replaceFirst("#2",m_xDecimalSeparatorLabel->get_label()); + pErrorWin = m_xTextSeparator.get(); + } + else if ((sExtension.indexOf('*') != -1) || (sExtension.indexOf('?') != -1)) + { + aErrorText = DBA_RES(STR_AUTONO_WILDCARDS); + aErrorText = aErrorText.replaceFirst("#1",sExtension); + pErrorWin = m_xOwnExtension.get(); + } + else + return true; + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xContainer.get(), + VclMessageType::Warning, VclButtonsType::Ok, + MnemonicGenerator::EraseAllMnemonicChars(aErrorText))); + xBox->run(); + pErrorWin->grab_focus(); + return false; + } + + bool OTextConnectionHelper::FillItemSet( SfxItemSet& rSet, const bool _bChangedSomething ) + { + bool bChangedSomething = _bChangedSomething; + + if ( ( m_nAvailableSections & TC_EXTENSION ) != 0 ) + { + OUString sExtension = GetExtension(); + if( m_aOldExtension != sExtension ) + { + rSet.Put( SfxStringItem( DSID_TEXTFILEEXTENSION, sExtension ) ); + bChangedSomething = true; + } + } + + if ( ( m_nAvailableSections & TC_HEADER ) != 0 ) + { + if (m_xRowHeader->get_state_changed_from_saved()) + { + rSet.Put(SfxBoolItem(DSID_TEXTFILEHEADER, m_xRowHeader->get_active())); + bChangedSomething = true; + } + } + + if ( ( m_nAvailableSections & TC_SEPARATORS ) != 0 ) + { + if (m_xFieldSeparator->get_value_changed_from_saved()) + { + rSet.Put( SfxStringItem(DSID_FIELDDELIMITER, GetSeparator( *m_xFieldSeparator, m_aFieldSeparatorList) ) ); + bChangedSomething = true; + } + if (m_xTextSeparator->get_value_changed_from_saved()) + { + rSet.Put( SfxStringItem(DSID_TEXTDELIMITER, GetSeparator( *m_xTextSeparator, m_aTextSeparatorList) ) ); + bChangedSomething = true; + } + + if (m_xDecimalSeparator->get_value_changed_from_saved()) + { + rSet.Put( SfxStringItem(DSID_DECIMALDELIMITER, m_xDecimalSeparator->get_active_text().copy(0, 1) ) ); + bChangedSomething = true; + } + if (m_xThousandsSeparator->get_value_changed_from_saved()) + { + rSet.Put( SfxStringItem(DSID_THOUSANDSDELIMITER, m_xThousandsSeparator->get_active_text().copy(0,1) ) ); + bChangedSomething = true; + } + } + + if ( ( m_nAvailableSections & TC_CHARSET ) != 0 ) + { + if ( m_xCharSet->StoreSelectedCharSet( rSet, DSID_CHARSET ) ) + bChangedSomething = true; + } + + return bChangedSomething; + } + + void OTextConnectionHelper::SetExtension(const OUString& _rVal) + { + if (_rVal == "txt") + m_xAccessTextFiles->set_active(true); + else if (_rVal == "csv") + m_xAccessCSVFiles->set_active(true); + else + { + m_xAccessOtherFiles->set_active(true); + m_xExtensionExample->set_label(_rVal); + } + } + + OUString OTextConnectionHelper::GetExtension() const + { + OUString sExtension; + if (m_xAccessTextFiles->get_active()) + sExtension = "txt"; + else if (m_xAccessCSVFiles->get_active()) + sExtension = "csv"; + else + { + sExtension = m_xOwnExtension->get_text(); + if ( sExtension.startsWith("*.") ) + sExtension = sExtension.copy(2); + } + return sExtension; + } + + OUString OTextConnectionHelper::GetSeparator(const weld::ComboBox& rBox, std::u16string_view rList) + { + sal_Unicode const nTok = '\t'; + int nPos(rBox.find_text(rBox.get_active_text())); + + if (nPos == -1) + return rBox.get_active_text(); + + if ( m_xTextSeparator.get() != &rBox || nPos != (rBox.get_count()-1) ) + return OUString( + static_cast< sal_Unicode >( o3tl::toInt32(o3tl::getToken(rList, (nPos*2)+1, nTok )) )); + // somewhat strange ... translates for instance an "32" into " " + return OUString(); + } + + void OTextConnectionHelper::SetSeparator( weld::ComboBox& rBox, std::u16string_view rList, const OUString& rVal ) + { + if (rVal.getLength()==1) + { + const sal_Unicode nVal {rVal[0]}; + for(sal_Int32 nIdx {0}; nIdx>=0;) + { + sal_Int32 nPrevIdx {nIdx}; + if (static_cast<sal_Unicode>(o3tl::toInt32(o3tl::getToken(rList, 1, '\t', nIdx))) == nVal) + { + rBox.set_entry_text(OUString(o3tl::getToken(rList,0, '\t', nPrevIdx))); + return; + } + } + rBox.set_entry_text( rVal ); + } + else if ( m_xTextSeparator.get() == &rBox && rVal.isEmpty() ) + rBox.set_entry_text(m_aTextNone); + else + rBox.set_entry_text(rVal.copy(0, 1)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/TextConnectionHelper.hxx b/dbaccess/source/ui/dlg/TextConnectionHelper.hxx new file mode 100644 index 000000000..6755a4223 --- /dev/null +++ b/dbaccess/source/ui/dlg/TextConnectionHelper.hxx @@ -0,0 +1,89 @@ +/* -*- 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 "adminpages.hxx" +#include <charsetlistbox.hxx> +#include <rtl/ustring.hxx> + +namespace dbaui + +{ + + #define TC_EXTENSION (short(0x01)) // a section specifying the extension of the files to connect to + #define TC_SEPARATORS (short(0x02)) // a section specifying the various separators + #define TC_HEADER (short(0x04)) // a section containing the "Text contains header" check box only + #define TC_CHARSET (short(0x08)) // not yet implemented + + class OTextConnectionHelper final + { + public: + OTextConnectionHelper(weld::Widget* pParent , const short _nAvailableSections); + + private: + OUString m_aFieldSeparatorList; + OUString m_aTextSeparatorList; + OUString m_aTextNone; + OUString m_aOldExtension; + Link<OTextConnectionHelper*, void> m_aGetExtensionHandler; /// to be called if a new type is selected + + short m_nAvailableSections; + + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Widget> m_xContainer; + std::unique_ptr<weld::Widget> m_xExtensionHeader; + std::unique_ptr<weld::RadioButton> m_xAccessTextFiles; + std::unique_ptr<weld::RadioButton> m_xAccessCSVFiles; + std::unique_ptr<weld::RadioButton> m_xAccessOtherFiles; + std::unique_ptr<weld::Entry> m_xOwnExtension; + std::unique_ptr<weld::Label> m_xExtensionExample; + std::unique_ptr<weld::Widget> m_xFormatHeader; + std::unique_ptr<weld::Label> m_xFieldSeparatorLabel; + std::unique_ptr<weld::ComboBox> m_xFieldSeparator; + std::unique_ptr<weld::Label> m_xTextSeparatorLabel; + std::unique_ptr<weld::ComboBox> m_xTextSeparator; + std::unique_ptr<weld::Label> m_xDecimalSeparatorLabel; + std::unique_ptr<weld::ComboBox> m_xDecimalSeparator; + std::unique_ptr<weld::Label> m_xThousandsSeparatorLabel; + std::unique_ptr<weld::ComboBox> m_xThousandsSeparator; + std::unique_ptr<weld::CheckButton> m_xRowHeader; + std::unique_ptr<weld::Widget> m_xCharSetHeader; + std::unique_ptr<weld::Label> m_xCharSetLabel; + std::unique_ptr<CharSetListBox> m_xCharSet; + + DECL_LINK(OnSetExtensionHdl, weld::Toggleable&, void); + DECL_LINK(OnEditModified, weld::Entry&, void); + + OUString GetSeparator(const weld::ComboBox& rBox, std::u16string_view rList); + void SetSeparator(weld::ComboBox& rBox, std::u16string_view rList, const OUString& rVal); + void SetExtension(const OUString& _rVal); + + public: + void implInitControls(const SfxItemSet& _rSet, bool _bValid); + void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList); + void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList); + void SetClickHandler(const Link<OTextConnectionHelper*, void>& _rHandler) { m_aGetExtensionHandler = _rHandler; } + OUString GetExtension() const; + bool FillItemSet( SfxItemSet& rSet, const bool bChangedSomething ); + bool prepareLeave(); + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/UserAdmin.cxx b/dbaccess/source/ui/dlg/UserAdmin.cxx new file mode 100644 index 000000000..b601c4939 --- /dev/null +++ b/dbaccess/source/ui/dlg/UserAdmin.cxx @@ -0,0 +1,316 @@ +/* -*- 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 "UserAdmin.hxx" +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> +#include <com/sun/star/sdbcx/XUsersSupplier.hpp> +#include <com/sun/star/sdbcx/XDrop.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbcx/XUser.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <IItemSetHelper.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <core_resource.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <sfx2/passwd.hxx> + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::task; +using namespace dbaui; +using namespace comphelper; + +namespace { + +class OPasswordDialog : public weld::GenericDialogController +{ + std::unique_ptr<weld::Frame> m_xUser; + std::unique_ptr<weld::Entry> m_xEDOldPassword; + std::unique_ptr<weld::Entry> m_xEDPassword; + std::unique_ptr<weld::Entry> m_xEDPasswordRepeat; + std::unique_ptr<weld::Button> m_xOKBtn; + + DECL_LINK(OKHdl_Impl, weld::Button&, void); + DECL_LINK(ModifiedHdl, weld::Entry&, void); + +public: + OPasswordDialog(weld::Window* pParent, std::u16string_view rUserName); + + OUString GetOldPassword() const { return m_xEDOldPassword->get_text(); } + OUString GetNewPassword() const { return m_xEDPassword->get_text(); } +}; + +} + +OPasswordDialog::OPasswordDialog(weld::Window* _pParent, std::u16string_view rUserName) + : GenericDialogController(_pParent, "dbaccess/ui/password.ui", "PasswordDialog") + , m_xUser(m_xBuilder->weld_frame("userframe")) + , m_xEDOldPassword(m_xBuilder->weld_entry("oldpassword")) + , m_xEDPassword(m_xBuilder->weld_entry("newpassword")) + , m_xEDPasswordRepeat(m_xBuilder->weld_entry("confirmpassword")) + , m_xOKBtn(m_xBuilder->weld_button("ok")) +{ + OUString sUser = m_xUser->get_label(); + sUser = sUser.replaceFirst("$name$: $", rUserName); + m_xUser->set_label(sUser); + m_xOKBtn->set_sensitive(false); + + m_xOKBtn->connect_clicked( LINK( this, OPasswordDialog, OKHdl_Impl ) ); + m_xEDOldPassword->connect_changed( LINK( this, OPasswordDialog, ModifiedHdl ) ); +} + +IMPL_LINK_NOARG(OPasswordDialog, OKHdl_Impl, weld::Button&, void) +{ + if (m_xEDPassword->get_text() == m_xEDPasswordRepeat->get_text()) + m_xDialog->response(RET_OK); + else + { + OUString aErrorMsg( DBA_RES( STR_ERROR_PASSWORDS_NOT_IDENTICAL)); + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, + aErrorMsg)); + xErrorBox->run(); + m_xEDPassword->set_text(OUString()); + m_xEDPasswordRepeat->set_text(OUString()); + m_xEDPassword->grab_focus(); + } +} + +IMPL_LINK(OPasswordDialog, ModifiedHdl, weld::Entry&, rEdit, void) +{ + m_xOKBtn->set_sensitive(!rEdit.get_text().isEmpty()); +} + +// OUserAdmin +OUserAdmin::OUserAdmin(weld::Container* pPage, weld::DialogController* pController,const SfxItemSet& _rAttrSet) + : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/useradminpage.ui", "UserAdminPage", _rAttrSet) + , m_xUSER(m_xBuilder->weld_combo_box("user")) + , m_xNEWUSER(m_xBuilder->weld_button("add")) + , m_xCHANGEPWD(m_xBuilder->weld_button("changepass")) + , m_xDELETEUSER(m_xBuilder->weld_button("delete")) + , m_xTable(m_xBuilder->weld_container("table")) + , m_xTableCtrlParent(m_xTable->CreateChildFrame()) + , m_xTableCtrl(VclPtr<OTableGrantControl>::Create(m_xTableCtrlParent)) +{ + m_xTableCtrl->Show(); + + m_xUSER->connect_changed(LINK(this, OUserAdmin, ListDblClickHdl)); + m_xNEWUSER->connect_clicked(LINK(this, OUserAdmin, UserHdl)); + m_xCHANGEPWD->connect_clicked(LINK(this, OUserAdmin, UserHdl)); + m_xDELETEUSER->connect_clicked(LINK(this, OUserAdmin, UserHdl)); +} + +OUserAdmin::~OUserAdmin() +{ + m_xConnection = nullptr; + m_xTableCtrl.disposeAndClear(); + m_xTableCtrlParent->dispose(); + m_xTableCtrlParent.clear(); +} + +void OUserAdmin::FillUserNames() +{ + if(m_xConnection.is()) + { + m_xUSER->clear(); + + Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData(); + + if ( xMetaData.is() ) + { + m_UserName = xMetaData->getUserName(); + + // first we need the users + if ( m_xUsers.is() ) + { + m_xUSER->clear(); + + m_aUserNames = m_xUsers->getElementNames(); + const OUString* pBegin = m_aUserNames.getConstArray(); + const OUString* pEnd = pBegin + m_aUserNames.getLength(); + for(;pBegin != pEnd;++pBegin) + m_xUSER->append_text(*pBegin); + + m_xUSER->set_active(0); + if(m_xUsers->hasByName(m_UserName)) + { + Reference<XAuthorizable> xAuth; + m_xUsers->getByName(m_UserName) >>= xAuth; + m_xTableCtrl->setGrantUser(xAuth); + } + + m_xTableCtrl->setUserName(GetUser()); + m_xTableCtrl->Init(); + } + } + } + + Reference<XAppend> xAppend(m_xUsers,UNO_QUERY); + m_xNEWUSER->set_sensitive(xAppend.is()); + Reference<XDrop> xDrop(m_xUsers,UNO_QUERY); + m_xDELETEUSER->set_sensitive(xDrop.is()); + + m_xCHANGEPWD->set_sensitive(m_xUsers.is()); + m_xTableCtrl->Enable(m_xUsers.is()); +} + +std::unique_ptr<SfxTabPage> OUserAdmin::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ) +{ + return std::make_unique<OUserAdmin>( pPage, pController, *_rAttrSet ); +} + +IMPL_LINK(OUserAdmin, UserHdl, weld::Button&, rButton, void) +{ + try + { + if (&rButton == m_xNEWUSER.get()) + { + SfxPasswordDialog aPwdDlg(GetFrameWeld()); + aPwdDlg.ShowExtras(SfxShowExtras::ALL); + if (aPwdDlg.run()) + { + Reference<XDataDescriptorFactory> xUserFactory(m_xUsers,UNO_QUERY); + Reference<XPropertySet> xNewUser = xUserFactory->createDataDescriptor(); + if(xNewUser.is()) + { + xNewUser->setPropertyValue(PROPERTY_NAME,Any(aPwdDlg.GetUser())); + xNewUser->setPropertyValue(PROPERTY_PASSWORD,Any(aPwdDlg.GetPassword())); + Reference<XAppend> xAppend(m_xUsers,UNO_QUERY); + if(xAppend.is()) + xAppend->appendByDescriptor(xNewUser); + } + } + } + else if (&rButton == m_xCHANGEPWD.get()) + { + OUString sName = GetUser(); + + if(m_xUsers->hasByName(sName)) + { + Reference<XUser> xUser; + m_xUsers->getByName(sName) >>= xUser; + if(xUser.is()) + { + OPasswordDialog aDlg(GetFrameWeld(), sName); + if (aDlg.run() == RET_OK) + { + OUString sNewPassword,sOldPassword; + sNewPassword = aDlg.GetNewPassword(); + sOldPassword = aDlg.GetOldPassword(); + + if(!sNewPassword.isEmpty()) + xUser->changePassword(sOldPassword,sNewPassword); + } + } + } + } + else + {// delete user + if(m_xUsers.is() && m_xUsers->hasByName(GetUser())) + { + Reference<XDrop> xDrop(m_xUsers,UNO_QUERY); + if(xDrop.is()) + { + std::unique_ptr<weld::MessageDialog> xQry(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + DBA_RES(STR_QUERY_USERADMIN_DELETE_USER))); + if (xQry->run() == RET_YES) + xDrop->dropByName(GetUser()); + } + } + } + FillUserNames(); + } + catch(const SQLException& e) + { + ::dbtools::showError(::dbtools::SQLExceptionInfo(e), GetDialogController()->getDialog()->GetXWindow(), m_xORB); + } + catch(Exception& ) + { + } +} + +IMPL_LINK_NOARG(OUserAdmin, ListDblClickHdl, weld::ComboBox&, void) +{ + m_xTableCtrl->setUserName(GetUser()); + m_xTableCtrl->UpdateTables(); + m_xTableCtrl->DeactivateCell(); + m_xTableCtrl->ActivateCell(m_xTableCtrl->GetCurRow(),m_xTableCtrl->GetCurColumnId()); +} + +OUString OUserAdmin::GetUser() const +{ + return m_xUSER->get_active_text(); +} + +void OUserAdmin::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& /*_rControlList*/) +{ +} + +void OUserAdmin::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& /*_rControlList*/) +{ +} + +void OUserAdmin::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) +{ + m_xTableCtrl->setComponentContext(m_xORB); + try + { + if ( !m_xConnection.is() && m_pAdminDialog ) + { + m_xConnection = m_pAdminDialog->createConnection().first; + Reference< XTablesSupplier > xTablesSup(m_xConnection,UNO_QUERY); + Reference<XUsersSupplier> xUsersSup(xTablesSup,UNO_QUERY); + if ( !xUsersSup.is() ) + { + Reference< XDataDefinitionSupplier > xDriver(m_pAdminDialog->getDriver(),UNO_QUERY); + if ( xDriver.is() ) + { + xUsersSup.set(xDriver->getDataDefinitionByConnection(m_xConnection),UNO_QUERY); + xTablesSup.set(xUsersSup,UNO_QUERY); + } + } + if ( xUsersSup.is() ) + { + m_xTableCtrl->setTablesSupplier(xTablesSup); + m_xUsers = xUsersSup->getUsers(); + } + } + FillUserNames(); + } + catch(const SQLException& e) + { + ::dbtools::showError(::dbtools::SQLExceptionInfo(e), GetDialogController()->getDialog()->GetXWindow(), m_xORB); + } + + OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/UserAdmin.hxx b/dbaccess/source/ui/dlg/UserAdmin.hxx new file mode 100644 index 000000000..e9c2a13e7 --- /dev/null +++ b/dbaccess/source/ui/dlg/UserAdmin.hxx @@ -0,0 +1,74 @@ +/* -*- 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 <TableGrantCtrl.hxx> +#include "adminpages.hxx" + +namespace com::sun::star { + namespace sdbc { + class XConnection; + } +} + +namespace dbaui +{ + +class OUserAdmin final : public OGenericAdministrationPage +{ + std::unique_ptr<weld::ComboBox> m_xUSER; + std::unique_ptr<weld::Button> m_xNEWUSER; + std::unique_ptr<weld::Button> m_xCHANGEPWD; + std::unique_ptr<weld::Button> m_xDELETEUSER; + std::unique_ptr<weld::Container> m_xTable; + css::uno::Reference<css::awt::XWindow> m_xTableCtrlParent; + VclPtr<OTableGrantControl> m_xTableCtrl; // show the grant rights of one user + + css::uno::Reference< css::sdbc::XConnection> m_xConnection; + css::uno::Reference< css::container::XNameAccess > m_xUsers; + css::uno::Sequence< OUString> m_aUserNames; + + OUString m_UserName; + + // methods + DECL_LINK(ListDblClickHdl, weld::ComboBox&, void); + DECL_LINK(UserHdl, weld::Button&, void); + + void FillUserNames(); + +public: + OUserAdmin(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs); + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + virtual ~OUserAdmin() override; + + OUString GetUser() const; + + // subclasses must override this, but it isn't pure virtual + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + + // <method>OGenericAdministrationPage::fillControls</method> + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + + // <method>OGenericAdministrationPage::fillWindows</method> + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/UserAdminDlg.cxx b/dbaccess/source/ui/dlg/UserAdminDlg.cxx new file mode 100644 index 000000000..ec44c3399 --- /dev/null +++ b/dbaccess/source/ui/dlg/UserAdminDlg.cxx @@ -0,0 +1,162 @@ +/* -*- 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 <core_resource.hxx> +#include "adminpages.hxx" +#include "DbAdminImpl.hxx" +#include <strings.hrc> +#include "UserAdmin.hxx" +#include <UserAdminDlg.hxx> + +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <connectivity/dbexception.hxx> +#include <connectivity/dbmetadata.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <tools/diagnose_ex.h> + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::sdbcx; + + // OUserAdminDlg + OUserAdminDlg::OUserAdminDlg(weld::Window* pParent, + SfxItemSet* pItems, + const Reference< XComponentContext >& rxORB, + const css::uno::Any& rDataSourceName, + const Reference< XConnection >& xConnection) + : SfxTabDialogController(pParent, "dbaccess/ui/useradmindialog.ui", "UserAdminDialog", pItems) + , m_pParent(pParent) + , m_pItemSet(pItems) + , m_xConnection(xConnection) + , m_bOwnConnection(!xConnection.is()) + { + m_pImpl.reset(new ODbDataSourceAdministrationHelper(rxORB, m_xDialog.get(), pParent, this)); + m_pImpl->setDataSourceOrName(rDataSourceName); + Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource(); + m_pImpl->translateProperties(xDatasource, *pItems); + SetInputSet(pItems); + // propagate this set as our new input set and reset the example set + m_xExampleSet.reset(new SfxItemSet(*GetInputSetImpl())); + + AddTabPage("settings", OUserAdmin::Create, nullptr); + + // remove the reset button - it's meaning is much too ambiguous in this dialog + RemoveResetButton(); + } + + OUserAdminDlg::~OUserAdminDlg() + { + if ( m_bOwnConnection ) + { + try + { + ::comphelper::disposeComponent(m_xConnection); + } + catch(const Exception&) + { + } + } + + SetInputSet(nullptr); + } + + short OUserAdminDlg::run() + { + try + { + ::dbtools::DatabaseMetaData aMetaData( createConnection().first ); + if ( !aMetaData.supportsUserAdministration( getORB() ) ) + { + OUString sError(DBA_RES(STR_USERADMIN_NOT_AVAILABLE)); + throw SQLException(sError, nullptr, "S1000", 0, Any()); + } + } + catch(const SQLException&) + { + ::dbtools::showError(::dbtools::SQLExceptionInfo(::cppu::getCaughtException()), m_pParent->GetXWindow(), getORB()); + return RET_CANCEL; + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + short nRet = SfxTabDialogController::run(); + if ( nRet == RET_OK ) + m_pImpl->saveChanges(*GetOutputItemSet()); + return nRet; + } + void OUserAdminDlg::PageCreated(const OString& rId, SfxTabPage& _rPage) + { + // register ourself as modified listener + static_cast<OGenericAdministrationPage&>(_rPage).SetServiceFactory( m_pImpl->getORB() ); + static_cast<OGenericAdministrationPage&>(_rPage).SetAdminDialog(this,this); + SfxTabDialogController::PageCreated(rId, _rPage); + } + const SfxItemSet* OUserAdminDlg::getOutputSet() const + { + return m_pItemSet; + } + SfxItemSet* OUserAdminDlg::getWriteOutputSet() + { + return m_pItemSet; + } + std::pair< Reference<XConnection>,bool> OUserAdminDlg::createConnection() + { + if ( !m_xConnection.is() ) + { + m_xConnection = m_pImpl->createConnection().first; + m_bOwnConnection = m_xConnection.is(); + } + return std::pair< Reference<XConnection>,bool> (m_xConnection,false); + } + Reference< XComponentContext > OUserAdminDlg::getORB() const + { + return m_pImpl->getORB(); + } + Reference< XDriver > OUserAdminDlg::getDriver() + { + return m_pImpl->getDriver(); + } + OUString OUserAdminDlg::getDatasourceType(const SfxItemSet& _rSet) const + { + return dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(_rSet); + } + void OUserAdminDlg::clearPassword() + { + m_pImpl->clearPassword(); + } + void OUserAdminDlg::setTitle(const OUString& _sTitle) + { + m_xDialog->set_title(_sTitle); + } + void OUserAdminDlg::enableConfirmSettings( bool ) {} + void OUserAdminDlg::saveDatasource() + { + PrepareLeaveCurrentPage(); + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/admincontrols.cxx b/dbaccess/source/ui/dlg/admincontrols.cxx new file mode 100644 index 000000000..de515f9e3 --- /dev/null +++ b/dbaccess/source/ui/dlg/admincontrols.cxx @@ -0,0 +1,201 @@ +/* -*- 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 "admincontrols.hxx" +#include <dsitems.hxx> + +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <vcl/svapp.hxx> + +namespace dbaui +{ + + // MySQLNativeSettings + MySQLNativeSettings::MySQLNativeSettings(weld::Widget* pParent, const Link<weld::Widget*,void>& rControlModificationLink) + : m_xBuilder(Application::CreateBuilder(pParent, "dbaccess/ui/mysqlnativesettings.ui")) + , m_xContainer(m_xBuilder->weld_widget("MysqlNativeSettings")) + , m_xDatabaseNameLabel(m_xBuilder->weld_label("dbnamelabel")) + , m_xDatabaseName(m_xBuilder->weld_entry("dbname")) + , m_xHostPortRadio(m_xBuilder->weld_radio_button("hostport")) + , m_xSocketRadio(m_xBuilder->weld_radio_button("socketlabel")) + , m_xNamedPipeRadio(m_xBuilder->weld_radio_button("namedpipelabel")) + , m_xHostNameLabel(m_xBuilder->weld_label("serverlabel")) + , m_xHostName(m_xBuilder->weld_entry("server")) + , m_xPortLabel(m_xBuilder->weld_label("portlabel")) + , m_xPort(m_xBuilder->weld_spin_button("port")) + , m_xDefaultPort(m_xBuilder->weld_label("defaultport")) + , m_xSocket(m_xBuilder->weld_entry("socket")) + , m_xNamedPipe(m_xBuilder->weld_entry("namedpipe")) + , m_aControlModificationLink(rControlModificationLink) + { + m_xDatabaseName->connect_changed( LINK(this, MySQLNativeSettings, EditModifyHdl) ); + m_xHostName->connect_changed( LINK(this, MySQLNativeSettings, EditModifyHdl) ); + m_xPort->connect_value_changed( LINK(this, MySQLNativeSettings, SpinModifyHdl) ); + m_xSocket->connect_changed( LINK(this, MySQLNativeSettings, EditModifyHdl) ); + m_xNamedPipe->connect_changed( LINK(this, MySQLNativeSettings, EditModifyHdl) ); + m_xSocketRadio->connect_toggled( LINK(this, MySQLNativeSettings, RadioToggleHdl) ); + m_xNamedPipeRadio->connect_toggled( LINK(this, MySQLNativeSettings, RadioToggleHdl) ); + m_xHostPortRadio->connect_toggled( LINK(this, MySQLNativeSettings, RadioToggleHdl) ); + + // sockets are available on Unix systems only, named pipes only on Windows +#ifdef UNX + m_xNamedPipeRadio->hide(); + m_xNamedPipe->hide(); +#else + m_xSocketRadio->hide(); + m_xSocket->hide(); +#endif + m_xContainer->show(); + } + + IMPL_LINK(MySQLNativeSettings, RadioToggleHdl, weld::Toggleable&, rRadioButton, void) + { + m_aControlModificationLink.Call(&rRadioButton); + + const bool bHostPortRadio = m_xHostPortRadio->get_active(); + m_xHostNameLabel->set_sensitive(bHostPortRadio); + m_xHostName->set_sensitive(bHostPortRadio); + m_xPortLabel->set_sensitive(bHostPortRadio); + m_xPort->set_sensitive(bHostPortRadio); + m_xDefaultPort->set_sensitive(bHostPortRadio); + + m_xSocket->set_sensitive(m_xSocketRadio->get_active()); + m_xNamedPipe->set_sensitive(m_xNamedPipeRadio->get_active()); + } + + IMPL_LINK(MySQLNativeSettings, EditModifyHdl, weld::Entry&, rEdit, void) + { + m_aControlModificationLink.Call(&rEdit); + } + + IMPL_LINK(MySQLNativeSettings, SpinModifyHdl, weld::SpinButton&, rEdit, void) + { + m_aControlModificationLink.Call(&rEdit); + } + + void MySQLNativeSettings::fillControls( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList ) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xDatabaseName.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xHostName.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xPort.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xSocket.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xNamedPipe.get())); + } + + void MySQLNativeSettings::fillWindows( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList ) + { + _rControlList.emplace_back( new ODisableWidgetWrapper<weld::Label>( m_xDatabaseNameLabel.get() ) ); + _rControlList.emplace_back( new ODisableWidgetWrapper<weld::Label>( m_xHostNameLabel.get() ) ); + _rControlList.emplace_back( new ODisableWidgetWrapper<weld::Label>( m_xPortLabel.get() ) ); + _rControlList.emplace_back( new ODisableWidgetWrapper<weld::Label>( m_xDefaultPort.get() ) ); + _rControlList.emplace_back( new ODisableWidgetWrapper<weld::RadioButton>( m_xSocketRadio.get() ) ); + _rControlList.emplace_back( new ODisableWidgetWrapper<weld::RadioButton>( m_xNamedPipeRadio.get() ) ); + } + + bool MySQLNativeSettings::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = false; + + OGenericAdministrationPage::fillString( *_rSet, m_xHostName.get(), DSID_CONN_HOSTNAME, bChangedSomething ); + OGenericAdministrationPage::fillString( *_rSet, m_xDatabaseName.get(), DSID_DATABASENAME, bChangedSomething ); + OGenericAdministrationPage::fillInt32 ( *_rSet, m_xPort.get(), DSID_MYSQL_PORTNUMBER, bChangedSomething ); +#ifdef UNX + OGenericAdministrationPage::fillString( *_rSet, m_xSocket.get(), DSID_CONN_SOCKET, bChangedSomething ); +#else + OGenericAdministrationPage::fillString( *_rSet, m_xNamedPipe.get(), DSID_NAMED_PIPE, bChangedSomething ); +#endif + + return bChangedSomething; + } + + void MySQLNativeSettings::implInitControls(const SfxItemSet& _rSet ) + { + const SfxBoolItem* pInvalid = _rSet.GetItem<SfxBoolItem>(DSID_INVALID_SELECTION); + bool bValid = !pInvalid || !pInvalid->GetValue(); + if ( !bValid ) + return; + + const SfxStringItem* pDatabaseName = _rSet.GetItem<SfxStringItem>(DSID_DATABASENAME); + const SfxStringItem* pHostName = _rSet.GetItem<SfxStringItem>(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = _rSet.GetItem<SfxInt32Item>(DSID_MYSQL_PORTNUMBER); + const SfxStringItem* pSocket = _rSet.GetItem<SfxStringItem>(DSID_CONN_SOCKET); + const SfxStringItem* pNamedPipe = _rSet.GetItem<SfxStringItem>(DSID_NAMED_PIPE); + + m_xDatabaseName->set_text( pDatabaseName->GetValue() ); + m_xDatabaseName->save_value(); + + m_xHostName->set_text( pHostName->GetValue() ); + m_xHostName->save_value(); + + m_xPort->set_value( pPortNumber->GetValue() ); + m_xPort->save_value(); + + m_xSocket->set_text( pSocket->GetValue() ); + m_xSocket->save_value(); + + m_xNamedPipe->set_text( pNamedPipe->GetValue() ); + m_xNamedPipe->save_value(); + + // if a socket (on Unix) or a pipe name (on Windows) is given, this is preferred over + // the port +#ifdef UNX + weld::RadioButton& rSocketPipeRadio = *m_xSocketRadio; + const SfxStringItem* pSocketPipeItem = pSocket; +#else + weld::RadioButton& rSocketPipeRadio = *m_xNamedPipeRadio; + const SfxStringItem* pSocketPipeItem = pNamedPipe; +#endif + const OUString& rSocketPipe( pSocketPipeItem->GetValue() ); + if (!rSocketPipe.isEmpty()) + rSocketPipeRadio.set_active(true); + else + m_xHostPortRadio->set_active(true); + } + + bool MySQLNativeSettings::canAdvance() const + { + if (m_xDatabaseName->get_text().isEmpty()) + return false; + + if ( m_xHostPortRadio->get_active() + && ( ( m_xHostName->get_text().isEmpty() ) + || ( m_xPort->get_text().isEmpty() ) + ) + ) + return false; + +#ifdef UNX + if ( ( m_xSocketRadio->get_active() ) + && ( m_xSocket->get_text().isEmpty() ) + ) +#else + if ( ( m_xNamedPipeRadio->get_active() ) + && ( m_xNamedPipe->get_text().isEmpty() ) + ) +#endif + return false; + + return true; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/admincontrols.hxx b/dbaccess/source/ui/dlg/admincontrols.hxx new file mode 100644 index 000000000..7bd1e5edf --- /dev/null +++ b/dbaccess/source/ui/dlg/admincontrols.hxx @@ -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 . + */ + +#pragma once + +#include "adminpages.hxx" + +#include <vcl/weld.hxx> + +namespace dbaui +{ + + // MySQLNativeSettings + class MySQLNativeSettings + { + private: + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Widget> m_xContainer; + std::unique_ptr<weld::Label> m_xDatabaseNameLabel; + std::unique_ptr<weld::Entry> m_xDatabaseName; + std::unique_ptr<weld::RadioButton> m_xHostPortRadio; + std::unique_ptr<weld::RadioButton> m_xSocketRadio; + std::unique_ptr<weld::RadioButton> m_xNamedPipeRadio; + std::unique_ptr<weld::Label> m_xHostNameLabel; + std::unique_ptr<weld::Entry> m_xHostName; + std::unique_ptr<weld::Label> m_xPortLabel; + std::unique_ptr<weld::SpinButton> m_xPort; + std::unique_ptr<weld::Label> m_xDefaultPort; + std::unique_ptr<weld::Entry> m_xSocket; + std::unique_ptr<weld::Entry> m_xNamedPipe; + Link<weld::Widget*,void> m_aControlModificationLink; + DECL_LINK(RadioToggleHdl, weld::Toggleable&, void); + DECL_LINK(SpinModifyHdl, weld::SpinButton&, void); + DECL_LINK(EditModifyHdl, weld::Entry&, void); + + public: + MySQLNativeSettings(weld::Widget* pParent, const Link<weld::Widget*,void>& rControlModificationLink); + void fillControls( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList ); + void fillWindows( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList ); + + bool FillItemSet( SfxItemSet* rCoreAttrs ); + void implInitControls( const SfxItemSet& _rSet ); + + bool canAdvance() const; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/adminpages.cxx b/dbaccess/source/ui/dlg/adminpages.cxx new file mode 100644 index 000000000..5f0eedbb0 --- /dev/null +++ b/dbaccess/source/ui/dlg/adminpages.cxx @@ -0,0 +1,278 @@ +/* -*- 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 "adminpages.hxx" +#include <core_resource.hxx> +#include <dbu_dlg.hxx> +#include <IItemSetHelper.hxx> +#include <strings.hrc> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <dsitems.hxx> +#include "dsselect.hxx" +#include "odbcconfig.hxx" +#include "optionalboolitem.hxx" +#include <sqlmessage.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <comphelper/types.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + using namespace ::dbtools; + + ISaveValueWrapper::~ISaveValueWrapper() + { + } + + OGenericAdministrationPage::OGenericAdministrationPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OString& rId, const SfxItemSet& rAttrSet) + : SfxTabPage(pPage, pController, rUIXMLDescription, rId, &rAttrSet) + , m_abEnableRoadmap(false) + , m_pAdminDialog(nullptr) + , m_pItemSetHelper(nullptr) + { + SetExchangeSupport(); + + m_xContainer->set_size_request(m_xContainer->get_approximate_digit_width() * WIZARD_PAGE_X, + m_xContainer->get_text_height() * WIZARD_PAGE_Y); + } + + DeactivateRC OGenericAdministrationPage::DeactivatePage(SfxItemSet* _pSet) + { + if (_pSet) + { + if (!prepareLeave()) + return DeactivateRC::KeepPage; + FillItemSet(_pSet); + } + + return DeactivateRC::LeavePage; + } + + void OGenericAdministrationPage::Reset(const SfxItemSet* _rCoreAttrs) + { + implInitControls(*_rCoreAttrs, false); + } + + void OGenericAdministrationPage::Activate() + { + BuilderPage::Activate(); + OSL_ENSURE(m_pItemSetHelper,"NO ItemSetHelper set!"); + if ( m_pItemSetHelper ) + ActivatePage(*m_pItemSetHelper->getOutputSet()); + } + + void OGenericAdministrationPage::ActivatePage(const SfxItemSet& _rSet) + { + implInitControls(_rSet, true); + } + + void OGenericAdministrationPage::getFlags(const SfxItemSet& _rSet, bool& _rValid, bool& _rReadonly) + { + const SfxBoolItem* pInvalid = _rSet.GetItem<SfxBoolItem>(DSID_INVALID_SELECTION); + _rValid = !pInvalid || !pInvalid->GetValue(); + const SfxBoolItem* pReadonly = _rSet.GetItem<SfxBoolItem>(DSID_READONLY); + _rReadonly = !_rValid || (pReadonly && pReadonly->GetValue()); + } + + IMPL_LINK(OGenericAdministrationPage, OnControlModified, weld::Widget*, pCtrl, void) + { + callModifiedHdl(pCtrl); + } + + IMPL_LINK(OGenericAdministrationPage, OnControlModifiedButtonClick, weld::Toggleable&, rCtrl, void) + { + callModifiedHdl(&rCtrl); + } + + IMPL_LINK(OGenericAdministrationPage, OnControlEntryModifyHdl, weld::Entry&, rCtrl, void) + { + callModifiedHdl(&rCtrl); + } + + IMPL_LINK(OGenericAdministrationPage, OnControlSpinButtonModifyHdl, weld::SpinButton&, rCtrl, void) + { + callModifiedHdl(&rCtrl); + } + + bool OGenericAdministrationPage::getSelectedDataSource(OUString& _sReturn, OUString const & _sCurr) + { + // collect all ODBC data source names + std::set<OUString> aOdbcDatasources; + OOdbcEnumeration aEnumeration; + if (!aEnumeration.isLoaded()) + { + // show an error message + OUString sError(DBA_RES(STR_COULD_NOT_LOAD_ODBC_LIB)); + sError = sError.replaceFirst("#lib#", aEnumeration.getLibraryName()); + std::unique_ptr<weld::MessageDialog> xDialog(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + sError)); + xDialog->run(); + return false; + } + else + { + aEnumeration.getDatasourceNames(aOdbcDatasources); + // execute the select dialog + ODatasourceSelectDialog aSelector(GetFrameWeld(), aOdbcDatasources); + if (!_sCurr.isEmpty()) + aSelector.Select(_sCurr); + if (RET_OK == aSelector.run()) + _sReturn = aSelector.GetSelected(); + } + return true; + } + + void OGenericAdministrationPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + std::vector< std::unique_ptr<ISaveValueWrapper> > aControlList; + if ( _bSaveValue ) + { + fillControls(aControlList); + for( const auto& pValueWrapper : aControlList ) + { + pValueWrapper->SaveValue(); + } + } + + if ( bReadonly ) + { + fillWindows(aControlList); + for( const auto& pValueWrapper : aControlList ) + { + pValueWrapper->Disable(); + } + } + } + + void OGenericAdministrationPage::initializePage() + { + OSL_ENSURE(m_pItemSetHelper,"NO ItemSetHelper set!"); + if ( m_pItemSetHelper ) + Reset(m_pItemSetHelper->getOutputSet()); + } + bool OGenericAdministrationPage::commitPage( ::vcl::WizardTypes::CommitPageReason ) + { + return true; + } + bool OGenericAdministrationPage::canAdvance() const + { + return true; + } + void OGenericAdministrationPage::fillBool( SfxItemSet& _rSet, const weld::CheckButton* pCheckBox, sal_uInt16 _nID, bool bOptionalBool, bool& _bChangedSomething, bool _bRevertValue ) + { + if (!(pCheckBox && pCheckBox->get_state_changed_from_saved())) + return; + + bool bValue = pCheckBox->get_active(); + if ( _bRevertValue ) + bValue = !bValue; + + if (bOptionalBool) + { + OptionalBoolItem aValue( _nID ); + if ( pCheckBox->get_state() != TRISTATE_INDET ) + aValue.SetValue( bValue ); + _rSet.Put( aValue ); + } + else + _rSet.Put( SfxBoolItem( _nID, bValue ) ); + + _bChangedSomething = true; + } + void OGenericAdministrationPage::fillInt32(SfxItemSet& _rSet, const weld::SpinButton* pEdit, sal_uInt16 _nID, bool& _bChangedSomething) + { + if (pEdit && pEdit->get_value_changed_from_saved()) + { + _rSet.Put(SfxInt32Item(_nID, pEdit->get_value())); + _bChangedSomething = true; + } + } + void OGenericAdministrationPage::fillString(SfxItemSet& _rSet, const weld::Entry* pEdit, sal_uInt16 _nID, bool& _bChangedSomething) + { + if (pEdit && pEdit->get_value_changed_from_saved()) + { + _rSet.Put(SfxStringItem(_nID, pEdit->get_text().trim())); + _bChangedSomething = true; + } + } + void OGenericAdministrationPage::fillString(SfxItemSet& _rSet, const dbaui::OConnectionURLEdit* pEdit, sal_uInt16 _nID, bool& _bChangedSomething) + { + if (pEdit && pEdit->get_value_changed_from_saved()) + { + _rSet.Put(SfxStringItem(_nID, pEdit->GetText().trim())); + _bChangedSomething = true; + } + } + + IMPL_LINK_NOARG(OGenericAdministrationPage, OnTestConnectionButtonClickHdl, weld::Button&, void) + { + OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF"); + bool bSuccess = false; + if ( !m_pAdminDialog ) + return; + + m_pAdminDialog->saveDatasource(); + OGenericAdministrationPage::implInitControls(*m_pItemSetHelper->getOutputSet(), true); + bool bShowMessage = true; + try + { + std::pair< Reference<XConnection>,bool> aConnectionPair = m_pAdminDialog->createConnection(); + bShowMessage = aConnectionPair.second; + bSuccess = aConnectionPair.first.is(); + ::comphelper::disposeComponent(aConnectionPair.first); + } + catch(Exception&) + { + } + if ( bShowMessage ) + { + MessageType eImage = MessageType::Info; + OUString aMessage,sTitle; + sTitle = DBA_RES(STR_CONNECTION_TEST); + if ( bSuccess ) + { + aMessage = DBA_RES(STR_CONNECTION_SUCCESS); + } + else + { + eImage = MessageType::Error; + aMessage = DBA_RES(STR_CONNECTION_NO_SUCCESS); + } + OSQLMessageBox aMsg(GetFrameWeld(), sTitle, aMessage, MessBoxStyle::Ok, eImage); + aMsg.run(); + } + if ( !bSuccess ) + m_pAdminDialog->clearPassword(); + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/adminpages.hxx b/dbaccess/source/ui/dlg/adminpages.hxx new file mode 100644 index 000000000..de8265751 --- /dev/null +++ b/dbaccess/source/ui/dlg/adminpages.hxx @@ -0,0 +1,233 @@ +/* -*- 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 <sfx2/tabdlg.hxx> +#include <vcl/wizardmachine.hxx> +#include <curledit.hxx> + +namespace dbaui +{ + /// helper class to wrap the savevalue and disable call + class SAL_NO_VTABLE ISaveValueWrapper + { + public: + virtual ~ISaveValueWrapper() = 0; + virtual void SaveValue() = 0; + virtual void Disable() = 0; + }; + + template < class T > class OSaveValueWidgetWrapper : public ISaveValueWrapper + { + T* m_pSaveValue; + public: + explicit OSaveValueWidgetWrapper(T* _pSaveValue) : m_pSaveValue(_pSaveValue) + { OSL_ENSURE(m_pSaveValue,"Illegal argument!"); } + + virtual void SaveValue() override { m_pSaveValue->save_value(); } + virtual void Disable() override { m_pSaveValue->set_sensitive(false); } + }; + + template <> class OSaveValueWidgetWrapper<weld::Toggleable> : public ISaveValueWrapper + { + weld::Toggleable* m_pSaveValue; + public: + explicit OSaveValueWidgetWrapper(weld::Toggleable* _pSaveValue) : m_pSaveValue(_pSaveValue) + { OSL_ENSURE(m_pSaveValue,"Illegal argument!"); } + + virtual void SaveValue() override { m_pSaveValue->save_state(); } + virtual void Disable() override { m_pSaveValue->set_sensitive(false); } + }; + + template <> class OSaveValueWidgetWrapper<dbaui::OConnectionURLEdit> : public ISaveValueWrapper + { + dbaui::OConnectionURLEdit* m_pSaveValue; + public: + explicit OSaveValueWidgetWrapper(dbaui::OConnectionURLEdit* _pSaveValue) : m_pSaveValue(_pSaveValue) + { OSL_ENSURE(m_pSaveValue,"Illegal argument!"); } + + virtual void SaveValue() override { m_pSaveValue->save_value(); } + virtual void Disable() override { m_pSaveValue->set_sensitive(false); } + }; + + template <class T> class ODisableWidgetWrapper : public ISaveValueWrapper + { + T* m_pSaveValue; + public: + explicit ODisableWidgetWrapper(T* _pSaveValue) : m_pSaveValue(_pSaveValue) + { OSL_ENSURE(m_pSaveValue,"Illegal argument!"); } + + virtual void SaveValue() override {} + virtual void Disable() override { m_pSaveValue->set_sensitive(false); } + }; + + // OGenericAdministrationPage + class IDatabaseSettingsDialog; + class IItemSetHelper; + class OGenericAdministrationPage :public SfxTabPage + ,public ::vcl::IWizardPageController + { + private: + Link<OGenericAdministrationPage const *, void> m_aModifiedHandler; /// to be called if something on the page has been modified + bool m_abEnableRoadmap; + protected: + IDatabaseSettingsDialog* m_pAdminDialog; + IItemSetHelper* m_pItemSetHelper; + + css::uno::Reference< css::uno::XComponentContext > + m_xORB; + public: + OGenericAdministrationPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OString& rId, const SfxItemSet& rAttrSet); + /// set a handler which gets called every time something on the page has been modified + void SetModifiedHandler(const Link<OGenericAdministrationPage const *, void>& _rHandler) { m_aModifiedHandler = _rHandler; } + + /** Sets the ParentDialog + @param _pAdminDialog + the ParentDialog + @param _pItemSetHelper + the itemset helper + */ + void SetAdminDialog(IDatabaseSettingsDialog* _pDialog,IItemSetHelper* _pItemSetHelper) + { + OSL_ENSURE(_pDialog && _pItemSetHelper,"Values are NULL!"); + m_pAdminDialog = _pDialog; + m_pItemSetHelper = _pItemSetHelper; + } + + /** Sets the ServiceFactory + @param _rxORB + The service factory. + */ + void SetServiceFactory(const css::uno::Reference< css::uno::XComponentContext >& rxORB) + { + m_xORB = rxORB; + } + + /** opens a dialog filled with all data sources available for this type and + returns the selected on. + @param _eType + The type for which the data source dialog should be opened. + @param _sReturn + <OUT/> contains the selected name. + @return + <FALSE/> if an error occurred, otherwise <TRUE/> + */ + bool getSelectedDataSource(OUString& _sReturn, OUString const & _sCurr); + + // svt::IWizardPageController + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + + void SetRoadmapStateValue( bool _bDoEnable ) { m_abEnableRoadmap = _bDoEnable; } + bool GetRoadmapStateValue() const { return m_abEnableRoadmap; } + + protected: + /// default implementation: call FillItemSet, call prepareLeave, + virtual DeactivateRC DeactivatePage(SfxItemSet* pSet) override; + /// default implementation: call implInitControls with the given item set and _bSaveValue = sal_False + virtual void Reset(const SfxItemSet* _rCoreAttrs) override; + /// default implementation: call implInitControls with the given item set and _bSaveValue = sal_True + virtual void ActivatePage(const SfxItemSet& _rSet) override; + + // BuilderPage overridables + virtual void Activate() override; + + protected: + virtual void callModifiedHdl(weld::Widget* /*pControl*/ = nullptr) { m_aModifiedHandler.Call(this); } + + /// called from within DeactivatePage. The page is allowed to be deactivated if this method returns sal_True + virtual bool prepareLeave() { return true; } + + /** called from within Reset and ActivatePage, use to initialize the controls with the items from the given set + @param _bSaveValue if set to sal_True, the implementation should call SaveValue on all relevant controls + */ + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue); + + /// analyze the invalid and the readonly flag which may be present in the set + static void getFlags(const SfxItemSet& _rSet, bool& _rValid, bool& _rReadonly); + + /** will be called inside <method>implInitControls</method> to save the value if necessary + @param _rControlList + The list must be filled with the controls. + It is not allowed to clear the list before pushing data into it. + */ + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) = 0; + + /** will be called inside <method>implInitControls</method> to disable if necessary + @param _rControlList + The list must be filled with the controls. + It is not allowed to clear the list before pushing data into it. + */ + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) = 0; + + public: + /** fills the Boolean value into the item set when the value changed. + @param _rSet + The item set where to put the new value into. + @param _pCheckBox + The check box which is checked. + @param _nID + The id in the itemset to set with the new value. + @param _bChangedSomething + <TRUE/> if something changed otherwise <FALSE/> + @param _bRevertValue + set to <TRUE/> if the display value should be reverted before putting it into the set + */ + static void fillBool(SfxItemSet& _rSet, const weld::CheckButton* pCheckBox, sal_uInt16 _nID, bool bOptionalBool, bool& _bChangedSomething, bool _bRevertValue = false); + + /** fills the int value into the item set when the value changed. + @param _rSet + The item set where to put the new value into. + @param _pEdit + The check box which is checked. + @param _nID + The id in the itemset to set with the new value. + @param _bChangedSomething + <TRUE/> if something changed otherwise <FALSE/> + */ + static void fillInt32(SfxItemSet& _rSet,const weld::SpinButton* pEdit,sal_uInt16 _nID, bool& _bChangedSomething); + + /** fills the String value into the item set when the value changed. + @param _rSet + The item set where to put the new value into. + @param _pEdit + The check box which is checked. + @param _nID + The id in the itemset to set with the new value. + @param _bChangedSomething + <TRUE/> if something changed otherwise <FALSE/> + */ + static void fillString(SfxItemSet& _rSet,const weld::Entry* pEdit,sal_uInt16 _nID, bool& _bChangedSomething); + static void fillString(SfxItemSet& _rSet,const dbaui::OConnectionURLEdit* pEdit,sal_uInt16 _nID, bool& _bChangedSomething); + + protected: + /** This link be used for controls where the tabpage does not need to take any special action when the control + is modified. The implementation just calls callModifiedHdl. + */ + DECL_LINK(OnControlModified, weld::Widget*, void); + DECL_LINK(OnControlEntryModifyHdl, weld::Entry&, void); + DECL_LINK(OnControlSpinButtonModifyHdl, weld::SpinButton&, void); + DECL_LINK(OnControlModifiedButtonClick, weld::Toggleable&, void); + DECL_LINK(OnTestConnectionButtonClickHdl, weld::Button&, void); + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/adodatalinks.cxx b/dbaccess/source/ui/dlg/adodatalinks.cxx new file mode 100644 index 000000000..82af63688 --- /dev/null +++ b/dbaccess/source/ui/dlg/adodatalinks.cxx @@ -0,0 +1,141 @@ +/* -*- 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 . + */ + + +#if defined(_WIN32) +// LO/windows.h conflict +#undef WB_LEFT +#undef WB_RIGHT +#include <msdasc.h> + +#include <comphelper/scopeguard.hxx> +#include <o3tl/char16_t2wchar_t.hxx> +#include <systools/win32/comtools.hxx> +#include <systools/win32/oleauto.hxx> + +#include <initguid.h> +#include <adoid.h> +#include <adoint.h> + +#include "adodatalinks.hxx" + +namespace { + +OUString PromptNew(sal_IntPtr hWnd) +{ + try + { + // Initialize COM + sal::systools::CoInitializeGuard aGuard(COINIT_APARTMENTTHREADED); + + // Instantiate DataLinks object. + sal::systools::COMReference<IDataSourceLocator> dlPrompt; + dlPrompt.CoCreateInstance(CLSID_DataLinks, //clsid -- Data Links UI + nullptr, //pUnkOuter + CLSCTX_INPROC_SERVER); //dwClsContext + + sal::systools::ThrowIfFailed(dlPrompt->put_hWnd(hWnd), "put_hWnd failed"); + + // Prompt for connection information. + sal::systools::COMReference<IDispatch> piDispatch; + sal::systools::ThrowIfFailed(dlPrompt->PromptNew(&piDispatch), "PromptNew failed"); + sal::systools::COMReference<ADOConnection> piTmpConnection(piDispatch, + sal::systools::COM_QUERY_THROW); + + sal::systools::BStr _result; + sal::systools::ThrowIfFailed(piTmpConnection->get_ConnectionString(&_result), + "get_ConnectionString failed"); + + return OUString(_result); + } + catch (const sal::systools::ComError&) + { + return OUString(); + } +} + +OUString PromptEdit(sal_IntPtr hWnd, OUString const & connstr) +{ + try + { + // Initialize COM + sal::systools::CoInitializeGuard aGuard(COINIT_APARTMENTTHREADED); + + sal::systools::COMReference<ADOConnection> piTmpConnection; + piTmpConnection.CoCreateInstance(CLSID_CADOConnection, nullptr, CLSCTX_INPROC_SERVER); + + sal::systools::ThrowIfFailed( + piTmpConnection->put_ConnectionString(sal::systools::BStr(connstr)), + "put_ConnectionString failed"); + + // Instantiate DataLinks object. + sal::systools::COMReference<IDataSourceLocator> dlPrompt; + dlPrompt.CoCreateInstance(CLSID_DataLinks, //clsid -- Data Links UI + nullptr, //pUnkOuter + CLSCTX_INPROC_SERVER); //dwClsContext + + sal::systools::ThrowIfFailed(dlPrompt->put_hWnd(hWnd), "put_hWnd failed"); + + try + { + // Prompt for connection information. + IDispatch* piDispatch = piTmpConnection.get(); + VARIANT_BOOL pbSuccess; + sal::systools::ThrowIfFailed(dlPrompt->PromptEdit(&piDispatch, &pbSuccess), + "PromptEdit failed"); + if (!pbSuccess) //if user press cancel then sal_False == pbSuccess + return connstr; + } + catch (const sal::systools::ComError&) + { + // Prompt for new connection information. + sal::systools::COMReference<IDispatch> piDispatch; + sal::systools::ThrowIfFailed(dlPrompt->PromptNew(&piDispatch), "PromptNew failed"); + piTmpConnection.set(piDispatch, sal::systools::COM_QUERY_THROW); + } + + sal::systools::BStr _result; + sal::systools::ThrowIfFailed(piTmpConnection->get_ConnectionString(&_result), + "get_ConnectionString failed"); + + return OUString(_result); + } + catch (const sal::systools::ComError&) + { + return connstr; + } +} + +} + +OUString getAdoDatalink(sal_IntPtr hWnd,OUString const & oldLink) +{ + OUString dataLink; + if (!oldLink.isEmpty()) + { + dataLink=PromptEdit(hWnd,oldLink); + } + else + dataLink=PromptNew(hWnd); + return dataLink; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/adodatalinks.hxx b/dbaccess/source/ui/dlg/adodatalinks.hxx new file mode 100644 index 000000000..6b753f62e --- /dev/null +++ b/dbaccess/source/ui/dlg/adodatalinks.hxx @@ -0,0 +1,26 @@ +/* -*- 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 <rtl/ustring.hxx> +#include <sal/types.h> + +OUString getAdoDatalink(sal_IntPtr hWnd, OUString const& oldLink); +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/adtabdlg.cxx b/dbaccess/source/ui/dlg/adtabdlg.cxx new file mode 100644 index 000000000..809b483cd --- /dev/null +++ b/dbaccess/source/ui/dlg/adtabdlg.cxx @@ -0,0 +1,467 @@ +/* -*- 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 <adtabdlg.hxx> +#include <tools/diagnose_ex.h> +#include <core_resource.hxx> +#include <strings.hrc> +#include <connectivity/dbtools.hxx> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/sdb/application/DatabaseObject.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <imageprovider.hxx> +#include <comphelper/containermultiplexer.hxx> +#include <cppuhelper/basemutex.hxx> +#include <algorithm> + +// slot ids +using namespace dbaui; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +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 dbtools; + +TableObjectListFacade::~TableObjectListFacade() +{ +} + +namespace { + +class TableListFacade : public ::cppu::BaseMutex + , public TableObjectListFacade + , public ::comphelper::OContainerListener +{ + OTableTreeListBox& m_rTableList; + Reference< XConnection > m_xConnection; + ::rtl::Reference< comphelper::OContainerListenerAdapter> + m_pContainerListener; + bool m_bAllowViews; + +public: + TableListFacade(OTableTreeListBox& _rTableList, const Reference< XConnection >& _rxConnection) + : ::comphelper::OContainerListener(m_aMutex) + ,m_rTableList( _rTableList ) + ,m_xConnection( _rxConnection ) + ,m_bAllowViews(true) + { + } + virtual ~TableListFacade() override; + +private: + virtual void updateTableObjectList( bool _bAllowViews ) override; + virtual OUString getSelectedName( OUString& _out_rAliasName ) const override; + virtual bool isLeafSelected() const override; + // OContainerListener + virtual void _elementInserted( const css::container::ContainerEvent& _rEvent ) override; + virtual void _elementRemoved( const css::container::ContainerEvent& _rEvent ) override; + virtual void _elementReplaced( const css::container::ContainerEvent& _rEvent ) override; +}; + +} + +TableListFacade::~TableListFacade() +{ + if ( m_pContainerListener.is() ) + m_pContainerListener->dispose(); +} + +OUString TableListFacade::getSelectedName( OUString& _out_rAliasName ) const +{ + weld::TreeView& rTableList = m_rTableList.GetWidget(); + std::unique_ptr<weld::TreeIter> xEntry(rTableList.make_iterator()); + + if (!rTableList.get_selected(xEntry.get())) + return OUString(); + + OUString aCatalog, aSchema, aTableName; + std::unique_ptr<weld::TreeIter> xSchema(rTableList.make_iterator(xEntry.get())); + if (rTableList.iter_parent(*xSchema)) + { + auto xAll = m_rTableList.getAllObjectsEntry(); + if (!xAll || !xSchema->equal(*xAll)) + { + std::unique_ptr<weld::TreeIter> xCatalog(rTableList.make_iterator(xSchema.get())); + if (rTableList.iter_parent(*xCatalog)) + { + if (!xAll || !xCatalog->equal(*xAll)) + aCatalog = rTableList.get_text(*xCatalog, 0); + } + aSchema = rTableList.get_text(*xSchema, 0); + } + } + aTableName = rTableList.get_text(*xEntry, 0); + + OUString aComposedName; + try + { + Reference< XDatabaseMetaData > xMeta( m_xConnection->getMetaData(), UNO_SET_THROW ); + if ( aCatalog.isEmpty() + && !aSchema.isEmpty() + && xMeta->supportsCatalogsInDataManipulation() + && !xMeta->supportsSchemasInDataManipulation() ) + { + aCatalog = aSchema; + aSchema.clear(); + } + + aComposedName = ::dbtools::composeTableName( + xMeta, aCatalog, aSchema, aTableName, false, ::dbtools::EComposeRule::InDataManipulation ); + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + _out_rAliasName = aTableName; + return aComposedName; +} + +void TableListFacade::_elementInserted( const container::ContainerEvent& /*_rEvent*/ ) +{ + updateTableObjectList(m_bAllowViews); +} + +void TableListFacade::_elementRemoved( const container::ContainerEvent& /*_rEvent*/ ) +{ + updateTableObjectList(m_bAllowViews); +} + +void TableListFacade::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ ) +{ +} + +void TableListFacade::updateTableObjectList( bool _bAllowViews ) +{ + m_bAllowViews = _bAllowViews; + weld::TreeView& rTableList = m_rTableList.GetWidget(); + rTableList.clear(); + try + { + Reference< XTablesSupplier > xTableSupp( m_xConnection, UNO_QUERY_THROW ); + + Reference< XViewsSupplier > xViewSupp; + Reference< XNameAccess > xTables, xViews; + Sequence< OUString > sTables, sViews; + + xTables = xTableSupp->getTables(); + if ( xTables.is() ) + { + if ( !m_pContainerListener.is() ) + { + Reference< XContainer> xContainer(xTables,uno::UNO_QUERY); + if ( xContainer.is() ) + m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer); + } + sTables = xTables->getElementNames(); + } + + xViewSupp.set( xTableSupp, UNO_QUERY ); + if ( xViewSupp.is() ) + { + xViews = xViewSupp->getViews(); + if ( xViews.is() ) + sViews = xViews->getElementNames(); + } + + // if no views are allowed remove the views also out the table name filter + if ( !_bAllowViews ) + { + const OUString* pTableBegin = sTables.getConstArray(); + const OUString* pTableEnd = pTableBegin + sTables.getLength(); + std::vector< OUString > aTables(pTableBegin,pTableEnd); + + const OUString* pViewBegin = sViews.getConstArray(); + const OUString* pViewEnd = pViewBegin + sViews.getLength(); + ::comphelper::UStringMixEqual aEqualFunctor; + for(;pViewBegin != pViewEnd;++pViewBegin) + aTables.erase(std::remove_if(aTables.begin(),aTables.end(), + [&aEqualFunctor, pViewBegin](const OUString& lhs) + { return aEqualFunctor(lhs, *pViewBegin); } ) + , aTables.end()); + sTables = Sequence< OUString>(aTables.data(), aTables.size()); + sViews = Sequence< OUString>(); + } + + m_rTableList.UpdateTableList( m_xConnection, sTables, sViews ); + + std::unique_ptr<weld::TreeIter> xEntry(rTableList.make_iterator()); + bool bEntry = rTableList.get_iter_first(*xEntry); + while (bEntry && rTableList.iter_has_child(*xEntry)) + { + rTableList.expand_row(*xEntry); + bEntry = rTableList.iter_next(*xEntry); + } + if (bEntry) + rTableList.select(*xEntry); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +bool TableListFacade::isLeafSelected() const +{ + weld::TreeView& rTableList = m_rTableList.GetWidget(); + std::unique_ptr<weld::TreeIter> xEntry(rTableList.make_iterator()); + const bool bEntry = rTableList.get_selected(xEntry.get()); + return bEntry && !rTableList.iter_has_child(*xEntry); +} + +namespace { + +class QueryListFacade : public ::cppu::BaseMutex + , public TableObjectListFacade + , public ::comphelper::OContainerListener +{ + weld::TreeView& m_rQueryList; + Reference< XConnection > m_xConnection; + ::rtl::Reference< comphelper::OContainerListenerAdapter> + m_pContainerListener; + +public: + QueryListFacade( weld::TreeView& _rQueryList, const Reference< XConnection >& _rxConnection ) + : ::comphelper::OContainerListener(m_aMutex) + ,m_rQueryList( _rQueryList ) + ,m_xConnection( _rxConnection ) + { + } + virtual ~QueryListFacade() override; + +private: + virtual void updateTableObjectList( bool _bAllowViews ) override; + virtual OUString getSelectedName( OUString& _out_rAliasName ) const override; + virtual bool isLeafSelected() const override; + // OContainerListener + virtual void _elementInserted( const css::container::ContainerEvent& _rEvent ) override; + virtual void _elementRemoved( const css::container::ContainerEvent& _rEvent ) override; + virtual void _elementReplaced( const css::container::ContainerEvent& _rEvent ) override; +}; + +} + +QueryListFacade::~QueryListFacade() +{ + if ( m_pContainerListener.is() ) + m_pContainerListener->dispose(); +} + +void QueryListFacade::_elementInserted( const container::ContainerEvent& _rEvent ) +{ + OUString sName; + if ( _rEvent.Accessor >>= sName ) + { + OUString aQueryImage(ImageProvider::getDefaultImageResourceID(css::sdb::application::DatabaseObject::QUERY)); + m_rQueryList.append("", sName, aQueryImage); + } +} + +void QueryListFacade::_elementRemoved( const container::ContainerEvent& /*_rEvent*/ ) +{ + updateTableObjectList(true); +} + +void QueryListFacade::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ ) +{ +} + +void QueryListFacade::updateTableObjectList( bool /*_bAllowViews*/ ) +{ + m_rQueryList.clear(); + try + { + OUString aQueryImage(ImageProvider::getDefaultImageResourceID(css::sdb::application::DatabaseObject::QUERY)); + + Reference< XQueriesSupplier > xSuppQueries( m_xConnection, UNO_QUERY_THROW ); + Reference< XNameAccess > xQueries( xSuppQueries->getQueries(), UNO_SET_THROW ); + if ( !m_pContainerListener.is() ) + { + Reference< XContainer> xContainer(xQueries,UNO_QUERY_THROW); + m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer); + } + const Sequence< OUString > aQueryNames = xQueries->getElementNames(); + + for ( auto const & name : aQueryNames ) + m_rQueryList.append("", name, aQueryImage); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +OUString QueryListFacade::getSelectedName( OUString& _out_rAliasName ) const +{ + OUString sSelected; + std::unique_ptr<weld::TreeIter> xEntry(m_rQueryList.make_iterator()); + const bool bEntry = m_rQueryList.get_selected(xEntry.get()); + if (bEntry) + sSelected = _out_rAliasName = m_rQueryList.get_text(*xEntry, 0); + return sSelected; +} + +bool QueryListFacade::isLeafSelected() const +{ + std::unique_ptr<weld::TreeIter> xEntry(m_rQueryList.make_iterator()); + const bool bEntry = m_rQueryList.get_selected(xEntry.get()); + return bEntry && !m_rQueryList.iter_has_child(*xEntry); + +} + +OAddTableDlg::OAddTableDlg(weld::Window* pParent, IAddTableDialogContext& _rContext) + : GenericDialogController(pParent, "dbaccess/ui/tablesjoindialog.ui", "TablesJoinDialog") + , m_rContext(_rContext) + , m_xCaseTables(m_xBuilder->weld_radio_button("tables")) + , m_xCaseQueries(m_xBuilder->weld_radio_button("queries")) + // false means: do not show any buttons + , m_xTableList(new OTableTreeListBox(m_xBuilder->weld_tree_view("tablelist"), false)) + , m_xQueryList(m_xBuilder->weld_tree_view("querylist")) + , m_xAddButton(m_xBuilder->weld_button("add")) + , m_xCloseButton(m_xBuilder->weld_button("close")) +{ + weld::TreeView& rTableList = m_xTableList->GetWidget(); + Size aSize(rTableList.get_approximate_digit_width() * 23, + rTableList.get_height_rows(15)); + rTableList.set_size_request(aSize.Width(), aSize.Height()); + m_xQueryList->set_size_request(aSize.Width(), aSize.Height()); + + m_xCaseTables->connect_toggled(LINK(this, OAddTableDlg, OnTypeSelected)); + m_xAddButton->connect_clicked( LINK( this, OAddTableDlg, AddClickHdl ) ); + m_xCloseButton->connect_clicked( LINK( this, OAddTableDlg, CloseClickHdl ) ); + rTableList.connect_row_activated( LINK( this, OAddTableDlg, TableListDoubleClickHdl ) ); + rTableList.connect_changed( LINK( this, OAddTableDlg, TableListSelectHdl ) ); + m_xQueryList->connect_row_activated( LINK( this, OAddTableDlg, TableListDoubleClickHdl ) ); + m_xQueryList->connect_changed( LINK( this, OAddTableDlg, TableListSelectHdl ) ); + + rTableList.set_selection_mode(SelectionMode::Single); + m_xTableList->SuppressEmptyFolders(); + + m_xQueryList->set_selection_mode(SelectionMode::Single); + + if ( !m_rContext.allowQueries() ) + { + m_xCaseTables->hide(); + m_xCaseQueries->hide(); + } + + m_xDialog->set_title(getDialogTitleForContext(m_rContext)); +} + +OAddTableDlg::~OAddTableDlg() +{ +} + +void OAddTableDlg::impl_switchTo( ObjectList _eList ) +{ + switch ( _eList ) + { + case Tables: + m_xTableList->GetWidget().show(); m_xCaseTables->set_active(true); + m_xQueryList->hide(); m_xCaseQueries->set_active(false); + m_xCurrentList.reset( new TableListFacade( *m_xTableList, m_rContext.getConnection() ) ); + m_xTableList->GetWidget().grab_focus(); + break; + + case Queries: + m_xTableList->GetWidget().hide(); m_xCaseTables->set_active(false); + m_xQueryList->show(); m_xCaseQueries->set_active(true); + m_xCurrentList.reset( new QueryListFacade( *m_xQueryList, m_rContext.getConnection() ) ); + m_xQueryList->grab_focus(); + break; + } + m_xCurrentList->updateTableObjectList( m_rContext.allowViews() ); +} + +void OAddTableDlg::Update() +{ + if (!m_xCurrentList) + impl_switchTo( Tables ); + else + m_xCurrentList->updateTableObjectList( m_rContext.allowViews() ); +} + +IMPL_LINK_NOARG( OAddTableDlg, AddClickHdl, weld::Button&, void ) +{ + TableListDoubleClickHdl(m_xTableList->GetWidget()); +} + +IMPL_LINK_NOARG(OAddTableDlg, TableListDoubleClickHdl, weld::TreeView&, bool) +{ + if ( impl_isAddAllowed() ) + { + if ( m_xCurrentList->isLeafSelected() ) + { + OUString sSelectedName, sAliasName; + sSelectedName = m_xCurrentList->getSelectedName( sAliasName ); + + m_rContext.addTableWindow( sSelectedName, sAliasName ); + } + if ( !impl_isAddAllowed() ) + m_xDialog->response(RET_CLOSE); + } + return true; +} + +IMPL_LINK_NOARG( OAddTableDlg, TableListSelectHdl, weld::TreeView&, void ) +{ + m_xAddButton->set_sensitive( m_xCurrentList->isLeafSelected() ); +} + +IMPL_LINK_NOARG( OAddTableDlg, CloseClickHdl, weld::Button&, void ) +{ + m_xDialog->response(RET_CLOSE); +} + +IMPL_LINK_NOARG(OAddTableDlg, OnTypeSelected, weld::Toggleable&, void) +{ + if ( m_xCaseTables->get_active() ) + impl_switchTo( Tables ); + else + impl_switchTo( Queries ); +} + +void OAddTableDlg::OnClose() +{ + m_rContext.onWindowClosing(); +} + +bool OAddTableDlg::impl_isAddAllowed() +{ + return m_rContext.allowAddition(); +} + +OUString OAddTableDlg::getDialogTitleForContext( IAddTableDialogContext const & _rContext ) +{ + OUString sTitle; + + if ( _rContext.allowQueries() ) + sTitle = DBA_RES( STR_ADD_TABLE_OR_QUERY ); + else + sTitle = DBA_RES( STR_ADD_TABLES ); + + return sTitle; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/advancedsettings.cxx b/dbaccess/source/ui/dlg/advancedsettings.cxx new file mode 100644 index 000000000..40964305a --- /dev/null +++ b/dbaccess/source/ui/dlg/advancedsettings.cxx @@ -0,0 +1,472 @@ +/* -*- 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 <memory> + +#include "advancedsettings.hxx" +#include <advancedsettingsdlg.hxx> +#include <dsitems.hxx> +#include "DbAdminImpl.hxx" +#include "DriverSettings.hxx" +#include "optionalboolitem.hxx" + +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svl/stritem.hxx> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::sdbc::XDriver; + + // SpecialSettingsPage + struct BooleanSettingDesc + { + std::unique_ptr<weld::CheckButton>& xControl; // the dialog's control which displays this setting + OString sControlId; // the widget name of the control in the .ui + sal_uInt16 nItemId; // the ID of the item (in an SfxItemSet) which corresponds to this setting + bool bInvertedDisplay; // true if and only if the checkbox is checked when the item is sal_False, and vice versa + bool bOptionalBool; // type is OptionalBool + }; + + // SpecialSettingsPage + SpecialSettingsPage::SpecialSettingsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs, const DataSourceMetaData& _rDSMeta) + : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/specialsettingspage.ui", "SpecialSettingsPage", _rCoreAttrs) + , m_aBooleanSettings { + { m_xIsSQL92Check, "usesql92", DSID_SQL92CHECK, false, false }, + { m_xAppendTableAlias, "append", DSID_APPEND_TABLE_ALIAS, false, false }, + { m_xAsBeforeCorrelationName, "useas", DSID_AS_BEFORE_CORRNAME, false, false }, + { m_xEnableOuterJoin, "useoj", DSID_ENABLEOUTERJOIN, false, false }, + { m_xIgnoreDriverPrivileges, "ignoreprivs", DSID_IGNOREDRIVER_PRIV, false, false }, + { m_xParameterSubstitution, "replaceparams", DSID_PARAMETERNAMESUBST, false, false }, + { m_xSuppressVersionColumn, "displayver", DSID_SUPPRESSVERSIONCL, true, false }, + { m_xCatalog, "usecatalogname", DSID_CATALOG, false, false }, + { m_xSchema, "useschemaname", DSID_SCHEMA, false, false }, + { m_xIndexAppendix, "createindex", DSID_INDEXAPPENDIX, false, false }, + { m_xDosLineEnds, "eol", DSID_DOSLINEENDS, false, false }, + { m_xCheckRequiredFields, "inputchecks", DSID_CHECK_REQUIRED_FIELDS, false, false }, + { m_xIgnoreCurrency, "ignorecurrency", DSID_IGNORECURRENCY, false, false }, + { m_xEscapeDateTime, "useodbcliterals", DSID_ESCAPE_DATETIME, false, false }, + { m_xPrimaryKeySupport, "primarykeys", DSID_PRIMARY_KEY_SUPPORT, false, false }, + { m_xRespectDriverResultSetType, "resulttype", DSID_RESPECTRESULTSETTYPE, false, false } } + , m_bHasBooleanComparisonMode( _rDSMeta.getFeatureSet().has( DSID_BOOLEANCOMPARISON ) ) + , m_bHasMaxRowScan( _rDSMeta.getFeatureSet().has( DSID_MAX_ROW_SCAN ) ) + { + const FeatureSet& rFeatures( _rDSMeta.getFeatureSet() ); + // create all the check boxes for the boolean settings + for (auto & booleanSetting : m_aBooleanSettings) + { + sal_uInt16 nItemId = booleanSetting.nItemId; + if ( rFeatures.has( nItemId ) ) + { + // check whether this must be a tristate check box + const SfxPoolItem& rItem = _rCoreAttrs.Get(nItemId); + booleanSetting.bOptionalBool = dynamic_cast<const OptionalBoolItem*>(&rItem) != nullptr; + booleanSetting.xControl = m_xBuilder->weld_check_button(booleanSetting.sControlId); + if (booleanSetting.bOptionalBool) + booleanSetting.xControl->connect_toggled(LINK(this, SpecialSettingsPage, OnTriStateToggleHdl)); + else + booleanSetting.xControl->connect_toggled(LINK(this, SpecialSettingsPage, OnToggleHdl)); + booleanSetting.xControl->show(); + } + } + + // create the controls for the boolean comparison mode + if ( m_bHasBooleanComparisonMode ) + { + m_xBooleanComparisonModeLabel = m_xBuilder->weld_label("comparisonft"); + m_xBooleanComparisonMode = m_xBuilder->weld_combo_box("comparison"); + m_xBooleanComparisonMode->connect_changed(LINK(this, SpecialSettingsPage, BooleanComparisonSelectHdl)); + m_xBooleanComparisonModeLabel->show(); + m_xBooleanComparisonMode->show(); + } + // create the controls for the max row scan + if ( m_bHasMaxRowScan ) + { + m_xMaxRowScanLabel = m_xBuilder->weld_label("rowsft"); + m_xMaxRowScan = m_xBuilder->weld_spin_button("rows"); + m_xMaxRowScan->connect_value_changed(LINK(this, OGenericAdministrationPage, OnControlSpinButtonModifyHdl)); + m_xMaxRowScanLabel->show(); + m_xMaxRowScan->show(); + } + } + + IMPL_LINK(SpecialSettingsPage, OnTriStateToggleHdl, weld::Toggleable&, rToggle, void) + { + auto eOldState = m_aTriStates[&rToggle]; + switch (eOldState) + { + case TRISTATE_INDET: + rToggle.set_state(TRISTATE_FALSE); + break; + case TRISTATE_TRUE: + rToggle.set_state(TRISTATE_INDET); + break; + case TRISTATE_FALSE: + rToggle.set_state(TRISTATE_TRUE); + break; + } + m_aTriStates[&rToggle] = rToggle.get_state(); + OnToggleHdl(rToggle); + } + + IMPL_LINK(SpecialSettingsPage, OnToggleHdl, weld::Toggleable&, rBtn, void) + { + if (&rBtn == m_xAppendTableAlias.get() && m_xAsBeforeCorrelationName) + { + // make m_xAsBeforeCorrelationName depend on m_xAppendTableAlias + m_xAsBeforeCorrelationName->set_sensitive(m_xAppendTableAlias->get_active()); + } + OnControlModifiedButtonClick(rBtn); + } + + IMPL_LINK(SpecialSettingsPage, BooleanComparisonSelectHdl, weld::ComboBox&, rControl, void) + { + callModifiedHdl(&rControl); + } + + SpecialSettingsPage::~SpecialSettingsPage() + { + } + + void SpecialSettingsPage::fillWindows( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList ) + { + if ( m_bHasBooleanComparisonMode ) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xBooleanComparisonModeLabel.get())); + } + if ( m_bHasMaxRowScan ) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xMaxRowScanLabel.get())); + } + } + + void SpecialSettingsPage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + for (auto const& booleanSetting : m_aBooleanSettings) + { + if (booleanSetting.xControl) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(booleanSetting.xControl.get())); + } + } + + if ( m_bHasBooleanComparisonMode ) + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xBooleanComparisonMode.get())); + if ( m_bHasMaxRowScan ) + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::SpinButton>(m_xMaxRowScan.get())); + } + + void SpecialSettingsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags( _rSet, bValid, bReadonly ); + + if ( !bValid ) + { + OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue); + return; + } + + m_aTriStates.clear(); + + // the boolean items + for (auto const& booleanSetting : m_aBooleanSettings) + { + if (!booleanSetting.xControl) + continue; + + bool bTriState = false; + + std::optional<bool> aValue; + + const SfxPoolItem* pItem = _rSet.GetItem<SfxPoolItem>(booleanSetting.nItemId); + if (const SfxBoolItem *pBoolItem = dynamic_cast<const SfxBoolItem*>( pItem) ) + { + aValue = pBoolItem->GetValue(); + } + else if (const OptionalBoolItem *pOptionalItem = dynamic_cast<const OptionalBoolItem*>( pItem) ) + { + aValue = pOptionalItem->GetFullValue(); + bTriState = true; + } + else + OSL_FAIL( "SpecialSettingsPage::implInitControls: unknown boolean item type!" ); + + if ( !aValue ) + { + booleanSetting.xControl->set_state(TRISTATE_INDET); + } + else + { + bool bValue = *aValue; + if ( booleanSetting.bInvertedDisplay ) + bValue = !bValue; + booleanSetting.xControl->set_active(bValue); + } + if (bTriState) + m_aTriStates[booleanSetting.xControl.get()] = booleanSetting.xControl->get_state(); + } + + if (m_xAppendTableAlias && m_xAsBeforeCorrelationName) + { + // make m_xAsBeforeCorrelationName depend on m_xAppendTableAlias + m_xAsBeforeCorrelationName->set_sensitive(m_xAppendTableAlias->get_active()); + } + + // the non-boolean items + if ( m_bHasBooleanComparisonMode ) + { + const SfxInt32Item* pBooleanComparison = _rSet.GetItem<SfxInt32Item>(DSID_BOOLEANCOMPARISON); + m_xBooleanComparisonMode->set_active(static_cast<sal_uInt16>(pBooleanComparison->GetValue())); + } + + if ( m_bHasMaxRowScan ) + { + const SfxInt32Item* pMaxRowScan = _rSet.GetItem<SfxInt32Item>(DSID_MAX_ROW_SCAN); + m_xMaxRowScan->set_value(pMaxRowScan->GetValue()); + } + + OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue); + } + + bool SpecialSettingsPage::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = false; + + // the boolean items + for (auto const& booleanSetting : m_aBooleanSettings) + { + if (!booleanSetting.xControl) + continue; + fillBool(*_rSet, booleanSetting.xControl.get(), booleanSetting.nItemId, booleanSetting.bOptionalBool, bChangedSomething, booleanSetting.bInvertedDisplay); + } + + // the non-boolean items + if ( m_bHasBooleanComparisonMode ) + { + if (m_xBooleanComparisonMode->get_value_changed_from_saved()) + { + _rSet->Put(SfxInt32Item(DSID_BOOLEANCOMPARISON, m_xBooleanComparisonMode->get_active())); + bChangedSomething = true; + } + } + if ( m_bHasMaxRowScan ) + { + fillInt32(*_rSet,m_xMaxRowScan.get(),DSID_MAX_ROW_SCAN,bChangedSomething); + } + return bChangedSomething; + } + + // GeneratedValuesPage + GeneratedValuesPage::GeneratedValuesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs) + : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/generatedvaluespage.ui", "GeneratedValuesPage", _rCoreAttrs) + , m_xAutoRetrievingEnabled(m_xBuilder->weld_check_button("autoretrieve")) + , m_xGrid(m_xBuilder->weld_widget("grid")) + , m_xAutoIncrementLabel(m_xBuilder->weld_label("statementft")) + , m_xAutoIncrement(m_xBuilder->weld_entry("statement")) + , m_xAutoRetrievingLabel(m_xBuilder->weld_label("queryft")) + , m_xAutoRetrieving(m_xBuilder->weld_entry("query")) + { + m_xAutoRetrievingEnabled->connect_toggled(LINK(this, GeneratedValuesPage, OnAutoToggleHdl)); + m_xAutoIncrement->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl)); + m_xAutoRetrieving->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl)); + } + + IMPL_LINK(GeneratedValuesPage, OnAutoToggleHdl, weld::Toggleable&, rBtn, void) + { + m_xGrid->set_sensitive(rBtn.get_active()); + OnControlModifiedButtonClick(rBtn); + } + + GeneratedValuesPage::~GeneratedValuesPage() + { + } + + void GeneratedValuesPage::fillWindows( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList ) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Widget>(m_xContainer.get())); + } + + void GeneratedValuesPage::fillControls( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList ) + { + _rControlList.emplace_back( new OSaveValueWidgetWrapper<weld::Toggleable>( m_xAutoRetrievingEnabled.get() ) ); + _rControlList.emplace_back( new OSaveValueWidgetWrapper<weld::Entry>( m_xAutoIncrement.get() ) ); + _rControlList.emplace_back( new OSaveValueWidgetWrapper<weld::Entry>( m_xAutoRetrieving.get() ) ); + } + + void GeneratedValuesPage::implInitControls( const SfxItemSet& _rSet, bool _bSaveValue ) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + // collect the items + const SfxStringItem* pAutoIncrementItem = _rSet.GetItem<SfxStringItem>(DSID_AUTOINCREMENTVALUE); + const SfxStringItem* pAutoRetrieveValueItem = _rSet.GetItem<SfxStringItem>(DSID_AUTORETRIEVEVALUE); + const SfxBoolItem* pAutoRetrieveEnabledItem = _rSet.GetItem<SfxBoolItem>(DSID_AUTORETRIEVEENABLED); + + // forward the values to the controls + if (bValid) + { + bool bEnabled = pAutoRetrieveEnabledItem->GetValue(); + m_xAutoRetrievingEnabled->set_active(bEnabled); + + m_xAutoIncrement->set_text(pAutoIncrementItem->GetValue()); + m_xAutoIncrement->save_value(); + m_xAutoRetrieving->set_text(pAutoRetrieveValueItem->GetValue()); + m_xAutoRetrieving->save_value(); + } + OGenericAdministrationPage::implInitControls( _rSet, _bSaveValue ); + } + + bool GeneratedValuesPage::FillItemSet(SfxItemSet* _rSet) + { + bool bChangedSomething = false; + + fillString( *_rSet, m_xAutoIncrement.get(), DSID_AUTOINCREMENTVALUE, bChangedSomething ); + fillBool( *_rSet, m_xAutoRetrievingEnabled.get(), DSID_AUTORETRIEVEENABLED, false, bChangedSomething ); + fillString( *_rSet, m_xAutoRetrieving.get(), DSID_AUTORETRIEVEVALUE, bChangedSomething ); + + return bChangedSomething; + } + + // AdvancedSettingsDialog + AdvancedSettingsDialog::AdvancedSettingsDialog(weld::Window* pParent, SfxItemSet* _pItems, + const Reference< XComponentContext >& _rxContext, const Any& _aDataSourceName ) + : SfxTabDialogController(pParent, "dbaccess/ui/advancedsettingsdialog.ui", "AdvancedSettingsDialog", _pItems) + { + m_pImpl.reset(new ODbDataSourceAdministrationHelper(_rxContext, m_xDialog.get(), pParent, this)); + m_pImpl->setDataSourceOrName(_aDataSourceName); + Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource(); + m_pImpl->translateProperties(xDatasource, *_pItems); + SetInputSet(_pItems); + // propagate this set as our new input set and reset the example set + m_xExampleSet.reset(new SfxItemSet(*GetInputSetImpl())); + + const OUString eType = dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(*_pItems); + + DataSourceMetaData aMeta( eType ); + const FeatureSet& rFeatures( aMeta.getFeatureSet() ); + + // auto-generated values? + if (rFeatures.supportsGeneratedValues()) + AddTabPage("generated", ODriversSettings::CreateGeneratedValuesPage, nullptr); + else + RemoveTabPage("generated"); + + // any "special settings"? + if (rFeatures.supportsAnySpecialSetting()) + AddTabPage("special", ODriversSettings::CreateSpecialSettingsPage, nullptr); + else + RemoveTabPage("special"); + + // remove the reset button - it's meaning is much too ambiguous in this dialog + RemoveResetButton(); + } + + AdvancedSettingsDialog::~AdvancedSettingsDialog() + { + SetInputSet(nullptr); + } + + bool AdvancedSettingsDialog::doesHaveAnyAdvancedSettings( const OUString& _sURL ) + { + DataSourceMetaData aMeta( _sURL ); + const FeatureSet& rFeatures( aMeta.getFeatureSet() ); + return rFeatures.supportsGeneratedValues() || rFeatures.supportsAnySpecialSetting(); + } + + short AdvancedSettingsDialog::Ok() + { + short nRet = SfxTabDialogController::Ok(); + if ( nRet == RET_OK ) + { + m_xExampleSet->Put(*GetOutputItemSet()); + m_pImpl->saveChanges(*m_xExampleSet); + } + return nRet; + } + + void AdvancedSettingsDialog::PageCreated(const OString& rId, SfxTabPage& _rPage) + { + // register ourself as modified listener + static_cast<OGenericAdministrationPage&>(_rPage).SetServiceFactory( getORB() ); + static_cast<OGenericAdministrationPage&>(_rPage).SetAdminDialog(this,this); + SfxTabDialogController::PageCreated(rId, _rPage); + } + + const SfxItemSet* AdvancedSettingsDialog::getOutputSet() const + { + return m_xExampleSet.get(); + } + + SfxItemSet* AdvancedSettingsDialog::getWriteOutputSet() + { + return m_xExampleSet.get(); + } + + std::pair< Reference< XConnection >, bool > AdvancedSettingsDialog::createConnection() + { + return m_pImpl->createConnection(); + } + + Reference< XComponentContext > AdvancedSettingsDialog::getORB() const + { + return m_pImpl->getORB(); + } + + Reference< XDriver > AdvancedSettingsDialog::getDriver() + { + return m_pImpl->getDriver(); + } + + OUString AdvancedSettingsDialog::getDatasourceType(const SfxItemSet& _rSet) const + { + return dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(_rSet); + } + + void AdvancedSettingsDialog::clearPassword() + { + m_pImpl->clearPassword(); + } + + void AdvancedSettingsDialog::setTitle(const OUString& _sTitle) + { + m_xDialog->set_title(_sTitle); + } + + void AdvancedSettingsDialog::enableConfirmSettings( bool ) {} + + void AdvancedSettingsDialog::saveDatasource() + { + PrepareLeaveCurrentPage(); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/advancedsettings.hxx b/dbaccess/source/ui/dlg/advancedsettings.hxx new file mode 100644 index 000000000..38f100612 --- /dev/null +++ b/dbaccess/source/ui/dlg/advancedsettings.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 "adminpages.hxx" +#include <dsmeta.hxx> +#include <vector> + +namespace dbaui +{ + struct BooleanSettingDesc; + + // SpecialSettingsPage + // implements the "Special Settings" page of the advanced database settings + class SpecialSettingsPage final : public OGenericAdministrationPage + { + std::unique_ptr<weld::CheckButton> m_xIsSQL92Check; + std::unique_ptr<weld::CheckButton> m_xAppendTableAlias; + std::unique_ptr<weld::CheckButton> m_xAsBeforeCorrelationName; + std::unique_ptr<weld::CheckButton> m_xEnableOuterJoin; + std::unique_ptr<weld::CheckButton> m_xIgnoreDriverPrivileges; + std::unique_ptr<weld::CheckButton> m_xParameterSubstitution; + std::unique_ptr<weld::CheckButton> m_xSuppressVersionColumn; + std::unique_ptr<weld::CheckButton> m_xCatalog; + std::unique_ptr<weld::CheckButton> m_xSchema; + std::unique_ptr<weld::CheckButton> m_xIndexAppendix; + std::unique_ptr<weld::CheckButton> m_xDosLineEnds; + std::unique_ptr<weld::CheckButton> m_xCheckRequiredFields; + std::unique_ptr<weld::CheckButton> m_xIgnoreCurrency; + std::unique_ptr<weld::CheckButton> m_xEscapeDateTime; + std::unique_ptr<weld::CheckButton> m_xPrimaryKeySupport; + std::unique_ptr<weld::CheckButton> m_xRespectDriverResultSetType; + + std::unique_ptr<weld::Label> m_xBooleanComparisonModeLabel; + std::unique_ptr<weld::ComboBox> m_xBooleanComparisonMode; + + std::unique_ptr<weld::Label> m_xMaxRowScanLabel; + std::unique_ptr<weld::SpinButton> m_xMaxRowScan; + + std::map<weld::Toggleable*, TriState> m_aTriStates; + + std::vector< BooleanSettingDesc > m_aBooleanSettings; + + bool m_bHasBooleanComparisonMode; + bool m_bHasMaxRowScan; + + public: + DECL_LINK(OnToggleHdl, weld::Toggleable&, void); + DECL_LINK(OnTriStateToggleHdl, weld::Toggleable&, void); + + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + + SpecialSettingsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs, const DataSourceMetaData& _rDSMeta); + virtual ~SpecialSettingsPage() override; + + private: + // OGenericAdministrationPage overridables + virtual void implInitControls (const SfxItemSet& _rSet, bool _bSaveValue ) override; + + // <method>OGenericAdministrationPage::fillControls</method> + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + + // <method>OGenericAdministrationPage::fillWindows</method> + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + + DECL_LINK(BooleanComparisonSelectHdl, weld::ComboBox&, void); + }; + + // GeneratedValuesPage + class GeneratedValuesPage final : public OGenericAdministrationPage + { + std::unique_ptr<weld::CheckButton> m_xAutoRetrievingEnabled; + std::unique_ptr<weld::Widget> m_xGrid; + std::unique_ptr<weld::Label> m_xAutoIncrementLabel; + std::unique_ptr<weld::Entry> m_xAutoIncrement; + std::unique_ptr<weld::Label> m_xAutoRetrievingLabel; + std::unique_ptr<weld::Entry> m_xAutoRetrieving; + + public: + virtual bool FillItemSet (SfxItemSet* _rCoreAttrs) override; + + GeneratedValuesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs); + virtual ~GeneratedValuesPage() override; + + private: + DECL_LINK(OnAutoToggleHdl, weld::Toggleable&, void); + + // subclasses must override this, but it isn't pure virtual + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + + // <method>OGenericAdministrationPage::fillControls</method> + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + + // <method>OGenericAdministrationPage::fillWindows</method> + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dbadmin.cxx b/dbaccess/source/ui/dlg/dbadmin.cxx new file mode 100644 index 000000000..c6ca46f75 --- /dev/null +++ b/dbaccess/source/ui/dlg/dbadmin.cxx @@ -0,0 +1,433 @@ +/* -*- 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 "ConnectionPage.hxx" +#include "DbAdminImpl.hxx" +#include "DriverSettings.hxx" +#include "adminpages.hxx" +#include <dbadmin.hxx> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <core_resource.hxx> +#include <strings.hrc> +#include <dsitems.hxx> +#include "dsnItem.hxx" +#include "optionalboolitem.hxx" +#include <stringlistitem.hxx> + +#include <unotools/confignode.hxx> + +namespace dbaui +{ +using namespace com::sun::star::uno; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::lang; +using namespace com::sun::star::util; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; + +// ODbAdminDialog +ODbAdminDialog::ODbAdminDialog(weld::Window* pParent, + SfxItemSet const * _pItems, + const Reference< XComponentContext >& _rxContext) + : SfxTabDialogController(pParent, "dbaccess/ui/admindialog.ui", "AdminDialog", _pItems) + , m_sMainPageID("advanced") +{ + m_pImpl.reset(new ODbDataSourceAdministrationHelper(_rxContext, m_xDialog.get(), pParent, this)); + + // add the initial tab page + AddTabPage(m_sMainPageID, OConnectionTabPage::Create, nullptr); + + // remove the reset button - it's meaning is much too ambiguous in this dialog + RemoveResetButton(); +} + +ODbAdminDialog::~ODbAdminDialog() +{ + SetInputSet(nullptr); +} + +short ODbAdminDialog::Ok() +{ + SfxTabDialogController::Ok(); + return ( AR_LEAVE_MODIFIED == implApplyChanges() ) ? RET_OK : RET_CANCEL; + // TODO : AR_ERROR is not handled correctly, we always close the dialog here +} + +void ODbAdminDialog::PageCreated(const OString& rId, SfxTabPage& _rPage) +{ + // register ourself as modified listener + static_cast<OGenericAdministrationPage&>(_rPage).SetServiceFactory( getORB() ); + static_cast<OGenericAdministrationPage&>(_rPage).SetAdminDialog(this,this); + + SfxTabDialogController::PageCreated(rId, _rPage); +} + +void ODbAdminDialog::addDetailPage(const OString& rPageId, TranslateId pTextId, CreateTabPage pCreateFunc) +{ + AddTabPage(rPageId, DBA_RES(pTextId), pCreateFunc); +} + +void ODbAdminDialog::impl_selectDataSource(const css::uno::Any& _aDataSourceName) +{ + m_pImpl->setDataSourceOrName(_aDataSourceName); + Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource(); + impl_resetPages( xDatasource ); + + const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>(getOutputSet()->GetItem(DSID_TYPECOLLECTION)); + assert(pCollectionItem && "must exist"); + ::dbaccess::ODsnTypeCollection* pCollection = pCollectionItem->getCollection(); + ::dbaccess::DATASOURCE_TYPE eType = pCollection->determineType(getDatasourceType(*getOutputSet())); + + // and insert the new ones + switch ( eType ) + { + case ::dbaccess::DST_DBASE: + addDetailPage("dbase", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateDbase); + break; + + case ::dbaccess::DST_ADO: + addDetailPage("ado", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateAdo); + break; + + case ::dbaccess::DST_FLAT: + addDetailPage("text", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateText); + break; + + case ::dbaccess::DST_ODBC: + addDetailPage("odbc", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateODBC); + break; + + case ::dbaccess::DST_MYSQL_ODBC: + addDetailPage("mysqlodbc", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateMySQLODBC); + break; + + case ::dbaccess::DST_MYSQL_JDBC: + addDetailPage("mysqljdbc", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateMySQLJDBC); + break; + + case ::dbaccess::DST_ORACLE_JDBC: + addDetailPage("oraclejdbc", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateOracleJDBC); + break; + + case ::dbaccess::DST_LDAP: + addDetailPage("ldap",STR_PAGETITLE_ADVANCED,ODriversSettings::CreateLDAP); + break; + case ::dbaccess::DST_USERDEFINE1: /// first user defined driver + case ::dbaccess::DST_USERDEFINE2: + case ::dbaccess::DST_USERDEFINE3: + case ::dbaccess::DST_USERDEFINE4: + case ::dbaccess::DST_USERDEFINE5: + case ::dbaccess::DST_USERDEFINE6: + case ::dbaccess::DST_USERDEFINE7: + case ::dbaccess::DST_USERDEFINE8: + case ::dbaccess::DST_USERDEFINE9: + case ::dbaccess::DST_USERDEFINE10: + { + OUString aTitle(DBA_RES(STR_PAGETITLE_ADVANCED)); + AddTabPage("user" + OString::number(eType - dbaccess::DST_USERDEFINE1 + 1), aTitle, ODriversSettings::CreateUser); + } + break; + default: + break; + } +} + +void ODbAdminDialog::impl_resetPages(const Reference< XPropertySet >& _rxDatasource) +{ + // the selection is valid if and only if we have a datasource now + GetInputSetImpl()->Put(SfxBoolItem(DSID_INVALID_SELECTION, !_rxDatasource.is())); + // (sal_False tells the tab pages to disable and reset all their controls, which is different + // from "just set them to readonly") + + // reset the pages + + // prevent flicker + m_xDialog->freeze(); + + // remove all items which relate to indirect properties from the input set + // (without this, the following may happen: select an arbitrary data source where some indirect properties + // are set. Select another data source of the same type, where the indirect props are not set (yet). Then, + // the indirect property values of the first ds are shown in the second ds ...) + const ODbDataSourceAdministrationHelper::MapInt2String& rMap = m_pImpl->getIndirectProperties(); + for (auto const& elem : rMap) + GetInputSetImpl()->ClearItem( static_cast<sal_uInt16>(elem.first) ); + + // extract all relevant data from the property set of the data source + m_pImpl->translateProperties(_rxDatasource, *GetInputSetImpl()); + + // reset the example set + m_xExampleSet.reset(new SfxItemSet(*GetInputSetImpl())); + + // special case: MySQL Native does not have the generic "advanced" page + + const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>(getOutputSet()->GetItem(DSID_TYPECOLLECTION)); + assert(pCollectionItem && "must exist"); + ::dbaccess::ODsnTypeCollection* pCollection = pCollectionItem->getCollection(); + if ( pCollection->determineType(getDatasourceType( *m_xExampleSet )) == ::dbaccess::DST_MYSQL_NATIVE ) + { + OString sMySqlNative("mysqlnative"); + AddTabPage(sMySqlNative, DBA_RES(STR_PAGETITLE_CONNECTION), ODriversSettings::CreateMySQLNATIVE); + RemoveTabPage("advanced"); + m_sMainPageID = sMySqlNative; + } + + SetCurPageId(m_sMainPageID); + SfxTabPage* pConnectionPage = GetTabPage(m_sMainPageID); + if ( pConnectionPage ) + pConnectionPage->Reset(GetInputSetImpl()); + // if this is NULL, the page has not been created yet, which means we're called before the + // dialog was displayed (probably from inside the ctor) + + m_xDialog->thaw(); +} + +void ODbAdminDialog::setTitle(const OUString& rTitle) +{ + m_xDialog->set_title(rTitle); +} + +void ODbAdminDialog::enableConfirmSettings( bool ) {} + +void ODbAdminDialog::saveDatasource() +{ + PrepareLeaveCurrentPage(); +} + +ODbAdminDialog::ApplyResult ODbAdminDialog::implApplyChanges() +{ + if (!PrepareLeaveCurrentPage()) + { // the page did not allow us to leave + return AR_KEEP; + } + + if ( !m_pImpl->saveChanges(*m_xExampleSet) ) + return AR_KEEP; + + return AR_LEAVE_MODIFIED; +} + +void ODbAdminDialog::selectDataSource(const css::uno::Any& _aDataSourceName) +{ + impl_selectDataSource(_aDataSourceName); +} + +const SfxItemSet* ODbAdminDialog::getOutputSet() const +{ + return GetExampleSet(); +} + +SfxItemSet* ODbAdminDialog::getWriteOutputSet() +{ + return m_xExampleSet.get(); +} + +std::pair< Reference<XConnection>,bool> ODbAdminDialog::createConnection() +{ + return m_pImpl->createConnection(); +} + +Reference< XComponentContext > ODbAdminDialog::getORB() const +{ + return m_pImpl->getORB(); +} + +Reference< XDriver > ODbAdminDialog::getDriver() +{ + return m_pImpl->getDriver(); +} + +OUString ODbAdminDialog::getDatasourceType(const SfxItemSet& _rSet) const +{ + return dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(_rSet); +} + +void ODbAdminDialog::clearPassword() +{ + m_pImpl->clearPassword(); +} + +void ODbAdminDialog::createItemSet(std::unique_ptr<SfxItemSet>& _rpSet, rtl::Reference<SfxItemPool>& _rpPool, std::vector<SfxPoolItem*>*& _rpDefaults, ::dbaccess::ODsnTypeCollection* _pTypeCollection) +{ + // just to be sure... + _rpSet = nullptr; + _rpPool = nullptr; + _rpDefaults = nullptr; + + const OUString sFilterAll( "%" ); + // create and initialize the defaults + _rpDefaults = new std::vector<SfxPoolItem*>(DSID_LAST_ITEM_ID - DSID_FIRST_ITEM_ID + 1); + SfxPoolItem** pCounter = _rpDefaults->data(); // want to modify this without affecting the out param _rppDefaults + *pCounter++ = new SfxStringItem(DSID_NAME, OUString()); + *pCounter++ = new SfxStringItem(DSID_ORIGINALNAME, OUString()); + *pCounter++ = new SfxStringItem(DSID_CONNECTURL, OUString()); + *pCounter++ = new OStringListItem(DSID_TABLEFILTER, Sequence< OUString >(&sFilterAll, 1)); + *pCounter++ = new DbuTypeCollectionItem(DSID_TYPECOLLECTION, _pTypeCollection); + *pCounter++ = new SfxBoolItem(DSID_INVALID_SELECTION, false); + *pCounter++ = new SfxBoolItem(DSID_READONLY, false); + *pCounter++ = new SfxStringItem(DSID_USER, OUString()); + *pCounter++ = new SfxStringItem(DSID_PASSWORD, OUString()); + *pCounter++ = new SfxStringItem(DSID_ADDITIONALOPTIONS, OUString()); + *pCounter++ = new SfxStringItem(DSID_CHARSET, OUString()); + *pCounter++ = new SfxBoolItem(DSID_PASSWORDREQUIRED, false); + *pCounter++ = new SfxBoolItem(DSID_SHOWDELETEDROWS, false); + *pCounter++ = new SfxBoolItem(DSID_ALLOWLONGTABLENAMES, false); + *pCounter++ = new SfxStringItem(DSID_JDBCDRIVERCLASS, OUString()); + *pCounter++ = new SfxStringItem(DSID_FIELDDELIMITER, OUString(',')); + *pCounter++ = new SfxStringItem(DSID_TEXTDELIMITER, OUString('"')); + *pCounter++ = new SfxStringItem(DSID_DECIMALDELIMITER, OUString('.')); + *pCounter++ = new SfxStringItem(DSID_THOUSANDSDELIMITER, OUString()); + *pCounter++ = new SfxStringItem(DSID_TEXTFILEEXTENSION, "txt"); + *pCounter++ = new SfxBoolItem(DSID_TEXTFILEHEADER, true); + *pCounter++ = new SfxBoolItem(DSID_PARAMETERNAMESUBST, false); + *pCounter++ = new SfxInt32Item(DSID_CONN_PORTNUMBER, 8100); + *pCounter++ = new SfxBoolItem(DSID_SUPPRESSVERSIONCL, false); + *pCounter++ = new SfxBoolItem(DSID_CONN_SHUTSERVICE, false); + *pCounter++ = new SfxInt32Item(DSID_CONN_DATAINC, 20); + *pCounter++ = new SfxInt32Item(DSID_CONN_CACHESIZE, 20); + *pCounter++ = new SfxStringItem(DSID_CONN_CTRLUSER, OUString()); + *pCounter++ = new SfxStringItem(DSID_CONN_CTRLPWD, OUString()); + *pCounter++ = new SfxBoolItem(DSID_USECATALOG, false); + *pCounter++ = new SfxStringItem(DSID_CONN_HOSTNAME, OUString()); + *pCounter++ = new SfxStringItem(DSID_CONN_LDAP_BASEDN, OUString()); + *pCounter++ = new SfxInt32Item(DSID_CONN_LDAP_PORTNUMBER, 389); + *pCounter++ = new SfxInt32Item(DSID_CONN_LDAP_ROWCOUNT, 100); + *pCounter++ = new SfxBoolItem(DSID_SQL92CHECK, false); + *pCounter++ = new SfxStringItem(DSID_AUTOINCREMENTVALUE, OUString()); + *pCounter++ = new SfxStringItem(DSID_AUTORETRIEVEVALUE, OUString()); + *pCounter++ = new SfxBoolItem(DSID_AUTORETRIEVEENABLED, false); + *pCounter++ = new SfxBoolItem(DSID_APPEND_TABLE_ALIAS, false); + *pCounter++ = new SfxInt32Item(DSID_MYSQL_PORTNUMBER, 3306); + *pCounter++ = new SfxBoolItem(DSID_IGNOREDRIVER_PRIV, true); + *pCounter++ = new SfxInt32Item(DSID_BOOLEANCOMPARISON, 0); + *pCounter++ = new SfxInt32Item(DSID_ORACLE_PORTNUMBER, 1521); + *pCounter++ = new SfxBoolItem(DSID_ENABLEOUTERJOIN, true); + *pCounter++ = new SfxBoolItem(DSID_CATALOG, true); + *pCounter++ = new SfxBoolItem(DSID_SCHEMA, true); + *pCounter++ = new SfxBoolItem(DSID_INDEXAPPENDIX, true); + *pCounter++ = new SfxBoolItem(DSID_CONN_LDAP_USESSL, false); + *pCounter++ = new SfxStringItem(DSID_DOCUMENT_URL, OUString()); + *pCounter++ = new SfxBoolItem(DSID_DOSLINEENDS, false); + *pCounter++ = new SfxStringItem(DSID_DATABASENAME, OUString()); + *pCounter++ = new SfxBoolItem(DSID_AS_BEFORE_CORRNAME, false); + *pCounter++ = new SfxBoolItem(DSID_CHECK_REQUIRED_FIELDS, true); + *pCounter++ = new SfxBoolItem(DSID_IGNORECURRENCY, false); + *pCounter++ = new SfxStringItem(DSID_CONN_SOCKET, OUString()); + *pCounter++ = new SfxBoolItem(DSID_ESCAPE_DATETIME, true); + *pCounter++ = new SfxStringItem(DSID_NAMED_PIPE, OUString()); + *pCounter++ = new OptionalBoolItem( DSID_PRIMARY_KEY_SUPPORT ); + *pCounter++ = new SfxInt32Item(DSID_MAX_ROW_SCAN, 100); + *pCounter++ = new SfxBoolItem( DSID_RESPECTRESULTSETTYPE,false ); + + // create the pool + static SfxItemInfo const aItemInfos[DSID_LAST_ITEM_ID - DSID_FIRST_ITEM_ID + 1] = + { + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + }; + + OSL_ENSURE(SAL_N_ELEMENTS(aItemInfos) == DSID_LAST_ITEM_ID,"Invalid Ids!"); + _rpPool = new SfxItemPool("DSAItemPool", DSID_FIRST_ITEM_ID, DSID_LAST_ITEM_ID, + aItemInfos, _rpDefaults); + _rpPool->FreezeIdRanges(); + + // and, finally, the set + _rpSet.reset(new SfxItemSet(*_rpPool)); +} + +void ODbAdminDialog::destroyItemSet(std::unique_ptr<SfxItemSet>& _rpSet, rtl::Reference<SfxItemPool>& _rpPool, std::vector<SfxPoolItem*>*& _rpDefaults) +{ + // _first_ delete the set (referring the pool) + _rpSet.reset(); + + // delete the pool + if (_rpPool) + { + _rpPool->ReleaseDefaults(true); + // the "true" means delete the items, too + _rpPool = nullptr; + } + + // reset the defaults ptr + _rpDefaults = nullptr; + // no need to explicitly delete the defaults, this has been done by the ReleaseDefaults +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dbfindex.cxx b/dbaccess/source/ui/dlg/dbfindex.cxx new file mode 100644 index 000000000..89f74ab72 --- /dev/null +++ b/dbaccess/source/ui/dlg/dbfindex.cxx @@ -0,0 +1,430 @@ +/* -*- 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 "dbfindex.hxx" +#include <comphelper/processfactory.hxx> +#include <osl/file.hxx> +#include <osl/thread.hxx> +#include <tools/config.hxx> +#include <osl/diagnose.h> +#include <unotools/localfilehelper.hxx> +#include <tools/urlobj.hxx> +#include <unotools/pathoptions.hxx> +#include <ucbhelper/content.hxx> +#include <svl/filenotation.hxx> +#include <rtl/strbuf.hxx> + +namespace dbaui +{ +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::svt; + +constexpr OStringLiteral aGroupIdent("dBase III"); + + +ODbaseIndexDialog::ODbaseIndexDialog(weld::Window * pParent, const OUString& aDataSrcName) + : GenericDialogController(pParent, "dbaccess/ui/dbaseindexdialog.ui", "DBaseIndexDialog") + , m_aDSN(aDataSrcName) + , m_xPB_OK(m_xBuilder->weld_button("ok")) + , m_xCB_Tables(m_xBuilder->weld_combo_box("table")) + , m_xIndexes(m_xBuilder->weld_widget("frame")) + , m_xLB_TableIndexes(m_xBuilder->weld_tree_view("tableindex")) + , m_xLB_FreeIndexes(m_xBuilder->weld_tree_view("freeindex")) + , m_xAdd(m_xBuilder->weld_button("add")) + , m_xRemove(m_xBuilder->weld_button("remove")) + , m_xAddAll(m_xBuilder->weld_button("addall")) + , m_xRemoveAll(m_xBuilder->weld_button("removeall")) +{ + int nWidth = m_xLB_TableIndexes->get_approximate_digit_width() * 18; + int nHeight = m_xLB_TableIndexes->get_height_rows(10); + m_xLB_TableIndexes->set_size_request(nWidth, nHeight); + m_xLB_FreeIndexes->set_size_request(nWidth, nHeight); + + m_xCB_Tables->connect_changed( LINK(this, ODbaseIndexDialog, TableSelectHdl) ); + m_xAdd->connect_clicked( LINK(this, ODbaseIndexDialog, AddClickHdl) ); + m_xRemove->connect_clicked( LINK(this, ODbaseIndexDialog, RemoveClickHdl) ); + m_xAddAll->connect_clicked( LINK(this, ODbaseIndexDialog, AddAllClickHdl) ); + m_xRemoveAll->connect_clicked( LINK(this, ODbaseIndexDialog, RemoveAllClickHdl) ); + m_xPB_OK->connect_clicked( LINK(this, ODbaseIndexDialog, OKClickHdl) ); + + m_xLB_FreeIndexes->connect_changed( LINK(this, ODbaseIndexDialog, OnListEntrySelected) ); + m_xLB_TableIndexes->connect_changed( LINK(this, ODbaseIndexDialog, OnListEntrySelected) ); + + Init(); + SetCtrls(); +} + +ODbaseIndexDialog::~ODbaseIndexDialog() +{ +} + +void ODbaseIndexDialog::checkButtons() +{ + m_xAdd->set_sensitive(0 != m_xLB_FreeIndexes->count_selected_rows()); + m_xAddAll->set_sensitive(0 != m_xLB_FreeIndexes->n_children()); + + m_xRemove->set_sensitive(0 != m_xLB_TableIndexes->count_selected_rows()); + m_xRemoveAll->set_sensitive(0 != m_xLB_TableIndexes->n_children()); +} + +OTableIndex ODbaseIndexDialog::implRemoveIndex(const OUString& _rName, TableIndexList& _rList, weld::TreeView& _rDisplay, bool _bMustExist) +{ + OTableIndex aReturn; + + TableIndexList::iterator aSearch = std::find_if(_rList.begin(), _rList.end(), + [&_rName](const OTableIndex& rIndex) { return rIndex.GetIndexFileName() == _rName; }); + if (aSearch != _rList.end()) + { + sal_Int32 nPos = static_cast<sal_Int32>(std::distance(_rList.begin(), aSearch)); + + aReturn = *aSearch; + + _rList.erase(aSearch); + _rDisplay.remove_text(_rName); + + // adjust selection if necessary + if (static_cast<sal_uInt32>(nPos) == _rList.size()) + _rDisplay.select(static_cast<sal_uInt16>(nPos)-1); + else + _rDisplay.select(static_cast<sal_uInt16>(nPos)); + } + OSL_ENSURE(!_bMustExist || !aReturn.GetIndexFileName().isEmpty(), "ODbaseIndexDialog::implRemoveIndex : did not find the index!"); + return aReturn; +} + +void ODbaseIndexDialog::implInsertIndex(const OTableIndex& _rIndex, TableIndexList& _rList, weld::TreeView& _rDisplay) +{ + _rList.push_front(_rIndex); + _rDisplay.append_text(_rIndex.GetIndexFileName()); + _rDisplay.select(0); +} + +OTableIndex ODbaseIndexDialog::RemoveTableIndex( std::u16string_view _rTableName, const OUString& _rIndexName ) +{ + OTableIndex aReturn; + + // does the table exist ? + TableInfoList::iterator aTablePos = std::find_if(m_aTableInfoList.begin(), m_aTableInfoList.end(), + [&] (const OTableInfo& arg) { return arg.aTableName == _rTableName; }); + + if (aTablePos == m_aTableInfoList.end()) + return aReturn; + + return implRemoveIndex(_rIndexName, aTablePos->aIndexList, *m_xLB_TableIndexes, true/*_bMustExist*/); +} + +void ODbaseIndexDialog::InsertTableIndex( std::u16string_view _rTableName, const OTableIndex& _rIndex) +{ + TableInfoList::iterator aTablePos = std::find_if(m_aTableInfoList.begin(), m_aTableInfoList.end(), + [&] (const OTableInfo& arg) { return arg.aTableName == _rTableName; }); + + if (aTablePos == m_aTableInfoList.end()) + return; + + implInsertIndex(_rIndex, aTablePos->aIndexList, *m_xLB_TableIndexes); +} + +IMPL_LINK_NOARG(ODbaseIndexDialog, OKClickHdl, weld::Button&, void) +{ + // let all tables write their INF file + + for (auto const& tableInfo : m_aTableInfoList) + tableInfo.WriteInfFile(m_aDSN); + + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(ODbaseIndexDialog, AddClickHdl, weld::Button&, void) +{ + OUString aSelection = m_xLB_FreeIndexes->get_selected_text(); + OUString aTableName = m_xCB_Tables->get_active_text(); + OTableIndex aIndex = RemoveFreeIndex( aSelection, true ); + InsertTableIndex( aTableName, aIndex ); + + checkButtons(); +} + +IMPL_LINK_NOARG(ODbaseIndexDialog, RemoveClickHdl, weld::Button&, void) +{ + OUString aSelection = m_xLB_TableIndexes->get_selected_text(); + OUString aTableName = m_xCB_Tables->get_active_text(); + OTableIndex aIndex = RemoveTableIndex( aTableName, aSelection ); + InsertFreeIndex( aIndex ); + + checkButtons(); +} + +IMPL_LINK_NOARG(ODbaseIndexDialog, AddAllClickHdl, weld::Button&, void) +{ + const sal_Int32 nCnt = m_xLB_FreeIndexes->n_children(); + OUString aTableName = m_xCB_Tables->get_active_text(); + + for (sal_Int32 nPos = 0; nPos < nCnt; ++nPos) + InsertTableIndex(aTableName, RemoveFreeIndex(m_xLB_FreeIndexes->get_text(0), true)); + + checkButtons(); +} + +IMPL_LINK_NOARG(ODbaseIndexDialog, RemoveAllClickHdl, weld::Button&, void) +{ + const sal_Int32 nCnt = m_xLB_TableIndexes->n_children(); + OUString aTableName = m_xCB_Tables->get_active_text(); + + for (sal_Int32 nPos = 0; nPos < nCnt; ++nPos) + InsertFreeIndex(RemoveTableIndex(aTableName, m_xLB_TableIndexes->get_text(0))); + + checkButtons(); +} + +IMPL_LINK_NOARG(ODbaseIndexDialog, OnListEntrySelected, weld::TreeView&, void) +{ + checkButtons(); +} + +IMPL_LINK(ODbaseIndexDialog, TableSelectHdl, weld::ComboBox&, rComboBox, void) +{ + // search the table + TableInfoList::iterator aTablePos = std::find_if(m_aTableInfoList.begin(), m_aTableInfoList.end(), + [&] (const OTableInfo& arg) { return arg.aTableName == rComboBox.get_active_text() ; }); + + if (aTablePos == m_aTableInfoList.end()) + return; + + // fill the listbox for the indexes + m_xLB_TableIndexes->clear(); + for (auto const& index : aTablePos->aIndexList) + m_xLB_TableIndexes->append_text(index.GetIndexFileName()); + + if (!aTablePos->aIndexList.empty()) + m_xLB_TableIndexes->select(0); + + checkButtons(); +} + +void ODbaseIndexDialog::Init() +{ + m_xPB_OK->set_sensitive(false); + m_xIndexes->set_sensitive(false); + + // All indices are first added to a list of free indices. + // Afterwards, check the index of each table in the Inf-file. + // These indices are removed from the list of free indices and + // entered in the indexlist of the table. + + // if the string does not contain a path, cut the string + INetURLObject aURL; + aURL.SetSmartProtocol(INetProtocol::File); + { + SvtPathOptions aPathOptions; + m_aDSN = aPathOptions.SubstituteVariable(m_aDSN); + } + aURL.SetSmartURL(m_aDSN); + + // String aFileName = aURL.PathToFileName(); + m_aDSN = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); + ::ucbhelper::Content aFile; + bool bFolder=true; + try + { + aFile = ::ucbhelper::Content(m_aDSN,Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext()); + bFolder = aFile.isFolder(); + } + catch(Exception&) + { + return; + } + + // first assume for all indexes they're free + + OUString const aIndexExt("ndx"); + OUString const aTableExt("dbf"); + + std::vector< OUString > aUsedIndexes; + + aURL.SetSmartProtocol(INetProtocol::File); + const Sequence<OUString> aFolderUrls = ::utl::LocalFileHelper::GetFolderContents(m_aDSN, bFolder); + for(const OUString& rURL : aFolderUrls) + { + OUString aName; + osl::FileBase::getSystemPathFromFileURL(rURL,aName); + aURL.SetSmartURL(aName); + OUString aExt = aURL.getExtension(); + if (aExt == aIndexExt) + { + m_aFreeIndexList.emplace_back(aURL.getName() ); + } + else if (aExt == aTableExt) + { + m_aTableInfoList.emplace_back(aURL.getName() ); + OTableInfo& rTabInfo = m_aTableInfoList.back(); + + // open the INF file + aURL.setExtension(u"inf"); + OFileNotation aTransformer(aURL.GetURLNoPass(), OFileNotation::N_URL); + Config aInfFile( aTransformer.get(OFileNotation::N_SYSTEM) ); + aInfFile.SetGroup( aGroupIdent ); + + // fill the indexes list + OString aNDX; + sal_uInt16 nKeyCnt = aInfFile.GetKeyCount(); + OString aKeyName; + OUString aEntry; + + for( sal_uInt16 nKey = 0; nKey < nKeyCnt; nKey++ ) + { + // does the key point to an index file ? + aKeyName = aInfFile.GetKeyName( nKey ); + aNDX = aKeyName.copy(0,3); + + // yes -> add to the tables index list + if (aNDX == "NDX") + { + aEntry = OStringToOUString(aInfFile.ReadKey(aKeyName), osl_getThreadTextEncoding()); + rTabInfo.aIndexList.emplace_back( aEntry ); + + // and remove it from the free index list + aUsedIndexes.push_back(aEntry); + // do this later below. We may not have encountered the index file, yet, thus we may not + // know the index as being free, yet + } + } + } + } + + for (auto const& usedIndex : aUsedIndexes) + RemoveFreeIndex( usedIndex, false ); + + if (!m_aTableInfoList.empty()) + { + m_xPB_OK->set_sensitive(true); + m_xIndexes->set_sensitive(true); + } + + checkButtons(); +} + +void ODbaseIndexDialog::SetCtrls() +{ + // ComboBox tables + for (auto const& tableInfo : m_aTableInfoList) + m_xCB_Tables->append_text(tableInfo.aTableName); + + // put the first dataset into Edit + if (!m_aTableInfoList.empty()) + { + const OTableInfo& rTabInfo = m_aTableInfoList.front(); + m_xCB_Tables->set_entry_text(rTabInfo.aTableName); + + // build ListBox of the table indices + for (auto const& index : rTabInfo.aIndexList) + m_xLB_TableIndexes->append_text(index.GetIndexFileName()); + + if (!rTabInfo.aIndexList.empty()) + m_xLB_TableIndexes->select(0); + } + + // ListBox of the free indices + for (auto const& freeIndex : m_aFreeIndexList) + m_xLB_FreeIndexes->append_text(freeIndex.GetIndexFileName()); + + if (!m_aFreeIndexList.empty()) + m_xLB_FreeIndexes->select(0); + + TableSelectHdl(*m_xCB_Tables); + checkButtons(); +} + +void OTableInfo::WriteInfFile( const OUString& rDSN ) const +{ + // open INF file + INetURLObject aURL; + aURL.SetSmartProtocol(INetProtocol::File); + OUString aDsn = rDSN; + { + SvtPathOptions aPathOptions; + aDsn = aPathOptions.SubstituteVariable(aDsn); + } + aURL.SetSmartURL(aDsn); + aURL.Append(aTableName); + aURL.setExtension(u"inf"); + + OFileNotation aTransformer(aURL.GetURLNoPass(), OFileNotation::N_URL); + Config aInfFile( aTransformer.get(OFileNotation::N_SYSTEM) ); + aInfFile.SetGroup( aGroupIdent ); + + // first, delete all table indices + OString aNDX; + sal_uInt16 nKeyCnt = aInfFile.GetKeyCount(); + sal_uInt16 nKey = 0; + + while( nKey < nKeyCnt ) + { + // Does the key point to an index file?... + OString aKeyName = aInfFile.GetKeyName( nKey ); + aNDX = aKeyName.copy(0,3); + + //...if yes, delete index file, nKey is at subsequent key + if (aNDX == "NDX") + { + aInfFile.DeleteKey(aKeyName); + nKeyCnt--; + } + else + nKey++; + + } + + // now add all saved indices + sal_uInt16 nPos = 0; + for (auto const& index : aIndexList) + { + OStringBuffer aKeyName("NDX"); + if( nPos > 0 ) // first index contains no number + aKeyName.append(static_cast<sal_Int32>(nPos)); + aInfFile.WriteKey( + aKeyName.makeStringAndClear(), + OUStringToOString(index.GetIndexFileName(), + osl_getThreadTextEncoding())); + ++nPos; + } + + aInfFile.Flush(); + + // if only [dbase] is left in INF-file, delete file + if(nPos) + return; + + try + { + ::ucbhelper::Content aContent(aURL.GetURLNoPass(),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext()); + aContent.executeCommand( "delete", Any( true ) ); + } + catch (const Exception& ) + { + // simply silent this. The strange algorithm here does a lot of + // things even if no files at all were created or accessed, so it's + // possible that the file we're trying to delete does not even + // exist, and this is a valid condition. + } +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dbfindex.hxx b/dbaccess/source/ui/dlg/dbfindex.hxx new file mode 100644 index 000000000..53b75640e --- /dev/null +++ b/dbaccess/source/ui/dlg/dbfindex.hxx @@ -0,0 +1,110 @@ +/* -*- 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 <vcl/weld.hxx> +#include <deque> + +namespace dbaui +{ + +// OTableIndex +/// represents a single dbf index +class OTableIndex +{ +private: + OUString aIndexFileName; + +public: + OTableIndex() { } + explicit OTableIndex( const OUString& rFileName ) : aIndexFileName( rFileName ) { } + + const OUString& GetIndexFileName() const { return aIndexFileName; } +}; + +typedef std::deque< OTableIndex > TableIndexList; + +// OTableInfo +class ODbaseIndexDialog; +/** holds the INF file of a table +*/ +class OTableInfo +{ + friend class ODbaseIndexDialog; +private: + OUString aTableName; + TableIndexList aIndexList; + +public: + explicit OTableInfo( const OUString& rName ) : aTableName(rName) { } + + void WriteInfFile( const OUString& rDSN ) const; +}; + +typedef std::deque< OTableInfo > TableInfoList; + +// IndexDialog +class ODbaseIndexDialog : public weld::GenericDialogController +{ +protected: + OUString m_aDSN; + TableInfoList m_aTableInfoList; + TableIndexList m_aFreeIndexList; + + std::unique_ptr<weld::Button> m_xPB_OK; + std::unique_ptr<weld::ComboBox> m_xCB_Tables; + std::unique_ptr<weld::Widget> m_xIndexes; + std::unique_ptr<weld::TreeView> m_xLB_TableIndexes; + std::unique_ptr<weld::TreeView> m_xLB_FreeIndexes; + + std::unique_ptr<weld::Button> m_xAdd; + std::unique_ptr<weld::Button> m_xRemove; + std::unique_ptr<weld::Button> m_xAddAll; + std::unique_ptr<weld::Button> m_xRemoveAll; + + DECL_LINK( TableSelectHdl, weld::ComboBox&, void ); + DECL_LINK( AddClickHdl, weld::Button&, void ); + DECL_LINK( RemoveClickHdl, weld::Button&, void ); + DECL_LINK( AddAllClickHdl, weld::Button&, void ); + DECL_LINK( RemoveAllClickHdl, weld::Button&, void ); + DECL_LINK( OKClickHdl, weld::Button&, void ); + DECL_LINK( OnListEntrySelected, weld::TreeView&, void ); + + void Init(); + void SetCtrls(); + + static OTableIndex implRemoveIndex(const OUString& _rName, TableIndexList& _rList, weld::TreeView& _rDisplay, bool _bMustExist); + static void implInsertIndex(const OTableIndex& _rIndex, TableIndexList& _rList, weld::TreeView& _rDisplay); + + OTableIndex RemoveFreeIndex( const OUString& _rName, bool _bMustExist ) { return implRemoveIndex(_rName, m_aFreeIndexList, *m_xLB_FreeIndexes, _bMustExist); } + void InsertFreeIndex( const OTableIndex& _rIndex ) { implInsertIndex(_rIndex, m_aFreeIndexList, *m_xLB_FreeIndexes); } + OTableIndex RemoveTableIndex( std::u16string_view _rTableName, const OUString& _rIndexName ); + void InsertTableIndex( std::u16string_view _rTableName, const OTableIndex& _rIndex ); + + void checkButtons(); + +public: + ODbaseIndexDialog(weld::Window * pParent, const OUString& rDataSrcName); + virtual ~ODbaseIndexDialog() override; +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dbwiz.cxx b/dbaccess/source/ui/dlg/dbwiz.cxx new file mode 100644 index 000000000..fa0653502 --- /dev/null +++ b/dbaccess/source/ui/dlg/dbwiz.cxx @@ -0,0 +1,336 @@ +/* -*- 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 <core_resource.hxx> +#include <dbwiz.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <dsitems.hxx> +#include "dsnItem.hxx" +#include "adminpages.hxx" +#include "generalpage.hxx" +#include <unotools/confignode.hxx> +#include "ConnectionPage.hxx" +#include "DriverSettings.hxx" +#include "DbAdminImpl.hxx" +#include <helpids.h> + +namespace dbaui +{ +using namespace com::sun::star::uno; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::lang; +using namespace com::sun::star::util; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; + +#define START_PAGE 0 +#define CONNECTION_PAGE 1 +#define ADDITIONAL_PAGE_DBASE 2 +#define ADDITIONAL_PAGE_FLAT 3 +#define ADDITIONAL_PAGE_LDAP 4 +//5 was ADDITIONAL_PAGE_ADABAS +#define ADDITIONAL_PAGE_MYSQL_JDBC 6 +#define ADDITIONAL_PAGE_MYSQL_ODBC 7 +#define ADDITIONAL_PAGE_ORACLE_JDBC 8 +#define ADDITIONAL_PAGE_ADO 9 +#define ADDITIONAL_PAGE_ODBC 10 +#define ADDITIONAL_USERDEFINED 11 +#define ADDITIONAL_PAGE_MYSQL_NATIVE 12 + +// ODbTypeWizDialog +ODbTypeWizDialog::ODbTypeWizDialog(weld::Window* _pParent, SfxItemSet const * _pItems, + const Reference< XComponentContext >& _rxORB, const css::uno::Any& _aDataSourceName) + : WizardMachine(_pParent, WizardButtonFlags::NEXT | WizardButtonFlags::PREVIOUS | WizardButtonFlags::FINISH | WizardButtonFlags::CANCEL | WizardButtonFlags::HELP ) +{ + m_pImpl.reset(new ODbDataSourceAdministrationHelper(_rxORB, m_xAssistant.get(), _pParent, this)); + m_pImpl->setDataSourceOrName(_aDataSourceName); + Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource(); + m_pOutSet.reset(new SfxItemSet( *_pItems->GetPool(), _pItems->GetRanges() )); + + m_pImpl->translateProperties(xDatasource, *m_pOutSet); + m_eType = dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(*m_pOutSet); + + defaultButton(WizardButtonFlags::NEXT); + enableButtons(WizardButtonFlags::FINISH, false); + enableAutomaticNextButtonState(); + + m_xPrevPage->set_help_id(HID_DBWIZ_PREVIOUS); + m_xNextPage->set_help_id(HID_DBWIZ_NEXT); + m_xCancel->set_help_id(HID_DBWIZ_CANCEL); + m_xFinish->set_help_id(HID_DBWIZ_FINISH); + // no local resources needed anymore + + const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>(_pItems->GetItem(DSID_TYPECOLLECTION)); + assert(pCollectionItem && "must exist"); + m_pCollection = pCollectionItem->getCollection(); + + ActivatePage(); + setTitleBase(DBA_RES(STR_DATABASE_TYPE_CHANGE)); + + m_xAssistant->set_current_page(0); +} + +ODbTypeWizDialog::~ODbTypeWizDialog() +{ +} + +IMPL_LINK(ODbTypeWizDialog, OnTypeSelected, OGeneralPage&, _rTabPage, void) +{ + m_eType = _rTabPage.GetSelectedType(); + const bool bURLRequired = m_pCollection->isConnectionUrlRequired(m_eType); + enableButtons(WizardButtonFlags::NEXT,bURLRequired); + enableButtons(WizardButtonFlags::FINISH,!bURLRequired); +} + +WizardState ODbTypeWizDialog::determineNextState( WizardState _nCurrentState ) const +{ + WizardState nNextState = WZS_INVALID_STATE; + switch(_nCurrentState) + { + case START_PAGE: + switch(m_pCollection->determineType(m_eType)) + { + case ::dbaccess::DST_MOZILLA: + case ::dbaccess::DST_OUTLOOK: + case ::dbaccess::DST_OUTLOOKEXP: + case ::dbaccess::DST_EVOLUTION: + case ::dbaccess::DST_EVOLUTION_GROUPWISE: + case ::dbaccess::DST_EVOLUTION_LDAP: + case ::dbaccess::DST_KAB: + case ::dbaccess::DST_MACAB: + nNextState = WZS_INVALID_STATE; + break; + case ::dbaccess::DST_MYSQL_NATIVE: + nNextState = ADDITIONAL_PAGE_MYSQL_NATIVE; + break; + default: + nNextState = CONNECTION_PAGE; + break; + } + break; + case CONNECTION_PAGE: + switch(m_pCollection->determineType(m_eType)) + { + case ::dbaccess::DST_MOZILLA: + case ::dbaccess::DST_THUNDERBIRD: + case ::dbaccess::DST_OUTLOOK: + case ::dbaccess::DST_OUTLOOKEXP: + case ::dbaccess::DST_EVOLUTION: + case ::dbaccess::DST_EVOLUTION_GROUPWISE: + case ::dbaccess::DST_EVOLUTION_LDAP: + case ::dbaccess::DST_KAB: + case ::dbaccess::DST_MACAB: + case ::dbaccess::DST_MSACCESS: + case ::dbaccess::DST_MSACCESS_2007: + case ::dbaccess::DST_JDBC: + case ::dbaccess::DST_CALC: + case ::dbaccess::DST_WRITER: + nNextState = WZS_INVALID_STATE; + break; + case ::dbaccess::DST_DBASE: + nNextState = ADDITIONAL_PAGE_DBASE; + break; + case ::dbaccess::DST_FLAT: + nNextState = ADDITIONAL_PAGE_FLAT; + break; + case ::dbaccess::DST_LDAP: + nNextState = ADDITIONAL_PAGE_LDAP; + break; + case ::dbaccess::DST_MYSQL_JDBC: + nNextState = ADDITIONAL_PAGE_MYSQL_JDBC; + break; + case ::dbaccess::DST_MYSQL_ODBC: + nNextState = ADDITIONAL_PAGE_MYSQL_ODBC; + break; + case ::dbaccess::DST_ORACLE_JDBC: + nNextState = ADDITIONAL_PAGE_ORACLE_JDBC; + break; + case ::dbaccess::DST_ADO: + nNextState = ADDITIONAL_PAGE_ADO; + break; + case ::dbaccess::DST_ODBC: + nNextState = ADDITIONAL_PAGE_ODBC; + break; + default: + nNextState = WZS_INVALID_STATE; + break; + } + break; + } + + return nNextState; +} + +const SfxItemSet* ODbTypeWizDialog::getOutputSet() const +{ + return m_pOutSet.get(); +} + +SfxItemSet* ODbTypeWizDialog::getWriteOutputSet() +{ + return m_pOutSet.get(); +} + +std::pair< Reference<XConnection>,bool> ODbTypeWizDialog::createConnection() +{ + return m_pImpl->createConnection(); +} + +Reference< XComponentContext > ODbTypeWizDialog::getORB() const +{ + return m_pImpl->getORB(); +} + +Reference< XDriver > ODbTypeWizDialog::getDriver() +{ + return m_pImpl->getDriver(); +} + +OUString ODbTypeWizDialog::getDatasourceType(const SfxItemSet& _rSet) const +{ + return dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(_rSet); +} + +void ODbTypeWizDialog::clearPassword() +{ + m_pImpl->clearPassword(); +} + +std::unique_ptr<BuilderPage> ODbTypeWizDialog::createPage(WizardState _nState) +{ + TranslateId pStringId = STR_PAGETITLE_ADVANCED; + std::unique_ptr<BuilderPage> xPage; + + OString sIdent(OString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + switch(_nState) + { + case START_PAGE: // start state + { + xPage = std::make_unique<OGeneralPageDialog>(pPageContainer, this, *m_pOutSet); + OGeneralPage* pGeneralPage = static_cast<OGeneralPage*>(xPage.get()); + pGeneralPage->SetTypeSelectHandler( LINK( this, ODbTypeWizDialog, OnTypeSelected)); + pStringId = STR_PAGETITLE_GENERAL; + } + break; + case CONNECTION_PAGE: + xPage = OConnectionTabPage::Create(pPageContainer, this, m_pOutSet.get()); + pStringId = STR_PAGETITLE_CONNECTION; + break; + + case ADDITIONAL_PAGE_DBASE: + xPage = ODriversSettings::CreateDbase(pPageContainer, this, m_pOutSet.get()); + break; + case ADDITIONAL_PAGE_FLAT: + xPage = ODriversSettings::CreateText(pPageContainer, this, m_pOutSet.get()); + break; + case ADDITIONAL_PAGE_LDAP: + xPage = ODriversSettings::CreateLDAP(pPageContainer, this, m_pOutSet.get()); + break; + case ADDITIONAL_PAGE_MYSQL_JDBC: + xPage = ODriversSettings::CreateMySQLJDBC(pPageContainer, this, m_pOutSet.get()); + break; + case ADDITIONAL_PAGE_MYSQL_NATIVE: + xPage = ODriversSettings::CreateMySQLNATIVE(pPageContainer, this, m_pOutSet.get()); + break; + case ADDITIONAL_PAGE_MYSQL_ODBC: + xPage = ODriversSettings::CreateMySQLODBC(pPageContainer, this, m_pOutSet.get()); + break; + case ADDITIONAL_PAGE_ORACLE_JDBC: + xPage = ODriversSettings::CreateOracleJDBC(pPageContainer, this, m_pOutSet.get()); + break; + case ADDITIONAL_PAGE_ADO: + xPage = ODriversSettings::CreateAdo(pPageContainer, this, m_pOutSet.get()); + break; + case ADDITIONAL_PAGE_ODBC: + xPage = ODriversSettings::CreateODBC(pPageContainer, this, m_pOutSet.get()); + break; + case ADDITIONAL_USERDEFINED: + xPage = ODriversSettings::CreateUser(pPageContainer, this, m_pOutSet.get()); + break; + default: + OSL_FAIL("Wrong state!"); + break; + } + + // register ourself as modified listener + if ( xPage ) + { + static_cast<OGenericAdministrationPage*>(xPage.get())->SetServiceFactory( m_pImpl->getORB() ); + static_cast<OGenericAdministrationPage*>(xPage.get())->SetAdminDialog(this,this); + m_xAssistant->set_page_title(sIdent, DBA_RES(pStringId)); + defaultButton( _nState == START_PAGE ? WizardButtonFlags::NEXT : WizardButtonFlags::FINISH ); + enableButtons( WizardButtonFlags::FINISH, _nState != START_PAGE); + } + return xPage; +} + +bool ODbTypeWizDialog::leaveState(WizardState _nState) +{ + SfxTabPage* pPage = static_cast<SfxTabPage*>(WizardMachine::GetPage(_nState)); + if ( pPage ) + pPage->FillItemSet(m_pOutSet.get()); + return true; +} + +void ODbTypeWizDialog::setTitle(const OUString& _sTitle) +{ + m_xAssistant->set_title(_sTitle); +} + +void ODbTypeWizDialog::enableConfirmSettings( bool _bEnable ) +{ + enableButtons( WizardButtonFlags::FINISH, _bEnable ); + // TODO: + // this is hacky. At the moment, this method is used in only one case. + // As soon as it is to be used more wide-spread, we should find a proper concept + // for enabling both the Next and Finish buttons, depending on the current page state. + // Plus, the concept must also care for the case where those pages are embedded into + // a normal tab dialog. +} + +void ODbTypeWizDialog::saveDatasource() +{ + SfxTabPage* pPage = static_cast<SfxTabPage*>(WizardMachine::GetPage(getCurrentState())); + if ( pPage ) + pPage->FillItemSet(m_pOutSet.get()); + + OUString sOldURL; + if ( m_pImpl->getCurrentDataSource().is() ) + m_pImpl->getCurrentDataSource()->getPropertyValue(PROPERTY_URL) >>= sOldURL; + DataSourceInfoConverter::convert( getORB(), m_pCollection,sOldURL,m_eType,m_pImpl->getCurrentDataSource()); +} + +vcl::IWizardPageController* ODbTypeWizDialog::getPageController(BuilderPage* pCurrentPage) const +{ + OGenericAdministrationPage* pPage = static_cast<OGenericAdministrationPage*>(pCurrentPage); + return pPage; +} + +bool ODbTypeWizDialog::onFinish() +{ + saveDatasource(); + return m_pImpl->saveChanges(*m_pOutSet) && WizardMachine::onFinish(); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dbwizsetup.cxx b/dbaccess/source/ui/dlg/dbwizsetup.cxx new file mode 100644 index 000000000..f687740dd --- /dev/null +++ b/dbaccess/source/ui/dlg/dbwizsetup.cxx @@ -0,0 +1,994 @@ +/* -*- 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 <core_resource.hxx> +#include <dbwizsetup.hxx> +#include <dsmeta.hxx> +#include "DBSetupConnectionPages.hxx" +#include <strings.hrc> +#include <strings.hxx> +#include <dsitems.hxx> +#include "dsnItem.hxx" + +#include <unotools/pathoptions.hxx> +#include <svl/stritem.hxx> +#include "adminpages.hxx" +#include <sfx2/docfilt.hxx> +#include <unotools/ucbhelper.hxx> +#include "generalpage.hxx" +#include <unotools/confignode.hxx> +#include "DbAdminImpl.hxx" +#include <helpids.h> +#include "ConnectionPageSetup.hxx" +#include <UITools.hxx> +#include <dbaccess/AsynchronousLink.hxx> +#include <sfx2/filedlghelper.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/frame/TerminationVetoException.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/ucb/SimpleFileAccess.hpp> +#include <com/sun/star/ucb/InteractiveIOException.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <com/sun/star/document/MacroExecMode.hpp> +#include <com/sun/star/ucb/IOErrorCode.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/task/XInteractionHandler2.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> + +#include <comphelper/interaction.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <connectivity/DriversConfig.hxx> + +namespace dbaui +{ +using namespace dbtools; +using namespace vcl; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::sdbcx; +using namespace com::sun::star::task; +using namespace com::sun::star::lang; +using namespace com::sun::star::io; +using namespace com::sun::star::util; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; +using namespace com::sun::star::frame; +using namespace com::sun::star::ucb; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::document; +using namespace ::comphelper; +using namespace ::cppu; + +using vcl::RoadmapWizardTypes::WizardPath; + +// ODbTypeWizDialogSetup +ODbTypeWizDialogSetup::ODbTypeWizDialogSetup(weld::Window* _pParent + ,SfxItemSet const * _pItems + ,const Reference< XComponentContext >& _rxORB + ,const css::uno::Any& _aDataSourceName + ) + : vcl::RoadmapWizardMachine( _pParent ) + + , m_bIsConnectable( false) + , m_sRM_IntroText( DBA_RES( STR_PAGETITLE_INTROPAGE ) ) + , m_sRM_dBaseText( DBA_RES( STR_PAGETITLE_DBASE ) ) + , m_sRM_TextText( DBA_RES( STR_PAGETITLE_TEXT ) ) + , m_sRM_MSAccessText( DBA_RES( STR_PAGETITLE_MSACCESS ) ) + , m_sRM_LDAPText( DBA_RES( STR_PAGETITLE_LDAP ) ) + , m_sRM_ADOText( DBA_RES( STR_PAGETITLE_ADO ) ) + , m_sRM_JDBCText( DBA_RES( STR_PAGETITLE_JDBC ) ) + , m_sRM_MySQLNativePageTitle( DBA_RES( STR_PAGETITLE_MYSQL_NATIVE ) ) + , m_sRM_OracleText( DBA_RES( STR_PAGETITLE_ORACLE ) ) + , m_sRM_MySQLText( DBA_RES( STR_PAGETITLE_MYSQL ) ) + , m_sRM_ODBCText( DBA_RES( STR_PAGETITLE_ODBC ) ) + , m_sRM_DocumentOrSpreadSheetText( DBA_RES( STR_PAGETITLE_DOCUMENT_OR_SPREADSHEET ) ) + , m_sRM_AuthentificationText( DBA_RES( STR_PAGETITLE_AUTHENTIFICATION ) ) + , m_sRM_FinalText( DBA_RES( STR_PAGETITLE_FINAL ) ) + , m_sWorkPath( SvtPathOptions().GetWorkPath() ) + , m_pGeneralPage( nullptr ) + , m_pMySQLIntroPage( nullptr ) + , m_pFinalPage( nullptr ) +{ + // no local resources needed anymore + // extract the datasource type collection from the item set + const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>(_pItems->GetItem(DSID_TYPECOLLECTION)); + assert(pCollectionItem && "must exist"); + m_pCollection = pCollectionItem->getCollection(); + + assert(m_pCollection && "ODbTypeWizDialogSetup::ODbTypeWizDialogSetup : really need a DSN type collection !"); + + m_pImpl.reset(new ODbDataSourceAdministrationHelper(_rxORB, m_xAssistant.get(), _pParent, this)); + m_pImpl->setDataSourceOrName(_aDataSourceName); + Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource(); + m_pOutSet.reset( new SfxItemSet( *_pItems->GetPool(), _pItems->GetRanges() ) ); + + m_pImpl->translateProperties(xDatasource, *m_pOutSet); + + defaultButton(WizardButtonFlags::NEXT); + enableButtons(WizardButtonFlags::FINISH, true); + enableAutomaticNextButtonState(); + + ::dbaccess::ODsnTypeCollection::TypeIterator aIter = m_pCollection->begin(); + ::dbaccess::ODsnTypeCollection::TypeIterator aEnd = m_pCollection->end(); + for(PathId i = 1;aIter != aEnd;++aIter,++i) + { + const OUString& sURLPrefix = aIter.getURLPrefix(); + WizardPath aPath; + aPath.push_back(PAGE_DBSETUPWIZARD_INTRO); + m_pCollection->fillPageIds(sURLPrefix,aPath); + aPath.push_back(PAGE_DBSETUPWIZARD_AUTHENTIFICATION); + aPath.push_back(PAGE_DBSETUPWIZARD_FINAL); + + declareAuthDepPath(sURLPrefix,i,aPath); + } + + WizardPath aPath; + aPath.push_back(PAGE_DBSETUPWIZARD_INTRO); + declarePath( static_cast<PathId>(m_pCollection->size()+1), aPath); + + m_xPrevPage->set_help_id(HID_DBWIZ_PREVIOUS); + m_xNextPage->set_help_id(HID_DBWIZ_NEXT); + m_xCancel->set_help_id(HID_DBWIZ_CANCEL); + m_xFinish->set_help_id(HID_DBWIZ_FINISH); + ActivatePage(); + setTitleBase(DBA_RES(STR_DBWIZARDTITLE)); + m_xAssistant->set_current_page(0); +} + +void ODbTypeWizDialogSetup::declareAuthDepPath( const OUString& _sURL, PathId _nPathId, const WizardPath& _rPaths) +{ + bool bHasAuthentication = DataSourceMetaData::getAuthentication( _sURL ) != AuthNone; + + // collect the elements of the path + WizardPath aPath; + + for (auto const& path : _rPaths) + { + if ( bHasAuthentication || ( path != PAGE_DBSETUPWIZARD_AUTHENTIFICATION ) ) + aPath.push_back(path); + } + + // call base method + ::vcl::RoadmapWizardMachine::declarePath( _nPathId, aPath ); +} + +OUString ODbTypeWizDialogSetup::getStateDisplayName(WizardState _nState) const +{ + OUString sRoadmapItem; + switch( _nState ) + { + case PAGE_DBSETUPWIZARD_INTRO: + sRoadmapItem = m_sRM_IntroText; + break; + + case PAGE_DBSETUPWIZARD_DBASE: + sRoadmapItem = m_sRM_dBaseText; + break; + case PAGE_DBSETUPWIZARD_ADO: + sRoadmapItem = m_sRM_ADOText; + break; + case PAGE_DBSETUPWIZARD_TEXT: + sRoadmapItem = m_sRM_TextText; + break; + case PAGE_DBSETUPWIZARD_MSACCESS: + sRoadmapItem = m_sRM_MSAccessText; + break; + case PAGE_DBSETUPWIZARD_LDAP: + sRoadmapItem = m_sRM_LDAPText; + break; + case PAGE_DBSETUPWIZARD_JDBC: + sRoadmapItem = m_sRM_JDBCText; + break; + case PAGE_DBSETUPWIZARD_ORACLE: + sRoadmapItem = m_sRM_OracleText; + break; + case PAGE_DBSETUPWIZARD_MYSQL_INTRO: + sRoadmapItem = m_sRM_MySQLText; + break; + case PAGE_DBSETUPWIZARD_MYSQL_JDBC: + sRoadmapItem = m_sRM_JDBCText; + break; + case PAGE_DBSETUPWIZARD_MYSQL_NATIVE: + sRoadmapItem = m_sRM_MySQLNativePageTitle; + break; + case PAGE_DBSETUPWIZARD_MYSQL_ODBC: + sRoadmapItem = m_sRM_ODBCText; + break; + case PAGE_DBSETUPWIZARD_ODBC: + sRoadmapItem = m_sRM_ODBCText; + break; + case PAGE_DBSETUPWIZARD_DOCUMENT_OR_SPREADSHEET: + sRoadmapItem = m_sRM_DocumentOrSpreadSheetText; + break; + case PAGE_DBSETUPWIZARD_AUTHENTIFICATION: + sRoadmapItem = m_sRM_AuthentificationText; + break; + case PAGE_DBSETUPWIZARD_USERDEFINED: + sRoadmapItem = DBA_RES(STR_PAGETITLE_CONNECTION); + break; + case PAGE_DBSETUPWIZARD_FINAL: + sRoadmapItem = m_sRM_FinalText; + break; + default: + break; + } + return sRoadmapItem; +} + +ODbTypeWizDialogSetup::~ODbTypeWizDialogSetup() +{ +} + +IMPL_LINK_NOARG(ODbTypeWizDialogSetup, OnTypeSelected, OGeneralPage&, void) +{ + activateDatabasePath(); +} + +static void lcl_removeUnused(const ::comphelper::NamedValueCollection& _aOld,const ::comphelper::NamedValueCollection& _aNew,::comphelper::NamedValueCollection& _rDSInfo) +{ + _rDSInfo.merge(_aNew,true); + uno::Sequence< beans::NamedValue > aOldValues = _aOld.getNamedValues(); + const beans::NamedValue* pIter = aOldValues.getConstArray(); + const beans::NamedValue* pEnd = pIter + aOldValues.getLength(); + for(;pIter != pEnd;++pIter) + { + if ( !_aNew.has(pIter->Name) ) + { + _rDSInfo.remove(pIter->Name); + } + } +} + +void DataSourceInfoConverter::convert(const Reference<XComponentContext> & xContext, const ::dbaccess::ODsnTypeCollection* _pCollection,const OUString& _sOldURLPrefix,const OUString& _sNewURLPrefix,const css::uno::Reference< css::beans::XPropertySet >& _xDatasource) +{ + if ( _pCollection->getPrefix(_sOldURLPrefix) == _pCollection->getPrefix(_sNewURLPrefix) ) + return ; + uno::Sequence< beans::PropertyValue> aInfo; + _xDatasource->getPropertyValue(PROPERTY_INFO) >>= aInfo; + ::comphelper::NamedValueCollection aDS(aInfo); + + ::connectivity::DriversConfig aDriverConfig(xContext); + + const ::comphelper::NamedValueCollection& aOldProperties = aDriverConfig.getProperties(_sOldURLPrefix); + const ::comphelper::NamedValueCollection& aNewProperties = aDriverConfig.getProperties(_sNewURLPrefix); + lcl_removeUnused(aOldProperties,aNewProperties,aDS); + + aDS >>= aInfo; + _xDatasource->setPropertyValue(PROPERTY_INFO,uno::Any(aInfo)); +} + +void ODbTypeWizDialogSetup::activateDatabasePath() +{ + switch ( m_pGeneralPage->GetDatabaseCreationMode() ) + { + case OGeneralPageWizard::eCreateNew: + { + sal_Int32 nCreateNewDBIndex = m_pCollection->getIndexOf( m_pGeneralPage->GetSelectedType() ); + if ( nCreateNewDBIndex == -1 ) + nCreateNewDBIndex = m_pCollection->getIndexOf( u"sdbc:dbase:" ); + OSL_ENSURE( nCreateNewDBIndex != -1, "ODbTypeWizDialogSetup::activateDatabasePath: the GeneralPage should have prevented this!" ); + activatePath( static_cast< PathId >( nCreateNewDBIndex + 1 ), true ); + + enableState(PAGE_DBSETUPWIZARD_FINAL ); + enableButtons( WizardButtonFlags::FINISH, true); + } + break; + case OGeneralPageWizard::eConnectExternal: + { + OUString sOld = m_sURL; + m_sURL = m_pGeneralPage->GetSelectedType(); + DataSourceInfoConverter::convert(getORB(), m_pCollection,sOld,m_sURL,m_pImpl->getCurrentDataSource()); + ::dbaccess::DATASOURCE_TYPE eType = VerifyDataSourceType(m_pCollection->determineType(m_sURL)); + if (eType == ::dbaccess::DST_UNKNOWN) + m_pCollection->determineType(m_sOldURL); + + activatePath( static_cast<PathId>(m_pCollection->getIndexOf(m_sURL) + 1), true); + updateTypeDependentStates(); + } + break; + case OGeneralPageWizard::eOpenExisting: + { + activatePath( static_cast<PathId>(m_pCollection->size() + 1), true ); + enableButtons( WizardButtonFlags::FINISH, !m_pGeneralPage->GetSelectedDocumentURL().isEmpty() ); + } + break; + default: + OSL_FAIL( "ODbTypeWizDialogSetup::activateDatabasePath: unknown creation mode!" ); + } + + enableButtons( WizardButtonFlags::NEXT, m_pGeneralPage->GetDatabaseCreationMode() != OGeneralPageWizard::eOpenExisting ); + // TODO: this should go into the base class. Point is, we activate a path whose *last* + // step is also the current one. The base class should automatically disable + // the Next button in such a case. However, not for this patch ... +} + +void ODbTypeWizDialogSetup::updateTypeDependentStates() +{ + bool bDoEnable = false; + bool bIsConnectionRequired = m_pCollection->isConnectionUrlRequired(m_sURL); + if (!bIsConnectionRequired) + { + bDoEnable = true; + } + else if ( m_sURL == m_sOldURL ) + { + bDoEnable = m_bIsConnectable; + } + enableState(PAGE_DBSETUPWIZARD_AUTHENTIFICATION, bDoEnable); + enableState(PAGE_DBSETUPWIZARD_FINAL, bDoEnable ); + enableButtons( WizardButtonFlags::FINISH, bDoEnable); +} + +void ODbTypeWizDialogSetup::resetPages(const Reference< XPropertySet >& _rxDatasource) +{ + // remove all items which relate to indirect properties from the input set + // (without this, the following may happen: select an arbitrary data source where some indirect properties + // are set. Select another data source of the same type, where the indirect props are not set (yet). Then, + // the indirect property values of the first ds are shown in the second ds ...) + const ODbDataSourceAdministrationHelper::MapInt2String& rMap = m_pImpl->getIndirectProperties(); + for (auto const& elem : rMap) + getWriteOutputSet()->ClearItem( static_cast<sal_uInt16>(elem.first) ); + + // extract all relevant data from the property set of the data source + m_pImpl->translateProperties(_rxDatasource, *getWriteOutputSet()); +} + +const SfxItemSet* ODbTypeWizDialogSetup::getOutputSet() const +{ + return m_pOutSet.get(); +} + +SfxItemSet* ODbTypeWizDialogSetup::getWriteOutputSet() +{ + return m_pOutSet.get(); +} + +std::pair< Reference<XConnection>,bool> ODbTypeWizDialogSetup::createConnection() +{ + return m_pImpl->createConnection(); +} + +Reference< XComponentContext > ODbTypeWizDialogSetup::getORB() const +{ + return m_pImpl->getORB(); +} + +Reference< XDriver > ODbTypeWizDialogSetup::getDriver() +{ + return m_pImpl->getDriver(); +} + +::dbaccess::DATASOURCE_TYPE ODbTypeWizDialogSetup::VerifyDataSourceType(const ::dbaccess::DATASOURCE_TYPE DatabaseType) const +{ + ::dbaccess::DATASOURCE_TYPE LocDatabaseType = DatabaseType; + if ((LocDatabaseType == ::dbaccess::DST_MYSQL_JDBC) || (LocDatabaseType == ::dbaccess::DST_MYSQL_ODBC) || (LocDatabaseType == ::dbaccess::DST_MYSQL_NATIVE)) + { + if (m_pMySQLIntroPage != nullptr) + { + switch( m_pMySQLIntroPage->getMySQLMode() ) + { + case OMySQLIntroPageSetup::VIA_JDBC: + return ::dbaccess::DST_MYSQL_JDBC; + case OMySQLIntroPageSetup::VIA_NATIVE: + return ::dbaccess::DST_MYSQL_NATIVE; + case OMySQLIntroPageSetup::VIA_ODBC: + return ::dbaccess::DST_MYSQL_ODBC; + } + } + } + return LocDatabaseType; +} + +OUString ODbTypeWizDialogSetup::getDatasourceType(const SfxItemSet& _rSet) const +{ + OUString sRet = dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(_rSet); + if (m_pMySQLIntroPage && m_pMySQLIntroPage->IsVisible()) + { + switch( m_pMySQLIntroPage->getMySQLMode() ) + { + case OMySQLIntroPageSetup::VIA_JDBC: + sRet = "sdbc:mysql:jdbc:"; + break; + case OMySQLIntroPageSetup::VIA_NATIVE: + sRet = "sdbc:mysql:mysqlc:"; + break; + case OMySQLIntroPageSetup::VIA_ODBC: + sRet = "sdbc:mysql:odbc:"; + break; + } + } + return sRet; +} + +void ODbTypeWizDialogSetup::clearPassword() +{ + m_pImpl->clearPassword(); +} + +void ODbTypeWizDialogSetup::SetIntroPage(OMySQLIntroPageSetup* pPage) +{ + m_pMySQLIntroPage = pPage; + m_pMySQLIntroPage->SetClickHdl(LINK( this, ODbTypeWizDialogSetup, ImplClickHdl ) ); +} + +void ODbTypeWizDialogSetup::SetGeneralPage(OGeneralPageWizard* pPage) +{ + m_pGeneralPage = pPage; + m_pGeneralPage->SetTypeSelectHandler(LINK(this, ODbTypeWizDialogSetup, OnTypeSelected)); + m_pGeneralPage->SetCreationModeHandler(LINK( this, ODbTypeWizDialogSetup, OnChangeCreationMode ) ); + m_pGeneralPage->SetDocumentSelectionHandler(LINK( this, ODbTypeWizDialogSetup, OnRecentDocumentSelected ) ); + m_pGeneralPage->SetChooseDocumentHandler(LINK( this, ODbTypeWizDialogSetup, OnSingleDocumentChosen ) ); +} + +void ODbTypeWizDialogSetup::SetFinalPage(OFinalDBPageSetup* pPage) +{ + m_pFinalPage = pPage; +} + +std::unique_ptr<BuilderPage> ODbTypeWizDialogSetup::createPage(WizardState _nState) +{ + std::unique_ptr<OGenericAdministrationPage> xPage; + + OString sIdent(OString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + switch(_nState) + { + case PAGE_DBSETUPWIZARD_INTRO: + xPage = std::make_unique<OGeneralPageWizard>(pPageContainer,this,*m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_DBASE: + xPage = OConnectionTabPageSetup::CreateDbaseTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_ADO: + xPage = OConnectionTabPageSetup::CreateADOTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_TEXT: + xPage = OTextConnectionPageSetup::CreateTextTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_ODBC: + xPage = OConnectionTabPageSetup::CreateODBCTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_JDBC: + xPage = OJDBCConnectionPageSetup::CreateJDBCTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_MYSQL_ODBC: + m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, m_pCollection->getPrefix("sdbc:mysql:odbc:"))); + xPage = OConnectionTabPageSetup::CreateODBCTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_MYSQL_JDBC: + m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, m_pCollection->getPrefix("sdbc:mysql:jdbc:"))); + xPage = OGeneralSpecialJDBCConnectionPageSetup::CreateMySQLJDBCTabPage(pPageContainer, this, *m_pOutSet); + break; + case PAGE_DBSETUPWIZARD_MYSQL_NATIVE: + m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, m_pCollection->getPrefix("sdbc:mysql:mysqlc:"))); + xPage = MySQLNativeSetupPage::Create(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_ORACLE: + xPage = OGeneralSpecialJDBCConnectionPageSetup::CreateOracleJDBCTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_LDAP: + xPage = OLDAPConnectionPageSetup::CreateLDAPTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_DOCUMENT_OR_SPREADSHEET: + xPage = OSpreadSheetConnectionPageSetup::CreateDocumentOrSpreadSheetTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_MSACCESS: + xPage = OConnectionTabPageSetup::CreateMSAccessTabPage(pPageContainer, this, *m_pOutSet); + break; + case PAGE_DBSETUPWIZARD_MYSQL_INTRO: + xPage = OMySQLIntroPageSetup::CreateMySQLIntroTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_AUTHENTIFICATION: + xPage = OAuthentificationPageSetup::CreateAuthentificationTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_USERDEFINED: + xPage = OConnectionTabPageSetup::CreateUserDefinedTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_FINAL: + xPage = OFinalDBPageSetup::CreateFinalDBTabPageSetup(pPageContainer, this, *m_pOutSet); + break; + } + + if ( xPage ) + { + if ((_nState != PAGE_DBSETUPWIZARD_INTRO) && (_nState != PAGE_DBSETUPWIZARD_AUTHENTIFICATION)) + { + xPage->SetModifiedHandler(LINK( this, ODbTypeWizDialogSetup, ImplModifiedHdl ) ); + } + + xPage->SetServiceFactory( m_pImpl->getORB() ); + xPage->SetAdminDialog(this, this); + + defaultButton( _nState == PAGE_DBSETUPWIZARD_FINAL ? WizardButtonFlags::FINISH : WizardButtonFlags::NEXT ); + enableButtons( WizardButtonFlags::FINISH, _nState == PAGE_DBSETUPWIZARD_FINAL ); + enableButtons( WizardButtonFlags::NEXT, _nState != PAGE_DBSETUPWIZARD_FINAL ); + + m_xAssistant->set_page_title(sIdent, getStateDisplayName(_nState)); + } + return xPage; +} + +IMPL_LINK(ODbTypeWizDialogSetup, ImplModifiedHdl, OGenericAdministrationPage const *, _pConnectionPageSetup, void) +{ + m_bIsConnectable = _pConnectionPageSetup->GetRoadmapStateValue( ); + enableState(PAGE_DBSETUPWIZARD_FINAL, m_bIsConnectable); + enableState(PAGE_DBSETUPWIZARD_AUTHENTIFICATION, m_bIsConnectable); + if (getCurrentState() == PAGE_DBSETUPWIZARD_FINAL) + enableButtons( WizardButtonFlags::FINISH, true); + else + enableButtons( WizardButtonFlags::FINISH, m_bIsConnectable); + enableButtons( WizardButtonFlags::NEXT, m_bIsConnectable && (getCurrentState() != PAGE_DBSETUPWIZARD_FINAL)); +} + +IMPL_LINK(ODbTypeWizDialogSetup, ImplClickHdl, OMySQLIntroPageSetup*, _pMySQLIntroPageSetup, void) +{ + OUString sURLPrefix; + switch( _pMySQLIntroPageSetup->getMySQLMode() ) + { + case OMySQLIntroPageSetup::VIA_ODBC: + sURLPrefix = "sdbc:mysql:odbc:"; + break; + case OMySQLIntroPageSetup::VIA_JDBC: + sURLPrefix = "sdbc:mysql:jdbc:"; + break; + case OMySQLIntroPageSetup::VIA_NATIVE: + sURLPrefix = "sdbc:mysql:mysqlc:"; + break; + } + activatePath( static_cast<PathId>(m_pCollection->getIndexOf(sURLPrefix) + 1), true); +} + +IMPL_LINK_NOARG(ODbTypeWizDialogSetup, OnChangeCreationMode, OGeneralPageWizard&, void) +{ + activateDatabasePath(); +} + +IMPL_LINK_NOARG(ODbTypeWizDialogSetup, OnRecentDocumentSelected, OGeneralPageWizard&, void) +{ + enableButtons( WizardButtonFlags::FINISH, !m_pGeneralPage->GetSelectedDocumentURL().isEmpty() ); +} + +IMPL_LINK_NOARG(ODbTypeWizDialogSetup, OnSingleDocumentChosen, OGeneralPageWizard&, void) +{ + if (prepareLeaveCurrentState(WizardTypes::eFinish)) + onFinish(); +} + +void ODbTypeWizDialogSetup::enterState(WizardState _nState) +{ + m_sURL = dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(*m_pOutSet); + RoadmapWizardMachine::enterState(_nState); + switch(_nState) + { + case PAGE_DBSETUPWIZARD_INTRO: + m_sOldURL = m_sURL; + break; + case PAGE_DBSETUPWIZARD_FINAL: + enableButtons( WizardButtonFlags::FINISH, true); + if ( m_pFinalPage ) + m_pFinalPage->enableTableWizardCheckBox(m_pCollection->supportsTableCreation(m_sURL)); + break; + } +} + +void ODbTypeWizDialogSetup::saveDatasource() +{ + SfxTabPage* pPage = static_cast<SfxTabPage*>(GetPage(getCurrentState())); + if ( pPage ) + pPage->FillItemSet(m_pOutSet.get()); +} + +bool ODbTypeWizDialogSetup::leaveState(WizardState _nState) +{ + if (_nState == PAGE_DBSETUPWIZARD_MYSQL_INTRO) + return true; + if ( _nState == PAGE_DBSETUPWIZARD_INTRO && m_sURL != m_sOldURL ) + { + resetPages(m_pImpl->getCurrentDataSource()); + } + SfxTabPage* pPage = static_cast<SfxTabPage*>(GetPage(_nState)); + return pPage && pPage->DeactivatePage(m_pOutSet.get()) != DeactivateRC::KeepPage; +} + +void ODbTypeWizDialogSetup::setTitle(const OUString& _sTitle) +{ + m_xAssistant->set_title(_sTitle); +} + +void ODbTypeWizDialogSetup::enableConfirmSettings( bool /*_bEnable*/ ) +{ +} + +namespace +{ + bool lcl_handle( const Reference< XInteractionHandler2 >& _rxHandler, const Any& _rRequest ) + { + rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest( _rRequest ); + rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort; + pRequest->addContinuation( pAbort ); + + return _rxHandler->handleInteractionRequest( pRequest ); + } +} + +bool ODbTypeWizDialogSetup::SaveDatabaseDocument() +{ + Reference< XInteractionHandler2 > xHandler( InteractionHandler::createWithParent(getORB(), nullptr) ); + try + { + if (callSaveAsDialog()) + { + m_pImpl->saveChanges(*m_pOutSet); + Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource(); + Reference< XModel > xModel( getDataSourceOrModel( xDatasource ), UNO_QUERY_THROW ); + Reference< XStorable > xStore( xModel, UNO_QUERY_THROW ); + + if ( m_pGeneralPage->GetDatabaseCreationMode() == OGeneralPageWizard::eCreateNew ) + CreateDatabase(); + + ::comphelper::NamedValueCollection aArgs( xModel->getArgs() ); + aArgs.put( "Overwrite", true ); + aArgs.put( "InteractionHandler", xHandler ); + aArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG ); + aArgs.put( "IgnoreFirebirdMigration", true ); + + OUString sPath = ODbDataSourceAdministrationHelper::getDocumentUrl( *m_pOutSet ); + xStore->storeAsURL( sPath, aArgs.getPropertyValues() ); + + if ( !m_pFinalPage || m_pFinalPage->IsDatabaseDocumentToBeRegistered() ) + RegisterDataSourceByLocation( sPath ); + + return true; + } + } + catch ( const Exception& e ) + { + Any aError = ::cppu::getCaughtException(); + if ( xHandler.is() ) + { + if ( !lcl_handle( xHandler, aError ) ) + { + InteractiveIOException aRequest; + aRequest.Classification = InteractionClassification_ERROR; + if ( aError.isExtractableTo( ::cppu::UnoType< IOException >::get() ) ) + // assume saving the document failed + aRequest.Code = IOErrorCode_CANT_WRITE; + else + aRequest.Code = IOErrorCode_GENERAL; + aRequest.Message = e.Message; + aRequest.Context = e.Context; + lcl_handle( xHandler, Any( aRequest ) ); + } + } + } + return false; +} + + bool ODbTypeWizDialogSetup::IsDatabaseDocumentToBeOpened() const + { + if ( m_pGeneralPage->GetDatabaseCreationMode() == OGeneralPageWizard::eOpenExisting ) + return true; + + if ( m_pFinalPage != nullptr ) + return m_pFinalPage->IsDatabaseDocumentToBeOpened(); + + return true; + } + + bool ODbTypeWizDialogSetup::IsTableWizardToBeStarted() const + { + if ( m_pGeneralPage->GetDatabaseCreationMode() == OGeneralPageWizard::eOpenExisting ) + return false; + + if ( m_pFinalPage != nullptr ) + return m_pFinalPage->IsTableWizardToBeStarted(); + + return false; + } + + void ODbTypeWizDialogSetup::CreateDatabase() + { + OUString sUrl; + const OUString eType = m_pGeneralPage->GetSelectedType(); + if ( dbaccess::ODsnTypeCollection::isEmbeddedDatabase(eType) ) + { + sUrl = eType; + Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource(); + OSL_ENSURE(xDatasource.is(),"DataSource is null!"); + if ( xDatasource.is() ) + xDatasource->setPropertyValue( PROPERTY_INFO, Any( m_pCollection->getDefaultDBSettings( eType ) ) ); + m_pImpl->translateProperties(xDatasource,*m_pOutSet); + } + else if ( m_pCollection->isFileSystemBased(eType) ) + { + Reference< XSimpleFileAccess3 > xSimpleFileAccess(ucb::SimpleFileAccess::create(getORB())); + INetURLObject aDBPathURL(m_sWorkPath); + aDBPathURL.Append(m_aDocURL.getBase()); + createUniqueFolderName(&aDBPathURL); + sUrl = aDBPathURL.GetMainURL( INetURLObject::DecodeMechanism::NONE); + xSimpleFileAccess->createFolder(sUrl); + sUrl = eType + sUrl; + } + m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, sUrl)); + m_pImpl->saveChanges(*m_pOutSet); + } + + void ODbTypeWizDialogSetup::RegisterDataSourceByLocation(std::u16string_view _sPath) + { + Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource(); + Reference< XDatabaseContext > xDatabaseContext( DatabaseContext::create(getORB()) ); + INetURLObject aURL( _sPath ); + OUString sFilename = aURL.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset ); + OUString sDatabaseName = ::dbtools::createUniqueName(xDatabaseContext, sFilename, false); + xDatabaseContext->registerObject(sDatabaseName, xDatasource); + } + + bool ODbTypeWizDialogSetup::callSaveAsDialog() + { + bool bRet = false; + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION, + FileDialogFlags::NONE, m_xAssistant.get()); + aFileDlg.SetContext(sfx2::FileDialogHelper::BaseSaveAs); + std::shared_ptr<const SfxFilter> pFilter = getStandardDatabaseFilter(); + if ( pFilter ) + { + OUString sDefaultName = DBA_RES( STR_DATABASEDEFAULTNAME ); + OUString sExtension = pFilter->GetDefaultExtension(); + sDefaultName += sExtension.replaceAt( 0, 1, u"" ); + INetURLObject aWorkURL( m_sWorkPath ); + aWorkURL.Append( sDefaultName ); + sDefaultName = createUniqueFileName( aWorkURL ); + aFileDlg.SetFileName( sDefaultName ); + + aFileDlg.AddFilter(pFilter->GetUIName(),pFilter->GetDefaultExtension()); + aFileDlg.SetCurrentFilter(pFilter->GetUIName()); + } + if ( aFileDlg.Execute() == ERRCODE_NONE ) + { + m_aDocURL = INetURLObject(aFileDlg.GetPath()); + + if( m_aDocURL.GetProtocol() != INetProtocol::NotValid ) + { + OUString sFileName = m_aDocURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + if ( ::utl::UCBContentHelper::IsDocument(sFileName) ) + ::utl::UCBContentHelper::Kill(sFileName); + m_pOutSet->Put(SfxStringItem(DSID_DOCUMENT_URL, sFileName)); + bRet = true; + } + } + return bRet; + } + + void ODbTypeWizDialogSetup::createUniqueFolderName(INetURLObject* pURL) + { + Reference< XSimpleFileAccess3 > xSimpleFileAccess(ucb::SimpleFileAccess::create(getORB())); + OUString sLastSegmentName = pURL->getName(); + bool bFolderExists = true; + sal_Int32 i = 1; + while (bFolderExists) + { + bFolderExists = xSimpleFileAccess->isFolder(pURL->GetMainURL( INetURLObject::DecodeMechanism::NONE )); + if (bFolderExists) + { + i++; + pURL->setName(OUStringConcatenation(sLastSegmentName + OUString::number(i))); + } + } + } + + OUString ODbTypeWizDialogSetup::createUniqueFileName(const INetURLObject& _rURL) + { + Reference< XSimpleFileAccess3 > xSimpleFileAccess(ucb::SimpleFileAccess::create(getORB())); + OUString BaseName = _rURL.getBase(); + + bool bElementExists = true; + + INetURLObject aExistenceCheck( _rURL ); + for ( sal_Int32 i = 1; bElementExists; ) + { + bElementExists = xSimpleFileAccess->exists( aExistenceCheck.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + if ( bElementExists ) + { + aExistenceCheck.setBase( OUStringConcatenation(BaseName + OUString::number( i ) )); + ++i; + } + } + return aExistenceCheck.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset ); + } + + vcl::IWizardPageController* ODbTypeWizDialogSetup::getPageController(BuilderPage* pCurrentPage) const + { + OGenericAdministrationPage* pPage = static_cast<OGenericAdministrationPage*>(pCurrentPage); + return pPage; + } + + namespace + { + typedef ::cppu::WeakImplHelper< XTerminateListener + > AsyncLoader_Base; + class AsyncLoader : public AsyncLoader_Base + { + private: + Reference< XComponentLoader > m_xFrameLoader; + Reference< XDesktop2 > m_xDesktop; + Reference< XInteractionHandler2 > m_xInteractionHandler; + OUString m_sURL; + OAsynchronousLink m_aAsyncCaller; + + public: + AsyncLoader( const Reference< XComponentContext >& _rxORB, const OUString& _rURL ); + + void doLoadAsync(); + + // XTerminateListener + virtual void SAL_CALL queryTermination( const css::lang::EventObject& Event ) override; + virtual void SAL_CALL notifyTermination( const css::lang::EventObject& Event ) override; + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + private: + DECL_LINK( OnOpenDocument, void*, void ); + }; + + AsyncLoader::AsyncLoader( const Reference< XComponentContext >& _rxORB, const OUString& _rURL ) + :m_sURL( _rURL ) + ,m_aAsyncCaller( LINK( this, AsyncLoader, OnOpenDocument ) ) + { + try + { + m_xDesktop.set( Desktop::create(_rxORB) ); + m_xFrameLoader.set( m_xDesktop, UNO_QUERY_THROW ); + m_xInteractionHandler = InteractionHandler::createWithParent(_rxORB, nullptr); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void AsyncLoader::doLoadAsync() + { + OSL_ENSURE( !m_aAsyncCaller.IsRunning(), "AsyncLoader:doLoadAsync: already running!" ); + + acquire(); + try + { + if ( m_xDesktop.is() ) + m_xDesktop->addTerminateListener( this ); + } + catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); } + + m_aAsyncCaller.Call(); + } + + IMPL_LINK_NOARG( AsyncLoader, OnOpenDocument, void*, void ) + { + try + { + if ( m_xFrameLoader.is() ) + { + ::comphelper::NamedValueCollection aLoadArgs; + aLoadArgs.put( "InteractionHandler", m_xInteractionHandler ); + aLoadArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG ); + + Sequence< PropertyValue > aLoadArgPV; + aLoadArgs >>= aLoadArgPV; + + m_xFrameLoader->loadComponentFromURL( m_sURL, + "_default", + FrameSearchFlag::ALL, + aLoadArgPV + ); + } + } + catch( const Exception& ) + { + // do not assert. + // Such an exception happens for instance of the to-be-loaded document does not exist anymore. + } + + try + { + if ( m_xDesktop.is() ) + m_xDesktop->removeTerminateListener( this ); + } + catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); } + + release(); + } + + void SAL_CALL AsyncLoader::queryTermination( const css::lang::EventObject& /*Event*/ ) + { + throw TerminationVetoException(); + } + + void SAL_CALL AsyncLoader::notifyTermination( const css::lang::EventObject& /*Event*/ ) + { + } + void SAL_CALL AsyncLoader::disposing( const css::lang::EventObject& /*Source*/ ) + { + } + } + + bool ODbTypeWizDialogSetup::onFinish() + { + if ( m_pGeneralPage->GetDatabaseCreationMode() == OGeneralPageWizard::eOpenExisting ) + { + // we're not going to re-use the XModel we have - since the document the user + // wants us to load could be a non-database document. Instead, we asynchronously + // open the selected document. Thus, the wizard's return value is RET_CANCEL, + // which means to not continue loading the database document + if ( !WizardMachine::Finish() ) + return false; + + try + { + rtl::Reference<AsyncLoader> pAsyncLoader = new AsyncLoader( getORB(), m_pGeneralPage->GetSelectedDocumentURL() ); + pAsyncLoader->doLoadAsync(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return true; + } + + if (getCurrentState() != PAGE_DBSETUPWIZARD_FINAL) + { + skipUntil(PAGE_DBSETUPWIZARD_FINAL); + } + if (getCurrentState() == PAGE_DBSETUPWIZARD_FINAL) + return SaveDatabaseDocument() && WizardMachine::onFinish(); + else + { + enableButtons( WizardButtonFlags::FINISH, false ); + return false; + } + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/detailpages.cxx b/dbaccess/source/ui/dlg/detailpages.cxx new file mode 100644 index 000000000..8a06d7de1 --- /dev/null +++ b/dbaccess/source/ui/dlg/detailpages.cxx @@ -0,0 +1,717 @@ +/* -*- 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 <config_java.h> +#include <core_resource.hxx> +#include "detailpages.hxx" +#include <sqlmessage.hxx> +#include <dsmeta.hxx> +#include "advancedsettings.hxx" +#include "DbAdminImpl.hxx" +#include <dsitems.hxx> +#include "dbfindex.hxx" +#include "dsnItem.hxx" + +#include <IItemSetHelper.hxx> +#include <strings.hrc> + +#include <svl/itemset.hxx> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#if HAVE_FEATURE_JAVA +#include <jvmaccess/virtualmachine.hxx> +#endif +#include <connectivity/CommonTools.hxx> +#include "DriverSettings.hxx" + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::container; + using namespace ::dbtools; + + OCommonBehaviourTabPage::OCommonBehaviourTabPage(weld::Container* pPage, weld::DialogController* pController, + const OUString& rUIXMLDescription, const OString& rId, const SfxItemSet& rCoreAttrs, + OCommonBehaviourTabPageFlags nControlFlags) + : OGenericAdministrationPage(pPage, pController, rUIXMLDescription, rId, rCoreAttrs) + , m_nControlFlags(nControlFlags) + { + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseOptions) + { + m_xOptionsLabel = m_xBuilder->weld_label("optionslabel"); + m_xOptionsLabel->show(); + m_xOptions = m_xBuilder->weld_entry("options"); + m_xOptions->show(); + m_xOptions->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl)); + } + + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseCharset) + { + m_xDataConvertLabel = m_xBuilder->weld_label("charsetheader"); + m_xDataConvertLabel->show(); + m_xCharsetLabel = m_xBuilder->weld_label("charsetlabel"); + m_xCharsetLabel->show(); + m_xCharset.reset(new CharSetListBox(m_xBuilder->weld_combo_box("charset"))); + m_xCharset->show(); + m_xCharset->connect_changed(LINK(this, OCommonBehaviourTabPage, CharsetSelectHdl)); + } + } + + IMPL_LINK_NOARG(OCommonBehaviourTabPage, CharsetSelectHdl, weld::ComboBox&, void) + { + callModifiedHdl(); + } + + OCommonBehaviourTabPage::~OCommonBehaviourTabPage() + { + m_xCharset.reset(); + } + + void OCommonBehaviourTabPage::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseOptions) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xOptionsLabel.get())); + } + + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseCharset) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xCharsetLabel.get())); + } + } + + void OCommonBehaviourTabPage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseOptions) + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xOptions.get())); + + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseCharset) + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xCharset->get_widget())); + } + + void OCommonBehaviourTabPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + // collect the items + const SfxStringItem* pOptionsItem = _rSet.GetItem<SfxStringItem>(DSID_ADDITIONALOPTIONS); + const SfxStringItem* pCharsetItem = _rSet.GetItem<SfxStringItem>(DSID_CHARSET); + + // forward the values to the controls + if (bValid) + { + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseOptions) + { + m_xOptions->set_text(pOptionsItem->GetValue()); + m_xOptions->save_value(); + } + + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseCharset) + { + m_xCharset->SelectEntryByIanaName( pCharsetItem->GetValue() ); + } + } + OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue); + } + + bool OCommonBehaviourTabPage::FillItemSet(SfxItemSet* _rSet) + { + bool bChangedSomething = false; + + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseOptions) + { + fillString(*_rSet,m_xOptions.get(),DSID_ADDITIONALOPTIONS,bChangedSomething); + } + + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseCharset) + { + if ( m_xCharset->StoreSelectedCharSet( *_rSet, DSID_CHARSET ) ) + bChangedSomething = true; + } + + return bChangedSomething; + } + + // ODbaseDetailsPage + ODbaseDetailsPage::ODbaseDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs) + : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/dbasepage.ui", "DbasePage", + _rCoreAttrs, OCommonBehaviourTabPageFlags::UseCharset) + , m_xShowDeleted(m_xBuilder->weld_check_button("showDelRowsCheckbutton")) + , m_xFT_Message(m_xBuilder->weld_label("specMessageLabel")) + , m_xIndexes(m_xBuilder->weld_button("indiciesButton")) + { + m_xIndexes->connect_clicked(LINK(this, ODbaseDetailsPage, OnButtonClicked)); + m_xShowDeleted->connect_toggled(LINK(this, ODbaseDetailsPage, OnButtonToggled)); + } + + ODbaseDetailsPage::~ODbaseDetailsPage() + { + } + + std::unique_ptr<SfxTabPage> ODriversSettings::CreateDbase(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet) + { + return std::make_unique<ODbaseDetailsPage>(pPage, pController, *_rAttrSet); + } + + void ODbaseDetailsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + // get the DSN string (needed for the index dialog) + const SfxStringItem* pUrlItem = _rSet.GetItem<SfxStringItem>(DSID_CONNECTURL); + const DbuTypeCollectionItem* pTypesItem = _rSet.GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION); + ::dbaccess::ODsnTypeCollection* pTypeCollection = pTypesItem ? pTypesItem->getCollection() : nullptr; + if (pTypeCollection && pUrlItem && pUrlItem->GetValue().getLength()) + m_sDsn = pTypeCollection->cutPrefix(pUrlItem->GetValue()); + + // get the other relevant items + const SfxBoolItem* pDeletedItem = _rSet.GetItem<SfxBoolItem>(DSID_SHOWDELETEDROWS); + + if ( bValid ) + { + m_xShowDeleted->set_active(pDeletedItem->GetValue()); + m_xFT_Message->set_visible(m_xShowDeleted->get_active()); + } + + OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue); + } + + bool ODbaseDetailsPage::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet(_rSet); + + fillBool(*_rSet, m_xShowDeleted.get(), DSID_SHOWDELETEDROWS, false, bChangedSomething); + return bChangedSomething; + } + + IMPL_LINK_NOARG(ODbaseDetailsPage, OnButtonClicked, weld::Button&, void) + { + ODbaseIndexDialog aIndexDialog(GetFrameWeld(), m_sDsn); + aIndexDialog.run(); + } + + IMPL_LINK_NOARG(ODbaseDetailsPage, OnButtonToggled, weld::Toggleable&, void) + { + m_xFT_Message->set_visible(m_xShowDeleted->get_active()); + // it was the checkbox -> we count as modified from now on + callModifiedHdl(); + } + + + // OAdoDetailsPage + OAdoDetailsPage::OAdoDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs) + : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/autocharsetpage.ui", "AutoCharset", + rCoreAttrs, OCommonBehaviourTabPageFlags::UseCharset ) + { + + } + + std::unique_ptr<SfxTabPage> ODriversSettings::CreateAdo(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) + { + return std::make_unique<OAdoDetailsPage>(pPage, pController, *rAttrSet); + } + + // OOdbcDetailsPage + OOdbcDetailsPage::OOdbcDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs) + : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/odbcpage.ui", "ODBC", rCoreAttrs, + OCommonBehaviourTabPageFlags::UseCharset | OCommonBehaviourTabPageFlags::UseOptions) + , m_xUseCatalog(m_xBuilder->weld_check_button("useCatalogCheckbutton")) + { + m_xUseCatalog->connect_toggled(LINK(this, OGenericAdministrationPage, OnControlModifiedButtonClick)); + } + + OOdbcDetailsPage::~OOdbcDetailsPage() + { + } + + std::unique_ptr<SfxTabPage> ODriversSettings::CreateODBC(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet) + { + return std::make_unique<OOdbcDetailsPage>(pPage, pController, *pAttrSet); + } + + bool OOdbcDetailsPage::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet(_rSet); + fillBool(*_rSet,m_xUseCatalog.get(),DSID_USECATALOG,false,bChangedSomething); + return bChangedSomething; + } + void OOdbcDetailsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + const SfxBoolItem* pUseCatalogItem = _rSet.GetItem<SfxBoolItem>(DSID_USECATALOG); + + if ( bValid ) + m_xUseCatalog->set_active(pUseCatalogItem->GetValue()); + + OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue); + } + // OOdbcDetailsPage + OUserDriverDetailsPage::OUserDriverDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs) + : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/userdetailspage.ui", "UserDetailsPage", + rCoreAttrs, OCommonBehaviourTabPageFlags::UseCharset | OCommonBehaviourTabPageFlags::UseOptions) + , m_xFTHostname(m_xBuilder->weld_label("hostnameft")) + , m_xEDHostname(m_xBuilder->weld_entry("hostname")) + , m_xPortNumber(m_xBuilder->weld_label("portnumberft")) + , m_xNFPortNumber(m_xBuilder->weld_spin_button("portnumber")) + , m_xUseCatalog(m_xBuilder->weld_check_button("usecatalog")) + { + m_xUseCatalog->connect_toggled(LINK(this, OGenericAdministrationPage, OnControlModifiedButtonClick)); + } + + OUserDriverDetailsPage::~OUserDriverDetailsPage() + { + } + + std::unique_ptr<SfxTabPage> ODriversSettings::CreateUser(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet) + { + return std::make_unique<OUserDriverDetailsPage>(pPage, pController, *pAttrSet); + } + + bool OUserDriverDetailsPage::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet(_rSet); + + fillInt32(*_rSet,m_xNFPortNumber.get(),DSID_CONN_PORTNUMBER,bChangedSomething); + fillString(*_rSet,m_xEDHostname.get(),DSID_CONN_HOSTNAME,bChangedSomething); + fillBool(*_rSet,m_xUseCatalog.get(),DSID_USECATALOG,false,bChangedSomething); + + return bChangedSomething; + } + void OUserDriverDetailsPage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + OCommonBehaviourTabPage::fillControls(_rControlList); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xEDHostname.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xUseCatalog.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::SpinButton>(m_xNFPortNumber.get())); + } + void OUserDriverDetailsPage::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + OCommonBehaviourTabPage::fillWindows(_rControlList); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTHostname.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xPortNumber.get())); + } + void OUserDriverDetailsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + const SfxBoolItem* pUseCatalogItem = _rSet.GetItem<SfxBoolItem>(DSID_USECATALOG); + const SfxStringItem* pHostName = _rSet.GetItem<SfxStringItem>(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = _rSet.GetItem<SfxInt32Item>(DSID_CONN_PORTNUMBER); + + if ( bValid ) + { + m_xEDHostname->set_text(pHostName->GetValue()); + m_xEDHostname->save_value(); + + m_xNFPortNumber->set_value(pPortNumber->GetValue()); + m_xNFPortNumber->save_value(); + + m_xUseCatalog->set_active(pUseCatalogItem->GetValue()); + } + + OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue); + } + // OMySQLODBCDetailsPage + OMySQLODBCDetailsPage::OMySQLODBCDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs) + : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/autocharsetpage.ui", "AutoCharset", + rCoreAttrs, OCommonBehaviourTabPageFlags::UseCharset ) + { + } + + std::unique_ptr<SfxTabPage> ODriversSettings::CreateMySQLODBC(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet) + { + return std::make_unique<OMySQLODBCDetailsPage>(pPage, pController, *pAttrSet); + } + + // OMySQLJDBCDetailsPage + OGeneralSpecialJDBCDetailsPage::OGeneralSpecialJDBCDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs ,sal_uInt16 _nPortId, bool bShowSocket) + : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/generalspecialjdbcdetailspage.ui", "GeneralSpecialJDBCDetails", + rCoreAttrs, OCommonBehaviourTabPageFlags::UseCharset) + , m_nPortId(_nPortId) + , m_bUseClass(true) + , m_xEDHostname(m_xBuilder->weld_entry("hostNameEntry")) + , m_xNFPortNumber(m_xBuilder->weld_spin_button("portNumberSpinbutton")) + , m_xFTSocket(m_xBuilder->weld_label("socketLabel")) + , m_xEDSocket(m_xBuilder->weld_entry("socketEntry")) + , m_xFTDriverClass(m_xBuilder->weld_label("driverClassLabel")) + , m_xEDDriverClass(m_xBuilder->weld_entry("jdbcDriverClassEntry")) + , m_xTestJavaDriver(m_xBuilder->weld_button("testDriverClassButton")) + { + const SfxStringItem* pUrlItem = rCoreAttrs.GetItem<SfxStringItem>(DSID_CONNECTURL); + const DbuTypeCollectionItem* pTypesItem = rCoreAttrs.GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION); + ::dbaccess::ODsnTypeCollection* pTypeCollection = pTypesItem ? pTypesItem->getCollection() : nullptr; + if (pTypeCollection && pUrlItem && pUrlItem->GetValue().getLength() ) + { + m_sDefaultJdbcDriverName = pTypeCollection->getJavaDriverClass(pUrlItem->GetValue()); + } + if ( m_sDefaultJdbcDriverName.getLength() ) + { + m_xEDDriverClass->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl)); + m_xTestJavaDriver->connect_clicked(LINK(this,OGeneralSpecialJDBCDetailsPage,OnTestJavaClickHdl)); + } + else + { + m_bUseClass = false; + m_xFTDriverClass->hide(); + m_xEDDriverClass->hide(); + m_xTestJavaDriver->hide(); + } + + m_xFTSocket->set_visible(bShowSocket && !m_bUseClass); + m_xEDSocket->set_visible(bShowSocket && !m_bUseClass); + + m_xEDHostname->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl)); + m_xNFPortNumber->connect_value_changed(LINK(this,OGenericAdministrationPage,OnControlSpinButtonModifyHdl)); + m_xEDSocket->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl)); + } + + OGeneralSpecialJDBCDetailsPage::~OGeneralSpecialJDBCDetailsPage() + { + } + + bool OGeneralSpecialJDBCDetailsPage::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet(_rSet); + if ( m_bUseClass ) + fillString(*_rSet,m_xEDDriverClass.get(),DSID_JDBCDRIVERCLASS,bChangedSomething); + fillString(*_rSet,m_xEDHostname.get(),DSID_CONN_HOSTNAME,bChangedSomething); + fillString(*_rSet,m_xEDSocket.get(),DSID_CONN_SOCKET,bChangedSomething); + fillInt32(*_rSet,m_xNFPortNumber.get(),m_nPortId,bChangedSomething ); + + return bChangedSomething; + } + void OGeneralSpecialJDBCDetailsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + const SfxStringItem* pDrvItem = _rSet.GetItem<SfxStringItem>(DSID_JDBCDRIVERCLASS); + const SfxStringItem* pHostName = _rSet.GetItem<SfxStringItem>(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = _rSet.GetItem<SfxInt32Item>(m_nPortId); + const SfxStringItem* pSocket = _rSet.GetItem<SfxStringItem>(DSID_CONN_SOCKET); + + if ( bValid ) + { + if ( m_bUseClass ) + { + m_xEDDriverClass->set_text(pDrvItem->GetValue()); + m_xEDDriverClass->save_value(); + } + + m_xEDHostname->set_text(pHostName->GetValue()); + m_xEDHostname->save_value(); + + m_xNFPortNumber->set_value(pPortNumber->GetValue()); + m_xNFPortNumber->save_value(); + + m_xEDSocket->set_text(pSocket->GetValue()); + m_xEDSocket->save_value(); + } + + OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue); + + // to get the correct value when saveValue was called by base class + if ( m_bUseClass && m_xEDDriverClass->get_text().trim().isEmpty() ) + { + m_xEDDriverClass->set_text(m_sDefaultJdbcDriverName); + m_xEDDriverClass->save_value(); + } + } + IMPL_LINK_NOARG(OGeneralSpecialJDBCDetailsPage, OnTestJavaClickHdl, weld::Button&, void) + { + OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF"); + OSL_ENSURE(m_bUseClass,"Who called me?"); + + bool bSuccess = false; +#if HAVE_FEATURE_JAVA + try + { + if (!m_xEDDriverClass->get_text().trim().isEmpty()) + { +// TODO change jvmaccess + ::rtl::Reference< jvmaccess::VirtualMachine > xJVM = ::connectivity::getJavaVM( m_pAdminDialog->getORB() ); + m_xEDDriverClass->set_text(m_xEDDriverClass->get_text().trim()); // fdo#68341 + bSuccess = ::connectivity::existsJavaClassByName(xJVM,m_xEDDriverClass->get_text()); + } + } + catch(Exception&) + { + } +#endif + TranslateId pMessage = bSuccess ? STR_JDBCDRIVER_SUCCESS : STR_JDBCDRIVER_NO_SUCCESS; + const MessageType mt = bSuccess ? MessageType::Info : MessageType::Error; + OSQLMessageBox aMsg(GetFrameWeld(), DBA_RES(pMessage), OUString(), MessBoxStyle::Ok | MessBoxStyle::DefaultOk, mt); + aMsg.run(); + } + + void OGeneralSpecialJDBCDetailsPage::callModifiedHdl(weld::Widget* pControl) + { + if (m_bUseClass && pControl == m_xEDDriverClass.get()) + m_xTestJavaDriver->set_sensitive(!m_xEDDriverClass->get_text().trim().isEmpty()); + + // tell the listener we were modified + OGenericAdministrationPage::callModifiedHdl(); + } + + // MySQLNativePage + MySQLNativePage::MySQLNativePage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs) + : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/mysqlnativepage.ui", "MysqlNativePage", rCoreAttrs, OCommonBehaviourTabPageFlags::UseCharset) + , m_xMySQLSettingsContainer(m_xBuilder->weld_widget("MySQLSettingsContainer")) + , m_xMySQLSettings(new MySQLNativeSettings(m_xMySQLSettingsContainer.get(), LINK(this,OGenericAdministrationPage,OnControlModified))) + , m_xSeparator1(m_xBuilder->weld_label("connectionheader")) + , m_xSeparator2(m_xBuilder->weld_label("userheader")) + , m_xUserNameLabel(m_xBuilder->weld_label("usernamelabel")) + , m_xUserName(m_xBuilder->weld_entry("username")) + , m_xPasswordRequired(m_xBuilder->weld_check_button("passwordrequired")) + { + m_xUserName->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl)); + } + + MySQLNativePage::~MySQLNativePage() + { + m_xMySQLSettings.reset(); + } + + void MySQLNativePage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + OCommonBehaviourTabPage::fillControls( _rControlList ); + m_xMySQLSettings->fillControls( _rControlList ); + + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xUserName.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xPasswordRequired.get())); + } + + void MySQLNativePage::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + OCommonBehaviourTabPage::fillWindows( _rControlList ); + m_xMySQLSettings->fillWindows( _rControlList); + + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xSeparator1.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xSeparator2.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xUserNameLabel.get())); + } + + bool MySQLNativePage::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet( _rSet ); + + bChangedSomething |= m_xMySQLSettings->FillItemSet( _rSet ); + + if (m_xUserName->get_value_changed_from_saved()) + { + _rSet->Put( SfxStringItem( DSID_USER, m_xUserName->get_text() ) ); + _rSet->Put( SfxStringItem( DSID_PASSWORD, OUString())); + bChangedSomething = true; + } + fillBool(*_rSet,m_xPasswordRequired.get(),DSID_PASSWORDREQUIRED,false,bChangedSomething); + + return bChangedSomething; + } + void MySQLNativePage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + m_xMySQLSettings->implInitControls( _rSet ); + + const SfxStringItem* pUidItem = _rSet.GetItem<SfxStringItem>(DSID_USER); + const SfxBoolItem* pAllowEmptyPwd = _rSet.GetItem<SfxBoolItem>(DSID_PASSWORDREQUIRED); + + if ( bValid ) + { + m_xUserName->set_text(pUidItem->GetValue()); + m_xUserName->save_value(); + m_xPasswordRequired->set_active(pAllowEmptyPwd->GetValue()); + } + + OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue); + } + + std::unique_ptr<SfxTabPage> ODriversSettings::CreateMySQLJDBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ) + { + return std::make_unique<OGeneralSpecialJDBCDetailsPage>(pPage, pController, *_rAttrSet,DSID_MYSQL_PORTNUMBER); + } + + std::unique_ptr<SfxTabPage> ODriversSettings::CreateMySQLNATIVE(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet) + { + return std::make_unique<MySQLNativePage>(pPage, pController, *pAttrSet); + } + + std::unique_ptr<SfxTabPage> ODriversSettings::CreateOracleJDBC(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet) + { + return std::make_unique<OGeneralSpecialJDBCDetailsPage>(pPage, pController, *_rAttrSet,DSID_ORACLE_PORTNUMBER, false); + } + + // OLDAPDetailsPage + OLDAPDetailsPage::OLDAPDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs) + : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/ldappage.ui", "LDAP", + rCoreAttrs, OCommonBehaviourTabPageFlags::NONE) + , m_xETBaseDN(m_xBuilder->weld_entry("baseDNEntry")) + , m_xCBUseSSL(m_xBuilder->weld_check_button("useSSLCheckbutton")) + , m_xNFPortNumber(m_xBuilder->weld_spin_button("portNumberSpinbutton")) + , m_xNFRowCount(m_xBuilder->weld_spin_button("LDAPRowCountspinbutton")) + { + m_xETBaseDN->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl)); + m_xNFPortNumber->connect_value_changed(LINK(this,OGenericAdministrationPage,OnControlSpinButtonModifyHdl)); + m_xNFRowCount->connect_value_changed(LINK(this,OGenericAdministrationPage,OnControlSpinButtonModifyHdl)); + + m_iNormalPort = 389; + m_iSSLPort = 636; + m_xCBUseSSL->connect_toggled(LINK(this, OLDAPDetailsPage, OnCheckBoxClick)); + } + + OLDAPDetailsPage::~OLDAPDetailsPage() + { + } + + std::unique_ptr<SfxTabPage> ODriversSettings::CreateLDAP(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet) + { + return std::make_unique<OLDAPDetailsPage>(pPage, pController, *_rAttrSet); + } + + bool OLDAPDetailsPage::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet(_rSet); + + fillString(*_rSet,m_xETBaseDN.get(),DSID_CONN_LDAP_BASEDN,bChangedSomething); + fillInt32(*_rSet,m_xNFPortNumber.get(),DSID_CONN_LDAP_PORTNUMBER,bChangedSomething); + fillInt32(*_rSet,m_xNFRowCount.get(),DSID_CONN_LDAP_ROWCOUNT,bChangedSomething); + fillBool(*_rSet,m_xCBUseSSL.get(),DSID_CONN_LDAP_USESSL,false,bChangedSomething); + return bChangedSomething; + } + + IMPL_LINK(OLDAPDetailsPage, OnCheckBoxClick, weld::Toggleable&, rCheckBox, void) + { + OnControlModifiedButtonClick(rCheckBox); + callModifiedHdl(); + if (m_xCBUseSSL->get_active()) + { + m_iNormalPort = m_xNFPortNumber->get_value(); + m_xNFPortNumber->set_value(m_iSSLPort); + } + else + { + m_iSSLPort = m_xNFPortNumber->get_value(); + m_xNFPortNumber->set_value(m_iNormalPort); + } + } + + void OLDAPDetailsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + const SfxStringItem* pBaseDN = _rSet.GetItem<SfxStringItem>(DSID_CONN_LDAP_BASEDN); + const SfxBoolItem* pUseSSL = _rSet.GetItem<SfxBoolItem>(DSID_CONN_LDAP_USESSL); + const SfxInt32Item* pPortNumber = _rSet.GetItem<SfxInt32Item>(DSID_CONN_LDAP_PORTNUMBER); + const SfxInt32Item* pRowCount = _rSet.GetItem<SfxInt32Item>(DSID_CONN_LDAP_ROWCOUNT); + + if ( bValid ) + { + m_xETBaseDN->set_text(pBaseDN->GetValue()); + m_xNFPortNumber->set_value(pPortNumber->GetValue()); + m_xNFRowCount->set_value(pRowCount->GetValue()); + m_xCBUseSSL->set_active(pUseSSL->GetValue()); + } + + OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue); + } + + // OTextDetailsPage + OTextDetailsPage::OTextDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs) + : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/emptypage.ui", "EmptyPage", rCoreAttrs, OCommonBehaviourTabPageFlags::NONE) + , m_xTextConnectionHelper(new OTextConnectionHelper(m_xContainer.get(), TC_EXTENSION | TC_HEADER | TC_SEPARATORS | TC_CHARSET)) + { + } + + OTextDetailsPage::~OTextDetailsPage() + { + m_xTextConnectionHelper.reset(); + } + + std::unique_ptr<SfxTabPage> ODriversSettings::CreateText(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet) + { + return std::make_unique<OTextDetailsPage>(pPage, pController, *pAttrSet); + } + + void OTextDetailsPage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + OCommonBehaviourTabPage::fillControls(_rControlList); + m_xTextConnectionHelper->fillControls(_rControlList); + + } + void OTextDetailsPage::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + OCommonBehaviourTabPage::fillWindows(_rControlList); + m_xTextConnectionHelper->fillWindows(_rControlList); + + } + void OTextDetailsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // first check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + m_xTextConnectionHelper->implInitControls(_rSet, bValid); + OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue); + } + + bool OTextDetailsPage::FillItemSet( SfxItemSet* rSet ) + { + bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet(rSet); + bChangedSomething = m_xTextConnectionHelper->FillItemSet(*rSet, bChangedSomething); + return bChangedSomething; + } + + bool OTextDetailsPage::prepareLeave() + { + return m_xTextConnectionHelper->prepareLeave(); + } + + std::unique_ptr<SfxTabPage> ODriversSettings::CreateGeneratedValuesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet) + { + return std::make_unique<GeneratedValuesPage>(pPage, pController, *_rAttrSet); + } + + std::unique_ptr<SfxTabPage> ODriversSettings::CreateSpecialSettingsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet) + { + OUString eType = ODbDataSourceAdministrationHelper::getDatasourceType( *_rAttrSet ); + DataSourceMetaData aMetaData( eType ); + return std::make_unique<SpecialSettingsPage>(pPage, pController, *_rAttrSet, aMetaData); + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/detailpages.hxx b/dbaccess/source/ui/dlg/detailpages.hxx new file mode 100644 index 000000000..2952f42e6 --- /dev/null +++ b/dbaccess/source/ui/dlg/detailpages.hxx @@ -0,0 +1,253 @@ +/* -*- 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 "adminpages.hxx" +#include <charsetlistbox.hxx> +#include "TextConnectionHelper.hxx" +#include "admincontrols.hxx" + +#include <o3tl/typed_flags_set.hxx> + +enum class OCommonBehaviourTabPageFlags { + NONE = 0x0000, + UseCharset = 0x0002, + UseOptions = 0x0004, +}; +namespace o3tl { + template<> struct typed_flags<OCommonBehaviourTabPageFlags> : is_typed_flags<OCommonBehaviourTabPageFlags, 0x0006> {}; +} + +namespace dbaui +{ + /** eases the implementation of tab pages handling user/password and/or character + set and/or generic options input + <BR> + The controls to be used have to be defined within the resource, as usual, but + this class does all the handling necessary. + */ + class OCommonBehaviourTabPage : public OGenericAdministrationPage + { + OCommonBehaviourTabPageFlags m_nControlFlags; + + std::unique_ptr<weld::Label> m_xOptionsLabel; + std::unique_ptr<weld::Entry> m_xOptions; + + std::unique_ptr<weld::Label> m_xDataConvertLabel; + std::unique_ptr<weld::Label> m_xCharsetLabel; + std::unique_ptr<CharSetListBox> m_xCharset; + + std::unique_ptr<weld::CheckButton> m_xAutoRetrievingEnabled; + std::unique_ptr<weld::Label> m_xAutoIncrementLabel; + std::unique_ptr<weld::Entry> m_xAutoIncrement; + std::unique_ptr<weld::Label> m_xAutoRetrievingLabel; + std::unique_ptr<weld::Entry> m_xAutoRetrieving; + + public: + virtual bool FillItemSet (SfxItemSet* _rCoreAttrs) override; + + OCommonBehaviourTabPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OString& rId, const SfxItemSet& _rCoreAttrs, OCommonBehaviourTabPageFlags nControlFlags); + protected: + + virtual ~OCommonBehaviourTabPage() override; + + // subclasses must override this, but it isn't pure virtual + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + + // <method>OGenericAdministrationPage::fillControls</method> + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + + // <method>OGenericAdministrationPage::fillWindows</method> + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + private: + DECL_LINK(CharsetSelectHdl, weld::ComboBox&, void); + }; + + + // ODbaseDetailsPage + class ODbaseDetailsPage : public OCommonBehaviourTabPage + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + + ODbaseDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs); + virtual ~ODbaseDetailsPage() override; + private: + OUString m_sDsn; + + std::unique_ptr<weld::CheckButton> m_xShowDeleted; + std::unique_ptr<weld::Label> m_xFT_Message; + std::unique_ptr<weld::Button> m_xIndexes; + + protected: + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + + private: + DECL_LINK(OnButtonClicked, weld::Button&, void); + DECL_LINK(OnButtonToggled, weld::Toggleable&, void); + }; + + // OAdoDetailsPage + class OAdoDetailsPage : public OCommonBehaviourTabPage + { + public: + OAdoDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs); + }; + + // OOdbcDetailsPage + class OOdbcDetailsPage : public OCommonBehaviourTabPage + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + + OOdbcDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs); + virtual ~OOdbcDetailsPage() override; + protected: + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + private: + std::unique_ptr<weld::CheckButton> m_xUseCatalog; + }; + + // OUserDriverDetailsPage + class OUserDriverDetailsPage : public OCommonBehaviourTabPage + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + + OUserDriverDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs); + virtual ~OUserDriverDetailsPage() override; + protected: + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + private: + std::unique_ptr<weld::Label> m_xFTHostname; + std::unique_ptr<weld::Entry> m_xEDHostname; + std::unique_ptr<weld::Label> m_xPortNumber; + std::unique_ptr<weld::SpinButton> m_xNFPortNumber; + std::unique_ptr<weld::CheckButton> m_xUseCatalog; + }; + + // OMySQLODBCDetailsPage + class OMySQLODBCDetailsPage : public OCommonBehaviourTabPage + { + public: + OMySQLODBCDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs); + }; + + // OGeneralSpecialJDBCDetailsPage + class OGeneralSpecialJDBCDetailsPage final : public OCommonBehaviourTabPage + { + public: + OGeneralSpecialJDBCDetailsPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& _rCoreAttrs, + sal_uInt16 _nPortId, + bool bShowSocket = true); + virtual ~OGeneralSpecialJDBCDetailsPage() override; + + private: + + virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override; + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual void callModifiedHdl(weld::Widget* pControl = nullptr) override; + + DECL_LINK(OnTestJavaClickHdl, weld::Button&, void); + + OUString m_sDefaultJdbcDriverName; + sal_uInt16 m_nPortId; + bool m_bUseClass; + + std::unique_ptr<weld::Entry> m_xEDHostname; + std::unique_ptr<weld::SpinButton> m_xNFPortNumber; + std::unique_ptr<weld::Label> m_xFTSocket; + std::unique_ptr<weld::Entry> m_xEDSocket; + std::unique_ptr<weld::Label> m_xFTDriverClass; + std::unique_ptr<weld::Entry> m_xEDDriverClass; + std::unique_ptr<weld::Button> m_xTestJavaDriver; + }; + + // MySQLNativePage + class MySQLNativePage : public OCommonBehaviourTabPage + { + public: + MySQLNativePage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs); + virtual ~MySQLNativePage() override; + + private: + std::unique_ptr<weld::Widget> m_xMySQLSettingsContainer; + std::unique_ptr<MySQLNativeSettings> m_xMySQLSettings; + std::unique_ptr<weld::Label> m_xSeparator1; + std::unique_ptr<weld::Label> m_xSeparator2; + std::unique_ptr<weld::Label> m_xUserNameLabel; + std::unique_ptr<weld::Entry> m_xUserName; + std::unique_ptr<weld::CheckButton> m_xPasswordRequired; + + protected: + virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override; + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + }; + + // OOdbcDetailsPage + class OLDAPDetailsPage : public OCommonBehaviourTabPage + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + + OLDAPDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs); + virtual ~OLDAPDetailsPage() override; + protected: + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + private: + sal_Int32 m_iSSLPort; + sal_Int32 m_iNormalPort; + + std::unique_ptr<weld::Entry> m_xETBaseDN; + std::unique_ptr<weld::CheckButton> m_xCBUseSSL; + std::unique_ptr<weld::SpinButton> m_xNFPortNumber; + std::unique_ptr<weld::SpinButton> m_xNFRowCount; + + DECL_LINK(OnCheckBoxClick, weld::Toggleable&, void); + }; + + // OTextDetailsPage + class OTextDetailsPage : public OCommonBehaviourTabPage + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + + OTextDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs); + virtual ~OTextDetailsPage() override; + + protected: + virtual bool prepareLeave() override; + + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + + private: + std::unique_ptr<OTextConnectionHelper> m_xTextConnectionHelper; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/directsql.cxx b/dbaccess/source/ui/dlg/directsql.cxx new file mode 100644 index 000000000..ba5d9d3be --- /dev/null +++ b/dbaccess/source/ui/dlg/directsql.cxx @@ -0,0 +1,430 @@ +/* -*- 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 <core_resource.hxx> +#include <directsql.hxx> +#include <sqledit.hxx> +#include <strings.hxx> +#include <strings.hrc> +#include <comphelper/types.hxx> +#include <osl/mutex.hxx> +#include <rtl/ustrbuf.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbc/XMultipleResults.hpp> + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::lang; + + constexpr sal_Int32 g_nHistoryLimit = 20; + + // DirectSQLDialog + DirectSQLDialog::DirectSQLDialog(weld::Window* _pParent, const Reference< XConnection >& _rxConn) + : GenericDialogController(_pParent, "dbaccess/ui/directsqldialog.ui", "DirectSQLDialog") + , m_xExecute(m_xBuilder->weld_button("execute")) + , m_xSQLHistory(m_xBuilder->weld_combo_box("sqlhistory")) + , m_xStatus(m_xBuilder->weld_text_view("status")) + , m_xDirectSQL(m_xBuilder->weld_check_button("directsql")) + , m_xShowOutput(m_xBuilder->weld_check_button("showoutput")) + , m_xOutput(m_xBuilder->weld_text_view("output")) + , m_xClose(m_xBuilder->weld_button("close")) + , m_xSQL(new SQLEditView(m_xBuilder->weld_scrolled_window("scrolledwindow", true))) + , m_xSQLEd(new weld::CustomWeld(*m_xBuilder, "sql", *m_xSQL)) + , m_nStatusCount(1) + , m_xConnection(_rxConn) + , m_pClosingEvent(nullptr) + { + int nWidth = m_xStatus->get_approximate_digit_width() * 60; + int nHeight = m_xStatus->get_height_rows(7); + + m_xSQLEd->set_size_request(nWidth, nHeight); + m_xStatus->set_size_request(-1, nHeight); + m_xOutput->set_size_request(-1, nHeight); + + m_xSQL->GrabFocus(); + + m_xExecute->connect_clicked(LINK(this, DirectSQLDialog, OnExecute)); + m_xClose->connect_clicked(LINK(this, DirectSQLDialog, OnCloseClick)); + m_xSQLHistory->connect_changed(LINK(this, DirectSQLDialog, OnListEntrySelected)); + + // add a dispose listener to the connection + Reference< XComponent > xConnComp(m_xConnection, UNO_QUERY); + OSL_ENSURE(xConnComp.is(), "DirectSQLDialog::DirectSQLDialog: invalid connection!"); + if (xConnComp.is()) + startComponentListening(xConnComp); + + m_xSQL->SetModifyHdl(LINK(this, DirectSQLDialog, OnStatementModified)); + OnStatementModified(nullptr); + } + + DirectSQLDialog::~DirectSQLDialog() + { + ::osl::MutexGuard aGuard(m_aMutex); + if (m_pClosingEvent) + Application::RemoveUserEvent(m_pClosingEvent); + stopAllComponentListening(); + } + + void DirectSQLDialog::_disposing( const EventObject& _rSource ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard(m_aMutex); + + assert(!m_pClosingEvent); + + OSL_ENSURE(Reference< XConnection >(_rSource.Source, UNO_QUERY).get() == m_xConnection.get(), + "DirectSQLDialog::_disposing: where does this come from?"); + + { + OUString sMessage(DBA_RES(STR_DIRECTSQL_CONNECTIONLOST)); + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, + sMessage)); + xError->run(); + } + + m_pClosingEvent = Application::PostUserEvent(LINK(this, DirectSQLDialog, OnClose)); + } + + sal_Int32 DirectSQLDialog::getHistorySize() const + { + #ifdef DBG_UTIL + { + const char* pError = impl_CheckInvariants(); + if (pError) + SAL_WARN("dbaccess.ui", "DirectSQLDialog::getHistorySize: " << pError); + } + #endif + return m_aStatementHistory.size(); + } + + void DirectSQLDialog::implEnsureHistoryLimit() + { + #ifdef DBG_UTIL + { + const char* pError = impl_CheckInvariants(); + if (pError) + SAL_WARN("dbaccess.ui", "DirectSQLDialog::implEnsureHistoryLimit: " << pError); + } + #endif + + if (getHistorySize() <= g_nHistoryLimit) + // nothing to do + return; + + sal_Int32 nRemoveEntries = getHistorySize() - g_nHistoryLimit; + while (nRemoveEntries--) + { + m_aStatementHistory.pop_front(); + m_aNormalizedHistory.pop_front(); + m_xSQLHistory->remove(0); + } + } + + void DirectSQLDialog::implAddToStatementHistory(const OUString& _rStatement) + { + #ifdef DBG_UTIL + { + const char* pError = impl_CheckInvariants(); + if (pError) + SAL_WARN("dbaccess.ui", "DirectSQLDialog::implAddToStatementHistor: " << pError); + } + #endif + + // add the statement to the history + m_aStatementHistory.push_back(_rStatement); + + // normalize the statement, and remember the normalized form, too + OUString sNormalized = _rStatement.replaceAll("\n", " "); + m_aNormalizedHistory.push_back(sNormalized); + + // add the normalized version to the list box + m_xSQLHistory->append_text(sNormalized); + + // ensure that we don't exceed the history limit + implEnsureHistoryLimit(); + } + +#ifdef DBG_UTIL + const char* DirectSQLDialog::impl_CheckInvariants() const + { + if (m_aStatementHistory.size() != m_aNormalizedHistory.size()) + return "statement history is inconsistent!"; + + if (!m_xSQLHistory) + return "invalid listbox!"; + + if (m_aStatementHistory.size() != static_cast<size_t>(m_xSQLHistory->get_count())) + return "invalid listbox entry count!"; + + if (!m_xConnection.is()) + return "have no connection!"; + + return nullptr; + } +#endif + + void DirectSQLDialog::implExecuteStatement(const OUString& _rStatement) + { + #ifdef DBG_UTIL + { + const char* pError = impl_CheckInvariants(); + if (pError) + SAL_WARN("dbaccess.ui", "DirectSQLDialog::implExecuteStatement: " << pError); + } + #endif + + ::osl::MutexGuard aGuard(m_aMutex); + + OUString sStatus; + + // clear the output box + m_xOutput->set_text(OUString()); + try + { + // create a statement + Reference< XStatement > xStatement = m_xConnection->createStatement(); + + if (m_xDirectSQL->get_active()) + { + Reference< com::sun::star::beans::XPropertySet > xStatementProps(xStatement, UNO_QUERY_THROW); + try + { + xStatementProps->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, Any(false)); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + css::uno::Reference< css::sdbc::XMultipleResults > xMR ( xStatement, UNO_QUERY ); + + if (xMeta.is() && xMeta->supportsMultipleResultSets() && xMR.is()) + { + bool hasRS = xStatement->execute(_rStatement); + if(hasRS) + { + css::uno::Reference< css::sdbc::XResultSet > xRS (xMR->getResultSet()); + if (m_xShowOutput->get_active()) + display(xRS); + } + else + addOutputText( + OUStringConcatenation(OUString::number(xMR->getUpdateCount()) + " rows updated\n")); + for (;;) + { + hasRS = xMR->getMoreResults(); + if (!hasRS && xMR->getUpdateCount() == -1) + break; + if(hasRS) + { + css::uno::Reference< css::sdbc::XResultSet > xRS (xMR->getResultSet()); + if (m_xShowOutput->get_active()) + display(xRS); + } + } + } + else + { + const OUString upperStatement = _rStatement.toAsciiUpperCase(); + if (upperStatement.startsWith("UPDATE")) + { + sal_Int32 resultCount = xStatement->executeUpdate(_rStatement); + addOutputText(OUStringConcatenation(OUString::number(resultCount) + " rows updated\n")); + } + else if (upperStatement.startsWith("INSERT")) + { + sal_Int32 resultCount = xStatement->executeUpdate(_rStatement); + addOutputText(OUStringConcatenation(OUString::number(resultCount) + " rows inserted\n")); + } + else if (upperStatement.startsWith("DELETE")) + { + sal_Int32 resultCount = xStatement->executeUpdate(_rStatement); + addOutputText(OUStringConcatenation(OUString::number(resultCount) + " rows deleted\n")); + } + else if (upperStatement.startsWith("CREATE")) + { + xStatement->executeUpdate(_rStatement); + addOutputText(u"Command executed\n"); + } + else if (upperStatement.startsWith("SELECT") || m_xShowOutput->get_active()) + { + css::uno::Reference< css::sdbc::XResultSet > xRS = xStatement->executeQuery(_rStatement); + if (m_xShowOutput->get_active()) + display(xRS); + } + else + { + sal_Int32 resultCount = xStatement->executeUpdate(_rStatement); + addOutputText(OUStringConcatenation(OUString::number(resultCount) + " rows updated\n")); + } + } + // successful + sStatus = DBA_RES(STR_COMMAND_EXECUTED_SUCCESSFULLY); + + // dispose the statement + ::comphelper::disposeComponent(xStatement); + } + catch(const SQLException& e) + { + sStatus = e.Message; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + // add the status text + addStatusText(sStatus); + } + + void DirectSQLDialog::display(const css::uno::Reference< css::sdbc::XResultSet >& xRS) + { + // get a handle for the rows + css::uno::Reference< css::sdbc::XRow > xRow( xRS, css::uno::UNO_QUERY ); + // work through each of the rows + while (xRS->next()) + { + // initialise the output line for each row + OUStringBuffer out; + // work along the columns until that are none left + try + { + int i = 1; + for (;;) + { + // be dumb, treat everything as a string + out.append(xRow->getString(i) + ","); + i++; + } + } + // trap for when we fall off the end of the row + catch (const SQLException&) + { + } + // report the output + addOutputText(out); + } + } + + void DirectSQLDialog::addStatusText(std::u16string_view _rMessage) + { + OUString sAppendMessage = OUString::number(m_nStatusCount++) + ": " + _rMessage + "\n\n"; + + OUString sCompleteMessage = m_xStatus->get_text() + sAppendMessage; + m_xStatus->set_text(sCompleteMessage); + + m_xStatus->select_region(sCompleteMessage.getLength(), sCompleteMessage.getLength()); + } + + void DirectSQLDialog::addOutputText(std::u16string_view _rMessage) + { + OUString sAppendMessage = OUString::Concat(_rMessage) + "\n"; + + OUString sCompleteMessage = m_xOutput->get_text() + sAppendMessage; + m_xOutput->set_text(sCompleteMessage); + } + + void DirectSQLDialog::executeCurrent() + { + #ifdef DBG_UTIL + { + const char* pError = impl_CheckInvariants(); + if (pError) + SAL_WARN("dbaccess.ui", "DirectSQLDialog::executeCurrent: " << pError); + } + #endif + + OUString sStatement = m_xSQL->GetText(); + + // execute + implExecuteStatement(sStatement); + + // add the statement to the history + implAddToStatementHistory(sStatement); + + m_xSQL->GrabFocus(); + } + + void DirectSQLDialog::switchToHistory(sal_Int32 _nHistoryPos) + { + #ifdef DBG_UTIL + { + const char* pError = impl_CheckInvariants(); + if (pError) + SAL_WARN("dbaccess.ui", "DirectSQLDialog::switchToHistory: " << pError); + } + #endif + + if ((_nHistoryPos >= 0) && (_nHistoryPos < getHistorySize())) + { + // set the text in the statement editor + OUString sStatement = m_aStatementHistory[_nHistoryPos]; + m_xSQL->SetTextAndUpdate(sStatement); + OnStatementModified(nullptr); + + m_xSQL->GrabFocus(); + } + else + OSL_FAIL("DirectSQLDialog::switchToHistory: invalid position!"); + } + + IMPL_LINK_NOARG( DirectSQLDialog, OnStatementModified, LinkParamNone*, void ) + { + m_xExecute->set_sensitive(!m_xSQL->GetText().isEmpty()); + } + + IMPL_LINK_NOARG( DirectSQLDialog, OnCloseClick, weld::Button&, void ) + { + m_xDialog->response(RET_OK); + } + + IMPL_LINK_NOARG( DirectSQLDialog, OnClose, void*, void ) + { + assert(m_pClosingEvent); + Application::RemoveUserEvent(m_pClosingEvent); + m_pClosingEvent = nullptr; + + m_xDialog->response(RET_OK); + } + + IMPL_LINK_NOARG( DirectSQLDialog, OnExecute, weld::Button&, void ) + { + executeCurrent(); + } + + IMPL_LINK_NOARG( DirectSQLDialog, OnListEntrySelected, weld::ComboBox&, void ) + { + const sal_Int32 nSelected = m_xSQLHistory->get_active(); + if (nSelected != -1) + switchToHistory(nSelected); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dlgattr.cxx b/dbaccess/source/ui/dlg/dlgattr.cxx new file mode 100644 index 000000000..1df2acc20 --- /dev/null +++ b/dbaccess/source/ui/dlg/dlgattr.cxx @@ -0,0 +1,60 @@ +/* -*- 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 <dlgattr.hxx> + +#include <sfx2/tabdlg.hxx> + +#include <svx/numinf.hxx> + +#include <svx/dialogs.hrc> +#include <svl/itemset.hxx> +#include <svx/svxids.hrc> + +using namespace dbaui; + + +SbaSbAttrDlg::SbaSbAttrDlg(weld::Widget* pParent, const SfxItemSet* pCellAttrs, + SvNumberFormatter* pFormatter, bool bHasFormat) + : SfxTabDialogController(pParent, "dbaccess/ui/fielddialog.ui", "FieldDialog", pCellAttrs) +{ + pNumberInfoItem.reset( new SvxNumberInfoItem( pFormatter, SID_ATTR_NUMBERFORMAT_INFO ) ); + + if (bHasFormat) + AddTabPage("format", RID_SVXPAGE_NUMBERFORMAT); + else + RemoveTabPage("format"); + AddTabPage("alignment", RID_SVXPAGE_ALIGNMENT); +} + +SbaSbAttrDlg::~SbaSbAttrDlg() +{ +} + +void SbaSbAttrDlg::PageCreated(const OString& rPageId, SfxTabPage& rTabPage) +{ + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + if (rPageId == "format") + { + aSet.Put (SvxNumberInfoItem( pNumberInfoItem->GetNumberFormatter(), SID_ATTR_NUMBERFORMAT_INFO)); + rTabPage.PageCreated(aSet); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dlgsave.cxx b/dbaccess/source/ui/dlg/dlgsave.cxx new file mode 100644 index 000000000..ce5d16881 --- /dev/null +++ b/dbaccess/source/ui/dlg/dlgsave.cxx @@ -0,0 +1,351 @@ +/* -*- 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 <dlgsave.hxx> +#include <core_resource.hxx> +#include <strings.hrc> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <connectivity/dbtools.hxx> +#include <UITools.hxx> +#include <SqlNameEdit.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <objectnamecheck.hxx> +#include <tools/diagnose_ex.h> + +using namespace dbaui; +using namespace dbtools; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +namespace dbaui +{ + +class OSaveAsDlgImpl +{ +public: + OUString m_aQryLabel; + OUString m_sTblLabel; + OUString m_aName; + const IObjectNameCheck& m_rObjectNameCheck; + css::uno::Reference< css::sdbc::XDatabaseMetaData> m_xMetaData; + sal_Int32 m_nType; + SADFlags m_nFlags; + + OSQLNameChecker m_aChecker; + + std::unique_ptr<weld::Label> m_xDescription; + std::unique_ptr<weld::Label> m_xCatalogLbl; + std::unique_ptr<weld::ComboBox> m_xCatalog; + std::unique_ptr<weld::Label> m_xSchemaLbl; + std::unique_ptr<weld::ComboBox> m_xSchema; + std::unique_ptr<weld::Label> m_xLabel; + std::unique_ptr<weld::Entry> m_xTitle; + std::unique_ptr<weld::Button> m_xPB_OK; + + DECL_LINK(TextFilterHdl, OUString&, bool); + + OSaveAsDlgImpl( weld::Builder* pParent, sal_Int32 _rType, + const css::uno::Reference< css::sdbc::XConnection>& _xConnection, + const OUString& rDefault, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags); + OSaveAsDlgImpl( weld::Builder* pParent, + const OUString& rDefault, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags); +}; + +} // dbaui + +IMPL_LINK(OSaveAsDlgImpl, TextFilterHdl, OUString&, rTest, bool) +{ + OUString sCorrected; + if (m_aChecker.checkString(rTest, sCorrected)) + rTest = sCorrected; + return true; +} + +OSaveAsDlgImpl::OSaveAsDlgImpl(weld::Builder* pBuilder, + sal_Int32 _rType, + const Reference< XConnection>& _xConnection, + const OUString& rDefault, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags) + : m_aQryLabel(DBA_RES(STR_QRY_LABEL)) + , m_sTblLabel(DBA_RES(STR_TBL_LABEL)) + , m_aName(rDefault) + , m_rObjectNameCheck( _rObjectNameCheck ) + , m_nType(_rType) + , m_nFlags(_nFlags) + , m_aChecker(OUString()) + , m_xDescription(pBuilder->weld_label("descriptionft")) + , m_xCatalogLbl(pBuilder->weld_label("catalogft")) + , m_xCatalog(pBuilder->weld_combo_box("catalog")) + , m_xSchemaLbl(pBuilder->weld_label("schemaft")) + , m_xSchema(pBuilder->weld_combo_box("schema")) + , m_xLabel(pBuilder->weld_label("titleft")) + , m_xTitle(pBuilder->weld_entry("title")) + , m_xPB_OK(pBuilder->weld_button("ok")) +{ + if ( _xConnection.is() ) + m_xMetaData = _xConnection->getMetaData(); + + if (m_xMetaData.is()) + { + OUString sExtraNameChars(m_xMetaData->getExtraNameCharacters()); + m_aChecker.setAllowedChars(sExtraNameChars); + } + + m_xTitle->connect_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl)); + m_xSchema->connect_entry_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl)); + m_xCatalog->connect_entry_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl)); +} + +OSaveAsDlgImpl::OSaveAsDlgImpl(weld::Builder* pBuilder, + const OUString& rDefault, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags) + : m_aQryLabel(DBA_RES(STR_QRY_LABEL)) + , m_sTblLabel(DBA_RES(STR_TBL_LABEL)) + , m_aName(rDefault) + , m_rObjectNameCheck( _rObjectNameCheck ) + , m_nType(CommandType::COMMAND) + , m_nFlags(_nFlags) + , m_aChecker(OUString()) + , m_xDescription(pBuilder->weld_label("descriptionft")) + , m_xCatalogLbl(pBuilder->weld_label("catalogft")) + , m_xCatalog(pBuilder->weld_combo_box("catalog")) + , m_xSchemaLbl(pBuilder->weld_label("schemaft")) + , m_xSchema(pBuilder->weld_combo_box("schema")) + , m_xLabel(pBuilder->weld_label("titleft")) + , m_xTitle(pBuilder->weld_entry("title")) + , m_xPB_OK(pBuilder->weld_button("ok")) +{ + m_xTitle->connect_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl)); + m_xSchema->connect_entry_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl)); + m_xCatalog->connect_entry_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl)); +} + +using namespace ::com::sun::star::lang; + +namespace +{ +typedef Reference< XResultSet > (SAL_CALL XDatabaseMetaData::*FGetMetaStrings)(); + +void lcl_fillComboList( weld::ComboBox& _rList, const Reference< XConnection >& _rxConnection, + FGetMetaStrings GetAll, const OUString& _rCurrent ) +{ + try { + Reference< XDatabaseMetaData > xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW ); + + Reference< XResultSet > xRes = (xMetaData.get()->*GetAll)(); + Reference< XRow > xRow( xRes, UNO_QUERY_THROW ); + OUString sValue; + while ( xRes->next() ) { + sValue = xRow->getString( 1 ); + if ( !xRow->wasNull() ) + _rList.append_text( sValue ); + } + + int nPos = _rList.find_text( _rCurrent ); + if (nPos != -1) + _rList.set_active( nPos ); + else + _rList.set_active( 0 ); + } catch( const Exception& ) { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} +} + +OSaveAsDlg::OSaveAsDlg( weld::Window * pParent, + sal_Int32 _rType, + const Reference< XComponentContext >& _rxContext, + const Reference< XConnection>& _xConnection, + const OUString& rDefault, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags) + : GenericDialogController(pParent, "dbaccess/ui/savedialog.ui", "SaveDialog") + , m_xContext( _rxContext ) +{ + m_pImpl.reset( new OSaveAsDlgImpl(m_xBuilder.get(),_rType,_xConnection,rDefault,_rObjectNameCheck,_nFlags) ); + + switch (_rType) { + case CommandType::QUERY: + implInitOnlyTitle(m_pImpl->m_aQryLabel); + break; + + case CommandType::TABLE: + OSL_ENSURE( m_pImpl->m_xMetaData.is(), "OSaveAsDlg::OSaveAsDlg: no meta data for entering table names: this will crash!" ); + { + m_pImpl->m_xLabel->set_label(m_pImpl->m_sTblLabel); + if(m_pImpl->m_xMetaData.is() && !m_pImpl->m_xMetaData->supportsCatalogsInTableDefinitions()) { + m_pImpl->m_xCatalogLbl->hide(); + m_pImpl->m_xCatalog->hide(); + } else { + // now fill the catalogs + lcl_fillComboList( *m_pImpl->m_xCatalog, _xConnection, + &XDatabaseMetaData::getCatalogs, _xConnection->getCatalog() ); + } + + if ( !m_pImpl->m_xMetaData->supportsSchemasInTableDefinitions()) { + m_pImpl->m_xSchemaLbl->hide(); + m_pImpl->m_xSchema->hide(); + } else { + lcl_fillComboList( *m_pImpl->m_xSchema, _xConnection, + &XDatabaseMetaData::getSchemas, m_pImpl->m_xMetaData->getUserName() ); + } + + OSL_ENSURE(m_pImpl->m_xMetaData.is(),"The metadata can not be null!"); + if(m_pImpl->m_aName.indexOf('.') != -1) { + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(m_pImpl->m_xMetaData, + m_pImpl->m_aName, + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + + int nPos = m_pImpl->m_xCatalog->find_text(sCatalog); + if (nPos != -1) + m_pImpl->m_xCatalog->set_active(nPos); + + if ( !sSchema.isEmpty() ) { + nPos = m_pImpl->m_xSchema->find_text(sSchema); + if (nPos != -1) + m_pImpl->m_xSchema->set_active(nPos); + } + m_pImpl->m_xTitle->set_text(sTable); + } else + m_pImpl->m_xTitle->set_text(m_pImpl->m_aName); + m_pImpl->m_xTitle->select_region(0, -1); + + sal_Int32 nLength = m_pImpl->m_xMetaData.is() ? m_pImpl->m_xMetaData->getMaxTableNameLength() : 0; + if (nLength) + { + m_pImpl->m_xTitle->set_max_length(nLength); + m_pImpl->m_xSchema->set_entry_max_length(nLength); + m_pImpl->m_xCatalog->set_entry_max_length(nLength); + } + + bool bCheck = _xConnection.is() && isSQL92CheckEnabled(_xConnection); + m_pImpl->m_aChecker.setCheck(bCheck); // enable non valid sql chars as well + } + break; + + default: + OSL_FAIL( "OSaveAsDlg::OSaveAsDlg: Type not supported yet!" ); + } + + implInit(); +} + +OSaveAsDlg::OSaveAsDlg(weld::Window * pParent, + const Reference< XComponentContext >& _rxContext, + const OUString& rDefault, + const OUString& _sLabel, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags) + : GenericDialogController(pParent, "dbaccess/ui/savedialog.ui", "SaveDialog") + , m_xContext( _rxContext ) +{ + m_pImpl.reset( new OSaveAsDlgImpl(m_xBuilder.get(),rDefault,_rObjectNameCheck,_nFlags) ); + implInitOnlyTitle(_sLabel); + implInit(); +} + +OSaveAsDlg::~OSaveAsDlg() +{ +} + +IMPL_LINK_NOARG(OSaveAsDlg, ButtonClickHdl, weld::Button&, void) +{ + m_pImpl->m_aName = m_pImpl->m_xTitle->get_text(); + + OUString sNameToCheck( m_pImpl->m_aName ); + + if ( m_pImpl->m_nType == CommandType::TABLE ) { + sNameToCheck = ::dbtools::composeTableName( + m_pImpl->m_xMetaData, + getCatalog(), + getSchema(), + sNameToCheck, + false, // no quoting + ::dbtools::EComposeRule::InDataManipulation + ); + } + + SQLExceptionInfo aNameError; + if ( m_pImpl->m_rObjectNameCheck.isNameValid( sNameToCheck, aNameError ) ) + m_xDialog->response(RET_OK); + + showError(aNameError, m_xDialog->GetXWindow(), m_xContext); + m_pImpl->m_xTitle->grab_focus(); +} + +IMPL_LINK_NOARG(OSaveAsDlg, EditModifyHdl, weld::Entry&, void) +{ + m_pImpl->m_xPB_OK->set_sensitive(!m_pImpl->m_xTitle->get_text().isEmpty()); +} + +void OSaveAsDlg::implInitOnlyTitle(const OUString& _rLabel) +{ + m_pImpl->m_xLabel->set_label(_rLabel); + m_pImpl->m_xCatalogLbl->hide(); + m_pImpl->m_xCatalog->hide(); + m_pImpl->m_xSchemaLbl->hide(); + m_pImpl->m_xSchema->hide(); + + m_pImpl->m_xTitle->set_text(m_pImpl->m_aName); + m_pImpl->m_aChecker.setCheck(false); // enable non valid sql chars as well +} + +void OSaveAsDlg::implInit() +{ + if ( !( m_pImpl->m_nFlags & SADFlags::AdditionalDescription ) ) { + // hide the description window + m_pImpl->m_xDescription->hide(); + } + + if ( SADFlags::TitlePasteAs == ( m_pImpl->m_nFlags & SADFlags::TitlePasteAs ) ) + m_xDialog->set_title( DBA_RES( STR_TITLE_PASTE_AS ) ); + else if ( SADFlags::TitleRename == ( m_pImpl->m_nFlags & SADFlags::TitleRename ) ) + m_xDialog->set_title( DBA_RES( STR_TITLE_RENAME ) ); + + m_pImpl->m_xPB_OK->connect_clicked(LINK(this,OSaveAsDlg,ButtonClickHdl)); + m_pImpl->m_xTitle->connect_changed(LINK(this,OSaveAsDlg,EditModifyHdl)); + m_pImpl->m_xTitle->grab_focus(); +} + +const OUString& OSaveAsDlg::getName() const +{ + return m_pImpl->m_aName; +} +OUString OSaveAsDlg::getCatalog() const +{ + return m_pImpl->m_xCatalog->get_visible() ? m_pImpl->m_xCatalog->get_active_text() : OUString(); +} +OUString OSaveAsDlg::getSchema() const +{ + return m_pImpl->m_xSchema->get_visible() ? m_pImpl->m_xSchema->get_active_text() : OUString(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dlgsize.cxx b/dbaccess/source/ui/dlg/dlgsize.cxx new file mode 100644 index 000000000..544d9577f --- /dev/null +++ b/dbaccess/source/ui/dlg/dlgsize.cxx @@ -0,0 +1,83 @@ +/* -*- 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 <dlgsize.hxx> + +namespace dbaui +{ + +#define DEF_ROW_HEIGHT 45 +#define DEF_COL_WIDTH 227 + +DlgSize::DlgSize(weld::Window* pParent, sal_Int32 nVal, bool bRow, sal_Int32 _nAlternativeStandard ) + : GenericDialogController(pParent, bRow ? OUString("dbaccess/ui/rowheightdialog.ui") : OUString("dbaccess/ui/colwidthdialog.ui"), + bRow ? OString("RowHeightDialog") : OString("ColWidthDialog")) + , m_nPrevValue(nVal) + , m_xMF_VALUE(m_xBuilder->weld_metric_spin_button("value", FieldUnit::CM)) + , m_xCB_STANDARD(m_xBuilder->weld_check_button("automatic")) +{ + sal_Int32 nStandard(bRow ? DEF_ROW_HEIGHT : DEF_COL_WIDTH); + if ( _nAlternativeStandard > 0 ) + nStandard = _nAlternativeStandard; + m_xCB_STANDARD->connect_toggled(LINK(this,DlgSize,CbClickHdl)); + + bool bDefault = -1 == nVal; + m_xCB_STANDARD->set_active(bDefault); + if (bDefault) + { + SetValue(nStandard); + m_nPrevValue = nStandard; + } + CbClickHdl(*m_xCB_STANDARD); +} + +DlgSize::~DlgSize() +{ +} + +void DlgSize::SetValue( sal_Int32 nVal ) +{ + m_xMF_VALUE->set_value(nVal, FieldUnit::CM ); +} + +sal_Int32 DlgSize::GetValue() const +{ + if (m_xCB_STANDARD->get_active()) + return -1; + return static_cast<sal_Int32>(m_xMF_VALUE->get_value( FieldUnit::CM )); +} + +IMPL_LINK_NOARG(DlgSize, CbClickHdl, weld::Toggleable&, void) +{ + m_xMF_VALUE->set_sensitive(!m_xCB_STANDARD->get_active()); + if (m_xCB_STANDARD->get_active()) + { + // don't use getValue as this will use m_xCB_STANDARD->to determine if we're standard + m_nPrevValue = static_cast<sal_Int32>(m_xMF_VALUE->get_value(FieldUnit::CM)); + m_xMF_VALUE->set_text(""); + } + else + { + SetValue(m_nPrevValue); + } +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dsnItem.hxx b/dbaccess/source/ui/dlg/dsnItem.hxx new file mode 100644 index 000000000..4ae414881 --- /dev/null +++ b/dbaccess/source/ui/dlg/dsnItem.hxx @@ -0,0 +1,48 @@ +/* -*- 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 <svl/poolitem.hxx> + +namespace dbaccess +{ + class ODsnTypeCollection; +} +namespace dbaui +{ + // DbuTypeCollectionItem + /** allows an ODsnTypeCollection to be transported in an SfxItemSet + */ + class DbuTypeCollectionItem : public SfxPoolItem + { + ::dbaccess::ODsnTypeCollection* m_pCollection; + + public: + DbuTypeCollectionItem(sal_Int16 nWhich, ::dbaccess::ODsnTypeCollection* _pCollection); + DbuTypeCollectionItem(const DbuTypeCollectionItem& _rSource); + + virtual bool operator==(const SfxPoolItem& _rItem) const override; + virtual DbuTypeCollectionItem* Clone(SfxItemPool* _pPool = nullptr) const override; + + ::dbaccess::ODsnTypeCollection* getCollection() const { return m_pCollection; } + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dsselect.cxx b/dbaccess/source/ui/dlg/dsselect.cxx new file mode 100644 index 000000000..4c0b9a836 --- /dev/null +++ b/dbaccess/source/ui/dlg/dsselect.cxx @@ -0,0 +1,133 @@ +/* -*- 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 "dsselect.hxx" + +#include <com/sun/star/sdbcx/XCreateCatalog.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> + +namespace dbaui +{ +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::ui::dialogs; + +ODatasourceSelectDialog::ODatasourceSelectDialog(weld::Window* _pParent, const std::set<OUString>& _rDatasources) + : GenericDialogController(_pParent, "dbaccess/ui/choosedatasourcedialog.ui", "ChooseDataSourceDialog") + , m_xDatasource(m_xBuilder->weld_tree_view("treeview")) + , m_xOk(m_xBuilder->weld_button("ok")) + , m_xCancel(m_xBuilder->weld_button("cancel")) + , m_xManageDatasources(m_xBuilder->weld_button("organize")) +{ + m_xDatasource->set_size_request(-1, m_xDatasource->get_height_rows(6)); + + fillListBox(_rDatasources); +#ifdef HAVE_ODBC_ADMINISTRATION + // allow ODBC datasource management + m_xManageDatasources->show(); + m_xManageDatasources->set_sensitive(true); + m_xManageDatasources->connect_clicked(LINK(this,ODatasourceSelectDialog,ManageClickHdl)); +#endif + m_xDatasource->connect_row_activated(LINK(this,ODatasourceSelectDialog,ListDblClickHdl)); +} + +ODatasourceSelectDialog::~ODatasourceSelectDialog() +{ +} + +IMPL_LINK(ODatasourceSelectDialog, ListDblClickHdl, weld::TreeView&, rListBox, bool) +{ + if (rListBox.n_children()) + m_xDialog->response(RET_OK); + return true; +} + +short ODatasourceSelectDialog::run() +{ + short nRet = GenericDialogController::run(); +#ifdef HAVE_ODBC_ADMINISTRATION + if (m_xODBCManagement.get()) + m_xODBCManagement->disableCallback(); +#endif + return nRet; +} + +#ifdef HAVE_ODBC_ADMINISTRATION +IMPL_LINK_NOARG(ODatasourceSelectDialog, ManageClickHdl, weld::Button&, void) +{ + if ( !m_xODBCManagement.get() ) + m_xODBCManagement.reset( new OOdbcManagement( LINK( this, ODatasourceSelectDialog, ManageProcessFinished ) ) ); + + if ( !m_xODBCManagement->manageDataSources_async() ) + { + // TODO: error message + m_xDatasource->grab_focus(); + m_xManageDatasources->set_sensitive(false); + return; + } + + m_xDatasource->set_sensitive(false); + m_xOk->set_sensitive(false); + m_xCancel->set_sensitive(false); + m_xManageDatasources->set_sensitive(false); + + SAL_WARN_IF( !m_xODBCManagement->isRunning(), "dbaccess.ui", "ODatasourceSelectDialog::ManageClickHdl: success, but not running - you were *fast*!" ); +} + +IMPL_LINK_NOARG( ODatasourceSelectDialog, ManageProcessFinished, void*, void ) +{ + m_xODBCManagement->receivedCallback(); + + std::set<OUString> aOdbcDatasources; + OOdbcEnumeration aEnumeration; + aEnumeration.getDatasourceNames( aOdbcDatasources ); + fillListBox( aOdbcDatasources ); + + m_xDatasource->set_sensitive(true); + m_xOk->set_sensitive(true); + m_xCancel->set_sensitive(true); + m_xManageDatasources->set_sensitive(true); +} + +#endif +void ODatasourceSelectDialog::fillListBox(const std::set<OUString>& _rDatasources) +{ + OUString sSelected; + if (m_xDatasource->n_children()) + sSelected = m_xDatasource->get_selected_text(); + m_xDatasource->clear(); + // fill the list + for (auto const& datasource : _rDatasources) + { + m_xDatasource->append_text(datasource); + } + + if (m_xDatasource->n_children()) + { + if (!sSelected.isEmpty()) + m_xDatasource->select_text(sSelected); + else // select the first entry + m_xDatasource->select(0); + } +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dsselect.hxx b/dbaccess/source/ui/dlg/dsselect.hxx new file mode 100644 index 000000000..87cdef17c --- /dev/null +++ b/dbaccess/source/ui/dlg/dsselect.hxx @@ -0,0 +1,61 @@ +/* -*- 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 <rtl/ustring.hxx> +#include <vcl/weld.hxx> + +#include <memory> +#include <set> + +class SfxItemSet; +namespace dbaui +{ +// ODatasourceSelector +class ODatasourceSelectDialog final : public weld::GenericDialogController +{ + std::unique_ptr<weld::TreeView> m_xDatasource; + std::unique_ptr<weld::Button> m_xOk; + std::unique_ptr<weld::Button> m_xCancel; + std::unique_ptr<weld::Button> m_xManageDatasources; +#ifdef HAVE_ODBC_ADMINISTRATION + std::unique_ptr<OOdbcManagement> m_xODBCManagement; +#endif + +public: + ODatasourceSelectDialog(weld::Window* pParent, const std::set<OUString>& rDatasources); + virtual ~ODatasourceSelectDialog() override; + OUString GetSelected() const { return m_xDatasource->get_selected_text(); } + void Select(const OUString& _rEntry) { m_xDatasource->select_text(_rEntry); } + + virtual short run() override; + +private: + DECL_LINK(ListDblClickHdl, weld::TreeView&, bool); +#ifdef HAVE_ODBC_ADMINISTRATION + DECL_LINK(ManageClickHdl, weld::Button&, void); + DECL_LINK(ManageProcessFinished, void*, void); +#endif + void fillListBox(const std::set<OUString>& _rDatasources); +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/finteraction.cxx b/dbaccess/source/ui/dlg/finteraction.cxx new file mode 100644 index 000000000..611119a0c --- /dev/null +++ b/dbaccess/source/ui/dlg/finteraction.cxx @@ -0,0 +1,59 @@ +/* -*- 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 "finteraction.hxx" +#include <com/sun/star/ucb/InteractiveIOException.hpp> + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::task; + using namespace ::com::sun::star::ucb; + + // OFilePickerInteractionHandler + OFilePickerInteractionHandler::OFilePickerInteractionHandler( const Reference< XInteractionHandler >& _rxMaster ) + :m_xMaster( _rxMaster ) + ,m_bDoesNotExist(false) + { + assert(m_xMaster.is()); + } + + OFilePickerInteractionHandler::~OFilePickerInteractionHandler( ) + { + } + + void SAL_CALL OFilePickerInteractionHandler::handle( const Reference< XInteractionRequest >& _rxRequest ) + { + InteractiveIOException aIoException; + if ( _rxRequest->getRequest() >>= aIoException ) + { + if ( IOErrorCode_NOT_EXISTING == aIoException.Code ) + { + m_bDoesNotExist = true; + return; + } + } + + if ( m_xMaster.is() ) + m_xMaster->handle( _rxRequest ); + } + +} // namespace svt + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/finteraction.hxx b/dbaccess/source/ui/dlg/finteraction.hxx new file mode 100644 index 000000000..a487392a5 --- /dev/null +++ b/dbaccess/source/ui/dlg/finteraction.hxx @@ -0,0 +1,54 @@ +/* -*- 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 <cppuhelper/implbase.hxx> +#include <com/sun/star/task/XInteractionHandler.hpp> + +namespace dbaui +{ + + // OFilePickerInteractionHandler + typedef ::cppu::WeakImplHelper< css::task::XInteractionHandler + > OFilePickerInteractionHandler_Base; + + /** an InteractionHandler implementation which extends another handler with some customizability + */ + class OFilePickerInteractionHandler final : public OFilePickerInteractionHandler_Base + { + css::uno::Reference< css::task::XInteractionHandler > + m_xMaster; // our master handler + bool m_bDoesNotExist; + + public: + explicit OFilePickerInteractionHandler( const css::uno::Reference< css::task::XInteractionHandler >& _rxMaster ); + + bool isDoesNotExist() const { return m_bDoesNotExist; } + + private: + // XInteractionHandler + virtual void SAL_CALL handle( const css::uno::Reference< css::task::XInteractionRequest >& _rxRequest ) override; + + virtual ~OFilePickerInteractionHandler() override; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/generalpage.cxx b/dbaccess/source/ui/dlg/generalpage.cxx new file mode 100644 index 000000000..f7017187b --- /dev/null +++ b/dbaccess/source/ui/dlg/generalpage.cxx @@ -0,0 +1,700 @@ +/* -*- 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 <config_features.h> +#include <core_resource.hxx> +#include "dsnItem.hxx" +#include "generalpage.hxx" +#include <connectivity/dbexception.hxx> +#include <strings.hrc> +#include <dsitems.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/docfilt.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <svl/stritem.hxx> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <UITools.hxx> +#include <officecfg/Office/Common.hxx> +#include <comphelper/processfactory.hxx> +#include <unotools/confignode.hxx> +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <dbwizsetup.hxx> + +namespace dbaui +{ + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + + // OGeneralPage + OGeneralPage::OGeneralPage(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const SfxItemSet& _rItems) + : OGenericAdministrationPage(pPage, pController, _rUIXMLDescription, "PageGeneral", _rItems) + , m_xSpecialMessage(m_xBuilder->weld_label("specialMessage")) + , m_eLastMessage(smNone) + , m_bInitTypeList(true) + , m_xDatasourceType(m_xBuilder->weld_combo_box("datasourceType")) + , m_pCollection(nullptr) + { + // extract the datasource type collection from the item set + const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>( _rItems.GetItem(DSID_TYPECOLLECTION) ); + if (pCollectionItem) + m_pCollection = pCollectionItem->getCollection(); + SAL_WARN_IF(!m_pCollection, "dbaccess.ui.generalpage", "OGeneralPage::OGeneralPage : really need a DSN type collection !"); + + // do some knittings + m_xDatasourceType->connect_changed(LINK(this, OGeneralPage, OnDatasourceTypeSelected)); + } + + OGeneralPage::~OGeneralPage() + { + } + + namespace + { + struct DisplayedType + { + OUString eType; + OUString sDisplayName; + + DisplayedType( const OUString& _eType, const OUString& _rDisplayName ) : eType( _eType ), sDisplayName( _rDisplayName ) { } + }; + typedef std::vector< DisplayedType > DisplayedTypes; + + struct DisplayedTypeLess + { + bool operator() ( const DisplayedType& _rLHS, const DisplayedType& _rRHS ) + { + return _rLHS.eType < _rRHS.eType; + } + }; + } + + void OGeneralPage::initializeTypeList() + { + if ( !m_bInitTypeList ) + return; + + m_bInitTypeList = false; + m_xDatasourceType->clear(); + + if ( !m_pCollection ) + return; + + DisplayedTypes aDisplayedTypes; + + ::dbaccess::ODsnTypeCollection::TypeIterator aEnd = m_pCollection->end(); + for ( ::dbaccess::ODsnTypeCollection::TypeIterator aTypeLoop = m_pCollection->begin(); + aTypeLoop != aEnd; + ++aTypeLoop + ) + { + const OUString& sURLPrefix = aTypeLoop.getURLPrefix(); + if ( !sURLPrefix.isEmpty() ) + { + // skip mysql connection variations. It is handled in another window. + if(sURLPrefix.startsWith("sdbc:mysql:") && !sURLPrefix.startsWith("sdbc:mysql:jdbc:")) + continue; + + OUString sDisplayName = aTypeLoop.getDisplayName(); + if (m_xDatasourceType->find_text(sDisplayName) == -1 && + approveDatasourceType(sURLPrefix, sDisplayName)) + { + aDisplayedTypes.emplace_back( sURLPrefix, sDisplayName ); + } + } + } + std::sort( aDisplayedTypes.begin(), aDisplayedTypes.end(), DisplayedTypeLess() ); + for ( const auto& rDisplayedType : aDisplayedTypes ) + insertDatasourceTypeEntryData( rDisplayedType.eType, rDisplayedType.sDisplayName ); + } + + void OGeneralPageWizard::initializeEmbeddedDBList() + { + if ( !m_bInitEmbeddedDBList ) + return; + + m_bInitEmbeddedDBList = false; + m_xEmbeddedDBType->clear(); + + if ( !m_pCollection ) + return; + + DisplayedTypes aDisplayedTypes; + + ::dbaccess::ODsnTypeCollection::TypeIterator aEnd = m_pCollection->end(); + for ( ::dbaccess::ODsnTypeCollection::TypeIterator aTypeLoop = m_pCollection->begin(); + aTypeLoop != aEnd; + ++aTypeLoop + ) + { + const OUString& sURLPrefix = aTypeLoop.getURLPrefix(); + if ( !sURLPrefix.isEmpty() ) + { + OUString sDisplayName = aTypeLoop.getDisplayName(); + if (m_xEmbeddedDBType->find_text(sDisplayName) == -1 && + dbaccess::ODsnTypeCollection::isEmbeddedDatabase(sURLPrefix)) + { +#if !HAVE_FEATURE_MACOSX_SANDBOX + if( !officecfg::Office::Common::Misc::ExperimentalMode::get() + && sURLPrefix.startsWith("sdbc:embedded:firebird") ) + continue; +#endif + aDisplayedTypes.emplace_back( sURLPrefix, sDisplayName ); + m_bIsDisplayedTypesEmpty = false; + } + } + } + std::sort( aDisplayedTypes.begin(), aDisplayedTypes.end(), DisplayedTypeLess() ); + for (auto const& displayedType : aDisplayedTypes) + insertEmbeddedDBTypeEntryData( displayedType.eType, displayedType.sDisplayName ); + } + + void OGeneralPage::setParentTitle(const OUString&) + { + } + + void OGeneralPage::switchMessage(std::u16string_view _sURLPrefix) + { + SPECIAL_MESSAGE eMessage = smNone; + if ( _sURLPrefix.empty()/*_eType == m_eNotSupportedKnownType*/ ) + { + eMessage = smUnsupportedType; + } + + if ( eMessage != m_eLastMessage ) + { + TranslateId pResId; + if ( smUnsupportedType == eMessage ) + pResId = STR_UNSUPPORTED_DATASOURCE_TYPE; + OUString sMessage; + if ( pResId ) + sMessage = DBA_RES(pResId); + + m_xSpecialMessage->set_label( sMessage ); + m_eLastMessage = eMessage; + } + } + + void OGeneralPage::onTypeSelected(const OUString& _sURLPrefix) + { + // the new URL text as indicated by the selection history + implSetCurrentType( _sURLPrefix ); + + switchMessage(_sURLPrefix); + + m_aTypeSelectHandler.Call(*this); + } + + void OGeneralPage::implInitControls( const SfxItemSet& _rSet, bool _bSaveValue ) + { + initializeTypeList(); + + m_xDatasourceType->set_active_text(getDatasourceName(_rSet)); + + // notify our listener that our type selection has changed (if so) + // FIXME: how to detect that it did not changed? (fdo#62937) + setParentTitle( m_eCurrentSelection ); + onTypeSelected( m_eCurrentSelection ); + + // a special message for the current page state + switchMessage( m_eCurrentSelection ); + + OGenericAdministrationPage::implInitControls( _rSet, _bSaveValue ); + } + + OUString OGeneralPageWizard::getEmbeddedDBName( const SfxItemSet& _rSet ) + { + // first check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags( _rSet, bValid, bReadonly ); + + // if the selection is invalid, disable everything + + implSetCurrentType( OUString() ); + + // compare the DSN prefix with the registered ones + OUString sDisplayName; + + if (m_pCollection && bValid) + { + implSetCurrentType( dbaccess::ODsnTypeCollection::getEmbeddedDatabase() ); + sDisplayName = m_pCollection->getTypeDisplayName( m_eCurrentSelection ); + onTypeSelected(m_eCurrentSelection); + } + + // select the correct datasource type + if ( dbaccess::ODsnTypeCollection::isEmbeddedDatabase( m_eCurrentSelection ) + && m_xEmbeddedDBType->find_text(sDisplayName) == -1 ) + { // this indicates it's really a type which is known in general, but not supported on the current platform + // show a message saying so + // eSpecialMessage = smUnsupportedType; + insertEmbeddedDBTypeEntryData( m_eCurrentSelection, sDisplayName ); + } + + return sDisplayName; + } + + OUString OGeneralPage::getDatasourceName( const SfxItemSet& _rSet ) + { + // first check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags( _rSet, bValid, bReadonly ); + + // if the selection is invalid, disable everything + OUString sConnectURL; + if ( bValid ) + { + // collect some items and some values + const SfxStringItem* pUrlItem = _rSet.GetItem<SfxStringItem>(DSID_CONNECTURL); + assert( pUrlItem ); + sConnectURL = pUrlItem->GetValue(); + } + + implSetCurrentType( OUString() ); + + // compare the DSN prefix with the registered ones + OUString sDisplayName; + + if (m_pCollection && bValid) + { + implSetCurrentType( m_pCollection->getPrefix( sConnectURL ) ); + sDisplayName = m_pCollection->getTypeDisplayName( m_eCurrentSelection ); + } + + // select the correct datasource type + if ( approveDatasourceType( m_eCurrentSelection, sDisplayName ) + && m_xDatasourceType->find_text(sDisplayName) == -1 ) + { // this indicates it's really a type which is known in general, but not supported on the current platform + // show a message saying so + // eSpecialMessage = smUnsupportedType; + insertDatasourceTypeEntryData( m_eCurrentSelection, sDisplayName ); + } + + return sDisplayName; + } + + // For the databaseWizard we only have one entry for the MySQL Database, + // because we have a separate tabpage to retrieve the respective datasource type + // ( ::dbaccess::DST_MYSQL_ODBC || ::dbaccess::DST_MYSQL_JDBC). Therefore we use ::dbaccess::DST_MYSQL_JDBC as a temporary + // representative for all MySQl databases) + // Also, embedded databases (embedded HSQL, at the moment), are not to appear in the list of + // databases to connect to. + bool OGeneralPage::approveDatasourceType( std::u16string_view _sURLPrefix, OUString& _inout_rDisplayName ) + { + return approveDatasourceType( m_pCollection->determineType(_sURLPrefix), _inout_rDisplayName ); + } + + bool OGeneralPage::approveDatasourceType( ::dbaccess::DATASOURCE_TYPE eType, OUString& _inout_rDisplayName ) + { + if ( eType == ::dbaccess::DST_MYSQL_NATIVE_DIRECT ) + { + // do not display the Connector/OOo driver itself, it is always wrapped via the MySQL-Driver, if + // this driver is installed + if ( m_pCollection->hasDriver( "sdbc:mysql:mysqlc:" ) ) + _inout_rDisplayName.clear(); + } + + if ( eType == ::dbaccess::DST_EMBEDDED_HSQLDB + || eType == ::dbaccess::DST_EMBEDDED_FIREBIRD ) + _inout_rDisplayName.clear(); + + return _inout_rDisplayName.getLength() > 0; + } + + void OGeneralPage::insertDatasourceTypeEntryData(const OUString& _sType, const OUString& sDisplayName) + { + // insert a (temporary) entry + m_xDatasourceType->append_text(sDisplayName); + m_aURLPrefixes.push_back(_sType); + } + + void OGeneralPageWizard::insertEmbeddedDBTypeEntryData(const OUString& _sType, const OUString& sDisplayName) + { + // insert a (temporary) entry + m_xEmbeddedDBType->append_text(sDisplayName); + m_aEmbeddedURLPrefixes.push_back(_sType); + } + + void OGeneralPage::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xSpecialMessage.get())); + } + + void OGeneralPage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xDatasourceType.get())); + } + + void OGeneralPage::implSetCurrentType( const OUString& _eType ) + { + if ( _eType == m_eCurrentSelection ) + return; + + m_eCurrentSelection = _eType; + } + + void OGeneralPage::Reset(const SfxItemSet* _rCoreAttrs) + { + // reset all locale data + implSetCurrentType( OUString() ); + // this ensures that our type selection link will be called, even if the new one is the same as the + // current one + OGenericAdministrationPage::Reset(_rCoreAttrs); + } + + IMPL_LINK( OGeneralPageWizard, OnEmbeddedDBTypeSelected, weld::ComboBox&, _rBox, void ) + { + // get the type from the entry data + const sal_Int32 nSelected = _rBox.get_active(); + if (o3tl::make_unsigned(nSelected) >= m_aEmbeddedURLPrefixes.size() ) + { + SAL_WARN("dbaccess.ui.generalpage", "Got out-of-range value '" << nSelected << "' from the DatasourceType selection ListBox's GetSelectedEntryPos(): no corresponding URL prefix"); + return; + } + const OUString sURLPrefix = m_aEmbeddedURLPrefixes[ nSelected ]; + + setParentTitle( sURLPrefix ); + // let the impl method do all the stuff + onTypeSelected( sURLPrefix ); + // tell the listener we were modified + callModifiedHdl(); + } + + IMPL_LINK( OGeneralPage, OnDatasourceTypeSelected, weld::ComboBox&, _rBox, void ) + { + // get the type from the entry data + const sal_Int32 nSelected = _rBox.get_active(); + if (nSelected == -1) + return; + if (o3tl::make_unsigned(nSelected) >= m_aURLPrefixes.size() ) + { + SAL_WARN("dbaccess.ui.generalpage", "Got out-of-range value '" << nSelected << "' from the DatasourceType selection ListBox's GetSelectedEntryPos(): no corresponding URL prefix"); + return; + } + const OUString sURLPrefix = m_aURLPrefixes[ nSelected ]; + + setParentTitle( sURLPrefix ); + // let the impl method do all the stuff + onTypeSelected( sURLPrefix ); + // tell the listener we were modified + callModifiedHdl(); + } + + // OGeneralPageDialog + OGeneralPageDialog::OGeneralPageDialog(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rItems) + : OGeneralPage(pPage, pController, "dbaccess/ui/generalpagedialog.ui", _rItems) + { + } + + void OGeneralPageDialog::setParentTitle( const OUString& _sURLPrefix ) + { + const OUString sName = m_pCollection->getTypeDisplayName( _sURLPrefix ); + if ( m_pAdminDialog ) + { + OUString sMessage = DBA_RES(STR_PARENTTITLE_GENERAL); + m_pAdminDialog->setTitle( sMessage.replaceAll( "#", sName ) ); + } + } + + void OGeneralPageDialog::implInitControls( const SfxItemSet& _rSet, bool _bSaveValue ) + { + OGeneralPage::implInitControls( _rSet, _bSaveValue ); + + // first check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly ); + + m_xDatasourceType->set_sensitive( bValid ); + } + + bool OGeneralPageDialog::FillItemSet( SfxItemSet* _rCoreAttrs ) + { + bool bChangedSomething = false; + + const sal_Int32 nEntry = m_xDatasourceType->get_active(); + OUString sURLPrefix = m_aURLPrefixes[ nEntry ]; + + if (m_xDatasourceType->get_value_changed_from_saved()) + { + _rCoreAttrs->Put( SfxStringItem( DSID_CONNECTURL, sURLPrefix ) ); + bChangedSomething = true; + } + + return bChangedSomething; + } + + // OGeneralPageWizard + OGeneralPageWizard::OGeneralPageWizard(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rItems) + : OGeneralPage( pPage, pController, "dbaccess/ui/generalpagewizard.ui", _rItems ) + , m_xRB_CreateDatabase(m_xBuilder->weld_radio_button("createDatabase")) + , m_xRB_OpenExistingDatabase(m_xBuilder->weld_radio_button("openExistingDatabase")) + , m_xRB_ConnectDatabase(m_xBuilder->weld_radio_button("connectDatabase")) + , m_xFT_EmbeddedDBLabel(m_xBuilder->weld_label("embeddeddbLabel")) + , m_xEmbeddedDBType(m_xBuilder->weld_combo_box("embeddeddbList")) + , m_xFT_DocListLabel(m_xBuilder->weld_label("docListLabel")) + , m_xFT_HelpText(m_xBuilder->weld_label("helpText")) + , m_xLB_DocumentList(new OpenDocumentListBox(m_xBuilder->weld_combo_box("documentList"), "com.sun.star.sdb.OfficeDatabaseDocument")) + , m_xPB_OpenDatabase(new OpenDocumentButton(m_xBuilder->weld_button("openDatabase"), "com.sun.star.sdb.OfficeDatabaseDocument")) + , m_xFT_NoEmbeddedDBLabel(m_xBuilder->weld_label("noembeddeddbLabel")) + , m_eOriginalCreationMode(eCreateNew) + , m_bInitEmbeddedDBList(true) + , m_bIsDisplayedTypesEmpty(true) + { + // If no driver for embedded DBs is installed, and no dBase driver, then hide the "Create new database" option + sal_Int32 nCreateNewDBIndex = m_pCollection->getIndexOf( dbaccess::ODsnTypeCollection::getEmbeddedDatabase() ); + if ( nCreateNewDBIndex == -1 ) + nCreateNewDBIndex = m_pCollection->getIndexOf( u"sdbc:dbase:" ); + bool bHideCreateNew = ( nCreateNewDBIndex == -1 ); + + // also, if our application policies tell us to hide the option, do it + ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithComponentContext( + ::comphelper::getProcessComponentContext(), + "/org.openoffice.Office.DataAccess/Policies/Features/Base" + ) ); + bool bAllowCreateLocalDatabase( true ); + OSL_VERIFY( aConfig.getNodeValue( "CreateLocalDatabase" ) >>= bAllowCreateLocalDatabase ); + if ( !bAllowCreateLocalDatabase ) + bHideCreateNew = true; + + if ( bHideCreateNew ) + { + m_xRB_CreateDatabase->hide(); + m_xRB_ConnectDatabase->set_active(true); + } + else + m_xRB_CreateDatabase->set_active(true); + + // do some knittings + m_xEmbeddedDBType->connect_changed(LINK(this, OGeneralPageWizard, OnEmbeddedDBTypeSelected)); + m_xRB_CreateDatabase->connect_toggled( LINK( this, OGeneralPageWizard, OnSetupModeSelected ) ); + m_xRB_ConnectDatabase->connect_toggled( LINK( this, OGeneralPageWizard, OnSetupModeSelected ) ); + m_xRB_OpenExistingDatabase->connect_toggled( LINK( this, OGeneralPageWizard, OnSetupModeSelected ) ); + m_xLB_DocumentList->connect_changed( LINK( this, OGeneralPageWizard, OnDocumentSelected ) ); + m_xPB_OpenDatabase->connect_clicked( LINK( this, OGeneralPageWizard, OnOpenDocument ) ); + m_xFT_NoEmbeddedDBLabel->hide(); + + pController->SetGeneralPage(this); + } + + OGeneralPageWizard::~OGeneralPageWizard() + { + } + + OGeneralPageWizard::CreationMode OGeneralPageWizard::GetDatabaseCreationMode() const + { + if ( m_xRB_CreateDatabase->get_active() ) + return eCreateNew; + if ( m_xRB_ConnectDatabase->get_active() ) + return eConnectExternal; + return eOpenExisting; + } + + void OGeneralPageWizard::implInitControls( const SfxItemSet& _rSet, bool _bSaveValue ) + { + OGeneralPage::implInitControls( _rSet, _bSaveValue ); + + initializeEmbeddedDBList(); + m_xEmbeddedDBType->set_active_text(getEmbeddedDBName(_rSet)); + + if(m_bIsDisplayedTypesEmpty) + { + m_xRB_CreateDatabase->set_sensitive(false); + m_xFT_EmbeddedDBLabel->hide(); + m_xEmbeddedDBType->hide(); + m_xFT_NoEmbeddedDBLabel->show(); + m_xRB_OpenExistingDatabase->set_active(true); + } + + // first check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags( _rSet, bValid, bReadonly ); + + SetPageTitle(OUString()); + + if ( !bValid || bReadonly ) + { + m_xFT_EmbeddedDBLabel->set_sensitive( false ); + m_xDatasourceType->set_sensitive( false ); + m_xPB_OpenDatabase->set_sensitive( false ); + m_xFT_DocListLabel->set_sensitive( false ); + m_xLB_DocumentList->set_sensitive( false ); + } + + if (m_xLB_DocumentList->get_count()) + m_xLB_DocumentList->set_active(0); + + m_eOriginalCreationMode = GetDatabaseCreationMode(); + + SetupModeSelected(); + } + + OUString OGeneralPageWizard::getDatasourceName(const SfxItemSet& _rSet) + { + // Sets the default selected database on startup. + if (m_xRB_CreateDatabase->get_active() ) + { + return m_pCollection->getTypeDisplayName( u"sdbc:firebird:" ); + } + + return OGeneralPage::getDatasourceName( _rSet ); + } + + bool OGeneralPageWizard::approveDatasourceType( ::dbaccess::DATASOURCE_TYPE eType, OUString& _inout_rDisplayName ) + { + switch ( eType ) + { + case ::dbaccess::DST_MYSQL_JDBC: + case ::dbaccess::DST_MYSQL_ODBC: + case ::dbaccess::DST_MYSQL_NATIVE: + _inout_rDisplayName = "MySQL/MariaDB"; + break; + default: + break; + } + + return OGeneralPage::approveDatasourceType( eType, _inout_rDisplayName ); + } + + bool OGeneralPageWizard::FillItemSet(SfxItemSet* _rCoreAttrs) + { + bool bChangedSomething = false; + + bool bCommitTypeSelection = true; + + if ( m_xRB_CreateDatabase->get_active() ) + { + _rCoreAttrs->Put( SfxStringItem( DSID_CONNECTURL, "sdbc:dbase:" ) ); + bChangedSomething = true; + bCommitTypeSelection = false; + } + else if ( m_xRB_OpenExistingDatabase->get_active() ) + { + if ( m_xRB_OpenExistingDatabase->get_state_changed_from_saved() ) + bChangedSomething = true; + + // TODO + bCommitTypeSelection = false; + } + + if ( bCommitTypeSelection ) + { + const sal_Int32 nEntry = m_xDatasourceType->get_active(); + OUString sURLPrefix = m_aURLPrefixes[nEntry]; + + if ( m_xDatasourceType->get_value_changed_from_saved() + || ( GetDatabaseCreationMode() != m_eOriginalCreationMode ) + ) + { + _rCoreAttrs->Put( SfxStringItem( DSID_CONNECTURL,sURLPrefix ) ); + bChangedSomething = true; + } + else + implSetCurrentType( sURLPrefix ); + } + return bChangedSomething; + } + + OUString OGeneralPageWizard::GetSelectedDocumentURL() const + { + if ( !m_aBrowsedDocumentURL.isEmpty() ) + return m_aBrowsedDocumentURL; + else + return m_xLB_DocumentList->GetSelectedDocumentURL(); + } + + void OGeneralPageWizard::EnableControls() + { + bool bValid, bReadonly; + getFlags( GetItemSet(), bValid, bReadonly ); + if ( bValid && !bReadonly ) + { + m_xEmbeddedDBType->set_sensitive(m_xRB_CreateDatabase->get_active()); + m_xFT_EmbeddedDBLabel->set_sensitive(m_xRB_CreateDatabase->get_active()); + m_xDatasourceType->set_sensitive(m_xRB_ConnectDatabase->get_active()); + m_xPB_OpenDatabase->set_sensitive(m_xRB_OpenExistingDatabase->get_active()); + m_xFT_DocListLabel->set_sensitive(m_xRB_OpenExistingDatabase->get_active()); + m_xLB_DocumentList->set_sensitive(m_xRB_OpenExistingDatabase->get_active()); + } + } + + void OGeneralPageWizard::SetupModeSelected() + { + m_aCreationModeHandler.Call( *this ); + + if (m_xRB_CreateDatabase->get_active()) + OnEmbeddedDBTypeSelected(*m_xEmbeddedDBType); + else + OnDatasourceTypeSelected(*m_xDatasourceType); + + EnableControls(); + } + + IMPL_LINK(OGeneralPageWizard, OnSetupModeSelected, weld::Toggleable&, rButton, void) + { + if (!rButton.get_active()) + return; + SetupModeSelected(); + } + + IMPL_LINK_NOARG( OGeneralPageWizard, OnDocumentSelected, weld::ComboBox&, void ) + { + m_aDocumentSelectionHandler.Call( *this ); + } + + IMPL_LINK_NOARG( OGeneralPageWizard, OnOpenDocument, weld::Button&, void ) + { + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION, + FileDialogFlags::NONE, "sdatabase", SfxFilterFlags::NONE, SfxFilterFlags::NONE, GetFrameWeld()); + aFileDlg.SetContext(sfx2::FileDialogHelper::BaseDataSource); + std::shared_ptr<const SfxFilter> pFilter = getStandardDatabaseFilter(); + if ( pFilter ) + { + aFileDlg.SetCurrentFilter(pFilter->GetUIName()); + } + if ( aFileDlg.Execute() != ERRCODE_NONE ) + return; + + OUString sPath = aFileDlg.GetPath(); + // check for aFileDlg.GetCurrentFilter used to be here but current fpicker filter + // can be set to anything, see tdf#125267 how this breaks if other value + // than 'ODF Database' is selected. Let's therefore check only if wildcard matches + if ( !pFilter->GetWildcard().Matches(sPath) ) + { + OUString sMessage(DBA_RES(STR_ERR_USE_CONNECT_TO)); + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + sMessage)); + xInfoBox->run(); + m_xRB_ConnectDatabase->set_active(true); + OnSetupModeSelected( *m_xRB_ConnectDatabase ); + return; + } + m_aBrowsedDocumentURL = sPath; + m_aChooseDocumentHandler.Call( *this ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/generalpage.hxx b/dbaccess/source/ui/dlg/generalpage.hxx new file mode 100644 index 000000000..1abda980e --- /dev/null +++ b/dbaccess/source/ui/dlg/generalpage.hxx @@ -0,0 +1,189 @@ +/* -*- 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 "adminpages.hxx" +#include <opendoccontrols.hxx> + +namespace dbaui +{ + class ODbTypeWizDialogSetup; + + // OGeneralPage + class OGeneralPage : public OGenericAdministrationPage + { + protected: + OGeneralPage(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const SfxItemSet& _rItems); + + OUString m_eCurrentSelection; /// currently selected type + + private: + std::unique_ptr<weld::Label> m_xSpecialMessage; + + enum SPECIAL_MESSAGE + { + smNone, + smUnsupportedType + }; + SPECIAL_MESSAGE m_eLastMessage; + + Link<OGeneralPage&,void> m_aTypeSelectHandler; /// to be called if a new type is selected + bool m_bInitTypeList : 1; + bool approveDatasourceType( std::u16string_view _sURLPrefix, OUString& _inout_rDisplayName ); + void insertDatasourceTypeEntryData( const OUString& _sType, const OUString& sDisplayName ); + + protected: + std::unique_ptr<weld::ComboBox> m_xDatasourceType; + + ::dbaccess::ODsnTypeCollection* + m_pCollection; /// the DSN type collection instance + + std::vector< OUString> + m_aURLPrefixes; + + public: + virtual ~OGeneralPage() override; + + /// set a handler which gets called every time the user selects a new type + void SetTypeSelectHandler( const Link<OGeneralPage&,void>& _rHandler ) { m_aTypeSelectHandler = _rHandler; } + + /// get the currently selected datasource type + const OUString& GetSelectedType() const { return m_eCurrentSelection; } + + protected: + // SfxTabPage overridables + virtual void Reset( const SfxItemSet* _rCoreAttrs ) override; + + virtual void implInitControls( const SfxItemSet& _rSet, bool _bSaveValue ) override; + virtual OUString getDatasourceName( const SfxItemSet& _rSet ); + virtual bool approveDatasourceType( ::dbaccess::DATASOURCE_TYPE eType, OUString& _inout_rDisplayName ); + + // <method>OGenericAdministrationPage::fillControls</method> + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + // <method>OGenericAdministrationPage::fillWindows</method> + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + + void onTypeSelected(const OUString& _sURLPrefix); + + /** + * Initializes the listbox, which contains entries each representing a + * connection to an existing database. + */ + void initializeTypeList(); + + void implSetCurrentType( const OUString& _eType ); + + void switchMessage(std::u16string_view _sURLPrefix); + + /// sets the title of the parent dialog + virtual void setParentTitle( const OUString& _sURLPrefix ); + + DECL_LINK(OnDatasourceTypeSelected, weld::ComboBox&, void); + }; + + // OGeneralPageDialog + class OGeneralPageDialog : public OGeneralPage + { + public: + OGeneralPageDialog(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rItems); + + protected: + virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override; + + virtual void implInitControls( const SfxItemSet& _rSet, bool _bSaveValue ) override; + virtual void setParentTitle( const OUString& _sURLPrefix ) override; + }; + + // OGeneralPageWizard + class OGeneralPageWizard final : public OGeneralPage + { + public: + OGeneralPageWizard( weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rItems ); + virtual ~OGeneralPageWizard() override; + + enum CreationMode + { + eCreateNew, + eConnectExternal, + eOpenExisting + }; + + private: + // dialog controls + std::unique_ptr<weld::RadioButton> m_xRB_CreateDatabase; + std::unique_ptr<weld::RadioButton> m_xRB_OpenExistingDatabase; + std::unique_ptr<weld::RadioButton> m_xRB_ConnectDatabase; + + std::unique_ptr<weld::Label> m_xFT_EmbeddedDBLabel; + std::unique_ptr<weld::ComboBox> m_xEmbeddedDBType; + + std::unique_ptr<weld::Label> m_xFT_DocListLabel; + std::unique_ptr<weld::Label> m_xFT_HelpText; + std::unique_ptr<OpenDocumentListBox> m_xLB_DocumentList; + std::unique_ptr<OpenDocumentButton> m_xPB_OpenDatabase; + + std::unique_ptr<weld::Label> m_xFT_NoEmbeddedDBLabel; + + // state + OUString m_aBrowsedDocumentURL; + CreationMode m_eOriginalCreationMode; + + Link<OGeneralPageWizard&,void> m_aCreationModeHandler; /// to be called if a new type is selected + Link<OGeneralPageWizard&,void> m_aDocumentSelectionHandler; /// to be called when a document in the RecentDoc list is selected + Link<OGeneralPageWizard&,void> m_aChooseDocumentHandler; /// to be called when a recent document has been definitely chosen + + bool m_bInitEmbeddedDBList : 1; + bool m_bIsDisplayedTypesEmpty : 1; + void insertEmbeddedDBTypeEntryData( const OUString& _sType, const OUString& sDisplayName ); + + void EnableControls(); + + public: + void SetCreationModeHandler( const Link<OGeneralPageWizard&,void>& _rHandler ) { m_aCreationModeHandler = _rHandler; } + CreationMode GetDatabaseCreationMode() const; + + void SetDocumentSelectionHandler( const Link<OGeneralPageWizard&,void>& _rHandler) { m_aDocumentSelectionHandler = _rHandler; } + void SetChooseDocumentHandler( const Link<OGeneralPageWizard&,void>& _rHandler) { m_aChooseDocumentHandler = _rHandler; } + OUString GetSelectedDocumentURL() const; + + private: + virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override; + + virtual void implInitControls( const SfxItemSet& _rSet, bool _bSaveValue ) override; + virtual OUString getDatasourceName( const SfxItemSet& _rSet ) override; + virtual bool approveDatasourceType( ::dbaccess::DATASOURCE_TYPE eType, OUString& _inout_rDisplayName ) override; + + std::vector< OUString> + m_aEmbeddedURLPrefixes; + + OUString getEmbeddedDBName( const SfxItemSet& _rSet ); + void initializeEmbeddedDBList(); + + void SetupModeSelected(); + + DECL_LINK( OnEmbeddedDBTypeSelected, weld::ComboBox&, void ); + DECL_LINK( OnSetupModeSelected, weld::Toggleable&, void ); + DECL_LINK( OnDocumentSelected, weld::ComboBox&, void ); + DECL_LINK( OnOpenDocument, weld::Button&, void ); + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/indexdialog.cxx b/dbaccess/source/ui/dlg/indexdialog.cxx new file mode 100644 index 000000000..4c9312848 --- /dev/null +++ b/dbaccess/source/ui/dlg/indexdialog.cxx @@ -0,0 +1,707 @@ +/* -*- 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 <set> + +#include <core_resource.hxx> +#include <indexdialog.hxx> +#include <strings.hrc> +#include <bitmaps.hlst> +#include <indexfieldscontrol.hxx> +#include <indexcollection.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <connectivity/dbtools.hxx> +#include <osl/diagnose.h> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::lang; + using namespace ::dbtools; + + // helper + static bool operator ==(const OIndexField& _rLHS, const OIndexField& _rRHS) + { + return (_rLHS.sFieldName == _rRHS.sFieldName) + && (_rLHS.bSortAscending == _rRHS.bSortAscending); + } + + static bool operator ==(const IndexFields& _rLHS, const IndexFields& _rRHS) + { + return std::equal(_rLHS.begin(), _rLHS.end(), _rRHS.begin(), _rRHS.end()); + } + + static bool operator !=(const IndexFields& _rLHS, const IndexFields& _rRHS) + { + return !(_rLHS == _rRHS); + } + + // DbaIndexDialog + DbaIndexDialog::DbaIndexDialog(weld::Window* pParent, const Sequence< OUString >& _rFieldNames, + const Reference< XNameAccess >& _rxIndexes, + const Reference< XConnection >& _rxConnection, + const Reference< XComponentContext >& _rxContext) + : GenericDialogController(pParent, "dbaccess/ui/indexdesigndialog.ui", "IndexDesignDialog") + , m_xConnection(_rxConnection) + , m_bEditingActive(false) + , m_bEditAgain(false) + , m_bNoHandlerCall(false) + , m_xContext(_rxContext) + , m_xActions(m_xBuilder->weld_toolbar("ACTIONS")) + , m_xIndexList(m_xBuilder->weld_tree_view("INDEX_LIST")) + , m_xIndexDetails(m_xBuilder->weld_label("INDEX_DETAILS")) + , m_xDescriptionLabel(m_xBuilder->weld_label("DESC_LABEL")) + , m_xDescription(m_xBuilder->weld_label("DESCRIPTION")) + , m_xUnique(m_xBuilder->weld_check_button("UNIQUE")) + , m_xFieldsLabel(m_xBuilder->weld_label("FIELDS_LABEL")) + , m_xClose(m_xBuilder->weld_button("close")) + , m_xTable(m_xBuilder->weld_container("FIELDS")) + , m_xTableCtrlParent(m_xTable->CreateChildFrame()) + , m_xFields(VclPtr<IndexFieldsControl>::Create(m_xTableCtrlParent)) + { + m_xIndexList->set_size_request(m_xIndexList->get_approximate_digit_width() * 17, + m_xIndexList->get_height_rows(12)); + + int nWidth = m_xIndexList->get_approximate_digit_width() * 60; + int nHeight = m_xIndexList->get_height_rows(8); + m_xTable->set_size_request(nWidth, nHeight); + + m_xActions->connect_clicked(LINK(this, DbaIndexDialog, OnIndexAction)); + + m_xIndexList->connect_changed(LINK(this, DbaIndexDialog, OnIndexSelected)); + m_xIndexList->connect_editing(LINK(this, DbaIndexDialog, OnEntryEditing), + LINK(this, DbaIndexDialog, OnEntryEdited)); + + m_xFields->SetSizePixel(Size(nWidth, 100)); + m_xFields->Init(_rFieldNames, ::dbtools::getBooleanDataSourceSetting( m_xConnection, "AddIndexAppendix" )); + m_xFields->Show(); + + m_xIndexes.reset(new OIndexCollection()); + try + { + m_xIndexes->attach(_rxIndexes); + } + catch(SQLException& e) + { + ::dbtools::showError(SQLExceptionInfo(e), pParent->GetXWindow(), _rxContext); + } + catch(Exception&) + { + OSL_FAIL("DbaIndexDialog::DbaIndexDialog: could not retrieve basic information from the UNO collection!"); + } + + fillIndexList(); + + m_xUnique->connect_toggled(LINK(this, DbaIndexDialog, OnModifiedClick)); + m_xFields->SetModifyHdl(LINK(this, DbaIndexDialog, OnModified)); + + m_xClose->connect_clicked(LINK(this, DbaIndexDialog, OnCloseDialog)); + + // if all of the indexes have an empty description, we're not interested in displaying it + bool bFound = false; + for (auto const& check : *m_xIndexes) + { + if (!check.sDescription.isEmpty()) + { + bFound = true; + break; + } + } + if (!bFound) + { + // hide the controls which are necessary for the description + m_xDescription->hide(); + m_xDescriptionLabel->hide(); + } + } + + void DbaIndexDialog::updateToolbox() + { + m_xActions->set_item_sensitive("ID_INDEX_NEW", !m_bEditingActive); + + int nSelected = m_xIndexList->get_selected_index(); + bool bSelectedAnything = nSelected != -1; + if (bSelectedAnything) + { + // is the current entry modified? + Indexes::const_iterator aSelectedPos = m_xIndexes->begin() + m_xIndexList->get_id(nSelected).toUInt32(); + m_xActions->set_item_sensitive("ID_INDEX_SAVE", aSelectedPos->isModified() || aSelectedPos->isNew()); + m_xActions->set_item_sensitive("ID_INDEX_RESET", aSelectedPos->isModified() || aSelectedPos->isNew()); + bSelectedAnything = !aSelectedPos->bPrimaryKey; + } + else + { + m_xActions->set_item_sensitive("ID_INDEX_SAVE", false); + m_xActions->set_item_sensitive("ID_INDEX_RESET", false); + } + m_xActions->set_item_sensitive("ID_INDEX_DROP", bSelectedAnything); + m_xActions->set_item_sensitive("ID_INDEX_RENAME", bSelectedAnything); + } + + void DbaIndexDialog::fillIndexList() + { + OUString aPKeyIcon(BMP_PKEYICON); + // fill the list with the index names + m_xIndexList->clear(); + sal_uInt32 nPos = 0; + for (auto const& indexLoop : *m_xIndexes) + { + m_xIndexList->append(OUString::number(nPos), indexLoop.sName); + if (indexLoop.bPrimaryKey) + m_xIndexList->set_image(nPos, aPKeyIcon); + ++nPos; + } + + if (nPos) + m_xIndexList->select(0); + + IndexSelected(); + } + + DbaIndexDialog::~DbaIndexDialog( ) + { + m_xIndexes.reset(); + m_xFields.disposeAndClear(); + m_xTableCtrlParent->dispose(); + m_xTableCtrlParent.clear(); + } + + bool DbaIndexDialog::implCommit(const weld::TreeIter* pEntry) + { + assert(pEntry && "DbaIndexDialog::implCommit: invalid entry!"); + + Indexes::iterator aCommitPos = m_xIndexes->begin() + m_xIndexList->get_id(*pEntry).toUInt32(); + + // if it's not a new index, remove it + // (we can't modify indexes, only drop'n'insert) + if (!aCommitPos->isNew()) + if (!implDropIndex(pEntry, false)) + return false; + + // create the new index + SQLExceptionInfo aExceptionInfo; + try + { + m_xIndexes->commitNewIndex(aCommitPos); + } + catch(SQLContext& e) { aExceptionInfo = SQLExceptionInfo(e); } + catch(SQLWarning& e) { aExceptionInfo = SQLExceptionInfo(e); } + catch(SQLException& e) { aExceptionInfo = SQLExceptionInfo(e); } + + // reflect the new selection in the toolbox + updateToolbox(); + + if (aExceptionInfo.isValid()) + showError(aExceptionInfo, m_xDialog->GetXWindow(), m_xContext); + else + { + m_xUnique->save_state(); + m_xFields->SaveValue(); + } + + return !aExceptionInfo.isValid(); + } + + void DbaIndexDialog::OnNewIndex() + { + // commit the current entry, if necessary + if (!implCommitPreviouslySelected()) + return; + + // get a new unique name for the new index + OUString sNewIndexName; + const OUString sNewIndexNameBase(DBA_RES(STR_LOGICAL_INDEX_NAME)); + sal_Int32 i; + + for ( i = 1; i < 0x7FFFFFFF; ++i ) + { + sNewIndexName = sNewIndexNameBase + OUString::number(i); + if (m_xIndexes->end() == m_xIndexes->find(sNewIndexName)) + break; + } + if (i == 0x7FFFFFFF) + { + OSL_FAIL("DbaIndexDialog::OnNewIndex: no free index name found!"); + // can't do anything ... of course we try another base, but this could end with the same result ... + return; + } + + std::unique_ptr<weld::TreeIter> xNewEntry(m_xIndexList->make_iterator()); + m_xIndexList->insert(nullptr, -1, &sNewIndexName, nullptr, nullptr, nullptr, false, xNewEntry.get()); + m_xIndexes->insert(sNewIndexName); + + // update the user data on the entries in the list box: + // they're iterators of the index collection, and thus they have changed when removing the index + m_xIndexList->all_foreach([this](weld::TreeIter& rEntry){ + Indexes::const_iterator aAfterInsertPos = m_xIndexes->find(m_xIndexList->get_text(rEntry)); + OSL_ENSURE(aAfterInsertPos != m_xIndexes->end(), "DbaIndexDialog::OnNewIndex: problems with one of the entries!"); + m_xIndexList->set_id(rEntry, OUString::number(aAfterInsertPos - m_xIndexes->begin())); + return false; + }); + + // select the entry and start in-place editing + m_bNoHandlerCall = true; + m_xIndexList->select(*xNewEntry); + m_bNoHandlerCall = false; + IndexSelected(); + m_xIndexList->grab_focus(); + m_xIndexList->start_editing(*xNewEntry); + updateToolbox(); + } + + void DbaIndexDialog::OnDropIndex(bool _bConfirm) + { + std::unique_ptr<weld::TreeIter> xSelected(m_xIndexList->make_iterator()); + // the selected index + if (!m_xIndexList->get_selected(xSelected.get())) + return; + + // let the user confirm the drop + if (_bConfirm) + { + OUString sConfirm(DBA_RES(STR_CONFIRM_DROP_INDEX)); + sConfirm = sConfirm.replaceFirst("$name$", m_xIndexList->get_text(*xSelected)); + std::unique_ptr<weld::MessageDialog> xConfirm(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Question, VclButtonsType::YesNo, + sConfirm)); + if (RET_YES != xConfirm->run()) + return; + } + + // do the drop + implDropIndex(xSelected.get(), true); + + // reflect the new selection in the toolbox + updateToolbox(); + } + + bool DbaIndexDialog::implDropIndex(const weld::TreeIter* pEntry, bool _bRemoveFromCollection) + { + // do the drop + Indexes::iterator aDropPos = m_xIndexes->begin() + m_xIndexList->get_id(*pEntry).toUInt32(); + OSL_ENSURE(aDropPos != m_xIndexes->end(), "DbaIndexDialog::OnDropIndex: did not find the index in my collection!"); + + SQLExceptionInfo aExceptionInfo; + bool bSuccess = false; + try + { + if (_bRemoveFromCollection) + bSuccess = m_xIndexes->drop(aDropPos); + else + bSuccess = m_xIndexes->dropNoRemove(aDropPos); + } + catch(SQLContext& e) { aExceptionInfo = SQLExceptionInfo(e); } + catch(SQLWarning& e) { aExceptionInfo = SQLExceptionInfo(e); } + catch(SQLException& e) { aExceptionInfo = SQLExceptionInfo(e); } + + if (aExceptionInfo.isValid()) + showError(aExceptionInfo, m_xDialog->GetXWindow(), m_xContext); + else if (bSuccess && _bRemoveFromCollection) + { + m_bNoHandlerCall = true; + + // if the entry to remove is the selected on... + if (m_xPreviousSelection && m_xPreviousSelection->equal(*pEntry)) + m_xPreviousSelection.reset(); + m_xIndexList->remove(*pEntry); + + m_bNoHandlerCall = false; + + // update the user data on the entries in the list box: + // they're iterators of the index collection, and thus they have changed when removing the index + m_xIndexList->all_foreach([this](weld::TreeIter& rEntry){ + Indexes::const_iterator aAfterDropPos = m_xIndexes->find(m_xIndexList->get_text(rEntry)); + OSL_ENSURE(aAfterDropPos != m_xIndexes->end(), "DbaIndexDialog::OnDropIndex: problems with one of the remaining entries!"); + m_xIndexList->set_id(rEntry, OUString::number(aAfterDropPos - m_xIndexes->begin())); + return false; + }); + + // the Remove automatically selected another entry (if possible), but we disabled the calling of the handler + // to prevent that we missed something... call the handler directly + IndexSelected(); + } + + return !aExceptionInfo.isValid(); + } + + void DbaIndexDialog::OnRenameIndex() + { + // the selected iterator + std::unique_ptr<weld::TreeIter> xSelected(m_xIndexList->make_iterator()); + if (!m_xIndexList->get_selected(xSelected.get())) + return; + + // save the changes made 'til here + // Upon leaving the edit mode, the control will be re-initialized with the + // settings from the current entry + implSaveModified(false); + + m_xIndexList->grab_focus(); + m_xIndexList->start_editing(*xSelected); + updateToolbox(); + } + + void DbaIndexDialog::OnSaveIndex() + { + // the selected index + implCommitPreviouslySelected(); + updateToolbox(); + } + + void DbaIndexDialog::OnResetIndex() + { + // the selected index + std::unique_ptr<weld::TreeIter> xSelected(m_xIndexList->make_iterator()); + // the selected index + if (!m_xIndexList->get_selected(xSelected.get())) + xSelected.reset(); + OSL_ENSURE(xSelected, "DbaIndexDialog::OnResetIndex: invalid call!"); + if (!xSelected) + return; + + Indexes::iterator aResetPos = m_xIndexes->begin() + m_xIndexList->get_id(*xSelected).toUInt32(); + + if (aResetPos->isNew()) + { + OnDropIndex(false); + return; + } + + SQLExceptionInfo aExceptionInfo; + try + { + m_xIndexes->resetIndex(aResetPos); + } + catch(SQLContext& e) { aExceptionInfo = SQLExceptionInfo(e); } + catch(SQLWarning& e) { aExceptionInfo = SQLExceptionInfo(e); } + catch(SQLException& e) { aExceptionInfo = SQLExceptionInfo(e); } + + if (aExceptionInfo.isValid()) + showError(aExceptionInfo, m_xDialog->GetXWindow(), m_xContext); + else + m_xIndexList->set_text(*xSelected, aResetPos->sName); + + updateControls(xSelected.get()); + updateToolbox(); + } + + IMPL_LINK(DbaIndexDialog, OnIndexAction, const OString&, rClicked, void) + { + if (rClicked == "ID_INDEX_NEW") + OnNewIndex(); + else if (rClicked == "ID_INDEX_DROP") + OnDropIndex(); + else if (rClicked == "ID_INDEX_RENAME") + OnRenameIndex(); + else if (rClicked == "ID_INDEX_SAVE") + OnSaveIndex(); + else if (rClicked == "ID_INDEX_RESET") + OnResetIndex(); + } + + IMPL_LINK_NOARG(DbaIndexDialog, OnCloseDialog, weld::Button&, void) + { + if (m_bEditingActive) + { + OSL_ENSURE(!m_bEditAgain, "DbaIndexDialog::OnCloseDialog: somebody was faster than hell!"); + // this means somebody entered a new name, which was invalid, which cause us to posted us an event, + // and before the event arrived the user clicked onto "close". VERY fast, this user... + m_xIndexList->end_editing(); + if (m_bEditAgain) + // could not commit the new name (started a new - asynchronous - edit trial) + return; + } + + // the currently selected entry + std::unique_ptr<weld::TreeIter> xSelected(m_xIndexList->make_iterator()); + // the selected index + if (!m_xIndexList->get_selected(xSelected.get())) + xSelected.reset(); + + OSL_ENSURE(xSelected && m_xPreviousSelection && xSelected->equal(*m_xPreviousSelection), "DbaIndexDialog::OnCloseDialog: inconsistence!"); + + sal_Int32 nResponse = RET_NO; + if (xSelected) + { + // the descriptor + Indexes::const_iterator aSelected = m_xIndexes->begin() + m_xIndexList->get_id(*xSelected).toUInt32(); + if (aSelected->isModified() || aSelected->isNew()) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xDialog.get(), "dbaccess/ui/saveindexdialog.ui")); + std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("SaveIndexDialog")); + nResponse = xQuery->run(); + } + } + + switch (nResponse) + { + case RET_YES: + if (!implCommitPreviouslySelected()) + return; + break; + case RET_NO: + break; + default: + return; + } + + m_xDialog->response(RET_OK); + } + + IMPL_LINK(DbaIndexDialog, OnEditIndexAgain, void*, p, void) + { + weld::TreeIter* pEntry = static_cast<weld::TreeIter*>(p); + m_bEditAgain = false; + m_xIndexList->grab_focus(); + m_xIndexList->start_editing(*pEntry); + delete pEntry; + } + + IMPL_LINK_NOARG(DbaIndexDialog, OnEntryEditing, const weld::TreeIter&, bool) + { + m_bEditingActive = true; + return true; + } + + IMPL_LINK(DbaIndexDialog, OnEntryEdited, const IterString&, rIterString, bool) + { + m_bEditingActive = false; + + const weld::TreeIter& rEntry = rIterString.first; + OUString sNewName = rIterString.second; + + Indexes::iterator aPosition = m_xIndexes->begin() + m_xIndexList->get_id(rEntry).toUInt32(); + + OSL_ENSURE(aPosition >= m_xIndexes->begin() && aPosition < m_xIndexes->end(), + "DbaIndexDialog::OnEntryEdited: invalid entry!"); + + Indexes::const_iterator aSameName = m_xIndexes->find(sNewName); + if (aSameName != aPosition && m_xIndexes->end() != aSameName) + { + OUString sError(DBA_RES(STR_INDEX_NAME_ALREADY_USED)); + sError = sError.replaceFirst("$name$", sNewName); + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, + sError)); + xError->run(); + + updateToolbox(); + m_bEditAgain = true; + std::unique_ptr<weld::TreeIter> xEntry(m_xIndexList->make_iterator(&rEntry)); + Application::PostUserEvent(LINK(this, DbaIndexDialog, OnEditIndexAgain), xEntry.release()); + return false; + } + + aPosition->sName = sNewName; + + // rename can be done by a drop/insert combination only + if (aPosition->isNew()) + { + updateToolbox(); + // no commitment needed here... + return true; + } + + if (aPosition->sName != aPosition->getOriginalName()) + { + aPosition->setModified(true); + updateToolbox(); + } + + return true; + } + + bool DbaIndexDialog::implSaveModified(bool _bPlausibility) + { + if (!m_xPreviousSelection) + return true; + + // try to commit the previously selected index + if (m_xFields->IsModified() && !m_xFields->SaveModified()) + return false; + + Indexes::iterator aPreviouslySelected = m_xIndexes->begin() + m_xIndexList->get_id(*m_xPreviousSelection).toUInt32(); + + // the unique flag + aPreviouslySelected->bUnique = m_xUnique->get_active(); + if (m_xUnique->get_state_changed_from_saved()) + aPreviouslySelected->setModified(true); + + // the fields + m_xFields->commitTo(aPreviouslySelected->aFields); + if (m_xFields->GetSavedValue() != aPreviouslySelected->aFields) + aPreviouslySelected->setModified(true); + + // plausibility checks + if (_bPlausibility && !implCheckPlausibility(aPreviouslySelected)) + return false; + + return true; + } + + bool DbaIndexDialog::implCheckPlausibility(const Indexes::const_iterator& _rPos) + { + // need at least one field + if (_rPos->aFields.empty()) + { + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, + DBA_RES(STR_NEED_INDEX_FIELDS))); + xError->run(); + m_xFields->GrabFocus(); + return false; + } + + // no double fields + std::set< OUString > aExistentFields; + for (auto const& fieldCheck : _rPos->aFields) + { + if (aExistentFields.end() != aExistentFields.find(fieldCheck.sFieldName)) + { + // a column is specified twice ... won't work anyway, so prevent this here and now + OUString sMessage(DBA_RES(STR_INDEXDESIGN_DOUBLE_COLUMN_NAME)); + sMessage = sMessage.replaceFirst("$name$", fieldCheck.sFieldName); + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, + sMessage)); + xError->run(); + m_xFields->GrabFocus(); + return false; + } + aExistentFields.insert(fieldCheck.sFieldName); + } + + return true; + } + + bool DbaIndexDialog::implCommitPreviouslySelected() + { + if (m_xPreviousSelection) + { + Indexes::const_iterator aPreviouslySelected = m_xIndexes->begin() + m_xIndexList->get_id(*m_xPreviousSelection).toUInt32(); + + if (!implSaveModified()) + return false; + + // commit the index (if necessary) + if (aPreviouslySelected->isModified() && !implCommit(m_xPreviousSelection.get())) + return false; + } + + return true; + } + + IMPL_LINK_NOARG(DbaIndexDialog, OnModifiedClick, weld::Toggleable&, void) + { + OnModified(*m_xFields); + } + + IMPL_LINK_NOARG( DbaIndexDialog, OnModified, IndexFieldsControl&, void ) + { + assert(m_xPreviousSelection && "DbaIndexDialog, OnModified: invalid call!"); + Indexes::iterator aPosition = m_xIndexes->begin() + m_xIndexList->get_id(*m_xPreviousSelection).toUInt32(); + + aPosition->setModified(true); + updateToolbox(); + } + + void DbaIndexDialog::updateControls(const weld::TreeIter* pEntry) + { + if (pEntry) + { + // the descriptor of the selected index + Indexes::const_iterator aSelectedIndex = m_xIndexes->begin() + m_xIndexList->get_id(*pEntry).toUInt32(); + + // fill the controls + m_xUnique->set_active(aSelectedIndex->bUnique); + m_xUnique->set_sensitive(!aSelectedIndex->bPrimaryKey); + m_xUnique->save_state(); + + m_xFields->initializeFrom(std::vector(aSelectedIndex->aFields)); + m_xFields->Enable(!aSelectedIndex->bPrimaryKey); + m_xFields->SaveValue(); + + m_xDescription->set_label(aSelectedIndex->sDescription); + m_xDescription->set_sensitive(!aSelectedIndex->bPrimaryKey); + + m_xDescriptionLabel->set_sensitive(!aSelectedIndex->bPrimaryKey); + } + else + { + m_xUnique->set_active(false); + m_xFields->initializeFrom(IndexFields()); + m_xDescription->set_label(OUString()); + } + } + + void DbaIndexDialog::IndexSelected() + { + if (m_bEditingActive) + m_xIndexList->end_editing(); + + std::unique_ptr<weld::TreeIter> xSelected(m_xIndexList->make_iterator()); + if (!m_xIndexList->get_selected(xSelected.get())) + xSelected.reset(); + + // commit the old data + if (m_xPreviousSelection && (!xSelected || !m_xPreviousSelection->equal(*xSelected))) + { + // (this call may happen in case somebody ended an in-place edit with 'return', so we need to check this before committing) + if (!implCommitPreviouslySelected()) + { + m_bNoHandlerCall = true; + m_xIndexList->select(*m_xPreviousSelection); + m_bNoHandlerCall = false; + return; + } + } + + // disable/enable the detail controls + m_xIndexDetails->set_sensitive(xSelected != nullptr); + m_xUnique->set_sensitive(xSelected != nullptr); + m_xDescriptionLabel->set_sensitive(xSelected != nullptr); + m_xFieldsLabel->set_sensitive(xSelected != nullptr); + m_xFields->Enable(xSelected != nullptr); + + updateControls(xSelected.get()); + if (xSelected) + m_xIndexList->grab_focus(); + + m_xPreviousSelection = std::move(xSelected); + + updateToolbox(); + } + + IMPL_LINK_NOARG(DbaIndexDialog, OnIndexSelected, weld::TreeView&, void) + { + if (m_bNoHandlerCall) + return; + IndexSelected(); + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/indexfieldscontrol.cxx b/dbaccess/source/ui/dlg/indexfieldscontrol.cxx new file mode 100644 index 000000000..35b0e3f02 --- /dev/null +++ b/dbaccess/source/ui/dlg/indexfieldscontrol.cxx @@ -0,0 +1,447 @@ +/* -*- 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 <core_resource.hxx> +#include <indexfieldscontrol.hxx> +#include <strings.hrc> +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> +#include <helpids.h> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> + +namespace dbaui +{ + +constexpr auto BROWSER_STANDARD_FLAGS = BrowserMode::COLUMNSELECTION | BrowserMode::HLINES | BrowserMode::VLINES | + BrowserMode::HIDECURSOR | BrowserMode::HIDESELECT | BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL; + +#define COLUMN_ID_FIELDNAME 1 +#define COLUMN_ID_ORDER 2 + + using namespace ::com::sun::star::uno; + using namespace ::svt; + + // DbaMouseDownListBoxController + class DbaMouseDownListBoxController : public ListBoxCellController + { + protected: + Link<DbaMouseDownListBoxController&,void> m_aAdditionalModifyHdl; + + public: + explicit DbaMouseDownListBoxController(ListBoxControl* _pParent) + :ListBoxCellController(_pParent) + { + } + + void SetAdditionalModifyHdl(const Link<DbaMouseDownListBoxController&,void>& _rHdl); + + protected: + virtual void callModifyHdl() override; + }; + + void DbaMouseDownListBoxController::SetAdditionalModifyHdl(const Link<DbaMouseDownListBoxController&,void>& _rHdl) + { + m_aAdditionalModifyHdl = _rHdl; + } + + void DbaMouseDownListBoxController::callModifyHdl() + { + m_aAdditionalModifyHdl.Call(*this); + ListBoxCellController::callModifyHdl(); + } + + // IndexFieldsControl + IndexFieldsControl::IndexFieldsControl(const css::uno::Reference<css::awt::XWindow> &rParent) + : EditBrowseBox(VCLUnoHelper::GetWindow(rParent), EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::ACTIVATE_ON_BUTTONDOWN, WB_TABSTOP | WB_BORDER, BROWSER_STANDARD_FLAGS) + , m_aSeekRow(m_aFields.end()) + , m_pSortingCell(nullptr) + , m_pFieldNameCell(nullptr) + , m_bAddIndexAppendix(false) + { + } + + IndexFieldsControl::~IndexFieldsControl() + { + disposeOnce(); + } + + void IndexFieldsControl::dispose() + { + m_pSortingCell.disposeAndClear(); + m_pFieldNameCell.disposeAndClear(); + ::svt::EditBrowseBox::dispose(); + } + + bool IndexFieldsControl::SeekRow(sal_Int32 nRow) + { + if (!EditBrowseBox::SeekRow(nRow)) + return false; + + if (nRow < 0) + { + m_aSeekRow = m_aFields.end(); + } + else + { + m_aSeekRow = m_aFields.begin() + nRow; + OSL_ENSURE(m_aSeekRow <= m_aFields.end(), "IndexFieldsControl::SeekRow: invalid row!"); + } + + return true; + } + + void IndexFieldsControl::PaintCell( OutputDevice& _rDev, const tools::Rectangle& _rRect, sal_uInt16 _nColumnId ) const + { + Point aPos(_rRect.TopLeft()); + aPos.AdjustX(1 ); + + OUString aText = GetRowCellText(m_aSeekRow,_nColumnId); + Size TxtSize(GetDataWindow().GetTextWidth(aText), GetDataWindow().GetTextHeight()); + + // clipping + if (aPos.X() < _rRect.Right() || aPos.X() + TxtSize.Width() > _rRect.Right() || + aPos.Y() < _rRect.Top() || aPos.Y() + TxtSize.Height() > _rRect.Bottom()) + _rDev.SetClipRegion(vcl::Region(_rRect)); + + // allow for a disabled control ... + bool bEnabled = IsEnabled(); + Color aOriginalColor = _rDev.GetTextColor(); + if (!bEnabled) + _rDev.SetTextColor(GetSettings().GetStyleSettings().GetDisableColor()); + + // draw the text + _rDev.DrawText(aPos, aText); + + // reset the color (if necessary) + if (!bEnabled) + _rDev.SetTextColor(aOriginalColor); + + if (_rDev.IsClipRegion()) + _rDev.SetClipRegion(); + } + + void IndexFieldsControl::initializeFrom(IndexFields&& _rFields) + { + // copy the field descriptions + m_aFields = std::move(_rFields); + m_aSeekRow = m_aFields.end(); + + SetUpdateMode(false); + // remove all rows + RowRemoved(1, GetRowCount()); + // insert rows for the fields + RowInserted(GetRowCount(), m_aFields.size(), false); + // insert an additional row for a new field for that index + RowInserted(GetRowCount(), 1, false); + SetUpdateMode(true); + + GoToRowColumnId(0, COLUMN_ID_FIELDNAME); + } + + void IndexFieldsControl::commitTo(IndexFields& _rFields) + { + // do not just copy the array, we may have empty field names (which should not be copied) + _rFields.resize(m_aFields.size()); + IndexFields::iterator aDest = std::copy_if(m_aFields.begin(), m_aFields.end(), _rFields.begin(), + [](const OIndexField& source) { return !source.sFieldName.isEmpty(); }); + + _rFields.resize(aDest - _rFields.begin()); + } + + sal_uInt32 IndexFieldsControl::GetTotalCellWidth(sal_Int32 _nRow, sal_uInt16 _nColId) + { + if (COLUMN_ID_ORDER == _nColId) + { + sal_Int32 nWidthAsc = GetTextWidth(m_sAscendingText) + GetSettings().GetStyleSettings().GetScrollBarSize(); + sal_Int32 nWidthDesc = GetTextWidth(m_sDescendingText) + GetSettings().GetStyleSettings().GetScrollBarSize(); + // maximum plus some additional space + return std::max(nWidthAsc, nWidthDesc) + GetTextWidth(OUString('0')) * 2; + } + return EditBrowseBox::GetTotalCellWidth(_nRow, _nColId); + } + + void IndexFieldsControl::Init(const Sequence< OUString >& _rAvailableFields, bool _bAddIndexAppendix) + { + m_bAddIndexAppendix = _bAddIndexAppendix; + + RemoveColumns(); + + // for the width: both columns together should be somewhat smaller than the whole window (without the scrollbar) + sal_Int32 nFieldNameWidth = GetSizePixel().Width(); + + if ( m_bAddIndexAppendix ) + { + m_sAscendingText = DBA_RES(STR_ORDER_ASCENDING); + m_sDescendingText = DBA_RES(STR_ORDER_DESCENDING); + + // the "sort order" column + OUString sColumnName = DBA_RES(STR_TAB_INDEX_SORTORDER); + // the width of the order column is the maximum widths of the texts used + // (the title of the column) + sal_Int32 nSortOrderColumnWidth = GetTextWidth(sColumnName); + // ("ascending" + scrollbar width) + sal_Int32 nOther = GetTextWidth(m_sAscendingText) + GetSettings().GetStyleSettings().GetScrollBarSize(); + nSortOrderColumnWidth = std::max(nSortOrderColumnWidth, nOther); + // ("descending" + scrollbar width) + nOther = GetTextWidth(m_sDescendingText) + GetSettings().GetStyleSettings().GetScrollBarSize(); + nSortOrderColumnWidth = std::max(nSortOrderColumnWidth, nOther); + // (plus some additional space) + nSortOrderColumnWidth += GetTextWidth(OUString('0')) * 2; + InsertDataColumn(COLUMN_ID_ORDER, sColumnName, nSortOrderColumnWidth, HeaderBarItemBits::STDSTYLE, 1); + + m_pSortingCell = VclPtr<ListBoxControl>::Create(&GetDataWindow()); + weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget(); + rSortingListBox.append_text(m_sAscendingText); + rSortingListBox.append_text(m_sDescendingText); + rSortingListBox.set_help_id(HID_DLGINDEX_INDEXDETAILS_SORTORDER); + + nFieldNameWidth -= nSortOrderColumnWidth; + } + StyleSettings aSystemStyle = Application::GetSettings().GetStyleSettings(); + nFieldNameWidth -= aSystemStyle.GetScrollBarSize(); + nFieldNameWidth -= 8; + // the "field name" column + OUString sColumnName = DBA_RES(STR_TAB_INDEX_FIELD); + InsertDataColumn(COLUMN_ID_FIELDNAME, sColumnName, nFieldNameWidth, HeaderBarItemBits::STDSTYLE, 0); + + // create the cell controllers + // for the field name cell + m_pFieldNameCell = VclPtr<ListBoxControl>::Create(&GetDataWindow()); + weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget(); + rNameListBox.append_text(OUString()); + rNameListBox.set_help_id(HID_DLGINDEX_INDEXDETAILS_FIELD); + const OUString* pFields = _rAvailableFields.getConstArray(); + const OUString* pFieldsEnd = pFields + _rAvailableFields.getLength(); + for (;pFields < pFieldsEnd; ++pFields) + rNameListBox.append_text(*pFields); + } + + CellController* IndexFieldsControl::GetController(sal_Int32 _nRow, sal_uInt16 _nColumnId) + { + if (!IsEnabled()) + return nullptr; + + IndexFields::const_iterator aRow; + bool bNewField = !implGetFieldDesc(_nRow, aRow); + + DbaMouseDownListBoxController* pReturn = nullptr; + switch (_nColumnId) + { + case COLUMN_ID_ORDER: + if (!bNewField && m_pSortingCell && !aRow->sFieldName.isEmpty()) + pReturn = new DbaMouseDownListBoxController(m_pSortingCell); + break; + + case COLUMN_ID_FIELDNAME: + pReturn = new DbaMouseDownListBoxController(m_pFieldNameCell); + break; + + default: + OSL_FAIL("IndexFieldsControl::GetController: invalid column id!"); + } + + if (pReturn) + pReturn->SetAdditionalModifyHdl(LINK(this, IndexFieldsControl, OnListEntrySelected)); + + return pReturn; + } + + bool IndexFieldsControl::implGetFieldDesc(sal_Int32 _nRow, IndexFields::const_iterator& _rPos) + { + _rPos = m_aFields.end(); + if ((_nRow < 0) || (o3tl::make_unsigned(_nRow) >= m_aFields.size())) + return false; + _rPos = m_aFields.begin() + _nRow; + return true; + } + + bool IndexFieldsControl::SaveModified() + { + if (!IsModified()) + return true; + + switch (GetCurColumnId()) + { + case COLUMN_ID_FIELDNAME: + { + weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget(); + OUString sFieldSelected = rNameListBox.get_active_text(); + bool bEmptySelected = sFieldSelected.isEmpty(); + if (isNewField()) + { + if (!bEmptySelected) + { + // add a new field to the collection + OIndexField aNewField; + aNewField.sFieldName = sFieldSelected; + m_aFields.push_back(aNewField); + RowInserted(GetRowCount()); + } + } + else + { + sal_Int32 nRow = GetCurRow(); + OSL_ENSURE(nRow < static_cast<sal_Int32>(m_aFields.size()), "IndexFieldsControl::SaveModified: invalid current row!"); + if (nRow >= 0) // may be -1 in case the control was empty + { + // remove the field from the selection + IndexFields::iterator aPos = m_aFields.begin() + nRow; + + if (bEmptySelected) + { + aPos->sFieldName.clear(); + + // invalidate the row to force repaint + Invalidate(GetRowRectPixel(nRow)); + return true; + } + + if (sFieldSelected == aPos->sFieldName) + // nothing changed + return true; + + aPos->sFieldName = sFieldSelected; + } + } + + Invalidate(GetRowRectPixel(GetCurRow())); + } + break; + case COLUMN_ID_ORDER: + { + OSL_ENSURE(!isNewField(), "IndexFieldsControl::SaveModified: why the hell ...!!!"); + // selected entry + weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget(); + sal_Int32 nPos = rSortingListBox.get_active(); + OSL_ENSURE(nPos != -1, "IndexFieldsControl::SaveModified: how did you get this selection??"); + // adjust the sort flag in the index field description + OIndexField& rCurrentField = m_aFields[GetCurRow()]; + rCurrentField.bSortAscending = (0 == nPos); + + } + break; + default: + OSL_FAIL("IndexFieldsControl::SaveModified: invalid column id!"); + } + return true; + } + + void IndexFieldsControl::InitController(CellControllerRef& /*_rController*/, sal_Int32 _nRow, sal_uInt16 _nColumnId) + { + IndexFields::const_iterator aFieldDescription; + bool bNewField = !implGetFieldDesc(_nRow, aFieldDescription); + + switch (_nColumnId) + { + case COLUMN_ID_FIELDNAME: + { + weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget(); + rNameListBox.set_active_text(bNewField ? OUString() : aFieldDescription->sFieldName); + rNameListBox.save_value(); + break; + } + + case COLUMN_ID_ORDER: + { + weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget(); + rSortingListBox.set_active_text(aFieldDescription->bSortAscending ? m_sAscendingText : m_sDescendingText); + rSortingListBox.save_value(); + break; + } + + default: + OSL_FAIL("IndexFieldsControl::InitController: invalid column id!"); + } + } + + IMPL_LINK( IndexFieldsControl, OnListEntrySelected, DbaMouseDownListBoxController&, rController, void ) + { + weld::ComboBox& rListBox = rController.GetListBox(); + if (!rListBox.get_popup_shown()) + m_aModifyHdl.Call(*this); + + if (&rListBox != &m_pFieldNameCell->get_widget()) + return; + +// a field has been selected + if (GetCurRow() >= GetRowCount() - 2) + { // and we're in one of the last two rows + OUString sSelectedEntry = rListBox.get_active_text(); + sal_Int32 nCurrentRow = GetCurRow(); + sal_Int32 rowCount = GetRowCount(); + + OSL_ENSURE((static_cast<sal_Int32>(m_aFields.size() + 1)) == rowCount, "IndexFieldsControl::OnListEntrySelected: inconsistence!"); + + if (!sSelectedEntry.isEmpty() && (nCurrentRow == rowCount - 1) /*&& (!m_nMaxColumnsInIndex || rowCount < m_nMaxColumnsInIndex )*/ ) + { // in the last row, a non-empty string has been selected + // -> insert a new row + m_aFields.emplace_back(); + RowInserted(GetRowCount()); + Invalidate(GetRowRectPixel(nCurrentRow)); + } + else if (sSelectedEntry.isEmpty() && (nCurrentRow == rowCount - 2)) + { // in the (last-1)th row, an empty entry has been selected + // -> remove the last row + m_aFields.pop_back(); + RowRemoved(GetRowCount() - 1); + Invalidate(GetRowRectPixel(nCurrentRow)); + } + } + + SaveModified(); + } + OUString IndexFieldsControl::GetCellText(sal_Int32 _nRow,sal_uInt16 nColId) const + { + IndexFields::const_iterator aRow = m_aFields.end(); + if ( _nRow >= 0 ) + { + aRow = m_aFields.begin() + _nRow; + OSL_ENSURE(aRow <= m_aFields.end(), "IndexFieldsControl::SeekRow: invalid row!"); + } + return GetRowCellText(aRow,nColId); + } + OUString IndexFieldsControl::GetRowCellText(const IndexFields::const_iterator& _rRow,sal_uInt16 nColId) const + { + if (_rRow < m_aFields.end()) + { + switch (nColId) + { + case COLUMN_ID_FIELDNAME: + return _rRow->sFieldName; + case COLUMN_ID_ORDER: + if (_rRow->sFieldName.isEmpty()) + return OUString(); + else + return _rRow->bSortAscending ? m_sAscendingText : m_sDescendingText; + default: + OSL_FAIL("IndexFieldsControl::GetCurrentRowCellText: invalid column id!"); + } + } + return OUString(); + } + bool IndexFieldsControl::IsTabAllowed(bool /*bForward*/) const + { + return false; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/odbcconfig.cxx b/dbaccess/source/ui/dlg/odbcconfig.cxx new file mode 100644 index 000000000..b2f3a45ff --- /dev/null +++ b/dbaccess/source/ui/dlg/odbcconfig.cxx @@ -0,0 +1,325 @@ +/* -*- 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 <config_folders.h> +#include "odbcconfig.hxx" + +#include <rtl/bootstrap.hxx> +#include <rtl/ustring.hxx> +#include <osl/diagnose.h> +#include <osl/process.h> +#include <osl/thread.hxx> +#include <vcl/svapp.hxx> + +#ifdef HAVE_ODBC_SUPPORT + +#if defined(_WIN32) +#define ODBC_LIBRARY "ODBC32.DLL" +#endif +#ifdef UNX +#ifdef MACOSX +#define ODBC_LIBRARY "libiodbc.dylib" +#else +#define ODBC_LIBRARY_PLAIN "libodbc.so" +#define ODBC_LIBRARY_1 "libodbc.so.1" +#define ODBC_LIBRARY "libodbc.so.2" +#endif +#endif + +#include <connectivity/odbc.hxx> + +#else + +#define ODBC_LIBRARY "" + +#endif // HAVE_ODBC_SUPPORT + +namespace dbaui +{ + +#ifdef HAVE_ODBC_SUPPORT +typedef SQLRETURN (SQL_API* TSQLManageDataSource) (SQLHWND hwndParent); +typedef SQLRETURN (SQL_API* TSQLAllocHandle) (SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE* OutputHandlePtr); +typedef SQLRETURN (SQL_API* TSQLFreeHandle) (SQLSMALLINT HandleType, SQLHANDLE Handle); +typedef SQLRETURN (SQL_API* TSQLSetEnvAttr) (SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength); +typedef SQLRETURN (SQL_API* TSQLDataSources) (SQLHENV EnvironmentHandle, SQLUSMALLINT Direction, SQLCHAR* ServerName, + SQLSMALLINT BufferLength1, SQLSMALLINT* NameLength1Ptr, SQLCHAR* Description, SQLSMALLINT BufferLength2, SQLSMALLINT* NameLength2Ptr); + +#endif + +// OOdbcLibWrapper + +bool OOdbcEnumeration::load(const char* _pLibPath) +{ + m_sLibPath = OUString::createFromAscii(_pLibPath); +#if defined(HAVE_ODBC_SUPPORT) && !defined(DISABLE_DYNLOADING) + // load the module + m_pOdbcLib = osl_loadModule(m_sLibPath.pData, SAL_LOADMODULE_NOW); + return (nullptr != m_pOdbcLib); +#else + return sal_False; +#endif +} + +void OOdbcEnumeration::unload() +{ +#if defined(HAVE_ODBC_SUPPORT) && !defined(DISABLE_DYNLOADING) + if (isLoaded()) + { + osl_unloadModule(m_pOdbcLib); + m_pOdbcLib = nullptr; + } +#endif +} + +oslGenericFunction OOdbcEnumeration::loadSymbol(const char* _pFunctionName) +{ + return osl_getFunctionSymbol(m_pOdbcLib, OUString::createFromAscii(_pFunctionName).pData); +} + + +struct OdbcTypesImpl +{ +#ifdef HAVE_ODBC_SUPPORT + SQLHANDLE hEnvironment; + OdbcTypesImpl() : hEnvironment(nullptr) { } +#else + void* pDummy; +#endif +}; + +OOdbcEnumeration::OOdbcEnumeration() + :m_pOdbcLib(nullptr) +#ifdef HAVE_ODBC_SUPPORT + ,m_pAllocHandle(nullptr) + ,m_pFreeHandle(nullptr) + ,m_pSetEnvAttr(nullptr) + ,m_pDataSources(nullptr) + ,m_pImpl(new OdbcTypesImpl) +#endif +{ + bool bLoaded = load(ODBC_LIBRARY); +#ifdef ODBC_LIBRARY_1 + if ( !bLoaded ) + bLoaded = load(ODBC_LIBRARY_1); +#endif +#ifdef ODBC_LIBRARY_PLAIN + if ( !bLoaded ) + bLoaded = load(ODBC_LIBRARY_PLAIN); +#endif + + if ( !bLoaded ) + return; + +#ifdef HAVE_ODBC_SUPPORT + // load the generic functions + m_pAllocHandle = loadSymbol("SQLAllocHandle"); + m_pFreeHandle = loadSymbol("SQLFreeHandle"); + m_pSetEnvAttr = loadSymbol("SQLSetEnvAttr"); + m_pDataSources = loadSymbol("SQLDataSources"); + + // all or nothing + if (!m_pAllocHandle || !m_pSetEnvAttr || !m_pDataSources || !m_pFreeHandle) + { + unload(); + m_pAllocHandle = m_pFreeHandle = m_pSetEnvAttr = m_pDataSources = nullptr; + } +#endif +} + +OOdbcEnumeration::~OOdbcEnumeration() +{ + freeEnv(); + unload(); +} + +// OOdbcEnumeration +bool OOdbcEnumeration::allocEnv() +{ + OSL_ENSURE(isLoaded(), "OOdbcEnumeration::allocEnv: not loaded!"); + if (!isLoaded()) + return false; + +#ifdef HAVE_ODBC_SUPPORT + if (m_pImpl->hEnvironment) + // nothing to do + return true; + SQLRETURN nResult = (*reinterpret_cast<TSQLAllocHandle>(m_pAllocHandle))(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_pImpl->hEnvironment); + if (SQL_SUCCESS != nResult) + // can't do anything without environment + return false; + + (*reinterpret_cast<TSQLSetEnvAttr>(m_pSetEnvAttr))(m_pImpl->hEnvironment, SQL_ATTR_ODBC_VERSION, reinterpret_cast<SQLPOINTER>(SQL_OV_ODBC3),SQL_IS_INTEGER); + return true; +#else + return sal_False; +#endif +} + +void OOdbcEnumeration::freeEnv() +{ +#ifdef HAVE_ODBC_SUPPORT + if (m_pImpl->hEnvironment) + (*reinterpret_cast<TSQLFreeHandle>(m_pFreeHandle))(SQL_HANDLE_ENV, m_pImpl->hEnvironment); + m_pImpl->hEnvironment = nullptr; +#endif +} + +void OOdbcEnumeration::getDatasourceNames(std::set<OUString>& _rNames) +{ + OSL_ENSURE(isLoaded(), "OOdbcEnumeration::getDatasourceNames: not loaded!"); + if (!isLoaded()) + return; + + if (!allocEnv()) + { + OSL_FAIL("OOdbcEnumeration::getDatasourceNames: could not allocate an ODBC environment!"); + return; + } + +#ifdef HAVE_ODBC_SUPPORT + // now that we have an environment collect the data source names + UCHAR szDSN[SQL_MAX_DSN_LENGTH+1]; + SWORD pcbDSN; + UCHAR szDescription[1024+1]; + SWORD pcbDescription; + SQLRETURN nResult = SQL_SUCCESS; + rtl_TextEncoding nTextEncoding = osl_getThreadTextEncoding(); + + for ( nResult = (*reinterpret_cast<TSQLDataSources>(m_pDataSources))(m_pImpl->hEnvironment, SQL_FETCH_FIRST, szDSN, + sizeof(szDSN), &pcbDSN, szDescription, sizeof(szDescription)-1, &pcbDescription); + ; + nResult = (*reinterpret_cast<TSQLDataSources>(m_pDataSources))(m_pImpl->hEnvironment, SQL_FETCH_NEXT, szDSN, + sizeof(szDSN), &pcbDSN, szDescription, sizeof(szDescription)-1, &pcbDescription) + ) + { + if (nResult != SQL_SUCCESS) + // no further error handling + break; + else + { + OUString aCurrentDsn(reinterpret_cast<const char*>(szDSN),pcbDSN, nTextEncoding); + _rNames.insert(aCurrentDsn); + } + } +#else + (void) _rNames; +#endif +} + +#ifdef HAVE_ODBC_ADMINISTRATION + +// ProcessTerminationWait +class ProcessTerminationWait : public ::osl::Thread +{ + oslProcess m_hProcessHandle; + Link<void*,void> m_aFinishHdl; + ImplSVEvent* m_nEventId; + +public: + ProcessTerminationWait( oslProcess _hProcessHandle, const Link<void*,void>& _rFinishHdl ) + : m_hProcessHandle( _hProcessHandle ) + , m_aFinishHdl( _rFinishHdl ) + , m_nEventId(nullptr) + { + } + + void disableCallback() + { + // if finished event not posted yet, disable by turning it to a no-op Link + m_aFinishHdl = Link<void*, void>(); + if (m_nEventId) + { + // already posted, remove it + Application::RemoveUserEvent(m_nEventId); + m_nEventId = nullptr; + } + } + + void receivedCallback() + { + m_nEventId = nullptr; + } + +protected: + virtual void SAL_CALL run() override + { + osl_setThreadName("dbaui::ProcessTerminationWait"); + + osl_joinProcess( m_hProcessHandle ); + osl_freeProcessHandle( m_hProcessHandle ); + m_nEventId = Application::PostUserEvent( m_aFinishHdl ); + } +}; + +// OOdbcManagement +OOdbcManagement::OOdbcManagement(const Link<void*,void>& rAsyncFinishCallback) + : m_aAsyncFinishCallback(rAsyncFinishCallback) +{ +} + +OOdbcManagement::~OOdbcManagement() +{ + // wait for our thread to be finished + if ( m_pProcessWait ) + m_pProcessWait->join(); +} + +bool OOdbcManagement::manageDataSources_async() +{ + OSL_PRECOND( !isRunning(), "OOdbcManagement::manageDataSources_async: still running from the previous call!" ); + if ( isRunning() ) + return false; + + // this is done in an external process, due to #i78733# + // (and note this whole functionality is supported on Windows only, ATM) + OUString sExecutableName( "$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER "/odbcconfig.exe" ); + ::rtl::Bootstrap::expandMacros( sExecutableName ); //TODO: detect failure + oslProcess hProcessHandle(nullptr); + oslProcessError eError = osl_executeProcess( sExecutableName.pData, nullptr, 0, 0, nullptr, nullptr, nullptr, 0, &hProcessHandle ); + if ( eError != osl_Process_E_None ) + return false; + + m_pProcessWait.reset( new ProcessTerminationWait( hProcessHandle, m_aAsyncFinishCallback ) ); + m_pProcessWait->create(); + return true; +} + +void OOdbcManagement::disableCallback() +{ + if (m_pProcessWait) + m_pProcessWait->disableCallback(); +} + +void OOdbcManagement::receivedCallback() +{ + if (m_pProcessWait) + m_pProcessWait->receivedCallback(); +} + +bool OOdbcManagement::isRunning() const +{ + return ( m_pProcessWait && m_pProcessWait->isRunning() ); +} + +#endif // HAVE_ODBC_ADMINISTRATION + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/odbcconfig.hxx b/dbaccess/source/ui/dlg/odbcconfig.hxx new file mode 100644 index 000000000..16177ad8a --- /dev/null +++ b/dbaccess/source/ui/dlg/odbcconfig.hxx @@ -0,0 +1,106 @@ +/* -*- 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 + +#if defined(_WIN32) || (defined (UNX) && !defined(ANDROID) && !defined(IOS)) +#define HAVE_ODBC_SUPPORT +#endif + +#if defined(_WIN32) && defined(HAVE_ODBC_SUPPORT) +#define HAVE_ODBC_ADMINISTRATION +#endif + +#include <rtl/ustring.hxx> +#include <tools/link.hxx> +#include <osl/module.h> + +#include <memory> +#include <set> + +namespace dbaui +{ + +// OOdbcEnumeration +struct OdbcTypesImpl; +class OOdbcEnumeration final +{ + oslModule m_pOdbcLib; // the library handle + OUString m_sLibPath; // the path to the library + +#ifdef HAVE_ODBC_SUPPORT + // entry points for ODBC administration + oslGenericFunction m_pAllocHandle; + oslGenericFunction m_pFreeHandle; + oslGenericFunction m_pSetEnvAttr; + oslGenericFunction m_pDataSources; + +#endif + std::unique_ptr<OdbcTypesImpl> m_pImpl; + // needed because we can't have a member of type SQLHANDLE: this would require us to include the respective + // ODBC file, which would lead to a lot of conflicts with other includes + +public: + OOdbcEnumeration(); + ~OOdbcEnumeration(); + +#ifdef HAVE_ODBC_SUPPORT + bool isLoaded() const { return nullptr != m_pOdbcLib; } +#else + bool isLoaded() const { return false; } +#endif + const OUString& getLibraryName() const { return m_sLibPath; } + + void getDatasourceNames(std::set<OUString>& _rNames); + +private: + oslGenericFunction loadSymbol(const char* _pFunctionName); + + /// load the lib + bool load(const char* _pLibPath); + /// unload the lib + void unload(); + /// ensure that an ODBC environment is allocated + bool allocEnv(); + /// free any allocated ODBC environment + void freeEnv(); +}; + +// OOdbcManagement +#ifdef HAVE_ODBC_ADMINISTRATION +class ProcessTerminationWait; +class OOdbcManagement +{ + std::unique_ptr< ProcessTerminationWait > m_pProcessWait; + Link<void*,void> m_aAsyncFinishCallback; + +public: + explicit OOdbcManagement( const Link<void*,void>& _rAsyncFinishCallback ); + ~OOdbcManagement(); + + bool manageDataSources_async(); + bool isRunning() const; + void disableCallback(); + void receivedCallback(); +}; +#endif + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/optionalboolitem.cxx b/dbaccess/source/ui/dlg/optionalboolitem.cxx new file mode 100644 index 000000000..30d176391 --- /dev/null +++ b/dbaccess/source/ui/dlg/optionalboolitem.cxx @@ -0,0 +1,44 @@ +/* -*- 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 "optionalboolitem.hxx" + +namespace dbaui +{ + + // OptionalBoolItem + OptionalBoolItem::OptionalBoolItem( sal_uInt16 _nWhich ) + :SfxPoolItem( _nWhich ) + { + } + + bool OptionalBoolItem::operator==( const SfxPoolItem& _rItem ) const + { + return SfxPoolItem::operator==(_rItem) && + static_cast<const OptionalBoolItem&>( _rItem ).m_aValue == m_aValue; + } + + OptionalBoolItem* OptionalBoolItem::Clone( SfxItemPool* /*_pPool*/ ) const + { + return new OptionalBoolItem( *this ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/optionalboolitem.hxx b/dbaccess/source/ui/dlg/optionalboolitem.hxx new file mode 100644 index 000000000..c500dfa2a --- /dev/null +++ b/dbaccess/source/ui/dlg/optionalboolitem.hxx @@ -0,0 +1,51 @@ +/* -*- 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 <svl/poolitem.hxx> + +#include <optional> + +namespace dbaui +{ + + // OptionalBoolItem + class OptionalBoolItem : public SfxPoolItem + { + ::std::optional< bool > m_aValue; + + public: + explicit OptionalBoolItem( sal_uInt16 nWhich ); + + virtual bool operator==( const SfxPoolItem& _rItem ) const override; + virtual OptionalBoolItem* Clone( SfxItemPool* _pPool = nullptr ) const override; + + bool HasValue() const { return !!m_aValue; } + void ClearValue() { m_aValue.reset(); } + bool GetValue() const { return *m_aValue; } + void SetValue(bool _bValue) { m_aValue = _bValue; } + + const ::std::optional< bool >& + GetFullValue() const { return m_aValue; } + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/paramdialog.cxx b/dbaccess/source/ui/dlg/paramdialog.cxx new file mode 100644 index 000000000..de3347682 --- /dev/null +++ b/dbaccess/source/ui/dlg/paramdialog.cxx @@ -0,0 +1,334 @@ +/* -*- 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 <core_resource.hxx> +#include <paramdialog.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <com/sun/star/util/NumberFormatter.hpp> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <vcl/weld.hxx> +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> +#include <tools/diagnose_ex.h> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::util; + using namespace ::connectivity; + + // OParameterDialog + + + OParameterDialog::OParameterDialog( + weld::Window* pParent, const Reference< XIndexAccess > & rParamContainer, + const Reference< XConnection > & _rxConnection, const Reference< XComponentContext >& rxContext) + : GenericDialogController(pParent, "dbaccess/ui/parametersdialog.ui", "Parameters") + , m_nCurrentlySelected(-1) + , m_xConnection(_rxConnection) + , m_aPredicateInput( rxContext, _rxConnection, getParseContext() ) + , m_aResetVisitFlag("dbaccess OParameterDialog m_aResetVisitFlag") + , m_xAllParams(m_xBuilder->weld_tree_view("allParamTreeview")) + , m_xParam(m_xBuilder->weld_entry("paramEntry")) + , m_xTravelNext(m_xBuilder->weld_button("next")) + , m_xOKBtn(m_xBuilder->weld_button("ok")) + , m_xCancelBtn(m_xBuilder->weld_button("cancel")) + { + m_xAllParams->set_size_request(-1, m_xAllParams->get_height_rows(10)); + + if (rxContext.is()) + m_xFormatter.set( NumberFormatter::create( rxContext ), UNO_QUERY_THROW); + else { + OSL_FAIL("OParameterDialog::OParameterDialog: need a service factory!"); + } + + Reference< XNumberFormatsSupplier > xNumberFormats = ::dbtools::getNumberFormats(m_xConnection, true); + if (!xNumberFormats.is()) + ::comphelper::disposeComponent(m_xFormatter); + else + m_xFormatter->attachNumberFormatsSupplier(xNumberFormats); + try + { + OSL_ENSURE(rParamContainer->getCount(), "OParameterDialog::OParameterDialog : can't handle empty containers !"); + + m_aFinalValues.realloc(rParamContainer->getCount()); + PropertyValue* pValues = m_aFinalValues.getArray(); + + for (sal_Int32 i = 0, nCount = rParamContainer->getCount(); i<nCount; ++i, ++pValues) + { + Reference< XPropertySet > xParamAsSet; + rParamContainer->getByIndex(i) >>= xParamAsSet; + OSL_ENSURE(xParamAsSet.is(),"Parameter is null!"); + if(!xParamAsSet.is()) + continue; + pValues->Name = ::comphelper::getString(xParamAsSet->getPropertyValue(PROPERTY_NAME)); + m_xAllParams->append_text(pValues->Name); + + m_aVisitedParams.push_back(VisitFlags::NONE); + // not visited, not dirty + } + + m_xParams = rParamContainer; + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + Construct(); + + m_aResetVisitFlag.SetInvokeHandler(LINK(this, OParameterDialog, OnVisitedTimeout)); + } + + OParameterDialog::~OParameterDialog() + { + if (m_aResetVisitFlag.IsActive()) + m_aResetVisitFlag.Stop(); + } + + void OParameterDialog::Construct() + { + m_xAllParams->connect_changed(LINK(this, OParameterDialog, OnEntryListBoxSelected)); + m_xParam->connect_focus_out(LINK(this, OParameterDialog, OnValueLoseFocusHdl)); + m_xParam->connect_changed(LINK(this, OParameterDialog, OnValueModified)); + m_xTravelNext->connect_clicked(LINK(this, OParameterDialog, OnButtonClicked)); + m_xOKBtn->connect_clicked(LINK(this, OParameterDialog, OnButtonClicked)); + m_xCancelBtn->connect_clicked(LINK(this, OParameterDialog, OnButtonClicked)); + + if (m_xAllParams->n_children()) + { + m_xAllParams->select(0); + OnEntrySelected(); + + if (m_xAllParams->n_children() == 1) + m_xTravelNext->set_sensitive(false); + + if (m_xAllParams->n_children() > 1) + m_xDialog->change_default_widget(m_xOKBtn.get(), m_xTravelNext.get()); + } + + m_xParam->grab_focus(); + } + + IMPL_LINK_NOARG(OParameterDialog, OnValueLoseFocusHdl, weld::Widget&, void) + { + CheckValueForError(); + } + + bool OParameterDialog::CheckValueForError() + { + if (m_nCurrentlySelected != -1) + { + if ( !( m_aVisitedParams[ m_nCurrentlySelected ] & VisitFlags::Dirty ) ) + // nothing to do, the value isn't dirty + return false; + } + + bool bRet = false; + + Reference< XPropertySet > xParamAsSet; + m_xParams->getByIndex(m_nCurrentlySelected) >>= xParamAsSet; + if (xParamAsSet.is()) + { + if (m_xConnection.is() && m_xFormatter.is()) + { + OUString sParamValue(m_xParam->get_text()); + bool bValid = m_aPredicateInput.normalizePredicateString( sParamValue, xParamAsSet ); + m_xParam->set_text(sParamValue); + m_xParam->set_message_type(bValid ? weld::EntryMessageType::Normal : weld::EntryMessageType::Error); + OUString sToolTip; + if ( bValid ) + { + // with this the value isn't dirty anymore + if (m_nCurrentlySelected != -1) + m_aVisitedParams[m_nCurrentlySelected] &= ~VisitFlags::Dirty; + } + else + { + OUString sName; + try + { + sName = ::comphelper::getString(xParamAsSet->getPropertyValue(PROPERTY_NAME)); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + OUString sMessage(DBA_RES(STR_COULD_NOT_CONVERT_PARAM)); + sToolTip = sMessage.replaceAll( "$name$", sName ); + m_xParam->grab_focus(); + bRet = true; + } + m_xParam->set_tooltip_text(sToolTip); + m_xOKBtn->set_sensitive(bValid); + } + } + + return bRet; + } + + IMPL_LINK(OParameterDialog, OnButtonClicked, weld::Button&, rButton, void) + { + if (m_xCancelBtn.get() == &rButton) + { + // no interpreting of the given values anymore... + m_xParam->connect_focus_out(Link<weld::Widget&, void>()); // no direct call from the control anymore ... + m_xDialog->response(RET_CANCEL); + } + else if (m_xOKBtn.get() == &rButton) + { + // transfer the current values into the Any + if (OnEntrySelected()) + { // there was an error interpreting the current text + return; + } + + if (m_xParams.is()) + { + // write the parameters + try + { + PropertyValue* pValues = m_aFinalValues.getArray(); + for (sal_Int32 i = 0, nCount = m_xParams->getCount(); i<nCount; ++i, ++pValues) + { + Reference< XPropertySet > xParamAsSet; + m_xParams->getByIndex(i) >>= xParamAsSet; + + OUString sValue; + pValues->Value >>= sValue; + pValues->Value = m_aPredicateInput.getPredicateValue( sValue, xParamAsSet ); + } + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + } + m_xDialog->response(RET_OK); + } + else if (m_xTravelNext.get() == &rButton) + { + if (sal_Int32 nCount = m_xAllParams->n_children()) + { + sal_Int32 nCurrent = m_xAllParams->get_selected_index(); + OSL_ENSURE(static_cast<size_t>(nCount) == m_aVisitedParams.size(), "OParameterDialog::OnButtonClicked : inconsistent lists !"); + + // search the next entry in list we haven't visited yet + sal_Int32 nNext = (nCurrent + 1) % nCount; + while ((nNext != nCurrent) && ( m_aVisitedParams[nNext] & VisitFlags::Visited )) + nNext = (nNext + 1) % nCount; + + if ( m_aVisitedParams[nNext] & VisitFlags::Visited ) + // there is no such "not visited yet" entry -> simply take the next one + nNext = (nCurrent + 1) % nCount; + + m_xAllParams->select(nNext); + OnEntrySelected(); + } + } + } + + IMPL_LINK_NOARG(OParameterDialog, OnEntryListBoxSelected, weld::TreeView&, void) + { + OnEntrySelected(); + } + + bool OParameterDialog::OnEntrySelected() + { + if (m_aResetVisitFlag.IsActive()) + { + LINK(this, OParameterDialog, OnVisitedTimeout).Call(&m_aResetVisitFlag); + m_aResetVisitFlag.Stop(); + } + // save the old values + if (m_nCurrentlySelected != -1) + { + // do the transformation of the current text + if (CheckValueForError()) + { // there was an error interpreting the text + m_xAllParams->select(m_nCurrentlySelected); + return true; + } + + m_aFinalValues.getArray()[m_nCurrentlySelected].Value <<= m_xParam->get_text(); + } + + // initialize the controls with the new values + sal_Int32 nSelected = m_xAllParams->get_selected_index(); + OSL_ENSURE(nSelected != -1, "OParameterDialog::OnEntrySelected : no current entry !"); + + m_xParam->set_text(::comphelper::getString(m_aFinalValues[nSelected].Value)); + m_nCurrentlySelected = nSelected; + + // with this the value isn't dirty + OSL_ENSURE(o3tl::make_unsigned(m_nCurrentlySelected) < m_aVisitedParams.size(), "OParameterDialog::OnEntrySelected : invalid current entry !"); + m_aVisitedParams[m_nCurrentlySelected] &= ~VisitFlags::Dirty; + + m_aResetVisitFlag.SetTimeout(1000); + m_aResetVisitFlag.Start(); + + return false; + } + + IMPL_LINK_NOARG(OParameterDialog, OnVisitedTimeout, Timer*, void) + { + OSL_ENSURE(m_nCurrentlySelected != -1, "OParameterDialog::OnVisitedTimeout : invalid call !"); + + // mark the currently selected entry as visited + OSL_ENSURE(o3tl::make_unsigned(m_nCurrentlySelected) < m_aVisitedParams.size(), "OParameterDialog::OnVisitedTimeout : invalid entry !"); + m_aVisitedParams[m_nCurrentlySelected] |= VisitFlags::Visited; + + // was it the last "not visited yet" entry ? + bool bVisited = false; + for (auto const& visitedParam : m_aVisitedParams) + { + if (!(visitedParam & VisitFlags::Visited)) + { + bVisited = true; + break; + } + } + + if (!bVisited) + { + // yes, there isn't another one -> change the "default button" + m_xDialog->change_default_widget(m_xTravelNext.get(), m_xOKBtn.get()); + } + } + + IMPL_LINK(OParameterDialog, OnValueModified, weld::Entry&, rEdit, void) + { + // mark the currently selected entry as dirty + OSL_ENSURE(o3tl::make_unsigned(m_nCurrentlySelected) < m_aVisitedParams.size(), "OParameterDialog::OnValueModified : invalid entry !"); + m_aVisitedParams[m_nCurrentlySelected] |= VisitFlags::Dirty; + rEdit.set_message_type(weld::EntryMessageType::Normal); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/queryfilter.cxx b/dbaccess/source/ui/dlg/queryfilter.cxx new file mode 100644 index 000000000..2735acee5 --- /dev/null +++ b/dbaccess/source/ui/dlg/queryfilter.cxx @@ -0,0 +1,748 @@ +/* -*- 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 <queryfilter.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdb/SQLFilterOperator.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <comphelper/string.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <connectivity/dbtools.hxx> +#include <strings.hxx> +#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> + +using namespace dbaui; +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::beans; + +static void Replace_OS_PlaceHolder(OUString& aString) +{ + aString = aString.replaceAll( "*", "%" ); + aString = aString.replaceAll( "?", "_" ); +} + +static void Replace_SQL_PlaceHolder(OUString& aString) +{ + aString = aString.replaceAll( "%", "*" ); + aString = aString.replaceAll( "_", "?" ); +} + +DlgFilterCrit::DlgFilterCrit(weld::Window * pParent, + const Reference< XComponentContext >& rxContext, + const Reference< XConnection>& _rxConnection, + const Reference< XSingleSelectQueryComposer >& _rxComposer, + const Reference< XNameAccess>& _rxCols) + : GenericDialogController(pParent, "dbaccess/ui/queryfilterdialog.ui", "QueryFilterDialog") + , m_xQueryComposer(_rxComposer) + , m_xColumns( _rxCols ) + , m_xConnection( _rxConnection ) + , m_xMetaData( _rxConnection->getMetaData() ) + , m_aPredicateInput( rxContext, _rxConnection, getParseContext() ) + , m_xLB_WHEREFIELD1(m_xBuilder->weld_combo_box("field1")) + , m_xLB_WHERECOMP1(m_xBuilder->weld_combo_box("cond1")) + , m_xET_WHEREVALUE1(m_xBuilder->weld_entry("value1")) + , m_xLB_WHERECOND2(m_xBuilder->weld_combo_box("op2")) + , m_xLB_WHEREFIELD2(m_xBuilder->weld_combo_box("field2")) + , m_xLB_WHERECOMP2(m_xBuilder->weld_combo_box("cond2")) + , m_xET_WHEREVALUE2(m_xBuilder->weld_entry("value2")) + , m_xLB_WHERECOND3(m_xBuilder->weld_combo_box("op3")) + , m_xLB_WHEREFIELD3(m_xBuilder->weld_combo_box("field3")) + , m_xLB_WHERECOMP3(m_xBuilder->weld_combo_box("cond3")) + , m_xET_WHEREVALUE3(m_xBuilder->weld_entry("value3")) +{ + //set all condition preferred width to max width + //if all entries exist + Size aSize(m_xLB_WHERECOMP1->get_preferred_size()); + m_xLB_WHERECOMP1->set_size_request(aSize.Width(), -1); + m_xLB_WHERECOMP2->set_size_request(aSize.Width(), -1); + m_xLB_WHERECOMP3->set_size_request(aSize.Width(), -1); + const sal_Int32 nEntryCount = m_xLB_WHERECOMP1->get_count(); + m_aSTR_COMPARE_OPERATORS.resize(nEntryCount); + for (sal_Int32 i = 0; i < nEntryCount; ++i) + { + m_aSTR_COMPARE_OPERATORS[i] = m_xLB_WHERECOMP1->get_text(i); + } + m_xLB_WHERECOMP1->clear(); + + // ... also write it into the remaining fields + Sequence< OUString> aNames = m_xColumns->getElementNames(); + const OUString* pIter = aNames.getConstArray(); + const OUString* pEnd = pIter + aNames.getLength(); + Reference<XPropertySet> xColumn; + for(;pIter != pEnd;++pIter) + { + try + { + xColumn.set( m_xColumns->getByName( *pIter ), UNO_QUERY_THROW ); + + sal_Int32 nDataType( 0 ); + OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_TYPE ) >>= nDataType ); + sal_Int32 eColumnSearch = ::dbtools::getSearchColumnFlag( m_xConnection, nDataType ); + if ( eColumnSearch == ColumnSearch::NONE ) + continue; + + bool bIsSearchable( true ); + OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_ISSEARCHABLE ) >>= bIsSearchable ); + if ( !bIsSearchable ) + continue; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + m_xLB_WHEREFIELD1->append_text( *pIter ); + m_xLB_WHEREFIELD2->append_text( *pIter ); + m_xLB_WHEREFIELD3->append_text( *pIter ); + } + + Reference<XNameAccess> xSelectColumns = Reference<XColumnsSupplier>(m_xQueryComposer,UNO_QUERY_THROW)->getColumns(); + aNames = xSelectColumns->getElementNames(); + pIter = aNames.getConstArray(); + pEnd = pIter + aNames.getLength(); + for(;pIter != pEnd;++pIter) + { + // don't insert a column name twice + if ( !m_xColumns->hasByName(*pIter) ) + { + xColumn.set(xSelectColumns->getByName(*pIter),UNO_QUERY); + OSL_ENSURE(xColumn.is(),"DlgFilterCrit::DlgFilterCrit: Column is null!"); + sal_Int32 nDataType(0); + xColumn->getPropertyValue(PROPERTY_TYPE) >>= nDataType; + sal_Int32 eColumnSearch = dbtools::getSearchColumnFlag(m_xConnection,nDataType); + // TODO + // !pColumn->IsFunction() + if(eColumnSearch != ColumnSearch::NONE) + { + m_xLB_WHEREFIELD1->append_text( *pIter ); + m_xLB_WHEREFIELD2->append_text( *pIter ); + m_xLB_WHEREFIELD3->append_text( *pIter ); + } + } + } + // initialize the listboxes with noEntry + m_xLB_WHEREFIELD1->set_active(0); + m_xLB_WHEREFIELD2->set_active(0); + m_xLB_WHEREFIELD3->set_active(0); + + // insert the criteria into the dialog + Sequence<Sequence<PropertyValue > > aValues = m_xQueryComposer->getStructuredFilter(); + int i(0); + fillLines(i, aValues); + aValues = m_xQueryComposer->getStructuredHavingClause(); + fillLines(i, aValues); + + EnableLines(); + + m_xLB_WHEREFIELD1->connect_changed(LINK(this,DlgFilterCrit,ListSelectHdl)); + m_xLB_WHEREFIELD2->connect_changed(LINK(this,DlgFilterCrit,ListSelectHdl)); + m_xLB_WHEREFIELD3->connect_changed(LINK(this,DlgFilterCrit,ListSelectHdl)); + + m_xLB_WHERECOMP1->connect_changed(LINK(this,DlgFilterCrit,ListSelectCompHdl)); + m_xLB_WHERECOMP2->connect_changed(LINK(this,DlgFilterCrit,ListSelectCompHdl)); + m_xLB_WHERECOMP3->connect_changed(LINK(this,DlgFilterCrit,ListSelectCompHdl)); + + m_xET_WHEREVALUE1->connect_focus_out( LINK( this, DlgFilterCrit, PredicateLoseFocus ) ); + m_xET_WHEREVALUE2->connect_focus_out( LINK( this, DlgFilterCrit, PredicateLoseFocus ) ); + m_xET_WHEREVALUE3->connect_focus_out( LINK( this, DlgFilterCrit, PredicateLoseFocus ) ); + + if (m_xET_WHEREVALUE1->get_sensitive()) + m_xET_WHEREVALUE1->grab_focus(); +} + +DlgFilterCrit::~DlgFilterCrit() +{ +} + +sal_Int32 DlgFilterCrit::GetOSQLPredicateType( std::u16string_view _rSelectedPredicate ) const +{ + sal_Int32 nPredicateIndex = -1; + for ( size_t i=0; i < m_aSTR_COMPARE_OPERATORS.size(); ++i) + if ( m_aSTR_COMPARE_OPERATORS[i] == _rSelectedPredicate ) + { + nPredicateIndex = i; + break; + } + + sal_Int32 nPredicateType = SQLFilterOperator::NOT_SQLNULL; + switch ( nPredicateIndex ) + { + case 0: + nPredicateType = SQLFilterOperator::EQUAL; + break; + case 1: + nPredicateType = SQLFilterOperator::NOT_EQUAL; + break; + case 2: + nPredicateType = SQLFilterOperator::LESS; + break; + case 3: + nPredicateType = SQLFilterOperator::LESS_EQUAL; + break; + case 4: + nPredicateType = SQLFilterOperator::GREATER; + break; + case 5: + nPredicateType = SQLFilterOperator::GREATER_EQUAL; + break; + case 6: + nPredicateType = SQLFilterOperator::LIKE; + break; + case 7: + nPredicateType = SQLFilterOperator::NOT_LIKE; + break; + case 8: + nPredicateType = SQLFilterOperator::SQLNULL; + break; + case 9: + nPredicateType = SQLFilterOperator::NOT_SQLNULL; + break; + default: + OSL_FAIL( "DlgFilterCrit::GetOSQLPredicateType: unknown predicate string!" ); + break; + } + + return nPredicateType; +} + +sal_Int32 DlgFilterCrit::GetSelectionPos(sal_Int32 eType, const weld::ComboBox& rListBox) +{ + sal_Int32 nPos; + switch(eType) + { + case SQLFilterOperator::EQUAL: + nPos = 0; + break; + case SQLFilterOperator::NOT_EQUAL: + nPos = 1; + break; + case SQLFilterOperator::LESS: + nPos = 2; + break; + case SQLFilterOperator::LESS_EQUAL: + nPos = 3; + break; + case SQLFilterOperator::GREATER: + nPos = 4; + break; + case SQLFilterOperator::GREATER_EQUAL: + nPos = 5; + break; + case SQLFilterOperator::NOT_LIKE: + nPos = rListBox.get_count() > 2 ? rListBox.get_count()-3 : 0; + break; + case SQLFilterOperator::LIKE: + nPos = rListBox.get_count() > 2 ? rListBox.get_count()-4 : 1; + break; + case SQLFilterOperator::SQLNULL: + nPos = rListBox.get_count()-2; + break; + case SQLFilterOperator::NOT_SQLNULL: + nPos = rListBox.get_count()-1; + break; + default: + // TODO What value should this be? + nPos = 0; + break; + } + return nPos; +} + +bool DlgFilterCrit::getCondition(const weld::ComboBox& _rField,const weld::ComboBox& _rComp,const weld::Entry& _rValue,PropertyValue& _rFilter) const +{ + bool bHaving = false; + try + { + _rFilter.Name = _rField.get_active_text(); + Reference< XPropertySet > xColumn = getQueryColumn(_rFilter.Name); + if ( xColumn.is() ) + { + bool bFunction = false; + OUString sTableName; + Reference< XPropertySetInfo > xInfo = xColumn->getPropertySetInfo(); + if ( xInfo->hasPropertyByName(PROPERTY_REALNAME) ) + { + if ( xInfo->hasPropertyByName(PROPERTY_TABLENAME) ) + { + xColumn->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName; + if ( !sTableName.isEmpty() ) + { + // properly quote all parts of the table name, so + // e.g. <schema>.<table> becomes "<schema>"."<table>" + OUString aCatlog,aSchema,aTable; + ::dbtools::qualifiedNameComponents( m_xMetaData, sTableName, aCatlog, aSchema, aTable, ::dbtools::EComposeRule::InDataManipulation ); + sTableName = ::dbtools::composeTableName( m_xMetaData, aCatlog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation ); + } + } + xColumn->getPropertyValue(PROPERTY_REALNAME) >>= _rFilter.Name; + static constexpr OUStringLiteral sAgg = u"AggregateFunction"; + if ( xInfo->hasPropertyByName(sAgg) ) + xColumn->getPropertyValue(sAgg) >>= bHaving; + static constexpr OUStringLiteral sFunction = u"Function"; + if ( xInfo->hasPropertyByName(sFunction) ) + xColumn->getPropertyValue(sFunction) >>= bFunction; + } + if ( !bFunction ) + { + const OUString aQuote = m_xMetaData.is() ? m_xMetaData->getIdentifierQuoteString() : OUString(); + _rFilter.Name = ::dbtools::quoteName(aQuote,_rFilter.Name); + if ( !sTableName.isEmpty() ) + { + sTableName += "." + _rFilter.Name; + _rFilter.Name = sTableName; + } + } + } + } + catch(const Exception&) + { + } + + _rFilter.Handle = GetOSQLPredicateType( _rComp.get_active_text() ); + if ( SQLFilterOperator::SQLNULL != _rFilter.Handle && _rFilter.Handle != SQLFilterOperator::NOT_SQLNULL ) + { + OUString sPredicateValue; + m_aPredicateInput.getPredicateValue( _rValue.get_text(), getMatchingColumn( _rValue ) ) >>= sPredicateValue; + if ( _rFilter.Handle == SQLFilterOperator::LIKE || + _rFilter.Handle == SQLFilterOperator::NOT_LIKE ) + ::Replace_OS_PlaceHolder( sPredicateValue ); + _rFilter.Value <<= sPredicateValue; + } + return bHaving; +} + +Reference< XPropertySet > DlgFilterCrit::getColumn( const OUString& _rFieldName ) const +{ + Reference< XPropertySet > xColumn; + try + { + if ( m_xColumns.is() && m_xColumns->hasByName( _rFieldName ) ) + m_xColumns->getByName( _rFieldName ) >>= xColumn; + + Reference< XNameAccess> xColumns = Reference< XColumnsSupplier >(m_xQueryComposer,UNO_QUERY_THROW)->getColumns(); + if ( xColumns.is() && !xColumn.is() ) + { + Sequence< OUString> aSeq = xColumns->getElementNames(); + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + for(;pIter != pEnd;++pIter) + { + Reference<XPropertySet> xProp(xColumns->getByName(*pIter),UNO_QUERY); + if ( xProp.is() && xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME) ) + { + OUString sRealName; + xProp->getPropertyValue(PROPERTY_REALNAME) >>= sRealName; + if ( sRealName == _rFieldName ) + { + if ( m_xColumns.is() && m_xColumns->hasByName( *pIter ) ) + m_xColumns->getByName( *pIter ) >>= xColumn; + break; + } + } + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return xColumn; +} + +Reference< XPropertySet > DlgFilterCrit::getQueryColumn( const OUString& _rFieldName ) const +{ + Reference< XPropertySet > xColumn; + try + { + Reference< XNameAccess> xColumns = Reference< XColumnsSupplier >(m_xQueryComposer,UNO_QUERY_THROW)->getColumns(); + if ( xColumns.is() && xColumns->hasByName( _rFieldName ) ) + xColumns->getByName( _rFieldName ) >>= xColumn; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return xColumn; +} + +Reference< XPropertySet > DlgFilterCrit::getMatchingColumn( const weld::Entry& _rValueInput ) const +{ + // the name + OUString sField; + if ( &_rValueInput == m_xET_WHEREVALUE1.get() ) + { + sField = m_xLB_WHEREFIELD1->get_active_text(); + } + else if ( &_rValueInput == m_xET_WHEREVALUE2.get() ) + { + sField = m_xLB_WHEREFIELD2->get_active_text(); + } + else if ( &_rValueInput == m_xET_WHEREVALUE3.get() ) + { + sField = m_xLB_WHEREFIELD3->get_active_text(); + } + else { + OSL_FAIL( "DlgFilterCrit::getMatchingColumn: invalid event source!" ); + } + + // the field itself + return getColumn( sField ); +} + +IMPL_LINK( DlgFilterCrit, PredicateLoseFocus, weld::Widget&, rControl, void ) +{ + weld::Entry& rField = dynamic_cast<weld::Entry&>(rControl); + // retrieve the field affected + Reference< XPropertySet> xColumn(getMatchingColumn(rField)); + // and normalize its content + if ( xColumn.is() ) + { + OUString sText(rField.get_text()); + m_aPredicateInput.normalizePredicateString(sText, xColumn); + rField.set_text(sText); + } +} + +void DlgFilterCrit::SetLine( int nIdx, const PropertyValue& _rItem, bool _bOr ) +{ + OUString aStr; + _rItem.Value >>= aStr; + if ( _rItem.Handle == SQLFilterOperator::LIKE || + _rItem.Handle == SQLFilterOperator::NOT_LIKE ) + ::Replace_SQL_PlaceHolder(aStr); + aStr = comphelper::string::stripEnd(aStr, ' '); + + Reference< XPropertySet > xColumn = getColumn( _rItem.Name ); + + // to make sure that we only set first three + weld::ComboBox* pColumnListControl = nullptr; + weld::ComboBox* pPredicateListControl = nullptr; + weld::Entry* pPredicateValueControl = nullptr; + switch( nIdx ) + { + case 0: + pColumnListControl = m_xLB_WHEREFIELD1.get(); + pPredicateListControl = m_xLB_WHERECOMP1.get(); + pPredicateValueControl = m_xET_WHEREVALUE1.get(); + break; + case 1: + m_xLB_WHERECOND2->set_active( _bOr ? 1 : 0 ); + + pColumnListControl = m_xLB_WHEREFIELD2.get(); + pPredicateListControl = m_xLB_WHERECOMP2.get(); + pPredicateValueControl = m_xET_WHEREVALUE2.get(); + break; + case 2: + m_xLB_WHERECOND3->set_active( _bOr ? 1 : 0 ); + + pColumnListControl = m_xLB_WHEREFIELD3.get(); + pPredicateListControl = m_xLB_WHERECOMP3.get(); + pPredicateValueControl = m_xET_WHEREVALUE3.get(); + break; + } + + if ( !(pColumnListControl && pPredicateListControl && pPredicateValueControl) ) + return; + + OUString sName; + if ( xColumn.is() ) + xColumn->getPropertyValue(PROPERTY_NAME) >>= sName; + else + sName = _rItem.Name; + // select the appropriate field name + SelectField( *pColumnListControl, sName ); + ListSelectHdl( *pColumnListControl ); + + // select the appropriate condition + pPredicateListControl->set_active( GetSelectionPos( _rItem.Handle, *pPredicateListControl ) ); + + // initially normalize this value + OUString aString( aStr ); + m_aPredicateInput.normalizePredicateString( aString, xColumn ); + pPredicateValueControl->set_text( aString ); +} + +void DlgFilterCrit::SelectField(weld::ComboBox& rBox, std::u16string_view rField) +{ + const sal_Int32 nCnt = rBox.get_count(); + + for( sal_Int32 i=0 ; i<nCnt ; i++ ) + { + if (rBox.get_text(i) == rField) + { + rBox.set_active(i); + return; + } + } + + rBox.set_active(0); +} + +void DlgFilterCrit::EnableLines() +{ + // enabling/disabling of whole lines + if( m_xLB_WHEREFIELD1->get_active() == 0 ) + { + m_xLB_WHEREFIELD2->set_sensitive(false); + m_xLB_WHERECOND2->set_sensitive(false); + m_xLB_WHERECOMP2->set_sensitive(false); + m_xET_WHEREVALUE2->set_sensitive(false); + + m_xLB_WHEREFIELD3->set_sensitive(false); + m_xLB_WHERECOND3->set_sensitive(false); + m_xLB_WHERECOMP3->set_sensitive(false); + m_xET_WHEREVALUE3->set_sensitive(false); + } + else + { + m_xLB_WHEREFIELD2->set_sensitive(true); + m_xLB_WHERECOND2->set_sensitive(true); + m_xLB_WHERECOMP2->set_sensitive(true); + m_xET_WHEREVALUE2->set_sensitive(true); + + m_xLB_WHEREFIELD3->set_sensitive(true); + m_xLB_WHERECOND3->set_sensitive(true); + m_xLB_WHERECOMP3->set_sensitive(true); + m_xET_WHEREVALUE3->set_sensitive(true); + } + + if( m_xLB_WHEREFIELD2->get_active() == 0 ) + { + m_xLB_WHEREFIELD3->set_sensitive(false); + m_xLB_WHERECOND3->set_sensitive(false); + m_xLB_WHERECOMP3->set_sensitive(false); + m_xET_WHEREVALUE3->set_sensitive(false); + } + else + { + m_xLB_WHEREFIELD3->set_sensitive(true); + m_xLB_WHERECOND3->set_sensitive(true); + m_xLB_WHERECOMP3->set_sensitive(true); + m_xET_WHEREVALUE3->set_sensitive(true); + } + + // comparison field equal to NOENTRY + if( m_xLB_WHEREFIELD1->get_active() == 0 ) + { + m_xLB_WHERECOMP1->set_sensitive(false); + m_xET_WHEREVALUE1->set_sensitive(false); + } + else + { + m_xLB_WHEREFIELD1->set_sensitive(true); + m_xLB_WHERECOMP1->set_sensitive(true); + m_xET_WHEREVALUE1->set_sensitive(true); + } + + if( m_xLB_WHEREFIELD2->get_active() == 0 ) + { + m_xLB_WHERECOND2->set_sensitive(false); + m_xLB_WHERECOMP2->set_sensitive(false); + m_xET_WHEREVALUE2->set_sensitive(false); + } + else + { + m_xLB_WHERECOND2->set_sensitive(true); + m_xLB_WHEREFIELD2->set_sensitive(true); + m_xLB_WHERECOMP2->set_sensitive(true); + m_xET_WHEREVALUE2->set_sensitive(true); + } + + if( m_xLB_WHEREFIELD3->get_active() == 0 ) + { + m_xLB_WHERECOND3->set_sensitive(false); + m_xLB_WHERECOMP3->set_sensitive(false); + m_xET_WHEREVALUE3->set_sensitive(false); + } + else + { + m_xLB_WHERECOND3->set_sensitive(true); + m_xLB_WHERECOND3->set_sensitive(true); + m_xLB_WHEREFIELD3->set_sensitive(true); + m_xLB_WHERECOMP3->set_sensitive(true); + m_xET_WHEREVALUE3->set_sensitive(true); + } + + // comparison operator equal to ISNULL or ISNOTNULL + if(m_xLB_WHERECOMP1->get_count() > 2 && + ((m_xLB_WHERECOMP1->get_active() == m_xLB_WHERECOMP1->get_count()-1) || + (m_xLB_WHERECOMP1->get_active() == m_xLB_WHERECOMP1->get_count()-2)) ) + m_xET_WHEREVALUE1->set_sensitive(false); + + if(m_xLB_WHERECOMP2->get_count() > 2 && + ((m_xLB_WHERECOMP2->get_active() == m_xLB_WHERECOMP2->get_count()-1) || + (m_xLB_WHERECOMP2->get_active() == m_xLB_WHERECOMP2->get_count()-2)) ) + m_xET_WHEREVALUE2->set_sensitive(false); + + if(m_xLB_WHERECOMP3->get_count() > 2 && + ((m_xLB_WHERECOMP3->get_active() == m_xLB_WHERECOMP3->get_count()-1) || + (m_xLB_WHERECOMP3->get_active() == m_xLB_WHERECOMP3->get_count()-2)) ) + m_xET_WHEREVALUE3->set_sensitive(false); +} + +IMPL_LINK( DlgFilterCrit, ListSelectHdl, weld::ComboBox&, rListBox, void ) +{ + OUString aName; + weld::ComboBox* pComp; + if(&rListBox == m_xLB_WHEREFIELD1.get()) + { + aName = m_xLB_WHEREFIELD1->get_active_text(); + pComp = m_xLB_WHERECOMP1.get(); + } + else if(&rListBox == m_xLB_WHEREFIELD2.get()) + { + aName = m_xLB_WHEREFIELD2->get_active_text(); + pComp = m_xLB_WHERECOMP2.get(); + } + else + { + aName = m_xLB_WHEREFIELD3->get_active_text(); + pComp = m_xLB_WHERECOMP3.get(); + } + + pComp->clear(); + + Reference<XPropertySet> xColumn = getColumn(aName); + if ( xColumn.is() ) + { + sal_Int32 nDataType = 0; + xColumn->getPropertyValue(PROPERTY_TYPE) >>= nDataType; + sal_Int32 eColumnSearch = dbtools::getSearchColumnFlag(m_xConnection,nDataType); + + if(eColumnSearch == ColumnSearch::FULL) + { + for(size_t i=0;i < m_aSTR_COMPARE_OPERATORS.size(); i++) + pComp->append_text(m_aSTR_COMPARE_OPERATORS[i]); + } + else if(eColumnSearch == ColumnSearch::CHAR) + { + for(sal_Int32 i=6; i<10; i++) + pComp->append_text(m_aSTR_COMPARE_OPERATORS[i]); + } + else if(eColumnSearch == ColumnSearch::BASIC) + { + size_t i; + for( i = 0; i < 6; i++ ) + pComp->append_text(m_aSTR_COMPARE_OPERATORS[i]); + for(i=8; i < m_aSTR_COMPARE_OPERATORS.size(); ++i) + pComp->append_text(m_aSTR_COMPARE_OPERATORS[i]); + } + else + { + OSL_FAIL("DlgFilterCrit::ListSelectHdl: This column should not exist at all."); + } + } + pComp->set_active(0); + + EnableLines(); +} + +IMPL_LINK_NOARG(DlgFilterCrit, ListSelectCompHdl, weld::ComboBox&, void) +{ + EnableLines(); +} + +void DlgFilterCrit::BuildWherePart() +{ + Sequence<Sequence<PropertyValue> > aFilter(1),aHaving(1); + + if( m_xLB_WHEREFIELD1->get_active() != 0 ) + { + PropertyValue aValue; + if ( getCondition(*m_xLB_WHEREFIELD1,*m_xLB_WHERECOMP1,*m_xET_WHEREVALUE1,aValue) ) + { + aHaving = { { aValue } }; + } + else + { + aFilter = { { aValue} }; + } + } + + if( m_xLB_WHEREFIELD2->get_active() != 0 ) + { + PropertyValue aValue; + Sequence<Sequence<PropertyValue> >& _rValues = aFilter; + if ( getCondition(*m_xLB_WHEREFIELD2,*m_xLB_WHERECOMP2,*m_xET_WHEREVALUE2,aValue) ) + _rValues = aHaving; + if ( m_xLB_WHERECOND2->get_active() ) + _rValues.realloc( _rValues.getLength() + 1); + sal_Int32 nPos = _rValues.getLength() - 1; + sal_Int32 nAndPos = _rValues[nPos].getLength(); + auto pValues = _rValues.getArray(); + pValues[nPos].realloc( _rValues[nPos].getLength() + 1); + pValues[nPos].getArray()[nAndPos] = aValue; + } + + if( m_xLB_WHEREFIELD3->get_active() != 0 ) + { + PropertyValue aValue; + Sequence<Sequence<PropertyValue> >& _rValues = aFilter; + if ( getCondition(*m_xLB_WHEREFIELD3,*m_xLB_WHERECOMP3,*m_xET_WHEREVALUE3,aValue) ) + _rValues = aHaving; + if (m_xLB_WHERECOND3->get_active()) + _rValues.realloc( _rValues.getLength() + 1); + sal_Int32 nPos = _rValues.getLength() - 1; + sal_Int32 nAndPos = _rValues[nPos].getLength(); + auto pValues = _rValues.getArray(); + pValues[nPos].realloc( _rValues[nPos].getLength() + 1); + pValues[nPos].getArray()[nAndPos] = aValue; + } + try + { + m_xQueryComposer->setStructuredFilter(aFilter); + m_xQueryComposer->setStructuredHavingClause(aHaving); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void DlgFilterCrit::fillLines(int &i, const Sequence< Sequence< PropertyValue > >& _aValues) +{ + const Sequence<PropertyValue >* pOrIter = _aValues.getConstArray(); + const Sequence<PropertyValue >* pOrEnd = pOrIter + _aValues.getLength(); + bool bOr(i != 0); // WHERE clause and HAVING clause are always ANDed, nor ORed + for(; pOrIter != pOrEnd; ++pOrIter) + { + const PropertyValue* pAndIter = pOrIter->getConstArray(); + const PropertyValue* pAndEnd = pAndIter + pOrIter->getLength(); + for(;pAndIter != pAndEnd; ++pAndIter) + { + SetLine( i++,*pAndIter,bOr); + bOr = false; + } + bOr=true; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/queryorder.cxx b/dbaccess/source/ui/dlg/queryorder.cxx new file mode 100644 index 000000000..40b25cdd3 --- /dev/null +++ b/dbaccess/source/ui/dlg/queryorder.cxx @@ -0,0 +1,218 @@ +/* -*- 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 <strings.hrc> +#include <strings.hxx> +#include <core_resource.hxx> +#include <queryorder.hxx> +#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <connectivity/dbtools.hxx> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <tools/diagnose_ex.h> + +using namespace dbaui; +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::beans; + + +DlgOrderCrit::DlgOrderCrit(weld::Window * pParent, + const Reference< XConnection>& _rxConnection, + const Reference< XSingleSelectQueryComposer >& _rxComposer, + const Reference< XNameAccess>& _rxCols) + : GenericDialogController(pParent, "dbaccess/ui/sortdialog.ui", "SortDialog") + , m_xQueryComposer(_rxComposer) + , m_xColumns(_rxCols) + , m_xConnection(_rxConnection) + , m_xLB_ORDERFIELD1(m_xBuilder->weld_combo_box("field1")) + , m_xLB_ORDERVALUE1(m_xBuilder->weld_combo_box("value1")) + , m_xLB_ORDERFIELD2(m_xBuilder->weld_combo_box("field2")) + , m_xLB_ORDERVALUE2(m_xBuilder->weld_combo_box("value2")) + , m_xLB_ORDERFIELD3(m_xBuilder->weld_combo_box("field3")) + , m_xLB_ORDERVALUE3(m_xBuilder->weld_combo_box("value3")) +{ + m_aColumnList[0] = m_xLB_ORDERFIELD1.get(); + m_aColumnList[1] = m_xLB_ORDERFIELD2.get(); + m_aColumnList[2] = m_xLB_ORDERFIELD3.get(); + + m_aValueList[0] = m_xLB_ORDERVALUE1.get(); + m_aValueList[1] = m_xLB_ORDERVALUE2.get(); + m_aValueList[2] = m_xLB_ORDERVALUE3.get(); + + OUString aSTR_NOENTRY(DBA_RES(STR_VALUE_NONE)); + for (auto j : m_aColumnList) + { + j->append_text(aSTR_NOENTRY); + } + + for (int j=0; j < DOG_ROWS; ++j) + { + m_aColumnList[j]->set_active(0); + m_aValueList[j]->set_active(0); + } + try + { + // ... also the remaining fields + Sequence< OUString> aNames = m_xColumns->getElementNames(); + const OUString* pIter = aNames.getConstArray(); + const OUString* pEnd = pIter + aNames.getLength(); + Reference<XPropertySet> xColumn; + for(;pIter != pEnd;++pIter) + { + xColumn.set(m_xColumns->getByName(*pIter),UNO_QUERY); + OSL_ENSURE(xColumn.is(),"Column is null!"); + if ( xColumn.is() ) + { + sal_Int32 nDataType = 0; + xColumn->getPropertyValue(PROPERTY_TYPE) >>= nDataType; + sal_Int32 eColumnSearch = dbtools::getSearchColumnFlag(m_xConnection,nDataType); + if(eColumnSearch != ColumnSearch::NONE) + { + for (auto j : m_aColumnList) + { + j->append_text(*pIter); + } + } + } + } + + m_sOrgOrder = m_xQueryComposer->getOrder(); + impl_initializeOrderList_nothrow(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + EnableLines(); + + m_xLB_ORDERFIELD1->connect_changed(LINK(this,DlgOrderCrit,FieldListSelectHdl)); + m_xLB_ORDERFIELD2->connect_changed(LINK(this,DlgOrderCrit,FieldListSelectHdl)); +} + +DlgOrderCrit::~DlgOrderCrit() +{ +} + +IMPL_LINK_NOARG( DlgOrderCrit, FieldListSelectHdl, weld::ComboBox&, void ) +{ + EnableLines(); +} + +void DlgOrderCrit::impl_initializeOrderList_nothrow() +{ + try + { + static const OUStringLiteral sNameProperty = u"Name"; + static const OUStringLiteral sAscendingProperty = u"IsAscending"; + + Reference< XIndexAccess > xOrderColumns( m_xQueryComposer->getOrderColumns(), UNO_SET_THROW ); + sal_Int32 nColumns = xOrderColumns->getCount(); + if ( nColumns > DOG_ROWS ) + nColumns = DOG_ROWS; + + for ( sal_Int32 i = 0; i < nColumns; ++i ) + { + Reference< XPropertySet > xColumn( xOrderColumns->getByIndex( i ), UNO_QUERY_THROW ); + + OUString sColumnName; + bool bIsAscending( true ); + + xColumn->getPropertyValue( sNameProperty ) >>= sColumnName; + xColumn->getPropertyValue( sAscendingProperty ) >>= bIsAscending; + + m_aColumnList[i]->set_active_text(sColumnName); + m_aValueList[i]->set_active(bIsAscending ? 0 : 1); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void DlgOrderCrit::EnableLines() +{ + + if ( m_xLB_ORDERFIELD1->get_active() == 0 ) + { + m_xLB_ORDERFIELD2->set_sensitive(false); + m_xLB_ORDERVALUE2->set_sensitive(false); + + m_xLB_ORDERFIELD2->set_active( 0 ); + m_xLB_ORDERVALUE2->set_active( 0 ); + } + else + { + m_xLB_ORDERFIELD2->set_sensitive(true); + m_xLB_ORDERVALUE2->set_sensitive(true); + } + + if ( m_xLB_ORDERFIELD2->get_active() == 0 ) + { + m_xLB_ORDERFIELD3->set_sensitive(false); + m_xLB_ORDERVALUE3->set_sensitive(false); + + m_xLB_ORDERFIELD3->set_active( 0 ); + m_xLB_ORDERVALUE3->set_active( 0 ); + } + else + { + m_xLB_ORDERFIELD3->set_sensitive(true); + m_xLB_ORDERVALUE3->set_sensitive(true); + } +} + +OUString DlgOrderCrit::GetOrderList( ) const +{ + Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData(); + OUString sQuote = xMetaData.is() ? xMetaData->getIdentifierQuoteString() : OUString(); + + OUStringBuffer sOrder; + for( sal_uInt16 i=0 ; i<DOG_ROWS; i++ ) + { + if (m_aColumnList[i]->get_active() != 0) + { + if(!sOrder.isEmpty()) + sOrder.append(","); + + OUString sName = m_aColumnList[i]->get_active_text(); + sOrder.append(::dbtools::quoteName(sQuote,sName)); + if (m_aValueList[i]->get_active()) + sOrder.append(" DESC "); + else + sOrder.append(" ASC "); + } + } + return sOrder.makeStringAndClear(); +} + +void DlgOrderCrit::BuildOrderPart() +{ + m_xQueryComposer->setOrder(GetOrderList()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/sqlmessage.cxx b/dbaccess/source/ui/dlg/sqlmessage.cxx new file mode 100644 index 000000000..eacc59083 --- /dev/null +++ b/dbaccess/source/ui/dlg/sqlmessage.cxx @@ -0,0 +1,604 @@ +/* -*- 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 <core_resource.hxx> +#include <sqlmessage.hxx> +#include <strings.hrc> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <vcl/stdtext.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <osl/diagnose.h> +#include <connectivity/dbexception.hxx> +#include <connectivity/sqlerror.hxx> +#include <unotools/configmgr.hxx> + +#include <tools/urlobj.hxx> + +#define RET_MORE RET_RETRY + 1 + +using namespace dbtools; +using namespace com::sun::star::uno; +using namespace com::sun::star::sdb; +using namespace com::sun::star::sdbc; + +namespace dbaui +{ + +namespace +{ + class ImageProvider + { + private: + OUString m_defaultImageID; + + public: + explicit ImageProvider(const OUString& defaultImageID) + : m_defaultImageID(defaultImageID) + { + } + + const OUString& getImage() const + { + return m_defaultImageID; + } + }; + + class LabelProvider + { + private: + OUString m_label; + public: + explicit LabelProvider(TranslateId labelResourceID) + : m_label(DBA_RES(labelResourceID)) + { + } + + const OUString& getLabel() const + { + return m_label; + } + }; + + class ProviderFactory + { + private: + mutable std::shared_ptr< ImageProvider > m_pErrorImage; + mutable std::shared_ptr< ImageProvider > m_pWarningsImage; + mutable std::shared_ptr< ImageProvider > m_pInfoImage; + mutable std::shared_ptr< LabelProvider > m_pErrorLabel; + mutable std::shared_ptr< LabelProvider > m_pWarningsLabel; + mutable std::shared_ptr< LabelProvider > m_pInfoLabel; + + public: + ProviderFactory() + { + } + + std::shared_ptr< ImageProvider > const & getImageProvider( SQLExceptionInfo::TYPE _eType ) const + { + std::shared_ptr< ImageProvider >* ppProvider( &m_pErrorImage ); + OUString sNormalImageID("dialog-error"); + + switch ( _eType ) + { + case SQLExceptionInfo::TYPE::SQLWarning: + ppProvider = &m_pWarningsImage; + sNormalImageID = "dialog-warning"; + break; + + case SQLExceptionInfo::TYPE::SQLContext: + ppProvider = &m_pInfoImage; + sNormalImageID = "dialog-information"; + break; + + default: + break; + } + + if ( !ppProvider->get() ) + (*ppProvider) = std::make_shared<ImageProvider>(sNormalImageID); + return *ppProvider; + } + + std::shared_ptr< LabelProvider > const & getLabelProvider( SQLExceptionInfo::TYPE _eType, bool _bSubLabel ) const + { + std::shared_ptr< LabelProvider >* ppProvider( &m_pErrorLabel ); + TranslateId pLabelID( STR_EXCEPTION_ERROR ); + + switch ( _eType ) + { + case SQLExceptionInfo::TYPE::SQLWarning: + ppProvider = &m_pWarningsLabel; + pLabelID = STR_EXCEPTION_WARNING; + break; + + case SQLExceptionInfo::TYPE::SQLContext: + ppProvider = &m_pInfoLabel; + pLabelID = _bSubLabel ? STR_EXCEPTION_DETAILS : STR_EXCEPTION_INFO; + break; + default: + break; + } + + if ( !ppProvider->get() ) + (*ppProvider) = std::make_shared<LabelProvider>( pLabelID ); + return *ppProvider; + } + + }; + + /// a stripped version of the SQLException, packed for displaying + struct ExceptionDisplayInfo + { + SQLExceptionInfo::TYPE eType; + + std::shared_ptr< ImageProvider > pImageProvider; + std::shared_ptr< LabelProvider > pLabelProvider; + + bool bSubEntry; + + OUString sMessage; + OUString sSQLState; + OUString sErrorCode; + + ExceptionDisplayInfo() : eType( SQLExceptionInfo::TYPE::Undefined ), bSubEntry( false ) { } + explicit ExceptionDisplayInfo( SQLExceptionInfo::TYPE _eType ) : eType( _eType ), bSubEntry( false ) { } + }; + + bool lcl_hasDetails( const ExceptionDisplayInfo& _displayInfo ) + { + return ( !_displayInfo.sErrorCode.isEmpty() ) + || ( !_displayInfo.sSQLState.isEmpty() + && _displayInfo.sSQLState != "S1000" + ); + } + + typedef std::vector< ExceptionDisplayInfo > ExceptionDisplayChain; + + /// strips the [OOoBase] vendor identifier from the given error message, if applicable + OUString lcl_stripOOoBaseVendor( const OUString& _rErrorMessage ) + { + OUString sErrorMessage( _rErrorMessage ); + + const OUString sVendorIdentifier( ::connectivity::SQLError::getMessagePrefix() ); + if ( sErrorMessage.startsWith( sVendorIdentifier ) ) + { + // characters to strip + sal_Int32 nStripLen( sVendorIdentifier.getLength() ); + // usually, there should be a whitespace between the vendor and the real message + while ( ( sErrorMessage.getLength() > nStripLen ) + && ( sErrorMessage[nStripLen] == ' ' ) + ) + ++nStripLen; + sErrorMessage = sErrorMessage.copy( nStripLen ); + } + + return sErrorMessage; + } + + void lcl_buildExceptionChain( const SQLExceptionInfo& _rErrorInfo, const ProviderFactory& _rFactory, ExceptionDisplayChain& _out_rChain ) + { + ExceptionDisplayChain().swap(_out_rChain); + + SQLExceptionIteratorHelper iter( _rErrorInfo ); + while ( iter.hasMoreElements() ) + { + // current chain element + SQLExceptionInfo aCurrentElement; + iter.next( aCurrentElement ); + + const SQLException* pCurrentError = aCurrentElement; + OSL_ENSURE( pCurrentError, "lcl_buildExceptionChain: iterator failure!" ); + // hasMoreElements should not have returned <TRUE/> in this case + + ExceptionDisplayInfo aDisplayInfo( aCurrentElement.getType() ); + + aDisplayInfo.sMessage = pCurrentError->Message.trim(); + aDisplayInfo.sSQLState = pCurrentError->SQLState; + if ( pCurrentError->ErrorCode ) + aDisplayInfo.sErrorCode = OUString::number( pCurrentError->ErrorCode ); + + if ( aDisplayInfo.sMessage.isEmpty() + && !lcl_hasDetails( aDisplayInfo ) + ) + { + OSL_FAIL( "lcl_buildExceptionChain: useless exception: no state, no error code, no message!" ); + continue; + } + + aDisplayInfo.pImageProvider = _rFactory.getImageProvider( aCurrentElement.getType() ); + aDisplayInfo.pLabelProvider = _rFactory.getLabelProvider( aCurrentElement.getType(), false ); + + _out_rChain.push_back( aDisplayInfo ); + + if ( aCurrentElement.getType() == SQLExceptionInfo::TYPE::SQLContext ) + { + const SQLContext* pContext = aCurrentElement; + if ( !pContext->Details.isEmpty() ) + { + ExceptionDisplayInfo aSubInfo( aCurrentElement.getType() ); + + aSubInfo.sMessage = pContext->Details; + aSubInfo.pImageProvider = _rFactory.getImageProvider( aCurrentElement.getType() ); + aSubInfo.pLabelProvider = _rFactory.getLabelProvider( aCurrentElement.getType(), true ); + aSubInfo.bSubEntry = true; + + _out_rChain.push_back( aSubInfo ); + } + } + } + } + + void lcl_insertExceptionEntry(weld::TreeView& rList, size_t nElementPos, const ExceptionDisplayInfo& rEntry) + { + rList.append(OUString::number(nElementPos), rEntry.pLabelProvider->getLabel(), rEntry.pImageProvider->getImage()); + } +} + +namespace { + +class OExceptionChainDialog : public weld::GenericDialogController +{ + std::unique_ptr<weld::TreeView> m_xExceptionList; + std::unique_ptr<weld::TextView> m_xExceptionText; + + OUString m_sStatusLabel; + OUString m_sErrorCodeLabel; + + ExceptionDisplayChain m_aExceptions; + +public: + OExceptionChainDialog(weld::Window* pParent, ExceptionDisplayChain&& rExceptions); + +protected: + DECL_LINK(OnExceptionSelected, weld::TreeView&, void); +}; + +} + +OExceptionChainDialog::OExceptionChainDialog(weld::Window* pParent, ExceptionDisplayChain&& rExceptions) + : GenericDialogController(pParent, "dbaccess/ui/sqlexception.ui", "SQLExceptionDialog") + , m_xExceptionList(m_xBuilder->weld_tree_view("list")) + , m_xExceptionText(m_xBuilder->weld_text_view("description")) + , m_aExceptions(std::move(rExceptions)) +{ + int nListWidth = m_xExceptionText->get_approximate_digit_width() * 28; + int nTextWidth = m_xExceptionText->get_approximate_digit_width() * 42; + int nHeight = m_xExceptionList->get_height_rows(6); + m_xExceptionList->set_size_request(nListWidth, nHeight); + m_xExceptionText->set_size_request(nTextWidth, nHeight); + + m_sStatusLabel = DBA_RES( STR_EXCEPTION_STATUS ); + m_sErrorCodeLabel = DBA_RES( STR_EXCEPTION_ERRORCODE ); + + m_xExceptionList->connect_changed(LINK(this, OExceptionChainDialog, OnExceptionSelected)); + + bool bHave22018 = false; + size_t elementPos = 0; + + for (auto const& elem : m_aExceptions) + { + lcl_insertExceptionEntry(*m_xExceptionList, elementPos, elem); + bHave22018 = elem.sSQLState == "22018"; + ++elementPos; + } + + // if the error has the code 22018, then add an additional explanation + // #i24021# + if ( bHave22018 ) + { + ProviderFactory aProviderFactory; + + ExceptionDisplayInfo aInfo22018; + aInfo22018.sMessage = DBA_RES( STR_EXPLAN_STRINGCONVERSION_ERROR ); + aInfo22018.pLabelProvider = aProviderFactory.getLabelProvider( SQLExceptionInfo::TYPE::SQLContext, false ); + aInfo22018.pImageProvider = aProviderFactory.getImageProvider( SQLExceptionInfo::TYPE::SQLContext ); + m_aExceptions.push_back( aInfo22018 ); + + lcl_insertExceptionEntry(*m_xExceptionList, m_aExceptions.size() - 1, aInfo22018); + } + + if (m_xExceptionList->n_children()) + { + m_xExceptionList->select(0); + OnExceptionSelected(*m_xExceptionList); + } +} + +IMPL_LINK_NOARG(OExceptionChainDialog, OnExceptionSelected, weld::TreeView&, void) +{ + OUString sText; + + OUString sId(m_xExceptionList->get_selected_id()); + if (!sId.isEmpty()) + { + const ExceptionDisplayInfo& aExceptionInfo(m_aExceptions[sId.toUInt32()]); + + if ( !aExceptionInfo.sSQLState.isEmpty() ) + { + sText += m_sStatusLabel + ": " + aExceptionInfo.sSQLState + "\n"; + } + + if ( !aExceptionInfo.sErrorCode.isEmpty() ) + { + sText += m_sErrorCodeLabel + ": " + aExceptionInfo.sErrorCode + "\n"; + } + + if ( !sText.isEmpty() ) + sText += "\n"; + + sText += aExceptionInfo.sMessage; + } + + m_xExceptionText->set_text(sText); +} + +// SQLMessageBox_Impl +struct SQLMessageBox_Impl +{ + ExceptionDisplayChain aDisplayInfo; + + explicit SQLMessageBox_Impl( const SQLExceptionInfo& _rExceptionInfo ) + { + // transform the exception chain to a form more suitable for displaying it here + ProviderFactory aProviderFactory; + lcl_buildExceptionChain( _rExceptionInfo, aProviderFactory, aDisplayInfo ); + } +}; + +namespace +{ + void lcl_addButton(weld::MessageDialog* pDialog, StandardButtonType eType, bool bDefault) + { + sal_uInt16 nButtonID = 0; + switch (eType) + { + case StandardButtonType::Yes: + nButtonID = RET_YES; + pDialog->add_button(GetStandardText(StandardButtonType::Yes), nButtonID); + break; + case StandardButtonType::No: + nButtonID = RET_NO; + pDialog->add_button(GetStandardText(StandardButtonType::No), nButtonID); + break; + case StandardButtonType::OK: + nButtonID = RET_OK; + pDialog->add_button(GetStandardText(StandardButtonType::OK), nButtonID); + break; + case StandardButtonType::Cancel: + nButtonID = RET_CANCEL; + pDialog->add_button(GetStandardText(StandardButtonType::Cancel), nButtonID); + break; + case StandardButtonType::Retry: + nButtonID = RET_RETRY; + pDialog->add_button(GetStandardText(StandardButtonType::Retry), nButtonID); + break; + case StandardButtonType::Help: + nButtonID = RET_HELP; + pDialog->add_button(GetStandardText(StandardButtonType::Help), nButtonID); + break; + default: + OSL_FAIL( "lcl_addButton: invalid button id!" ); + break; + } + if (bDefault) + pDialog->set_default_response(nButtonID); + } +} + +void OSQLMessageBox::impl_fillMessages() +{ + OSL_PRECOND( !m_pImpl->aDisplayInfo.empty(), "OSQLMessageBox::impl_fillMessages: nothing to display at all?" ); + + if ( m_pImpl->aDisplayInfo.empty() ) + return; + const ExceptionDisplayInfo* pSecondInfo = nullptr; + + const ExceptionDisplayInfo& rFirstInfo = *m_pImpl->aDisplayInfo.begin(); + if ( m_pImpl->aDisplayInfo.size() > 1 ) + pSecondInfo = &m_pImpl->aDisplayInfo[1]; + OUString sPrimary, sSecondary; + sPrimary = rFirstInfo.sMessage; + // one or two texts to display? + if ( pSecondInfo ) + { + // we show two elements in the main dialog if and only if one of + // - the first element in the chain is an SQLContext, and the second + // element denotes its sub entry + // - the first and the second element are both independent (i.e. the second + // is no sub entry), and none of them is a context. + bool bFirstElementIsContext = ( rFirstInfo.eType == SQLExceptionInfo::TYPE::SQLContext ); + bool bSecondElementIsContext = ( pSecondInfo->eType == SQLExceptionInfo::TYPE::SQLContext ); + + if ( bFirstElementIsContext && pSecondInfo->bSubEntry ) + sSecondary = pSecondInfo->sMessage; + if ( !bFirstElementIsContext && !bSecondElementIsContext ) + sSecondary = pSecondInfo->sMessage; + } + + // primary text + m_xDialog->set_primary_text(lcl_stripOOoBaseVendor(sPrimary)); + + // secondary text (if applicable) + m_xDialog->set_secondary_text(lcl_stripOOoBaseVendor(sSecondary)); +} + +void OSQLMessageBox::impl_createStandardButtons( MessBoxStyle _nStyle ) +{ + if ( _nStyle & MessBoxStyle::YesNoCancel ) + { + lcl_addButton(m_xDialog.get(), StandardButtonType::Yes, bool(_nStyle & MessBoxStyle::DefaultYes)); + lcl_addButton(m_xDialog.get(), StandardButtonType::No, bool(_nStyle & MessBoxStyle::DefaultNo)); + lcl_addButton(m_xDialog.get(), StandardButtonType::Cancel, bool(_nStyle & MessBoxStyle::DefaultCancel)); + } + else if ( _nStyle & MessBoxStyle::OkCancel ) + { + lcl_addButton(m_xDialog.get(), StandardButtonType::OK, bool(_nStyle & MessBoxStyle::DefaultOk)); + lcl_addButton(m_xDialog.get(), StandardButtonType::Cancel, bool(_nStyle & MessBoxStyle::DefaultCancel)); + } + else if ( _nStyle & MessBoxStyle::YesNo ) + { + lcl_addButton(m_xDialog.get(), StandardButtonType::Yes, bool(_nStyle & MessBoxStyle::DefaultYes)); + lcl_addButton(m_xDialog.get(), StandardButtonType::No, bool(_nStyle & MessBoxStyle::DefaultNo)); + } + else if ( _nStyle & MessBoxStyle::RetryCancel ) + { + lcl_addButton(m_xDialog.get(), StandardButtonType::Retry, bool(_nStyle & MessBoxStyle::DefaultRetry)); + lcl_addButton(m_xDialog.get(), StandardButtonType::Cancel, bool(_nStyle & MessBoxStyle::DefaultCancel)); + } + else if ( _nStyle & MessBoxStyle::Ok ) + { + lcl_addButton(m_xDialog.get(), StandardButtonType::OK, true); + } + + if ( m_sHelpURL.isEmpty() ) + return; + + lcl_addButton(m_xDialog.get(), StandardButtonType::Help, false); + + OUString aTmp; + INetURLObject aHID( m_sHelpURL ); + if ( aHID.GetProtocol() == INetProtocol::Hid ) + aTmp = aHID.GetURLPath(); + else + aTmp = m_sHelpURL; + + m_xDialog->set_help_id(OUStringToOString(aTmp, RTL_TEXTENCODING_UTF8)); +} + +void OSQLMessageBox::impl_addDetailsButton() +{ + size_t nFirstPageVisible = m_xDialog->get_secondary_text().isEmpty() ? 1 : 2; + + bool bMoreDetailsAvailable = m_pImpl->aDisplayInfo.size() > nFirstPageVisible; + if ( !bMoreDetailsAvailable ) + { + // even if the text fits into what we can display, we might need to details button + // if there is more non-trivial information in the errors than the mere messages + for (auto const& error : m_pImpl->aDisplayInfo) + { + if ( lcl_hasDetails(error) ) + { + bMoreDetailsAvailable = true; + break; + } + } + } + + if ( bMoreDetailsAvailable ) + { + m_xDialog->add_button(GetStandardText(StandardButtonType::More), RET_MORE); + m_xMoreButton.reset(m_xDialog->weld_widget_for_response(RET_MORE)); + m_xMoreButton->connect_clicked(LINK(this, OSQLMessageBox, ButtonClickHdl)); + } +} + +void OSQLMessageBox::Construct(weld::Window* pParent, MessBoxStyle _nStyle, MessageType _eImage) +{ + // init the image + MessageType eType( _eImage ); + if ( eType == AUTO ) + { + switch ( m_pImpl->aDisplayInfo[0].eType ) + { + case SQLExceptionInfo::TYPE::SQLException: eType = Error; break; + case SQLExceptionInfo::TYPE::SQLWarning: eType = Warning; break; + case SQLExceptionInfo::TYPE::SQLContext: eType = Info; break; + default: OSL_FAIL( "OSQLMessageBox::Construct: invalid type!" ); + } + } + VclMessageType eMessageType; + switch (eType) + { + default: + OSL_FAIL( "OSQLMessageBox::impl_initImage: unsupported image type!" ); + [[fallthrough]]; + case Info: + eMessageType = VclMessageType::Info; + break; + case Warning: + eMessageType = VclMessageType::Warning; + break; + case Error: + eMessageType = VclMessageType::Error; + break; + case Query: + eMessageType = VclMessageType::Question; + break; + } + + m_xDialog.reset(Application::CreateMessageDialog(pParent, eMessageType, VclButtonsType::NONE, "")); + m_xDialog->set_title(utl::ConfigManager::getProductName() + " Base"); + + impl_fillMessages(); + + // create buttons + impl_createStandardButtons( _nStyle ); + impl_addDetailsButton(); +} + +OSQLMessageBox::OSQLMessageBox(weld::Window* pParent, const SQLExceptionInfo& rException, MessBoxStyle nStyle, const OUString& rHelpURL) + : m_pImpl(new SQLMessageBox_Impl(rException)) + , m_sHelpURL(rHelpURL) +{ + Construct(pParent, nStyle, AUTO); +} + +OSQLMessageBox::OSQLMessageBox(weld::Window* pParent, const OUString& rTitle, const OUString& rMessage, MessBoxStyle nStyle, MessageType eType, const ::dbtools::SQLExceptionInfo* pAdditionalErrorInfo ) +{ + SQLContext aError; + aError.Message = rTitle; + aError.Details = rMessage; + if (pAdditionalErrorInfo) + aError.NextException = pAdditionalErrorInfo->get(); + + m_pImpl.reset(new SQLMessageBox_Impl(SQLExceptionInfo(aError))); + + Construct(pParent, nStyle, eType); +} + +OSQLMessageBox::~OSQLMessageBox() +{ +} + +IMPL_LINK_NOARG(OSQLMessageBox, ButtonClickHdl, weld::Button&, void) +{ + OExceptionChainDialog aDlg(m_xDialog.get(), std::vector(m_pImpl->aDisplayInfo)); + aDlg.run(); +} + +// OSQLWarningBox +OSQLWarningBox::OSQLWarningBox(weld::Window* pParent, const OUString& rMessage, MessBoxStyle nStyle, + const ::dbtools::SQLExceptionInfo* pAdditionalErrorInfo ) + : OSQLMessageBox(pParent, DBA_RES(STR_EXCEPTION_WARNING), rMessage, nStyle, MessageType::Warning, pAdditionalErrorInfo) +{ +} + +// OSQLErrorBox +OSQLErrorBox::OSQLErrorBox(weld::Window* pParent, const OUString& rMessage) + : OSQLMessageBox(pParent, DBA_RES(STR_EXCEPTION_ERROR), rMessage, MessBoxStyle::Ok | MessBoxStyle::DefaultOk, + MessageType::Error, nullptr) +{ +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/tablespage.cxx b/dbaccess/source/ui/dlg/tablespage.cxx new file mode 100644 index 000000000..6094f84e7 --- /dev/null +++ b/dbaccess/source/ui/dlg/tablespage.cxx @@ -0,0 +1,488 @@ +/* -*- 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 "tablespage.hxx" +#include <dsitems.hxx> +#include <datasourceconnector.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbexception.hxx> +#include <stringlistitem.hxx> +#include <svl/stritem.hxx> +#include <strings.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <sqlmessage.hxx> +#include <UITools.hxx> +#include <osl/diagnose.h> +#include <TablesSingleDlg.hxx> +#include <tools/diagnose_ex.h> +#include <cppuhelper/exc_hlp.hxx> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::sdbcx; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::util; + using namespace ::dbtools; + using namespace ::comphelper; + + // OTableSubscriptionPage + OTableSubscriptionPage::OTableSubscriptionPage(weld::Container* pPage, OTableSubscriptionDialog* pTablesDlg, const SfxItemSet& _rCoreAttrs) + : OGenericAdministrationPage(pPage, pTablesDlg, "dbaccess/ui/tablesfilterpage.ui", "TablesFilterPage", _rCoreAttrs) + , m_bCatalogAtStart(true) + , m_pTablesDlg(pTablesDlg) + , m_xTables(m_xBuilder->weld_widget("TablesFilterPage")) + , m_xTablesList(new OTableTreeListBox(m_xBuilder->weld_tree_view("treeview"), true)) + { + m_xTablesList->init(); + + weld::TreeView& rWidget = m_xTablesList->GetWidget(); + + rWidget.set_size_request(rWidget.get_approximate_digit_width() * 48, + rWidget.get_height_rows(12)); + + // initialize the TabListBox + rWidget.set_selection_mode(SelectionMode::Multiple); + + rWidget.connect_toggled(LINK(this, OTableSubscriptionPage, OnTreeEntryChecked)); + } + + OTableSubscriptionPage::~OTableSubscriptionPage() + { + // just to make sure that our connection will be removed + try + { + ::comphelper::disposeComponent(m_xCurrentConnection); + } + catch (RuntimeException&) { } + } + + void OTableSubscriptionPage::implCheckTables(const Sequence< OUString >& _rTables) + { + // the meta data for the current connection, used for splitting up table names + Reference< XDatabaseMetaData > xMeta; + try + { + if (m_xCurrentConnection.is()) + xMeta = m_xCurrentConnection->getMetaData(); + } + catch(SQLException&) + { + OSL_FAIL("OTableSubscriptionPage::implCheckTables : could not retrieve the current connection's meta data!"); + } + + // uncheck all + CheckAll(false); + + // check the ones which are in the list + OUString sCatalog, sSchema, sName; + + std::unique_ptr<weld::TreeIter> xRootEntry(m_xTablesList->getAllObjectsEntry()); + + for (const OUString& rIncludeTable : _rTables) + { + if (xMeta.is()) + qualifiedNameComponents(xMeta, rIncludeTable, sCatalog, sSchema, sName,::dbtools::EComposeRule::InDataManipulation); + else + sName = rIncludeTable; + + bool bAllTables = (1 == sName.getLength()) && ('%' == sName[0]); + bool bAllSchemas = (1 == sSchema.getLength()) && ('%' == sSchema[0]); + + // the catalog entry + std::unique_ptr<weld::TreeIter> xCatalog(m_xTablesList->GetEntryPosByName(sCatalog, xRootEntry.get())); + if (!(xCatalog || sCatalog.isEmpty())) + // the table (resp. its catalog) referred in this filter entry does not exist anymore + continue; + + if (bAllSchemas && xCatalog) + { + m_xTablesList->checkWildcard(*xCatalog); + continue; + } + + // the schema entry + std::unique_ptr<weld::TreeIter> xSchema = m_xTablesList->GetEntryPosByName(sSchema, (xCatalog ? xCatalog.get() : xRootEntry.get())); + if (!(xSchema || sSchema.isEmpty())) + // the table (resp. its schema) referred in this filter entry does not exist anymore + continue; + + if (bAllTables && xSchema) + { + m_xTablesList->checkWildcard(*xSchema); + continue; + } + + std::unique_ptr<weld::TreeIter> xEntry(m_xTablesList->GetEntryPosByName(sName, xSchema ? xSchema.get() : (xCatalog ? xCatalog.get() : xRootEntry.get()))); + if (xEntry) + m_xTablesList->GetWidget().set_toggle(*xEntry, TRISTATE_TRUE); + } + m_xTablesList->CheckButtons(); + } + + void OTableSubscriptionPage::implCompleteTablesCheck( const css::uno::Sequence< OUString >& _rTableFilter ) + { + if (!_rTableFilter.hasElements()) + { // no tables visible + CheckAll(false); + } + else + { + if ((1 == _rTableFilter.getLength()) && _rTableFilter[0] == "%") + { // all tables visible + CheckAll(); + } + else + implCheckTables( _rTableFilter ); + } + } + + void OTableSubscriptionPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + // get the name of the data source we're working for + const SfxStringItem* pNameItem = _rSet.GetItem<SfxStringItem>(DSID_NAME); + OSL_ENSURE(pNameItem, "OTableSubscriptionPage::implInitControls: missing the name attribute!"); + OUString sDSName = pNameItem->GetValue(); + + if (bValid && !sDSName.isEmpty() && !m_xCurrentConnection.is() ) + { // get the current table list from the connection for the current settings + + // the PropertyValues for the current dialog settings + Sequence< PropertyValue > aConnectionParams; + OSL_ENSURE(m_pTablesDlg, "OTableSubscriptionPage::implInitControls: need a parent dialog doing the translation!"); + if ( m_pTablesDlg ) + { + if (!m_pTablesDlg->getCurrentSettings(aConnectionParams)) + { + m_xTablesList->GetWidget().clear(); + m_pTablesDlg->endExecution(); + return; + } + } + + // fill the table list with this connection information + SQLExceptionInfo aErrorInfo; + + try + { + weld::WaitObject aWaitCursor(GetFrameWeld()); + + Reference<XPropertySet> xProp = m_pTablesDlg->getCurrentDataSource(); + OSL_ENSURE(xProp.is(),"No data source set!"); + if ( xProp.is() ) + { + Any aTableFilter = xProp->getPropertyValue(PROPERTY_TABLEFILTER); + Any aTableTypeFilter = xProp->getPropertyValue(PROPERTY_TABLETYPEFILTER); + + Reference<XModifiable> xModi(getDataSourceOrModel(xProp),UNO_QUERY); + bool bModified = ( xModi.is() && xModi->isModified() ); + + Sequence< OUString > aNewTableFilter { "%" }; + xProp->setPropertyValue(PROPERTY_TABLEFILTER,Any(aNewTableFilter)); + + xProp->setPropertyValue( PROPERTY_TABLETYPEFILTER, Any( Sequence< OUString >() ) ); + Reference< css::lang::XEventListener> xEvt; + aErrorInfo = ::dbaui::createConnection(xProp, m_xORB, xEvt, m_xCurrentConnection); + + xProp->setPropertyValue(PROPERTY_TABLEFILTER,aTableFilter); + xProp->setPropertyValue(PROPERTY_TABLETYPEFILTER,aTableTypeFilter); + + if ( xModi.is() && !bModified ) + xModi->setModified(false); + + } + + if ( m_xCurrentConnection.is() ) + { + m_xTablesList->UpdateTableList( m_xCurrentConnection ); + if (m_pTablesDlg) + m_pTablesDlg->successfullyConnected(); + } + } + catch (const SQLException&) + { + aErrorInfo = ::cppu::getCaughtException(); + } + + if (aErrorInfo.isValid()) + { + // establishing the connection failed. Show an error window and exit. + OSQLMessageBox aMessageBox(GetFrameWeld(), aErrorInfo); + aMessageBox.run(); + m_xTables->set_sensitive(false); + m_xTablesList->GetWidget().clear(); + + if ( m_pTablesDlg ) + { + m_pTablesDlg->clearPassword(); + m_pTablesDlg->endExecution(); + } + } + else + { + // in addition, we need some infos about the connection used + m_sCatalogSeparator = "."; // (default) + m_bCatalogAtStart = true; // (default) + try + { + Reference< XDatabaseMetaData > xMeta; + if (m_xCurrentConnection.is()) + xMeta = m_xCurrentConnection->getMetaData(); + if (xMeta.is() && xMeta->supportsCatalogsInDataManipulation()) + { + m_sCatalogSeparator = xMeta->getCatalogSeparator(); + m_bCatalogAtStart = xMeta->isCatalogAtStart(); + } + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + + // get the current table filter + const OStringListItem* pTableFilter = _rSet.GetItem<OStringListItem>(DSID_TABLEFILTER); + Sequence< OUString > aTableFilter; + if (pTableFilter) + aTableFilter = pTableFilter->getList(); + + implCompleteTablesCheck( aTableFilter ); + + // expand the first entry by default + std::unique_ptr<weld::TreeIter> xExpand = m_xTablesList->getAllObjectsEntry(); + while (xExpand) + { + m_xTablesList->GetWidget().expand_row(*xExpand); + if (!m_xTablesList->GetWidget().iter_children(*xExpand)) + break; + std::unique_ptr<weld::TreeIter> xSibling(m_xTablesList->GetWidget().make_iterator(xExpand.get())); + if (m_xTablesList->GetWidget().iter_next_sibling(*xSibling)) + xExpand.reset(); + } + + // update the toolbox according the current selection and check state + OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue); + } + + void OTableSubscriptionPage::CheckAll( bool _bCheck ) + { + std::unique_ptr<weld::TreeIter> xEntry(m_xTablesList->GetWidget().make_iterator()); + if (m_xTablesList->GetWidget().get_iter_first(*xEntry)) + { + do + { + m_xTablesList->GetWidget().set_toggle(*xEntry, _bCheck ? TRISTATE_TRUE : TRISTATE_FALSE); + } + while (m_xTablesList->GetWidget().iter_next(*xEntry)); + } + + if (_bCheck) + { + auto xRoot = m_xTablesList->getAllObjectsEntry(); + if (xRoot) + m_xTablesList->checkWildcard(*xRoot); + } + } + + DeactivateRC OTableSubscriptionPage::DeactivatePage(SfxItemSet* _pSet) + { + DeactivateRC nResult = OGenericAdministrationPage::DeactivatePage(_pSet); + + // dispose the connection, we don't need it anymore, so we're not wasting resources + try + { + ::comphelper::disposeComponent(m_xCurrentConnection); + } + catch (RuntimeException&) { } + + return nResult; + } + + IMPL_LINK(OTableSubscriptionPage, OnTreeEntryChecked, const weld::TreeView::iter_col&, rRowCol, void) + { + m_xTablesList->checkedButton_noBroadcast(rRowCol.first); + callModifiedHdl(); + } + + Sequence< OUString > OTableSubscriptionPage::collectDetailedSelection() const + { + Sequence< OUString > aTableFilter; + constexpr OUStringLiteral sWildcard = u"%"; + + std::unique_ptr<weld::TreeIter> xAllObjectsEntry(m_xTablesList->getAllObjectsEntry()); + if (!xAllObjectsEntry) + return aTableFilter; + std::unique_ptr<weld::TreeIter> xEntry(m_xTablesList->GetWidget().make_iterator(xAllObjectsEntry.get())); + if (!m_xTablesList->GetWidget().iter_next(*xEntry)) + xEntry.reset(); + while (xEntry) + { + bool bCatalogWildcard = false; + bool bSchemaWildcard = false; + std::unique_ptr<weld::TreeIter> xSchema; + std::unique_ptr<weld::TreeIter> xCatalog; + + if (m_xTablesList->GetWidget().get_toggle(*xEntry) == TRISTATE_TRUE && !m_xTablesList->GetWidget().iter_has_child(*xEntry)) + { // checked and a leaf, which means it's no catalog, no schema, but a real table + OUStringBuffer sComposedName; + OUString sCatalog; + if (m_xTablesList->GetWidget().get_iter_depth(*xEntry)) + { + xSchema = m_xTablesList->GetWidget().make_iterator(xEntry.get()); + m_xTablesList->GetWidget().iter_parent(*xSchema); + if (xAllObjectsEntry->equal(*xSchema)) + { + // do not want to have the root entry + xSchema.reset(); + } + + if (xSchema) + { // it's a real schema entry, not the "all objects" root + if (m_xTablesList->GetWidget().get_iter_depth(*xSchema)) + { + xCatalog = m_xTablesList->GetWidget().make_iterator(xSchema.get()); + m_xTablesList->GetWidget().iter_parent(*xCatalog); + if (xAllObjectsEntry->equal(*xCatalog)) + { + // do not want to have the root entry + xCatalog.reset(); + } + + if (xCatalog) + { // it's a real catalog entry, not the "all objects" root + bCatalogWildcard = m_xTablesList->isWildcardChecked(*xCatalog); + if (m_bCatalogAtStart) + { + sComposedName.append(m_xTablesList->GetWidget().get_text(*xCatalog) + m_sCatalogSeparator); + if (bCatalogWildcard) + sComposedName.append(sWildcard); + } + else + { + if (bCatalogWildcard) + sCatalog = sWildcard; + else + sCatalog.clear(); + sCatalog += m_sCatalogSeparator + m_xTablesList->GetWidget().get_text(*xCatalog) ; + } + } + } + bSchemaWildcard = m_xTablesList->isWildcardChecked(*xSchema); + sComposedName.append(m_xTablesList->GetWidget().get_text(*xSchema) + "."); + } + + if (bSchemaWildcard) + sComposedName.append(sWildcard); + } + if (!bSchemaWildcard && !bCatalogWildcard) + sComposedName.append(m_xTablesList->GetWidget().get_text(*xEntry)); + + if (!m_bCatalogAtStart && !bCatalogWildcard) + sComposedName.append(sCatalog); + + // need some space + sal_Int32 nOldLen = aTableFilter.getLength(); + aTableFilter.realloc(nOldLen + 1); + // add the new name + aTableFilter.getArray()[nOldLen] = sComposedName.makeStringAndClear(); + } + + if (bCatalogWildcard) + xEntry = implNextSibling(xCatalog.get()); + else if (bSchemaWildcard) + xEntry = implNextSibling(xSchema.get()); + else + { + if (!m_xTablesList->GetWidget().iter_next(*xEntry)) + xEntry.reset(); + } + } + + return aTableFilter; + } + + std::unique_ptr<weld::TreeIter> OTableSubscriptionPage::implNextSibling(const weld::TreeIter* pEntry) const + { + std::unique_ptr<weld::TreeIter> xReturn; + if (pEntry) + { + xReturn = m_xTablesList->GetWidget().make_iterator(pEntry); + if (!m_xTablesList->GetWidget().iter_next_sibling(*xReturn)) + { + std::unique_ptr<weld::TreeIter> xParent = m_xTablesList->GetWidget().make_iterator(pEntry); + if (m_xTablesList->GetWidget().iter_parent(*xParent)) + xReturn = implNextSibling(xParent.get()); + else + xReturn.reset(); + } + } + return xReturn; + } + + bool OTableSubscriptionPage::FillItemSet( SfxItemSet* _rCoreAttrs ) + { + bool bValid, bReadonly; + getFlags(*_rCoreAttrs, bValid, bReadonly); + + if (!bValid || bReadonly) + // don't store anything if the data we're working with is invalid or readonly + return true; + + // create the output string which contains all the table names + if ( m_xCurrentConnection.is() ) + { // collect the table filter data only if we have a connection - else no tables are displayed at all + Sequence< OUString > aTableFilter; + auto xRoot = m_xTablesList->getAllObjectsEntry(); + if (xRoot && m_xTablesList->isWildcardChecked(*xRoot)) + { + aTableFilter = { "%" }; + } + else + { + aTableFilter = collectDetailedSelection(); + } + _rCoreAttrs->Put( OStringListItem(DSID_TABLEFILTER, aTableFilter) ); + } + + return true; + } + + void OTableSubscriptionPage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& /*_rControlList*/) + { + } + + void OTableSubscriptionPage::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Widget>(m_xTables.get())); + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/tablespage.hxx b/dbaccess/source/ui/dlg/tablespage.hxx new file mode 100644 index 000000000..483518b2a --- /dev/null +++ b/dbaccess/source/ui/dlg/tablespage.hxx @@ -0,0 +1,81 @@ +/* -*- 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 "adminpages.hxx" +#include <tabletree.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> + +namespace dbaui +{ + + // OTableSubscriptionPage + class OTableSubscriptionDialog; + class OTableSubscriptionPage final + :public OGenericAdministrationPage + { + private: + OUString m_sCatalogSeparator; + bool m_bCatalogAtStart : 1; + + css::uno::Reference< css::sdbc::XConnection > + m_xCurrentConnection; /// valid as long as the page is active + OTableSubscriptionDialog* m_pTablesDlg; + + std::unique_ptr<weld::Widget> m_xTables; + std::unique_ptr<OTableTreeListBox> m_xTablesList; + + public: + virtual bool FillItemSet(SfxItemSet* _rCoreAttrs) override; + virtual DeactivateRC DeactivatePage(SfxItemSet* _pSet) override; + + OTableSubscriptionPage(weld::Container* pPage, OTableSubscriptionDialog* pController, const SfxItemSet& _rCoreAttrs); + virtual ~OTableSubscriptionPage() override; + + private: + virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override; + + DECL_LINK(OnTreeEntryChecked, const weld::TreeView::iter_col&, void); + + /** check the tables in <member>m_aTablesList</member> according to <arg>_rTables</arg> + */ + void implCheckTables(const css::uno::Sequence< OUString >& _rTables); + + /// returns the next sibling, if not available, the next sibling of the parent, a.s.o. + std::unique_ptr<weld::TreeIter> implNextSibling(const weld::TreeIter* pEntry) const; + + /** return the current selection in <member>m_aTablesList</member> + */ + css::uno::Sequence< OUString > collectDetailedSelection() const; + + /// (un)check all entries + void CheckAll( bool bCheck = true ); + + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + + // checks the tables according to the filter given + // in opposite to implCheckTables, this method handles the case of an empty sequence, too ... + void implCompleteTablesCheck( const css::uno::Sequence< OUString >& _rTableFilter ); + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/textconnectionsettings.cxx b/dbaccess/source/ui/dlg/textconnectionsettings.cxx new file mode 100644 index 000000000..5076b3d32 --- /dev/null +++ b/dbaccess/source/ui/dlg/textconnectionsettings.cxx @@ -0,0 +1,69 @@ +/* -*- 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 <textconnectionsettings.hxx> +#include "TextConnectionHelper.hxx" +#include <dsitems.hxx> +#include <stringconstants.hxx> + +namespace dbaui +{ + // TextConnectionSettingsDialog + TextConnectionSettingsDialog::TextConnectionSettingsDialog(weld::Window* pParent, SfxItemSet& rItems) + : GenericDialogController(pParent, "dbaccess/ui/textconnectionsettings.ui", "TextConnectionSettingsDialog") + , m_rItems(rItems) + , m_xContainer(m_xBuilder->weld_widget("TextPageContainer")) + , m_xOK(m_xBuilder->weld_button("ok")) + , m_xTextConnectionHelper(new OTextConnectionHelper(m_xContainer.get(), TC_HEADER | TC_SEPARATORS | TC_CHARSET)) + { + m_xOK->connect_clicked(LINK(this, TextConnectionSettingsDialog, OnOK)); + } + + TextConnectionSettingsDialog::~TextConnectionSettingsDialog() + { + } + + void TextConnectionSettingsDialog::bindItemStorages( SfxItemSet& _rSet, PropertyValues& _rValues ) + { + _rValues[ PROPERTY_ID_HEADER_LINE ] = std::make_shared<SetItemPropertyStorage>( _rSet, DSID_TEXTFILEHEADER ); + _rValues[ PROPERTY_ID_FIELD_DELIMITER ] = std::make_shared<SetItemPropertyStorage>( _rSet, DSID_FIELDDELIMITER ); + _rValues[ PROPERTY_ID_STRING_DELIMITER ] = std::make_shared<SetItemPropertyStorage>( _rSet, DSID_TEXTDELIMITER ); + _rValues[ PROPERTY_ID_DECIMAL_DELIMITER ] = std::make_shared<SetItemPropertyStorage>( _rSet, DSID_DECIMALDELIMITER ); + _rValues[ PROPERTY_ID_THOUSAND_DELIMITER ] = std::make_shared<SetItemPropertyStorage>( _rSet, DSID_THOUSANDSDELIMITER ); + _rValues[ PROPERTY_ID_ENCODING ] = std::make_shared<SetItemPropertyStorage>( _rSet, DSID_CHARSET ); + } + + short TextConnectionSettingsDialog::run() + { + m_xTextConnectionHelper->implInitControls(m_rItems, true); + return GenericDialogController::run(); + } + + IMPL_LINK_NOARG(TextConnectionSettingsDialog, OnOK, weld::Button&, void) + { + if (m_xTextConnectionHelper->prepareLeave()) + { + m_xTextConnectionHelper->FillItemSet( m_rItems, false/*bUnused*/ ); + m_xDialog->response(RET_OK); + } + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/AppElementType.hxx b/dbaccess/source/ui/inc/AppElementType.hxx new file mode 100644 index 000000000..59105cf22 --- /dev/null +++ b/dbaccess/source/ui/inc/AppElementType.hxx @@ -0,0 +1,53 @@ +/* -*- 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/sdb/application/DatabaseObject.hpp> + +namespace dbaui +{ + + enum ElementType + { + E_TABLE = css::sdb::application::DatabaseObject::TABLE, + E_QUERY = css::sdb::application::DatabaseObject::QUERY, + E_FORM = css::sdb::application::DatabaseObject::FORM, + E_REPORT = css::sdb::application::DatabaseObject::REPORT, + + E_NONE = 4, + E_ELEMENT_TYPE_COUNT = E_NONE + }; + + enum PreviewMode + { + E_PREVIEWNONE = 0, + E_DOCUMENT = 1, + E_DOCUMENTINFO = 2 + }; + + enum ElementOpenMode + { + E_OPEN_NORMAL, + E_OPEN_DESIGN, + E_OPEN_FOR_MAIL + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/ChildWindow.hxx b/dbaccess/source/ui/inc/ChildWindow.hxx new file mode 100644 index 000000000..8da6c8570 --- /dev/null +++ b/dbaccess/source/ui/inc/ChildWindow.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#pragma once + +#include <vcl/weld.hxx> + +namespace dbaui +{ +class OChildWindow +{ +protected: + OChildWindow(weld::Container* pParent, const OUString& rUIXMLDescription, const OString& rID); + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Container> m_xContainer; + +public: + virtual ~OChildWindow(); + + virtual void GrabFocus() = 0; + + virtual bool HasChildPathFocus() const = 0; + + void Enable(bool bEnable) { m_xContainer->set_sensitive(bEnable); } + + void SetHelpId(const OString& rHelpId) { m_xContainer->set_help_id(rHelpId); } + + void Show() { m_xContainer->show(); } +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/dbaccess/source/ui/inc/CollectionView.hxx b/dbaccess/source/ui/inc/CollectionView.hxx new file mode 100644 index 000000000..c80e98f5e --- /dev/null +++ b/dbaccess/source/ui/inc/CollectionView.hxx @@ -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 . + */ + +#pragma once + +#include <vcl/weld.hxx> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +namespace dbaui +{ + /* this class allows to browse through the collection of forms and reports + */ + class OCollectionView : public weld::GenericDialogController + { + css::uno::Reference< css::ucb::XContent> m_xContent; + css::uno::Reference< css::uno::XComponentContext > m_xContext; + css::uno::Reference< css::ucb::XCommandEnvironment > m_xCmdEnv; + bool m_bCreateForm; + + std::unique_ptr<weld::Label> m_xFTCurrentPath; + std::unique_ptr<weld::Button> m_xNewFolder; + std::unique_ptr<weld::Button> m_xUp; + std::unique_ptr<weld::TreeView> m_xView; + std::unique_ptr<weld::Entry> m_xName; + std::unique_ptr<weld::Button> m_xPB_OK; + + DECL_LINK(Up_Click, weld::Button&, void); + DECL_LINK(NewFolder_Click, weld::Button&, void); + DECL_LINK(Save_Click, weld::Button&, void); + DECL_LINK(Dbl_Click_FileView, weld::TreeView&, bool); + + /// sets the fixedtext to the right content + void initCurrentPath(); + + void Initialize(); + public: + OCollectionView(weld::Window * pParent, + const css::uno::Reference< css::ucb::XContent>& _xContent, + const OUString& _sDefaultName, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + virtual ~OCollectionView() override; + const css::uno::Reference< css::ucb::XContent>& getSelectedFolder() const { return m_xContent;} + OUString getName() const; + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/ColumnControlWindow.hxx b/dbaccess/source/ui/inc/ColumnControlWindow.hxx new file mode 100644 index 000000000..e68b99067 --- /dev/null +++ b/dbaccess/source/ui/inc/ColumnControlWindow.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 "FieldDescControl.hxx" +#include "TypeInfo.hxx" +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <vcl/InterimItemWindow.hxx> + +namespace dbaui +{ + // OColumnControlWindow + class OColumnControlWindow : public OFieldDescControl + { + css::lang::Locale m_aLocale; + css::uno::Reference< css::uno::XComponentContext> m_xContext; + css::uno::Reference< css::sdbc::XConnection> m_xConnection; + mutable css::uno::Reference< css::util::XNumberFormatter > m_xFormatter; // a number formatter working with the connection's NumberFormatsSupplier + + OTypeInfoMap m_aDestTypeInfo; + std::vector<OTypeInfoMap::iterator> m_aDestTypeInfoIndex; + + mutable TOTypeInfoSP m_pTypeInfo; // default type + OUString m_sTypeNames; // these type names are the ones out of the resource file + OUString m_sAutoIncrementValue; + bool m_bAutoIncrementEnabled; + protected: + virtual void ActivateAggregate( EControlType eType ) override; + virtual void DeactivateAggregate( EControlType eType ) override; + + virtual css::lang::Locale GetLocale() const override; + virtual css::uno::Reference< css::util::XNumberFormatter > GetFormatter() const override; + virtual TOTypeInfoSP getTypeInfo(sal_Int32 _nPos) override; + virtual bool isAutoIncrementValueEnabled() const override; + virtual OUString getAutoIncrementValue() const override; + virtual void CellModified(sal_Int32 nRow, sal_uInt16 nColId ) override; + + public: + OColumnControlWindow(weld::Container* pParent, + const css::uno::Reference< css::uno::XComponentContext>& _rxContext); + + void setConnection(const css::uno::Reference< css::sdbc::XConnection>& _xCon); + + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() override; + virtual css::uno::Reference< css::sdbc::XConnection> getConnection() override; + virtual const OTypeInfoMap* getTypeInfo() const override; + TOTypeInfoSP const & getDefaultTyp() const; + }; + + class OColumnControlTopLevel final : public InterimItemWindow + { + std::unique_ptr<OColumnControlWindow> m_xControl; + public: + OColumnControlTopLevel(vcl::Window* pParent, + const css::uno::Reference< css::uno::XComponentContext>& _rxContext); + virtual void dispose() override; + + OColumnControlWindow& GetControl() { return *m_xControl; } + + virtual void GetFocus() override; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/ConnectionLine.hxx b/dbaccess/source/ui/inc/ConnectionLine.hxx new file mode 100644 index 000000000..954c7e02d --- /dev/null +++ b/dbaccess/source/ui/inc/ConnectionLine.hxx @@ -0,0 +1,71 @@ +/* -*- 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 <tools/gen.hxx> +#include "ConnectionLineData.hxx" +#include <vcl/vclptr.hxx> + +class OutputDevice; +namespace dbaui +{ + + // ConnData ---------->* ConnLineData + // ^1 ^1 + // | | + // Conn ---------->* ConnLine + + /* + the class OConnectionLine represents the graphical line between the to two windows + **/ + class OTableConnection; + class OConnectionLine final + { + VclPtr<OTableConnection> m_pTabConn; + OConnectionLineDataRef m_pData; + + Point m_aSourceConnPos, + m_aDestConnPos; + Point m_aSourceDescrLinePos, + m_aDestDescrLinePos; + public: + OConnectionLine( OTableConnection* pConn, OConnectionLineDataRef const & pLineData ); + OConnectionLine( const OConnectionLine& rLine ); + ~OConnectionLine(); + + OConnectionLine& operator=( const OConnectionLine& rLine ); + + tools::Rectangle GetBoundingRect() const; + bool RecalcLine(); + void Draw( OutputDevice* pOutDev ); + bool CheckHit( const Point& rMousePos ) const; + + bool IsValid() const; + + tools::Rectangle GetSourceTextPos() const; + tools::Rectangle GetDestTextPos() const; + + const OConnectionLineDataRef& GetData() const { return m_pData; } + + Point getMidPoint() const; + }; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/ConnectionLineAccess.hxx b/dbaccess/source/ui/inc/ConnectionLineAccess.hxx new file mode 100644 index 000000000..1652b8b0b --- /dev/null +++ b/dbaccess/source/ui/inc/ConnectionLineAccess.hxx @@ -0,0 +1,91 @@ +/* -*- 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 "TableConnection.hxx" +#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp> +#include <cppuhelper/implbase2.hxx> +#include <toolkit/awt/vclxaccessiblecomponent.hxx> +#include <vcl/vclptr.hxx> + +namespace dbaui +{ + typedef ::cppu::ImplHelper2< css::accessibility::XAccessibleRelationSet, + css::accessibility::XAccessible + > OConnectionLineAccess_BASE; + class OTableConnection; + /** the class OConnectionLineAccess represents the accessible object for the connection between two table windows + like they are used in the QueryDesign and the RelationDesign + */ + class OConnectionLineAccess : public VCLXAccessibleComponent + , public OConnectionLineAccess_BASE + { + VclPtr<const OTableConnection> m_pLine; // the window which I should give accessibility to + protected: + /** this function is called upon disposing the component + */ + virtual void SAL_CALL disposing() override; + + public: + OConnectionLineAccess(OTableConnection* _pLine); + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire( ) noexcept override + { // here inline is allowed because we do not use this class outside this dll + VCLXAccessibleComponent::acquire( ); + } + virtual void SAL_CALL release( ) noexcept override + { // here inline is allowed because we do not use this class outside this dll + VCLXAccessibleComponent::release( ); + } + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + + // XAccessible + virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override; + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override; + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) override; + virtual sal_Int16 SAL_CALL getAccessibleRole( ) override; + virtual OUString SAL_CALL getAccessibleDescription( ) override; + virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override; + + // XAccessibleComponent + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override; + virtual css::awt::Rectangle SAL_CALL getBounds( ) override; + virtual css::awt::Point SAL_CALL getLocation( ) override; + virtual css::awt::Point SAL_CALL getLocationOnScreen( ) override; + virtual css::awt::Size SAL_CALL getSize( ) override; + + // XAccessibleRelationSet + virtual sal_Int32 SAL_CALL getRelationCount( ) override; + virtual css::accessibility::AccessibleRelation SAL_CALL getRelation( sal_Int32 nIndex ) override; + virtual sal_Bool SAL_CALL containsRelation( sal_Int16 aRelationType ) override; + virtual css::accessibility::AccessibleRelation SAL_CALL getRelationByType( sal_Int16 aRelationType ) override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/ConnectionLineData.hxx b/dbaccess/source/ui/inc/ConnectionLineData.hxx new file mode 100644 index 000000000..10ad0bfdd --- /dev/null +++ b/dbaccess/source/ui/inc/ConnectionLineData.hxx @@ -0,0 +1,80 @@ +/* -*- 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 "QEnumTypes.hxx" +#include <vector> + +#include <rtl/ref.hxx> +#include <salhelper/simplereferenceobject.hxx> +#include <rtl/ustring.hxx> + +namespace dbaui +{ + + // ConnData ---------->* ConnLineData + // ^1 ^1 + // | | + // Conn ---------->* ConnLine + + /** + the class OConnectionLineData contains the data of a connection + e.g. the source and the destination field + **/ + class OConnectionLineData : public ::salhelper::SimpleReferenceObject + { + OUString m_aSourceFieldName; + OUString m_aDestFieldName; + + friend bool operator==(const OConnectionLineData& lhs, const OConnectionLineData& rhs); + friend bool operator!=(const OConnectionLineData& lhs, const OConnectionLineData& rhs) { return !(lhs == rhs); } + protected: + virtual ~OConnectionLineData() override; + public: + OConnectionLineData(); + OConnectionLineData( const OUString& rSourceFieldName, const OUString& rDestFieldName ); + OConnectionLineData( const OConnectionLineData& rConnLineData ); + // provide a copy of own instance (this is somehow more acceptable for me compared to a virtual assignment operator + void CopyFrom(const OConnectionLineData& rSource); + + // member access (write) + void SetFieldName(EConnectionSide nWhich, const OUString& strFieldName) + { + if (nWhich==JTCS_FROM) + m_aSourceFieldName = strFieldName; + else + m_aDestFieldName = strFieldName; + } + void SetSourceFieldName( const OUString& rSourceFieldName){ SetFieldName(JTCS_FROM, rSourceFieldName); } + void SetDestFieldName( const OUString& rDestFieldName ){ SetFieldName(JTCS_TO, rDestFieldName); } + + // member access (read) + const OUString& GetFieldName(EConnectionSide nWhich) const { return (nWhich == JTCS_FROM) ? m_aSourceFieldName : m_aDestFieldName; } + OUString const & GetSourceFieldName() const { return GetFieldName(JTCS_FROM); } + OUString const & GetDestFieldName() const { return GetFieldName(JTCS_TO); } + + void Reset(); + OConnectionLineData& operator=( const OConnectionLineData& rConnLineData ); + }; + + typedef ::rtl::Reference< OConnectionLineData > OConnectionLineDataRef; + typedef std::vector< OConnectionLineDataRef > OConnectionLineDataVec; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/DExport.hxx b/dbaccess/source/ui/inc/DExport.hxx new file mode 100644 index 000000000..ab7c85811 --- /dev/null +++ b/dbaccess/source/ui/inc/DExport.hxx @@ -0,0 +1,162 @@ +/* -*- 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 <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <map> +#include <vector> +#include <comphelper/stl_types.hxx> +#include "TypeInfo.hxx" +#include "WTypeSelect.hxx" +#include "commontypes.hxx" +#include "IUpdateHelper.hxx" + +namespace com::sun::star { + namespace awt{ + struct FontDescriptor; + } + namespace sdbc{ + class XPreparedStatement; + class XDatabaseMetaData; + } +} + +#define COLUMN_POSITION_NOT_FOUND (sal_Int32(-1)) + +class SvNumberFormatter; +namespace dbaui +{ + class OFieldDescription; + class ODatabaseExport + { + public: + typedef std::map<OUString, OFieldDescription*, ::comphelper::UStringMixLess> TColumns; + typedef std::vector<TColumns::const_iterator> TColumnVector; + typedef std::vector< std::pair<sal_Int32,sal_Int32> > TPositions; + + protected: + TPositions m_vColumnPositions; ///< columns to be used + std::vector<sal_Int32> m_vColumnTypes; ///< ColumnTypes for faster access + std::vector<sal_Int32> m_vColumnSize; + std::vector<sal_Int16> m_vNumberFormat; + css::lang::Locale m_aLocale; + + TColumns m_aDestColumns; ///< container for new created columns + TColumnVector m_vDestVector; + + css::uno::Reference< css::beans::XPropertySet > m_xTable; ///< dest table + css::uno::Reference< css::container::XNameAccess> m_xTables; ///< container + SharedConnection m_xConnection; ///< dest conn + + std::shared_ptr<IUpdateHelper> m_pUpdateHelper; + css::uno::Reference< css::util::XNumberFormatter > m_xFormatter; ///< a number formatter working with the connection's NumberFormatsSupplier + css::uno::Reference< css::uno::XComponentContext> m_xContext; + css::util::Date m_aNullDate; + + SvNumberFormatter* m_pFormatter; + SvStream& m_rInputStream; + /// for saving the selected tablename + OUString m_sDefaultTableName; + + OUString m_sTextToken; ///< cell content + OUString m_sNumToken; ///< SDNUM value + TOTypeInfoSP m_pTypeInfo; ///< contains the default type + const TColumnVector* m_pColumnList; + const OTypeInfoMap* m_pInfoMap; + sal_Int32 m_nColumnPos; ///< current column position + sal_Int32 m_nRows; ///< number of rows to be searched + sal_Int32 m_nRowCount; ///< current count of rows + bool m_bError; ///< error and termination code + bool m_bInTbl; ///< true, if parser is in RTF table + bool m_bHead; ///< true, if the header hasn't been read yet + bool m_bDontAskAgain;///< if there is an error when pasting, don't show it again + bool m_bIsAutoIncrement; ///< if PKey is set by user + bool m_bFoundTable; ///< set to true when a table was found + bool m_bCheckOnly; + bool m_bAppendFirstLine; + + + virtual TypeSelectionPageFactory + getTypeSelectionPageFactory() = 0; + + void CreateDefaultColumn(const OUString& _rColumnName); + sal_Int16 CheckString(const OUString& aToken, sal_Int16 _nOldNumberFormat); + void adjustFormat(); + void eraseTokens(); + void insertValueIntoColumn(); + void createRowSet(); + void showErrorDialog(const css::sdbc::SQLException& e); + void ensureFormatter(); + + /** executeWizard calls a wizard to create/append data + + @param _sTableName the tablename + @param _aTextColor the text color of the new created table + @param _rFont the font of the new table + + @return true when an error occurs + */ + bool executeWizard( const OUString& _sTableName, + const css::uno::Any& _aTextColor, + const css::awt::FontDescriptor& _rFont); + + virtual ~ODatabaseExport(); + + public: + ODatabaseExport( + const SharedConnection& _rxConnection, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + SvStream& _rInputStream + ); + + // required for automatic type recognition + ODatabaseExport( + sal_Int32 nRows, + TPositions&& _rColumnPositions, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const TColumnVector* rList, + const OTypeInfoMap* _pInfoMap, + bool _bAutoIncrementEnabled, + SvStream& _rInputStream + ); + + void SetColumnTypes(const TColumnVector* rList,const OTypeInfoMap* _pInfoMap); + + void SetTableName(const OUString &_sTableName){ m_sDefaultTableName = _sTableName ; } + + void enableCheckOnly() { m_bCheckOnly = true; } + bool isCheckEnabled() const { return m_bCheckOnly; } + + static css::uno::Reference< css::sdbc::XPreparedStatement > createPreparedStatment( const css::uno::Reference< css::sdbc::XDatabaseMetaData>& _xMetaData + ,const css::uno::Reference< css::beans::XPropertySet>& _xDestTable + ,const TPositions& _rvColumnPositions); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/FieldControls.hxx b/dbaccess/source/ui/inc/FieldControls.hxx new file mode 100644 index 000000000..7eb88ec4e --- /dev/null +++ b/dbaccess/source/ui/inc/FieldControls.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 "SqlNameEdit.hxx" +#include <unotools/resmgr.hxx> + +namespace dbaui +{ + + class OPropColumnEditCtrl : public OSQLNameEntry + { + short m_nPos; + OUString m_strHelpText; + public: + OPropColumnEditCtrl(std::unique_ptr<weld::Entry> xEntry, OUString const & _rAllowedChars, TranslateId pHelpId, short nPosition); + + short GetPos() const { return m_nPos; } + const OUString& GetHelp() const { return m_strHelpText; } + }; + + class OPropEditCtrl : public OWidgetBase + { + std::unique_ptr<weld::Entry> m_xEntry; + short m_nPos; + OUString m_strHelpText; + + public: + OPropEditCtrl(std::unique_ptr<weld::Entry> xEntry, TranslateId pHelpId, short nPosition); + + void set_text(const OUString& rText) { m_xEntry->set_text(rText); } + OUString get_text() const { return m_xEntry->get_text(); } + void set_editable(bool bEditable) { m_xEntry->set_editable(bEditable); } + + virtual void save_value() override { m_xEntry->save_value(); } + virtual bool get_value_changed_from_saved() const override { return m_xEntry->get_value_changed_from_saved(); } + + short GetPos() const { return m_nPos; } + const OUString& GetHelp() const { return m_strHelpText; } + }; + + class OPropNumericEditCtrl : public OWidgetBase + { + std::unique_ptr<weld::SpinButton> m_xSpinButton; + short m_nPos; + OUString m_strHelpText; + + public: + OPropNumericEditCtrl(std::unique_ptr<weld::SpinButton> xSpinButton, TranslateId pHelpId, short nPosition); + + void set_text(const OUString& rText) { m_xSpinButton->set_text(rText); } + OUString get_text() const { return m_xSpinButton->get_text(); } + + virtual void save_value() override { m_xSpinButton->save_value(); } + virtual bool get_value_changed_from_saved() const override { return m_xSpinButton->get_value_changed_from_saved(); } + void set_digits(int nLen) { m_xSpinButton->set_digits(nLen); } + void set_min(int nMin) { m_xSpinButton->set_min(nMin); } + void set_max(int nMax) { m_xSpinButton->set_max(nMax); } + void set_range(int nMin, int nMax) { m_xSpinButton->set_range(nMin, nMax); } + int get_value() const { return m_xSpinButton->get_value(); } + + short GetPos() const { return m_nPos; } + const OUString& GetHelp() const { return m_strHelpText; } + + void set_editable(bool bEditable) { m_xSpinButton->set_editable(bEditable); } + }; + + class OPropListBoxCtrl : public OWidgetBase + { + std::unique_ptr<weld::ComboBox> m_xComboBox; + short m_nPos; + OUString m_strHelpText; + + public: + OPropListBoxCtrl(std::unique_ptr<weld::ComboBox> xComboBox, TranslateId pHelpId, short nPosition); + virtual ~OPropListBoxCtrl() override + { + m_xComboBox->clear(); + } + + virtual void save_value() override { m_xComboBox->save_value(); } + virtual bool get_value_changed_from_saved() const override { return m_xComboBox->get_value_changed_from_saved(); } + + weld::ComboBox& GetComboBox() { return *m_xComboBox; } + + OUString get_active_text() const { return m_xComboBox->get_active_text(); } + void set_active_text(const OUString &rText) { m_xComboBox->set_active_text(rText); } + + int get_active() const { return m_xComboBox->get_active(); } + void set_active(int nPos) { m_xComboBox->set_active(nPos); } + + int get_count() const { return m_xComboBox->get_count(); } + + void append_text(const OUString &rText) { m_xComboBox->append_text(rText); } + void remove_text(const OUString &rText) { m_xComboBox->remove_text(rText); } + int find_text(const OUString &rText) const { return m_xComboBox->find_text(rText); } + + short GetPos() const { return m_nPos; } + const OUString& GetHelp() const { return m_strHelpText; } + }; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/FieldDescControl.hxx b/dbaccess/source/ui/inc/FieldDescControl.hxx new file mode 100644 index 000000000..478a41070 --- /dev/null +++ b/dbaccess/source/ui/inc/FieldDescControl.hxx @@ -0,0 +1,201 @@ +/* -*- 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 <vcl/weld.hxx> +#include "IClipBoardTest.hxx" +#include "QEnumTypes.hxx" +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include "TypeInfo.hxx" +#include <unotools/resmgr.hxx> + +// field description columns of a table +#define FIELD_NAME 1 +#define FIELD_TYPE 2 +#define HELP_TEXT 3 +#define COLUMN_DESCRIPTION 4 + +#define FIELD_FIRST_VIRTUAL_COLUMN 5 + +#define FIELD_PROPERTY_REQUIRED 5 +#define FIELD_PROPERTY_NUMTYPE 6 +#define FIELD_PROPERTY_AUTOINC 7 +#define FIELD_PROPERTY_DEFAULT 8 +#define FIELD_PROPERTY_TEXTLEN 9 +#define FIELD_PROPERTY_LENGTH 10 +#define FIELD_PROPERTY_SCALE 11 +#define FIELD_PROPERTY_BOOL_DEFAULT 12 +#define FIELD_PROPERTY_FORMAT 13 +#define FIELD_PROPERTY_COLUMNNAME 14 +#define FIELD_PROPERTY_TYPE 15 +#define FIELD_PROPERTY_AUTOINCREMENT 16 + +namespace dbaui +{ + class OTableDesignHelpBar; + class OPropListBoxCtrl; + class OPropEditCtrl; + class OPropNumericEditCtrl; + class OFieldDescription; + class OPropColumnEditCtrl; + + class OFieldDescControl : public IClipboardTest + { + private: + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Container> m_xContainer; + + OTableDesignHelpBar* m_pHelp; + weld::Widget* m_pLastFocusWindow; + weld::Widget* m_pActFocusWindow; + + std::unique_ptr<weld::Label> m_xDefaultText; + std::unique_ptr<weld::Label> m_xRequiredText; + std::unique_ptr<weld::Label> m_xAutoIncrementText; + std::unique_ptr<weld::Label> m_xTextLenText; + std::unique_ptr<weld::Label> m_xNumTypeText; + std::unique_ptr<weld::Label> m_xLengthText; + std::unique_ptr<weld::Label> m_xScaleText; + std::unique_ptr<weld::Label> m_xFormatText; + std::unique_ptr<weld::Label> m_xBoolDefaultText; + std::unique_ptr<weld::Label> m_xColumnNameText; + std::unique_ptr<weld::Label> m_xTypeText; + std::unique_ptr<weld::Label> m_xAutoIncrementValueText; + + std::unique_ptr<OPropListBoxCtrl> m_xRequired; + std::unique_ptr<OPropListBoxCtrl> m_xNumType; + std::unique_ptr<OPropListBoxCtrl> m_xAutoIncrement; + std::unique_ptr<OPropEditCtrl> m_xDefault; + std::unique_ptr<OPropNumericEditCtrl> m_xTextLen; + std::unique_ptr<OPropNumericEditCtrl> m_xLength; + std::unique_ptr<OPropNumericEditCtrl> m_xScale; + std::unique_ptr<OPropEditCtrl> m_xFormatSample; + std::unique_ptr<OPropListBoxCtrl> m_xBoolDefault; + std::unique_ptr<OPropColumnEditCtrl> m_xColumnName; + std::unique_ptr<OPropListBoxCtrl> m_xType; + std::unique_ptr<OPropEditCtrl> m_xAutoIncrementValue; + + std::unique_ptr<weld::Button> m_xFormat; + + Link<weld::Widget&, void> m_aControlFocusIn; + + TOTypeInfoSP m_pPreviousType; + short m_nPos; + OUString aYes; + OUString aNo; + + sal_Int32 m_nEditWidth; + + OFieldDescription* pActFieldDescr; + + DECL_LINK(FormatClickHdl, weld::Button&, void); + DECL_LINK(ChangeHdl, weld::ComboBox&, void); + + // used by ActivatePropertyField + DECL_LINK( OnControlFocusLost, weld::Widget&, void ); + DECL_LINK( OnControlFocusGot, weld::Widget&, void ); + + DECL_LINK( HelpFocusOut, weld::Widget&, void ); + + void UpdateFormatSample(OFieldDescription const * pFieldDescr); + + bool isTextFormat(const OFieldDescription* _pFieldDescr,sal_uInt32& _nFormatKey) const; + std::unique_ptr<OPropNumericEditCtrl> CreateNumericControl(const OString& rId, TranslateId pHelpId, short _nProperty, const OString& _sHelpId); + void InitializeControl(weld::Widget* _pControl,const OString& _sHelpId); + void InitializeControl(OPropListBoxCtrl* _pControl,const OString& _sHelpId,bool _bAddChangeHandler); + + bool IsFocusInEditableWidget() const; + + void dispose(); + protected: + void saveCurrentFieldDescData() { SaveData( pActFieldDescr ); } + OFieldDescription* getCurrentFieldDescData() { return pActFieldDescr; } + void setCurrentFieldDescData( OFieldDescription* _pDesc ) { pActFieldDescr = _pDesc; } + + virtual void ActivateAggregate( EControlType eType ); + virtual void DeactivateAggregate( EControlType eType ); + virtual bool IsReadOnly() { return false; }; + + virtual css::uno::Reference< css::util::XNumberFormatter > GetFormatter() const = 0; + + virtual css::lang::Locale GetLocale() const = 0; + + virtual void CellModified(sal_Int32 nRow, sal_uInt16 nColId ) = 0; + virtual void SetModified(bool bModified); // base implementation is empty + + virtual TOTypeInfoSP getTypeInfo(sal_Int32 _nPos) = 0; + virtual const OTypeInfoMap* getTypeInfo() const = 0; + + virtual bool isAutoIncrementValueEnabled() const = 0; + virtual OUString getAutoIncrementValue() const = 0; + + OUString BoolStringPersistent(std::u16string_view rUIString) const; + OUString BoolStringUI(const OUString& rPersistentString) const; + + const OPropColumnEditCtrl* getColumnCtrl() const { return m_xColumnName.get(); } + + void implFocusLost(weld::Widget* _pWhich); + + public: + OFieldDescControl(weld::Container* pPage, OTableDesignHelpBar* pHelpBar); + virtual ~OFieldDescControl(); + + void DisplayData(OFieldDescription* pFieldDescr ); + + void SaveData( OFieldDescription* pFieldDescr ); + + void SetControlText( sal_uInt16 nControlId, const OUString& rText ); + void SetReadOnly( bool bReadOnly ); + + void Enable(bool bEnable) { m_xContainer->set_sensitive(bEnable); } + void SetHelpId(const OString& rId) { m_xContainer->set_help_id(rId); } + + virtual bool isCutAllowed() override; + virtual bool isCopyAllowed() override; + virtual bool isPasteAllowed() override; + + virtual void cut() override; + virtual void copy() override; + virtual void paste() override; + + void connect_focus_in(const Link<weld::Widget&, void>& rLink) + { + m_aControlFocusIn = rLink; + } + + void Init(); + + void GrabFocus(); + + bool HasChildPathFocus() const; + + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() = 0; + virtual css::uno::Reference< css::sdbc::XConnection> getConnection() = 0; + + OUString getControlDefault( const OFieldDescription* pFieldDescr, bool _bCheck = true) const; + // tdf#138409 take the control default in the UI Locale format, e.g. 12,34 and return a string + // suitable as the database default, e.g. 12.34 + OUString CanonicalizeToControlDefault(const OFieldDescription* pFieldDescr, const OUString& rUserText) const; + + void setEditWidth(sal_Int32 _nWidth) { m_nEditWidth = _nWidth; } + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/FieldDescriptions.hxx b/dbaccess/source/ui/inc/FieldDescriptions.hxx new file mode 100644 index 000000000..5eccd7430 --- /dev/null +++ b/dbaccess/source/ui/inc/FieldDescriptions.hxx @@ -0,0 +1,111 @@ +/* -*- 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 <editeng/svxenum.hxx> +#include "TypeInfo.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> + +namespace dbaui +{ + class OFieldDescription + { + private: + css::uno::Any m_aControlDefault; // the value which the control inserts as default + css::uno::Any m_aWidth; // sal_Int32 or void + css::uno::Any m_aRelativePosition; // sal_Int32 or void + + TOTypeInfoSP m_pType; + + css::uno::Reference< css::beans::XPropertySet > m_xDest; + css::uno::Reference< css::beans::XPropertySetInfo > m_xDestInfo; + + OUString m_sName; + OUString m_sTypeName; + OUString m_sDescription; + OUString m_sHelpText; + + OUString m_sAutoIncrementValue; + sal_Int32 m_nType; // only used when m_pType is null + sal_Int32 m_nPrecision; + sal_Int32 m_nScale; + sal_Int32 m_nIsNullable; + sal_Int32 m_nFormatKey; + SvxCellHorJustify m_eHorJustify; + bool m_bIsAutoIncrement; + bool m_bIsPrimaryKey; + bool m_bIsCurrency; + bool m_bHidden; + + public: + OFieldDescription(); + OFieldDescription( const OFieldDescription& rDescr ); + OFieldDescription(const css::uno::Reference< css::beans::XPropertySet >& _xAffectedCol + ,bool _bUseAsDest = false); + ~OFieldDescription(); + + void SetName(const OUString& _rName); + void SetDescription(const OUString& _rDescription); + void SetHelpText(const OUString& _sHelptext); + void SetDefaultValue(const css::uno::Any& _rDefaultValue); + void SetControlDefault(const css::uno::Any& _rControlDefault); + void SetAutoIncrementValue(const OUString& _sAutoIncValue); + void SetType(const TOTypeInfoSP& _pType); + void SetTypeValue(sal_Int32 _nType); + void SetTypeName(const OUString& _sTypeName); + void SetPrecision(sal_Int32 _rPrecision); + void SetScale(sal_Int32 _rScale); + void SetIsNullable(sal_Int32 _rIsNullable); + void SetFormatKey(sal_Int32 _rFormatKey); + void SetHorJustify(const SvxCellHorJustify& _rHorJustify); + void SetAutoIncrement(bool _bAuto); + void SetPrimaryKey(bool _bPKey); + void SetCurrency(bool _bIsCurrency); + + /** copies the content of the field description into the column + @param _rxColumn the dest + */ + void copyColumnSettingsTo(const css::uno::Reference< css::beans::XPropertySet >& _rxColumn); + + void FillFromTypeInfo(const TOTypeInfoSP& _pType,bool _bForce,bool _bReset); + + OUString GetName() const; + OUString GetDescription() const; + OUString GetHelpText() const; + css::uno::Any GetControlDefault() const; + OUString GetAutoIncrementValue() const; + sal_Int32 GetType() const; + OUString GetTypeName() const; + sal_Int32 GetPrecision() const; + sal_Int32 GetScale() const; + sal_Int32 GetIsNullable() const; + sal_Int32 GetFormatKey() const; + SvxCellHorJustify GetHorJustify() const; + const TOTypeInfoSP& getTypeInfo() const { return m_pType;} + TOTypeInfoSP getSpecialTypeInfo() const; + bool IsAutoIncrement() const; + bool IsPrimaryKey() const { return m_bIsPrimaryKey;} + bool IsCurrency() const { return m_bIsCurrency;} + bool IsNullable() const; + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/GeneralUndo.hxx b/dbaccess/source/ui/inc/GeneralUndo.hxx new file mode 100644 index 000000000..1bbb593e3 --- /dev/null +++ b/dbaccess/source/ui/inc/GeneralUndo.hxx @@ -0,0 +1,40 @@ +/* -*- 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 <svl/undo.hxx> +#include <core_resource.hxx> + +namespace dbaui +{ + // SbaCommentUndoAction - Undo base class for actions whose GetComment provides + // a string loaded from a Sba resource + + class OCommentUndoAction : public SfxUndoAction + { + OUString m_strComment; // undo, redo comment + + public: + OCommentUndoAction(TranslateId pCommentID) { m_strComment = DBA_RES(pCommentID); } + + virtual OUString GetComment() const override { return m_strComment; } + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/HtmlReader.hxx b/dbaccess/source/ui/inc/HtmlReader.hxx new file mode 100644 index 000000000..5c4ddde13 --- /dev/null +++ b/dbaccess/source/ui/inc/HtmlReader.hxx @@ -0,0 +1,68 @@ +/* -*- 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 "DExport.hxx" +#include <svtools/parhtml.hxx> +#include <editeng/svxenum.hxx> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +class SvStream; + +namespace dbaui +{ + class OHTMLReader final : public HTMLParser, public ODatabaseExport + { + OUString m_sCurrent; + sal_Int32 m_nTableCount; + sal_Int16 m_nColumnWidth; ///< maximum column width + + virtual void NextToken( HtmlTokenId nToken ) override; // base class + bool CreateTable( HtmlTokenId nToken ); + virtual TypeSelectionPageFactory + getTypeSelectionPageFactory() override; + + void TableDataOn(SvxCellHorJustify& eVal); + void TableFontOn(css::awt::FontDescriptor& _rFont, Color &_rTextColor); + sal_Int16 GetWidthPixel( const HTMLOption& rOption ); + void setTextEncoding(); + void fetchOptions(); + virtual ~OHTMLReader() override; + + public: + OHTMLReader(SvStream& rIn, + const SharedConnection& _rxConnection, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + // required for automatic type recognition + OHTMLReader(SvStream& rIn, + sal_Int32 nRows, + TPositions&& _rColumnPositions, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const TColumnVector* rList, + const OTypeInfoMap* _pInfoMap, + bool _bAutoIncrementEnabled); + + virtual SvParserState CallParser() override;// base class + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/IClipBoardTest.hxx b/dbaccess/source/ui/inc/IClipBoardTest.hxx new file mode 100644 index 000000000..e3eb04962 --- /dev/null +++ b/dbaccess/source/ui/inc/IClipBoardTest.hxx @@ -0,0 +1,40 @@ +/* -*- 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/types.h> + +namespace dbaui +{ + class SAL_NO_VTABLE IClipboardTest + { + public: + virtual bool isCutAllowed() = 0; + virtual bool isCopyAllowed() = 0; + virtual bool isPasteAllowed() = 0; + + virtual void copy() = 0; + virtual void cut() = 0; + virtual void paste() = 0; + + protected: + ~IClipboardTest() {} + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/IItemSetHelper.hxx b/dbaccess/source/ui/inc/IItemSetHelper.hxx new file mode 100644 index 000000000..cdc1026ea --- /dev/null +++ b/dbaccess/source/ui/inc/IItemSetHelper.hxx @@ -0,0 +1,72 @@ +/* -*- 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/types.h> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> + +namespace com::sun::star { + namespace sdbc { + class XConnection; + class XDriver; + } + namespace lang { + class XMultiServiceFactory; + } +} + +class SfxItemSet; +namespace dbaui +{ + class SAL_NO_VTABLE IItemSetHelper + { + public: + virtual const SfxItemSet* getOutputSet() const = 0; + virtual SfxItemSet* getWriteOutputSet() = 0; + + protected: + ~IItemSetHelper() {} + }; + + class SAL_NO_VTABLE IDatabaseSettingsDialog + { + public: + virtual css::uno::Reference< css::uno::XComponentContext > getORB() const = 0; + virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() = 0; + virtual css::uno::Reference< css::sdbc::XDriver > getDriver() = 0; + virtual OUString getDatasourceType(const SfxItemSet& _rSet) const = 0; + virtual void clearPassword() = 0; + virtual void saveDatasource() = 0; + virtual void setTitle(const OUString& _sTitle) = 0; + + /** enables or disables the user's possibility to confirm the settings + + In a wizard, disabling this will usually disable the "Finish" button. + In a normal tab dialog, this will usually disable the "OK" button. + */ + virtual void enableConfirmSettings( bool _bEnable ) = 0; + + protected: + ~IDatabaseSettingsDialog() {} + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/IUpdateHelper.hxx b/dbaccess/source/ui/inc/IUpdateHelper.hxx new file mode 100644 index 000000000..e6ef24a96 --- /dev/null +++ b/dbaccess/source/ui/inc/IUpdateHelper.hxx @@ -0,0 +1,44 @@ +/* -*- 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/util/Date.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/Time.hpp> + +namespace dbaui +{ + class SAL_NO_VTABLE IUpdateHelper + { + public: + virtual void updateString(sal_Int32 _nPos, const OUString& _sValue) = 0; + virtual void updateDouble(sal_Int32 _nPos,const double& _nValue) = 0; + virtual void updateInt(sal_Int32 _nPos, sal_Int32 _nValue) = 0; + virtual void updateNull(sal_Int32 _nPos, ::sal_Int32 sqlType) = 0; + virtual void updateDate(sal_Int32 _nPos,const css::util::Date& _nValue) = 0; + virtual void updateTime(sal_Int32 _nPos,const css::util::Time& _nValue) = 0; + virtual void updateTimestamp(sal_Int32 _nPos,const css::util::DateTime& _nValue) = 0; + virtual void insertRow() = 0; + + protected: + ~IUpdateHelper() {} + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/JAccess.hxx b/dbaccess/source/ui/inc/JAccess.hxx new file mode 100644 index 000000000..3a630faa2 --- /dev/null +++ b/dbaccess/source/ui/inc/JAccess.hxx @@ -0,0 +1,70 @@ +/* -*- 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 "JoinTableView.hxx" +#include <toolkit/awt/vclxaccessiblecomponent.hxx> +#include <cppuhelper/implbase1.hxx> +#include <vcl/vclptr.hxx> + +namespace dbaui +{ + class OJoinTableView; + typedef ::cppu::ImplHelper1< css::accessibility::XAccessible + > OJoinDesignViewAccess_BASE; + /** the class OJoinDesignViewAccess represents the accessible object for join views + like the QueryDesign and the RelationDesign + */ + class OJoinDesignViewAccess : public VCLXAccessibleComponent, public OJoinDesignViewAccess_BASE + { + VclPtr<OJoinTableView> m_pTableView; // the window which I should give accessibility to + + public: + /** OJoinDesignViewAccess needs a valid view + */ + OJoinDesignViewAccess( OJoinTableView* _pTableView); + + // XInterface + DECLARE_XINTERFACE( ) + DECLARE_XTYPEPROVIDER( ) + + virtual OUString SAL_CALL getImplementationName() override; + + // XAccessible + virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override; + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override; + virtual sal_Int16 SAL_CALL getAccessibleRole( ) override; + + void notifyAccessibleEvent( + const sal_Int16 _nEventId, + const css::uno::Any& _rOldValue, + const css::uno::Any& _rNewValue + ) + { + NotifyAccessibleEvent(_nEventId,_rOldValue,_rNewValue); + } + + void clearTableView(); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/JoinController.hxx b/dbaccess/source/ui/inc/JoinController.hxx new file mode 100644 index 000000000..941082322 --- /dev/null +++ b/dbaccess/source/ui/inc/JoinController.hxx @@ -0,0 +1,154 @@ +/* -*- 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 "singledoccontroller.hxx" +#include "JoinTableView.hxx" +#include "JoinDesignView.hxx" +#include "TableConnectionData.hxx" +#include "TableWindowData.hxx" +#include <memory> + +namespace comphelper +{ + class NamedValueCollection; +} + +namespace dbaui +{ + class OAddTableDlg; + class AddTableDialogContext; + class OTableWindow; + typedef OSingleDocumentController OJoinController_BASE; + + class OJoinController : public OJoinController_BASE + { + protected: + TTableConnectionData m_vTableConnectionData; + TTableWindowData m_vTableData; + + ::dbtools::SQLExceptionInfo m_aExceptionInfo; + + std::shared_ptr<OAddTableDlg> m_xAddTableDialog; + std::unique_ptr< AddTableDialogContext > m_pDialogContext; + Point m_aMinimumTableViewSize; + + // state of a feature. 'feature' may be the handle of a css::util::URL somebody requested a dispatch interface for OR a toolbar slot. + virtual FeatureState GetState(sal_uInt16 nId) const override; + // execute a feature + virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override; + + /** loads the information for the windows. + @param i_rViewSettings + The properties which comes from the layout information. + */ + void loadTableWindows( const ::comphelper::NamedValueCollection& i_rViewSettings ); + + /** loads the information for one window. + @param _rTable + The properties which comes from the layout information. + */ + void loadTableWindow( const ::comphelper::NamedValueCollection& i_rTableWindowSettings ); + + /** saves the TableWindows structure in a sequence of property values + @param _rViewProps + Contains the new sequence. + */ + void saveTableWindows( ::comphelper::NamedValueCollection& o_rViewSettings ) const; + + virtual ~OJoinController() override; + public: + OJoinController(const css::uno::Reference< css::uno::XComponentContext >& _rM); + + // attribute access + TTableWindowData& getTableWindowData() { return m_vTableData; } + TTableConnectionData& getTableConnectionData() { return m_vTableConnectionData;} + OAddTableDlg* getAddTableDialog()const { return m_xAddTableDialog.get(); } + + // OSingleDocumentController overridables + virtual void reconnect( bool _bUI ) override; + virtual void impl_onModifyChanged() override; + + // own overridables + /** determines whether or not it's allowed for database views to participate in the game + */ + virtual bool allowViews() const = 0; + + /** determines whether or not it's allowed for queries to participate in the game + */ + virtual bool allowQueries() const = 0; + + /** provides access to the OJoinDesignView belonging to the controller, which might + or might not be the direct view (getView) + */ + virtual OJoinDesignView* getJoinView(); + + /** erase the data in the data vector + @param _pData + the data which should be erased + */ + void removeConnectionData(const TTableConnectionData::value_type& _pData); + + void SaveTabWinsPosSize( OJoinTableView::OTableWindowMap* pTabWinList, tools::Long nOffsetX, tools::Long nOffsetY ); + + static void SaveTabWinPosSize(OTableWindow const * pTabWin, tools::Long nOffsetX, tools::Long nOffsetY); + + // UNO interface overridables + // XEventListener + using OJoinController_BASE::disposing; + + // css::lang::XComponent + virtual void SAL_CALL disposing() override; + // css::frame::XController + virtual sal_Bool SAL_CALL suspend(sal_Bool bSuspend) override; + + // misc + /** only defines a method to save a SQLException in d&d methods to show the error at a later state + set the internal member m_aExceptionInfo to _rInfo + */ + void setErrorOccurred(const ::dbtools::SQLExceptionInfo& _rInfo) + { + m_aExceptionInfo = _rInfo; + } + /** + just returns the internal member and clears it + */ + ::dbtools::SQLExceptionInfo clearOccurredError() + { + ::dbtools::SQLExceptionInfo aInfo = m_aExceptionInfo; + m_aExceptionInfo = ::dbtools::SQLExceptionInfo(); + return aInfo; + } + + // show the dialog + void runDialogAsync(); + + protected: + TTableWindowData::value_type createTableWindowData(const OUString& _sComposedName,const OUString& _sTableName,const OUString& _sWindowName); + // ask the user if the design should be saved when it is modified + virtual short saveModified() = 0; + // called when the original state should be reset (first time load) + virtual void reset() = 0; + virtual void describeSupportedFeatures() override; + + AddTableDialogContext& impl_getDialogContext() const; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/JoinDesignView.hxx b/dbaccess/source/ui/inc/JoinDesignView.hxx new file mode 100644 index 000000000..f4871e9df --- /dev/null +++ b/dbaccess/source/ui/inc/JoinDesignView.hxx @@ -0,0 +1,68 @@ +/* -*- 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 <dbaccess/dataview.hxx> + +class Splitter; + +namespace dbaui +{ + class OJoinController; + class OScrollWindowHelper; + class OJoinTableView; + class OTableWindow; + + class OJoinDesignView : public ODataView + { + protected: + VclPtr<OScrollWindowHelper> m_pScrollWindow; // contains only the scrollbars + VclPtr<OJoinTableView> m_pTableView; // presents the upper window + OJoinController& m_rController; + + public: + OJoinDesignView(vcl::Window* pParent, + OJoinController& _rController, + const css::uno::Reference< css::uno::XComponentContext >& ); + virtual ~OJoinDesignView() override; + virtual void dispose() override; + + // set the view readonly or not + virtual void setReadOnly(bool _bReadOnly); + // set the statement for representation + /// late construction + virtual void Construct() override; + virtual void initialize() override; + virtual void KeyInput( const KeyEvent& rEvt ) override; + + void SaveTabWinUIConfig(OTableWindow const * pWin); + OJoinController& getController() const { return m_rController; } + // called when fields are deleted + + OJoinTableView* getTableView() const { return m_pTableView; } + OScrollWindowHelper* getScrollHelper() const { return m_pScrollWindow; } + protected: + // return the Rectangle where I can paint myself + virtual void resizeDocumentView(tools::Rectangle& rRect) override; + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/JoinExchange.hxx b/dbaccess/source/ui/inc/JoinExchange.hxx new file mode 100644 index 000000000..7401ec886 --- /dev/null +++ b/dbaccess/source/ui/inc/JoinExchange.hxx @@ -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 . + */ +#pragma once + +#include "TableWindowListBox.hxx" + +#include <vcl/transfer.hxx> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <cppuhelper/implbase1.hxx> + +namespace dbaui +{ + // OJoinExchObj: Additional data to create Joins in the JoinShell + + typedef ::cppu::ImplHelper1< css::lang::XUnoTunnel > OJoinExchObj_Base; + class OJoinExchObj final : public TransferDataContainer, public OJoinExchObj_Base + { + bool m_bFirstEntry; + + OJoinExchangeData m_jxdSourceDescription; + + virtual ~OJoinExchObj() override; + + public: + OJoinExchObj(); + void setDescriptors(const OJoinExchangeData& jxdSource, bool _bFirstEntry); + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire( ) noexcept override; + virtual void SAL_CALL release( ) noexcept override; + + // XUnoTunnel + static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId(); + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& _rIdentifier ) override; + + static OJoinExchangeData GetSourceDescription(const css::uno::Reference< css::datatransfer::XTransferable >& _rxObject); + static bool isFormatAvailable( const DataFlavorExVector& _rFormats ,SotClipboardFormatId _nSlotID=SotClipboardFormatId::SBA_JOIN); + + private: + virtual void AddSupportedFormats() override; + virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/JoinTableView.hxx b/dbaccess/source/ui/inc/JoinTableView.hxx new file mode 100644 index 000000000..80de958ea --- /dev/null +++ b/dbaccess/source/ui/inc/JoinTableView.hxx @@ -0,0 +1,325 @@ +/* -*- 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 <vcl/window.hxx> +#include <vcl/timer.hxx> +#include <vcl/idle.hxx> +#include <vcl/scrbar.hxx> +#include <vcl/vclptr.hxx> +#include <vcl/transfer.hxx> + +#include "callbacks.hxx" +#include "TableConnectionData.hxx" +#include "TableWindowData.hxx" + +#include <map> +#include <vector> + +struct AcceptDropEvent; +struct ExecuteDropEvent; +class SfxUndoAction; + +namespace dbaui +{ + class OTableConnection; + class OTableWindow; + struct OJoinExchangeData; + class OJoinDesignView; + class OTableWindowData; + class OJoinDesignViewAccess; + + // this class contains only the scrollbars to avoid that + // the tablewindows clip the scrollbars + class OJoinTableView; + class OScrollWindowHelper : public vcl::Window + { + VclPtr<ScrollBar> m_aHScrollBar; + VclPtr<ScrollBar> m_aVScrollBar; + VclPtr<vcl::Window> m_pCornerWindow; + VclPtr<OJoinTableView> m_pTableView; + + protected: + virtual void Resize() override; + + public: + OScrollWindowHelper( vcl::Window* pParent); + virtual ~OScrollWindowHelper() override; + virtual void dispose() override; + + void setTableView(OJoinTableView* _pTableView); + + void resetRange(const Point& _aSize); + + // own methods + ScrollBar& GetHScrollBar() { return *m_aHScrollBar; } + ScrollBar& GetVScrollBar() { return *m_aVScrollBar; } + }; + + + class OJoinTableView : public vcl::Window, + public IDragTransferableListener, + public DropTargetHelper + { + friend class OJoinMoveTabWinUndoAct; + + public: + typedef std::map<OUString, VclPtr<OTableWindow> > OTableWindowMap; + + private: + OTableWindowMap m_aTableMap; + std::vector<VclPtr<OTableConnection> > m_vTableConnection; + + Idle m_aDragScrollIdle; + tools::Rectangle m_aDragRect; + tools::Rectangle m_aSizingRect; + Point m_aDragOffset; + Point m_aScrollOffset; + Point m_ptPrevDraggingPos; + Size m_aOutputSize; + + + VclPtr<OTableWindow> m_pDragWin; + VclPtr<OTableWindow> m_pSizingWin; + VclPtr<OTableConnection> m_pSelectedConn; + + + DECL_LINK(OnDragScrollTimer, Timer*, void); + + protected: + VclPtr<OTableWindow> m_pLastFocusTabWin; + VclPtr<OJoinDesignView> m_pView; + rtl::Reference<OJoinDesignViewAccess> m_pAccessible; + + public: + OJoinTableView( vcl::Window* pParent, OJoinDesignView* pView ); + virtual ~OJoinTableView() override; + virtual void dispose() override; + + // window override + virtual void StateChanged( StateChangedType nStateChange ) override; + virtual void GetFocus() override; + virtual void LoseFocus() override; + virtual void KeyInput( const KeyEvent& rEvt ) override; + // Accessibility + virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override; + + // own methods + ScrollBar& GetHScrollBar() { return static_cast<OScrollWindowHelper*>(GetParent())->GetHScrollBar(); } + ScrollBar& GetVScrollBar() { return static_cast<OScrollWindowHelper*>(GetParent())->GetVScrollBar(); } + DECL_LINK( ScrollHdl, ScrollBar*, void ); + + void DrawConnections(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect); + void InvalidateConnections(); + + void BeginChildMove( OTableWindow* pTabWin, const Point& rMousePos ); + void BeginChildSizing( OTableWindow* pTabWin, PointerStyle nPointer ); + + void NotifyTitleClicked( OTableWindow* pTabWin, const Point& rMousePos ); + + virtual void AddTabWin(const OUString& _rComposedName, const OUString& rWinName, bool bNewTable = false); + virtual void RemoveTabWin( OTableWindow* pTabWin ); + + // hide all TabWins (does NOT delete them; they are put in an UNDO action) + void HideTabWins(); + + virtual void AddConnection(const OJoinExchangeData& jxdSource, const OJoinExchangeData& jxdDest) = 0; + + /** RemoveConnection allows to remove connections from join table view + + it implies that the same as addConnection + + @param rConnection the connection which should be removed + @param bDelete when true then the connection will be deleted + + @return an iterator to next valid connection, so it can be used in any loop + */ + virtual bool RemoveConnection(VclPtr<OTableConnection>& rConnection, bool bDelete); + + /** allows to add new connections to join table view + + it implies an invalidation of the features ID_BROWSER_ADDTABLE and + SID_RELATION_ADD_RELATION also the modified flag will be set to true + + @param _pConnection the connection which should be added + @param _bAddData when true then the data should also be appended + */ + void addConnection(OTableConnection* _pConnection,bool _bAddData = true); + + bool ScrollPane( tools::Long nDelta, bool bHoriz, bool bPaintScrollBars ); + sal_uLong GetTabWinCount() const; + const Point& GetScrollOffset() const { return m_aScrollOffset; } + + OJoinDesignView* getDesignView() const { return m_pView; } + OTableWindow* GetTabWindow( const OUString& rName ); + + VclPtr<OTableConnection>& GetSelectedConn() { return m_pSelectedConn; } + /** @note NULL is explicitly allowed (then no-op) */ + void DeselectConn(OTableConnection* pConn); + void SelectConn(OTableConnection* pConn); + + OTableWindowMap& GetTabWinMap() { return m_aTableMap; } + + /** gives a read only access to the connection vector + */ + const std::vector<VclPtr<OTableConnection> >& getTableConnections() const { return m_vTableConnection; } + + bool ExistsAConn(const OTableWindow* pFromWin) const; + + /** search for all connections of a table + + @param _pFromWin the table for which connections should be found + @return an iterator which can be used to travel all connections of the table + */ + std::vector<VclPtr<OTableConnection> >::const_iterator getTableConnections(const OTableWindow* _pFromWin) const; + + /** how many connection belongs to single table + + @param _pFromWin the table for which connections should be found + @return the count of connections which belongs to this table + */ + sal_Int32 getConnectionCount(const OTableWindow* _pFromWin) const; + + OTableConnection* GetTabConn(const OTableWindow* pLhs,const OTableWindow* pRhs,bool _bSuppressCrossOrNaturalJoin = false) const; + + /** clear the window map and connection vector without destroying it + + that means that the data of the windows and connection will be + untouched + */ + void clearLayoutInformation(); + + /** set the focus to that tab win which most recently had it + (or to the first available one) **/ + void GrabTabWinFocus(); + + /** take all WinData and ConnData from the document and create the + corresponding Wins and Conns */ + virtual void ReSync() { } + + /** Hard deletion + + That means that all Conns and Wins are deleted from their respective + lists and the corresponding Data removed from the document */ + virtual void ClearAll(); + + /** @note used by AddTabDlg to see if more tables can be added */ + virtual bool IsAddAllowed(); + virtual bool PreNotify(NotifyEvent& rNEvt) override; + + // DnD stuff + virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override; + virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override; + + /** @note can be used for special ui handling after d&d */ + virtual void lookForUiActivities(); + + /** Hook that is called after moving/resizing TabWins + + The position is 'virtual': the container has a virtual area of + which only a part - changeable by scroll bar - is visible. + Therefore: ptOldPosition is always positive, even if it represents + a point with a negative physical ordinate above the visible area + + @note The standard implementation just passes the new data to the + Wins + */ + void TabWinMoved(OTableWindow* ptWhich, const Point& ptOldPosition); + + void TabWinSized(OTableWindow* ptWhich, const Point& ptOldPosition, const Size& szOldSize); + + void modified(); + + /** check if the given window is visible. + + @param _rPoint The Point to check + @param _rSize The Size to be check as well + @return true if the area is visible, false otherwise + */ + bool isMovementAllowed(const Point& _rPoint,const Size& _rSize); + + const Size& getRealOutputSize() const { return m_aOutputSize; } + + virtual void EnsureVisible(const OTableWindow* _pWin); + void EnsureVisible(const Point& _rPoint,const Size& _rSize); + + TTableWindowData::value_type createTableWindowData(const OUString& _rComposedName + ,const OUString& _sTableName + ,const OUString& _rWinName); + + protected: + virtual void MouseButtonUp( const MouseEvent& rEvt ) override; + virtual void MouseButtonDown( const MouseEvent& rEvt ) override; + virtual void Tracking( const TrackingEvent& rTEvt ) override; + virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override; + virtual void ConnDoubleClicked(VclPtr<OTableConnection>& rConnection); + void SetDefaultTabWinPosSize( OTableWindow* pTabWin ); + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + + virtual void Resize() override; + + virtual void dragFinished( ) override; + /// @note here the physical position (that can be changed while + /// resizing) is used, as no scrolling can take place while resizing + virtual void Command(const CommandEvent& rEvt) override; + + virtual std::shared_ptr<OTableWindowData> CreateImpl(const OUString& _rComposedName + ,const OUString& _sTableName + ,const OUString& _rWinName); + + /** factory method to create table windows + + @param _pData The data corresponding to the window. + @return The new TableWindow + */ + virtual VclPtr<OTableWindow> createWindow(const TTableWindowData::value_type& _pData) = 0; + + /** determines whether the classes Init method should accept a query + name, or only table names */ + virtual bool allowQueries() const; + + /** called when init fails at the tablewindowdata because the m_xTable + object could not provide columns, but no exception was thrown. + Expected to throw. */ + virtual void onNoColumns_throw(); + + virtual bool suppressCrossNaturalJoin(const TTableConnectionData::value_type& _pData) const; + + private: + void InitColors(); + void ScrollWhileDragging(); + + /** opens the context menu to delete a connection + @param _aPos the position where the popup menu should appear + @param _pSelConnection the connection which should be deleted + */ + void executePopup(const Point& _aPos, VclPtr<OTableConnection>& rSelConnection); + + /** invalidates this window without children and set the controller + modified + @param _pAction a possible undo action to add at the controller + */ + void invalidateAndModify(std::unique_ptr<SfxUndoAction> _pAction); + + private: + using Window::Scroll; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/QEnumTypes.hxx b/dbaccess/source/ui/inc/QEnumTypes.hxx new file mode 100644 index 000000000..b889870c9 --- /dev/null +++ b/dbaccess/source/ui/inc/QEnumTypes.hxx @@ -0,0 +1,79 @@ +/* -*- 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 + +namespace dbaui +{ + enum EOrderDir + { + ORDER_NONE=0, + ORDER_ASC, + ORDER_DESC + }; + + enum EFunctionType + { + FKT_NONE =0x00000000, + FKT_OTHER =0x00000001, + FKT_AGGREGATE =0x00000002, + FKT_CONDITION =0x00000004, + FKT_NUMERIC =0x00000008 + // if this function type is set, it is either EXISTS or UNIQUE, + // the FieldName contains the complete statement + }; + + enum EConnectionSide + { + JTCS_FROM=0, + JTCS_TO + }; + + enum ETableFieldType + { + TAB_NORMAL_FIELD=0, + TAB_PRIMARY_FIELD + }; + + enum EJoinType + { + FULL_JOIN=0, + LEFT_JOIN, + RIGHT_JOIN, + CROSS_JOIN, + INNER_JOIN + }; + + enum EControlType + { + tpDefault = 0, + tpRequired, + tpTextLen, + tpNumType, + tpLength, + tpScale, + tpFormat, + tpAutoIncrement, + tpBoolDefault, + tpColumnName, + tpType, + tpAutoIncrementValue + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/QueryDesignView.hxx b/dbaccess/source/ui/inc/QueryDesignView.hxx new file mode 100644 index 000000000..efef444e8 --- /dev/null +++ b/dbaccess/source/ui/inc/QueryDesignView.hxx @@ -0,0 +1,154 @@ +/* -*- 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 "JoinDesignView.hxx" +#include <vcl/split.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include "querycontroller.hxx" + +namespace connectivity +{ + class OSQLParseNode; +} +namespace weld +{ + class ComboBox; +} +namespace dbaui +{ + enum SqlParseError + { + eIllegalJoin, + eStatementTooLong, + eNoConnection, + eNoSelectStatement, + eStatementTooComplex, + eNoColumnInLike, + eColumnNotFound, + eNativeMode, + eTooManyTables, + eTooManyColumns, + eIllegalJoinCondition, + eOk + }; + + class OSelectionBrowseBox; + class OQueryContainerWindow; + class OQueryController; + + class OQueryDesignView : public OJoinDesignView + { + enum ChildFocusState + { + SELECTION, + TABLEVIEW, + NONE + }; + + VclPtr<Splitter> m_aSplitter; + + css::lang::Locale m_aLocale; + OUString m_sDecimalSep; + + VclPtr<OSelectionBrowseBox> m_pSelectionBox; // presents the lower window + ChildFocusState m_eChildFocus; + bool m_bInSplitHandler; + + public: + OQueryDesignView(OQueryContainerWindow* pParent, OQueryController& _rController, const css::uno::Reference< css::uno::XComponentContext >& ); + virtual ~OQueryDesignView() override; + virtual void dispose() override; + + bool isCutAllowed() const; + bool isPasteAllowed() const; + bool isCopyAllowed() const; + void copy(); + void cut(); + void paste(); + // clears the whole query + void clear(); + // set the view readonly or not + virtual void setReadOnly(bool _bReadOnly) override; + // check if the statement is correct when not returning false + bool checkStatement(); + // returns the current sql statement + OUString getStatement(); + /// late construction + virtual void Construct() override; + virtual void initialize() override; + // Window overrides + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + virtual void GetFocus() override; + + bool isSlotEnabled(sal_Int32 _nSlotId); + void setSlotEnabled(sal_Int32 _nSlotId, bool _bEnable); + void setNoneVisibleRow(sal_Int32 _nRows); + + const css::lang::Locale& getLocale() const { return m_aLocale;} + const OUString& getDecimalSeparator() const { return m_sDecimalSep;} + + SqlParseError InsertField( const OTableFieldDescRef& rInfo, bool bActivate = true); + bool HasFieldByAliasName(std::u16string_view rFieldName, OTableFieldDescRef const & rInfo) const; + // called when a table from tabview was deleted + void TableDeleted(const OUString& rAliasName); + + sal_Int32 getColWidth( sal_uInt16 _nColPos) const; + void fillValidFields(std::u16string_view strTableName, weld::ComboBox& rFieldList); + + void SaveUIConfig(); + void stopTimer(); + void startTimer(); + void reset(); + + /** initializes the view from the current parser / parse iterator of the controller + + @param _pErrorInfo + When not <NULL/>, the instance pointed to by this parameter takes the error + which happened during the initialization. + If it is not <NULL/>, then any such error will be displayed, using the controller's + showError method. + + @return <TRUE/> if and only if the initialization was successful + */ + bool initByParseIterator( ::dbtools::SQLExceptionInfo* _pErrorInfo ); + + void initByFieldDescriptions( + const css::uno::Sequence< css::beans::PropertyValue >& i_rFieldDescriptions + ); + + std::unique_ptr<::connectivity::OSQLParseNode> getPredicateTreeFromEntry( const OTableFieldDescRef& pEntry, + const OUString& _sCriteria, + OUString& _rsErrorMessage, + css::uno::Reference< css::beans::XPropertySet>& _rxColumn) const; + + void fillFunctionInfo( const ::connectivity::OSQLParseNode* pNode + ,const OUString& sFunctionTerm + ,OTableFieldDescRef& aInfo); + protected: + // return the Rectangle where I can paint myself + virtual void resizeDocumentView(tools::Rectangle& rRect) override; + DECL_LINK( SplitHdl, Splitter*, void ); + + private: + using OJoinDesignView::SaveTabWinUIConfig; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/QueryPropertiesDialog.hxx b/dbaccess/source/ui/inc/QueryPropertiesDialog.hxx new file mode 100644 index 000000000..2d8bb80dc --- /dev/null +++ b/dbaccess/source/ui/inc/QueryPropertiesDialog.hxx @@ -0,0 +1,45 @@ +/* -*- 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/. + */ + +#pragma once + +#include <vcl/weld.hxx> + +namespace dbaui +{ + +/** + * Dialog to set such properties of a query as distinct values and limit + * It can be opened from Edit menu in Query Design View + */ +class QueryPropertiesDialog : public weld::GenericDialogController +{ + +public: + + QueryPropertiesDialog( + weld::Window* pParent, const bool bDistinct, const sal_Int64 nLimit ); + virtual ~QueryPropertiesDialog() override; + bool getDistinct() const + { + return m_xRB_Distinct->get_active(); + } + + sal_Int64 getLimit() const; + +private: + + std::unique_ptr<weld::RadioButton> m_xRB_Distinct; + std::unique_ptr<weld::RadioButton> m_xRB_NonDistinct; + std::unique_ptr<weld::ComboBox> m_xLB_Limit; +}; + +} ///dbaui namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/QueryTableView.hxx b/dbaccess/source/ui/inc/QueryTableView.hxx new file mode 100644 index 000000000..26133d2cc --- /dev/null +++ b/dbaccess/source/ui/inc/QueryTableView.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 "JoinTableView.hxx" +#include "TableFieldDescription.hxx" + +namespace dbaui +{ + class OQueryTabWinUndoAct; + class OQueryTableConnection; + class OQueryTableWindow; + class OQueryDesignView; + + class OQueryTableView : public OJoinTableView + { + protected: + virtual void ConnDoubleClicked(VclPtr<OTableConnection>& rConnection) override; + + virtual VclPtr<OTableWindow> createWindow(const TTableWindowData::value_type& _pData) override; + + /** called when init fails at the tablewindowdata because the m_xTable + object could not provide columns, but no exception was thrown. + Expected to throw. */ + virtual void onNoColumns_throw() override; + + virtual bool suppressCrossNaturalJoin(const TTableConnectionData::value_type& _pData) const override; + + public: + OQueryTableView(vcl::Window* pParent,OQueryDesignView* pView); + + /// base class overwritten: create and delete windows + /// (not really delete, as it becomes an UndoAction) + bool ContainsTabWin(const OTableWindow& rTabWin); // #i122589# Allow to check if OTableWindow is registered + virtual void AddTabWin( const OUString& _rTableName, const OUString& _rAliasName, bool bNewTable = false ) override; + virtual void RemoveTabWin(OTableWindow* pTabWin) override; + + /// AddTabWin, setting an alias + void AddTabWin(const OUString& strDatabase, const OUString& strTableName, const OUString& strAlias, bool bNewTable); + /// search TabWin + OQueryTableWindow* FindTable(const OUString& rAliasName); + bool FindTableFromField(const OUString& rFieldName, OTableFieldDescRef const & rInfo, sal_uInt16& rCnt); + + /// base class overwritten: create and delete Connections + virtual void AddConnection(const OJoinExchangeData& jxdSource, const OJoinExchangeData& jxdDest) override; + + virtual bool RemoveConnection(VclPtr<OTableConnection>& rConn, bool bDelete) override; + + // transfer of connections from and to UndoAction + + /// Inserting a Connection the structure + void GetConnection(OQueryTableConnection* pConn); + /** Removing a Connection from the structure + + This results effectively in complete reset of request form, as all + windows are hidden, as are all Connections to these windows and all + request columns based on those tables */ + void DropConnection(VclPtr<OQueryTableConnection> const & rConn); + + // show and hide TabWin (NOT create or delete) + bool ShowTabWin(OQueryTableWindow* pTabWin, OQueryTabWinUndoAct* pUndoAction, bool _bAppend); + void HideTabWin(OQueryTableWindow* pTabWin, OQueryTabWinUndoAct* pUndoAction); + + /// ensure visibility of TabWins (+ and invalidate connections) + virtual void EnsureVisible(const OTableWindow* _pWin) override; + + /// how many tables with a certain alias do I already have? + sal_Int32 CountTableAlias(const OUString& rName, sal_Int32& rMax); + + /// insert field (simply passed to parents) + void InsertField(const OTableFieldDescRef& rInfo); + + /// rebuild everything (TabWins, Connections) + /// (PRECONDITION: ClearAll was called previously) + virtual void ReSync() override; + + /// delete everything hard (TabWins, Connections), without any notifications + virtual void ClearAll() override; + + // used by AddTabDlg to see if tables can still be added + //virtual sal_Bool IsAddAllowed(); + + /// announce new Connection and insert it, if not existing yet + void NotifyTabConnection(const OQueryTableConnection& rNewConn, bool _bCreateUndoAction = true); + + bool ExistsAVisitedConn(const OQueryTableWindow* pFrom) const; + + virtual std::shared_ptr<OTableWindowData> CreateImpl(const OUString& _rComposedName + ,const OUString& _sTableName + ,const OUString& _rWinName) override; + + /** opens the join dialog and allows to create a new join connection */ + void createNewConnection(); + + private: + using OJoinTableView::EnsureVisible; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/QueryTextView.hxx b/dbaccess/source/ui/inc/QueryTextView.hxx new file mode 100644 index 000000000..33f66342b --- /dev/null +++ b/dbaccess/source/ui/inc/QueryTextView.hxx @@ -0,0 +1,69 @@ +/* -*- 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 <vcl/InterimItemWindow.hxx> +#include "querycontainerwindow.hxx" +#include "sqledit.hxx" + +namespace dbaui +{ + class OQueryTextView final : public InterimItemWindow + { + friend class OQueryViewSwitch; + + OQueryController& m_rController; + std::unique_ptr<SQLEditView> m_xSQL; + std::unique_ptr<weld::CustomWeld> m_xSQLEd; + + Timer m_timerUndoActionCreation; + OUString m_strOrigText; // is restored on undo + Timer m_timerInvalidate; + bool m_bStopTimer; + + DECL_LINK(OnUndoActionTimer, Timer*, void); + DECL_LINK(OnInvalidateTimer, Timer*, void); + DECL_LINK(ModifyHdl, LinkParamNone*, void); + + public: + OQueryTextView(OQueryContainerWindow* pParent, OQueryController& rController); + virtual ~OQueryTextView() override; + virtual void dispose() override; + + void SetSQLText(const OUString& rNewText); + OUString GetSQLText() const; + + virtual void GetFocus() override; + + bool isCutAllowed() const; + void copy(); + void cut(); + void paste(); + // clears the whole query + void clear(); + // set the statement for representation + void setStatement(const OUString& _rsStatement); + OUString getStatement() const; + + void stopTimer(); + void startTimer(); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/QueryViewSwitch.hxx b/dbaccess/source/ui/inc/QueryViewSwitch.hxx new file mode 100644 index 000000000..0f17d40bd --- /dev/null +++ b/dbaccess/source/ui/inc/QueryViewSwitch.hxx @@ -0,0 +1,94 @@ +/* -*- 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/uno/XComponentContext.hpp> +#include <tools/gen.hxx> +#include <vcl/vclptr.hxx> + +namespace dbtools +{ + class SQLExceptionInfo; +} + +namespace dbaui +{ + class OQueryDesignView; + class OQueryTextView; + class OAddTableDlg; + class OQueryContainerWindow; + class OQueryController; + + class OQueryViewSwitch final + { + VclPtr<OQueryDesignView> m_pDesignView; + VclPtr<OQueryTextView> m_pTextView; + bool m_bAddTableDialogWasVisible; // true if so + public: + OQueryViewSwitch(OQueryContainerWindow* pParent, OQueryController& _rController,const css::uno::Reference< css::uno::XComponentContext >& ); + ~OQueryViewSwitch(); + + bool isCutAllowed() const; + bool isPasteAllowed() const; + bool isCopyAllowed() const; + void copy(); + void cut(); + void paste(); + // clears the whole query + void clear(); + // check if the statement is correct when not returning false + bool checkStatement(); + // set the statement for representation + void setStatement(const OUString& _rsStatement); + // returns the current sql statement + OUString getStatement(); + /// late construction + void Construct(); + void initialize(); + /** show the text or the design view + @return + <TRUE/> if and only if the view could be successfully, switched, <FALSE/> otherwise + (In the latter case, the controller will issue another switchView call to restore the + old state) + */ + bool switchView( ::dbtools::SQLExceptionInfo* _pErrorInfo ); + void forceInitialView(); + bool isSlotEnabled(sal_Int32 _nSlotId); + void setSlotEnabled(sal_Int32 _nSlotId, bool _bEnable); + void setNoneVisibleRow(sal_Int32 _nRows); + void SaveUIConfig(); + void reset(); + void GrabFocus(); + + // returns the add table dialog from the design view + OAddTableDlg* getAddTableDialog(); + + OQueryDesignView* getDesignView() const { return m_pDesignView; } + OQueryContainerWindow* getContainer() const; + + void SetPosSizePixel( Point _rPt,Size _rSize); + css::uno::Reference< css::uno::XComponentContext > const & getORB() const; + + private: + void impl_forceSQLView(); + bool impl_postViewSwitch( const bool i_bGraphicalDesign, const bool i_bSuccess ); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RTableConnectionData.hxx b/dbaccess/source/ui/inc/RTableConnectionData.hxx new file mode 100644 index 000000000..0dd40e2fa --- /dev/null +++ b/dbaccess/source/ui/inc/RTableConnectionData.hxx @@ -0,0 +1,79 @@ +/* -*- 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 "TableConnectionData.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include "QEnumTypes.hxx" + +namespace dbaui +{ + enum class Cardinality { + Undefined, OneMany, ManyOne, OneOne + }; + + class OConnectionLineData; + class ORelationTableConnectionData final : public OTableConnectionData + { + friend bool operator==(const ORelationTableConnectionData& lhs, const ORelationTableConnectionData& rhs); + + ::osl::Mutex m_aMutex; + + // @see com.sun.star.sdbc.KeyRule + sal_Int32 m_nUpdateRules; + sal_Int32 m_nDeleteRules; + Cardinality m_nCardinality; + + bool checkPrimaryKey(const css::uno::Reference< css::beans::XPropertySet>& i_xTable, EConnectionSide _eEConnectionSide) const; + bool IsSourcePrimKey() const { return checkPrimaryKey(getReferencingTable()->getTable(),JTCS_FROM); } + bool IsDestPrimKey() const { return checkPrimaryKey(getReferencedTable()->getTable(),JTCS_TO); } + + ORelationTableConnectionData& operator=( const ORelationTableConnectionData& rConnData ); + public: + ORelationTableConnectionData(); + ORelationTableConnectionData( const ORelationTableConnectionData& rConnData ); + ORelationTableConnectionData( const TTableWindowData::value_type& _pReferencingTable, + const TTableWindowData::value_type& _pReferencedTable, + const OUString& rConnName = OUString() ); + virtual ~ORelationTableConnectionData() override; + + virtual void CopyFrom(const OTableConnectionData& rSource) override; + virtual std::shared_ptr<OTableConnectionData> NewInstance() const override { return std::make_shared<ORelationTableConnectionData>(); } + + /** Update create a new relation + + @return true if successful + */ + virtual bool Update() override; + + void SetCardinality(); + void SetUpdateRules( sal_Int32 nAttr ){ m_nUpdateRules = nAttr; } + void SetDeleteRules( sal_Int32 nAttr ){ m_nDeleteRules = nAttr; } + + sal_Int32 GetUpdateRules() const { return m_nUpdateRules; } + sal_Int32 GetDeleteRules() const { return m_nDeleteRules; } + Cardinality GetCardinality() const { return m_nCardinality; } + + void IsConnectionPossible(); + void ChangeOrientation(); + void DropRelation(); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RelControliFace.hxx b/dbaccess/source/ui/inc/RelControliFace.hxx new file mode 100644 index 000000000..65ef79db0 --- /dev/null +++ b/dbaccess/source/ui/inc/RelControliFace.hxx @@ -0,0 +1,40 @@ +/* -*- 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 + +namespace dbaui +{ + class IRelationControlInterface + { + public: + virtual ~IRelationControlInterface(){} + + /** setValid set the valid inside, can be used for OK buttons + @param _bValid true when the using control allows an update + */ + virtual void setValid(bool _bValid) = 0; + + /** notifyConnectionChange is callback which is called when the table selection has changed and a new connection exists + @param _pConnectionData the connection which exists between the new tables + */ + virtual void notifyConnectionChange() = 0; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RelationControl.hxx b/dbaccess/source/ui/inc/RelationControl.hxx new file mode 100644 index 000000000..5d4edee2a --- /dev/null +++ b/dbaccess/source/ui/inc/RelationControl.hxx @@ -0,0 +1,91 @@ +/* -*- 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 <vcl/weld.hxx> +#include "JoinTableView.hxx" + +namespace dbaui +{ + class OTableListBoxControl; + class IRelationControlInterface; + class ORelationControl; + + class OTableListBoxControl final + { + std::unique_ptr<weld::ComboBox> m_xLeftTable; + std::unique_ptr<weld::ComboBox> m_xRightTable; + std::unique_ptr<weld::Container> m_xTable; + css::uno::Reference<css::awt::XWindow> m_xTableCtrlParent; + VclPtr<ORelationControl> m_xRC_Tables; + + const OJoinTableView::OTableWindowMap* m_pTableMap; + IRelationControlInterface* m_pParentDialog; + OUString m_strCurrentLeft; + OUString m_strCurrentRight; + DECL_LINK( OnTableChanged, weld::ComboBox&, void ); + public: + OTableListBoxControl(weld::Builder* _pParent, + const OJoinTableView::OTableWindowMap* _pTableMap, + IRelationControlInterface* _pParentDialog); + ~OTableListBoxControl(); + + /** fillListBoxes fills the list boxes with the table windows + */ + void fillListBoxes(); + + /** fillAndDisable fill the listboxes only with one entry and then disable them + @param _pConnectionData + contains the data which should be filled into the listboxes + */ + void fillAndDisable(const TTableConnectionData::value_type& _pConnectionData); + + /** enables the relation control + * + * \param _bEnable when sal_True enables it, otherwise disable it. + */ + void enableRelation(bool _bEnable); + + /** NotifyCellChange notifies the browse control that the connection data has changed + */ + void NotifyCellChange(); + + /** Init is a call through to the control inside this one + @param _pConnData + the connection data which is used to init the control + */ + void Init(const TTableConnectionData::value_type& _pConnData); + void lateUIInit(); + void lateInit(); + + void Disable(); + void Invalidate(); + + void SaveModified(); + + TTableWindowData::value_type const & getReferencingTable() const; + + /** getContainer returns the container interface + @return the interface of the container + */ + IRelationControlInterface* getContainer() const { return m_pParentDialog; } + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RelationController.hxx b/dbaccess/source/ui/inc/RelationController.hxx new file mode 100644 index 000000000..a457f38b8 --- /dev/null +++ b/dbaccess/source/ui/inc/RelationController.hxx @@ -0,0 +1,79 @@ +/* -*- 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 <memory> +#include <string_view> + +#include "JoinController.hxx" + +namespace weld +{ + class WaitObject; +} + +namespace dbaui +{ + class ORelationController : public OJoinController + { + css::uno::Reference< css::container::XNameAccess > m_xTables; + std::unique_ptr<weld::WaitObject> m_xWaitObject; + sal_uLong m_nThreadEvent; + bool m_bRelationsPossible; + protected: + // all the features which should be handled by this class + virtual void describeSupportedFeatures() override; + // state of a feature. 'feature' may be the handle of a css::util::URL somebody requested a dispatch interface for OR a toolbar slot. + virtual FeatureState GetState(sal_uInt16 nId) const override; + // execute a feature + virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override; + + void loadData(); + TTableWindowData::value_type existsTable(std::u16string_view _rComposedTableName) const; + + // load the window positions out of the datasource + void loadLayoutInformation(); + public: + ORelationController(const css::uno::Reference< css::uno::XComponentContext >& _rM); + + virtual ~ORelationController() override; + + void mergeData(const TTableConnectionData& _aConnectionData); + + virtual bool Construct(vcl::Window* pParent) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString> SAL_CALL getSupportedServiceNames() override; + + // OJoinController overridables + virtual bool allowViews() const override; + virtual bool allowQueries() const override; + + private: + // ask the user if the design should be saved when it is modified + virtual short saveModified() override; + virtual void reset() override; + virtual void impl_initialize() override; + virtual OUString getPrivateTitle( ) const override; + DECL_LINK( OnThreadFinished, void*, void ); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RelationDesignView.hxx b/dbaccess/source/ui/inc/RelationDesignView.hxx new file mode 100644 index 000000000..2fba88be0 --- /dev/null +++ b/dbaccess/source/ui/inc/RelationDesignView.hxx @@ -0,0 +1,45 @@ +/* -*- 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 "JoinDesignView.hxx" + +namespace dbaui +{ + class ORelationController; + + class ORelationDesignView : public OJoinDesignView + { + public: + ORelationDesignView(vcl::Window* pParent, ORelationController& _rController,const css::uno::Reference< css::uno::XComponentContext >& ); + + // set the statement for representation + /// late construction + virtual void Construct() override; + virtual void initialize() override; + + + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + virtual void GetFocus() override; + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RelationDlg.hxx b/dbaccess/source/ui/inc/RelationDlg.hxx new file mode 100644 index 000000000..c4285f04a --- /dev/null +++ b/dbaccess/source/ui/inc/RelationDlg.hxx @@ -0,0 +1,74 @@ +/* -*- 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 <memory> +#include <vcl/weld.hxx> +#include "JoinTableView.hxx" +#include "RelControliFace.hxx" +#include "RelationControl.hxx" + +namespace dbaui +{ + class OJoinTableView; + class ORelationDialog final : public weld::GenericDialogController + , public IRelationControlInterface + { + VclPtr<OJoinTableView> m_pParent; + TTableConnectionData::value_type m_pConnData; + TTableConnectionData::value_type m_pOrigConnData; + bool m_bTriedOneUpdate; + + std::unique_ptr<weld::RadioButton> m_xRB_NoCascUpd; + std::unique_ptr<weld::RadioButton> m_xRB_CascUpd; + std::unique_ptr<weld::RadioButton> m_xRB_CascUpdNull; + std::unique_ptr<weld::RadioButton> m_xRB_CascUpdDefault; + std::unique_ptr<weld::RadioButton> m_xRB_NoCascDel; + std::unique_ptr<weld::RadioButton> m_xRB_CascDel; + std::unique_ptr<weld::RadioButton> m_xRB_CascDelNull; + std::unique_ptr<weld::RadioButton> m_xRB_CascDelDefault; + std::unique_ptr<weld::Button> m_xPB_OK; + + std::unique_ptr<OTableListBoxControl> m_xTableControl; + + public: + ORelationDialog(OJoinTableView* pParent, + const TTableConnectionData::value_type& pConnectionData, + bool bAllowTableSelect = false ); + virtual ~ORelationDialog() override; + + virtual short run() override; + + /** setValid set the valid inside, can be used for OK buttons + @param _bValid true when the using control allows an update + */ + virtual void setValid(bool _bValid) override; + + /** notifyConnectionChange is callback which is called when the table selection has changed and a new connection exists + @param _pConnectionData the connection which exists between the new tables + */ + virtual void notifyConnectionChange() override; + private: + void Init(const TTableConnectionData::value_type& _pConnectionData); + + DECL_LINK(OKClickHdl, weld::Button&, void); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RelationTableView.hxx b/dbaccess/source/ui/inc/RelationTableView.hxx new file mode 100644 index 000000000..6c178a3de --- /dev/null +++ b/dbaccess/source/ui/inc/RelationTableView.hxx @@ -0,0 +1,74 @@ +/* -*- 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 "JoinTableView.hxx" +#include <comphelper/containermultiplexer.hxx> +#include <cppuhelper/basemutex.hxx> +#include <rtl/ref.hxx> + +namespace dbaui +{ + class ORelationDesignView; + + class ORelationTableView : public ::cppu::BaseMutex, + public OJoinTableView, + public ::comphelper::OContainerListener + { + VclPtr<OTableConnection> m_pExistingConnection; ///< is set when a connection was dragged on an existing connection + TTableConnectionData::value_type m_pCurrentlyTabConnData; ///< set when we creating a connection with more than one keycolumn + ::rtl::Reference< comphelper::OContainerListenerAdapter> m_pContainerListener; + bool m_bInRemove; + + virtual void ConnDoubleClicked(VclPtr<OTableConnection>& rConnection) override; + virtual void AddTabWin(const OUString& _rComposedName, const OUString& rWinName, bool bNewTable = false) override; + + virtual VclPtr<OTableWindow> createWindow(const TTableWindowData::value_type& _pData) override; + + /** determines whether the classes Init method should accept a query + name, or only table names */ + virtual bool allowQueries() const override; + + // OContainerListener + virtual void _elementInserted( const css::container::ContainerEvent& _rEvent ) override; + virtual void _elementRemoved( const css::container::ContainerEvent& _rEvent ) override; + virtual void _elementReplaced( const css::container::ContainerEvent& _rEvent ) override; + + public: + ORelationTableView( vcl::Window* pParent, ORelationDesignView* pView ); + virtual ~ORelationTableView() override; + virtual void dispose() override; + + virtual void RemoveTabWin( OTableWindow* pTabWin ) override; + virtual void AddConnection(const OJoinExchangeData& jxdSource, const OJoinExchangeData& jxdDest) override; + virtual bool RemoveConnection(VclPtr<OTableConnection>& rConn, bool _bDelete) override; + + virtual void ReSync() override; + + /// Creates a dialogue for a completely new relation. + void AddNewRelation(); + + /// used by AddTabDlg to check if tables can be added + virtual bool IsAddAllowed() override; + + virtual void lookForUiActivities() override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RtfReader.hxx b/dbaccess/source/ui/inc/RtfReader.hxx new file mode 100644 index 000000000..58f6aa26b --- /dev/null +++ b/dbaccess/source/ui/inc/RtfReader.hxx @@ -0,0 +1,59 @@ +/* -*- 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 <vector> +#include <svtools/parrtf.hxx> +#include "DExport.hxx" + +class SvStream; + +namespace dbaui +{ + class ORTFReader final : public SvRTFParser , public ODatabaseExport + { + std::vector<Color> m_vecColor; + + bool CreateTable(int nToken); + virtual void NextToken( int nToken ) override; // base class + virtual TypeSelectionPageFactory + getTypeSelectionPageFactory() override; + + virtual ~ORTFReader() override; + + public: + ORTFReader( SvStream& rIn, + const SharedConnection& _rxConnection, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + // required for automatic type recognition + ORTFReader( SvStream& rIn, + sal_Int32 nRows, + TPositions&& _rColumnPositions, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const TColumnVector* rList, + const OTypeInfoMap* _pInfoMap, + bool _bAutoIncrementEnabled); + + virtual SvParserState CallParser() override;// base class + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/SqlNameEdit.hxx b/dbaccess/source/ui/inc/SqlNameEdit.hxx new file mode 100644 index 000000000..257b18ebb --- /dev/null +++ b/dbaccess/source/ui/inc/SqlNameEdit.hxx @@ -0,0 +1,121 @@ +/* -*- 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/editbrowsebox.hxx> +#include <vcl/weld.hxx> + +namespace dbaui +{ + class OSQLNameChecker + { + OUString m_sAllowedChars; + bool m_bCheck; // true when we should check for invalid chars + public: + OSQLNameChecker(const OUString& _rAllowedChars) + :m_sAllowedChars(_rAllowedChars) + ,m_bCheck(true) + { + } + + void setAllowedChars(const OUString& _rAllowedChars) + { + m_sAllowedChars = _rAllowedChars; + } + void setCheck(bool _bCheck) + { + m_bCheck = _bCheck; + } + bool checkString(const OUString& _sToCheck,OUString& _rsCorrected); + }; + + class OSQLNameEditControl : public svt::EditControl + , public OSQLNameChecker + { + public: + OSQLNameEditControl(BrowserDataWin* pParent, const OUString& rAllowedChars) + : svt::EditControl(pParent) + , OSQLNameChecker(rAllowedChars) + { + m_xWidget->connect_changed(LINK(this, OSQLNameEditControl, ModifyHdl)); + } + + virtual void connect_changed(const Link<weld::Entry&, void>& rLink) override + { + m_ChainChangedHdl = rLink; + } + + private: + DECL_LINK(ModifyHdl, weld::Entry&, void); + + Link<weld::Entry&,void> m_ChainChangedHdl; + }; + + class OWidgetBase + { + private: + weld::Widget* m_pWidget; + public: + OWidgetBase(weld::Widget *pWidget) + : m_pWidget(pWidget) + { + } + + void hide() { m_pWidget->hide(); } + void show() { m_pWidget->show(); } + void set_sensitive(bool bSensitive) { m_pWidget->set_sensitive(bSensitive); } + + weld::Widget* GetWidget() { return m_pWidget; } + + virtual bool get_value_changed_from_saved() const = 0; + virtual void save_value() = 0; + + virtual ~OWidgetBase() {} + }; + + class OSQLNameEntry : public OWidgetBase + , public OSQLNameChecker + { + private: + std::unique_ptr<weld::Entry> m_xEntry; + + DECL_LINK(ModifyHdl, weld::Entry&, void); + + public: + OSQLNameEntry(std::unique_ptr<weld::Entry> xEntry, const OUString& _rAllowedChars = OUString()) + : OWidgetBase(xEntry.get()) + , OSQLNameChecker(_rAllowedChars) + , m_xEntry(std::move(xEntry)) + { + m_xEntry->connect_changed(LINK(this, OSQLNameEntry, ModifyHdl)); + } + + OUString get_text() const { return m_xEntry->get_text(); } + void set_text(const OUString& rText) { m_xEntry->set_text(rText); } + void set_max_length(int nLen) { m_xEntry->set_max_length(nLen); } + virtual void save_value() override { m_xEntry->save_value(); } + virtual bool get_value_changed_from_saved() const override + { + return m_xEntry->get_value_changed_from_saved(); + } + }; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableConnection.hxx b/dbaccess/source/ui/inc/TableConnection.hxx new file mode 100644 index 000000000..3c6ce0fdf --- /dev/null +++ b/dbaccess/source/ui/inc/TableConnection.hxx @@ -0,0 +1,98 @@ +/* -*- 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 <vector> +#include <vcl/window.hxx> +#include <com/sun/star/uno/Reference.h> +#include "TableConnectionData.hxx" + +class Point; +namespace tools { class Rectangle; } + +namespace dbaui +{ + class OTableConnectionData; + class OTableWindow; + class OJoinTableView; + class OConnectionLine; + + class OTableConnection : public vcl::Window + { + std::vector<std::unique_ptr<OConnectionLine>> m_vConnLine; + TTableConnectionData::value_type + m_pData; + VclPtr<OJoinTableView> m_pParent; + + bool m_bSelected; + + void Init(); + /** loops through the vector and deletes all lines */ + void clearLineData(); + + public: + OTableConnection( OJoinTableView* pContainer, const TTableConnectionData::value_type& pTabConnData ); + OTableConnection( const OTableConnection& rConn ); + /** destructor + + @attention Normally a pointer to OTableConnectionData is given but + here, however, one has to create an instance (with + OTableConnectionDate::NewInstance) which is never deleted + (same like in other cases). Thus, the caller is + responsible to check and save the data for deleting it + eventually. + */ + virtual ~OTableConnection() override; + virtual void dispose() override; + + OTableConnection& operator=( const OTableConnection& rConn ); + + void Select(); + void Deselect(); + bool IsSelected() const { return m_bSelected; } + bool CheckHit( const Point& rMousePos ) const; + void InvalidateConnection(); + void UpdateLineList(); + + OTableWindow* GetSourceWin() const; + OTableWindow* GetDestWin() const; + + void RecalcLines(); + /** isTableConnection + + @param _pTable the table where we should check if we belong to it + @return true when the source or the destination window are equal + */ + bool isTableConnection(const OTableWindow* _pTable) + { + return (_pTable == GetSourceWin() || _pTable == GetDestWin()); + } + + tools::Rectangle GetBoundingRect() const; + + const TTableConnectionData::value_type& GetData() const { return m_pData; } + const std::vector<std::unique_ptr<OConnectionLine>>& GetConnLineList() const { return m_vConnLine; } + OJoinTableView* GetParent() const { return m_pParent; } + virtual void Draw(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect); + using Window::Draw; + virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableConnectionData.hxx b/dbaccess/source/ui/inc/TableConnectionData.hxx new file mode 100644 index 000000000..38de22894 --- /dev/null +++ b/dbaccess/source/ui/inc/TableConnectionData.hxx @@ -0,0 +1,101 @@ +/* -*- 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 "ConnectionLineData.hxx" +#include "TableWindowData.hxx" +#include <vector> +#include <memory> + +namespace dbaui +{ + //===========================================// + // ConnData ---------->* ConnLineData // + // ^1 ^1 // + // | | // + // Conn ---------->* ConnLine // + //===========================================// + + /** Contains all connection data which exists between two windows */ + class OTableConnectionData + { + protected: + TTableWindowData::value_type m_pReferencingTable; + TTableWindowData::value_type m_pReferencedTable; + OUString m_aConnName; + + OConnectionLineDataVec m_vConnLineData; + + void Init(); + + OTableConnectionData& operator=( const OTableConnectionData& rConnData ); + public: + OTableConnectionData(); + OTableConnectionData( const TTableWindowData::value_type& _pReferencingTable, + const TTableWindowData::value_type& _pReferencedTable ); + OTableConnectionData( const OTableConnectionData& rConnData ); + virtual ~OTableConnectionData(); + + /// initialise from a source (more comfortable than a virtual assignment operator) + virtual void CopyFrom(const OTableConnectionData& rSource); + + /** deliver a new instance of my own type + + derived classes have to deliver an instance of their own type + + @note does NOT have to be initialised + */ + virtual std::shared_ptr<OTableConnectionData> NewInstance() const; + + void SetConnLine( sal_uInt16 nIndex, const OUString& rSourceFieldName, const OUString& rDestFieldName ); + bool AppendConnLine( const OUString& rSourceFieldName, const OUString& rDestFieldName ); + /** Deletes list of ConnLines + */ + void ResetConnLines(); + + /** moves the empty lines to the back + removes duplicated empty lines + + caller is responsible for repainting them + + @return index of first changed line, or one-past-the-end if no change + */ + OConnectionLineDataVec::size_type normalizeLines(); + + const OConnectionLineDataVec& GetConnLineDataList() const { return m_vConnLineData; } + OConnectionLineDataVec& GetConnLineDataList() { return m_vConnLineData; } + + const TTableWindowData::value_type& getReferencingTable() const { return m_pReferencingTable; } + const TTableWindowData::value_type& getReferencedTable() const { return m_pReferencedTable; } + + void setReferencingTable(const TTableWindowData::value_type& _pTable) { m_pReferencingTable = _pTable; } + void setReferencedTable(const TTableWindowData::value_type& _pTable) { m_pReferencedTable = _pTable; } + + /** Update create a new connection + + @return true if successful + */ + virtual bool Update(){ return true; } + }; + + typedef std::vector< std::shared_ptr<OTableConnectionData> > TTableConnectionData; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableController.hxx b/dbaccess/source/ui/inc/TableController.hxx new file mode 100644 index 000000000..ce2017b58 --- /dev/null +++ b/dbaccess/source/ui/inc/TableController.hxx @@ -0,0 +1,129 @@ +/* -*- 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 "singledoccontroller.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include "TypeInfo.hxx" +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XKeysSupplier.hpp> +#include <com/sun/star/container/XNameAccess.hpp> + +namespace dbaui +{ + class OTableRow; + typedef OSingleDocumentController OTableController_BASE; + class OTableController final : public OTableController_BASE + { + private: + std::vector< std::shared_ptr<OTableRow> > m_vRowList; + OTypeInfoMap m_aTypeInfo; + std::vector<OTypeInfoMap::iterator> m_aTypeInfoIndex; + + css::uno::Reference< css::beans::XPropertySet > m_xTable; + + OUString m_sName; // table for update data + OUString m_sAutoIncrementValue; // the autoincrement value set in the datasource + OUString m_sTypeNames; // these type names are the ones out of the resource file + TOTypeInfoSP m_pTypeInfo; // fall back when type is unknown because database driver has a failure + + bool m_bAllowAutoIncrementValue; // no : 1 NO BIT , is true when the datasource has an AutoIncrementValue property in their info property + bool m_bNew : 1; // is true when we create a new table + + + void reSyncRows(); + void assignTable(); // set the table if a name is given + void loadData(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + bool checkColumns(bool _bNew); // check if we have double column names + void appendColumns(css::uno::Reference< css::sdbcx::XColumnsSupplier> const & _rxColSup, bool _bNew, bool _bKeyColumns = false); + void appendPrimaryKey(css::uno::Reference< css::sdbcx::XKeysSupplier> const & _rxSup, bool _bNew); + void alterColumns(); + void dropPrimaryKey(); + css::uno::Reference< css::container::XNameAccess> getKeyColumns() const; + OUString createUniqueName(const OUString& _rName); + + void reload(); + + // all the features which should be handled by this class + virtual void describeSupportedFeatures() override; + // state of a feature. 'feature' may be the handle of a css::util::URL somebody requested a dispatch interface for OR a toolbar slot. + virtual FeatureState GetState(sal_uInt16 nId) const override; + // execute a feature + virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override; + + virtual void losingConnection( ) override; + + virtual OUString getPrivateTitle( ) const override; + + void doEditIndexes(); + bool doSaveDoc(bool _bSaveAs); + + virtual ~OTableController() override; + public: + OTableController(const css::uno::Reference< css::uno::XComponentContext >& _rM); + + const css::uno::Reference< css::beans::XPropertySet >& getTable() const { return m_xTable;} + + bool isAddAllowed() const; + bool isDropAllowed() const; + bool isAlterAllowed() const; + bool isAutoIncrementPrimaryKey() const; + + bool isAutoIncrementValueEnabled() const { return m_bAllowAutoIncrementValue; } + const OUString& getAutoIncrementValue() const { return m_sAutoIncrementValue; } + + virtual void impl_onModifyChanged() override; + + std::vector< std::shared_ptr<OTableRow> >& getRows() { return m_vRowList; } + + /// returns the position of the first empty row + sal_Int32 getFirstEmptyRowPosition(); + + const OTypeInfoMap& getTypeInfo() const { return m_aTypeInfo; } + + TOTypeInfoSP const & getTypeInfo(sal_Int32 _nPos) const { return m_aTypeInfoIndex[_nPos]->second; } + TOTypeInfoSP getTypeInfoByType(sal_Int32 _nDataType) const; + + const TOTypeInfoSP& getTypeInfoFallBack() const { return m_pTypeInfo; } + + virtual bool Construct(vcl::Window* pParent) override; + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // css::frame::XController + virtual sal_Bool SAL_CALL suspend(sal_Bool bSuspend) override; + + // css::lang::XComponent + virtual void SAL_CALL disposing() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString> SAL_CALL getSupportedServiceNames() override; + + private: + void startTableListening(); + void stopTableListening(); + virtual void impl_initialize() override; + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableCopyHelper.hxx b/dbaccess/source/ui/inc/TableCopyHelper.hxx new file mode 100644 index 000000000..b543dade8 --- /dev/null +++ b/dbaccess/source/ui/inc/TableCopyHelper.hxx @@ -0,0 +1,188 @@ +/* -*- 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 "AppElementType.hxx" +#include "commontypes.hxx" +#include <svx/dataaccessdescriptor.hxx> +#include <sot/storage.hxx> +#include <vcl/transfer.hxx> +#include <vcl/weld.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> + +namespace dbaui +{ + class OGenericUnoController; + /// Functor object for class DataFlavorExVector::value_type returntype is bool + struct TAppSupportedSotFunctor + { + ElementType eEntryType; + TAppSupportedSotFunctor(const ElementType& _eEntryType) + : eEntryType(_eEntryType) + { + } + + bool operator()(const DataFlavorExVector::value_type& _aType) + { + switch (_aType.mnSotId) + { + case SotClipboardFormatId::RTF: // RTF data descriptions + case SotClipboardFormatId::HTML: // HTML data descriptions + case SotClipboardFormatId::DBACCESS_TABLE: // table descriptor + return (E_TABLE == eEntryType); + case SotClipboardFormatId::DBACCESS_QUERY: // query descriptor + case SotClipboardFormatId::DBACCESS_COMMAND: // SQL command + return E_QUERY == eEntryType; + default: break; + } + return false; + } + }; + + class OTableCopyHelper + { + private: + OGenericUnoController* m_pController; + OUString m_sTableNameForAppend; + + public: + // is needed to describe the drop target + struct DropDescriptor + { + svx::ODataAccessDescriptor aDroppedData; + + //for transfor the tablename + OUString sDefaultTableName; + + OUString aUrl; + tools::SvRef<SotTempStream> aHtmlRtfStorage; + ElementType nType; + std::unique_ptr<weld::TreeIter> xDroppedAt; + sal_Int8 nAction; + bool bHtml; + bool bError; + + DropDescriptor() + : nType(E_TABLE) + , nAction(DND_ACTION_NONE) + , bHtml(false) + , bError(false) + { } + }; + + OTableCopyHelper(OGenericUnoController* _pController); + + /** pastes a table into the data source + @param _rPasteData + The data helper. + @param _sDestDataSourceName + The name of the dest data source. + */ + void pasteTable( const TransferableDataHelper& _rTransData + ,std::u16string_view _sDestDataSourceName + ,const SharedConnection& _xConnection); + + /** pastes a table into the data source + @param _nFormatId + The format which should be copied. + @param _rPasteData + The data helper. + @param _sDestDataSourceName + The name of the dest data source. + */ + void pasteTable( SotClipboardFormatId _nFormatId + ,const TransferableDataHelper& _rTransData + ,std::u16string_view _sDestDataSourceName + ,const SharedConnection& _xConnection); + + /** copies a table which was constructed by tags like HTML or RTF + @param _rDesc + The Drop descriptor + @param _bCheck + If set to <TRUE/> than the controller checks only if a copy is possible. + @param _xConnection + The connection + */ + bool copyTagTable( DropDescriptor const & _rDesc, + bool _bCheck, + const SharedConnection& _xConnection); + + /** copies a table which was constructed by tags like HTML or RTF + @param _rDesc + The Drop descriptor + @param _bCheck + If set to <TRUE/> than the controller checks only if a copy is possible. + @param _xConnection + The connection + */ + void asyncCopyTagTable( DropDescriptor& _rDesc + ,std::u16string_view _sDestDataSourceName + ,const SharedConnection& _xConnection); + + /** copies a table which was constructed by tags like HTML or RTF + @param _aDroppedData + The dropped data + @param _rDesc + IN/OUT parameter + @param _xConnection + The connection + */ + bool copyTagTable(const TransferableDataHelper& _aDroppedData, + DropDescriptor& _rAsyncDrop, + const SharedConnection& _xConnection); + + /// returns <TRUE/> if the clipboard supports a table format, otherwise <FALSE/>. + static bool isTableFormat(const TransferableDataHelper& _rClipboard); + + void SetTableNameForAppend( const OUString& _rDefaultTableName ) { m_sTableNameForAppend = _rDefaultTableName; } + void ResetTableNameForAppend() { SetTableNameForAppend( OUString() ); } + const OUString& GetTableNameForAppend() const { return m_sTableNameForAppend ;} + + private: + /** pastes a table into the data source + @param _rPasteData + The data descriptor. + @param _sDestDataSourceName + The name of the dest data source. + */ + void pasteTable( + const svx::ODataAccessDescriptor& _rPasteData, + std::u16string_view _sDestDataSourceName, + const SharedConnection& _xDestConnection + ); + + /** insert a table into the data source. The source can either be a table or a query + */ + void insertTable( + std::u16string_view i_rSourceDataSource, + const css::uno::Reference< css::sdbc::XConnection>& i_rSourceConnection, + const OUString& i_rCommand, + const sal_Int32 i_nCommandType, + const css::uno::Reference< css::sdbc::XResultSet >& i_rSourceRows, + const css::uno::Sequence< css::uno::Any >& i_rSelection, + const bool i_bBookmarkSelection, + std::u16string_view i_rDestDataSource, + const css::uno::Reference< css::sdbc::XConnection>& i_rDestConnection + ); + + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableDesignControl.hxx b/dbaccess/source/ui/inc/TableDesignControl.hxx new file mode 100644 index 000000000..89debc9e1 --- /dev/null +++ b/dbaccess/source/ui/inc/TableDesignControl.hxx @@ -0,0 +1,78 @@ +/* -*- 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/editbrowsebox.hxx> + +#include "IClipBoardTest.hxx" +#include "TypeInfo.hxx" + +namespace dbaui +{ + class OTableDesignView; + + class OTableRowView : public ::svt::EditBrowseBox, public IClipboardTest + { + friend class OTableDesignUndoAct; + + protected: + tools::Long m_nDataPos; ///< currently needed row + tools::Long m_nCurrentPos; ///< current position of selected column + + private: + sal_uInt16 m_nCurUndoActId; + + public: + OTableRowView(vcl::Window* pParent); + + virtual void SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const TOTypeInfoSP& _pTypeInfo ) = 0; + virtual void SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const css::uno::Any& _rNewData ) = 0; + virtual css::uno::Any GetCellData( sal_Int32 nRow, sal_uInt16 nColId ) = 0; + virtual void SetControlText( sal_Int32 nRow, sal_uInt16 nColId, const OUString& rText ) = 0; + + virtual OTableDesignView* GetView() const = 0; + + sal_uInt16 GetCurUndoActId() const { return m_nCurUndoActId; } + + // IClipboardTest + virtual void cut() override; + virtual void copy() override; + virtual void paste() override; + + protected: + void Paste( sal_Int32 nRow ); + + virtual void CopyRows() = 0; + virtual void DeleteRows() = 0; + virtual void InsertRows( sal_Int32 nRow ) = 0; + virtual void InsertNewRows( sal_Int32 nRow ) = 0; + + virtual bool IsPrimaryKeyAllowed() = 0; + virtual bool IsInsertNewAllowed( sal_Int32 nRow ) = 0; + virtual bool IsDeleteAllowed() = 0; + + virtual RowStatus GetRowStatus(sal_Int32 nRow) const override; + virtual void KeyInput(const KeyEvent& rEvt) override; + virtual void Command( const CommandEvent& rEvt ) override; + + virtual void Init() override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableDesignHelpBar.hxx b/dbaccess/source/ui/inc/TableDesignHelpBar.hxx new file mode 100644 index 000000000..db4023d36 --- /dev/null +++ b/dbaccess/source/ui/inc/TableDesignHelpBar.hxx @@ -0,0 +1,59 @@ +/* -*- 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 <vcl/weld.hxx> +#include "IClipBoardTest.hxx" + +namespace dbaui +{ + class OTableDesignHelpBar final : public IClipboardTest + { + private: + std::unique_ptr<weld::TextView> m_xTextWin; + + public: + OTableDesignHelpBar(std::unique_ptr<weld::TextView> xTextWin); + + void SetHelpText( const OUString& rText ); + + bool HasFocus() const { return m_xTextWin->has_focus(); } + + void connect_focus_in(const Link<weld::Widget&, void>& rLink) + { + m_xTextWin->connect_focus_in(rLink); + } + + void connect_focus_out(const Link<weld::Widget&, void>& rLink) + { + m_xTextWin->connect_focus_out(rLink); + } + + // IClipboardTest + virtual bool isCutAllowed() override; + virtual bool isCopyAllowed() override; + virtual bool isPasteAllowed() override; + + virtual void copy() override; + virtual void cut() override; + virtual void paste() override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableDesignView.hxx b/dbaccess/source/ui/inc/TableDesignView.hxx new file mode 100644 index 000000000..077eb211e --- /dev/null +++ b/dbaccess/source/ui/inc/TableDesignView.hxx @@ -0,0 +1,112 @@ +/* -*- 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 <dbaccess/dataview.hxx> +#include <com/sun/star/lang/Locale.hpp> +#include <vcl/InterimItemWindow.hxx> +#include <vcl/weld.hxx> +#include "IClipBoardTest.hxx" + +namespace dbaui +{ + class OTableController; + class OTableDesignView; + class OTableFieldDescWin; + class OTableEditorCtrl; + + class OTableBorderWindow final : public InterimItemWindow + { + std::unique_ptr<weld::Paned> m_xHorzSplitter; + std::unique_ptr<weld::Container> m_xEditorParent; + css::uno::Reference<css::awt::XWindow> m_xEditorParentWin; + VclPtr<OTableEditorCtrl> m_xEditorCtrl; + std::unique_ptr<weld::Container> m_xFieldDescParent; + std::unique_ptr<OTableFieldDescWin> m_xFieldDescWin; + + public: + OTableBorderWindow(OTableDesignView* pParent); + virtual ~OTableBorderWindow() override; + // Window overrides + virtual void dispose() override; + + virtual void GetFocus() override; + virtual void Layout() override; + + OTableEditorCtrl* GetEditorCtrl() const { return m_xEditorCtrl.get(); } + OTableFieldDescWin* GetDescWin() const { return m_xFieldDescWin.get(); } + }; + + class OTableDesignView : public ODataView + , public IClipboardTest + { + enum ChildFocusState + { + DESCRIPTION, + EDITOR, + NONE + }; + private: + css::lang::Locale m_aLocale; + VclPtr<OTableBorderWindow> m_pWin; + OTableController& m_rController; + ChildFocusState m_eChildFocus; + + IClipboardTest* getActiveChild() const; + + DECL_LINK( FieldDescFocusIn, weld::Widget&, void ); + protected: + + // return the Rectangle where I can paint myself + virtual void resizeDocumentView(tools::Rectangle& rRect) override; + + public: + OTableDesignView( vcl::Window* pParent, + const css::uno::Reference< css::uno::XComponentContext >&, + OTableController& _rController); + virtual ~OTableDesignView() override; + virtual void dispose() override; + + // Window overrides + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + virtual void GetFocus() override; + + OTableEditorCtrl* GetEditorCtrl() const { return m_pWin ? m_pWin->GetEditorCtrl() : nullptr; } + OTableFieldDescWin* GetDescWin() const { return m_pWin ? m_pWin->GetDescWin() : nullptr; } + OTableController& getController() const { return m_rController; } + + const css::lang::Locale& getLocale() const { return m_aLocale;} + + // IClipboardTest + virtual bool isCutAllowed() override; + virtual bool isCopyAllowed() override; + virtual bool isPasteAllowed() override; + virtual void copy() override; + virtual void cut() override; + virtual void paste() override; + + // set the view readonly or not + void setReadOnly(bool _bReadOnly); + + virtual void initialize() override; + void reSync(); // resync window data with realdata + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableFieldDescription.hxx b/dbaccess/source/ui/inc/TableFieldDescription.hxx new file mode 100644 index 000000000..d21ad953a --- /dev/null +++ b/dbaccess/source/ui/inc/TableFieldDescription.hxx @@ -0,0 +1,150 @@ +/* -*- 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 <vector> + +#include "QEnumTypes.hxx" +#include <rtl/ustring.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <rtl/ref.hxx> +#include <vcl/vclptr.hxx> +#include <vcl/window.hxx> + +#include <salhelper/simplereferenceobject.hxx> + +namespace comphelper +{ + class NamedValueCollection; +} + +namespace vcl { class Window; } + +namespace dbaui +{ + class OTableFieldDesc : public ::salhelper::SimpleReferenceObject + { + private: + std::vector< OUString > + m_aCriteria; + + OUString m_aTableName; + OUString m_aAliasName; ///< table range + OUString m_aFieldName; ///< column + OUString m_aFieldAlias; ///< column alias + OUString m_aFunctionName;///< contains the function name (only if m_eFunctionType != FKT_NONE) + + VclPtr<vcl::Window> m_pTabWindow; + + sal_Int32 m_eDataType; + sal_Int32 m_eFunctionType; + ETableFieldType m_eFieldType; + EOrderDir m_eOrderDir; + sal_Int32 m_nIndex; + sal_Int32 m_nColWidth; + sal_uInt16 m_nColumnId; + bool m_bGroupBy; + bool m_bVisible; + + // when adding new fields, please take care of IsEmpty! + + public: + OTableFieldDesc(); + OTableFieldDesc(const OUString& rTable, const OUString& rField ); + OTableFieldDesc(const OTableFieldDesc& rRS); + virtual ~OTableFieldDesc() override; + + inline bool IsEmpty() const; + + OTableFieldDesc& operator=( const OTableFieldDesc& _aField ); + + bool IsVisible() const { return m_bVisible;} + bool IsGroupBy() const { return m_bGroupBy;} + + void SetVisible( bool bVis=true ) { m_bVisible = bVis; } + void SetGroupBy( bool bGb ) { m_bGroupBy = bGb; } + void SetTabWindow( vcl::Window* pWin ){ m_pTabWindow = pWin; } + void SetField( const OUString& rF ) { m_aFieldName = rF; } + void SetFieldAlias( const OUString& rF ) { m_aFieldAlias = rF; } + void SetTable( const OUString& rT ) { m_aTableName = rT; } + void SetAlias( const OUString& rT ) { m_aAliasName = rT; } + void SetFunction( const OUString& rT ) { m_aFunctionName = rT; } + void SetOrderDir( EOrderDir eDir ) { m_eOrderDir = eDir; } + void SetDataType( sal_Int32 eTyp ) { m_eDataType = eTyp; } + void SetFieldType( ETableFieldType eTyp ) { m_eFieldType = eTyp; } + void SetCriteria( sal_uInt16 nIdx, const OUString& rCrit ); + void SetColWidth( sal_Int32 nWidth ) { m_nColWidth = nWidth; } + void SetFieldIndex( sal_Int32 nFieldIndex ) { m_nIndex = nFieldIndex; } + void SetFunctionType( sal_Int32 eTyp ) { m_eFunctionType = eTyp; } + void SetColumnId(sal_uInt16 _nColumnId) { m_nColumnId = _nColumnId; } + + const OUString& GetField() const { return m_aFieldName;} + const OUString& GetFieldAlias() const { return m_aFieldAlias;} + const OUString& GetTable() const { return m_aTableName;} + const OUString& GetAlias() const { return m_aAliasName;} + const OUString& GetFunction() const { return m_aFunctionName;} + sal_Int32 GetDataType() const { return m_eDataType; } + ETableFieldType GetFieldType() const { return m_eFieldType; } + EOrderDir GetOrderDir() const { return m_eOrderDir; } + OUString GetCriteria( sal_uInt16 nIdx ) const; + sal_Int32 GetColWidth() const { return m_nColWidth; } + sal_Int32 GetFieldIndex() const { return m_nIndex; } + vcl::Window* GetTabWindow() const { return m_pTabWindow;} + sal_Int32 GetFunctionType() const { return m_eFunctionType; } + sal_uInt16 GetColumnId() const { return m_nColumnId;} + + bool isAggregateFunction() const { return (m_eFunctionType & FKT_AGGREGATE) == FKT_AGGREGATE; } + bool isOtherFunction() const { return (m_eFunctionType & FKT_OTHER) == FKT_OTHER; } + bool isNumeric() const { return (m_eFunctionType & FKT_NUMERIC) == FKT_NUMERIC; } + bool isNoneFunction() const { return m_eFunctionType == FKT_NONE; } + bool isCondition() const { return (m_eFunctionType & FKT_CONDITION) == FKT_CONDITION; } + bool isNumericOrAggregateFunction() const { return isNumeric() || isAggregateFunction(); } + + bool HasCriteria() const + { + for (auto const& criteria : m_aCriteria) + { + if(!criteria.isEmpty()) + return true; + } + return false; + } + + const std::vector< OUString>& GetCriteria() const { return m_aCriteria; } + + void Load( const css::beans::PropertyValue& i_rSettings, const bool i_bIncludingCriteria ); + void Save( ::comphelper::NamedValueCollection& o_rSettings, const bool i_bIncludingCriteria ); + }; + + inline bool OTableFieldDesc::IsEmpty() const + { + bool bEmpty = (m_aTableName.isEmpty() && + m_aAliasName.isEmpty() && + m_aFieldName.isEmpty() && + m_aFieldAlias.isEmpty() && + m_aFunctionName.isEmpty() && + !HasCriteria()); + return bEmpty; + } + + typedef ::rtl::Reference< OTableFieldDesc> OTableFieldDescRef; + typedef std::vector<OTableFieldDescRef> OTableFields; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableGrantCtrl.hxx b/dbaccess/source/ui/inc/TableGrantCtrl.hxx new file mode 100644 index 000000000..74a9fd8b5 --- /dev/null +++ b/dbaccess/source/ui/inc/TableGrantCtrl.hxx @@ -0,0 +1,104 @@ +/* -*- 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 <svtools/editbrowsebox.hxx> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XAuthorizable.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +class Edit; +namespace dbaui +{ + +class OTableGrantControl : public ::svt::EditBrowseBox +{ + typedef struct + { + sal_Int32 nRights; + sal_Int32 nWithGrant; + } TPrivileges; + + typedef std::map<OUString, TPrivileges> TTablePrivilegeMap; + + css::uno::Reference< css::container::XNameAccess > m_xUsers; + css::uno::Reference< css::container::XNameAccess > m_xTables; + css::uno::Reference< css::uno::XComponentContext> m_xContext; + css::uno::Reference< css::sdbcx::XAuthorizable> m_xGrantUser; + css::uno::Sequence< OUString> m_aTableNames; + + mutable TTablePrivilegeMap m_aPrivMap; + OUString m_sUserName; + VclPtr<::svt::CheckBoxControl> m_pCheckCell; + VclPtr<::svt::EditControl> m_pEdit; + tools::Long m_nDataPos; + ImplSVEvent * m_nDeactivateEvent; + +public: + OTableGrantControl(const css::uno::Reference<css::awt::XWindow> &rParent); + virtual ~OTableGrantControl() override; + virtual void dispose() override; + void UpdateTables(); + void setUserName(const OUString& _sUserName); + void setGrantUser(const css::uno::Reference< css::sdbcx::XAuthorizable>& _xGrantUser); + + void setTablesSupplier(const css::uno::Reference< css::sdbcx::XTablesSupplier >& _xTablesSup); + void setComponentContext(const css::uno::Reference< css::uno::XComponentContext>& _rxContext); + + virtual void Init() override; + + // IAccessibleTableProvider + /** Creates the accessible object of a data table cell. + @param nRow The row index of the cell. + @param nColumnId The column ID of the cell. + @return The XAccessible interface of the specified cell. */ + virtual css::uno::Reference< + css::accessibility::XAccessible > + CreateAccessibleCell( sal_Int32 nRow, sal_uInt16 nColumnId ) override; + +protected: + virtual bool PreNotify(NotifyEvent& rNEvt ) override; + + virtual bool IsTabAllowed(bool bForward) const override; + virtual void InitController( ::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol ) override; + virtual ::svt::CellController* GetController( sal_Int32 nRow, sal_uInt16 nCol ) override; + virtual void PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColId ) const override; + virtual bool SeekRow( sal_Int32 nRow ) override; + virtual bool SaveModified() override; + virtual OUString GetCellText( sal_Int32 nRow, sal_uInt16 nColId ) const override; + + virtual void CellModified() override; + +private: + DECL_LINK( AsynchActivate, void*, void ); + DECL_LINK( AsynchDeactivate, void*, void ); + + static bool isAllowed(sal_uInt16 _nColumnId,sal_Int32 _nPrivilege); + void fillPrivilege(sal_Int32 _nRow) const; + TTablePrivilegeMap::const_iterator findPrivilege(sal_Int32 _nRow) const; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableRow.hxx b/dbaccess/source/ui/inc/TableRow.hxx new file mode 100644 index 000000000..4f34a94bf --- /dev/null +++ b/dbaccess/source/ui/inc/TableRow.hxx @@ -0,0 +1,76 @@ +/* -*- 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 <tools/long.hxx> +#include "TypeInfo.hxx" + +class SvStream; + +namespace dbaui +{ + class OFieldDescription; + class OTableRow + { + private: + OFieldDescription* m_pActFieldDescr; + sal_Int32 m_nPos; + bool m_bReadOnly; + bool m_bOwnsDescriptions; + + protected: + public: + OTableRow(); + OTableRow( const OTableRow& rRow, tools::Long nPosition = -1 ); + ~OTableRow(); + + OFieldDescription* GetActFieldDescr() const { return m_pActFieldDescr; } + bool isValid() const { return GetActFieldDescr() != nullptr; } + + void SetFieldType( const TOTypeInfoSP& _pType, bool _bForce = false ); + + void SetPrimaryKey( bool bSet ); + bool IsPrimaryKey() const; + + /** returns the current position in the table. + @return + the current position in the table + */ + sal_Int32 GetPos() const { return m_nPos; } + void SetPos(sal_Int32 _nPos) { m_nPos = _nPos; } + + /** set the row readonly + @param _bRead + if <TRUE/> then the row is readonly, otherwise not + */ + void SetReadOnly( bool _bRead=true ){ m_bReadOnly = _bRead; } + + /** returns if the row is readonly + @return + <TRUE/> if readonly, otherwise <FALSE/> + */ + bool IsReadOnly() const { return m_bReadOnly; } + + friend SvStream& WriteOTableRow( SvStream& rStr,const OTableRow& _rRow ); + friend SvStream& ReadOTableRow( SvStream& rStr, OTableRow& _rRow ); + }; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableRowExchange.hxx b/dbaccess/source/ui/inc/TableRowExchange.hxx new file mode 100644 index 000000000..36e249795 --- /dev/null +++ b/dbaccess/source/ui/inc/TableRowExchange.hxx @@ -0,0 +1,40 @@ +/* -*- 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 <vcl/transfer.hxx> +#include <memory> + +namespace dbaui +{ + class OTableRow; + class OTableRowExchange : public TransferableHelper + { + std::vector< std::shared_ptr<OTableRow> > m_vTableRow; + public: + OTableRowExchange(std::vector< std::shared_ptr<OTableRow> >&& _rvTableRow); + protected: + virtual void AddSupportedFormats() override; + virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override; + virtual bool WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor& rFlavor ) override; + virtual void ObjectReleased() override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableWindow.hxx b/dbaccess/source/ui/inc/TableWindow.hxx new file mode 100644 index 000000000..c3bed06c7 --- /dev/null +++ b/dbaccess/source/ui/inc/TableWindow.hxx @@ -0,0 +1,183 @@ +/* -*- 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> +#include <com/sun/star/beans/XPropertySet.hpp> +#include "TableWindowTitle.hxx" +#include <rtl/ref.hxx> +#include "TableWindowData.hxx" +#include "TableWindowListBox.hxx" +#include <vector> +#include <vcl/window.hxx> + +#include <comphelper/containermultiplexer.hxx> +#include <cppuhelper/basemutex.hxx> +#include <o3tl/typed_flags_set.hxx> + +// Flags for the size adjustment of SbaJoinTabWins +enum class SizingFlags { + NONE = 0x0000, + Top = 0x0001, + Bottom = 0x0002, + Left = 0x0004, + Right = 0x0008, +}; +namespace o3tl { + template<> struct typed_flags<SizingFlags> : is_typed_flags<SizingFlags, 0x0f> {}; +} + + +namespace dbaui +{ + class OJoinDesignView; + class OJoinTableView; + class OTableWindowAccess; + + class OTableWindow : public ::cppu::BaseMutex + ,public ::comphelper::OContainerListener + ,public vcl::Window + { + friend class OTableWindowTitle; + friend class OTableWindowListBox; + protected: + // and the table itself (needed for me as I want to lock it as long as the window is alive) + VclPtr<OTableWindowTitle> m_xTitle; + VclPtr<OTableWindowListBox> m_xListBox; + + private: + TTableWindowData::value_type + m_pData; + ::rtl::Reference< comphelper::OContainerListenerAdapter> + m_pContainerListener; + sal_Int32 m_nMoveCount; // how often the arrow keys was pressed + sal_Int32 m_nMoveIncrement; // how many pixel we should move + SizingFlags m_nSizingFlags; + + // OContainerListener + virtual void _elementInserted( const css::container::ContainerEvent& _rEvent ) override; + virtual void _elementRemoved( const css::container::ContainerEvent& _rEvent ) override; + virtual void _elementReplaced( const css::container::ContainerEvent& _rEvent ) override; + + protected: + virtual void Resize() override; + virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override; + virtual void MouseMove( const MouseEvent& rEvt ) override; + virtual void MouseButtonDown( const MouseEvent& rEvt ) override; + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + + // called at FIRST Init + void FillListBox(); + // called at EACH Init + + virtual void OnEntryDoubleClicked(weld::TreeIter& /*rEntry*/) { } + // called from the DoubleClickHdl of the ListBox + + /** delete the user data with the equal type as created within createUserData + @param _pUserData + The user data store in the listbox entries. Created with a call to createUserData. + _pUserData may be <NULL/>. _pUserData will be set to <NULL/> after call. + */ + virtual void deleteUserData(void*& _pUserData); + + /** creates user information that will be append at the ListBoxentry + @param _xColumn + The corresponding column, can be <NULL/>. + @param _bPrimaryKey + <TRUE/> when the column belongs to the primary key + @return + the user data which will be append at the listbox entry, may be <NULL/> + */ + virtual void* createUserData(const css::uno::Reference< + css::beans::XPropertySet>& _xColumn, + bool _bPrimaryKey); + + /** updates image + */ + void impl_updateImage(); + + OTableWindow( vcl::Window* pParent, const TTableWindowData::value_type& pTabWinData ); + + public: + virtual ~OTableWindow() override; + virtual void dispose() override; + + // late Constructor, see also CreateListbox and FillListbox + virtual bool Init(); + + OJoinTableView* getTableView(); + const OJoinTableView* getTableView() const; + OJoinDesignView* getDesignView(); + void SetPosPixel( const Point& rNewPos ) override; + void SetSizePixel( const Size& rNewSize ) override; + void SetPosSizePixel( const Point& rNewPos, const Size& rNewSize ) override; + + OUString getTitle() const; + void SetBoldTitle( bool bBold ); + void setActive(bool _bActive = true); + + void Remove(); + + OUString const & GetTableName() const { return m_pData->GetTableName(); } + OUString const & GetWinName() const { return m_pData->GetWinName(); } + OUString const & GetComposedName() const { return m_pData->GetComposedName(); } + const VclPtr<OTableWindowListBox>& GetListBox() const { return m_xListBox; } + const TTableWindowData::value_type& GetData() const { return m_pData; } + const VclPtr<OTableWindowTitle>& GetTitleCtrl() const { return m_xTitle; } + + /** returns the name which should be used when displaying join or relations + @return + The composed name or the window name. + */ + virtual OUString GetName() const = 0; + + css::uno::Reference< css::container::XNameAccess > GetOriginalColumns() const { return m_pData->getColumns(); } + css::uno::Reference< css::beans::XPropertySet > GetTable() const { return m_pData->getTable(); } + + /** set the sizing flag to the direction + @param _rPos + The EndPosition after resizing. + */ + void setSizingFlag(const Point& _rPos); + + /** returns the new sizing + */ + tools::Rectangle getSizingRect(const Point& _rPos,const Size& _rOutputSize) const; + + // window override + virtual void StateChanged( StateChangedType nStateChange ) override; + virtual void GetFocus() override; + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + virtual void Command(const CommandEvent& rEvt) override; + + // Accessibility + virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override; + + // do I have connections to the outside? + bool ExistsAConn() const; + + void EnumValidFields(std::vector< OUString>& arrstrFields); + + /** clears the listbox inside. Must be called be the dtor is called. + */ + void clearListBox(); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableWindowAccess.hxx b/dbaccess/source/ui/inc/TableWindowAccess.hxx new file mode 100644 index 000000000..b51e4c80f --- /dev/null +++ b/dbaccess/source/ui/inc/TableWindowAccess.hxx @@ -0,0 +1,94 @@ +/* -*- 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 "TableWindow.hxx" +#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp> +#include <cppuhelper/implbase2.hxx> +#include <toolkit/awt/vclxaccessiblecomponent.hxx> +#include <vcl/vclptr.hxx> + +namespace dbaui +{ + typedef ::cppu::ImplHelper2< css::accessibility::XAccessibleRelationSet, + css::accessibility::XAccessible + > OTableWindowAccess_BASE; + class OTableWindow; + /** the class OTableWindowAccess represents the accessible object for table windows + like they are used in the QueryDesign and the RelationDesign + */ + class OTableWindowAccess : public VCLXAccessibleComponent + , public OTableWindowAccess_BASE + { + VclPtr<OTableWindow> m_pTable; // the window which I should give accessibility to + + css::uno::Reference< css::accessibility::XAccessible > getParentChild(sal_Int32 _nIndex); + protected: + /** this function is called upon disposing the component + */ + virtual void SAL_CALL disposing() override; + + virtual void ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) override; + public: + OTableWindowAccess( OTableWindow* _pTable); + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire( ) noexcept override + { // here inline is allowed because we do not use this class outside this dll + VCLXAccessibleComponent::acquire( ); + } + virtual void SAL_CALL release( ) noexcept override + { // here inline is allowed because we do not use this class outside this dll + VCLXAccessibleComponent::release( ); + } + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XAccessible + virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override; + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override; + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) override; + virtual sal_Int16 SAL_CALL getAccessibleRole( ) override; + virtual OUString SAL_CALL getAccessibleName( ) override; + virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override; + + // XAccessibleComponent + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override; + + // XAccessibleExtendedComponent + virtual OUString SAL_CALL getTitledBorderText( ) override; + + // XAccessibleRelationSet + virtual sal_Int32 SAL_CALL getRelationCount( ) override; + virtual css::accessibility::AccessibleRelation SAL_CALL getRelation( sal_Int32 nIndex ) override; + virtual sal_Bool SAL_CALL containsRelation( sal_Int16 aRelationType ) override; + virtual css::accessibility::AccessibleRelation SAL_CALL getRelationByType( sal_Int16 aRelationType ) override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableWindowData.hxx b/dbaccess/source/ui/inc/TableWindowData.hxx new file mode 100644 index 000000000..f7aea00b9 --- /dev/null +++ b/dbaccess/source/ui/inc/TableWindowData.hxx @@ -0,0 +1,95 @@ +/* -*- 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 <tools/gen.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <unotools/eventlisteneradapter.hxx> +#include <memory> +#include <vector> + +namespace dbaui +{ + class OTableWindowData : public ::utl::OEventListenerAdapter + { + mutable ::osl::Mutex m_aMutex; + + void listen(); + protected: + // the columns of the table + css::uno::Reference< css::beans::XPropertySet > m_xTable; // can either be a table or a query + css::uno::Reference< css::container::XIndexAccess> m_xKeys; + css::uno::Reference< css::container::XNameAccess > m_xColumns; + + OUString m_aTableName; + OUString m_aWinName; + OUString m_sComposedName; + Point m_aPosition; + Size m_aSize; + bool m_bShowAll; + bool m_bIsQuery; + bool m_bIsValid; + + public: + explicit OTableWindowData( const css::uno::Reference< css::beans::XPropertySet>& _xTable + ,const OUString& _rComposedName + ,const OUString& strTableName + ,const OUString& rWinName ); + virtual ~OTableWindowData() override; + + /** late constructor + * + * \param _xConnection + * \param _bAllowQueries when true, queries are allowed + * \return false if the table was unaccessible otherwise true + */ + bool init(const css::uno::Reference< css::sdbc::XConnection >& _xConnection + ,bool _bAllowQueries); + + const OUString& GetComposedName() const { return m_sComposedName; } + const OUString& GetTableName() const { return m_aTableName; } + const OUString& GetWinName() const { return m_aWinName; } + const Point& GetPosition() const { return m_aPosition; } + const Size& GetSize() const { return m_aSize; } + bool IsShowAll() const { return m_bShowAll; } + bool isQuery() const { return m_bIsQuery; } + bool isValid() const { return m_bIsValid; } // it is either a table or query but it is known + bool HasPosition() const; + bool HasSize() const; + + void SetWinName( const OUString& rWinName ) { m_aWinName = rWinName; } + void SetPosition( const Point& rPos ) { m_aPosition=rPos; } + void SetSize( const Size& rSize ) { m_aSize = rSize; } + void ShowAll( bool bAll ) { m_bShowAll = bAll; } + + css::uno::Reference< css::beans::XPropertySet> getTable() const { ::osl::MutexGuard aGuard( m_aMutex ); return m_xTable; } + css::uno::Reference< css::container::XIndexAccess> getKeys() const { ::osl::MutexGuard aGuard( m_aMutex ); return m_xKeys; } + css::uno::Reference< css::container::XNameAccess > getColumns() const { ::osl::MutexGuard aGuard( m_aMutex ); return m_xColumns; } + + // OEventListenerAdapter + virtual void _disposing( const css::lang::EventObject& _rSource ) override; + }; + + typedef std::vector< std::shared_ptr<OTableWindowData> > TTableWindowData; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableWindowListBox.hxx b/dbaccess/source/ui/inc/TableWindowListBox.hxx new file mode 100644 index 000000000..cdad4947c --- /dev/null +++ b/dbaccess/source/ui/inc/TableWindowListBox.hxx @@ -0,0 +1,121 @@ +/* -*- 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 <vcl/transfer.hxx> +#include <vcl/InterimItemWindow.hxx> +#include "callbacks.hxx" + +struct AcceptDropEvent; +struct ExecuteDropEvent; +namespace dbaui +{ + class OTableWindowListBox; + struct OJoinExchangeData + { + public: + VclPtr<OTableWindowListBox> pListBox; // the ListBox inside the same (you can get the TabWin and the WinName out of it) + int nEntry; // the entry, which was dragged or to which was dropped on + + OJoinExchangeData(OTableWindowListBox* pBox); + OJoinExchangeData() : pListBox(nullptr), nEntry(-1) { } + }; + + struct OJoinDropData + { + OJoinExchangeData aSource; + OJoinExchangeData aDest; + }; + + class OJoinExchObj; + class OTableWindow; + class TableWindowListBoxHelper; + + class OTableWindowListBox + : public InterimItemWindow + , public IDragTransferableListener + { + std::unique_ptr<weld::TreeView> m_xTreeView; + std::unique_ptr<TableWindowListBoxHelper> m_xDragDropTargetHelper; + + DECL_LINK( OnDoubleClick, weld::TreeView&, bool ); + DECL_LINK(CommandHdl, const CommandEvent&, bool); + DECL_LINK( DropHdl, void*, void ); + DECL_LINK( LookForUiHdl, void*, void ); + DECL_LINK( DragBeginHdl, bool&, bool ); + DECL_LINK( ScrollHdl, weld::TreeView&, void ); + + rtl::Reference<OJoinExchObj> m_xHelper; + + VclPtr<OTableWindow> m_pTabWin; + ImplSVEvent * m_nDropEvent; + ImplSVEvent * m_nUiEvent; + OJoinDropData m_aDropInfo; + + protected: + virtual void LoseFocus() override; + virtual void GetFocus() override; + + virtual void dragFinished( ) override; + + public: + OTableWindowListBox(OTableWindow* pParent); + virtual ~OTableWindowListBox() override; + virtual void dispose() override; + + const weld::TreeView& get_widget() const { return *m_xTreeView; } + weld::TreeView& get_widget() { return *m_xTreeView; } + + // DnD stuff + sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt); + sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt); + + // window + virtual void Command(const CommandEvent& rEvt) override; + + OTableWindow* GetTabWin(){ return m_pTabWin; } + int GetEntryFromText( std::u16string_view rEntryText ); + }; + + class TableWindowListBoxHelper final : public DropTargetHelper + { + private: + OTableWindowListBox& m_rParent; + + virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override + { + return m_rParent.AcceptDrop(rEvt); + } + + virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override + { + return m_rParent.ExecuteDrop(rEvt); + } + + public: + TableWindowListBoxHelper(OTableWindowListBox& rParent, const css::uno::Reference<css::datatransfer::dnd::XDropTarget>& rDropTarget) + : DropTargetHelper(rDropTarget) + , m_rParent(rParent) + { + } + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableWindowTitle.hxx b/dbaccess/source/ui/inc/TableWindowTitle.hxx new file mode 100644 index 000000000..0a3779bd8 --- /dev/null +++ b/dbaccess/source/ui/inc/TableWindowTitle.hxx @@ -0,0 +1,44 @@ +/* -*- 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 <vcl/InterimItemWindow.hxx> + +namespace dbaui +{ + class OTableWindow; + class OTableWindowTitle final : public InterimItemWindow + { + VclPtr<OTableWindow> m_pTabWin; + std::unique_ptr<weld::Label> m_xLabel; + std::unique_ptr<weld::Image> m_xImage; + + DECL_LINK(MousePressHdl, const MouseEvent&, bool); + + public: + OTableWindowTitle( OTableWindow* pParent ); + virtual ~OTableWindowTitle() override; + virtual void dispose() override; + + weld::Label& GetLabel() { return *m_xLabel; } + weld::Image& GetImage() { return *m_xImage; } + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TablesSingleDlg.hxx b/dbaccess/source/ui/inc/TablesSingleDlg.hxx new file mode 100644 index 000000000..c75fa1eb3 --- /dev/null +++ b/dbaccess/source/ui/inc/TablesSingleDlg.hxx @@ -0,0 +1,71 @@ +/* -*- 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 <sfx2/basedlgs.hxx> +#include "IItemSetHelper.hxx" +#include <com/sun/star/beans/PropertyValue.hpp> + +#include <memory> + +namespace com::sun::star { + namespace beans { + class XPropertySet; + } + namespace uno { + class XComponentContext; + } +} + +namespace dbaui +{ +class ODbDataSourceAdministrationHelper; + // OTableSubscriptionDialog + class OTableSubscriptionDialog : public SfxSingleTabDialogController, public IItemSetHelper + { + std::unique_ptr<ODbDataSourceAdministrationHelper> m_pImpl; + bool m_bStopExecution; // set when the dialog should not be executed + + std::unique_ptr<SfxItemSet> m_pOutSet; + public: + + OTableSubscriptionDialog(weld::Window* pParent + ,const SfxItemSet* _pItems + ,const css::uno::Reference< css::uno::XComponentContext >& _rxORB + ,const css::uno::Any& _aDataSourceName + ); + virtual ~OTableSubscriptionDialog() override; + + // forwards from ODbDataSourceAdministrationHelper + void successfullyConnected(); + bool getCurrentSettings(css::uno::Sequence< css::beans::PropertyValue >& _rDriverParams); + void clearPassword(); + css::uno::Reference< css::beans::XPropertySet > const & getCurrentDataSource(); + void endExecution() { m_bStopExecution = true; } + + virtual const SfxItemSet* getOutputSet() const override; + virtual SfxItemSet* getWriteOutputSet() override; + + virtual short run() override; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TokenWriter.hxx b/dbaccess/source/ui/inc/TokenWriter.hxx new file mode 100644 index 000000000..82e36240f --- /dev/null +++ b/dbaccess/source/ui/inc/TokenWriter.hxx @@ -0,0 +1,206 @@ +/* -*- 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 "commontypes.hxx" + +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> + +#include <cppuhelper/implbase.hxx> +#include <svx/dataaccessdescriptor.hxx> +#include <vcl/weld.hxx> + +namespace com::sun::star { + namespace sdbc{ + class XRowUpdate; + } +} + +class SvStream; + +namespace dbaui +{ + // ODatabaseImportExport base class for import/export + class ODatabaseExport; + class ODatabaseImportExport : public ::cppu::WeakImplHelper< css::lang::XEventListener> + { + protected: + css::uno::Sequence< css::uno::Any> m_aSelection; + bool m_bBookmarkSelection; + SvStream* m_pStream; + css::awt::FontDescriptor m_aFont; + css::uno::Reference< css::beans::XPropertySet > m_xObject; // table/query + SharedConnection m_xConnection; + css::uno::Reference< css::sdbc::XResultSet > m_xResultSet; + css::uno::Reference< css::sdbc::XRow > m_xRow; + css::uno::Reference< css::sdbcx::XRowLocate > m_xRowLocate; + css::uno::Reference< css::sdbc::XResultSetMetaData > m_xResultSetMetaData; + css::uno::Reference< css::container::XIndexAccess > m_xRowSetColumns; + css::uno::Reference< css::util::XNumberFormatter > m_xFormatter; // a number formatter working with the connection's NumberFormatsSupplier + css::uno::Reference< css::uno::XComponentContext > m_xContext; + + OUString m_sName; + + //for transfor the tablename + OUString m_sDefaultTableName; + + OUString m_sDataSourceName; + sal_Int32 m_nCommandType; + bool m_bNeedToReInitialize; + + rtl_TextEncoding m_eDestEnc; + bool m_bInInitialize; + bool m_bCheckOnly; + + // export data + ODatabaseImportExport( const svx::ODataAccessDescriptor& _aDataDescriptor, + const css::uno::Reference< css::uno::XComponentContext >& _rM, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF); + + // import data + ODatabaseImportExport( const SharedConnection& _rxConnection, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rM); + + virtual ~ODatabaseImportExport() override; + + virtual void initialize(); + public: + void setStream(SvStream* _pStream){ m_pStream = _pStream; } + + //for set the tablename + void setSTableName(const OUString &_sTableName){ m_sDefaultTableName = _sTableName; } + + virtual bool Write(); // Export + virtual bool Read(); // Import + + void initialize(const svx::ODataAccessDescriptor& _aDataDescriptor); + void dispose(); + + void enableCheckOnly() { m_bCheckOnly = true; } + bool isCheckEnabled() const { return m_bCheckOnly; } + + private: + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + void impl_initFromDescriptor( const svx::ODataAccessDescriptor& _aDataDescriptor, bool _bPlusDefaultInit ); + }; + + // RTF Import and Export + + class ORTFImportExport : public ODatabaseImportExport + { + void appendRow(OString const * pHorzChar,sal_Int32 _nColumnCount,sal_Int32& k,sal_Int32& kk); + public: + // export data + ORTFImportExport( const svx::ODataAccessDescriptor& _aDataDescriptor, + const css::uno::Reference< css::uno::XComponentContext >& _rM, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF) + : ODatabaseImportExport(_aDataDescriptor,_rM,_rxNumberF) {}; + + // import data + ORTFImportExport( const SharedConnection& _rxConnection, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rM) + : ODatabaseImportExport(_rxConnection,_rxNumberF,_rM) + {} + + virtual bool Write() override; + virtual bool Read() override; + }; + // HTML Import and Export + #define SBA_HTML_FONTSIZES 7 + const sal_Int16 nIndentMax = 23; + class OHTMLImportExport : public ODatabaseImportExport + { + static const sal_Int16 nCellSpacing; + static const char sIndentSource[]; + char sIndent[nIndentMax+1]; + sal_Int16 m_nIndent; + #if OSL_DEBUG_LEVEL > 0 + bool m_bCheckFont; + #endif + + void WriteHeader(); + void WriteBody(); + void WriteTables(); + void WriteCell( sal_Int32 nFormat,sal_Int32 nWidthPixel,sal_Int32 nHeightPixel,const char* pChar,const OUString& rValue,const char* pHtmlTag); + void IncIndent( sal_Int16 nVal ); + const char* GetIndentStr() const { return sIndent; } + void FontOn(); + inline void FontOff(); + + public: + // export data + OHTMLImportExport( const svx::ODataAccessDescriptor& _aDataDescriptor, + const css::uno::Reference< css::uno::XComponentContext >& _rM, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF); + // import data + OHTMLImportExport( const SharedConnection& _rxConnection, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rM) + : ODatabaseImportExport(_rxConnection,_rxNumberF,_rM) + , m_nIndent(0) + {} + + virtual bool Write() override; + virtual bool Read() override; + + }; + // normal RowSet Import and Export + + class ORowSetImportExport : public ODatabaseImportExport + { + std::vector<sal_Int32> m_aColumnMapping; + std::vector<sal_Int32> m_aColumnTypes; + css::uno::Reference< css::sdbc::XResultSetUpdate > m_xTargetResultSetUpdate; + css::uno::Reference< css::sdbc::XRowUpdate > m_xTargetRowUpdate; + css::uno::Reference< css::sdbc::XResultSetMetaData > m_xTargetResultSetMetaData; + weld::Window* m_pParent; + bool m_bAlreadyAsked; + + bool insertNewRow(); + protected: + virtual void initialize() override; + + public: + // export data + ORowSetImportExport(weld::Window* pParent, + const css::uno::Reference< css::sdbc::XResultSetUpdate >& xResultSetUpdate, + const svx::ODataAccessDescriptor& aDataDescriptor, + const css::uno::Reference< css::uno::XComponentContext >& rM); + + virtual bool Write() override; + virtual bool Read() override; + + private: + using ODatabaseImportExport::initialize; + }; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TypeInfo.hxx b/dbaccess/source/ui/inc/TypeInfo.hxx new file mode 100644 index 000000000..e9958e8e8 --- /dev/null +++ b/dbaccess/source/ui/inc/TypeInfo.hxx @@ -0,0 +1,121 @@ +/* -*- 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 <rtl/ustring.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include <map> +#include <memory> + +namespace dbaui +{ +// Based on these ids the language dependent OUString are fetched from the resource +const sal_uInt16 TYPE_UNKNOWN = 0; +const sal_uInt16 TYPE_TEXT = 1; +const sal_uInt16 TYPE_NUMERIC = 2; +const sal_uInt16 TYPE_DATETIME = 3; +const sal_uInt16 TYPE_DATE = 4; +const sal_uInt16 TYPE_TIME = 5; +const sal_uInt16 TYPE_BOOL = 6; +const sal_uInt16 TYPE_CURRENCY = 7; +const sal_uInt16 TYPE_MEMO = 8; +const sal_uInt16 TYPE_COUNTER = 9; +const sal_uInt16 TYPE_IMAGE = 10; +const sal_uInt16 TYPE_CHAR = 11; +const sal_uInt16 TYPE_DECIMAL = 12; +const sal_uInt16 TYPE_BINARY = 13; +const sal_uInt16 TYPE_VARBINARY = 14; +const sal_uInt16 TYPE_BIGINT = 15; +const sal_uInt16 TYPE_DOUBLE = 16; +const sal_uInt16 TYPE_FLOAT = 17; +const sal_uInt16 TYPE_REAL = 18; +const sal_uInt16 TYPE_INTEGER = 19; +const sal_uInt16 TYPE_SMALLINT = 20; +const sal_uInt16 TYPE_TINYINT = 21; +const sal_uInt16 TYPE_SQLNULL = 22; +const sal_uInt16 TYPE_OBJECT = 23; +const sal_uInt16 TYPE_DISTINCT = 24; +const sal_uInt16 TYPE_STRUCT = 25; +const sal_uInt16 TYPE_ARRAY = 26; +const sal_uInt16 TYPE_BLOB = 27; +const sal_uInt16 TYPE_CLOB = 28; +const sal_uInt16 TYPE_REF = 29; +const sal_uInt16 TYPE_OTHER = 30; +const sal_uInt16 TYPE_BIT = 31; + + class OTypeInfo + { + public: + OUString aUIName; // the name which is the user see (a combination of resource text and aTypeName) + OUString aTypeName; // name of type in database + OUString aCreateParams; // parameter for creation + OUString aLocalTypeName; + + sal_Int32 nPrecision; // length of type + sal_Int32 nNumPrecRadix; // indicating the radix, which is usually 2 or 10 + sal_Int32 nType; // database type + + sal_Int16 nMaximumScale; // decimal places after decimal point + sal_Int16 nMinimumScale; // min decimal places after decimal point + + sal_Int16 nSearchType; // if it is possible to search for type + + bool bCurrency : 1, // currency + bAutoIncrement : 1, // if automatic incrementing field + bNullable : 1; // if field can be NULL + + OTypeInfo() + :nPrecision(0) + ,nNumPrecRadix(10) + ,nType(css::sdbc::DataType::OTHER) + ,nMaximumScale(0) + ,nMinimumScale(0) + ,nSearchType(css::sdbc::ColumnSearch::FULL) + ,bCurrency(false) + ,bAutoIncrement(false) + ,bNullable(true) + {} + const OUString& getDBName() const { return aTypeName; } + + }; + + typedef std::shared_ptr<OTypeInfo> TOTypeInfoSP; + typedef std::multimap<sal_Int32,TOTypeInfoSP> OTypeInfoMap; + /** return the most suitable typeinfo for a requested type + @param _rTypeInfo contains a map of type to typeinfo + @param _nType the requested type + @param _sTypeName the typename + @param _sCreateParams the create params + @param _nPrecision the precision + @param _nScale the scale + @param _bAutoIncrement if it is an auto increment + @param _brForceToType true when type was found which has some differences + */ + TOTypeInfoSP getTypeInfoFromType(const OTypeInfoMap& _rTypeInfo, + sal_Int32 _nType, + const OUString& _sTypeName, + const OUString& _sCreateParams, + sal_Int32 _nPrecision, + sal_Int32 _nScale, + bool _bAutoIncrement, + bool& _brForceToType); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/UITools.hxx b/dbaccess/source/ui/inc/UITools.hxx new file mode 100644 index 000000000..c622c73f6 --- /dev/null +++ b/dbaccess/source/ui/inc/UITools.hxx @@ -0,0 +1,396 @@ +/* -*- 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 <connectivity/dbexception.hxx> +#include <comphelper/stl_types.hxx> +#include "TypeInfo.hxx" +#include <editeng/svxenum.hxx> +#include <vcl/taskpanelist.hxx> +#include <connectivity/dbtools.hxx> +#include <unotools/resmgr.hxx> + +#include <memory> +#include <string_view> + +#define RET_ALL 100 + +// we only need forward decl here +namespace com::sun::star { + + namespace beans { class XPropertySet;} + namespace container + { + class XNameAccess; + class XHierarchicalNameContainer; + } + namespace lang + { + class XEventListener; + } + namespace awt + { + struct FontDescriptor; + class XWindow; + } + namespace sdbc + { + class XDatabaseMetaData; + class XConnection; + } + namespace util + { + struct URL; + class XNumberFormatter; + } + namespace ucb { class XContent; } + namespace uno { class XComponentContext; } +} + +namespace svt +{ + class EditBrowseBox; +} + +namespace vcl { class Window; } +namespace weld { + class Widget; + class Window; +} +class ToolBox; +namespace vcl { class Font; } +class SvNumberFormatter; +class SfxFilter; + +namespace dbaui +{ + + /** creates a new connection and appends the eventlistener + @param _rsDataSourceName name of the datasource + @param _xDatabaseContext the database context + @param _rxContext the UNO component context + @param _rEvtLst the eventlistener which will be added to the new created connection + @param _rOUTConnection this parameter will be filled with the new created connection + @return SQLExceptionInfo contains a SQLException, SQLContext or a SQLWarning when they araised else .isValid() will return false + */ + ::dbtools::SQLExceptionInfo createConnection( + const OUString& _rsDataSourceName, + const css::uno::Reference< css::container::XNameAccess >& _xDatabaseContext, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + css::uno::Reference< css::lang::XEventListener> const & _rEvtLst, + css::uno::Reference< css::sdbc::XConnection>& _rOUTConnection ); + /** creates a new connection and appends the eventlistener + @param _xDataSource the datasource + @param _rxContext the UNO component context + @param _rEvtLst the eventlistener which will be added to the new created connection + @param _rOUTConnection this parameter will be filled with the new created connection + @return SQLExceptionInfo contains a SQLException, SQLContext or a SQLWarning when they araised else .isValid() will return false + */ + ::dbtools::SQLExceptionInfo createConnection( + const css::uno::Reference< css::beans::XPropertySet >& _xDataSource, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + css::uno::Reference< css::lang::XEventListener> const & _rEvtLst, + css::uno::Reference< css::sdbc::XConnection>& _rOUTConnection ); + + /** fills a map and a vector with localized type names + @param _rxConnection the connection to access the metadata + @param _rsTypeNames a list of localized type names separated with ';' + @param _rTypeInfoMap the filled map with the type names + @param _rTypeInfoIters the vector filled with map iterators + */ + void fillTypeInfo( const css::uno::Reference< css::sdbc::XConnection>& _rxConnection, + std::u16string_view _rsTypeNames, + OTypeInfoMap& _rTypeInfoMap, + std::vector<OTypeInfoMap::iterator>& _rTypeInfoIters); + + /** fill a column with data of a field description + @param _rxColumn the column which should be filled + @param _pFieldDesc the source of the data + */ + class OFieldDescription; + void setColumnProperties( const css::uno::Reference< css::beans::XPropertySet>& _rxColumn, + const OFieldDescription* _pFieldDesc); + + OUString createDefaultName( const css::uno::Reference< css::sdbc::XDatabaseMetaData>& _xMetaData, + const css::uno::Reference< css::container::XNameAccess>& _xTables, + const OUString& _sName); + + /** checks if the given name exists in the database context + */ + bool checkDataSourceAvailable( const OUString& _sDataSourceName, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + + /** maps SvxCellHorJustify to css::awt::TextAlign + @param SvxCellHorJustify& _eAlignment + @return the corresponding css::awt::TextAlign + */ + sal_Int32 mapTextAlign(const SvxCellHorJustify& _eAlignment); + + /** retrieves a data source given by name or URL, and displays an error if this fails + + Any <type scope="css::sdbc">SQLException</type>s which occur will be displayed. + Additionally, and Exceptions which indicate a data source name pointing to a non-existent database + URL will also be denoted. Yet more additionally, and other exceptions will be forwarded to + a <type scope="css::sdb">InteractionHandler</type>. + + @param _rDataSourceName + the URL of the database document, or the name of a registered data source + @param _pErrorMessageParent + the window to use as parent for error messages + @param _rxContext + a service factory to use for components to be created + @param _pErrorInfo + takes the error info in case of failure. If <NULL/>, the error is displayed to the user. + */ + css::uno::Reference< css::sdbc::XDataSource > + getDataSourceByName( + const OUString& _rDataSourceName, + weld::Window* _pErrorMessageParent, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + ::dbtools::SQLExceptionInfo* _pErrorInfo + ); + + /** returns either the model when data source is given as parameter, + or returns a data source when a model is given. + @param _xObject Either a data source or a model. + */ + css::uno::Reference< css::uno::XInterface > getDataSourceOrModel(const css::uno::Reference< css::uno::XInterface >& _xObject); + + /** maps css::awt::TextAlign to SvxCellHorJustify + @param css::awt::TextAlign& _nAlignment + @return the corresponding SvxCellHorJustify + */ + SvxCellHorJustify mapTextJustify(sal_Int32 _nAlignment); + + /** call the format dialog and set the selected format at the column + @param _xAffectedCol Font to be converted + @param _xField Font to be converted + */ + void callColumnFormatDialog(const css::uno::Reference< css::beans::XPropertySet>& _xAffectedCol, + const css::uno::Reference< css::beans::XPropertySet>& _xField, + SvNumberFormatter* _pFormatter, + weld::Widget* _pParent); + + /** second variant of the function before + */ + bool callColumnFormatDialog(weld::Widget* _pParent, + SvNumberFormatter* _pFormatter, + sal_Int32 _nDataType, + sal_Int32& _nFormatKey, + SvxCellHorJustify& _eJustify, + bool _bHasFormat); + /** append a name to tablefilter of a datasource + @param xConnection the connection is need to get the datasource + @param rName the name which should be appended + @param rxContext needed to check if datasource is available + @param pParent needed when an error must be shown + @return false when datsource is not available otherwise true + */ + bool appendToFilter(const css::uno::Reference< css::sdbc::XConnection>& xConnection, + const OUString& rName, + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + weld::Window* pParent); + + /** notifySystemWindow adds or remove the given window _pToRegister at the Systemwindow found when search _pWindow. + @param _pWindow + The window which is used to search for the SystemWindow. + @param _pToRegister + The window which should be added or removed on the TaskPaneList. + @param _rMemFunc + The member function which should be called at the SystemWindow when found. + Possible values are: + ::comphelper::mem_fun(&TaskPaneList::AddWindow) + ::comphelper::mem_fun(&TaskPaneList::RemoveWindow) + */ + void notifySystemWindow(vcl::Window const * _pWindow, + vcl::Window* _pToRegister, + const ::comphelper::mem_fun1_t<TaskPaneList,vcl::Window*>& _rMemFunc); + + void adjustBrowseBoxColumnWidth( ::svt::EditBrowseBox* _pBox, sal_uInt16 _nColId ); + + /** check if SQL92 name checking is enabled + @param _xConnection + Used to get the datasource as parent from the connection. + @return + <TRUE/> if so otherwise <FALSE/> + */ + bool isSQL92CheckEnabled(const css::uno::Reference< css::sdbc::XConnection>& _xConnection); + + /** check if the alias name of the table should be added at select statements + @param _xConnection + Used to get the datasource as parent from the connection. + @return + <TRUE/> if so otherwise <FALSE/> + */ + bool isAppendTableAliasEnabled(const css::uno::Reference< css::sdbc::XConnection>& _xConnection); + + /** determines whether when generating SQL statements, AS should be placed before a table alias + */ + bool generateAsBeforeTableAlias( const css::uno::Reference< css::sdbc::XConnection>& _rxConnection ); + + /** fills the bool and string value with information out of the datasource info property + @param _xDatasource + Asked for the properties. + @param _rAutoIncrementValueEnabled + <OUT/> Set to sal_True when the property was set in the datasource. + @param _rsAutoIncrementValue + <OUT/> Set to the value when the property was set in the datasource. + */ + void fillAutoIncrementValue(const css::uno::Reference< css::beans::XPropertySet>& _xDatasource + ,bool& _rAutoIncrementValueEnabled + ,OUString& _rsAutoIncrementValue); + + /** fills the bool and string value with information out of the datasource info property + @param _xConnection + Used to get the datasource as parent from the connection. + @param _rAutoIncrementValueEnabled + <OUT/> Set to sal_True when the property was set in the datasource. + @param _rsAutoIncrementValue + <OUT/> Set to the value when the property was set in the datasource. + */ + void fillAutoIncrementValue(const css::uno::Reference< css::sdbc::XConnection>& _xConnection + ,bool& _rAutoIncrementValueEnabled + ,OUString& _rsAutoIncrementValue); + + /** set the evaluation flag at the number formatter + @param _rxFormatter + */ + void setEvalDateFormatForFormatter(css::uno::Reference< css::util::XNumberFormatter > const & _rxFormatter); + + /** query for a type info which can be used to create a primary key column + @param _rTypeInfo + The map which contains all available types. + @return + The type info which can be used to create a primary key column. + */ + TOTypeInfoSP queryPrimaryKeyType(const OTypeInfoMap& _rTypeInfo); + + /** query for a specific type. + @param _nDataType + The type we are searching. + @param _rTypeInfo + The map which contains all available types. + @return + The type or <NULL/> if we can't find it. + */ + TOTypeInfoSP queryTypeInfoByType(sal_Int32 _nDataType,const OTypeInfoMap& _rTypeInfo); + + /** returns the configuration node name of user defined drivers. + @return + the configuration node name of user defined drivers. + */ + + /** returns the result of the user action when view the query dialog. + @param pParent + The parent of the dialog + @param pTitle + A string resource id for the text which will be displayed as title. + @param pText + A string resource id for the text which will be displayed above the buttons. + When the string contains a #1. This will be replaced by the name. + @param bAll + When set to <TRUE/>, the all button will be appended. + @param rName + The name of the object to ask for. + @return + RET_YES, RET_NO, RET_ALL + */ + sal_Int32 askForUserAction(weld::Window* pParent, TranslateId pTitle, TranslateId pText, bool bAll, std::u16string_view rName); + + /** creates a new view from a query or table + @param _sName + The name of the view to be created. + @param _xConnection + The source connection. + @param _xSourceObject + The object for which a view should be created. + @return + The created view. + */ + css::uno::Reference< css::beans::XPropertySet> createView( const OUString& _sName + ,const css::uno::Reference< css::sdbc::XConnection >& _xConnection + ,const css::uno::Reference< css::beans::XPropertySet>& _xSourceObject); + + /** creates a view with the given command + */ + css::uno::Reference< css::beans::XPropertySet> createView( + const OUString& _rName, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + const OUString& _rCommand + ); + + /** returns the stripped database name. + @param _xDataSource + The data source + @param _rsDatabaseName + Will be filled with the original data source if it is empty. + @return + The stripped database name either the registered name or if it is a file url the last segment. + */ + OUString getStrippedDatabaseName(const css::uno::Reference< css::beans::XPropertySet>& _xDataSource + ,OUString& _rsDatabaseName); + + /** returns the standard database filter + @return + the filter + */ + std::shared_ptr<const SfxFilter> getStandardDatabaseFilter(); + + /** opens a save dialog to store a form or report folder in the current hierarchy. + @param _pParent + The parent of the dialog. + @param _rxContext + a multi service factory which can be used to instantiate usual global services + @param _xNames + Where to insert the new object. + @param _sParentFolder + The name of the parent folder. + @param _bForm + <TRUE/> if a form should be inserted + @param _bCollection + A folder should be inserted + @param _xContent + The content which should be copied. + @param _bMove + if <TRUE/> the name of the content must be inserted without any change, otherwise not. + @return + <TRUE/> if the insert operation was successful, otherwise <FALSE/>. + */ + bool insertHierarchyElement( + weld::Window* pParent, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const css::uno::Reference< css::container::XHierarchicalNameContainer>& _xNames, + const OUString& _sParentFolder, + bool _bForm, + bool _bCollection = true, + const css::uno::Reference< css::ucb::XContent>& _xContent = nullptr, + bool _bMove = false + ); + + /** creates a number formatter + @param _rxConnection + The connection is needed to create the formatter + @param _rxContext + The multi service factory + */ + css::uno::Reference< css::util::XNumberFormatter > getNumberFormatter(const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,const css::uno::Reference< css::uno::XComponentContext >& _rxContext ); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/UserAdminDlg.hxx b/dbaccess/source/ui/inc/UserAdminDlg.hxx new file mode 100644 index 000000000..941eab5fa --- /dev/null +++ b/dbaccess/source/ui/inc/UserAdminDlg.hxx @@ -0,0 +1,76 @@ +/* -*- 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 <sfx2/tabdlg.hxx> +#include "IItemSetHelper.hxx" +#include <memory> + +namespace com::sun::star { + namespace sdbc { + class XConnection; + } + namespace lang { + class XMultiServiceFactory; + } +} + +namespace dbaui +{ + class ODbDataSourceAdministrationHelper; + // OUserAdminDlg + + /** implements the user admin dialog + */ + class OUserAdminDlg : public SfxTabDialogController, public IItemSetHelper, public IDatabaseSettingsDialog + { + weld::Window* m_pParent; + std::unique_ptr<ODbDataSourceAdministrationHelper> m_pImpl; + SfxItemSet* m_pItemSet; + css::uno::Reference< css::sdbc::XConnection> m_xConnection; + bool m_bOwnConnection; + protected: + virtual void PageCreated(const OString& rId, SfxTabPage& _rPage) override; + public: + OUserAdminDlg(weld::Window* pParent, SfxItemSet* pItems, + const css::uno::Reference< css::uno::XComponentContext >& rxORB, + const css::uno::Any& rDataSourceName, + const css::uno::Reference< css::sdbc::XConnection>& rConnection); + + virtual ~OUserAdminDlg() override; + + virtual const SfxItemSet* getOutputSet() const override; + virtual SfxItemSet* getWriteOutputSet() override; + + virtual short run() override; + + // forwards to ODbDataSourceAdministrationHelper + virtual css::uno::Reference< css::uno::XComponentContext > getORB() const override; + virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() override; + virtual css::uno::Reference< css::sdbc::XDriver > getDriver() override; + virtual OUString getDatasourceType(const SfxItemSet& _rSet) const override; + virtual void clearPassword() override; + virtual void saveDatasource() override; + virtual void setTitle(const OUString& _sTitle) override; + virtual void enableConfirmSettings( bool _bEnable ) override; + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WCPage.hxx b/dbaccess/source/ui/inc/WCPage.hxx new file mode 100644 index 000000000..69dc96f14 --- /dev/null +++ b/dbaccess/source/ui/inc/WCPage.hxx @@ -0,0 +1,78 @@ +/* -*- 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 "WTabPage.hxx" + +namespace dbaui +{ + class OWizColumnSelect; + class OWizNormalExtend; + class OCopyTable final : public OWizardPage + { + bool m_bPKeyAllowed; + bool m_bUseHeaderAllowed; + sal_Int16 m_nOldOperation; + + std::unique_ptr<weld::Entry> m_xEdTableName; + std::unique_ptr<weld::RadioButton> m_xRB_DefData; + std::unique_ptr<weld::RadioButton> m_xRB_Def; + std::unique_ptr<weld::RadioButton> m_xRB_View; + std::unique_ptr<weld::RadioButton> m_xRB_AppendData; + std::unique_ptr<weld::CheckButton> m_xCB_UseHeaderLine; + std::unique_ptr<weld::CheckButton> m_xCB_PrimaryColumn; + std::unique_ptr<weld::Label> m_xFT_KeyName; + std::unique_ptr<weld::Entry> m_xEdKeyName; + + DECL_LINK( RadioChangeHdl, weld::Toggleable&, void ); + DECL_LINK( KeyClickHdl, weld::Toggleable&, void ); + + bool checkAppendData(); + void SetAppendDataRadio(); + + public: + virtual void Reset() override; + virtual void Activate() override; + virtual bool LeavePage() override; + virtual OUString GetTitle() const override ; + + OCopyTable(weld::Container* pParent, OCopyTableWizard* pWizard); + virtual ~OCopyTable() override; + + bool IsOptionDefData() const { return m_xRB_DefData->get_active(); } + bool IsOptionDef() const { return m_xRB_Def->get_active(); } + bool IsOptionView() const { return m_xRB_View->get_active(); } + OUString GetKeyName() const { return m_xEdKeyName->get_text(); } + + void setCreateStyleAction(); + void disallowViews() + { + m_xRB_View->set_sensitive(false); + } + void disallowUseHeaderLine() + { + m_bUseHeaderAllowed = false; + m_xCB_UseHeaderLine->set_sensitive(false); + } + + void setCreatePrimaryKey( bool _bDoCreate, const OUString& _rSuggestedName ); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WColumnSelect.hxx b/dbaccess/source/ui/inc/WColumnSelect.hxx new file mode 100644 index 000000000..38b1317fd --- /dev/null +++ b/dbaccess/source/ui/inc/WColumnSelect.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 "WTabPage.hxx" +#include "WCopyTable.hxx" + +#include <comphelper/stl_types.hxx> + +namespace dbaui +{ + class OFieldDescription; + + // Wizard Page: OWizColumnSelect + + class OWizColumnSelect : public OWizardPage + { + std::unique_ptr<weld::TreeView> m_xOrgColumnNames; // left side + std::unique_ptr<weld::Button> m_xColumn_RH; + std::unique_ptr<weld::Button> m_xColumns_RH; + std::unique_ptr<weld::Button> m_xColumn_LH; + std::unique_ptr<weld::Button> m_xColumns_LH; + std::unique_ptr<weld::TreeView> m_xNewColumnNames; // right side + + DECL_LINK( ButtonClickHdl, weld::Button&, void ); + DECL_LINK( ListDoubleClickHdl, weld::TreeView&, bool ); + + static void clearListBox(weld::TreeView& _rListBox); + static void fillColumns(weld::TreeView const * pRight, + std::vector< OUString> &_rRightColumns); + + void createNewColumn( weld::TreeView* _pListbox, + OFieldDescription const * _pSrcField, + std::vector< OUString>& _rRightColumns, + const OUString& _sColumnName, + std::u16string_view _sExtraChars, + sal_Int32 _nMaxNameLen, + const ::comphelper::UStringMixEqual& _aCase); + + void moveColumn( weld::TreeView* _pRight, + weld::TreeView const * _pLeft, + std::vector< OUString>& _rRightColumns, + const OUString& _sColumnName, + std::u16string_view _sExtraChars, + sal_Int32 _nMaxNameLen, + const ::comphelper::UStringMixEqual& _aCase); + + void enableButtons(); + + sal_Int32 adjustColumnPosition(weld::TreeView const * _pLeft, + std::u16string_view _sColumnName, + ODatabaseExport::TColumnVector::size_type nCurrentPos, + const ::comphelper::UStringMixEqual& _aCase); + + public: + virtual void Reset ( ) override; + virtual void Activate() override; + virtual bool LeavePage() override; + virtual OUString GetTitle() const override ; + + OWizColumnSelect(weld::Container* pParent, OCopyTableWizard* pWizard); + virtual ~OWizColumnSelect() override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WCopyTable.hxx b/dbaccess/source/ui/inc/WCopyTable.hxx new file mode 100644 index 000000000..613311283 --- /dev/null +++ b/dbaccess/source/ui/inc/WCopyTable.hxx @@ -0,0 +1,413 @@ +/* -*- 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> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <comphelper/stl_types.hxx> +#include "TypeInfo.hxx" +#include <vcl/roadmapwizard.hxx> +#include "DExport.hxx" +#include "WTabPage.hxx" +#include "FieldDescriptions.hxx" +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XKeysSupplier.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <map> +#include <algorithm> + +namespace dbaui +{ + + class TColumnFindFunctor + { + public: + virtual bool operator()(const OUString& _sColumnName) const = 0; + + protected: + ~TColumnFindFunctor() {} + }; + + class TExportColumnFindFunctor : public TColumnFindFunctor + { + ODatabaseExport::TColumns* m_pColumns; + public: + TExportColumnFindFunctor(ODatabaseExport::TColumns* _pColumns) + { + m_pColumns = _pColumns; + } + + virtual ~TExportColumnFindFunctor() {} + + bool operator()(const OUString& _sColumnName) const override + { + return m_pColumns->find(_sColumnName) != m_pColumns->end(); + } + }; + + class TMultiListBoxEntryFindFunctor : public TColumnFindFunctor + { + ::comphelper::UStringMixEqual m_aCase; + std::vector< OUString>* m_pVector; + public: + TMultiListBoxEntryFindFunctor(std::vector< OUString>* _pVector, + const ::comphelper::UStringMixEqual& _aCase) + :m_aCase(_aCase) + ,m_pVector(_pVector) + { + } + + virtual ~TMultiListBoxEntryFindFunctor() {} + + bool operator()(const OUString& _sColumnName) const override + { + return std::any_of(m_pVector->begin(),m_pVector->end(), + [this, &_sColumnName](const OUString& lhs) + { return m_aCase(lhs, _sColumnName); }); + } + }; + + // ICopyTableSourceObject + /** interface to an object to copy to another DB, using the OCopyTableWizard + + when the wizard is used to copy an object to another DB, it usually requires + a sdbcx-level or sdb-level object (a css.sdbcx.Table or css.sdb.Query, that is). + + However, to also support copying tables from sdbc-level connections, we allow to + work with the object name only. This implies some less features (like copying the + UI settings of a table is not done), but still allows to copy definition and data. + */ + class ICopyTableSourceObject + { + public: + /// retrieves the fully qualified name of the object to copy + virtual OUString getQualifiedObjectName() const = 0; + /// determines whether the object is a view + virtual bool isView() const = 0; + /** copies the UI settings of the object to the given target object. Might be + ignored by implementations which do not have Ui settings. + */ + virtual void copyUISettingsTo( const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const = 0; + /// retrieves the column names of the to-be-copied object + virtual css::uno::Sequence< OUString > + getColumnNames() const = 0; + /// retrieves the names of the primary keys of the to-be-copied object + virtual css::uno::Sequence< OUString > + getPrimaryKeyColumnNames() const = 0; + /// creates a OFieldDescription for the given column of the to-be-copied object + virtual OFieldDescription* createFieldDescription( const OUString& _rColumnName ) const = 0; + /// returns the SELECT statement which can be used to retrieve the data of the to-be-copied object + virtual OUString getSelectStatement() const = 0; + + /** copies the filter and sorting + * + * \return + */ + virtual void copyFilterAndSortingTo(const css::uno::Reference< css::sdbc::XConnection >& _xConnection,const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const = 0; + + /** returns the prepared statement which can be used to retrieve the data of the to-be-copied object + + The default implementation of this method will simply prepare a statement with the return value + of ->getSelectStatement. + */ + virtual ::utl::SharedUNOComponent< css::sdbc::XPreparedStatement > + getPreparedSelectStatement() const = 0; + + virtual ~ICopyTableSourceObject(); + }; + + // ObjectCopySource + class ObjectCopySource : public ICopyTableSourceObject + { + private: + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; + css::uno::Reference< css::beans::XPropertySet > m_xObject; + css::uno::Reference< css::beans::XPropertySetInfo > m_xObjectPSI; + css::uno::Reference< css::container::XNameAccess > m_xObjectColumns; + + public: + ObjectCopySource( + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + const css::uno::Reference< css::beans::XPropertySet >& _rxObject + ); + + // ICopyTableSourceObject overridables + virtual OUString getQualifiedObjectName() const override; + virtual bool isView() const override; + virtual void copyUISettingsTo( const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override; + virtual void copyFilterAndSortingTo(const css::uno::Reference< css::sdbc::XConnection >& _xConnection, const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override; + virtual css::uno::Sequence< OUString > + getColumnNames() const override; + virtual css::uno::Sequence< OUString > + getPrimaryKeyColumnNames() const override; + virtual OFieldDescription* createFieldDescription( const OUString& _rColumnName ) const override; + virtual OUString getSelectStatement() const override; + virtual ::utl::SharedUNOComponent< css::sdbc::XPreparedStatement > + getPreparedSelectStatement() const override; + }; + + // NamedTableCopySource + class NamedTableCopySource : public ICopyTableSourceObject + { + private: + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; + OUString m_sTableName; + OUString m_sTableCatalog; + OUString m_sTableSchema; + OUString m_sTableBareName; + std::vector< OFieldDescription > m_aColumnInfo; + ::utl::SharedUNOComponent< css::sdbc::XPreparedStatement > m_xStatement; + + public: + NamedTableCopySource( + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + const OUString& _rTableName + ); + + // ICopyTableSourceObject overridables + virtual OUString getQualifiedObjectName() const override; + virtual bool isView() const override; + virtual void copyUISettingsTo( const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override; + virtual void copyFilterAndSortingTo(const css::uno::Reference< css::sdbc::XConnection >& _xConnection,const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override; + virtual css::uno::Sequence< OUString > + getColumnNames() const override; + virtual css::uno::Sequence< OUString > + getPrimaryKeyColumnNames() const override; + virtual OFieldDescription* createFieldDescription( const OUString& _rColumnName ) const override; + virtual OUString getSelectStatement() const override; + virtual ::utl::SharedUNOComponent< css::sdbc::XPreparedStatement > + getPreparedSelectStatement() const override; + + private: + void impl_ensureColumnInfo_throw(); + ::utl::SharedUNOComponent< css::sdbc::XPreparedStatement > const & + impl_ensureStatement_throw(); + }; + + // Wizard Dialog + class OCopyTableWizard : public vcl::RoadmapWizardMachine + { + friend class OWizColumnSelect; + friend class OWizTypeSelect; + friend class OWizTypeSelectControl; + friend class OCopyTable; + friend class OWizNameMatching; + + public: + typedef std::map<OUString, OUString, ::comphelper::UStringMixLess> TNameMapping; + + enum Wizard_Button_Style + { + WIZARD_NEXT, + WIZARD_PREV, + WIZARD_FINISH, + + WIZARD_NONE + }; + + private: + ODatabaseExport::TColumns m_vDestColumns; // contains the columns + ODatabaseExport::TColumnVector m_aDestVec; // the order to insert the columns + ODatabaseExport::TColumns m_vSourceColumns; + ODatabaseExport::TColumnVector m_vSourceVec; + + OTypeInfoMap m_aTypeInfo; + std::vector<OTypeInfoMap::iterator> m_aTypeInfoIndex; + OTypeInfoMap m_aDestTypeInfo; + std::vector<OTypeInfoMap::iterator> m_aDestTypeInfoIndex; + TNameMapping m_mNameMapping; + + ODatabaseExport::TPositions m_vColumnPositions; + std::vector<sal_Int32> m_vColumnTypes; + + css::uno::Reference< css::sdbc::XConnection > m_xDestConnection; + + const ICopyTableSourceObject& m_rSourceObject; + + css::uno::Reference< css::util::XNumberFormatter > m_xFormatter; + css::uno::Reference< css::uno::XComponentContext> m_xContext; + css::uno::Reference< css::task::XInteractionHandler> m_xInteractionHandler; + + OUString m_sTypeNames; // these type names are the ones out of the resource file + sal_uInt32 m_nPageCount; + bool m_bDeleteSourceColumns; + bool m_bInterConnectionCopy; // are we copying between different connections? + + css::lang::Locale m_aLocale; + OUString m_sName; // for a table the name is composed + OUString m_sSourceName; + OUString m_aKeyName; + TOTypeInfoSP m_pTypeInfo; // default type + bool m_bAddPKFirstTime; + sal_Int16 m_nOperation; + Wizard_Button_Style m_ePressed; + bool m_bCreatePrimaryKeyColumn; + bool m_bUseHeaderLine; + + private: + DECL_LINK( ImplPrevHdl, weld::Button&, void ); + DECL_LINK( ImplNextHdl, weld::Button&, void); + DECL_LINK( ImplOKHdl, weld::Button&, void ); + bool CheckColumns(sal_Int32& _rnBreakPos); + void loadData( const ICopyTableSourceObject& _rSourceObject, + ODatabaseExport::TColumns& _rColumns, + ODatabaseExport::TColumnVector& _rColVector ); + void construct(); + // need for table creation + static void appendColumns( css::uno::Reference< css::sdbcx::XColumnsSupplier> const & _rxColSup, const ODatabaseExport::TColumnVector* _pVec, bool _bKeyColumns = false ); + static void appendKey(css::uno::Reference< css::sdbcx::XKeysSupplier> const & _rxSup,const ODatabaseExport::TColumnVector* _pVec); + // checks if the type is supported in the destination database + bool supportsType(sal_Int32 _nDataType,sal_Int32& _rNewDataType); + + virtual std::unique_ptr<BuilderPage> createPage(vcl::WizardTypes::WizardState /*nState*/) override + { + assert(false); + return nullptr; + } + + virtual void ActivatePage() override; + + sal_uInt16 GetCurLevel() const { return getCurrentState(); } + + weld::Container* CreatePageContainer(); + + public: + // used for copy tables or queries + OCopyTableWizard( + weld::Window * pParent, + const OUString& _rDefaultName, + sal_Int16 _nOperation, + const ICopyTableSourceObject& _rSourceObject, + const css::uno::Reference< css::sdbc::XConnection >& _xSourceConnection, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const css::uno::Reference< css::task::XInteractionHandler>& _xInteractionHandler + ); + + // used for importing rtf/html sources + OCopyTableWizard( + weld::Window* pParent, + const OUString& _rDefaultName, + sal_Int16 _nOperation, + ODatabaseExport::TColumns&& _rDestColumns, + const ODatabaseExport::TColumnVector& _rSourceColVec, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + const css::uno::Reference< css::util::XNumberFormatter >& _xFormatter, + TypeSelectionPageFactory _pTypeSelectionPageFactory, + SvStream& _rTypeSelectionPageArg, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + virtual ~OCopyTableWizard() override; + + virtual bool DeactivatePage() override; + weld::Button& GetOKButton() { return *m_xFinish; } + Wizard_Button_Style GetPressedButton() const { return m_ePressed; } + void EnableNextButton(bool bEnable); + void AddWizardPage(std::unique_ptr<OWizardPage> xPage); // delete page from OCopyTableWizard + void CheckButtons(); // checks which button can be disabled, enabled + + // returns a vector where the position of a column and if the column is in the selection + // when not the value is COLUMN_POSITION_NOT_FOUND. + const ODatabaseExport::TPositions& GetColumnPositions() const { return m_vColumnPositions; } + const std::vector<sal_Int32>& GetColumnTypes() const { return m_vColumnTypes; } + bool UseHeaderLine() const { return m_bUseHeaderLine; } + void setUseHeaderLine(bool _bUseHeaderLine) { m_bUseHeaderLine = _bUseHeaderLine; } + + void insertColumn(sal_Int32 _nPos,OFieldDescription* _pField); + + /** replaces a field description with another one. The name must not be known so far. + @param _nPos + The pos inside the vector, 0 based. + @param _pField + The field to set. + @param _sOldName + The name of column to be replaced. + */ + void replaceColumn(sal_Int32 _nPos,OFieldDescription* _pField,const OUString& _sOldName); + + /** returns whether a primary key should be created in the target database + */ + bool shouldCreatePrimaryKey() const { return m_bCreatePrimaryKeyColumn;} + void setCreatePrimaryKey( bool _bDoCreate, const OUString& _rSuggestedName ); + + static bool supportsPrimaryKey( const css::uno::Reference< css::sdbc::XConnection >& _rxConnection ); + bool supportsPrimaryKey() const { return supportsPrimaryKey( m_xDestConnection ); } + + static bool supportsViews( const css::uno::Reference< css::sdbc::XConnection >& _rxConnection ); + bool supportsViews() const { return supportsViews( m_xDestConnection ); } + + /** returns the name of the primary key + @return + The name of the primary key. + */ + const OUString& getPrimaryKeyName() const { return m_aKeyName; } + + const OTypeInfoMap& getTypeInfo() const { return m_aTypeInfo; } + + TOTypeInfoSP const & getDestTypeInfo(sal_Int32 _nPos) const { return m_aDestTypeInfoIndex[_nPos]->second; } + const OTypeInfoMap& getDestTypeInfo() const { return m_aDestTypeInfo; } + + const css::lang::Locale& GetLocale() const { return m_aLocale; } + const css::uno::Reference< css::util::XNumberFormatter >& GetFormatter() const { return m_xFormatter; } + const css::uno::Reference< css::uno::XComponentContext>& GetComponentContext() const { return m_xContext; } + + const ODatabaseExport::TColumns& getSourceColumns() const{ return m_vSourceColumns; } + const ODatabaseExport::TColumnVector& getSrcVector() const { return m_vSourceVec; } + ODatabaseExport::TColumns& getDestColumns() { return m_vDestColumns; } + const ODatabaseExport::TColumnVector& getDestVector() const { return m_aDestVec; } + const OUString& getName() const { return m_sName; } + + /** clears the dest vectors + */ + void clearDestColumns(); + + css::uno::Reference< css::beans::XPropertySet > returnTable(); + css::uno::Reference< css::beans::XPropertySet > getTable() const; + css::uno::Reference< css::beans::XPropertySet > createTable(); + css::uno::Reference< css::beans::XPropertySet > createView() const; + sal_Int32 getMaxColumnNameLength() const; + + void setOperation( const sal_Int16 _nOperation ); + sal_Int16 getOperation() const { return m_nOperation;} + + OUString convertColumnName( const TColumnFindFunctor& _rCmpFunctor, + const OUString& _sColumnName, + std::u16string_view _sExtraChars, + sal_Int32 _nMaxNameLen); + TOTypeInfoSP convertType(const TOTypeInfoSP&_pType, bool& _bNotConvert); + + OUString createUniqueName(const OUString& _sName); + + // displays an error message that a column type is not supported + void showColumnTypeNotSupported(std::u16string_view _rColumnName); + + void removeColumnNameFromNameMap(const OUString& _sName); + void showError(const OUString& _sErrorMessage); + void showError(const css::uno::Any& _aError); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WExtendPages.hxx b/dbaccess/source/ui/inc/WExtendPages.hxx new file mode 100644 index 000000000..7d75f2cc1 --- /dev/null +++ b/dbaccess/source/ui/inc/WExtendPages.hxx @@ -0,0 +1,69 @@ +/* -*- 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 "WTypeSelect.hxx" + +class SvStream; +namespace dbaui +{ + class OCopyTableWizard; + + // Wizard Page: OWizHTMLExtend + class OWizHTMLExtend : public OWizTypeSelect + { + protected: + virtual void createReaderAndCallParser(sal_Int32 _nRows) override; + public: + OWizHTMLExtend(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream& rStream) + : OWizTypeSelect(pPage, pWizard, &rStream) + { + } + + static std::unique_ptr<OWizTypeSelect> Create(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream& rInput ) { return std::make_unique<OWizHTMLExtend>(pPage, pWizard, rInput); } + }; + // Wizard Page: OWizRTFExtend + class OWizRTFExtend : public OWizTypeSelect + { + protected: + virtual void createReaderAndCallParser(sal_Int32 _nRows) override; + public: + OWizRTFExtend(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream& rStream) + : OWizTypeSelect(pPage, pWizard, &rStream) + { + } + + static std::unique_ptr<OWizTypeSelect> Create(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream& rInput) { return std::make_unique<OWizRTFExtend>(pPage, pWizard, rInput); } + }; + + // Wizard Page: OWizNormalExtend + class OWizNormalExtend : public OWizTypeSelect + { + protected: + virtual void createReaderAndCallParser(sal_Int32 _nRows) override; + public: + OWizNormalExtend(weld::Container* pPage, OCopyTableWizard* pWizard) + : OWizTypeSelect(pPage, pWizard) + { + EnableAuto(false); + } + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WNameMatch.hxx b/dbaccess/source/ui/inc/WNameMatch.hxx new file mode 100644 index 000000000..d108c043c --- /dev/null +++ b/dbaccess/source/ui/inc/WNameMatch.hxx @@ -0,0 +1,63 @@ +/* -*- 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 "WTabPage.hxx" +#include "DExport.hxx" +#include "WCopyTable.hxx" + +namespace dbaui +{ + // Wizard Page: OWizNameMatching + // Name matching for data appending + class OWizNameMatching : public OWizardPage + { + std::unique_ptr<weld::Label> m_xTABLE_LEFT; + std::unique_ptr<weld::Label> m_xTABLE_RIGHT; + std::unique_ptr<weld::TreeView> m_xCTRL_LEFT; // left side + std::unique_ptr<weld::TreeView> m_xCTRL_RIGHT; // right side + std::unique_ptr<weld::Button> m_xColumn_up; + std::unique_ptr<weld::Button> m_xColumn_down; + std::unique_ptr<weld::Button> m_xColumn_up_right; + std::unique_ptr<weld::Button> m_xColumn_down_right; + std::unique_ptr<weld::Button> m_xAll; + std::unique_ptr<weld::Button> m_xNone; + OUString m_sSourceText; + OUString m_sDestText; + + DECL_LINK( ButtonClickHdl, weld::Button&, void ); + DECL_LINK( RightButtonClickHdl, weld::Button&, void ); + DECL_LINK( AllNoneClickHdl, weld::Button&, void ); + DECL_LINK( TableListClickHdl, weld::TreeView&, void ); + DECL_LINK( TableListRightSelectHdl, weld::TreeView&, void ); + + static void FillListBox(weld::TreeView& rTreeView, const ODatabaseExport::TColumnVector& rList, bool bCheckButtons); + + public: + virtual void Reset ( ) override; + virtual void Activate() override; + virtual bool LeavePage() override; + virtual OUString GetTitle() const override ; + + OWizNameMatching(weld::Container* pPage, OCopyTableWizard* pWizard); + virtual ~OWizNameMatching() override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WTabPage.hxx b/dbaccess/source/ui/inc/WTabPage.hxx new file mode 100644 index 000000000..cc7564cba --- /dev/null +++ b/dbaccess/source/ui/inc/WTabPage.hxx @@ -0,0 +1,46 @@ +/* -*- 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 <vcl/wizardmachine.hxx> + +namespace dbaui +{ + // Wizard Page + class OCopyTableWizard; + class OWizardPage : public ::vcl::OWizardPage + { + protected: + OCopyTableWizard* m_pParent; + bool m_bFirstTime; // Page is called the first time; should be set in the reset method + + OWizardPage(weld::Container* pPage, OCopyTableWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID); + + public: + virtual ~OWizardPage() override; + virtual void Reset ( ) = 0; + virtual bool LeavePage() = 0; + virtual OUString GetTitle() const = 0; + + bool IsFirstTime() const { return m_bFirstTime; } + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WTypeSelect.hxx b/dbaccess/source/ui/inc/WTypeSelect.hxx new file mode 100644 index 000000000..8a953302a --- /dev/null +++ b/dbaccess/source/ui/inc/WTypeSelect.hxx @@ -0,0 +1,139 @@ +/* -*- 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 "FieldDescControl.hxx" +#include "TypeInfo.hxx" +#include "WTabPage.hxx" + +class SvStream; + +namespace dbaui +{ + class OWizTypeSelect; + class OTableDesignHelpBar; + // OWizTypeSelectControl + class OWizTypeSelectControl final : public OFieldDescControl + { + OWizTypeSelect* m_pParentTabPage; + virtual void ActivateAggregate( EControlType eType ) override; + virtual void DeactivateAggregate( EControlType eType ) override; + + virtual void CellModified(sal_Int32 nRow, sal_uInt16 nColId ) override; + + virtual css::lang::Locale GetLocale() const override; + virtual css::uno::Reference< css::util::XNumberFormatter > GetFormatter() const override; + virtual TOTypeInfoSP getTypeInfo(sal_Int32 _nPos) override; + virtual const OTypeInfoMap* getTypeInfo() const override; + virtual bool isAutoIncrementValueEnabled() const override; + virtual OUString getAutoIncrementValue() const override; + + public: + OWizTypeSelectControl(weld::Container* pPage, OWizTypeSelect* pParentTabPage); + virtual ~OWizTypeSelectControl() override; + + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() override; + virtual css::uno::Reference< css::sdbc::XConnection> getConnection() override; + }; + + // Wizard Page: OWizTypeSelectList + // just defines the css::ucb::Command for the Contextmenu + class OWizTypeSelectList + { + std::unique_ptr<weld::TreeView> m_xControl; + bool m_bPKey; + bool IsPrimaryKeyAllowed() const; + void setPrimaryKey( OFieldDescription* _pFieldDescr, + sal_uInt16 _nPos, + bool _bSet = false); + + DECL_LINK(CommandHdl, const CommandEvent&, bool); + + Link<weld::TreeView&, void> m_aChangeHdl; + + public: + OWizTypeSelectList(std::unique_ptr<weld::TreeView> xControl); + void SetPKey(bool bPKey) { m_bPKey = bPKey; } + weld::TreeView* GetWidget() { return m_xControl.get(); } + OUString get_selected_id() const { return m_xControl->get_selected_id(); } + void clear() { m_xControl->clear(); } + void append(const OUString& rId, const OUString& rStr) + { + m_xControl->append(rId, rStr); + } + void set_image(int nRow, const OUString& rImage) + { + m_xControl->set_image(nRow, rImage); + } + void set_selection_mode(SelectionMode eMode) { m_xControl->set_selection_mode(eMode); } + int count_selected_rows() const { return m_xControl->count_selected_rows(); } + void select(int pos) { m_xControl->select(pos); } + void connect_changed(const Link<weld::TreeView&, void>& rLink) + { + m_aChangeHdl = rLink; + m_xControl->connect_changed(rLink); + } + }; + + // Wizard Page: OWizTypeSelect + // Serves as base class for different copy properties. + // Calls FillColumnList, when button AUTO is triggered + class OWizTypeSelect : public OWizardPage + { + friend class OWizTypeSelectControl; + friend class OWizTypeSelectList; + + DECL_LINK( ColumnSelectHdl, weld::TreeView&, void ); + DECL_LINK( ButtonClickHdl, weld::Button&, void ); + protected: + std::unique_ptr<OWizTypeSelectList> m_xColumnNames; + std::unique_ptr<weld::Label> m_xColumns; + std::unique_ptr<weld::Container> m_xControlContainer; + std::unique_ptr<OWizTypeSelectControl> m_xTypeControl; + std::unique_ptr<weld::Label> m_xAutoType; + std::unique_ptr<weld::Label> m_xAutoFt; + std::unique_ptr<weld::SpinButton> m_xAutoEt; + std::unique_ptr<weld::Button> m_xAutoPb; + + SvStream* m_pParserStream; // stream to read the tokens from or NULL + OUString m_sAutoIncrementValue; + sal_Int32 m_nDisplayRow; + bool m_bAutoIncrementEnabled; + bool m_bDuplicateName; + + virtual void createReaderAndCallParser(sal_Int32 _nRows) = 0; + + void EnableAuto(bool bEnable); + public: + virtual void Reset ( ) override; + virtual void Activate( ) override; + virtual bool LeavePage() override; + virtual OUString GetTitle() const override; + + OWizTypeSelect(weld::Container* pParent, OCopyTableWizard* pWizard, SvStream* pStream = nullptr); + virtual ~OWizTypeSelect() override; + + void setDisplayRow(sal_Int32 _nRow) { m_nDisplayRow = _nRow - 1; } + void setDuplicateName(bool _bDuplicateName) { m_bDuplicateName = _bDuplicateName; } + }; + + typedef std::unique_ptr<OWizTypeSelect> (*TypeSelectionPageFactory)(weld::Container*, OCopyTableWizard*, SvStream&); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/adtabdlg.hxx b/dbaccess/source/ui/inc/adtabdlg.hxx new file mode 100644 index 000000000..5fe1d7c1d --- /dev/null +++ b/dbaccess/source/ui/inc/adtabdlg.hxx @@ -0,0 +1,98 @@ +/* -*- 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 <memory> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <vcl/weld.hxx> +#include "tabletree.hxx" + +namespace dbaui +{ + /** unifies the access to a list of table/query objects + */ + class TableObjectListFacade + { + public: + virtual void updateTableObjectList( bool _bAllowViews ) = 0; + virtual OUString getSelectedName( OUString& _out_rAliasName ) const = 0; + virtual bool isLeafSelected() const = 0; + + virtual ~TableObjectListFacade(); + }; + + class IAddTableDialogContext + { + public: + virtual css::uno::Reference< css::sdbc::XConnection > + getConnection() const = 0; + virtual bool allowViews() const = 0; + virtual bool allowQueries() const = 0; + virtual bool allowAddition() const = 0; + virtual void addTableWindow( const OUString& _rQualifiedTableName, const OUString& _rAliasName ) = 0; + virtual void onWindowClosing() = 0; + + protected: + ~IAddTableDialogContext() {} + }; + + class OAddTableDlg : public weld::GenericDialogController + { + IAddTableDialogContext& m_rContext; + std::unique_ptr< TableObjectListFacade > m_xCurrentList; + + std::unique_ptr<weld::RadioButton> m_xCaseTables; + std::unique_ptr<weld::RadioButton> m_xCaseQueries; + + std::unique_ptr<OTableTreeListBox> m_xTableList; + std::unique_ptr<weld::TreeView> m_xQueryList; + + std::unique_ptr<weld::Button> m_xAddButton; + std::unique_ptr<weld::Button> m_xCloseButton; + + DECL_LINK( AddClickHdl, weld::Button&, void ); + DECL_LINK( CloseClickHdl, weld::Button&, void); + DECL_LINK( TableListDoubleClickHdl, weld::TreeView&, bool ); + DECL_LINK( TableListSelectHdl, weld::TreeView&, void ); + DECL_LINK( OnTypeSelected, weld::Toggleable&, void ); + + public: + OAddTableDlg(weld::Window* _pParent, + IAddTableDialogContext& _rContext); + virtual ~OAddTableDlg() override; + + void Update(); + void OnClose(); + + static OUString getDialogTitleForContext( + IAddTableDialogContext const & _rContext ); + + private: + bool impl_isAddAllowed(); + + enum ObjectList + { + Tables, + Queries + }; + void impl_switchTo( ObjectList _eList ); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/advancedsettingsdlg.hxx b/dbaccess/source/ui/inc/advancedsettingsdlg.hxx new file mode 100644 index 000000000..b28fe5ce3 --- /dev/null +++ b/dbaccess/source/ui/inc/advancedsettingsdlg.hxx @@ -0,0 +1,70 @@ +/* -*- 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 "IItemSetHelper.hxx" +#include <sfx2/tabdlg.hxx> +#include <memory> + +namespace dbaui +{ + + // AdvancedSettingsDialog + class ODbDataSourceAdministrationHelper; + /** implements the advanced page dlg of the data source properties. + */ + class AdvancedSettingsDialog : public SfxTabDialogController + , public IItemSetHelper + , public IDatabaseSettingsDialog + { + std::unique_ptr<ODbDataSourceAdministrationHelper> m_pImpl; + + protected: + virtual void PageCreated(const OString& rId, SfxTabPage& _rPage) override; + virtual short Ok() override; + + public: + AdvancedSettingsDialog(weld::Window* pParent, + SfxItemSet* _pItems, + const css::uno::Reference< css::uno::XComponentContext >& _rxORB, + const css::uno::Any& _aDataSourceName); + + virtual ~AdvancedSettingsDialog() override; + + /// determines whether or not the given data source type has any advanced setting + static bool doesHaveAnyAdvancedSettings( const OUString& _sURL ); + + virtual const SfxItemSet* getOutputSet() const override; + virtual SfxItemSet* getWriteOutputSet() override; + + // forwards to ODbDataSourceAdministrationHelper + virtual css::uno::Reference< css::uno::XComponentContext > getORB() const override; + virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() override; + virtual css::uno::Reference< css::sdbc::XDriver > getDriver() override; + virtual OUString getDatasourceType(const SfxItemSet& _rSet) const override; + virtual void clearPassword() override; + virtual void saveDatasource() override; + virtual void setTitle(const OUString& _sTitle) override; + virtual void enableConfirmSettings( bool _bEnable ) override; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/asyncmodaldialog.hxx b/dbaccess/source/ui/inc/asyncmodaldialog.hxx new file mode 100644 index 000000000..483dfb7c1 --- /dev/null +++ b/dbaccess/source/ui/inc/asyncmodaldialog.hxx @@ -0,0 +1,47 @@ +/* -*- 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/ui/dialogs/XExecutableDialog.hpp> + +namespace dbaui +{ + + // AsyncDialogExecutor + /** helper class for executing (UNO) dialogs modal, but asynchronously + */ + class AsyncDialogExecutor + { + public: + /** executes the given dialog asynchronously, but still modal + + @throws IllegalArgumentException + if the given dialog is <NULL/> + @todo + allow for a callback for the result + */ + static void executeModalDialogAsync( + const css::uno::Reference< css::ui::dialogs::XExecutableDialog >& _rxDialog + ); + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/browserids.hxx b/dbaccess/source/ui/inc/browserids.hxx new file mode 100644 index 000000000..0c510497d --- /dev/null +++ b/dbaccess/source/ui/inc/browserids.hxx @@ -0,0 +1,98 @@ +/* -*- 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 <svx/svxids.hrc> +#include <dbaccess_slotid.hrc> + +#define ID_BROWSER_COPY SID_COPY +#define ID_BROWSER_CUT SID_CUT +#define ID_BROWSER_EDITDOC SID_EDITDOC +#define ID_BROWSER_UNDORECORD SID_FM_RECORD_UNDO +#define ID_BROWSER_SAVERECORD SID_FM_RECORD_SAVE +#define ID_BROWSER_PASTE SID_PASTE +#define ID_BROWSER_CLIPBOARD_FORMAT_ITEMS SID_CLIPBOARD_FORMAT_ITEMS +#define ID_BROWSER_REDO SID_REDO +#define ID_BROWSER_SAVEDOC SID_SAVEDOC +#define ID_BROWSER_SAVEASDOC SID_SAVEASDOC +#define ID_BROWSER_TITLE SID_DOCINFO_TITLE +#define ID_BROWSER_UNDO SID_UNDO +#define ID_BROWSER_INSERTCOLUMNS SID_SBA_BRW_INSERT +#define ID_BROWSER_FORMLETTER SID_SBA_BRW_MERGE +#define ID_BROWSER_INSERTCONTENT SID_SBA_BRW_UPDATE + +#define ID_BROWSER_SEARCH SID_FM_SEARCH +#define ID_BROWSER_SORTUP SID_FM_SORTUP +#define ID_BROWSER_SORTDOWN SID_FM_SORTDOWN +#define ID_BROWSER_AUTOFILTER SID_FM_AUTOFILTER +#define ID_BROWSER_FILTERCRIT SID_FM_FILTERCRIT +#define ID_BROWSER_ORDERCRIT SID_FM_ORDERCRIT +#define ID_BROWSER_REMOVEFILTER SID_FM_REMOVE_FILTER_SORT +#define ID_BROWSER_FILTERED SID_FM_FORM_FILTERED +#define ID_BROWSER_REFRESH SID_FM_REFRESH +#define ID_BROWSER_COLATTRSET 10020 // column formatting +#define ID_BROWSER_COLWIDTH 10021 // column width +#define ID_BROWSER_TABLEATTR 10022 // table format attributes +#define ID_BROWSER_ROWHEIGHT 10023 // row height +#define ID_BROWSER_ADDTABLE SID_FM_ADDTABLE +#define ID_BROWSER_EXPLORER SID_DSBROWSER_EXPLORER +#define ID_BROWSER_DOCUMENT_DATASOURCE SID_DOCUMENT_DATA_SOURCE + +// The following ids are local to special components (e.g. menus), so they don't need to be unique +// overall. Please have this in mind when changing anything +#define ID_TREE_EDIT_DATABASE 1 +#define ID_TREE_CLOSE_CONN 2 + // FREE +#define ID_TREE_ADMINISTRATE 4 + +#define ID_REPORT_NEW_TEXT 14 +#define ID_FORM_NEW_TEXT 15 +#define ID_FORM_NEW_CALC 16 +#define ID_FORM_NEW_IMPRESS 17 +#define ID_NEW_QUERY_DESIGN 20 +#define ID_EDIT_QUERY_DESIGN 21 +#define ID_NEW_QUERY_SQL 22 +#define ID_EDIT_QUERY_SQL 23 +#define ID_NEW_TABLE_DESIGN 25 +#define ID_NEW_VIEW_DESIGN 28 +#define ID_DIRECT_SQL 32 +#define ID_BROWSER_REFRESH_REBUILD 34 +#define ID_INDEX_NEW 36 +#define ID_INDEX_DROP 37 +#define ID_INDEX_RENAME 38 +#define ID_INDEX_SAVE 39 +#define ID_INDEX_RESET 40 +#define ID_DOCUMENT_CREATE_REPWIZ 41 +#define ID_BROWSER_SQL 42 + +#define ID_APP_NEW_QUERY_AUTO_PILOT 44 +#define ID_NEW_TABLE_DESIGN_AUTO_PILOT 45 +#define ID_NEW_VIEW_DESIGN_AUTO_PILOT 46 + + +// other +#define ID_BROWSER_QUERY_EXECUTE SID_FM_EXECUTE + +#define ID_BROWSER_CLOSE SID_CLOSEWIN +#define ID_BROWSER_ESCAPEPROCESSING SID_FM_NATIVESQL + +#define ID_BROWSER_INSERT_ROW (SID_SBA_START + 46) // insert row + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/brwctrlr.hxx b/dbaccess/source/ui/inc/brwctrlr.hxx new file mode 100644 index 000000000..e5e1db401 --- /dev/null +++ b/dbaccess/source/ui/inc/brwctrlr.hxx @@ -0,0 +1,332 @@ +/* -*- 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 <dbaccess/genericcontroller.hxx> +#include "brwview.hxx" +#include "sbagrid.hxx" + +#include <com/sun/star/form/XLoadable.hpp> +#include <com/sun/star/container/XContainerListener.hpp> +#include <com/sun/star/sdb/XSQLErrorListener.hpp> +#include <com/sun/star/sdbc/XRowSet.hpp> +#include <com/sun/star/form/XResetListener.hpp> +#include <com/sun/star/form/XDatabaseParameterListener.hpp> +#include <com/sun/star/form/XConfirmDeleteListener.hpp> +#include <com/sun/star/form/XFormComponent.hpp> +#include <com/sun/star/awt/XFocusListener.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/frame/XModule.hpp> + +#include <vcl/timer.hxx> +#include <vcl/transfer.hxx> +#include <cppuhelper/implbase.hxx> +#include <svtools/cliplistener.hxx> + +struct FmFoundRecordInformation; +struct FmSearchContext; + +namespace dbtools +{ + class SQLExceptionInfo; +} + +namespace dbaui +{ + + typedef ::cppu::ImplInheritanceHelper < OGenericUnoController + , css::sdb::XSQLErrorListener + , css::form::XDatabaseParameterListener + , css::form::XConfirmDeleteListener + , css::form::XLoadListener + , css::form::XResetListener + , css::awt::XFocusListener + , css::container::XContainerListener + , css::beans::XPropertyChangeListener + , css::frame::XModule + > SbaXDataBrowserController_Base; + + class SbaXDataBrowserController :public SbaXDataBrowserController_Base + ,public SbaGridListener + { + // attributes + private: + // for implementing the XFormController + class FormControllerImpl; + friend class FormControllerImpl; + + css::uno::Reference< css::sdbc::XRowSet > m_xRowSet; // our rowset + css::uno::Reference< css::sdbcx::XColumnsSupplier > m_xColumnsSupplier; // queried from the rowset member + css::uno::Reference< css::form::XLoadable > m_xLoadable; // queried from the rowset member as well + css::uno::Reference< css::form::XFormComponent > m_xGridModel; // the model of our grid + css::uno::Reference< css::util::XNumberFormatter > m_xFormatter; // a number formatter working with the connection's NumberFormatsSupplier + mutable css::uno::Reference< css::sdb::XSingleSelectQueryComposer > + m_xParser; // for sorting 'n filtering + + sal_Int32 m_nRowSetPrivileges; // cached Privileges property of m_xRowSet + + AutoTimer m_aInvalidateClipboard; // for testing the state of the CUT/COPY/PASTE-slots + + TransferableDataHelper m_aSystemClipboard; // content of the clipboard + rtl::Reference<TransferableClipboardListener> + m_pClipboardNotifier; // notifier for changes in the clipboard + + OAsynchronousLink m_aAsyncGetCellFocus; + OAsynchronousLink m_aAsyncDisplayError; + ::dbtools::SQLExceptionInfo m_aCurrentError; + + OUString m_sStateSaveRecord; + OUString m_sStateUndoRecord; + OUString m_sModuleIdentifier; + + // members for asynchronous load operations + rtl::Reference<FormControllerImpl> m_xFormControllerImpl; // implementing the XFormController + + sal_uInt16 m_nFormActionNestingLevel; // see enter-/leaveFormAction + + bool m_bLoadCanceled : 1; // the load was canceled somehow + bool m_bCannotSelectUnfiltered : 1; // received a DATA_CANNOT_SELECT_UNFILTERED error + + protected: + class FormErrorHelper final + { + SbaXDataBrowserController* m_pOwner; + public: + FormErrorHelper(SbaXDataBrowserController* pOwner) : m_pOwner(pOwner) { m_pOwner->enterFormAction(); } + ~FormErrorHelper() { m_pOwner->leaveFormAction(); } + }; + friend class FormErrorHelper; + + // attribute access + protected: + const css::uno::Reference< css::sdbc::XRowSet >& getRowSet() const { return m_xRowSet; } + const css::uno::Reference< css::form::XLoadable >& getLoadable() const { return m_xLoadable; } + + const css::uno::Reference< css::form::XFormComponent >& getFormComponent() const { return m_xGridModel; } + css::uno::Reference< css::awt::XControlModel > getControlModel() const { return css::uno::Reference< css::awt::XControlModel > (m_xGridModel, css::uno::UNO_QUERY); } + const css::uno::Reference< css::util::XNumberFormatter >& getNumberFormatter()const { return m_xFormatter; } + + bool isValid() const { return m_xRowSet.is() && m_xGridModel.is(); } + bool isValidCursor() const; // checks the css::data::XDatabaseCursor-interface of m_xRowSet + bool isLoaded() const; + bool loadingCancelled() const { return m_bLoadCanceled; } + void onStartLoading( const css::uno::Reference< css::form::XLoadable >& _rxLoadable ); + void setLoadingCancelled() { m_bLoadCanceled = true; } + + public: + SbaXDataBrowserController(const css::uno::Reference< css::uno::XComponentContext >& _rM); + + UnoDataBrowserView* getBrowserView() const { return static_cast< UnoDataBrowserView*>(getView()); } + // late construction + virtual bool Construct(vcl::Window* pParent) override; + + // UNO + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override; + + // css::lang::XEventListener + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + + // css::util::XModifyListener + virtual void SAL_CALL modified(const css::lang::EventObject& aEvent) override; + + // css::container::XContainerListener + virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& Event) override; + virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& Event) override; + virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& Event) override; + + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + // XModule + virtual void SAL_CALL setIdentifier( const OUString& Identifier ) override; + virtual OUString SAL_CALL getIdentifier( ) override; + + // css::awt::XFocusListener + virtual void SAL_CALL focusGained(const css::awt::FocusEvent& e) override; + virtual void SAL_CALL focusLost(const css::awt::FocusEvent& e) override; + + // css::frame::XController + virtual sal_Bool SAL_CALL suspend(sal_Bool bSuspend) override; + + // css::lang::XComponent + virtual void SAL_CALL disposing() override; + + // css::frame::XFrameActionListener + virtual void SAL_CALL frameAction(const css::frame::FrameActionEvent& aEvent) override; + + // css::sdb::XSQLErrorListener + virtual void SAL_CALL errorOccured(const css::sdb::SQLErrorEvent& aEvent) override; + + // css::form::XDatabaseParameterListener + virtual sal_Bool SAL_CALL approveParameter(const css::form::DatabaseParameterEvent& aEvent) override; + + // css::form::XConfirmDeleteListener + virtual sal_Bool SAL_CALL confirmDelete(const css::sdb::RowChangeEvent& aEvent) override; + + // css::form::XLoadListener + virtual void SAL_CALL loaded(const css::lang::EventObject& aEvent) override; + virtual void SAL_CALL unloading(const css::lang::EventObject& aEvent) override; + virtual void SAL_CALL unloaded(const css::lang::EventObject& aEvent) override; + virtual void SAL_CALL reloading(const css::lang::EventObject& aEvent) override; + virtual void SAL_CALL reloaded(const css::lang::EventObject& aEvent) override; + + // css::form::XResetListener + virtual sal_Bool SAL_CALL approveReset(const css::lang::EventObject& rEvent) override; + virtual void SAL_CALL resetted(const css::lang::EventObject& rEvent) override; + + // SbaGridListener + virtual void RowChanged() override; + virtual void ColumnChanged() override; + virtual void SelectionChanged() override; + virtual void CellActivated() override; + virtual void CellDeactivated() override; + virtual void BeforeDrop() override; + virtual void AfterDrop() override; + + public: + + protected: + virtual ~SbaXDataBrowserController() override; + + // all the features which should be handled by this class + virtual void describeSupportedFeatures() override; + // state of a feature. 'feature' may be the handle of a css::util::URL somebody requested a dispatch interface for OR a toolbar slot. + virtual FeatureState GetState(sal_uInt16 nId) const override; + // execute a feature + virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override; + + virtual void startFrameListening( const css::uno::Reference< css::frame::XFrame >& _rxFrame ) override; + virtual void stopFrameListening( const css::uno::Reference< css::frame::XFrame >& _rxFrame ) override; + + virtual css::uno::Reference< css::sdbc::XRowSet > CreateForm(); + // our default implementation simply instantiates a stardiv.one.form.component.Form service + // (probably this needs not to be overridden, but you may return anything you want as long as it + // supports the css::form::DatabaseForm service. For instance you may want to create an adapter here which + // is synchronized with a foreign css::form::DatabaseForm you got elsewhere) + virtual bool InitializeForm( + const css::uno::Reference< css::beans::XPropertySet >& i_formProperties ) = 0; + // called immediately after a successful CreateForm + // do any initialization (data source etc.) here. the form should be fully functional after that. + // return sal_False if you didn't succeed (don't throw exceptions, they won't be caught) + + css::uno::Reference< css::form::XFormComponent > CreateGridModel(); + // our default implementation simply instantiates a stardiv.one.form.component.Grid service + // you most probably don't want to override this behavior + + // the default implementation of disposing distributes the events to the following disposingXXX functions + void disposingFormModel(const css::lang::EventObject& Source); + void disposingColumnModel(const css::lang::EventObject& Source); + + // want to be a listener to the grid control ? use this ! + void addControlListeners(const css::uno::Reference< css::awt::XControl > & _xGridControl); + void removeControlListeners(const css::uno::Reference< css::awt::XControl > & _xGridControl); + + // want to be a listener to the grid model ? use this ! + virtual void addModelListeners(const css::uno::Reference< css::awt::XControlModel > & _xGridControlModel); + virtual void removeModelListeners(const css::uno::Reference< css::awt::XControlModel > & _xGridControlModel); + + // want to be a listener grid columns ? use this ! + virtual void AddColumnListener(const css::uno::Reference< css::beans::XPropertySet > & xCol); + virtual void RemoveColumnListener(const css::uno::Reference< css::beans::XPropertySet > & xCol); + + // call after "major changes" (e.g. the completion of the async load). + // invalidates all toolbox slots and all supported features. + + virtual bool LoadForm(); + // load the form + // the default implementation does a direct load or starts a load thread, depending on the multithread capabilities + // of the data source. + // the default implementation also calls LoadFinished after a synchronous load, so be sure to do the same if you override + // this method and don't call the base class' method + + virtual void LoadFinished(bool bWasSynch); + // called if the loading (the _complete_ loading process) is done (no matter if synchron or asynchron). + + virtual void criticalFail(); + // called whenever a reload operation on the rowset failed + // (an "operation" is not only a simple reload: if the user sets a filter, and reloading the form + // after setting this filter fails, the filter is reset and the form is reloaded, again. Only the + // whole process (_both_ XLoadable::reload calls _together_) form the "reload operation" + + // empty the frame where our view resides + bool CommitCurrent(); + // commit the current column (i.e. cell) + bool SaveModified(bool bAskFor = true); + // save the modified record + + css::uno::Reference< css::beans::XPropertySet > getBoundField() const; + // a PropertySet corresponding to the cursor field a column is bound to. + // The field for the current column will be retrieved. + + void enterFormAction(); + void leaveFormAction(); + + // init the formatter if form changes + void initFormatter(); + + /// loads or reloads the form + bool reloadForm(const css::uno::Reference< css::form::XLoadable >& _rxLoadable); + + virtual bool preReloadForm(){ return false; } + virtual void postReloadForm(){} + + css::uno::Reference< css::sdb::XSingleSelectQueryComposer > + createParser_nothrow(); + + private: + void setCurrentModified( bool _bSet ); + + // execute the filter or sort slot + void ExecuteFilterSortCrit(bool bFilter); + + // execute the search slot + void ExecuteSearch(); + + void initializeParser() const; // changes the mutable member m_xParser + void applyParserFilter(const OUString& _rOldFilter, bool _bOldFilterApplied,const ::OUString& _sOldHaving,const css::uno::Reference< css::sdb::XSingleSelectQueryComposer >& _xParser); + void applyParserOrder(const OUString& _rOldOrder,const css::uno::Reference< css::sdb::XSingleSelectQueryComposer >& _xParser); + + sal_Int16 getCurrentColumnPosition() const; + void setCurrentColumnPosition( sal_Int16 _nPos ); + void addColumnListeners(const css::uno::Reference< css::awt::XControlModel > & _xGridControlModel); + + void impl_checkForCannotSelectUnfiltered( const ::dbtools::SQLExceptionInfo& _rError ); + + // time to check the CUT/COPY/PASTE-slot-states + DECL_LINK( OnInvalidateClipboard, Timer*, void ); + DECL_LINK( OnClipboardChanged, TransferableDataHelper*, void ); + + // search callbacks + DECL_LINK(OnSearchContextRequest, FmSearchContext&, sal_uInt32); + DECL_LINK(OnFoundData, FmFoundRecordInformation&, void); + DECL_LINK(OnCanceledNotFound, FmFoundRecordInformation&, void); + + DECL_LINK( OnAsyncGetCellFocus, void*, void ); + DECL_LINK( OnAsyncDisplayError, void*, void ); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/brwview.hxx b/dbaccess/source/ui/inc/brwview.hxx new file mode 100644 index 000000000..0933861b8 --- /dev/null +++ b/dbaccess/source/ui/inc/brwview.hxx @@ -0,0 +1,96 @@ +/* -*- 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 <vcl/window.hxx> + +#include <dbaccess/dataview.hxx> +#include <unotools/eventlisteneradapter.hxx> +#include "dbtreelistbox.hxx" + +namespace com::sun::star::awt { + class XControl; + class XControlContainer; + class XControlModel; +} + +class Splitter; + +namespace dbaui +{ + class SbaGridControl; + + class UnoDataBrowserView final : public ODataView, public ::utl::OEventListenerAdapter + { + css::uno::Reference< css::awt::XControl > m_xGrid; // our grid's UNO representation + css::uno::Reference< css::awt::XControlContainer > m_xMe; // our own UNO representation + VclPtr<InterimDBTreeListBox> m_pTreeView; + VclPtr<Splitter> m_pSplitter; + mutable VclPtr<SbaGridControl> m_pVclControl; // our grid's VCL representation + + DECL_LINK( SplitHdl, Splitter*, void ); + // attribute access + public: + const css::uno::Reference< css::awt::XControl >& getGridControl() const { return m_xGrid; } + SbaGridControl* getVclControl() const; + + UnoDataBrowserView( vcl::Window* pParent, + IController& _rController, + const css::uno::Reference< css::uno::XComponentContext >& ); + virtual ~UnoDataBrowserView() override; + virtual void dispose() override; + + /// late construction + void Construct(const css::uno::Reference< css::awt::XControlModel >& xModel); + + /** as columns may be hidden there is a difference between a columns model pos and its view pos + so we you may use these translation function + */ + sal_uInt16 View2ModelPos(sal_uInt16 nPos) const; + /// for the same reason the view column count isn't the same as the model column count + + void setSplitter(Splitter* pSplitter); + void setTreeView(InterimDBTreeListBox* pTreeView); + + void showStatus( const OUString& _rStatus ); + void hideStatus(); + + const css::uno::Reference< css::awt::XControlContainer >& getContainer() const { return m_xMe; } + + private: + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + virtual void GetFocus() override; + virtual void resizeDocumentView(tools::Rectangle& rRect) override; + virtual void _disposing( const css::lang::EventObject& _rSource ) override; + + using ODataView::Construct; + }; + + class BrowserViewStatusDisplay final + { + VclPtr<UnoDataBrowserView> m_pView; + + public: + BrowserViewStatusDisplay( UnoDataBrowserView* _pView, const OUString& _rStatus ); + ~BrowserViewStatusDisplay( ); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/callbacks.hxx b/dbaccess/source/ui/inc/callbacks.hxx new file mode 100644 index 000000000..e380b2671 --- /dev/null +++ b/dbaccess/source/ui/inc/callbacks.hxx @@ -0,0 +1,123 @@ +/* -*- 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 <sot/exchange.hxx> + +class Point; +struct AcceptDropEvent; +struct ExecuteDropEvent; + +namespace comphelper { class OInterfaceContainerHelper2; } + +namespace vcl +{ + class Window; +} + +namespace weld +{ + class TreeIter; + class TreeView; +} + +namespace dbaui +{ + + class IController; + // IControlActionListener + class SAL_NO_VTABLE IControlActionListener + { + public: + /** requests a quick help text to display + @return <FALSE/> if the default quick help text should be used + */ + virtual bool requestQuickHelp(const void* pUserData, OUString& rText) const = 0; + + /** handler for StartDrag requests + @return <TRUE/> if a drag operation was started + */ + virtual bool requestDrag(const weld::TreeIter& rEntry) = 0; + + /** check whether or not a drop request should be accepted + */ + virtual sal_Int8 queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors ) = 0; + + /** execute a drop request + */ + virtual sal_Int8 executeDrop( const ExecuteDropEvent& _rEvt ) = 0; + + protected: + ~IControlActionListener() {} + }; + + // IContextMenuProvider + class SAL_NO_VTABLE IContextMenuProvider + { + public: + /** returns the context menu resource name for the control + + Supposed to be a valid name from uiconfig/<module>/popupmenu folder. + */ + virtual OUString getContextMenuResourceName() const = 0; + + /** returns the controller which is responsible for providing states of certain features, + and executing them. + */ + virtual IController& getCommandController() = 0; + + /** returns the container of registered context menu interceptors, or NULL if the implementation + does not support context menu interception + */ + virtual ::comphelper::OInterfaceContainerHelper2* + getContextMenuInterceptors() = 0; + + /** returns the current selection in the given control + + This selection is used for filling a ContextMenuExecuteEvent event for the given + control. + */ + virtual css::uno::Any getCurrentSelection(weld::TreeView& rControl) const = 0; + + virtual vcl::Window* getMenuParent() const = 0; + + /** adjust rPos which is initially relative to rControl to be relative to + the window of getMenuParent + */ + virtual void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const = 0; + + protected: + ~IContextMenuProvider() {} + }; + + // IDragTransferableListener + class SAL_NO_VTABLE IDragTransferableListener + { + public: + /// called when a drag operation done with a Transferable has been finished + virtual void dragFinished( ) = 0; + + protected: + ~IDragTransferableListener() {} + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/charsetlistbox.hxx b/dbaccess/source/ui/inc/charsetlistbox.hxx new file mode 100644 index 000000000..aedfb6ec5 --- /dev/null +++ b/dbaccess/source/ui/inc/charsetlistbox.hxx @@ -0,0 +1,48 @@ +/* -*- 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 <vcl/weld.hxx> +#include "charsets.hxx" + +class SfxItemSet; + +namespace dbaui +{ + // CharSetListBox + class CharSetListBox + { + public: + CharSetListBox(std::unique_ptr<weld::ComboBox> xControl); + + void SelectEntryByIanaName( const OUString& _rIanaName ); + bool StoreSelectedCharSet( SfxItemSet& _rSet, const sal_uInt16 _nItemId ); + + weld::ComboBox* get_widget() { return m_xControl.get(); } + void connect_changed(const Link<weld::ComboBox&, void>& rLink) { m_xControl->connect_changed(rLink); } + void show() { m_xControl->show(); } + + private: + OCharsetDisplay m_aCharSets; + std::unique_ptr<weld::ComboBox> m_xControl; + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/charsets.hxx b/dbaccess/source/ui/inc/charsets.hxx new file mode 100644 index 000000000..ed1f88d7b --- /dev/null +++ b/dbaccess/source/ui/inc/charsets.hxx @@ -0,0 +1,105 @@ +/* -*- 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 <connectivity/dbcharset.hxx> +#include <rtl/ustring.hxx> + +namespace dbaui +{ + + // OCharsetDisplay + typedef ::dbtools::OCharsetMap OCharsetDisplay_Base; + class OCharsetDisplay final : protected OCharsetDisplay_Base + { + private: + OUString m_aSystemDisplayName; + + public: + class ExtendedCharsetIterator; + friend class OCharsetDisplay::ExtendedCharsetIterator; + + typedef ExtendedCharsetIterator iterator; + typedef ExtendedCharsetIterator const_iterator; + + OCharsetDisplay(); + + // various find operations + const_iterator findEncoding(const rtl_TextEncoding _eEncoding) const; + const_iterator findIanaName(const OUString& _rIanaName) const; + const_iterator findDisplayName(const OUString& _rDisplayName) const; + + /// get access to the first element of the charset collection + const_iterator begin() const; + /// get access to the (last + 1st) element of the charset collection + const_iterator end() const; + + private: + virtual bool approveEncoding( const rtl_TextEncoding _eEncoding, const rtl_TextEncodingInfo& _rInfo ) const override; + + using OCharsetDisplay_Base::find; + }; + + //- CharsetDisplayDerefHelper + typedef ::dbtools::CharsetIteratorDerefHelper CharsetDisplayDerefHelper_Base; + class CharsetDisplayDerefHelper final : protected CharsetDisplayDerefHelper_Base + { + friend class OCharsetDisplay::ExtendedCharsetIterator; + + OUString m_sDisplayName; + + public: + CharsetDisplayDerefHelper(const CharsetDisplayDerefHelper& _rSource); + + OUString const & getIanaName() const { return CharsetDisplayDerefHelper_Base::getIanaName(); } + const OUString& getDisplayName() const { return m_sDisplayName; } + + private: + CharsetDisplayDerefHelper(const ::dbtools::CharsetIteratorDerefHelper& _rBase, const OUString& _rDisplayName); + }; + + //- OCharsetDisplay::ExtendedCharsetIterator + class OCharsetDisplay::ExtendedCharsetIterator + { + friend class OCharsetDisplay; + + friend bool operator==(const ExtendedCharsetIterator& lhs, const ExtendedCharsetIterator& rhs); + friend bool operator!=(const ExtendedCharsetIterator& lhs, const ExtendedCharsetIterator& rhs) { return !(lhs == rhs); } + + typedef ::dbtools::OCharsetMap container; + typedef container::CharsetIterator base_iterator; + + protected: + const OCharsetDisplay* m_pContainer; + base_iterator m_aPosition; + + public: + CharsetDisplayDerefHelper operator*() const; + + /// prefix increment + const ExtendedCharsetIterator& operator++(); + + protected: + ExtendedCharsetIterator( const OCharsetDisplay* _pContainer, const base_iterator& _rPosition ); + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/commontypes.hxx b/dbaccess/source/ui/inc/commontypes.hxx new file mode 100644 index 000000000..50c567010 --- /dev/null +++ b/dbaccess/source/ui/inc/commontypes.hxx @@ -0,0 +1,39 @@ +/* -*- 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 <unotools/sharedunocomponent.hxx> + +namespace com::sun::star { + namespace sdbc { + class XConnection; + } +} + +namespace dbaui +{ + + typedef ::utl::SharedUNOComponent< css::sdbc::XConnection > SharedConnection; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/curledit.hxx b/dbaccess/source/ui/inc/curledit.hxx new file mode 100644 index 000000000..a99c2c3af --- /dev/null +++ b/dbaccess/source/ui/inc/curledit.hxx @@ -0,0 +1,102 @@ +/* -*- 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 <vcl/weld.hxx> +#include <dsntypes.hxx> + +namespace dbaui +{ + +class OConnectionURLEdit +{ + OUString m_sSavedValue; + + ::dbaccess::ODsnTypeCollection* m_pTypeCollection; + OUString m_sSaveValueNoPrefix; + bool m_bShowPrefix; // when <TRUE> the prefix will be visible, otherwise not + + std::unique_ptr<weld::Entry> m_xEntry; + std::unique_ptr<weld::Label> m_xForcedPrefix; + +public: + OConnectionURLEdit(std::unique_ptr<weld::Entry> xEntry, std::unique_ptr<weld::Label> xForcedPrefix); + ~OConnectionURLEdit(); + +public: + bool get_visible() const { return m_xEntry->get_visible(); } + void connect_changed(const Link<weld::Entry&, void>& rLink) { m_xEntry->connect_changed(rLink); } + void set_help_id(const OString& rName) { m_xEntry->set_help_id(rName); } + void hide() + { + m_xEntry->hide(); + if (m_bShowPrefix) + m_xForcedPrefix->hide(); + } + void show() + { + m_xEntry->show(); + if (m_bShowPrefix) + m_xForcedPrefix->show(); + } + void save_value() { m_sSavedValue = GetText(); } + bool get_value_changed_from_saved() const { return m_sSavedValue != GetText(); } + void grab_focus() + { + m_xEntry->grab_focus(); + } + void set_sensitive(bool bSensitive) + { + m_xEntry->set_sensitive(bSensitive); + if (m_bShowPrefix) + m_xForcedPrefix->set_sensitive(bSensitive); + } + void connect_focus_in(const Link<weld::Widget&, void>& rLink) + { + m_xEntry->connect_focus_in(rLink); + } + void connect_focus_out(const Link<weld::Widget&, void>& rLink) + { + m_xEntry->connect_focus_out(rLink); + } + + // Edit overridables + void SetText(const OUString& _rStr); + void SetText(const OUString& _rStr, const Selection& _rNewSelection); + OUString GetText() const; + + /** Shows the Prefix + @param _bShowPrefix + If <TRUE/> than the prefix will be visible, otherwise not. + */ + void ShowPrefix(bool _bShowPrefix); + /// get the currently set text, excluding the prefix indicating the type + OUString GetTextNoPrefix() const; + /// set a new text, leave the current prefix unchanged + void SetTextNoPrefix(const OUString& _rText); + + void SaveValueNoPrefix() { m_sSaveValueNoPrefix = GetTextNoPrefix(); } + const OUString& GetSavedValueNoPrefix() const { return m_sSaveValueNoPrefix; } + void SetTypeCollection(::dbaccess::ODsnTypeCollection* _pTypeCollection) { m_pTypeCollection = _pTypeCollection; } +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/databaseobjectview.hxx b/dbaccess/source/ui/inc/databaseobjectview.hxx new file mode 100644 index 000000000..d6b23878a --- /dev/null +++ b/dbaccess/source/ui/inc/databaseobjectview.hxx @@ -0,0 +1,230 @@ +/* -*- 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 <rtl/ustring.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <comphelper/namedvaluecollection.hxx> + +namespace dbaui +{ + /** encapsulates access to the view of a database object. + + @todo + this is to be merged with the OLinkedDocumentAccess class + */ + class DatabaseObjectView + { + private: + css::uno::Reference< css::uno::XComponentContext > + m_xORB; + css::uno::Reference< css::frame::XFrame > + m_xParentFrame; + css::uno::Reference< css::frame::XComponentLoader > + m_xFrameLoader; + css::uno::Reference< css::sdb::application::XDatabaseDocumentUI > + m_xApplication; + OUString m_sComponentURL; + + private: + css::uno::Reference< css::lang::XComponent > + doDispatch( + const ::comphelper::NamedValueCollection& i_rDispatchArgs + ); + + protected: + /** creates the desired view + + The default implementation will call <member>fillDispatchArgs</member>, followed + by <member>doDispatch</member>. + + @param _rDataSource + the data source, as passed to the <member>createNew</member> or <member>openExisting</member> method. + @param _rObjectName + the name of the object for which the view is to be opened, + or an empty string if a view for a new object should be created. + @param _rCreationArgs + the arguments for the view's creation + */ + virtual css::uno::Reference< css::lang::XComponent > doCreateView( + const css::uno::Any& _rDataSource, + const OUString& _rObjectName, + const ::comphelper::NamedValueCollection& i_rCreationArgs + ); + + virtual void fillDispatchArgs( + ::comphelper::NamedValueCollection& i_rDispatchArgs, + const css::uno::Any& _rDataSource, + const OUString& _rObjectName + ); + + const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& + getApplicationUI() const { return m_xApplication; } + css::uno::Reference< css::sdbc::XConnection > + getConnection() const; + + public: + DatabaseObjectView( + const css::uno::Reference< css::uno::XComponentContext >& _rxORB, + const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& _rxApplication, + const css::uno::Reference< css::frame::XFrame >& _rxParentFrame, + const OUString& _rComponentURL + ); + virtual ~DatabaseObjectView(){} + + /** sets the target frame into which the view should be loaded. + + By default, the view is loaded into a top-level frame not being part of the + Desktop. + */ + void setTargetFrame( const css::uno::Reference< css::frame::XFrame >& _rxFrame ) + { + m_xFrameLoader.set( _rxFrame, css::uno::UNO_QUERY ); + } + + /** opens a view for a to-be-created object + + @param _xDataSource + the data source for which a new object is to be created + @return + the controller of the newly created document + */ + css::uno::Reference< css::lang::XComponent > + createNew( + const css::uno::Reference< css::sdbc::XDataSource >& _xDataSource, + const ::comphelper::NamedValueCollection& i_rDispatchArgs = ::comphelper::NamedValueCollection() + ); + + /** opens a view for an existent object + + @param _xDataSource + the data source for which a new object is to be created + @param _rObjectName + the name of the object to be edited + @param _rArgs + Additional settings which should be forwarded to the frame + @return + the frame into which the view has been loaded + */ + css::uno::Reference< css::lang::XComponent > + openExisting( + const css::uno::Any& _aDataSource, + const OUString& _rName, + const ::comphelper::NamedValueCollection& i_rDispatchArgs + ); + }; + + // QueryDesigner + class QueryDesigner final : public DatabaseObjectView + { + sal_Int32 m_nCommandType; + + virtual void fillDispatchArgs( + ::comphelper::NamedValueCollection& i_rDispatchArgs, + const css::uno::Any& _aDataSource, + const OUString& _rObjectName + ) override; + + public: + QueryDesigner( + const css::uno::Reference< css::uno::XComponentContext >& _rxORB, + const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& _rxApplication, + const css::uno::Reference< css::frame::XFrame >& _rxParentFrame, + bool _bCreateView + ); + }; + + // TableDesigner + class TableDesigner : public DatabaseObjectView + { + protected: + virtual void fillDispatchArgs( + ::comphelper::NamedValueCollection& i_rDispatchArgs, + const css::uno::Any& _aDataSource, + const OUString& _rObjectName + ) override; + + virtual css::uno::Reference< css::lang::XComponent > doCreateView( + const css::uno::Any& _rDataSource, + const OUString& _rObjectName, + const ::comphelper::NamedValueCollection& i_rCreationArgs + ) override; + + public: + TableDesigner( + const css::uno::Reference< css::uno::XComponentContext >& _rxORB, + const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& _rxApplication, + const css::uno::Reference< css::frame::XFrame >& _rxParentFrame + ); + + private: + /** retrieves the table designer component as provided by the connection, if any + @param _rTableName + the name of the table for which a designer is to be obtained + @return + the designer component, as provided by the connection, or <NULL/>, if the connection + does not provide a specialized designer. + @see css::sdb::application::XTableUIProvider + */ + css::uno::Reference< css::uno::XInterface > + impl_getConnectionProvidedDesigner_nothrow( const OUString& _rTableName ); + }; + + // ResultSetBrowser + class ResultSetBrowser : public DatabaseObjectView + { + private: + bool m_bTable; + + protected: + virtual void fillDispatchArgs( + ::comphelper::NamedValueCollection& i_rDispatchArgs, + const css::uno::Any& _aDataSource, + const OUString& _rQualifiedName + ) override; + + public: + ResultSetBrowser( + const css::uno::Reference< css::uno::XComponentContext >& _rxORB, + const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& _rxApplication, + const css::uno::Reference< css::frame::XFrame >& _rxParentFrame, + bool _bTable + ); + + }; + // RelationDesigner + class RelationDesigner : public DatabaseObjectView + { + public: + RelationDesigner( + const css::uno::Reference< css::uno::XComponentContext >& _rxORB, + const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& _rxApplication, + const css::uno::Reference< css::frame::XFrame >& _rxParentFrame + ); + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/datasourceconnector.hxx b/dbaccess/source/ui/inc/datasourceconnector.hxx new file mode 100644 index 000000000..541c49607 --- /dev/null +++ b/dbaccess/source/ui/inc/datasourceconnector.hxx @@ -0,0 +1,76 @@ +/* -*- 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/uno/XComponentContext.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> + +namespace dbtools +{ + class SQLExceptionInfo; +} + +namespace weld { class Window; } +namespace dbaui +{ + + // ODatasourceConnector + class ODatasourceConnector final + { + weld::Window* m_pErrorMessageParent; + css::uno::Reference< css::uno::XComponentContext > + m_xContext; + OUString m_sContextInformation; + + public: + ODatasourceConnector( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + weld::Window* _pMessageParent + ); + ODatasourceConnector( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + weld::Window* _pMessageParent, + const OUString& _rContextInformation + ); + + /// returns <TRUE/> if the object is able to create data source connections + bool isValid() const { return m_xContext.is(); } + + /** creates a connection to the data source, displays the possible error to the user, or returns it + */ + css::uno::Reference< css::sdbc::XConnection > + connect( + const OUString& _rDataSourceName, + ::dbtools::SQLExceptionInfo* _pErrorInfo + ) const; + + /** creates a connection to the data source, displays the possible error to the user, or returns it + */ + css::uno::Reference< css::sdbc::XConnection > + connect( + const css::uno::Reference< css::sdbc::XDataSource>& _xDataSource, + ::dbtools::SQLExceptionInfo* _pErrorInfo + ) const; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dbadmin.hxx b/dbaccess/source/ui/inc/dbadmin.hxx new file mode 100644 index 000000000..8caf3c129 --- /dev/null +++ b/dbaccess/source/ui/inc/dbadmin.hxx @@ -0,0 +1,114 @@ +/* -*- 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 <sfx2/tabdlg.hxx> +#include <dsntypes.hxx> +#include "IItemSetHelper.hxx" +#include <unotools/resmgr.hxx> +#include <memory> + +namespace com::sun::star { + namespace beans { + class XPropertySet; + } + namespace sdbc { + class XConnection; + } + namespace lang { + class XMultiServiceFactory; + } +} + +namespace dbaui +{ + +// ODbAdminDialog +class ODbDataSourceAdministrationHelper; +/** tab dialog for administrating the office wide registered data sources +*/ +class ODbAdminDialog final : public SfxTabDialogController, public IItemSetHelper, public IDatabaseSettingsDialog +{ +private: + std::unique_ptr<ODbDataSourceAdministrationHelper> m_pImpl; + + OString m_sMainPageID; + +public: + /** ctor. The itemset given should have been created by <method>createItemSet</method> and should be destroyed + after the dialog has been destroyed + */ + ODbAdminDialog(weld::Window* pParent, SfxItemSet const * _pItems, + const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + virtual ~ODbAdminDialog() override; + + /** create and return an item set for use with the dialog. + @param _pTypeCollection pointer to an <type>ODatasourceMap</type>. May be NULL, in this case + the pool will not contain a typecollection default. + */ + static void createItemSet(std::unique_ptr<SfxItemSet>& _rpSet, rtl::Reference<SfxItemPool>& _rpPool, std::vector<SfxPoolItem*>*& _rpDefaults, ::dbaccess::ODsnTypeCollection* _pTypeCollection); + /** destroy and item set / item pool / pool defaults previously created by <method>createItemSet</method> + */ + static void destroyItemSet(std::unique_ptr<SfxItemSet>& _rpSet, rtl::Reference<SfxItemPool>& _rpPool, std::vector<SfxPoolItem*>*& _rpDefaults); + + /** selects the DataSource + @param _rName + The name of the data source + */ + void selectDataSource(const css::uno::Any& _aDataSourceName); + + virtual const SfxItemSet* getOutputSet() const override; + virtual SfxItemSet* getWriteOutputSet() override; + + // forwards to ODbDataSourceAdministrationHelper + virtual css::uno::Reference< css::uno::XComponentContext > getORB() const override; + virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() override; + virtual css::uno::Reference< css::sdbc::XDriver > getDriver() override; + virtual OUString getDatasourceType(const SfxItemSet& _rSet) const override; + virtual void clearPassword() override; + virtual void saveDatasource() override; + virtual void setTitle(const OUString& _sTitle) override; + virtual void enableConfirmSettings( bool _bEnable ) override; + +private: + // adds a new detail page and remove all the old ones + void addDetailPage(const OString& rPageId, TranslateId pTextId, CreateTabPage pCreateFunc); + + virtual void PageCreated(const OString& rId, SfxTabPage& _rPage) override; + virtual short Ok() override; + + /// select a datasource with a given name, adjust the item set accordingly, and everything like that .. + void impl_selectDataSource(const css::uno::Any& _aDataSourceName); + /// reset the tag pages according to m_sCurrentDatasource and <arg>_rxDatasource</arg> + void impl_resetPages(const css::uno::Reference< css::beans::XPropertySet >& _rxDatasource); + + enum ApplyResult + { + AR_LEAVE_MODIFIED, // something was modified and has successfully been committed + AR_KEEP // don't leave the page (e.g. because an error occurred) + }; + /** apply all changes made + */ + ApplyResult implApplyChanges(); +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dbexchange.hxx b/dbaccess/source/ui/inc/dbexchange.hxx new file mode 100644 index 000000000..7fb0c6ee0 --- /dev/null +++ b/dbaccess/source/ui/inc/dbexchange.hxx @@ -0,0 +1,83 @@ +/* -*- 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 "TokenWriter.hxx" +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <svx/dbaexchange.hxx> + +#include <rtl/ref.hxx> + +namespace com::sun::star::uno { + class XComponentContext; +} + +namespace dbaui +{ + + class ORTFImportExport; + class OHTMLImportExport; + + class ODataClipboard : public svx::ODataAccessObjectTransferable + + { + ::rtl::Reference< OHTMLImportExport > m_pHtml; + ::rtl::Reference< ORTFImportExport > m_pRtf; + + public: + ODataClipboard(); + + ODataClipboard( + const css::uno::Reference< css::beans::XPropertySet >& i_rAliveForm, + const css::uno::Sequence< css::uno::Any >& i_rSelectedRows, + const bool i_bBookmarkSelection, + const css::uno::Reference< css::uno::XComponentContext >& i_rORB + ); + + void Update( + const OUString& _rDatasource, + const sal_Int32 _nCommandType, + const OUString& _rCommand, + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + const css::uno::Reference< css::util::XNumberFormatter >& _rxFormatter, + const css::uno::Reference< css::uno::XComponentContext >& _rxORB + ); + + void Update( + const OUString& _rDatasource, + const sal_Int32 _nCommandType, + const OUString& _rCommand, + const css::uno::Reference< css::util::XNumberFormatter >& _rxFormatter, + const css::uno::Reference< css::uno::XComponentContext >& _rxORB + ); + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + protected: + virtual void AddSupportedFormats() override; + virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override; + virtual void ObjectReleased() override; + virtual bool WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor& rFlavor ) override; + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dbtreelistbox.hxx b/dbaccess/source/ui/inc/dbtreelistbox.hxx new file mode 100644 index 000000000..7682841a2 --- /dev/null +++ b/dbaccess/source/ui/inc/dbtreelistbox.hxx @@ -0,0 +1,164 @@ +/* -*- 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 <vcl/InterimItemWindow.hxx> +#include <vcl/transfer.hxx> +#include <vcl/timer.hxx> +#include <vcl/weld.hxx> + +#include <memory> + +namespace dbaui +{ + class IEntryFilter + { + public: + virtual bool includeEntry(const void* pUserData) const = 0; + + protected: + ~IEntryFilter() {} + }; + + class IControlActionListener; + class IContextMenuProvider; + + class TreeListBox; + + class TreeListBoxDropTarget : public DropTargetHelper + { + private: + TreeListBox& m_rTreeView; + + virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override; + virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override; + + public: + TreeListBoxDropTarget(TreeListBox& rTreeView); + }; + + class TreeListBox + { + protected: + std::unique_ptr<weld::TreeView> m_xTreeView; + TreeListBoxDropTarget m_aDropTargetHelper; + + std::unique_ptr<weld::TreeIter> m_xDragedEntry; + IControlActionListener* m_pActionListener; + IContextMenuProvider* m_pContextMenuProvider; + + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(SelectHdl, weld::TreeView&, void); + DECL_LINK(QueryTooltipHdl, const weld::TreeIter&, OUString); + DECL_LINK(CommandHdl, const CommandEvent&, bool); + DECL_LINK(DragBeginHdl, bool&, bool); + + private: + Timer m_aTimer; // is needed for table updates + rtl::Reference<TransferDataContainer> m_xHelper; + + Link<LinkParamNone*,void> m_aSelChangeHdl; // handler to be called (asynchronously) when the selection changes in any way + Link<LinkParamNone*,void> m_aCopyHandler; // called when someone press CTRL+C + Link<LinkParamNone*,void> m_aPasteHandler; // called when someone press CTRL+V + Link<LinkParamNone*,void> m_aDeleteHandler; // called when someone press DELETE Key + + DECL_LINK(OnTimeOut, Timer*, void); + + protected: + void implStopSelectionTimer(); + void implStartSelectionTimer(); + + virtual bool DoChildKeyInput(const KeyEvent& rKEvt); + + public: + TreeListBox(std::unique_ptr<weld::TreeView> xTreeView, bool bSQLType); + virtual ~TreeListBox(); + + std::unique_ptr<weld::TreeIter> GetEntryPosByName(std::u16string_view rName, + const weld::TreeIter* pStart = nullptr, + const IEntryFilter* pFilter = nullptr) const; + + std::unique_ptr<weld::TreeIter> GetRootLevelParent(const weld::TreeIter* pEntry) const; + + void setControlActionListener(IControlActionListener* pListener) { m_pActionListener = pListener; } + void setContextMenuProvider(IContextMenuProvider* pContextMenuProvider) { m_pContextMenuProvider = pContextMenuProvider; } + + weld::TreeView& GetWidget() { return *m_xTreeView; } + const weld::TreeView& GetWidget() const { return *m_xTreeView; } + + TransferDataContainer& GetDataTransfer() { return *m_xHelper; } + + sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt); + sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt); + + void SetSelChangeHdl( const Link<LinkParamNone*,void>& _rHdl ) { m_aSelChangeHdl = _rHdl; } + void setCopyHandler(const Link<LinkParamNone*,void>& _rHdl) { m_aCopyHandler = _rHdl; } + void setPasteHandler(const Link<LinkParamNone*,void>& _rHdl) { m_aPasteHandler = _rHdl; } + void setDeleteHandler(const Link<LinkParamNone*,void>& _rHdl) { m_aDeleteHandler = _rHdl; } + }; + + class InterimDBTreeListBox : public InterimItemWindow + , public TreeListBox + { + private: + std::unique_ptr<weld::Label> m_xStatusBar; + public: + InterimDBTreeListBox(vcl::Window* pParent); + virtual void dispose() override; + weld::Label& GetStatusBar() { return *m_xStatusBar; } + virtual ~InterimDBTreeListBox() override; + void show_container() { m_xContainer->show(); } + protected: + virtual bool DoChildKeyInput(const KeyEvent& rKEvt) override; + }; + + class DBTreeViewBase + { + protected: + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Container> m_xContainer; + std::unique_ptr<TreeListBox> m_xTreeListBox; + public: + DBTreeViewBase(weld::Container* pContainer); + virtual ~DBTreeViewBase(); + + weld::TreeView& GetWidget() { return m_xTreeListBox->GetWidget(); } + const weld::TreeView& GetWidget() const { return m_xTreeListBox->GetWidget(); } + + TreeListBox& getListBox() const { return *m_xTreeListBox; } + + void hide() { m_xContainer->hide(); } + void show() { m_xContainer->show(); } + bool get_visible() const { return m_xContainer->get_visible(); } + }; + + class DBTreeView final : public DBTreeViewBase + { + public: + DBTreeView(weld::Container* pContainer, bool bSQLType); + }; + + class DBTableTreeView final : public DBTreeViewBase + { + public: + DBTableTreeView(weld::Container* pContainer); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dbu_dlg.hxx b/dbaccess/source/ui/inc/dbu_dlg.hxx new file mode 100644 index 000000000..ed97c4c93 --- /dev/null +++ b/dbaccess/source/ui/inc/dbu_dlg.hxx @@ -0,0 +1,24 @@ +/* -*- 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 + +#define WIZARD_PAGE_X 56 +#define WIZARD_PAGE_Y 30 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dbwiz.hxx b/dbaccess/source/ui/inc/dbwiz.hxx new file mode 100644 index 000000000..0c51ab1a9 --- /dev/null +++ b/dbaccess/source/ui/inc/dbwiz.hxx @@ -0,0 +1,101 @@ +/* -*- 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 <dsntypes.hxx> +#include "IItemSetHelper.hxx" +#include <vcl/wizardmachine.hxx> +#include <memory> + +namespace com::sun::star { + namespace beans { + class XPropertySet; + } + namespace sdbc { + class XConnection; + } + namespace lang { + class XMultiServiceFactory; + } +} + +using vcl::WizardTypes::WizardState; +using vcl::WizardTypes::CommitPageReason; + +namespace dbaccess +{ + class ODsnTypeCollection; +} +namespace dbaui +{ + +// ODbTypeWizDialog +class OGeneralPage; +class ODbDataSourceAdministrationHelper; +/** tab dialog for administrating the office wide registered data sources +*/ +class ODbTypeWizDialog : public vcl::WizardMachine , public IItemSetHelper, public IDatabaseSettingsDialog +{ +private: + std::unique_ptr<ODbDataSourceAdministrationHelper> m_pImpl; + std::unique_ptr<SfxItemSet> m_pOutSet; + ::dbaccess::ODsnTypeCollection* + m_pCollection; /// the DSN type collection instance + OUString m_eType; + +public: + /** ctor. The itemset given should have been created by <method>createItemSet</method> and should be destroyed + after the dialog has been destroyed + */ + ODbTypeWizDialog(weld::Window* pParent + ,SfxItemSet const * _pItems + ,const css::uno::Reference< css::uno::XComponentContext >& _rxORB + ,const css::uno::Any& _aDataSourceName + ); + virtual ~ODbTypeWizDialog() override; + + virtual const SfxItemSet* getOutputSet() const override; + virtual SfxItemSet* getWriteOutputSet() override; + + // forwards to ODbDataSourceAdministrationHelper + virtual css::uno::Reference< css::uno::XComponentContext > getORB() const override; + virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() override; + virtual css::uno::Reference< css::sdbc::XDriver > getDriver() override; + virtual OUString getDatasourceType(const SfxItemSet& _rSet) const override; + virtual void clearPassword() override; + virtual void saveDatasource() override; + virtual void setTitle(const OUString& _sTitle) override; + virtual void enableConfirmSettings( bool _bEnable ) override; + +protected: + /// to override to create new pages + virtual std::unique_ptr<BuilderPage> createPage(WizardState _nState) override; + virtual WizardState determineNextState(WizardState _nCurrentState) const override; + virtual bool leaveState(WizardState _nState) override; + virtual ::vcl::IWizardPageController* getPageController(BuilderPage* pCurrentPage) const override; + virtual bool onFinish() override; + +private: + DECL_LINK(OnTypeSelected, OGeneralPage&, void); +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dbwizsetup.hxx b/dbaccess/source/ui/inc/dbwizsetup.hxx new file mode 100644 index 000000000..0829b328d --- /dev/null +++ b/dbaccess/source/ui/inc/dbwizsetup.hxx @@ -0,0 +1,170 @@ +/* -*- 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 <dsntypes.hxx> +#include "IItemSetHelper.hxx" +#include <tools/urlobj.hxx> +#include <memory> +#include <vcl/roadmapwizard.hxx> + +namespace com::sun::star { + namespace beans { + class XPropertySet; + } + namespace sdbc { + class XConnection; + } + namespace lang { + class XMultiServiceFactory; + } +} + +using vcl::WizardTypes::WizardState; +using vcl::WizardTypes::CommitPageReason; +using vcl::RoadmapWizardTypes::PathId; + +namespace dbaui +{ + +class OGenericAdministrationPage; + +// ODbTypeWizDialogSetup +class OGeneralPage; +class OGeneralPageWizard; +class ODbDataSourceAdministrationHelper; +/** tab dialog for administrating the office wide registered data sources +*/ +class OMySQLIntroPageSetup; +class OFinalDBPageSetup; + +class ODbTypeWizDialogSetup final : public vcl::RoadmapWizardMachine, public IItemSetHelper, public IDatabaseSettingsDialog +{ +private: + std::unique_ptr<ODbDataSourceAdministrationHelper> m_pImpl; + std::unique_ptr<SfxItemSet> m_pOutSet; + OUString m_sURL; + OUString m_sOldURL; + bool m_bIsConnectable : 1; + OUString m_sRM_IntroText; + OUString m_sRM_dBaseText; + OUString m_sRM_TextText; + OUString m_sRM_MSAccessText; + OUString m_sRM_LDAPText; + OUString m_sRM_ADOText; + OUString m_sRM_JDBCText; + OUString m_sRM_MySQLNativePageTitle; + OUString m_sRM_OracleText; + OUString m_sRM_MySQLText; + OUString m_sRM_ODBCText; + OUString m_sRM_DocumentOrSpreadSheetText; + OUString m_sRM_AuthentificationText; + OUString m_sRM_FinalText; + INetURLObject m_aDocURL; + OUString m_sWorkPath; + OGeneralPageWizard* m_pGeneralPage; + OMySQLIntroPageSetup* m_pMySQLIntroPage; + OFinalDBPageSetup* m_pFinalPage; + + ::dbaccess::ODsnTypeCollection* + m_pCollection; /// the DSN type collection instance + +public: + /** ctor. The itemset given should have been created by <method>createItemSet</method> and should be destroyed + after the dialog has been destroyed + */ + ODbTypeWizDialogSetup(weld::Window* pParent + ,SfxItemSet const * _pItems + ,const css::uno::Reference< css::uno::XComponentContext >& _rxORB + ,const css::uno::Any& _aDataSourceName + ); + virtual ~ODbTypeWizDialogSetup() override; + + virtual const SfxItemSet* getOutputSet() const override; + virtual SfxItemSet* getWriteOutputSet() override; + + // forwards to ODbDataSourceAdministrationHelper + virtual css::uno::Reference< css::uno::XComponentContext > getORB() const override; + virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() override; + virtual css::uno::Reference< css::sdbc::XDriver > getDriver() override; + virtual OUString getDatasourceType(const SfxItemSet& _rSet) const override; + virtual void clearPassword() override; + virtual void setTitle(const OUString& _sTitle) override; + virtual void enableConfirmSettings( bool _bEnable ) override; + virtual void saveDatasource() override; + virtual OUString getStateDisplayName( WizardState _nState ) const override; + + /** returns <TRUE/> if the database should be opened, otherwise <FALSE/>. + */ + bool IsDatabaseDocumentToBeOpened() const; + + /** returns <TRUE/> if the table wizard should be opened, otherwise <FALSE/>. + */ + bool IsTableWizardToBeStarted() const; + + void SetIntroPage(OMySQLIntroPageSetup* pPage); + void SetGeneralPage(OGeneralPageWizard* pPage); + void SetFinalPage(OFinalDBPageSetup* pPage); + +private: + /// to override to create new pages + virtual std::unique_ptr<BuilderPage> createPage(WizardState _nState) override; + virtual bool leaveState(WizardState _nState) override; + virtual void enterState(WizardState _nState) override; + virtual ::vcl::IWizardPageController* getPageController(BuilderPage* pCurrentPage) const override; + virtual bool onFinish() override; + + void resetPages(const css::uno::Reference< css::beans::XPropertySet >& _rxDatasource); + + /** declares a path with or without authentication, as indicated by the database type + + @param _sURL + the data source type for which the path is declared. If this + data source type does not support authentication, the PAGE_DBSETUPWIZARD_AUTHENTIFICATION + state will be stripped from the sequence of states. + @param _nPathId + the ID of the path + @path + the first state in this path, following by an arbitrary number of others, as in + RoadmapWizard::declarePath. + */ + void declareAuthDepPath( const OUString& _sURL, PathId _nPathId, const vcl::RoadmapWizardTypes::WizardPath& _rPaths); + + void RegisterDataSourceByLocation(std::u16string_view sPath); + bool SaveDatabaseDocument(); + void activateDatabasePath(); + OUString createUniqueFileName(const INetURLObject& rURL); + void CreateDatabase(); + void createUniqueFolderName(INetURLObject* pURL); + ::dbaccess::DATASOURCE_TYPE VerifyDataSourceType(const ::dbaccess::DATASOURCE_TYPE DatabaseType) const; + + void updateTypeDependentStates(); + bool callSaveAsDialog(); + DECL_LINK(OnTypeSelected, OGeneralPage&, void); + DECL_LINK(OnChangeCreationMode, OGeneralPageWizard&, void); + DECL_LINK(OnRecentDocumentSelected, OGeneralPageWizard&, void); + DECL_LINK(OnSingleDocumentChosen, OGeneralPageWizard&, void); + DECL_LINK(ImplClickHdl, OMySQLIntroPageSetup*, void); + DECL_LINK(ImplModifiedHdl, OGenericAdministrationPage const *, void); +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/defaultobjectnamecheck.hxx b/dbaccess/source/ui/inc/defaultobjectnamecheck.hxx new file mode 100644 index 000000000..59705fe61 --- /dev/null +++ b/dbaccess/source/ui/inc/defaultobjectnamecheck.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 "objectnamecheck.hxx" + +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> + +#include <memory> + +namespace dbaui +{ + + // HierarchicalNameCheck + struct HierarchicalNameCheck_Impl; + /** class implementing the IObjectNameCheck interface, and checking given object names + against a hierarchical name container + */ + class HierarchicalNameCheck :public IObjectNameCheck + { + private: + std::unique_ptr< HierarchicalNameCheck_Impl > m_pImpl; + + public: + /** constructs a HierarchicalNameCheck instance + @param _rxNames + the hierarchical container of named objects, against which given names should be + checked + @param _rRelativeRoot + the root in the hierarchy against which given names should be checked + @throws css::lang::IllegalArgumentException + if the given container is <NULL/> + */ + HierarchicalNameCheck( + const css::uno::Reference< css::container::XHierarchicalNameAccess >& _rxNames, + const OUString& _rRelativeRoot + ); + + virtual ~HierarchicalNameCheck() override; + + HierarchicalNameCheck(const HierarchicalNameCheck&) = delete; + const HierarchicalNameCheck& operator=(const HierarchicalNameCheck&) = delete; + + // IObjectNameCheck overridables + virtual bool isNameValid( + const OUString& _rObjectName, + ::dbtools::SQLExceptionInfo& _out_rErrorToDisplay + ) const override; + }; + + // DynamicTableOrQueryNameCheck + struct DynamicTableOrQueryNameCheck_Impl; + /** class implementing the IObjectNameCheck interface, and checking a given name + for being valid as either a query or a table name. + + The class can be parametrized to act as either table name or query name validator. + + For databases which support queries in queries, the name check is implicitly extended + to both queries and tables, no matter which category is checked. This prevents, for + such databases, that users can create a query with the name of an existing table, + or vice versa. + + @seealso dbtools::DatabaseMetaData::supportsSubqueriesInFrom + @seealso css::sdb::tools::XObjectNames::checkNameForCreate + */ + class DynamicTableOrQueryNameCheck :public IObjectNameCheck + { + private: + std::unique_ptr< DynamicTableOrQueryNameCheck_Impl > m_pImpl; + + public: + /** constructs a DynamicTableOrQueryNameCheck instance + @param _rxSdbLevelConnection + a connection supporting the css.sdb.Connection service, in other word, it + does expose the XTablesSupplier and XQueriesSupplier interfaces. + @param _nCommandType + specifies whether table names or query names should be checked. Only valid values + are CommandType::TABLE and CommandType::QUERY. + @throws css::lang::IllegalArgumentException + if the given connection is <NULL/>, or the given command type is neither + CommandType::TABLE nor CommandType::QUERY. + */ + DynamicTableOrQueryNameCheck( + const css::uno::Reference< css::sdbc::XConnection >& _rxSdbLevelConnection, + sal_Int32 _nCommandType + ); + + virtual ~DynamicTableOrQueryNameCheck() override; + + DynamicTableOrQueryNameCheck(const DynamicTableOrQueryNameCheck&) = delete; + const DynamicTableOrQueryNameCheck& operator=(const DynamicTableOrQueryNameCheck&) = delete; + + // IObjectNameCheck overridables + virtual bool isNameValid( + const OUString& _rObjectName, + ::dbtools::SQLExceptionInfo& _out_rErrorToDisplay + ) const override; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/directsql.hxx b/dbaccess/source/ui/inc/directsql.hxx new file mode 100644 index 000000000..bfe8195fc --- /dev/null +++ b/dbaccess/source/ui/inc/directsql.hxx @@ -0,0 +1,113 @@ +/* -*- 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 <vcl/weld.hxx> +#include <deque> +#include <string_view> + +#include <com/sun/star/sdbc/XConnection.hpp> +#include <unotools/eventlisteneradapter.hxx> +#include <osl/mutex.hxx> + +#include "sqledit.hxx" + +struct ImplSVEvent; + +namespace dbaui +{ + // DirectSQLDialog + class DirectSQLDialog final + : public weld::GenericDialogController + , public ::utl::OEventListenerAdapter + { + ::osl::Mutex m_aMutex; + + std::unique_ptr<weld::Button> m_xExecute; + std::unique_ptr<weld::ComboBox> m_xSQLHistory; + std::unique_ptr<weld::TextView> m_xStatus; + std::unique_ptr<weld::CheckButton> m_xDirectSQL; + std::unique_ptr<weld::CheckButton> m_xShowOutput; + std::unique_ptr<weld::TextView> m_xOutput; + std::unique_ptr<weld::Button> m_xClose; + std::unique_ptr<SQLEditView> m_xSQL; + std::unique_ptr<weld::CustomWeld> m_xSQLEd; + + typedef std::deque< OUString > StringQueue; + StringQueue m_aStatementHistory; // previous statements + StringQueue m_aNormalizedHistory; // previous statements, normalized to be used in the list box + + sal_Int32 m_nStatusCount; + + css::uno::Reference< css::sdbc::XConnection > + m_xConnection; + + ImplSVEvent* m_pClosingEvent; + + public: + DirectSQLDialog( + weld::Window* _pParent, + const css::uno::Reference< css::sdbc::XConnection >& _rxConn); + virtual ~DirectSQLDialog() override; + + /// number of history entries + sal_Int32 getHistorySize() const; + + private: + void executeCurrent(); + void switchToHistory(sal_Int32 _nHistoryPos); + + // OEventListenerAdapter + virtual void _disposing( const css::lang::EventObject& _rSource ) override; + + DECL_LINK( OnExecute, weld::Button&, void ); + DECL_LINK( OnClose, void*, void ); + DECL_LINK( OnCloseClick, weld::Button&, void ); + DECL_LINK( OnListEntrySelected, weld::ComboBox&, void ); + DECL_LINK( OnStatementModified, LinkParamNone*, void ); + + /// adds a statement to the statement history + void implAddToStatementHistory(const OUString& _rStatement); + + /// ensures that our history has at most m_nHistoryLimit entries + void implEnsureHistoryLimit(); + + /// executes the statement given, adds the status to the status list + void implExecuteStatement(const OUString& _rStatement); + + /// adds a status text to the status list + void addStatusText(std::u16string_view _rMessage); + + /// adds a status text to the output list + void addOutputText(std::u16string_view _rMessage); + + /// displays resultset + void display(const css::uno::Reference< css::sdbc::XResultSet >& xRS); + +#ifdef DBG_UTIL + const char* impl_CheckInvariants() const; +#endif + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dlgattr.hxx b/dbaccess/source/ui/inc/dlgattr.hxx new file mode 100644 index 000000000..6c3a00f95 --- /dev/null +++ b/dbaccess/source/ui/inc/dlgattr.hxx @@ -0,0 +1,41 @@ +/* -*- 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 <sfx2/tabdlg.hxx> + +class SvxNumberInfoItem; +class SfxItemSet; +class SvNumberFormatter; +namespace dbaui +{ + + class SbaSbAttrDlg : public SfxTabDialogController + { + std::unique_ptr<SvxNumberInfoItem> pNumberInfoItem; + + public: + SbaSbAttrDlg(weld::Widget* pParent, const SfxItemSet*, SvNumberFormatter*, bool bHasFormat); + virtual ~SbaSbAttrDlg() override; + + virtual void PageCreated(const OString& rPageId, SfxTabPage& rTabPage) override; + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dlgsave.hxx b/dbaccess/source/ui/inc/dlgsave.hxx new file mode 100644 index 000000000..d56fc6ade --- /dev/null +++ b/dbaccess/source/ui/inc/dlgsave.hxx @@ -0,0 +1,81 @@ +/* -*- 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/uno/XComponentContext.hpp> +#include <o3tl/typed_flags_set.hxx> +#include <vcl/weld.hxx> +#include <memory> + +namespace com::sun::star { + namespace sdbc { + class XConnection; + } +} + +enum class SADFlags { + NONE = 0x0000, + AdditionalDescription = 0x0001, + TitlePasteAs = 0x0100, + TitleRename = 0x0200, +}; +namespace o3tl { + template<> struct typed_flags<SADFlags> : is_typed_flags<SADFlags, 0x0301> {}; +} + +namespace dbaui +{ + class OSaveAsDlgImpl; + class IObjectNameCheck; + class OSaveAsDlg : public weld::GenericDialogController + { + private: + std::unique_ptr<OSaveAsDlgImpl> m_pImpl; + css::uno::Reference< css::uno::XComponentContext > m_xContext; + public: + OSaveAsDlg( weld::Window * pParent, sal_Int32 _rType, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const css::uno::Reference< css::sdbc::XConnection>& _xConnection, + const OUString& rDefault, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags); + + OSaveAsDlg( weld::Window* _pParent, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const OUString& _rDefault, + const OUString& _sLabel, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags); + virtual ~OSaveAsDlg() override; + + const OUString& getName() const; + OUString getCatalog() const; + OUString getSchema() const; + private: + DECL_LINK(ButtonClickHdl, weld::Button&, void); + DECL_LINK(EditModifyHdl, weld::Entry&, void); + + void implInitOnlyTitle(const OUString& _rLabel); + void implInit(); + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dlgsize.hxx b/dbaccess/source/ui/inc/dlgsize.hxx new file mode 100644 index 000000000..5a673d712 --- /dev/null +++ b/dbaccess/source/ui/inc/dlgsize.hxx @@ -0,0 +1,44 @@ +/* -*- 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 <vcl/weld.hxx> + +namespace dbaui +{ + + class DlgSize final : public weld::GenericDialogController + { + private: + sal_Int32 m_nPrevValue; + void SetValue( sal_Int32 nVal ); + + DECL_LINK(CbClickHdl, weld::Toggleable&, void); + + std::unique_ptr<weld::MetricSpinButton> m_xMF_VALUE; + std::unique_ptr<weld::CheckButton> m_xCB_STANDARD; + + public: + DlgSize(weld::Window * pParent, sal_Int32 nVal, bool bRow, sal_Int32 _nAlternativeStandard = -1); + virtual ~DlgSize() override; + sal_Int32 GetValue() const; + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dsitems.hxx b/dbaccess/source/ui/inc/dsitems.hxx new file mode 100644 index 000000000..09410d31b --- /dev/null +++ b/dbaccess/source/ui/inc/dsitems.hxx @@ -0,0 +1,95 @@ +/* -*- 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/types.h> + +typedef sal_Int32 ItemID; + +// item ids for the data source administration dialog + +#define DSID_NAME 1 // name of a data source, SfxStringItem +#define DSID_ORIGINALNAME 2 // original name, internal, SfxStringItem +#define DSID_CONNECTURL 3 // connection URL, SfxStringItem +#define DSID_TABLEFILTER 4 // table filter, OStringListItem +#define DSID_TYPECOLLECTION 5 // collection of data source types, ODsnTypeCollection +#define DSID_INVALID_SELECTION 6 // is the selection (thus the set data) invalid?, SfxBoolItem +#define DSID_READONLY 7 // is the selection (thus the set data) readonly?, SfxBoolItem +#define DSID_USER 8 // the user name used for logon, SfxStringItem +#define DSID_PASSWORD 9 // the password used for logon, SfxStringItem +#define DSID_ADDITIONALOPTIONS 10 // additional options used for connecting, SfxStringItem +#define DSID_CHARSET 11 // character set to use, SfxStringItem by now +#define DSID_PASSWORDREQUIRED 12 // is the password required to connect?, SfxBoolItem +#define DSID_SHOWDELETEDROWS 13 // show deleted rows?, SfxBoolItem +#define DSID_ALLOWLONGTABLENAMES 14 // allow tables names longer than 8.3?, SfxBoolItem +#define DSID_JDBCDRIVERCLASS 15 // JDBC driver class, SfxStringItem +#define DSID_FIELDDELIMITER 16 // field delimiter, SfxUInt16Item +#define DSID_TEXTDELIMITER 17 // text delimiter, SfxUInt16Item +#define DSID_DECIMALDELIMITER 18 // decimal delimiter, SfxUInt16Item +#define DSID_THOUSANDSDELIMITER 19 // thousands delimiter, SfxUInt16Item +#define DSID_TEXTFILEEXTENSION 20 // extension for text files, SfxStringItem +#define DSID_TEXTFILEHEADER 21 // the text file contains a header?, SfxBoolItem +#define DSID_PARAMETERNAMESUBST 22 +#define DSID_CONN_PORTNUMBER 23 +#define DSID_SUPPRESSVERSIONCL 24 // meta data: sal_True if the data source described by the set is to-be-deleted +#define DSID_CONN_SHUTSERVICE 25 +#define DSID_CONN_DATAINC 26 +#define DSID_CONN_CACHESIZE 27 +#define DSID_CONN_CTRLUSER 28 +#define DSID_CONN_CTRLPWD 29 +#define DSID_USECATALOG 30 // should the driver use the catalog name when the database is filebased +#define DSID_CONN_HOSTNAME 31 +#define DSID_CONN_LDAP_BASEDN 32 +#define DSID_CONN_LDAP_PORTNUMBER 33 +#define DSID_CONN_LDAP_ROWCOUNT 34 +#define DSID_SQL92CHECK 35 +#define DSID_AUTOINCREMENTVALUE 36 +#define DSID_AUTORETRIEVEVALUE 37 +#define DSID_AUTORETRIEVEENABLED 38 +#define DSID_APPEND_TABLE_ALIAS 39 +#define DSID_MYSQL_PORTNUMBER 40 +#define DSID_IGNOREDRIVER_PRIV 41 +#define DSID_BOOLEANCOMPARISON 42 +#define DSID_ORACLE_PORTNUMBER 43 +#define DSID_ENABLEOUTERJOIN 44 +#define DSID_CATALOG 45 +#define DSID_SCHEMA 46 +#define DSID_INDEXAPPENDIX 47 +#define DSID_CONN_LDAP_USESSL 48 +#define DSID_DOCUMENT_URL 49 +#define DSID_DOSLINEENDS 50 +#define DSID_DATABASENAME 51 +#define DSID_AS_BEFORE_CORRNAME 52 +#define DSID_CHECK_REQUIRED_FIELDS 53 +#define DSID_IGNORECURRENCY 54 +#define DSID_CONN_SOCKET 55 +#define DSID_ESCAPE_DATETIME 56 +#define DSID_NAMED_PIPE 57 +#define DSID_PRIMARY_KEY_SUPPORT 58 +#define DSID_MAX_ROW_SCAN 59 +#define DSID_RESPECTRESULTSETTYPE 60 + // don't forget to adjust DSID_LAST_ITEM_ID below! + +// item range. Adjust this if you introduce new items above + +#define DSID_FIRST_ITEM_ID DSID_NAME +#define DSID_LAST_ITEM_ID DSID_RESPECTRESULTSETTYPE + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dsmeta.hxx b/dbaccess/source/ui/inc/dsmeta.hxx new file mode 100644 index 000000000..69b13ebb7 --- /dev/null +++ b/dbaccess/source/ui/inc/dsmeta.hxx @@ -0,0 +1,125 @@ +/* -*- 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 <set> + +#include "dsitems.hxx" + +#include <rtl/ustring.hxx> + +#include <memory> + +namespace dbaui +{ + + // AuthenticationMode + enum AuthenticationMode + { + AuthNone, + AuthUserPwd, + AuthPwd + }; + + // DataSourceMetaData + class FeatureSet; + class DataSourceMetaData_Impl; + /** encapsulates meta data for a data source + + On the long run, this class should a) encapsulate *all* meta data which + currently is hard coded somewhere in the program logic and b) be initialized + from the configuration. + + At the moment, the data a) is still hard coded in the, well, code and b) + contains meta data about the advanced settings only. + */ + class DataSourceMetaData + { + public: + DataSourceMetaData( const OUString& _sURL ); + ~DataSourceMetaData(); + + /// returns a struct describing this data source type's support for our known advanced settings + const FeatureSet& getFeatureSet() const; + + /// determines whether or not the data source requires authentication + static AuthenticationMode getAuthentication( const OUString& _sURL ); + + private: + std::shared_ptr< DataSourceMetaData_Impl > m_pImpl; + }; + + // FeatureSet + /** can be used to ask for (UI) support for certain advanced features + */ + class FeatureSet + { + public: + typedef std::set< ItemID >::const_iterator const_iterator; + + public: + FeatureSet() { } + + void put( const ItemID _id ) { m_aContent.insert( _id ); } + bool has( const ItemID _id ) const { return m_aContent.find( _id ) != m_aContent.end(); } + + inline bool supportsAnySpecialSetting() const; + inline bool supportsGeneratedValues() const; + + const_iterator begin() const { return m_aContent.begin(); } + const_iterator end() const { return m_aContent.end(); } + + private: + std::set< ItemID > m_aContent; + }; + + inline bool FeatureSet::supportsGeneratedValues() const + { + return has( DSID_AUTORETRIEVEENABLED ); + } + + inline bool FeatureSet::supportsAnySpecialSetting() const + { + return has( DSID_SQL92CHECK ) + || has( DSID_APPEND_TABLE_ALIAS ) + || has( DSID_AS_BEFORE_CORRNAME ) + || has( DSID_ENABLEOUTERJOIN ) + || has( DSID_IGNOREDRIVER_PRIV ) + || has( DSID_PARAMETERNAMESUBST ) + || has( DSID_SUPPRESSVERSIONCL ) + || has( DSID_CATALOG ) + || has( DSID_SCHEMA ) + || has( DSID_INDEXAPPENDIX ) + || has( DSID_DOSLINEENDS ) + || has( DSID_BOOLEANCOMPARISON ) + || has( DSID_CHECK_REQUIRED_FIELDS ) + || has( DSID_IGNORECURRENCY ) + || has( DSID_ESCAPE_DATETIME ) + || has( DSID_PRIMARY_KEY_SUPPORT ) + || has( DSID_MAX_ROW_SCAN ) + || has( DSID_RESPECTRESULTSETTYPE ) + ; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/exsrcbrw.hxx b/dbaccess/source/ui/inc/exsrcbrw.hxx new file mode 100644 index 000000000..0ecda1ed6 --- /dev/null +++ b/dbaccess/source/ui/inc/exsrcbrw.hxx @@ -0,0 +1,96 @@ +/* -*- 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 "brwctrlr.hxx" + +#include <comphelper/interfacecontainer3.hxx> +#include <comphelper/uno3.hxx> + +// SbaExternalSourceBrowser + +namespace dbaui +{ + class SbaXFormAdapter; + class SbaExternalSourceBrowser final + :public SbaXDataBrowserController + ,public css::util::XModifyBroadcaster + { + ::comphelper::OInterfaceContainerHelper3<css::util::XModifyListener> m_aModifyListeners; + // for multiplexing the modify events + rtl::Reference<SbaXFormAdapter> m_pDataSourceImpl; + bool m_bInQueryDispatch; + // our queryDispatch will ask our frame, which first will ask our queryDispatch, so we need to protect against + // recursion + + public: + SbaExternalSourceBrowser(const css::uno::Reference< css::uno::XComponentContext >& _rM); + + // UNO + DECLARE_UNO3_DEFAULTS(SbaExternalSourceBrowser, SbaXDataBrowserController) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + // virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > getIdlClasses(); + + // static css::uno::Reference< css::reflection::XIdlClass > getStaticIdlClass(); + + // css::frame::XDispatch + virtual void SAL_CALL dispatch(const css::util::URL& aURL, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override; + + // css::frame::XDispatchProvider + virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch(const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags) override; + + // css::util::XModifyListener + virtual void SAL_CALL modified(const css::lang::EventObject& aEvent) override; + + // css::util::XModifyBroadcaster + virtual void SAL_CALL addModifyListener(const css::uno::Reference< css::util::XModifyListener > & aListener) override; + virtual void SAL_CALL removeModifyListener(const css::uno::Reference< css::util::XModifyListener > & aListener) override; + + // css::lang::XComponent + virtual void SAL_CALL disposing() override; + + // css::form::XLoadListener + virtual void SAL_CALL unloading(const css::lang::EventObject& aEvent) override; + + // css::lang::XEventListener + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + private: + virtual ~SbaExternalSourceBrowser() override; + + virtual css::uno::Reference< css::sdbc::XRowSet > CreateForm() override; + virtual bool InitializeForm( const css::uno::Reference< css::beans::XPropertySet >& i_formProperties ) override; + + virtual bool LoadForm() override; + + void Attach(const css::uno::Reference< css::sdbc::XRowSet > & xMaster); + + void ClearView(); + + void startListening(); + void stopListening(); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/formadapter.hxx b/dbaccess/source/ui/inc/formadapter.hxx new file mode 100644 index 000000000..c6d565896 --- /dev/null +++ b/dbaccess/source/ui/inc/formadapter.hxx @@ -0,0 +1,436 @@ +/* -*- 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 "sbamultiplex.hxx" + +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRowSet.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdb/XSQLErrorBroadcaster.hpp> +#include <com/sun/star/sdb/XRowSetApproveBroadcaster.hpp> +#include <com/sun/star/form/XLoadable.hpp> +#include <com/sun/star/sdb/XResultSetAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/form/XReset.hpp> +#include <com/sun/star/form/XSubmit.hpp> +#include <com/sun/star/form/XDatabaseParameterBroadcaster.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/awt/XTabControllerModel.hpp> +#include <com/sun/star/io/XPersistObject.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <comphelper/interfacecontainer3.hxx> +#include <comphelper/uno3.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/implbase12.hxx> +#include <cppuhelper/implbase10.hxx> + +namespace dbaui +{ + // SbaXFormAdapter + + typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaDataSupplier + , css::sdb::XResultSetAccess + , css::sdbc::XResultSetUpdate + , css::sdbc::XRowSet + , css::sdb::XRowSetApproveBroadcaster + , css::sdbcx::XRowLocate + , css::sdbc::XRowUpdate + , css::sdbc::XRow + , css::sdbcx::XColumnsSupplier + , css::sdbc::XColumnLocate + // --- stardiv::one::form::component::DatabaseForm --- + , css::sdbc::XParameters + , css::sdbcx::XDeleteRows + > SbaXFormAdapter_BASE1; + typedef ::cppu::ImplHelper12 < css::sdbc::XWarningsSupplier + , css::sdbc::XCloseable + , css::form::XLoadable + , css::sdb::XSQLErrorBroadcaster + , css::form::XDatabaseParameterBroadcaster + // --- stardiv::one::form::component::Form --- + , css::form::XForm + , css::form::XSubmit + , css::awt::XTabControllerModel + // --- stardiv::one::form::FormComponent --- + , css::lang::XComponent + , css::beans::XFastPropertySet + // already present : css::form::XFormComponent (base of css::form::XForm) + , css::beans::XMultiPropertySet + , css::container::XNamed + > SbaXFormAdapter_BASE2; + typedef ::cppu::ImplHelper10 < css::io::XPersistObject + , css::beans::XPropertySet + // --- stardiv::one::data::DatabaseCursor --- + , css::util::XCancellable + // already present : css::beans::XPropertySet + // --- stardiv::one::data::DatabaseComponent --- + // already present : css::lang::XComponent + // already present : css::container::XChild (base of css::form::XForm) + // interfaces I don't know the service which they belong to ;) + // (they are supported by FmXDatabaseForm, se we support it, too) + , css::beans::XPropertyState + , css::form::XReset + , css::container::XNameContainer + , css::container::XIndexContainer + , css::container::XContainer + , css::container::XEnumerationAccess + // interfaces we need because of other reasons + , css::beans::XPropertyChangeListener + > SbaXFormAdapter_BASE3; + + class SbaXFormAdapter final + :public SbaXFormAdapter_BASE1 + ,public SbaXFormAdapter_BASE2 + ,public SbaXFormAdapter_BASE3 + { + private: + css::uno::Reference< css::sdbc::XRowSet > m_xMainForm; + ::osl::Mutex m_aMutex; + + SbaXLoadMultiplexer m_aLoadListeners; + SbaXRowSetMultiplexer m_aRowSetListeners; + SbaXRowSetApproveMultiplexer m_aRowSetApproveListeners; + SbaXSQLErrorMultiplexer m_aErrorListeners; + SbaXParameterMultiplexer m_aParameterListeners; + SbaXSubmitMultiplexer m_aSubmitListeners; + SbaXResetMultiplexer m_aResetListeners; + + SbaXPropertyChangeMultiplexer m_aPropertyChangeListeners; + SbaXVetoableChangeMultiplexer m_aVetoablePropertyChangeListeners; + SbaXPropertiesChangeMultiplexer m_aPropertiesChangeListeners; + + ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> m_aDisposeListeners; + ::comphelper::OInterfaceContainerHelper3<css::container::XContainerListener> m_aContainerListeners; + + // hierarchy administration + css::uno::Reference< css::uno::XInterface > m_xParent; + std::vector< css::uno::Reference< css::form::XFormComponent > > m_aChildren; + std::vector< OUString > m_aChildNames; + + // properties + OUString m_sName; + sal_Int32 m_nNamePropHandle; + + public: + const css::uno::Reference< css::sdbc::XRowSet >& getAttachedForm() const { return m_xMainForm; } + + public: + SbaXFormAdapter(); + virtual ~SbaXFormAdapter() override; + + // css::uno::Reference< css::reflection::XIdlClass > getIdlClass(); + // css::uno::Sequence<css::uno::Reference< css::reflection::XIdlClass > > getIdlClasses(); + + void AttachForm(const css::uno::Reference< css::sdbc::XRowSet >& xNewMaster); + + // UNO + DECLARE_UNO3_DEFAULTS(SbaXFormAdapter, SbaXFormAdapter_BASE1) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override; + + // css::sdbc::XCloseable + virtual void SAL_CALL close() override; + + // css::sdbc::XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData() override; + + // css::sdbc::XColumnLocate + virtual sal_Int32 SAL_CALL findColumn(const OUString& columnName) override; + + // css::sdbcx::XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns() override; + + // css::sdbc::XRow + virtual sal_Bool SAL_CALL wasNull() override; + virtual OUString SAL_CALL getString(sal_Int32 columnIndex) override; + virtual sal_Bool SAL_CALL getBoolean(sal_Int32 columnIndex) override; + virtual sal_Int8 SAL_CALL getByte(sal_Int32 columnIndex) override; + virtual sal_Int16 SAL_CALL getShort(sal_Int32 columnIndex) override; + virtual sal_Int32 SAL_CALL getInt(sal_Int32 columnIndex) override; + virtual sal_Int64 SAL_CALL getLong(sal_Int32 columnIndex) override; + virtual float SAL_CALL getFloat(sal_Int32 columnIndex) override; + virtual double SAL_CALL getDouble(sal_Int32 columnIndex) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes(sal_Int32 columnIndex) override; + virtual css::util::Date SAL_CALL getDate(sal_Int32 columnIndex) override; + virtual css::util::Time SAL_CALL getTime(sal_Int32 columnIndex) override; + virtual css::util::DateTime SAL_CALL getTimestamp(sal_Int32 columnIndex) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream(sal_Int32 columnIndex) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream(sal_Int32 columnIndex) override; + virtual css::uno::Any SAL_CALL getObject(sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef(sal_Int32 columnIndex) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob(sal_Int32 columnIndex) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob(sal_Int32 columnIndex) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray(sal_Int32 columnIndex) override; + + // css::sdbcx::XRowLocate + virtual css::uno::Any SAL_CALL getBookmark() override; + virtual sal_Bool SAL_CALL moveToBookmark(const css::uno::Any& bookmark) override; + virtual sal_Bool SAL_CALL moveRelativeToBookmark(const css::uno::Any& bookmark, sal_Int32 rows) override; + virtual sal_Int32 SAL_CALL compareBookmarks(const css::uno::Any& first, const css::uno::Any& second) override; + virtual sal_Bool SAL_CALL hasOrderedBookmarks() override; + virtual sal_Int32 SAL_CALL hashBookmark(const css::uno::Any& bookmark) override; + + // css::sdbc::XRowUpdate + virtual void SAL_CALL updateNull(sal_Int32 columnIndex) override; + virtual void SAL_CALL updateBoolean(sal_Int32 columnIndex, sal_Bool x) override; + virtual void SAL_CALL updateByte(sal_Int32 columnIndex, sal_Int8 x) override; + virtual void SAL_CALL updateShort(sal_Int32 columnIndex, sal_Int16 x) override; + virtual void SAL_CALL updateInt(sal_Int32 columnIndex, sal_Int32 x) override; + virtual void SAL_CALL updateLong(sal_Int32 columnIndex, sal_Int64 x) override; + virtual void SAL_CALL updateFloat(sal_Int32 columnIndex, float x) override; + virtual void SAL_CALL updateDouble(sal_Int32 columnIndex, double x) override; + virtual void SAL_CALL updateString(sal_Int32 columnIndex, const OUString& x) override; + virtual void SAL_CALL updateBytes(sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x) override; + virtual void SAL_CALL updateDate(sal_Int32 columnIndex, const css::util::Date& x) override; + virtual void SAL_CALL updateTime(sal_Int32 columnIndex, const css::util::Time& x) override; + virtual void SAL_CALL updateTimestamp(sal_Int32 columnIndex, const css::util::DateTime& x) override; + virtual void SAL_CALL updateBinaryStream(sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length) override; + virtual void SAL_CALL updateCharacterStream(sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length) override; + virtual void SAL_CALL updateObject(sal_Int32 columnIndex, const css::uno::Any& x) override; + virtual void SAL_CALL updateNumericObject(sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale) override; + + // css::sdbc::XResultSet + virtual sal_Bool SAL_CALL next() override; + virtual sal_Bool SAL_CALL isBeforeFirst() override; + virtual sal_Bool SAL_CALL isAfterLast() override; + virtual sal_Bool SAL_CALL isFirst() override; + virtual sal_Bool SAL_CALL isLast() override; + virtual void SAL_CALL beforeFirst() override; + virtual void SAL_CALL afterLast() override; + virtual sal_Bool SAL_CALL first() override; + virtual sal_Bool SAL_CALL last() override; + virtual sal_Int32 SAL_CALL getRow() override; + virtual sal_Bool SAL_CALL absolute(sal_Int32 row) override; + virtual sal_Bool SAL_CALL relative(sal_Int32 rows) override; + virtual sal_Bool SAL_CALL previous() override; + virtual void SAL_CALL refreshRow() override; + virtual sal_Bool SAL_CALL rowUpdated() override; + virtual sal_Bool SAL_CALL rowInserted() override; + virtual sal_Bool SAL_CALL rowDeleted() override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement() override; + + // css::sdbc::XResultSetUpdate + virtual void SAL_CALL insertRow() override; + virtual void SAL_CALL updateRow() override; + virtual void SAL_CALL deleteRow() override; + virtual void SAL_CALL cancelRowUpdates() override; + virtual void SAL_CALL moveToInsertRow() override; + virtual void SAL_CALL moveToCurrentRow() override; + + // css::sdbc::XRowSet + virtual void SAL_CALL execute() override; + virtual void SAL_CALL addRowSetListener(const css::uno::Reference< css::sdbc::XRowSetListener >& listener) override; + virtual void SAL_CALL removeRowSetListener(const css::uno::Reference< css::sdbc::XRowSetListener >& listener) override; + + // css::sdbcx::XDeleteRows + virtual css::uno::Sequence<sal_Int32> SAL_CALL deleteRows(const css::uno::Sequence< css::uno::Any >& rows) override; + + // css::sdbc::XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings() override; + virtual void SAL_CALL clearWarnings() override; + + // css::sdb::XRowSetApproveBroadcaster + virtual void SAL_CALL addRowSetApproveListener(const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener) override; + virtual void SAL_CALL removeRowSetApproveListener(const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener) override; + + // css::sdbc::XSQLErrorBroadcaster + virtual void SAL_CALL addSQLErrorListener(const css::uno::Reference< css::sdb::XSQLErrorListener >& _rListener) override; + virtual void SAL_CALL removeSQLErrorListener(const css::uno::Reference< css::sdb::XSQLErrorListener >& _rListener) override; + + // css::sdb::XResultSetAccess + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL createResultSet() override; + + // css::form::XLoadable + virtual void SAL_CALL load() override; + virtual void SAL_CALL unload() override; + virtual void SAL_CALL reload() override; + virtual sal_Bool SAL_CALL isLoaded() override; + virtual void SAL_CALL addLoadListener(const css::uno::Reference< css::form::XLoadListener >& aListener) override; + virtual void SAL_CALL removeLoadListener(const css::uno::Reference< css::form::XLoadListener >& aListener) override; + + // css::sdbc::XParameters + virtual void SAL_CALL setNull(sal_Int32 parameterIndex, sal_Int32 sqlType) override; + virtual void SAL_CALL setObjectNull(sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName) override; + virtual void SAL_CALL setBoolean(sal_Int32 parameterIndex, sal_Bool x) override; + virtual void SAL_CALL setByte(sal_Int32 parameterIndex, sal_Int8 x) override; + virtual void SAL_CALL setShort(sal_Int32 parameterIndex, sal_Int16 x) override; + virtual void SAL_CALL setInt(sal_Int32 parameterIndex, sal_Int32 x) override; + virtual void SAL_CALL setLong(sal_Int32 parameterIndex, sal_Int64 x) override; + virtual void SAL_CALL setFloat(sal_Int32 parameterIndex, float x) override; + virtual void SAL_CALL setDouble(sal_Int32 parameterIndex, double x) override; + virtual void SAL_CALL setString(sal_Int32 parameterIndex, const OUString& x) override; + virtual void SAL_CALL setBytes(sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x) override; + virtual void SAL_CALL setDate(sal_Int32 parameterIndex, const css::util::Date& x) override; + virtual void SAL_CALL setTime(sal_Int32 parameterIndex, const css::util::Time& x) override; + virtual void SAL_CALL setTimestamp(sal_Int32 parameterIndex, const css::util::DateTime& x) override; + virtual void SAL_CALL setBinaryStream(sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length) override; + virtual void SAL_CALL setCharacterStream(sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length) override; + virtual void SAL_CALL setObject(sal_Int32 parameterIndex, const css::uno::Any& x) override; + virtual void SAL_CALL setObjectWithInfo(sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale) override; + virtual void SAL_CALL setRef(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x) override; + virtual void SAL_CALL setBlob(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x) override; + virtual void SAL_CALL setClob(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x) override; + virtual void SAL_CALL setArray(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x) override; + virtual void SAL_CALL clearParameters() override; + + // css::form::XDatabaseParameterBroadcaster + virtual void SAL_CALL addParameterListener(const css::uno::Reference< css::form::XDatabaseParameterListener >& aListener) override; + virtual void SAL_CALL removeParameterListener(const css::uno::Reference< css::form::XDatabaseParameterListener >& aListener) override; + + // css::container::XChild + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent() override; + virtual void SAL_CALL setParent(const css::uno::Reference< css::uno::XInterface >& Parent) override; + + // css::form::XSubmit + virtual void SAL_CALL submit(const css::uno::Reference< css::awt::XControl >& aControl, const css::awt::MouseEvent& aMouseEvt) override; + virtual void SAL_CALL addSubmitListener(const css::uno::Reference< css::form::XSubmitListener >& aListener) override; + virtual void SAL_CALL removeSubmitListener(const css::uno::Reference< css::form::XSubmitListener >& aListener) override; + + // css::awt::XTabControllerModel + virtual sal_Bool SAL_CALL getGroupControl() override; + virtual void SAL_CALL setGroupControl(sal_Bool GroupControl) override; + virtual void SAL_CALL setControlModels(const css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& Controls) override; + virtual css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > SAL_CALL getControlModels() override; + virtual void SAL_CALL setGroup(const css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& _rGroup, const OUString& GroupName) override; + virtual sal_Int32 SAL_CALL getGroupCount() override; + virtual void SAL_CALL getGroup(sal_Int32 nGroup, css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& _rGroup, OUString& Name) override; + virtual void SAL_CALL getGroupByName(const OUString& Name, css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& _rGroup) override; + + // css::lang::XComponent + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener(const css::uno::Reference< css::lang::XEventListener >& xListener) override; + virtual void SAL_CALL removeEventListener(const css::uno::Reference< css::lang::XEventListener >& aListener) override; + + // css::beans::XFastPropertySet + virtual void SAL_CALL setFastPropertyValue(sal_Int32 nHandle, const css::uno::Any& aValue) override; + virtual css::uno::Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle) override; + + // css::container::XNamed + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setName(const OUString& aName) override; + + // css::io::XPersistObject + virtual OUString SAL_CALL getServiceName() override; + virtual void SAL_CALL write(const css::uno::Reference< css::io::XObjectOutputStream >& _rxOutStream) override; + virtual void SAL_CALL read(const css::uno::Reference< css::io::XObjectInputStream >& _rxInStream) override; + + // css::beans::XMultiPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + virtual void SAL_CALL setPropertyValues(const css::uno::Sequence< OUString >& PropertyNames, const css::uno::Sequence< css::uno::Any >& Values) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues(const css::uno::Sequence< OUString >& aPropertyNames) override; + virtual void SAL_CALL addPropertiesChangeListener(const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener) override; + virtual void SAL_CALL removePropertiesChangeListener(const css::uno::Reference< css::beans::XPropertiesChangeListener >& Listener) override; + virtual void SAL_CALL firePropertiesChangeEvent(const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener) override; + + // css::beans::XPropertySet + virtual void SAL_CALL setPropertyValue(const OUString& aPropertyName, const css::uno::Any& aValue) override; + virtual css::uno::Any SAL_CALL getPropertyValue(const OUString& PropertyName) override; + virtual void SAL_CALL addPropertyChangeListener(const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener) override; + virtual void SAL_CALL removePropertyChangeListener(const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener) override; + virtual void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener) override; + virtual void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener) override; + + // css::util::XCancellable + virtual void SAL_CALL cancel() override; + + // css::beans::XPropertyState + virtual css::beans::PropertyState SAL_CALL getPropertyState(const OUString& PropertyName) override; + virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL getPropertyStates(const css::uno::Sequence< OUString >& aPropertyName) override; + virtual void SAL_CALL setPropertyToDefault(const OUString& PropertyName) override; + virtual css::uno::Any SAL_CALL getPropertyDefault(const OUString& aPropertyName) override; + + // css::form::XReset + virtual void SAL_CALL reset() override; + virtual void SAL_CALL addResetListener(const css::uno::Reference< css::form::XResetListener >& aListener) override; + virtual void SAL_CALL removeResetListener(const css::uno::Reference< css::form::XResetListener >& aListener) override; + + // css::container::XNameContainer + virtual void SAL_CALL insertByName(const OUString& aName, const css::uno::Any& aElement) override; + virtual void SAL_CALL removeByName(const OUString& Name) override; + + // css::container::XNameReplace + virtual void SAL_CALL replaceByName(const OUString& aName, const css::uno::Any& aElement) override; + + // css::container::XNameAccess + virtual css::uno::Any SAL_CALL getByName(const OUString& aName) override; + virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override; + virtual sal_Bool SAL_CALL hasByName(const OUString& aName) override; + + // css::container::XElementAccess + virtual css::uno::Type SAL_CALL getElementType() override ; + virtual sal_Bool SAL_CALL hasElements() override; + + // css::container::XIndexContainer + virtual void SAL_CALL insertByIndex(sal_Int32 _rIndex, const css::uno::Any& Element) override; + virtual void SAL_CALL removeByIndex(sal_Int32 _rIndex) override; + + // css::container::XIndexReplace + virtual void SAL_CALL replaceByIndex(sal_Int32 _rIndex, const css::uno::Any& Element) override; + + // css::container::XIndexAccess + virtual sal_Int32 SAL_CALL getCount() override; + virtual css::uno::Any SAL_CALL getByIndex(sal_Int32 _rIndex) override; + + // css::container::XContainer + virtual void SAL_CALL addContainerListener(const css::uno::Reference< css::container::XContainerListener >& xListener) override; + virtual void SAL_CALL removeContainerListener(const css::uno::Reference< css::container::XContainerListener >& xListener) override; + + // css::container::XEnumerationAccess + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override; + + // css::lang::XEventListener + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + + // css::beans::XPropertyChangeListener + virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& evt) override; + + private: + // container handling + /// @throws css::lang::IllegalArgumentException + void implInsert(const css::uno::Any& aElement, sal_Int32 nIndex, const OUString* pNewElName = nullptr); + sal_Int32 implGetPos(const OUString& rName); + + void StopListening(); + void StartListening(); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/imageprovider.hxx b/dbaccess/source/ui/inc/imageprovider.hxx new file mode 100644 index 000000000..a8d24f428 --- /dev/null +++ b/dbaccess/source/ui/inc/imageprovider.hxx @@ -0,0 +1,105 @@ +/* -*- 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/graphic/XGraphic.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> + +#include <memory> + +namespace dbaui +{ + // ImageProvider + struct ImageProvider_Data; + /** provides images for database objects such as tables, queries, forms, reports ... + + At the moment, this class cares for small icons only, that is, icons which can be used + in a tree control. On the medium term, we should extend it with support for different-sized + icons. + */ + class ImageProvider + { + private: + std::shared_ptr< ImageProvider_Data > m_pData; + + public: + /** creates a semi-functional ImageProvider instance + + The resulting instance is not able to provide any concrete object images, + but only default images. + */ + ImageProvider(); + + /** creates an ImageProvider instance + + @param _rxConnection + denotes the connection to work for. Must not be <NULL/>. + */ + ImageProvider( + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection + ); + + /** returns the image to be used for a database object with the given name + + @param _nDatabaseObjectType + the type of the object. Must be one of the css.sdb.application.DatabaseObject + constants. + @param _rName + the name of the object + @return + the name of the image to be used for the object. + */ + OUString getImageId( + const OUString& _rName, + const sal_Int32 _nDatabaseObjectType + ); + + // check whether the connection can give us an icon + css::uno::Reference<css::graphic::XGraphic> getXGraphic(const OUString& _rName, + const sal_Int32 _nDatabaseObjectType); + + /** returns the resource ID for the default image to be used for a database object + + In opposite to getImageId, this method does not check the concrete object + for its image, but returns a default image to be used for all objects of the given + type. + + @param _nDatabaseObjectType + the type of the object. Must be one of the css.sdb.application.DatabaseObject + constants. + @return + the resource image name to be used for the object type. + */ + static OUString getDefaultImageResourceID(sal_Int32 _nDatabaseObjectType); + + static OUString getFolderImageId( + sal_Int32 _nDatabaseObjectType + ); + + /** retrieves the image to be used for a database as a whole. + @return + the image to be used for folders of this type + */ + static OUString getDatabaseImage(); + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/indexcollection.hxx b/dbaccess/source/ui/inc/indexcollection.hxx new file mode 100644 index 000000000..d677eed06 --- /dev/null +++ b/dbaccess/source/ui/inc/indexcollection.hxx @@ -0,0 +1,94 @@ +/* -*- 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> +#include <com/sun/star/beans/XPropertySet.hpp> +#include "indexes.hxx" + +namespace dbaui +{ + + // OIndexCollection + class OIndexCollection + { + protected: + css::uno::Reference< css::container::XNameAccess > + m_xIndexes; + + // cached information + Indexes m_aIndexes; + + public: + // construction + OIndexCollection(); + OIndexCollection(const OIndexCollection& _rSource); + // OIndexCollection(const css::uno::Reference< css::container::XNameAccess >& _rxIndexes); + + OIndexCollection& operator=(const OIndexCollection& _rSource); + + // iterating through the collection + typedef OIndex* iterator; + typedef OIndex const* const_iterator; + + /// get access to the first element of the index collection + Indexes::const_iterator begin() const { return m_aIndexes.begin(); } + /// get access to the first element of the index collection + Indexes::iterator begin() { return m_aIndexes.begin(); } + /// get access to the (last + 1st) element of the index collection + Indexes::const_iterator end() const { return m_aIndexes.end(); } + /// get access to the (last + 1st) element of the index collection + Indexes::iterator end() { return m_aIndexes.end(); } + + // searching + Indexes::const_iterator find(const OUString& _rName) const; + Indexes::iterator find(const OUString& _rName); + Indexes::const_iterator findOriginal(const OUString& _rName) const; + Indexes::iterator findOriginal(const OUString& _rName); + + // inserting without committing + // the OriginalName of the newly inserted index will be empty, thus indicating that it's new + Indexes::iterator insert(const OUString& _rName); + // commit a new index, which is already part if the collection, but does not have an equivalent in the + // data source, yet + void commitNewIndex(const Indexes::iterator& _rPos); + + // reset the data for the given index + void resetIndex(const Indexes::iterator& _rPos); + + // attach to a new key container + void attach(const css::uno::Reference< css::container::XNameAccess >& _rxIndexes); + // detach from the container + void detach(); + + /// drop an index, and remove it from the collection + bool drop(const Indexes::iterator& _rPos); + /// simply drop the index described by the name, but don't remove the descriptor from the collection + bool dropNoRemove(const Indexes::iterator& _rPos); + + protected: + void implConstructFrom(const css::uno::Reference< css::container::XNameAccess >& _rxIndexes); + static void implFillIndexInfo(OIndex& _rIndex, const css::uno::Reference< css::beans::XPropertySet >& _rxDescriptor); + void implFillIndexInfo(OIndex& _rIndex); + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/indexdialog.hxx b/dbaccess/source/ui/inc/indexdialog.hxx new file mode 100644 index 000000000..f03b04f6f --- /dev/null +++ b/dbaccess/source/ui/inc/indexdialog.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 <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <vcl/weld.hxx> +#include "indexes.hxx" + +namespace dbaui +{ + // DbaIndexDialog + class IndexFieldsControl; + class OIndexCollection; + class DbaIndexDialog final : public weld::GenericDialogController + { + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + + std::unique_ptr<OIndexCollection> m_xIndexes; + std::unique_ptr<weld::TreeIter> m_xPreviousSelection; + bool m_bEditingActive; + bool m_bEditAgain; + bool m_bNoHandlerCall; + + css::uno::Reference< css::uno::XComponentContext > + m_xContext; + + std::unique_ptr<weld::Toolbar> m_xActions; + std::unique_ptr<weld::TreeView> m_xIndexList; + std::unique_ptr<weld::Label> m_xIndexDetails; + std::unique_ptr<weld::Label> m_xDescriptionLabel; + std::unique_ptr<weld::Label> m_xDescription; + std::unique_ptr<weld::CheckButton> m_xUnique; + std::unique_ptr<weld::Label> m_xFieldsLabel; + std::unique_ptr<weld::Button> m_xClose; + std::unique_ptr<weld::Container> m_xTable; + css::uno::Reference<css::awt::XWindow> m_xTableCtrlParent; + VclPtr<IndexFieldsControl> m_xFields; + + public: + DbaIndexDialog( + weld::Window* _pParent, + const css::uno::Sequence< OUString >& _rFieldNames, + const css::uno::Reference< css::container::XNameAccess >& _rxIndexes, + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + virtual ~DbaIndexDialog() override; + + typedef std::pair<const weld::TreeIter&, OUString> IterString; + private: + void fillIndexList(); + void updateToolbox(); + void updateControls(const weld::TreeIter* pEntry); + + void IndexSelected(); + + DECL_LINK( OnIndexSelected, weld::TreeView&, void ); + DECL_LINK( OnIndexAction, const OString&, void ); + DECL_LINK( OnEntryEditing, const weld::TreeIter&, bool ); + DECL_LINK( OnEntryEdited, const IterString&, bool ); + DECL_LINK( OnModifiedClick, weld::Toggleable&, void ); + DECL_LINK( OnModified, IndexFieldsControl&, void ); + DECL_LINK( OnCloseDialog, weld::Button&, void ); + + DECL_LINK( OnEditIndexAgain, void*, void ); + + void OnNewIndex(); + void OnDropIndex(bool _bConfirm = true); + void OnRenameIndex(); + void OnSaveIndex(); + void OnResetIndex(); + + bool implCommit(const weld::TreeIter* pEntry); + bool implSaveModified(bool _bPlausibility = true); + bool implCommitPreviouslySelected(); + + bool implDropIndex(const weld::TreeIter* pEntry, bool _bRemoveFromCollection); + + bool implCheckPlausibility(const Indexes::const_iterator& _rPos); + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/indexes.hxx b/dbaccess/source/ui/inc/indexes.hxx new file mode 100644 index 000000000..75bd5b44b --- /dev/null +++ b/dbaccess/source/ui/inc/indexes.hxx @@ -0,0 +1,81 @@ +/* -*- 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 <vector> + +namespace dbaui +{ + // OIndexField + struct OIndexField + { + OUString sFieldName; + bool bSortAscending; + + OIndexField() : bSortAscending(true) { } + }; + + typedef std::vector<OIndexField> IndexFields; + + // OIndex + struct GrantIndexAccess + { + friend class OIndexCollection; + private: + GrantIndexAccess() { } + }; + + struct OIndex final + { + OUString sOriginalName; + bool bModified; + + public: + OUString sName; + OUString sDescription; + bool bPrimaryKey; + bool bUnique; + IndexFields aFields; + + OIndex(const OUString& _rOriginalName) + : sOriginalName(_rOriginalName), bModified(false), sName(_rOriginalName), bPrimaryKey(false), bUnique(false) + { + } + + const OUString& getOriginalName() const { return sOriginalName; } + + bool isModified() const { return bModified; } + void setModified(bool _bModified) { bModified = _bModified; } + void clearModified() { setModified(false); } + + bool isNew() const { return getOriginalName().isEmpty(); } + void flagAsNew(const GrantIndexAccess&) { sOriginalName.clear(); } + void flagAsCommitted(const GrantIndexAccess&) { sOriginalName = sName; } + }; + + typedef std::vector<OIndex> Indexes; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/indexfieldscontrol.hxx b/dbaccess/source/ui/inc/indexfieldscontrol.hxx new file mode 100644 index 000000000..90ae7172e --- /dev/null +++ b/dbaccess/source/ui/inc/indexfieldscontrol.hxx @@ -0,0 +1,91 @@ +/* -*- 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/editbrowsebox.hxx> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include "indexes.hxx" + +namespace dbaui +{ + + class DbaMouseDownListBoxController; + + // IndexFieldsControl + class IndexFieldsControl final : public ::svt::EditBrowseBox + { + IndexFields m_aSavedValue; + + IndexFields m_aFields; // !! order matters !! + IndexFields::const_iterator m_aSeekRow; // !! + + Link<IndexFieldsControl&,void> m_aModifyHdl; + + VclPtr< ::svt::ListBoxControl> m_pSortingCell; + VclPtr< ::svt::ListBoxControl> m_pFieldNameCell; + + OUString m_sAscendingText; + OUString m_sDescendingText; + + bool m_bAddIndexAppendix; + + public: + IndexFieldsControl(const css::uno::Reference<css::awt::XWindow> &rParent); + virtual ~IndexFieldsControl() override; + virtual void dispose() override; + + void Init(const css::uno::Sequence< OUString >& _rAvailableFields, bool _bAddIndexAppendix); + + void initializeFrom(IndexFields&& _rFields); + void commitTo(IndexFields& _rFields); + + bool SaveModified() override; + using EditBrowseBox::IsModified; + + const IndexFields& GetSavedValue() const { return m_aSavedValue; } + void SaveValue() { m_aSavedValue = m_aFields; } + + void SetModifyHdl(const Link<IndexFieldsControl&,void>& _rHdl) { m_aModifyHdl = _rHdl; } + virtual OUString GetCellText(sal_Int32 _nRow,sal_uInt16 nColId) const override; + + private: + // EditBrowseBox overridables + virtual void PaintCell( OutputDevice& _rDev, const tools::Rectangle& _rRect, sal_uInt16 _nColumnId ) const override; + virtual bool SeekRow(sal_Int32 nRow) override; + virtual sal_uInt32 GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId) override; + virtual bool IsTabAllowed(bool bForward) const override; + + ::svt::CellController* GetController(sal_Int32 _nRow, sal_uInt16 _nColumnId) override; + void InitController(::svt::CellControllerRef&, sal_Int32 _nRow, sal_uInt16 _nColumnId) override; + + OUString GetRowCellText(const IndexFields::const_iterator& _rRow,sal_uInt16 nColId) const; + bool implGetFieldDesc(sal_Int32 _nRow, IndexFields::const_iterator& _rPos); + + bool isNewField() const { return GetCurRow() >= static_cast<sal_Int32>(m_aFields.size()); } + + DECL_LINK( OnListEntrySelected, DbaMouseDownListBoxController&, void ); + + using ::svt::EditBrowseBox::Init; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/linkeddocuments.hxx b/dbaccess/source/ui/inc/linkeddocuments.hxx new file mode 100644 index 000000000..961b2ea4c --- /dev/null +++ b/dbaccess/source/ui/inc/linkeddocuments.hxx @@ -0,0 +1,108 @@ +/* -*- 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 "AppElementType.hxx" + +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp> +#include <comphelper/namedvaluecollection.hxx> + +namespace weld { class Window; } +namespace dbaui +{ + + // OLinkedDocumentsAccess + class OLinkedDocumentsAccess final + { + css::uno::Reference< css::uno::XComponentContext > + m_xContext; + css::uno::Reference< css::container::XNameAccess > + m_xDocumentContainer; + css::uno::Reference< css::sdbc::XConnection> + m_xConnection; + css::uno::Reference< css::sdb::application::XDatabaseDocumentUI > + m_xDocumentUI; + weld::Window* m_pDialogParent; + OUString m_sDataSourceName; + + public: + OLinkedDocumentsAccess( + weld::Window* pDialogParent, + const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& i_rDocumentUI, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const css::uno::Reference< css::container::XNameAccess >& _rxContainer, + const css::uno::Reference< css::sdbc::XConnection>& _xConnection, + const OUString& _sDataSourceName + ); + ~OLinkedDocumentsAccess(); + + bool isConnected() const { return m_xConnection.is(); } + + css::uno::Reference< css::lang::XComponent> + open( + const OUString& _rLinkName, + css::uno::Reference< css::lang::XComponent>& _xDefinition, + ElementOpenMode _eOpenMode, + const ::comphelper::NamedValueCollection& _rAdditionalArgs + ); + + css::uno::Reference< css::lang::XComponent > + newDocument( + sal_Int32 i_nActionID, + const ::comphelper::NamedValueCollection& i_rCreationArgs, + css::uno::Reference< css::lang::XComponent >& o_rDefinition + ); + + void newFormWithPilot( + const sal_Int32 _nCommandType, + const OUString& _rObjectName + ); + void newReportWithPilot( + const sal_Int32 _nCommandType, + const OUString& _rObjectName + ); + void newQueryWithPilot(); + void newTableWithPilot(); + + private: + css::uno::Reference< css::lang::XComponent > + impl_open( + const OUString& _rLinkName, + css::uno::Reference< css::lang::XComponent >& _xDefinition, + ElementOpenMode _eOpenMode, + const ::comphelper::NamedValueCollection& _rAdditionalArgs + ); + + void + impl_newWithPilot( + const char* _pWizardService, + const sal_Int32 _nCommandType, + const OUString& _rObjectName + ); + + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/objectnamecheck.hxx b/dbaccess/source/ui/inc/objectnamecheck.hxx new file mode 100644 index 000000000..52f639e53 --- /dev/null +++ b/dbaccess/source/ui/inc/objectnamecheck.hxx @@ -0,0 +1,57 @@ +/* -*- 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 <rtl/ustring.hxx> + +namespace dbtools { class SQLExceptionInfo; } + +namespace dbaui +{ + + // IObjectNameCheck + /** interface encapsulating the check for the validity of an object name + */ + class IObjectNameCheck + { + public: + /** determines whether a given object name is valid + + @param _rObjectName + the name to check + @param _out_rErrorToDisplay + output parameter taking an error message describing why the name is not + valid, if applicable. + + @return + <TRUE/> if and only if the given name is valid. + */ + virtual bool isNameValid( + const OUString& _rObjectName, + ::dbtools::SQLExceptionInfo& _out_rErrorToDisplay + ) const = 0; + + public: + virtual ~IObjectNameCheck() { } + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/opendoccontrols.hxx b/dbaccess/source/ui/inc/opendoccontrols.hxx new file mode 100644 index 000000000..8448a047d --- /dev/null +++ b/dbaccess/source/ui/inc/opendoccontrols.hxx @@ -0,0 +1,78 @@ +/* -*- 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 <vcl/weld.hxx> +#include <rtl/ustring.hxx> + +namespace dbaui +{ + + // OpenDocumentButton + /** a button which can be used to open a document + + The text of the button is the same as for the "Open" command in the application + UI. Additionally, the icon for this command is also displayed on the button. + */ + class OpenDocumentButton + { + private: + OUString m_sModule; + + std::unique_ptr<weld::Button> m_xControl; + public: + OpenDocumentButton(std::unique_ptr<weld::Button> xControl, const char* _pAsciiModuleName); + + void set_sensitive(bool bSensitive) { m_xControl->set_sensitive(bSensitive); } + void connect_clicked(const Link<weld::Button&, void>& rLink) { m_xControl->connect_clicked(rLink); } + + private: + void impl_init( const char* _pAsciiModuleName ); + }; + + // OpenDocumentListBox + class OpenDocumentListBox + { + private: + typedef std::pair< OUString, OUString > StringPair; + + std::vector<StringPair> m_aURLs; + + std::unique_ptr<weld::ComboBox> m_xControl; + + public: + OpenDocumentListBox(std::unique_ptr<weld::ComboBox> xControl, const char* _pAsciiModuleName); + + OUString GetSelectedDocumentURL() const; + + void set_sensitive(bool bSensitive) { m_xControl->set_sensitive(bSensitive); } + int get_count() const { return m_xControl->get_count(); } + void set_active(int nPos) { m_xControl->set_active(nPos); } + void connect_changed(const Link<weld::ComboBox&, void>& rLink) { m_xControl->connect_changed(rLink); } + + private: + const StringPair & impl_getDocumentAtIndex( sal_uInt16 _nListIndex ) const; + + void impl_init( const char* _pAsciiModuleName ); + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/paramdialog.hxx b/dbaccess/source/ui/inc/paramdialog.hxx new file mode 100644 index 000000000..489a621e6 --- /dev/null +++ b/dbaccess/source/ui/inc/paramdialog.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 <vcl/weld.hxx> +#include <vcl/timer.hxx> + +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <connectivity/predicateinput.hxx> +#include <svx/ParseContext.hxx> +#include <o3tl/typed_flags_set.hxx> + +namespace connectivity +{ + class OSQLParseNode; +} + +enum class VisitFlags { + NONE = 0x00, + Visited = 0x01, + Dirty = 0x02, +}; +namespace o3tl { + template<> struct typed_flags<VisitFlags> : is_typed_flags<VisitFlags, 0x03> {}; +} + +namespace dbaui +{ + // OParameterDialog + class OParameterDialog final + : public weld::GenericDialogController + , public ::svxform::OParseContextClient + { + sal_Int32 m_nCurrentlySelected; + + css::uno::Reference< css::container::XIndexAccess > + m_xParams; + css::uno::Reference< css::sdbc::XConnection > + m_xConnection; + css::uno::Reference< css::util::XNumberFormatter > + m_xFormatter; + ::dbtools::OPredicateInputController + m_aPredicateInput; + + std::vector<VisitFlags> m_aVisitedParams; + Timer m_aResetVisitFlag; + // we reset the "visited flag" 1 second after and entry has been selected + + css::uno::Sequence< css::beans::PropertyValue > + m_aFinalValues; /// the final values as entered by the user + + // the controls + std::unique_ptr<weld::TreeView> m_xAllParams; + std::unique_ptr<weld::Entry> m_xParam; + std::unique_ptr<weld::Button> m_xTravelNext; + std::unique_ptr<weld::Button> m_xOKBtn; + std::unique_ptr<weld::Button> m_xCancelBtn; + + public: + OParameterDialog(weld::Window* _pParent, + const css::uno::Reference< css::container::XIndexAccess > & _rParamContainer, + const css::uno::Reference< css::sdbc::XConnection > & _rxConnection, + const css::uno::Reference< css::uno::XComponentContext >& rxContext); + virtual ~OParameterDialog() override; + + const css::uno::Sequence< css::beans::PropertyValue >& + getValues() const { return m_aFinalValues; } + + private: + void Construct(); + + DECL_LINK(OnVisitedTimeout, Timer*, void); + DECL_LINK(OnValueModified, weld::Entry&, void); + DECL_LINK(OnEntryListBoxSelected, weld::TreeView&, void); + DECL_LINK(OnButtonClicked, weld::Button&, void); + DECL_LINK(OnValueLoseFocusHdl, weld::Widget&, void); + bool CheckValueForError(); + bool OnEntrySelected(); + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/propertystorage.hxx b/dbaccess/source/ui/inc/propertystorage.hxx new file mode 100644 index 000000000..35d9f24d6 --- /dev/null +++ b/dbaccess/source/ui/inc/propertystorage.hxx @@ -0,0 +1,54 @@ +/* -*- 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/uno/Any.hxx> +#include <map> +#include <memory> + +class SfxItemSet; + +namespace dbaui +{ + + /** a PropertyStorage implementation which stores the value in an item set + */ + class SetItemPropertyStorage + { + public: + SetItemPropertyStorage( SfxItemSet& _rItemSet, const sal_uInt16 _nItemID ) + :m_rItemSet( _rItemSet ) + ,m_nItemID( _nItemID ) + { + } + + void getPropertyValue( css::uno::Any& _out_rValue ) const; + void setPropertyValue( const css::uno::Any& _rValue ); + + private: + SfxItemSet& m_rItemSet; + const sal_uInt16 m_nItemID; + }; + + typedef std::map< sal_Int32, std::shared_ptr< SetItemPropertyStorage > > PropertyValues; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/querycontainerwindow.hxx b/dbaccess/source/ui/inc/querycontainerwindow.hxx new file mode 100644 index 000000000..12583ec0c --- /dev/null +++ b/dbaccess/source/ui/inc/querycontainerwindow.hxx @@ -0,0 +1,104 @@ +/* -*- 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 <vcl/window.hxx> +#include <vcl/split.hxx> +#include <dbaccess/dataview.hxx> +#include <com/sun/star/frame/XFrame2.hpp> +#include "QueryViewSwitch.hxx" +#include <vcl/dockwin.hxx> + +namespace dbaui +{ + + // OBeamer + // temporary class until the beamer is implemented + class OBeamer : public DockingWindow + { + public: + OBeamer(vcl::Window* _pParent) : DockingWindow(_pParent,0){} + }; + + // OQueryContainerWindow + class OQueryContainerWindow : public ODataView + { + OQueryViewSwitch* m_pViewSwitch; + VclPtr<OBeamer> m_pBeamer; + VclPtr<Splitter> m_pSplitter; + css::uno::Reference< css::frame::XFrame2 > m_xBeamer; + + DECL_LINK( SplitHdl, Splitter*, void ); + public: + OQueryContainerWindow(vcl::Window* pParent, OQueryController& _rController,const css::uno::Reference< css::uno::XComponentContext >&); + virtual ~OQueryContainerWindow() override; + virtual void dispose() override; + + virtual void Construct() override; + + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + + // show the beamer + void showPreview(const css::uno::Reference< css::frame::XFrame >& _xFrame); + // called when the beamer has been disposed + void disposingPreview(); + + const css::uno::Reference< css::frame::XFrame2 >& + getPreviewFrame() const { return m_xBeamer; } + + OQueryDesignView* getDesignView() { return m_pViewSwitch->getDesignView(); } + + bool isCutAllowed() const { return m_pViewSwitch->isCutAllowed(); } + bool isPasteAllowed() const { return m_pViewSwitch->isPasteAllowed(); } + bool isCopyAllowed() const { return m_pViewSwitch->isCopyAllowed(); } + void copy() { m_pViewSwitch->copy(); } + void cut() { m_pViewSwitch->cut(); } + void paste() { m_pViewSwitch->paste(); } + + void clear() { m_pViewSwitch->clear(); } + bool isSlotEnabled( sal_Int32 _nSlotId ) { return m_pViewSwitch->isSlotEnabled( _nSlotId ); } + void setSlotEnabled( sal_Int32 _nSlotId, bool _bEnable ) { m_pViewSwitch->setSlotEnabled( _nSlotId, _bEnable ); } + void setNoneVisibleRow(sal_Int32 _nRows) { m_pViewSwitch->setNoneVisibleRow( _nRows); } + + bool checkStatement() { return m_pViewSwitch->checkStatement( ); } + OUString getStatement() { return m_pViewSwitch->getStatement( ); } + void setStatement( const OUString& _rsStatement ) { m_pViewSwitch->setStatement( _rsStatement ); } + + void initialize() override { m_pViewSwitch->initialize(); } + void SaveUIConfig() { m_pViewSwitch->SaveUIConfig(); } + void reset() { m_pViewSwitch->reset(); } + + bool switchView( ::dbtools::SQLExceptionInfo* _pErrorInfo ); + void forceInitialView(); + + virtual void GetFocus() override; + + protected: + // re-arrange the controls belonging to the document itself + virtual void resizeAll( const tools::Rectangle& _rPlayground ) override; + + // arrange derived classes controls in the rectangle given + virtual void resizeDocumentView(tools::Rectangle& _rPlayground) override; + }; + // end of temp classes + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/querycontroller.hxx b/dbaccess/source/ui/inc/querycontroller.hxx new file mode 100644 index 000000000..94bb5d8f4 --- /dev/null +++ b/dbaccess/source/ui/inc/querycontroller.hxx @@ -0,0 +1,217 @@ +/* -*- 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 "JoinController.hxx" +#include "querycontainerwindow.hxx" +#include <svx/ParseContext.hxx> +#include "TableFieldDescription.hxx" + +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/XSQLQueryComposer.hpp> +#include <com/sun/star/sdbcx/XAlterView.hpp> + +#include <comphelper/proparrhlp.hxx> +#include <comphelper/propertycontainer.hxx> +#include <comphelper/uno3.hxx> +#include <connectivity/sqliterator.hxx> +#include <connectivity/sqlparse.hxx> + +namespace comphelper +{ + class NamedValueCollection; +} + +namespace dbaui +{ + class OQueryContainerWindow; + + typedef ::comphelper::OPropertyContainer OQueryController_PBase; + typedef ::comphelper::OPropertyArrayUsageHelper< OQueryController > OQueryController_PABase; + class OQueryController :public OJoinController + ,public OQueryController_PBase + ,public OQueryController_PABase + { + OTableFields m_vTableFieldDesc; + OTableFields m_vUnUsedFieldsDesc; // contains fields which aren't visible and don't have any criteria + + css::uno::Sequence< css::beans::PropertyValue > m_aFieldInformation; + + std::unique_ptr<::svxform::OSystemParseContext> m_pParseContext; + ::connectivity::OSQLParser m_aSqlParser; + std::unique_ptr<::connectivity::OSQLParseTreeIterator> m_pSqlIterator; + + css::uno::Reference< css::sdb::XSQLQueryComposer > m_xComposer; + /// if we're editing an existing view, this is non-NULL + css::uno::Reference< css::sdbcx::XAlterView > m_xAlterView; + + OUString m_sStatement; // contains the current sql statement + OUString m_sUpdateCatalogName; // catalog for update data + OUString m_sUpdateSchemaName; // schema for update data + mutable OUString + m_sName; // name of the query + + sal_Int64 m_nLimit; // the limit of the query result (All==-1) + + sal_Int32 m_nVisibleRows; // which rows the selection browse should show + sal_Int32 m_nSplitPos; // the position of the splitter + sal_Int32 m_nCommandType; // the type of the object we're designing + bool m_bGraphicalDesign; // are we in the graphical design mode (sal_True) or in the text design (sal_False)? + bool m_bDistinct; // true when you want "select distinct" otherwise false + bool m_bEscapeProcessing;// is true when we shouldn't parse the statement + + + /** returns the container of queries, views, or command definitions, depending on what object type + we design currently. + + Not allowed to be called if we design an independent SQL command. + */ + css::uno::Reference< css::container::XNameAccess > + getObjectContainer() const; + + bool editingView() const { return m_nCommandType == css::sdb::CommandType::TABLE; } + bool editingQuery() const { return m_nCommandType == css::sdb::CommandType::QUERY; } + bool editingCommand() const { return m_nCommandType == css::sdb::CommandType::COMMAND; } + + bool askForNewName( const css::uno::Reference< css::container::XNameAccess>& _xElements, + bool _bSaveAs); + // creates the querycomposer + void setQueryComposer(); + void deleteIterator(); + void executeQuery(); + bool doSaveAsDoc(bool _bSaveAs); + + void saveViewSettings( ::comphelper::NamedValueCollection& o_rViewSettings, const bool i_includingCriteria ) const; + void loadViewSettings( const ::comphelper::NamedValueCollection& o_rViewSettings ); + OUString translateStatement( bool _bFireStatementChange = true ); + + void execute_QueryPropDlg(); + + protected: + // all the features which should be handled by this class + virtual void describeSupportedFeatures() override; + // state of a feature. 'feature' may be the handle of a css::util::URL somebody requested a dispatch interface for OR a toolbar slot. + virtual FeatureState GetState(sal_uInt16 nId) const override; + // execute a feature + virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override; + + virtual void reconnect( bool _bUI ) override; + virtual OUString getPrivateTitle( ) const override; + + OQueryContainerWindow* getContainer() const { return static_cast< OQueryContainerWindow* >( getView() ); } + + public: + OQueryController(const css::uno::Reference< css::uno::XComponentContext >& _rM); + + virtual ~OQueryController() override; + OTableFields& getTableFieldDesc() { return m_vTableFieldDesc; } + OTableFields& getUnUsedFields() { return m_vUnUsedFieldsDesc; } + + void clearFields(); + + virtual void impl_onModifyChanged() override; + + // should the statement be parsed by our own sql parser + bool isEscapeProcessing() const { return m_bEscapeProcessing; } + bool isGraphicalDesign() const { return m_bGraphicalDesign; } + bool isDistinct() const { return m_bDistinct; } + sal_Int64 getLimit() const { return m_nLimit; } + + const OUString& getStatement() const { return m_sStatement; } + sal_Int32 getSplitPos() const { return m_nSplitPos;} + sal_Int32 getVisibleRows() const { return m_nVisibleRows; } + + void setDistinct(bool _bDistinct) { m_bDistinct = _bDistinct;} + void setLimit(const sal_Int64 _nLimit) { m_nLimit = _nLimit;} + void setSplitPos(sal_Int32 _nSplitPos) { m_nSplitPos = _nSplitPos;} + void setVisibleRows(sal_Int32 _nVisibleRows) { m_nVisibleRows = _nVisibleRows;} + + sal_Int32 getColWidth(sal_uInt16 _nColPos) const; + + const css::uno::Sequence< css::beans::PropertyValue >& + getFieldInformation() const { return m_aFieldInformation; } + + ::connectivity::OSQLParser& getParser() { return m_aSqlParser; } + ::connectivity::OSQLParseTreeIterator& getParseIterator() { return *m_pSqlIterator; } + + virtual bool Construct(vcl::Window* pParent) override; + + DECLARE_XINTERFACE( ) + DECLARE_XTYPEPROVIDER( ) + // XPropertySet + virtual css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // css::lang::XComponent + virtual void SAL_CALL disposing() override; + + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString> SAL_CALL getSupportedServiceNames() override; + + // XController + virtual css::uno::Any SAL_CALL getViewData() override; + virtual void SAL_CALL restoreViewData(const css::uno::Any& Data) override; + + private: + virtual void onLoadedMenu(const css::uno::Reference< css::frame::XLayoutManager >& _xLayoutManager) override; + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + // OPropertySetHelper + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const override; + + virtual OJoinDesignView* getJoinView() override; + // ask the user if the design should be saved when it is modified + virtual short saveModified() override; + virtual void reset() override; + virtual void impl_initialize() override; + + void impl_reset( const bool i_bIgnoreQuerySettings = false ); + /// tells the user that we needed to switch to SQL view automatically + void impl_showAutoSQLViewError( const css::uno::Any& _rErrorDetails ); + + /** switches to the graphical or SQL view mode, as determined by m_bGraphicalDesign + */ + void impl_setViewMode( ::dbtools::SQLExceptionInfo* _pErrorInfo ); + + /// sets m_sStatement, and notifies our respective property change listeners + void setStatement_fireEvent( const OUString& _rNewStatement, bool _bFireStatementChange = true ); + /// sets the m_bEscapeProcessing member, and notifies our respective property change listeners + void setEscapeProcessing_fireEvent( const bool _bEscapeProcessing ); + + // OJoinController overridables + virtual bool allowViews() const override; + virtual bool allowQueries() const override; + + private: + DECL_LINK( OnExecuteAddTable, void*, void ); + + private: + using OQueryController_PBase::getFastPropertyValue; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/queryfilter.hxx b/dbaccess/source/ui/inc/queryfilter.hxx new file mode 100644 index 000000000..396778f22 --- /dev/null +++ b/dbaccess/source/ui/inc/queryfilter.hxx @@ -0,0 +1,109 @@ +/* -*- 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 <vcl/weld.hxx> +#include <connectivity/sqliterator.hxx> + +#include <connectivity/predicateinput.hxx> +#include <svx/ParseContext.hxx> + +namespace com::sun::star { + namespace sdb + { + class XSingleSelectQueryComposer; + } + namespace sdbc + { + class XConnection; + class XDatabaseMetaData; + } + namespace container + { + class XNameAccess; + } + namespace beans + { + struct PropertyValue; + } +} + +// DlgFilterCrit +namespace dbaui +{ + class DlgFilterCrit final : public weld::GenericDialogController + , public ::svxform::OParseContextClient + { + private: + std::vector<OUString> m_aSTR_COMPARE_OPERATORS; + + css::uno::Reference< css::sdb::XSingleSelectQueryComposer> m_xQueryComposer; + css::uno::Reference< css::container::XNameAccess> m_xColumns; + css::uno::Reference< css::sdbc::XConnection> m_xConnection; + css::uno::Reference< css::sdbc::XDatabaseMetaData> m_xMetaData; + + ::dbtools::OPredicateInputController m_aPredicateInput; + + std::unique_ptr<weld::ComboBox> m_xLB_WHEREFIELD1; + std::unique_ptr<weld::ComboBox> m_xLB_WHERECOMP1; + std::unique_ptr<weld::Entry> m_xET_WHEREVALUE1; + + std::unique_ptr<weld::ComboBox> m_xLB_WHERECOND2; + std::unique_ptr<weld::ComboBox> m_xLB_WHEREFIELD2; + std::unique_ptr<weld::ComboBox> m_xLB_WHERECOMP2; + std::unique_ptr<weld::Entry> m_xET_WHEREVALUE2; + + std::unique_ptr<weld::ComboBox> m_xLB_WHERECOND3; + std::unique_ptr<weld::ComboBox> m_xLB_WHEREFIELD3; + std::unique_ptr<weld::ComboBox> m_xLB_WHERECOMP3; + std::unique_ptr<weld::Entry> m_xET_WHEREVALUE3; + + static void SelectField(weld::ComboBox& rBox, std::u16string_view rField); + DECL_LINK(ListSelectHdl, weld::ComboBox&, void); + DECL_LINK(ListSelectCompHdl, weld::ComboBox&, void); + + void SetLine( int nIdx, const css::beans::PropertyValue& _rItem, bool _bOr ); + void EnableLines(); + sal_Int32 GetOSQLPredicateType( std::u16string_view _rSelectedPredicate ) const; + static sal_Int32 GetSelectionPos(sal_Int32 eType, const weld::ComboBox& rListBox); + bool getCondition(const weld::ComboBox& _rField, const weld::ComboBox& _rComp, const weld::Entry& _rValue, css::beans::PropertyValue& _rFilter) const; + void fillLines(int &i, const css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > >& _aValues); + + css::uno::Reference< css::beans::XPropertySet > getMatchingColumn( const weld::Entry& _rValueInput ) const; + css::uno::Reference< css::beans::XPropertySet > getColumn( const OUString& _rFieldName ) const; + css::uno::Reference< css::beans::XPropertySet > getQueryColumn( const OUString& _rFieldName ) const; + + public: + DlgFilterCrit(weld::Window * pParent, + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference< css::sdbc::XConnection>& _rxConnection, + const css::uno::Reference< css::sdb::XSingleSelectQueryComposer>& _rxComposer, + const css::uno::Reference< css::container::XNameAccess>& _rxCols); + virtual ~DlgFilterCrit() override; + + void BuildWherePart(); + + private: + DECL_LINK(PredicateLoseFocus, weld::Widget&, void); + }; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/queryorder.hxx b/dbaccess/source/ui/inc/queryorder.hxx new file mode 100644 index 000000000..523d84f31 --- /dev/null +++ b/dbaccess/source/ui/inc/queryorder.hxx @@ -0,0 +1,81 @@ +/* -*- 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 <vcl/weld.hxx> + +#define DOG_ROWS 3 + +namespace com::sun::star{ + namespace sdb + { + class XSingleSelectQueryComposer; + } + namespace sdbc + { + class XConnection; + } + namespace container + { + class XNameAccess; + } +} + +// DlgOrderCrit +namespace dbaui +{ + class DlgOrderCrit final : public weld::GenericDialogController + { + OUString m_sOrgOrder; + + css::uno::Reference< css::sdb::XSingleSelectQueryComposer> m_xQueryComposer; + css::uno::Reference< css::container::XNameAccess> m_xColumns; + css::uno::Reference< css::sdbc::XConnection> m_xConnection; + + weld::ComboBox* m_aColumnList[DOG_ROWS]; + weld::ComboBox* m_aValueList[DOG_ROWS]; + + std::unique_ptr<weld::ComboBox> m_xLB_ORDERFIELD1; + std::unique_ptr<weld::ComboBox> m_xLB_ORDERVALUE1; + std::unique_ptr<weld::ComboBox> m_xLB_ORDERFIELD2; + std::unique_ptr<weld::ComboBox> m_xLB_ORDERVALUE2; + std::unique_ptr<weld::ComboBox> m_xLB_ORDERFIELD3; + std::unique_ptr<weld::ComboBox> m_xLB_ORDERVALUE3; + + DECL_LINK(FieldListSelectHdl, weld::ComboBox&, void); + void EnableLines(); + + public: + DlgOrderCrit(weld::Window * pParent, + const css::uno::Reference< css::sdbc::XConnection>& _rxConnection, + const css::uno::Reference< css::sdb::XSingleSelectQueryComposer>& _rxComposer, + const css::uno::Reference< css::container::XNameAccess>& _rxCols); + virtual ~DlgOrderCrit() override; + + void BuildOrderPart(); + + OUString GetOrderList( ) const; + const OUString& GetOriginalOrder() const { return m_sOrgOrder; } + + private: + void impl_initializeOrderList_nothrow(); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/sbagrid.hrc b/dbaccess/source/ui/inc/sbagrid.hrc new file mode 100644 index 000000000..c84dbccea --- /dev/null +++ b/dbaccess/source/ui/inc/sbagrid.hrc @@ -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 . + */ + +#ifndef DBACCESS_SBA_GRID_HRC +#define DBACCESS_SBA_GRID_HRC + +//----------------Menueitems------------------------------------------------- +// Table +#define SBA_WHICHID_START 100 + +// Columns +// Formatting +#define SBA_DEF_RANGEFORMAT (SBA_WHICHID_START+143) // RangeItem +#define SBA_DEF_FMTVALUE (SBA_WHICHID_START+144) // SfxULONG, Format + +// Justification +#define SBA_ATTR_ALIGN_HOR_JUSTIFY (SBA_WHICHID_START + 145) // SvxHorJustifyItem + +#endif // DBACCESS_SBA_GRID_HRC + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/sbagrid.hxx b/dbaccess/source/ui/inc/sbagrid.hxx new file mode 100644 index 000000000..0d22f6dce --- /dev/null +++ b/dbaccess/source/ui/inc/sbagrid.hxx @@ -0,0 +1,293 @@ +/* -*- 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 <svx/fmgridcl.hxx> + +#include <svx/fmgridif.hxx> + +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/util/URL.hpp> +#include <comphelper/multiinterfacecontainer3.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/uno3.hxx> +#include "sbamultiplex.hxx" +#include <svx/dataaccessdescriptor.hxx> +#include <rtl/ref.hxx> +#include <map> +#include <queue> + +class SvNumberFormatter; + +namespace com::sun::star { + namespace lang { + class XMultiServiceFactory; + } +} + +namespace dbaui +{ + struct SbaURLCompare + { + bool operator() (const css::util::URL& x, const css::util::URL& y) const { return x.Complete == y.Complete; } + }; + + class SbaXStatusMultiplexer; + class SbaXGridControl + :public FmXGridControl + ,public css::frame::XDispatch + { + typedef std::map<css::util::URL, rtl::Reference<SbaXStatusMultiplexer>, SbaURLCompare> StatusMultiplexerArray; + StatusMultiplexerArray m_aStatusMultiplexer; + + public: + SbaXGridControl(const css::uno::Reference< css::uno::XComponentContext >&); + virtual ~SbaXGridControl() override; + + // UNO + DECLARE_UNO3_DEFAULTS(SbaXGridControl, FmXGridControl) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override; + + // css::lang::XServiceInfo + OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // css::frame::XDispatch + virtual void SAL_CALL dispatch(const css::util::URL& aURL, const css::uno::Sequence< css::beans::PropertyValue >& aArgs) override; + virtual void SAL_CALL addStatusListener(const css::uno::Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) override; + virtual void SAL_CALL removeStatusListener(const css::uno::Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) override; + + // css::lang::XComponent + virtual void SAL_CALL dispose() override; + + virtual void SAL_CALL createPeer(const css::uno::Reference< css::awt::XToolkit > & rToolkit, const css::uno::Reference< css::awt::XWindowPeer > & rParentPeer) override; + + protected: + virtual rtl::Reference<FmXGridPeer> imp_CreatePeer(vcl::Window* pParent) override; + }; + + // SbaXGridPeer + + class SbaXGridPeer final + :public FmXGridPeer + ,public css::frame::XDispatch + { + comphelper::OMultiTypeInterfaceContainerHelperVar3< css::frame::XStatusListener, + css::util::URL, SbaURLCompare> m_aStatusListeners; + + public: + SbaXGridPeer(const css::uno::Reference< css::uno::XComponentContext >&); + virtual ~SbaXGridPeer() override; + + // UNO + virtual void SAL_CALL acquire() noexcept override { FmXGridPeer::acquire(); } + virtual void SAL_CALL release() noexcept override { FmXGridPeer::release(); } + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + UNO3_GETIMPLEMENTATION_DECL(SbaXGridPeer) + + // css::frame::XDispatch + virtual void SAL_CALL dispatch(const css::util::URL& aURL, const css::uno::Sequence< css::beans::PropertyValue >& aArgs) override; + virtual void SAL_CALL addStatusListener(const css::uno::Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) override; + virtual void SAL_CALL removeStatusListener(const css::uno::Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) override; + + // css::frame::XDispatchProvider + virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch(const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags) override; + + // css::lang::XComponent + virtual void SAL_CALL dispose() override; + + private: + virtual VclPtr<FmGridControl> imp_CreateControl(vcl::Window* pParent, WinBits nStyle) override; + void NotifyStatusChanged(const css::util::URL& aUrl, const css::uno::Reference< css::frame::XStatusListener > & xControl); + + // for any execution of XDispatch::dispatch + struct DispatchArgs + { + css::util::URL aURL; + css::uno::Sequence< css::beans::PropertyValue > aArgs; + }; + std::queue< DispatchArgs > m_aDispatchArgs; + DECL_LINK( OnDispatchEvent, void*, void ); + + // for dynamic states of our 4 dispatchable URLs + enum DispatchType + { + dtBrowserAttribs, + dtRowHeight, + dtColumnAttribs, + dtColumnWidth, + + dtUnknown + }; + static DispatchType classifyDispatchURL( const css::util::URL& _rURL ); + + typedef std::map<DispatchType, bool> MapDispatchToBool; + MapDispatchToBool m_aDispatchStates; + }; + + // SbaGridHeader + + class SbaGridHeader + :public FmGridHeader + ,public DragSourceHelper + { + public: + SbaGridHeader(BrowseBox* pParent); + virtual void dispose() override; + virtual ~SbaGridHeader() override; + protected: + + // FmGridHeader overridables + virtual void PreExecuteColumnContextMenu(sal_uInt16 nColId, weld::Menu& rMenu, + weld::Menu& rInsertMenu, weld::Menu& rChangeMenu, + weld::Menu& rShowMenu) override; + virtual void PostExecuteColumnContextMenu(sal_uInt16 nColId, const weld::Menu& rMenu, const OString& rExecutionResult) override; + + private: + // DragSourceHelper overridables + virtual void StartDrag( sal_Int8 _nAction, const Point& _rPosPixel ) override; + + // Window overridables + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + + void ImplStartColumnDrag(sal_Int8 _nAction, const Point& _rMousePos); + }; + + // interfaces for communication between the vcl grid control and a controller + class SbaGridListener + { + public: + virtual void RowChanged() = 0; + virtual void ColumnChanged() = 0; + virtual void SelectionChanged() = 0; + virtual void CellActivated() = 0; + virtual void CellDeactivated() = 0; + virtual void BeforeDrop() = 0; + virtual void AfterDrop() = 0; + + protected: + ~SbaGridListener() {} + }; + + // SbaGridControl + class SbaGridControl final : public FmGridControl + { + friend class SbaGridHeader; + friend class SbaXGridPeer; + + // Attributes + svx::ODataAccessDescriptor m_aDataDescriptor; + SbaGridListener* m_pMasterListener; + + ImplSVEvent * m_nAsyncDropEvent; + + bool m_bActivatingForDrop; + + public: + SbaGridControl(css::uno::Reference< css::uno::XComponentContext > const & _rM, Window* pParent, FmXGridPeer* _pPeer, WinBits nBits); + virtual ~SbaGridControl() override; + virtual void dispose() override; + + virtual void Select() override; + + void SetMasterListener(SbaGridListener* pListener) { m_pMasterListener = pListener; } + + virtual void ActivateCell(sal_Int32 nRow, sal_uInt16 nCol, bool bSetCellFocus = true) override; + virtual void DeactivateCell(bool bUpdate = true) override; + using FmGridControl::ActivateCell; + + bool IsAllSelected() const { return (GetSelectRowCount() == GetRowCount()) && (GetRowCount() > 0); } + + HeaderBar* GetHeaderBar() const { return FmGridControl::GetHeaderBar(); } + + /** return the description of the specified object. + @param eObjType + The type to ask for + @param _nPosition + The position of a tablecell (index position), header bar column/row cell + @return + The description of the specified object. + */ + virtual OUString GetAccessibleObjectDescription( AccessibleBrowseBoxObjType eObjType,sal_Int32 _nPosition = -1) const override; + + using FmGridControl::DeleteSelectedRows; + /** copies the currently selected rows to the clipboard + @precond + at least one row is selected + */ + void CopySelectedRowsToClipboard(); + + private: + // DragSourceHelper overridables + virtual void StartDrag( sal_Int8 _nAction, const Point& _rPosPixel ) override; + + // BrowseBox overridables + virtual sal_Int8 AcceptDrop( const BrowserAcceptDropEvent& rEvt ) override; + virtual sal_Int8 ExecuteDrop( const BrowserExecuteDropEvent& rEvt ) override; + virtual void MouseButtonDown( const BrowserMouseEvent& rMEvt) override; + + // EditBrowseBox overridables + virtual VclPtr<BrowserHeader> imp_CreateHeaderBar(BrowseBox* pParent) override; + virtual ::svt::CellController* GetController(sal_Int32 nRow, sal_uInt16 nCol) override; + + // DbGridControl overridables + virtual void PreExecuteRowContextMenu(weld::Menu& rMenu) override; + virtual void PostExecuteRowContextMenu(const OString& rExecutionResult) override; + + // DbGridControl overridables + virtual void onRowChange() override; + virtual void onColumnChange() override; + + // get a fields property set from a model pos + css::uno::Reference< css::beans::XPropertySet > getField(sal_uInt16 nModelPos); + + // get my data source + css::uno::Reference< css::beans::XPropertySet > getDataSource() const; + + // drag events + void DoColumnDrag(sal_uInt16 nColumnPos); + void DoFieldDrag(sal_uInt16 nColumnPos, sal_Int16 nRowPos); + + void SetBrowserAttrs(); + void SetColWidth(sal_uInt16 nColId); + void SetRowHeight(); + void SetColAttrs(sal_uInt16 nColId); + + SvNumberFormatter* GetDatasourceFormatter(); + + DECL_LINK(AsynchDropEvent, void*, void); + + bool IsReadOnlyDB() const; + void implTransferSelectedRows( sal_Int16 nRowPos, bool _bTrueIfClipboardFalseIfDrag ); + + using FmGridControl::AcceptDrop; + using FmGridControl::ExecuteDrop; + using FmGridControl::MouseButtonDown; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/sbamultiplex.hxx b/dbaccess/source/ui/inc/sbamultiplex.hxx new file mode 100644 index 000000000..d48e3299e --- /dev/null +++ b/dbaccess/source/ui/inc/sbamultiplex.hxx @@ -0,0 +1,308 @@ +/* -*- 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/XVetoableChangeListener.hpp> +#include <com/sun/star/form/XDatabaseParameterListener.hpp> +#include <com/sun/star/form/XLoadListener.hpp> +#include <com/sun/star/beans/XPropertiesChangeListener.hpp> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/form/XSubmitListener.hpp> +#include <com/sun/star/form/XResetListener.hpp> +#include <com/sun/star/sdb/XSQLErrorListener.hpp> +#include <com/sun/star/sdb/XRowSetApproveListener.hpp> +#include <com/sun/star/sdbc/XRowSetListener.hpp> +#include <com/sun/star/frame/XStatusListener.hpp> +#include <comphelper/uno3.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <comphelper/multiinterfacecontainer3.hxx> +#include <cppuhelper/weak.hxx> + +namespace dbaui +{ + // TODO : replace this class if MM provides a WeakSubObject in cppu + class OSbaWeakSubObject : public ::cppu::OWeakObject + { + protected: + ::cppu::OWeakObject& m_rParent; + + public: + OSbaWeakSubObject(::cppu::OWeakObject& rParent) : m_rParent(rParent) { } + + virtual void SAL_CALL acquire() noexcept override { m_rParent.acquire(); } + virtual void SAL_CALL release() noexcept override { m_rParent.release(); } + }; + + // some listener multiplexers + // css::frame::XStatusListener + class SbaXStatusMultiplexer + :public OSbaWeakSubObject + ,public css::frame::XStatusListener + ,public ::comphelper::OInterfaceContainerHelper3<css::frame::XStatusListener> + { + public: + SbaXStatusMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex); + DECLARE_UNO3_DEFAULTS(SbaXStatusMultiplexer, OSbaWeakSubObject) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + /* css::lang::XEventListener */ + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + + virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& e) override; + + private: + css::frame::FeatureStateEvent m_aLastKnownStatus; + public: + const css::frame::FeatureStateEvent& getLastEvent( ) const { return m_aLastKnownStatus; } + /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */ + using OSbaWeakSubObject::operator new; + using OSbaWeakSubObject::operator delete; + }; + + // css::form::XLoadListener + class SbaXLoadMultiplexer + :public OSbaWeakSubObject + ,public css::form::XLoadListener + ,public ::comphelper::OInterfaceContainerHelper3<css::form::XLoadListener> + { + public: + SbaXLoadMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex); + DECLARE_UNO3_DEFAULTS(SbaXLoadMultiplexer, OSbaWeakSubObject) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + /* css::lang::XEventListener */ + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + + virtual void SAL_CALL loaded(const css::lang::EventObject& e) override; + virtual void SAL_CALL unloaded(const css::lang::EventObject& e) override; + virtual void SAL_CALL unloading(const css::lang::EventObject& e) override; + virtual void SAL_CALL reloading(const css::lang::EventObject& e) override; + virtual void SAL_CALL reloaded(const css::lang::EventObject& e) override; + /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */ + using OSbaWeakSubObject::operator new; + using OSbaWeakSubObject::operator delete; + }; + + // css::form::XDatabaseParameterListener + class SbaXParameterMultiplexer + :public OSbaWeakSubObject + ,public css::form::XDatabaseParameterListener + ,public ::comphelper::OInterfaceContainerHelper3<css::form::XDatabaseParameterListener> + { + public: + SbaXParameterMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex); + DECLARE_UNO3_DEFAULTS(SbaXParameterMultiplexer, OSbaWeakSubObject) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + /* css::lang::XEventListener */ + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + virtual sal_Bool SAL_CALL approveParameter(const css::form::DatabaseParameterEvent& e) override; + /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */ + using OSbaWeakSubObject::operator new; + using OSbaWeakSubObject::operator delete; + }; + + // css::form::XSubmitListener + class SbaXSubmitMultiplexer + :public OSbaWeakSubObject + ,public css::form::XSubmitListener + ,public ::comphelper::OInterfaceContainerHelper3<css::form::XSubmitListener> + { + public: + SbaXSubmitMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex); + DECLARE_UNO3_DEFAULTS(SbaXSubmitMultiplexer, OSbaWeakSubObject) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + /* css::lang::XEventListener */ + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + virtual sal_Bool SAL_CALL approveSubmit(const css::lang::EventObject& e) override; + /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */ + using OSbaWeakSubObject::operator new; + using OSbaWeakSubObject::operator delete; + }; + + // css::form::XResetListener + class SbaXResetMultiplexer + :public OSbaWeakSubObject + ,public css::form::XResetListener + ,public ::comphelper::OInterfaceContainerHelper3<css::form::XResetListener> + { + public: + SbaXResetMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex); + DECLARE_UNO3_DEFAULTS(SbaXResetMultiplexer, OSbaWeakSubObject) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + /* css::lang::XEventListener */ + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + virtual sal_Bool SAL_CALL approveReset(const css::lang::EventObject& e) override; + virtual void SAL_CALL resetted(const css::lang::EventObject& e) override; + /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */ + using OSbaWeakSubObject::operator new; + using OSbaWeakSubObject::operator delete; + }; + + // css::sdbc::XRowSetListener + class SbaXRowSetMultiplexer + :public OSbaWeakSubObject + ,public css::sdbc::XRowSetListener + ,public ::comphelper::OInterfaceContainerHelper3<css::sdbc::XRowSetListener> + { + public: + SbaXRowSetMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex); + DECLARE_UNO3_DEFAULTS(SbaXRowSetMultiplexer, OSbaWeakSubObject) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + /* css::lang::XEventListener */ + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + virtual void SAL_CALL cursorMoved(const css::lang::EventObject& e) override; + virtual void SAL_CALL rowChanged(const css::lang::EventObject& e) override; + virtual void SAL_CALL rowSetChanged(const css::lang::EventObject& e) override; + /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */ + using OSbaWeakSubObject::operator new; + using OSbaWeakSubObject::operator delete; + }; + + // css::sdb::XRowSetApproveListener + class SbaXRowSetApproveMultiplexer + :public OSbaWeakSubObject + ,public css::sdb::XRowSetApproveListener + ,public ::comphelper::OInterfaceContainerHelper3<css::sdb::XRowSetApproveListener> + { + public: + SbaXRowSetApproveMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex); + DECLARE_UNO3_DEFAULTS(SbaXRowSetApproveMultiplexer, OSbaWeakSubObject) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + /* css::lang::XEventListener */ + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + virtual sal_Bool SAL_CALL approveCursorMove(const css::lang::EventObject& e) override; + virtual sal_Bool SAL_CALL approveRowChange(const css::sdb::RowChangeEvent& e) override; + virtual sal_Bool SAL_CALL approveRowSetChange(const css::lang::EventObject& e) override; + /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */ + using OSbaWeakSubObject::operator new; + using OSbaWeakSubObject::operator delete; + }; + + // css::sdb::XSQLErrorListener + class SbaXSQLErrorMultiplexer + :public OSbaWeakSubObject + ,public css::sdb::XSQLErrorListener + ,public ::comphelper::OInterfaceContainerHelper3<css::sdb::XSQLErrorListener> + { + public: + SbaXSQLErrorMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex); + DECLARE_UNO3_DEFAULTS(SbaXSQLErrorMultiplexer, OSbaWeakSubObject) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + /* css::lang::XEventListener */ + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + virtual void SAL_CALL errorOccured(const css::sdb::SQLErrorEvent& e) override; + /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */ + using OSbaWeakSubObject::operator new; + using OSbaWeakSubObject::operator delete; + }; + + // css::beans::XPropertyChangeListener + class SbaXPropertyChangeMultiplexer final + :public OSbaWeakSubObject + ,public css::beans::XPropertyChangeListener + { + typedef ::comphelper::OMultiTypeInterfaceContainerHelperVar3<css::beans::XPropertyChangeListener, OUString> ListenerContainerMap; + ListenerContainerMap m_aListeners; + + public: + SbaXPropertyChangeMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex ); + DECLARE_UNO3_DEFAULTS(SbaXPropertyChangeMultiplexer, OSbaWeakSubObject) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + /* css::lang::XEventListener */ + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + + virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& e) override; + + void addInterface(const OUString& rName, const css::uno::Reference< css::beans::XPropertyChangeListener >& rListener); + void removeInterface(const OUString& rName, const css::uno::Reference< css::beans::XPropertyChangeListener >& rListener); + + void disposeAndClear(); + + sal_Int32 getOverallLen() const; + + ::comphelper::OInterfaceContainerHelper3<css::beans::XPropertyChangeListener>* getContainer(const OUString& rName) + { return m_aListeners.getContainer(rName); } + + private: + void Notify(::comphelper::OInterfaceContainerHelper3<css::beans::XPropertyChangeListener>& rListeners, const css::beans::PropertyChangeEvent& e); + }; + + // css::beans::XVetoableChangeListener + class SbaXVetoableChangeMultiplexer final + :public OSbaWeakSubObject + ,public css::beans::XVetoableChangeListener + { + typedef ::comphelper::OMultiTypeInterfaceContainerHelperVar3<css::beans::XVetoableChangeListener, OUString > ListenerContainerMap; + ListenerContainerMap m_aListeners; + + public: + SbaXVetoableChangeMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex ); + DECLARE_UNO3_DEFAULTS(SbaXVetoableChangeMultiplexer, OSbaWeakSubObject) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + /* css::lang::XEventListener */ + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + + virtual void SAL_CALL vetoableChange(const css::beans::PropertyChangeEvent& e) override; + + void addInterface(const OUString& rName, const css::uno::Reference< css::beans::XVetoableChangeListener >& rListener); + void removeInterface(const OUString& rName, const css::uno::Reference< css::beans::XVetoableChangeListener >& rListener); + + void disposeAndClear(); + + sal_Int32 getOverallLen() const; + + ::comphelper::OInterfaceContainerHelper3<css::beans::XVetoableChangeListener>* getContainer(const OUString& rName) + { return m_aListeners.getContainer(rName); } + + private: + void Notify(::comphelper::OInterfaceContainerHelper3<css::beans::XVetoableChangeListener>& rListeners, const css::beans::PropertyChangeEvent& e); + }; + + // css::beans::XPropertiesChangeListener + class SbaXPropertiesChangeMultiplexer + :public OSbaWeakSubObject + ,public css::beans::XPropertiesChangeListener + ,public ::comphelper::OInterfaceContainerHelper3<css::beans::XPropertiesChangeListener> + { + public: + SbaXPropertiesChangeMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex); + DECLARE_UNO3_DEFAULTS(SbaXPropertiesChangeMultiplexer, OSbaWeakSubObject) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + /* css::lang::XEventListener */ + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + virtual void SAL_CALL propertiesChange(const css::uno::Sequence< css::beans::PropertyChangeEvent >& e) override; + /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */ + using OSbaWeakSubObject::operator new; + using OSbaWeakSubObject::operator delete; + }; + // the SbaXPropertiesChangeMultiplexer doesn't care about the property names a listener logs on for, it simply + // forwards _all_ changes to _all_ listeners +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/singledoccontroller.hxx b/dbaccess/source/ui/inc/singledoccontroller.hxx new file mode 100644 index 000000000..e5e11ba7a --- /dev/null +++ b/dbaccess/source/ui/inc/singledoccontroller.hxx @@ -0,0 +1,78 @@ +/* -*- 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 <memory> +#include <dbaccess/dbsubcomponentcontroller.hxx> + +#include <com/sun/star/document/XUndoManagerSupplier.hpp> + +#include <cppuhelper/implbase.hxx> + +class SfxUndoAction; +class SfxUndoManager; + +namespace dbaui +{ + + // OSingleDocumentController + struct OSingleDocumentController_Data; + typedef ::cppu::ImplInheritanceHelper< DBSubComponentController + , css::document::XUndoManagerSupplier + > OSingleDocumentController_Base; + class OSingleDocumentController : public OSingleDocumentController_Base + { + protected: + OSingleDocumentController( const css::uno::Reference< css::uno::XComponentContext>& _rxORB ); + virtual ~OSingleDocumentController() override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + public: + /// need for undo's and redo's + SfxUndoManager& GetUndoManager() const; + + /// complete clears the Undo/Redo stacks + void ClearUndoManager(); + + /** addUndoActionAndInvalidate adds an undo action to the undoManager, + additionally invalidates the UNDO and REDO slot + @param pAction the undo action to add + */ + void addUndoActionAndInvalidate( std::unique_ptr<SfxUndoAction> pAction ); + + // OGenericUnoController + virtual FeatureState GetState( sal_uInt16 nId ) const override; + virtual void Execute( sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs ) override; + + // XUndoManagerSupplier + virtual css::uno::Reference< css::document::XUndoManager > SAL_CALL getUndoManager( ) override; + + // XEventListener + using OSingleDocumentController_Base::disposing; + + private: + std::unique_ptr< OSingleDocumentController_Data > m_pData; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/sqledit.hxx b/dbaccess/source/ui/inc/sqledit.hxx new file mode 100644 index 000000000..0f2ecc8b6 --- /dev/null +++ b/dbaccess/source/ui/inc/sqledit.hxx @@ -0,0 +1,99 @@ +/* -*- 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 <comphelper/syntaxhighlight.hxx> +#include <rtl/ref.hxx> +#include <svtools/colorcfg.hxx> +#include <svx/weldeditview.hxx> +#include <vcl/timer.hxx> + +namespace com::sun::star::beans { class XMultiPropertySet; } + +namespace dbaui +{ + class SQLEditView final : public WeldEditView, public utl::ConfigurationListener + { + private: + class ChangesListener; + friend class ChangesListener; + + std::unique_ptr<weld::ScrolledWindow> m_xScrolledWindow; + Link<LinkParamNone*,void> m_aModifyLink; + const svtools::ColorConfig m_aColorConfig; + Timer m_aUpdateDataTimer; + const SyntaxHighlighter m_aHighlighter; + svtools::ColorConfig m_ColorConfig; + rtl::Reference<SfxItemPool> m_pItemPool; + + rtl::Reference<ChangesListener> m_listener; + osl::Mutex m_mutex; + css::uno::Reference<css::beans::XMultiPropertySet> m_notifier; + + bool m_bInUpdate; + bool m_bDisableInternalUndo; + + DECL_LINK(ModifyHdl, LinkParamNone*, void); + DECL_LINK(ImplUpdateDataHdl, Timer*, void); + DECL_LINK(ScrollHdl, weld::ScrolledWindow&, void); + DECL_LINK(EditStatusHdl, EditStatus&, void); + + Color GetColorValue(TokenType aToken); + + void ImplSetFont(); + + void DoBracketHilight(sal_uInt16 nKey); + + static void SetItemPoolFont(SfxItemPool* pItemPool); + + void UpdateData(); + + void SetScrollBarRange(); + void DoScroll(); + + virtual void EditViewScrollStateChange() override; + + public: + SQLEditView(std::unique_ptr<weld::ScrolledWindow> xScrolledWindow); + virtual void makeEditEngine() override; + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + virtual ~SQLEditView() override; + + virtual bool KeyInput(const KeyEvent& rKEvt) override; + virtual bool Command(const CommandEvent& rCEvt) override; + + void SetTextAndUpdate(const OUString& rNewText); + + void SetModifyHdl(const Link<LinkParamNone*,void>& rLink) + { + m_aModifyLink = rLink; + } + + void DisableInternalUndo(); + + static Color GetSyntaxHighlightColor(const svtools::ColorConfig& rColorConfig, HighlighterLanguage eLanguage, TokenType aToken); + + virtual void ConfigurationChanged(utl::ConfigurationBroadcaster*, ConfigurationHints) override; + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/sqlmessage.hxx b/dbaccess/source/ui/inc/sqlmessage.hxx new file mode 100644 index 000000000..a2541dc0f --- /dev/null +++ b/dbaccess/source/ui/inc/sqlmessage.hxx @@ -0,0 +1,145 @@ +/* -*- 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 <connectivity/dbexception.hxx> +#include <vcl/weld.hxx> +#include <memory> + +// some forwards +namespace com::sun::star { + namespace sdb { + class SQLContext; + } + namespace sdbc { + class SQLException; + } +} + +namespace dbaui +{ + +enum MessageType +{ + Info, + Error, + Warning, + Query, + AUTO +}; + +enum class MessBoxStyle { + NONE = 0x0000, + Ok = 0x0001, + OkCancel = 0x0002, + YesNo = 0x0004, + YesNoCancel = 0x0008, + RetryCancel = 0x0010, + DefaultOk = 0x0020, + DefaultCancel = 0x0040, + DefaultRetry = 0x0080, + DefaultYes = 0x0100, + DefaultNo = 0x0200, +}; + +} + +namespace o3tl { + template<> struct typed_flags<dbaui::MessBoxStyle> : is_typed_flags<dbaui::MessBoxStyle, 0x03ff> {}; +} + + +namespace dbaui +{ + +// OSQLMessageBox +struct SQLMessageBox_Impl; +class OSQLMessageBox : public weld::DialogController +{ + std::unique_ptr<weld::MessageDialog> m_xDialog; + std::unique_ptr<weld::Button> m_xMoreButton; + std::unique_ptr<SQLMessageBox_Impl> m_pImpl; + OUString m_sHelpURL; + + virtual weld::Dialog* getDialog() override { return m_xDialog.get(); } +public: + /** display an SQLException with auto-recognizing a main and a detailed message + + The first two messages from the exception chain are used as main and detailed message (recognizing the + detailed field of an <type scope="css::sdb">SQLContext</type>). + */ + OSQLMessageBox( + weld::Window* pParent, + const dbtools::SQLExceptionInfo& _rException, + MessBoxStyle _nStyle = MessBoxStyle::Ok | MessBoxStyle::DefaultOk, + const OUString& _rHelpURL = OUString() + ); + + /** display a database related error message + + @param rTitle the title to display + @param rMessage the detailed message to display + @param _eType determines the image to use. AUTO is disallowed in this constructor version + */ + OSQLMessageBox(weld::Window* pParent, + const OUString& rTitle, + const OUString& rMessage, + MessBoxStyle nStyle = MessBoxStyle::Ok | MessBoxStyle::DefaultOk, + MessageType _eType = Info, + const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo = nullptr ); + + void set_title(const OUString& rTitle) { m_xDialog->set_title(rTitle); } + void add_button(const OUString& rText, int nResponse, const OString& rHelpId = OString()) { m_xDialog->add_button(rText, nResponse, rHelpId); } + void set_default_response(int nResponse) { m_xDialog->set_default_response(nResponse); } + + virtual ~OSQLMessageBox() override; + +private: + void Construct(weld::Window* pParent, MessBoxStyle nStyle, MessageType eImage); + + DECL_LINK(ButtonClickHdl, weld::Button&, void); + +private: + void impl_fillMessages(); + void impl_createStandardButtons( MessBoxStyle _nStyle ); + void impl_addDetailsButton(); +}; + +// OSQLWarningBox +class OSQLWarningBox : public OSQLMessageBox +{ +public: + OSQLWarningBox( weld::Window* pParent, + const OUString& _rMessage, + MessBoxStyle _nStyle = MessBoxStyle::Ok | MessBoxStyle::DefaultOk, + const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo = nullptr ); +}; + +// OSQLErrorBox +class OSQLErrorBox : public OSQLMessageBox +{ +public: + OSQLErrorBox( weld::Window* pParent, + const OUString& _rMessage ); +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/stringlistitem.hxx b/dbaccess/source/ui/inc/stringlistitem.hxx new file mode 100644 index 000000000..3d16f6770 --- /dev/null +++ b/dbaccess/source/ui/inc/stringlistitem.hxx @@ -0,0 +1,48 @@ +/* -*- 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 <svl/poolitem.hxx> + +#include <com/sun/star/uno/Sequence.hxx> +#include <rtl/ustring.hxx> + +namespace dbaui +{ +// OStringListItem +/** <type>SfxPoolItem</type> which transports a sequence of <type scope="rtl">OUString</type>'s +*/ +class OStringListItem : public SfxPoolItem +{ + css::uno::Sequence<OUString> m_aList; + +public: + OStringListItem(sal_Int16 nWhich, const css::uno::Sequence<OUString>& _rList); + OStringListItem(const OStringListItem& _rSource); + + virtual bool operator==(const SfxPoolItem& _rItem) const override; + virtual OStringListItem* Clone(SfxItemPool* _pPool = nullptr) const override; + + const css::uno::Sequence<OUString>& getList() const { return m_aList; } +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/tabletree.hxx b/dbaccess/source/ui/inc/tabletree.hxx new file mode 100644 index 000000000..ebfbf7d29 --- /dev/null +++ b/dbaccess/source/ui/inc/tabletree.hxx @@ -0,0 +1,155 @@ +/* -*- 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 "imageprovider.hxx" +#include "dbtreelistbox.hxx" + +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp> +#include <memory> + +namespace dbaui +{ + +// OTableTreeListBox +class OTableTreeListBox : public TreeListBox +{ + css::uno::Reference< css::sdbc::XConnection > + m_xConnection; // the connection we're working for, set in implOnNewConnection, called by UpdateTableList + std::unique_ptr< ImageProvider > + m_xImageProvider; // provider for our images + bool m_bVirtualRoot; // should the first entry be visible + bool m_bNoEmptyFolders; // should empty catalogs/schematas be prevented from being displayed? + bool m_bShowToggles; // show toggle buttons + +public: + OTableTreeListBox(std::unique_ptr<weld::TreeView> xTreeView, bool bShowToggles); + + void init() { m_bVirtualRoot = true; } + + typedef std::pair< OUString, bool > TTableViewName; + typedef std::vector< TTableViewName > TNames; + + void SuppressEmptyFolders() { m_bNoEmptyFolders = true; } + + /** determines whether the given entry denotes a tables folder + */ + bool isFolderEntry(const weld::TreeIter& rEntry) const; + + /** fill the table list with the tables belonging to the connection described by the parameters + @param _rxConnection + the connection, which must support the service com.sun.star.sdb.Connection + @throws + <type scope="css::sdbc">SQLException</type> if no connection could be created + */ + void UpdateTableList( + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection + ); + + /** fill the table list with the tables and views determined by the two given containers. + The views sequence is used to determine which table is of type view. + @param _rxConnection the connection where you got the object names from. Must not be NULL. + Used to split the full qualified names into its parts. + @param _rTables table/view sequence + @param _rViews view sequence + */ + void UpdateTableList( + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + const css::uno::Sequence< OUString>& _rTables, + const css::uno::Sequence< OUString>& _rViews + ); + + /** to be used if a foreign instance added a table + */ + std::unique_ptr<weld::TreeIter> addedTable( const OUString& _rName ); + + /** to be used if a foreign instance removed a table + */ + void removedTable( const OUString& _rName ); + + std::unique_ptr<weld::TreeIter> getAllObjectsEntry() const; + + /** does a wildcard check of the given entry + <p>There are two different 'checked' states: If the user checks all children of an entry, this is different + from checking the entry itself. The second is called 'wildcard' checking, 'cause in the resulting + table filter it's represented by a wildcard.</p> + */ + void checkWildcard(const weld::TreeIter& rEntry); + + /** determine if the given entry is 'wildcard checked' + @see checkWildcard + */ + bool isWildcardChecked(const weld::TreeIter& rEntry); + + void CheckButtons(); // make the button states consistent (bottom-up) + + void checkedButton_noBroadcast(const weld::TreeIter& rEntry); +private: + TriState implDetermineState(const weld::TreeIter& rEntry); + + void implEmphasize(const weld::TreeIter& rEntry, bool _bChecked, bool _bUpdateDescendants = true, bool _bUpdateAncestors = true); + + /** adds the given entry to our list + @precond + our image provider must already have been reset to the connection to which the meta data + belong. + */ + std::unique_ptr<weld::TreeIter> implAddEntry( + const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rxMeta, + const OUString& _rTableName, + bool _bCheckName = true + ); + + void implOnNewConnection( const css::uno::Reference< css::sdbc::XConnection >& _rxConnection ); + + bool impl_getAndAssertMetaData( css::uno::Reference< css::sdbc::XDatabaseMetaData >& _out_rMetaData ) const; + + bool haveVirtualRoot() const { return m_bVirtualRoot; } + +public: + /** fill the table list with the tables and views determined by the two given containers + @param _rxConnection the connection where you got the object names from. Must not be NULL. + Used to split the full qualified names into its parts. + @param _rTables table/view sequence, the second argument is <TRUE/> if it is a table, otherwise it is a view. + */ + void UpdateTableList( + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + const TNames& _rTables + ); + + /** returns a NamedDatabaseObject record which describes the given entry + */ + css::sdb::application::NamedDatabaseObject + describeObject(const weld::TreeIter& rEntry); + + /** returns the fully qualified name of a table entry + @param _pEntry + the entry whose name is to be obtained. Must not denote a folder entry. + */ + OUString getQualifiedTableName(const weld::TreeIter& rEntry) const; + + std::unique_ptr<weld::TreeIter> getEntryByQualifiedName(const OUString& rName); +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/textconnectionsettings.hxx b/dbaccess/source/ui/inc/textconnectionsettings.hxx new file mode 100644 index 000000000..9d21c8795 --- /dev/null +++ b/dbaccess/source/ui/inc/textconnectionsettings.hxx @@ -0,0 +1,59 @@ +/* -*- 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 "propertystorage.hxx" +#include <vcl/weld.hxx> +#include <memory> + +class SfxItemSet; +namespace dbaui +{ + + class OTextConnectionHelper; + + // TextConnectionSettingsDialog + class TextConnectionSettingsDialog : public weld::GenericDialogController + { + public: + TextConnectionSettingsDialog(weld::Window* _pParent, SfxItemSet& rItems); + virtual ~TextConnectionSettingsDialog() override; + + /** initializes a set of PropertyStorage instances, which are bound to + the text-connection relevant items in our item sets + */ + static void bindItemStorages( SfxItemSet& _rSet, PropertyValues& _rValues ); + + virtual short run() override; + + private: + SfxItemSet& m_rItems; + + std::unique_ptr<weld::Widget> m_xContainer; + std::unique_ptr<weld::Button> m_xOK; + std::unique_ptr<OTextConnectionHelper> m_xTextConnectionHelper; + + private: + DECL_LINK(OnOK, weld::Button&, void); + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/undosqledit.hxx b/dbaccess/source/ui/inc/undosqledit.hxx new file mode 100644 index 000000000..2b760bbad --- /dev/null +++ b/dbaccess/source/ui/inc/undosqledit.hxx @@ -0,0 +1,45 @@ +/* -*- 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 "GeneralUndo.hxx" +#include <strings.hrc> + +namespace dbaui +{ + class OQueryTextView; + + // OSqlEditUndoAct - Undo-class for changing sql text + class OSqlEditUndoAct final : public OCommentUndoAction + { + OQueryTextView& m_rOwner; + OUString m_strNextText; + + virtual void Undo() override { ToggleText(); } + virtual void Redo() override { ToggleText(); } + + void ToggleText(); + public: + OSqlEditUndoAct(OQueryTextView& rEdit) : OCommentUndoAction(STR_QUERY_UNDO_MODIFYSQLEDIT), m_rOwner(rEdit) { } + + void SetOriginalText(const OUString& strText) { m_strNextText = strText; } + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/unoadmin.hxx b/dbaccess/source/ui/inc/unoadmin.hxx new file mode 100644 index 000000000..944dccf87 --- /dev/null +++ b/dbaccess/source/ui/inc/unoadmin.hxx @@ -0,0 +1,59 @@ +/* -*- 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 <com/sun/star/sdbc/XConnection.hpp> +#include <dsntypes.hxx> + +class SfxItemSet; +class SfxItemPool; +class SfxPoolItem; + +namespace dbaui +{ + +// ODatabaseAdministrationDialog +typedef ::svt::OGenericUnoDialog ODatabaseAdministrationDialogBase; +class ODatabaseAdministrationDialog + :public ODatabaseAdministrationDialogBase +{ +protected: + std::unique_ptr<SfxItemSet> m_pDatasourceItems; // item set for the dialog + rtl::Reference<SfxItemPool> m_pItemPool; // item pool for the item set for the dialog + std::vector<SfxPoolItem*>* + m_pItemPoolDefaults; // pool defaults + std::unique_ptr<::dbaccess::ODsnTypeCollection> + m_pCollection; // datasource type collection + + css::uno::Any m_aInitialSelection; + css::uno::Reference< css::sdbc::XConnection > m_xActiveConnection; + +protected: + ODatabaseAdministrationDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + virtual ~ODatabaseAdministrationDialog() override; +protected: +// OGenericUnoDialog overridables + virtual void implInitialize(const css::uno::Any& _rValue) override; +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/unodatbr.hxx b/dbaccess/source/ui/inc/unodatbr.hxx new file mode 100644 index 000000000..4bb5c26c7 --- /dev/null +++ b/dbaccess/source/ui/inc/unodatbr.hxx @@ -0,0 +1,447 @@ +/* -*- 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 <memory> +#include "brwctrlr.hxx" +#include <com/sun/star/frame/XStatusListener.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/i18n/XCollator.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/document/XScriptInvocationContext.hpp> +#include <com/sun/star/ui/XContextMenuInterception.hpp> +#include <com/sun/star/sdb/application/DatabaseObject.hpp> +#include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp> +#include <com/sun/star/sdb/XDatabaseRegistrationsListener.hpp> +#include <comphelper/interfacecontainer2.hxx> +#include <cppuhelper/implbase5.hxx> +#include "callbacks.hxx" +#include <vcl/transfer.hxx> +#include <svx/dataaccessdescriptor.hxx> +#include "TableCopyHelper.hxx" +#include "commontypes.hxx" + +class Splitter; +class ODataClipboard; + +namespace com::sun::star::container { class XNameContainer; } + +namespace dbaui +{ + struct DBTreeEditedEntry; + struct DBTreeListUserData; + class ImageProvider; + + typedef ::cppu::ImplHelper5 < css::frame::XStatusListener + , css::view::XSelectionSupplier + , css::document::XScriptInvocationContext + , css::ui::XContextMenuInterception + , css::sdb::XDatabaseRegistrationsListener + > SbaTableQueryBrowser_Base; + class SbaTableQueryBrowser final + :public SbaXDataBrowserController + ,public SbaTableQueryBrowser_Base + ,public IControlActionListener + ,public IContextMenuProvider + { + css::uno::Reference< css::i18n::XCollator > m_xCollator; + css::uno::Reference< css::frame::XFrame > m_xCurrentFrameParent; + css::uno::Reference< css::awt::XWindow > m_xMainToolbar; + + struct ExternalFeature + { + css::util::URL aURL; + css::uno::Reference< css::frame::XDispatch > + xDispatcher; + bool bEnabled; + + ExternalFeature() : bEnabled( false ) { } + ExternalFeature( const css::util::URL& _rURL ) : aURL( _rURL ), bEnabled( false ) { } + }; + + typedef std::map< sal_uInt16, ExternalFeature > ExternalFeaturesMap; + ExternalFeaturesMap m_aExternalFeatures; + + svx::ODataAccessDescriptor m_aDocumentDataSource; + // if we're part of a document, this is the state of the DocumentDataSource slot + + ::comphelper::OInterfaceContainerHelper2 m_aSelectionListeners; + ::comphelper::OInterfaceContainerHelper2 m_aContextMenuInterceptors; + + OTableCopyHelper::DropDescriptor m_aAsyncDrop; + OTableCopyHelper m_aTableCopyHelper; + + OUString m_sQueryCommand; // the command of the query currently loaded (if any) + //OUString m_sToBeLoaded; // contains the element name which should be loaded if any + + VclPtr<InterimDBTreeListBox> m_pTreeView; // contains the datasources of the registry + VclPtr<Splitter> m_pSplitter; + std::unique_ptr<weld::TreeIter> m_xCurrentlyDisplayed; + ImplSVEvent * m_nAsyncDrop; + + bool m_bQueryEscapeProcessing : 1; // the escape processing flag of the query currently loaded (if any) + bool m_bShowMenu; // if sal_True the menu should be visible otherwise not + bool m_bInSuspend; + bool m_bEnableBrowser; + ::std::optional< bool > + m_aDocScriptSupport; // relevant if and only if we are associated with exactly one DBDoc + + virtual OUString getPrivateTitle( ) const override; + // attribute access + public: + SbaTableQueryBrowser(const css::uno::Reference< css::uno::XComponentContext >& _rM); + virtual ~SbaTableQueryBrowser() override; + + enum EntryType + { + // don't change the above definitions! There are places (in particular SbaTableQueryBrowser::getCurrentSelection) + // which rely on the fact that the EntryType values really equal the DatabaseObject(Container) values! + etDatasource = css::sdb::application::DatabaseObjectContainer::DATA_SOURCE, + etQueryContainer = css::sdb::application::DatabaseObjectContainer::QUERIES, + etTableContainer = css::sdb::application::DatabaseObjectContainer::TABLES, + etQuery = css::sdb::application::DatabaseObject::QUERY, + etTableOrView = css::sdb::application::DatabaseObject::TABLE, + etUnknown = -1 + }; + + /** returns a DatabaseObject value corresponding to the given EntryType + @param _eType + the entry type. Must not be etUnknown. + */ + static sal_Int32 getDatabaseObjectType( EntryType _eType ); + + DECLARE_UNO3_DEFAULTS(SbaTableQueryBrowser,SbaXDataBrowserController) + // late construction + virtual bool Construct(vcl::Window* pParent) override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override; + + // css::beans::XPropertyChangeListener + virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& evt) override; + + // css::frame::XController + virtual sal_Bool SAL_CALL suspend(sal_Bool bSuspend) override; + virtual void SAL_CALL attachFrame(const css::uno::Reference< css::frame::XFrame > & xFrame) override; + + // css::lang::XComponent + virtual void SAL_CALL disposing() override; + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // XSelectionSupplier + virtual sal_Bool SAL_CALL select( const css::uno::Any& aSelection ) override; + virtual css::uno::Any SAL_CALL getSelection( ) override; + virtual void SAL_CALL addSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override; + virtual void SAL_CALL removeSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XContainerListener + virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override; + virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override; + virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override; + // css::frame::XFrameActionListener + virtual void SAL_CALL frameAction(const css::frame::FrameActionEvent& aEvent) override; + + // XScriptInvocationContext + virtual css::uno::Reference< css::document::XEmbeddedScripts > SAL_CALL getScriptContainer() override; + + // XContextMenuInterception + virtual void SAL_CALL registerContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor >& Interceptor ) override; + virtual void SAL_CALL releaseContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor >& Interceptor ) override; + + // XDatabaseRegistrationsListener + virtual void SAL_CALL registeredDatabaseLocation( const css::sdb::DatabaseRegistrationEvent& Event ) override; + virtual void SAL_CALL revokedDatabaseLocation( const css::sdb::DatabaseRegistrationEvent& Event ) override; + virtual void SAL_CALL changedDatabaseLocation( const css::sdb::DatabaseRegistrationEvent& Event ) override; + + private: + // SbaXDataBrowserController overridable + virtual bool InitializeForm( const css::uno::Reference< css::beans::XPropertySet >& i_formProperties ) override; + + void InitializeGridModel(const css::uno::Reference< css::form::XFormComponent > & xGrid); + + virtual bool preReloadForm() override; + virtual void postReloadForm() override; + + virtual void addModelListeners(const css::uno::Reference< css::awt::XControlModel > & _xGridControlModel) override; + virtual void removeModelListeners(const css::uno::Reference< css::awt::XControlModel > & _xGridControlModel) override; + + virtual void AddColumnListener(const css::uno::Reference< css::beans::XPropertySet > & xCol) override; + virtual void RemoveColumnListener(const css::uno::Reference< css::beans::XPropertySet > & xCol) override; + + virtual void LoadFinished(bool _bWasSynch) override; + + virtual void criticalFail() override; + + virtual void describeSupportedFeatures() override; + virtual FeatureState GetState(sal_uInt16 nId) const override; + virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override; + + // IControlActionListener overridables + virtual bool requestQuickHelp(const void* pUserData, OUString& rText) const override; + virtual bool requestDrag(const weld::TreeIter& rEntry) override; + virtual sal_Int8 queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors ) override; + virtual sal_Int8 executeDrop( const ExecuteDropEvent& _rEvt ) override; + + // IContextMenuProvider + virtual OUString getContextMenuResourceName() const override; + virtual IController& getCommandController() override; + virtual ::comphelper::OInterfaceContainerHelper2* + getContextMenuInterceptors() override; + virtual css::uno::Any getCurrentSelection(weld::TreeView& rControl) const override; + virtual vcl::Window* getMenuParent() const override; + virtual void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const override; + + virtual void impl_initialize() override; + + // SbaGridListener overridables + virtual void RowChanged() override; + virtual void ColumnChanged() override; + virtual void SelectionChanged() override; + + // methods for showing/hiding the explorer part + bool haveExplorer() const; + void hideExplorer(); + void showExplorer(); + void toggleExplorer() { if (haveExplorer()) hideExplorer(); else showExplorer(); } + + // methods for handling the 'selection' (painting them bold) of SvLBoxEntries + // returns <TRUE/> if the entry is selected (which means it's part of the selected path) + bool isSelected(const weld::TreeIter& rEntry) const; + // select the entry (and only the entry, not the whole path) + void select(const weld::TreeIter* pEntry, bool bSelect); + // select the path of the entry (which must be an entry without children) + void selectPath(const weld::TreeIter* pEntry, bool bSelect = true); + + virtual void loadMenu(const css::uno::Reference< css::frame::XFrame >& _xFrame) override; + + // check the state of the external slot given, update any UI elements if necessary + void implCheckExternalSlot( sal_uInt16 _nId ); + + // connect to the external dispatchers (if any) + void connectExternalDispatches(); + + /** get the state of an external slot + <p>The slot is available if an external dispatcher is responsible for it, _and_ if this dispatcher + told us the slot is available.</p> + */ + bool getExternalSlotState( sal_uInt16 _nId ) const; + + /** add an entry (including the subentries for queries/tables) to the list model + + <p>The given names and images may be empty, in this case they're filled with the correct + values. This way they may be reused for the next call, which saves some resource manager calls.</p> + */ + void implAddDatasource(const OUString& _rDbName, OUString& _rDbImage, + OUString& _rQueryName, OUString& _rQueryImage, + OUString& _rTableName, OUString& _rTableImage, + const SharedConnection& _rxConnection + ); + + void implAddDatasource( const OUString& _rDataSourceName, const SharedConnection& _rxConnection ); + + /// removes (and cleans up) the entry for the given data source + void impl_cleanupDataSourceEntry( std::u16string_view _rDataSourceName ); + + /// clears the tree list box + void clearTreeModel(); + + /** unloads the form, empties the grid model, cleans up anything related to the currently displayed object + @param _bDisposeConnection + <TRUE/> if the connection should be disposed + @param _bFlushData + <TRUE/> if the currently displayed object (if any) should be flushed + */ + void unloadAndCleanup( bool _bDisposeConnection = true ); + + // disposes the connection associated with the given entry (which must represent a data source) + void disposeConnection(const weld::TreeIter* xpDSEntry); + + /// flushes and disposes the given connection, and de-registers as listener + void impl_releaseConnection( SharedConnection& _rxConnection ); + + /** close the connection (and collapse the list entries) of the given list entries + */ + void closeConnection(const weld::TreeIter& rEntry, bool bDisposeConnection = true); + + void populateTree(const css::uno::Reference< css::container::XNameAccess>& xNameAccess, const weld::TreeIter& rParent, EntryType eEntryType); + void initializeTreeModel(); + + /** search in the tree for query- or tablecontainer equal to this interface and return + this container entry + */ + std::unique_ptr<weld::TreeIter> getEntryFromContainer(const css::uno::Reference<css::container::XNameAccess>& rxNameAccess); + + // return true when there is connection available + bool ensureConnection(const weld::TreeIter* pDSEntry, void * pDSData, SharedConnection& rConnection); + bool ensureConnection(const weld::TreeIter* pAnyEntry, SharedConnection& rConnection); + + bool getExistentConnectionFor(const weld::TreeIter* pDSEntry, SharedConnection& rConnection); + /** returns an image provider which works with the connection belonging to the given entry + */ + std::unique_ptr<ImageProvider> getImageProviderFor(const weld::TreeIter* pAnyEntry); + + void implAdministrate(const weld::TreeIter& rApplyTo); + + bool implCopyObject(ODataClipboard& rExchange, const weld::TreeIter& rApplyTo, sal_Int32 nCommandType); + + EntryType getEntryType(const weld::TreeIter& rEntry) const; + EntryType getChildType(const weld::TreeIter& rEntry) const; + static bool isObject( EntryType _eType ) { return ( etTableOrView== _eType ) || ( etQuery == _eType ); } + static bool isContainer( EntryType _eType ) { return (etTableContainer == _eType) || (etQueryContainer == _eType); } + bool isContainer(const weld::TreeIter& rEntry) const { return isContainer(getEntryType(rEntry)); } + + // ensure that the xObject for the given entry is set on the user data + bool ensureEntryObject(const weld::TreeIter& rEntry); + + // get the display text of the entry given + OUString GetEntryText(const weld::TreeIter& rEntry) const; + + // is called when a table or a query was selected + DECL_LINK( OnSelectionChange, LinkParamNone*, void ); + DECL_LINK( OnExpandEntry, const weld::TreeIter&, bool ); + + DECL_LINK( OnCopyEntry, LinkParamNone*, void ); + + int OnTreeEntryCompare(const weld::TreeIter& rLHS, const weld::TreeIter& rRHS); + + DECL_LINK( OnAsyncDrop, void*, void ); + + void implRemoveStatusListeners(); + + bool implSelect(const svx::ODataAccessDescriptor& _rDescriptor, bool _bSelectDirect = false); + bool implSelect(const weld::TreeIter* pEntry); + + /// selects the entry given and loads the grid control with the object's data + bool implSelect( + const OUString& _rDataSourceName, + const OUString& _rCommand, + const sal_Int32 _nCommandType, + const bool _bEscapeProcessing, + const SharedConnection& _rxConnection, + bool _bSelectDirect + ); + + std::unique_ptr<weld::TreeIter> implGetConnectionEntry(const weld::TreeIter& rEntry) const; + /// inserts an entry into the tree + std::unique_ptr<weld::TreeIter> implAppendEntry( + const weld::TreeIter* pParent, + const OUString& rName, + const DBTreeListUserData* pUserData); + + /// loads the grid control with the data object specified (which may be a table, a query or a command) + bool implLoadAnything(const OUString& _rDataSourceName, const OUString& _rCommand, + const sal_Int32 _nCommandType, const bool _bEscapeProcessing, const SharedConnection& _rxConnection ); + + /** retrieves the tree entry for the object described by <arg>_rDescriptor</arg> + @param rDescriptor + the object descriptor + @param ppDataSourceEntry + If not <NULL/>, the data source tree entry will be returned here + @param ppContainerEntry + If not <NULL/>, the object container tree entry will be returned here + */ + std::unique_ptr<weld::TreeIter> getObjectEntry(const svx::ODataAccessDescriptor& rDescriptor, + std::unique_ptr<weld::TreeIter>* ppDataSourceEntry, std::unique_ptr<weld::TreeIter>* ppContainerEntry + ); + /** retrieves the tree entry for the object described by data source name, command and command type + @param rDataSource + the data source name + @param rCommand + the command + @param nCommandType + the command type + @param rDescriptor + the object descriptor + @param ppDataSourceEntry + If not <NULL/>, the data source tree entry will be returned here + @param ppContainerEntry + If not <NULL/>, the object container tree entry will be returned here + @param bExpandAncestors + If <TRUE/>, all ancestor on the way to the entry will be expanded + */ + std::unique_ptr<weld::TreeIter> getObjectEntry( + const OUString& rDataSource, const OUString& rCommand, sal_Int32 nCommandType, + std::unique_ptr<weld::TreeIter>* ppDataSourceEntry, std::unique_ptr<weld::TreeIter>* ppContainerEntry, + bool _bExpandAncestors = true, + const SharedConnection& rxConnection = SharedConnection() + ); + + /// checks if m_aDocumentDataSource describes a known object + void checkDocumentDataSource(); + + static void extractDescriptorProps(const svx::ODataAccessDescriptor& _rDescriptor, + OUString& _rDataSource, OUString& _rCommand, sal_Int32& _rCommandType, bool& _rEscapeProcessing); + + void transferChangedControlProperty(const OUString& _rProperty, const css::uno::Any& _rNewValue); + + // checks whether the given tree entry denotes a data source + bool impl_isDataSourceEntry(const weld::TreeIter* pEntry) const; + + /// retrieves the data source URL/name for the given entry representing a data source + OUString getDataSourceAccessor(const weld::TreeIter& rDataSourceEntry) const; + + /** get the signature (command/escape processing) of the query the form is based on + <p>If the for is not based on a query or not even loaded, nothing happens and <FALSE/> is returned.</p> + */ + bool implGetQuerySignature( OUString& _rCommand, bool& _bEscapeProcessing ); + + bool isEntryCopyAllowed(const weld::TreeIter& rEntry) const; + + void copyEntry(const weld::TreeIter& rEntry); + + // remove all grid columns and dispose them + static void clearGridColumns(const css::uno::Reference< css::container::XNameContainer >& _xColContainer); + + /** checks if the currently displayed entry changed + @param rName + Name of the changed entry + @param rContainer + The container of the displayed entry + @return + <TRUE/> if it is the currently displayed otherwise <FALSE/> + */ + bool isCurrentlyDisplayedChanged(std::u16string_view rName, const weld::TreeIter& rContainer); + + /** called whenever the content of the browser is used for preview, as the very last action + of the load process + */ + void initializePreviewMode(); + + /** checks whether the Order/Filter clauses set at our row set are valid, removes them if not so + */ + void impl_sanitizeRowSetClauses_nothrow(); + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/unosqlmessage.hxx b/dbaccess/source/ui/inc/unosqlmessage.hxx new file mode 100644 index 000000000..c084ef240 --- /dev/null +++ b/dbaccess/source/ui/inc/unosqlmessage.hxx @@ -0,0 +1,68 @@ +/* -*- 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/proparrhlp.hxx> + +namespace dbaui +{ + +typedef ::svt::OGenericUnoDialog OSQLMessageDialogBase; +class OSQLMessageDialog final + :public OSQLMessageDialogBase + ,public ::comphelper::OPropertyArrayUsageHelper< OSQLMessageDialog > +{ + // <properties> + css::uno::Any m_aException; + OUString m_sHelpURL; + // </properties> + +public: + OSQLMessageDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + + // XTypeProvider + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + +private: + virtual void SAL_CALL initialize(css::uno::Sequence< css::uno::Any > const & args) override; + +// OPropertySetHelper overridables + // (overwriting these three, because we have some special handling for our property) + virtual sal_Bool SAL_CALL convertFastPropertyValue( css::uno::Any& _rConvertedValue, css::uno::Any& _rOldValue, sal_Int32 _nHandle, const css::uno::Any& _rValue) override; + + // OGenericUnoDialog overridables + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/DExport.cxx b/dbaccess/source/ui/misc/DExport.cxx new file mode 100644 index 000000000..4f25bb467 --- /dev/null +++ b/dbaccess/source/ui/misc/DExport.cxx @@ -0,0 +1,840 @@ +/* -*- 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 <DExport.hxx> +#include <core_resource.hxx> + +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <strings.hrc> +#include <strings.hxx> +#include <connectivity/dbconversion.hxx> +#include <sal/log.hxx> +#include <sfx2/sfxhtml.hxx> +#include <svl/numuno.hxx> +#include <connectivity/dbtools.hxx> +#include <TypeInfo.hxx> +#include <FieldDescriptions.hxx> +#include <UITools.hxx> +#include <tools/diagnose_ex.h> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <WCopyTable.hxx> +#include <unotools/syslocale.hxx> +#include <svl/numformat.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/FValue.hxx> +#include <com/sun/star/sdb/application/CopyTableOperation.hpp> +#include <sqlmessage.hxx> +#include "UpdateHelperImpl.hxx" +#include <cppuhelper/exc_hlp.hxx> + +using namespace dbaui; +using namespace utl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::awt; + +namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation; + +// ODatabaseExport +ODatabaseExport::ODatabaseExport(sal_Int32 nRows, + TPositions&&_rColumnPositions, + const Reference< XNumberFormatter >& _rxNumberF, + const Reference< css::uno::XComponentContext >& _rxContext, + const TColumnVector* pList, + const OTypeInfoMap* _pInfoMap, + bool _bAutoIncrementEnabled, + SvStream& _rInputStream) + :m_vColumnPositions(std::move(_rColumnPositions)) + ,m_aDestColumns(true) + ,m_xFormatter(_rxNumberF) + ,m_xContext(_rxContext) + ,m_pFormatter(nullptr) + ,m_rInputStream( _rInputStream ) + ,m_pColumnList(pList) + ,m_pInfoMap(_pInfoMap) + ,m_nColumnPos(0) + ,m_nRows(1) + ,m_nRowCount(0) + ,m_bError(false) + ,m_bInTbl(false) + ,m_bHead(true) + ,m_bDontAskAgain(false) + ,m_bIsAutoIncrement(_bAutoIncrementEnabled) + ,m_bFoundTable(false) + ,m_bCheckOnly(false) + ,m_bAppendFirstLine(false) +{ + m_nRows += nRows; + sal_Int32 nCount = 0; + for(const std::pair<sal_Int32,sal_Int32> & rPair : m_vColumnPositions) + if ( rPair.first != COLUMN_POSITION_NOT_FOUND ) + ++nCount; + + m_vColumnSize.resize(nCount); + m_vNumberFormat.resize(nCount); + for(sal_Int32 i=0;i<nCount;++i) + { + m_vColumnSize[i] = 0; + m_vNumberFormat[i] = 0; + } + + try + { + SvtSysLocale aSysLocale; + m_aLocale = aSysLocale.GetLanguageTag().getLocale(); + } + catch(Exception&) + { + } + + SetColumnTypes(pList,_pInfoMap); +} + +ODatabaseExport::ODatabaseExport(const SharedConnection& _rxConnection, + const Reference< XNumberFormatter >& _rxNumberF, + const Reference< css::uno::XComponentContext >& _rxContext, + SvStream& _rInputStream) + :m_aDestColumns(_rxConnection->getMetaData().is() && _rxConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) + ,m_xConnection(_rxConnection) + ,m_xFormatter(_rxNumberF) + ,m_xContext(_rxContext) + ,m_pFormatter(nullptr) + ,m_rInputStream( _rInputStream ) + ,m_pColumnList(nullptr) + ,m_pInfoMap(nullptr) + ,m_nColumnPos(0) + ,m_nRows(1) + ,m_nRowCount(0) + ,m_bError(false) + ,m_bInTbl(false) + ,m_bHead(true) + ,m_bDontAskAgain(false) + ,m_bIsAutoIncrement(false) + ,m_bFoundTable(false) + ,m_bCheckOnly(false) + ,m_bAppendFirstLine(false) +{ + try + { + SvtSysLocale aSysLocale; + m_aLocale = aSysLocale.GetLanguageTag().getLocale(); + } + catch(Exception&) + { + } + + Reference<XTablesSupplier> xTablesSup(m_xConnection,UNO_QUERY); + if(xTablesSup.is()) + m_xTables = xTablesSup->getTables(); + + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + Reference<XResultSet> xSet = xMeta.is() ? xMeta->getTypeInfo() : Reference<XResultSet>(); + if(xSet.is()) + { + ::connectivity::ORowSetValue aValue; + std::vector<sal_Int32> aTypes; + std::vector<bool> aNullable; + Reference<XResultSetMetaData> xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(xSet,UNO_QUERY_THROW)->getMetaData(); + Reference<XRow> xRow(xSet,UNO_QUERY_THROW); + while(xSet->next()) + { + if ( aTypes.empty() ) + { + sal_Int32 nCount = xResultSetMetaData->getColumnCount(); + if ( nCount < 1 ) + nCount = 18; + aTypes.reserve(nCount+1); + aNullable.reserve(nCount+1); + aTypes.push_back(-1); + aNullable.push_back(false); + for (sal_Int32 j = 1; j <= nCount ; ++j) + { + aNullable.push_back(xResultSetMetaData->isNullable(j) != ColumnValue::NO_NULLS ); + aTypes.push_back(xResultSetMetaData->getColumnType(j)); + } + } + + sal_Int32 nPos = 1; + OSL_ENSURE((nPos) < static_cast<sal_Int32>(aTypes.size()),"aTypes: Illegal index for vector"); + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + OUString sTypeName = aValue.getString(); + ++nPos; + OSL_ENSURE((nPos) < static_cast<sal_Int32>(aTypes.size()),"aTypes: Illegal index for vector"); + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + sal_Int32 nType = aValue.getInt32(); + ++nPos; + + if( nType == DataType::VARCHAR ) + { + m_pTypeInfo = std::make_shared<OTypeInfo>(); + + m_pTypeInfo->aTypeName = sTypeName; + m_pTypeInfo->nType = nType; + + OSL_ENSURE((nPos) < static_cast<sal_Int32>(aTypes.size()),"aTypes: Illegal index for vector"); + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->nPrecision = aValue.getInt32(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); //LiteralPrefix + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); //LiteralSuffix + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->aCreateParams = aValue.getString(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->bNullable = aValue.getInt32() == ColumnValue::NULLABLE; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + // bCaseSensitive + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->nSearchType = aValue.getInt16(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + // bUnsigned + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->bCurrency = aValue.getBool(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->bAutoIncrement = aValue.getBool(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->aLocalTypeName = aValue.getString(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->nMinimumScale = aValue.getInt16(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->nMaximumScale = aValue.getInt16(); + nPos = 18; + aValue.fill(nPos,aTypes[nPos],xRow); + m_pTypeInfo->nNumPrecRadix = aValue.getInt32(); + + // check if values are less than zero like it happens in a oracle jdbc driver + if( m_pTypeInfo->nPrecision < 0) + m_pTypeInfo->nPrecision = 0; + if( m_pTypeInfo->nMinimumScale < 0) + m_pTypeInfo->nMinimumScale = 0; + if( m_pTypeInfo->nMaximumScale < 0) + m_pTypeInfo->nMaximumScale = 0; + if( m_pTypeInfo->nNumPrecRadix <= 1) + m_pTypeInfo->nNumPrecRadix = 10; + break; + } + } + } + if ( !m_pTypeInfo ) + m_pTypeInfo = std::make_shared<OTypeInfo>(); +} + +ODatabaseExport::~ODatabaseExport() +{ + m_pFormatter = nullptr; + for (auto const& destColumn : m_aDestColumns) + delete destColumn.second; + m_vDestVector.clear(); + m_aDestColumns.clear(); +} + +void ODatabaseExport::insertValueIntoColumn() +{ + if(m_nColumnPos >= sal_Int32(m_vDestVector.size())) + return; + + OFieldDescription* pField = m_vDestVector[m_nColumnPos]->second; + if(!pField) + return; + + sal_Int32 nNewPos = m_bIsAutoIncrement ? m_nColumnPos+1 : m_nColumnPos; + OSL_ENSURE(nNewPos < static_cast<sal_Int32>(m_vColumnPositions.size()),"m_vColumnPositions: Illegal index for vector"); + + if ( nNewPos < static_cast<sal_Int32>(m_vColumnPositions.size() ) ) + { + sal_Int32 nPos = m_vColumnPositions[nNewPos].first; + if ( nPos != COLUMN_POSITION_NOT_FOUND ) + { + if ( m_sTextToken.isEmpty() && pField->IsNullable() ) + m_pUpdateHelper->updateNull(nPos,pField->GetType()); + else + { + OSL_ENSURE((nNewPos) < static_cast<sal_Int32>(m_vColumnTypes.size()),"Illegal index for vector"); + if (m_vColumnTypes[nNewPos] != DataType::VARCHAR && m_vColumnTypes[nNewPos] != DataType::CHAR && m_vColumnTypes[nNewPos] != DataType::LONGVARCHAR ) + { + SAL_INFO("dbaccess.ui", "ODatabaseExport::insertValueIntoColumn != DataType::VARCHAR" ); + ensureFormatter(); + sal_Int32 nNumberFormat = 0; + double fOutNumber = 0.0; + bool bNumberFormatError = false; + if ( m_pFormatter && !m_sNumToken.isEmpty() ) + { + LanguageType eNumLang = LANGUAGE_NONE; + sal_uInt32 nNumberFormat2( nNumberFormat ); + fOutNumber = SfxHTMLParser::GetTableDataOptionsValNum(nNumberFormat2,eNumLang,m_sTextToken,m_sNumToken,*m_pFormatter); + if ( eNumLang != LANGUAGE_NONE ) + { + nNumberFormat2 = m_pFormatter->GetFormatForLanguageIfBuiltIn( nNumberFormat2, eNumLang ); + (void)m_pFormatter->IsNumberFormat( m_sTextToken, nNumberFormat2, fOutNumber ); + } + nNumberFormat = static_cast<sal_Int32>(nNumberFormat2); + } + else + { + Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier(); + Reference<XNumberFormatTypes> xNumType(xSupplier->getNumberFormats(),UNO_QUERY); + const sal_Int16 nFormats[] = { + NumberFormat::DATETIME + ,NumberFormat::DATE + ,NumberFormat::TIME + ,NumberFormat::CURRENCY + ,NumberFormat::NUMBER + ,NumberFormat::LOGICAL + }; + for (short nFormat : nFormats) + { + try + { + nNumberFormat = m_xFormatter->detectNumberFormat(xNumType->getStandardFormat(nFormat,m_aLocale),m_sTextToken); + break; + } + catch(Exception&) + { + } + } + try + { + fOutNumber = m_xFormatter->convertStringToNumber(nNumberFormat,m_sTextToken); + } + catch(Exception&) + { + bNumberFormatError = true; + m_pUpdateHelper->updateString(nPos,m_sTextToken); + } + } + if ( !bNumberFormatError ) + { + try + { + Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier(); + Reference< XNumberFormats > xFormats = xSupplier->getNumberFormats(); + Reference<XPropertySet> xProp = xFormats->getByKey(nNumberFormat); + sal_Int16 nType = 0; + xProp->getPropertyValue(PROPERTY_TYPE) >>= nType; + switch(nType) + { + case NumberFormat::DATE: + m_pUpdateHelper->updateDate(nPos,::dbtools::DBTypeConversion::toDate(fOutNumber,m_aNullDate)); + break; + case NumberFormat::DATETIME: + m_pUpdateHelper->updateTimestamp(nPos,::dbtools::DBTypeConversion::toDateTime(fOutNumber,m_aNullDate)); + break; + case NumberFormat::TIME: + m_pUpdateHelper->updateTime(nPos,::dbtools::DBTypeConversion::toTime(fOutNumber)); + break; + default: + m_pUpdateHelper->updateDouble(nPos,fOutNumber); + } + } + catch(Exception&) + { + m_pUpdateHelper->updateString(nPos,m_sTextToken); + } + } + + } + else + m_pUpdateHelper->updateString(nPos,m_sTextToken); + } + } + } + eraseTokens(); +} + +sal_Int16 ODatabaseExport::CheckString(const OUString& aCheckToken, sal_Int16 _nOldNumberFormat) +{ + sal_Int16 nNumberFormat = 0; + + try + { + Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier(); + Reference< XNumberFormats > xFormats = xSupplier->getNumberFormats(); + + ensureFormatter(); + if ( m_pFormatter && !m_sNumToken.isEmpty() ) + { + LanguageType eNumLang; + sal_uInt32 nFormatKey(0); + double fOutNumber = SfxHTMLParser::GetTableDataOptionsValNum(nFormatKey,eNumLang,m_sTextToken,m_sNumToken,*m_pFormatter); + if ( eNumLang != LANGUAGE_NONE ) + { + nFormatKey = m_pFormatter->GetFormatForLanguageIfBuiltIn( nFormatKey, eNumLang ); + if ( !m_pFormatter->IsNumberFormat( m_sTextToken, nFormatKey, fOutNumber ) ) + return NumberFormat::TEXT; + } + Reference<XPropertySet> xProp = xFormats->getByKey(nFormatKey); + xProp->getPropertyValue(PROPERTY_TYPE) >>= nNumberFormat; + } + else + { + Reference<XNumberFormatTypes> xNumType(xFormats,UNO_QUERY); + sal_Int32 nFormatKey = m_xFormatter->detectNumberFormat(xNumType->getStandardFormat(NumberFormat::ALL,m_aLocale),aCheckToken); + m_xFormatter->convertStringToNumber(nFormatKey,aCheckToken); + + Reference<XPropertySet> xProp = xFormats->getByKey(nFormatKey); + sal_Int16 nType = 0; + xProp->getPropertyValue(PROPERTY_TYPE) >>= nType; + + switch(nType) + { + case NumberFormat::ALL: + nNumberFormat = NumberFormat::ALL; + break; + case NumberFormat::DEFINED: + nNumberFormat = NumberFormat::TEXT; + break; + case NumberFormat::DATE: + switch(_nOldNumberFormat) + { + case NumberFormat::DATETIME: + case NumberFormat::TEXT: + case NumberFormat::DATE: + nNumberFormat = _nOldNumberFormat; + break; + case NumberFormat::ALL: + nNumberFormat = NumberFormat::DATE; + break; + default: + nNumberFormat = NumberFormat::TEXT; + + } + break; + case NumberFormat::TIME: + switch(_nOldNumberFormat) + { + case NumberFormat::DATETIME: + case NumberFormat::TEXT: + case NumberFormat::TIME: + nNumberFormat = _nOldNumberFormat; + break; + case NumberFormat::ALL: + nNumberFormat = NumberFormat::TIME; + break; + default: + nNumberFormat = NumberFormat::TEXT; + break; + } + break; + case NumberFormat::CURRENCY: + switch(_nOldNumberFormat) + { + case NumberFormat::NUMBER: + nNumberFormat = NumberFormat::CURRENCY; + break; + case NumberFormat::CURRENCY: + nNumberFormat = _nOldNumberFormat; + break; + case NumberFormat::ALL: + nNumberFormat = NumberFormat::CURRENCY; + break; + default: + nNumberFormat = NumberFormat::TEXT; + break; + } + break; + case NumberFormat::NUMBER: + case NumberFormat::SCIENTIFIC: + case NumberFormat::FRACTION: + case NumberFormat::PERCENT: + switch(_nOldNumberFormat) + { + case NumberFormat::NUMBER: + nNumberFormat = _nOldNumberFormat; + break; + case NumberFormat::CURRENCY: + nNumberFormat = NumberFormat::CURRENCY; + break; + case NumberFormat::ALL: + nNumberFormat = nType; + break; + default: + nNumberFormat = NumberFormat::TEXT; + break; + } + break; + case NumberFormat::TEXT: + case NumberFormat::UNDEFINED: + case NumberFormat::LOGICAL: + nNumberFormat = NumberFormat::TEXT; // Text overwrites everything + break; + case NumberFormat::DATETIME: + switch(_nOldNumberFormat) + { + case NumberFormat::DATETIME: + case NumberFormat::TEXT: + case NumberFormat::TIME: + nNumberFormat = _nOldNumberFormat; + break; + case NumberFormat::ALL: + nNumberFormat = NumberFormat::DATETIME; + break; + default: + nNumberFormat = NumberFormat::TEXT; + break; + } + break; + default: + SAL_WARN("dbaccess.ui", "ODatabaseExport: Unknown NumberFormat"); + } + } + } + catch(Exception&) + { + nNumberFormat = NumberFormat::TEXT; // Text overwrites everything + } + + return nNumberFormat; +} + +void ODatabaseExport::SetColumnTypes(const TColumnVector* _pList,const OTypeInfoMap* _pInfoMap) +{ + if(!(_pList && _pInfoMap)) + return; + + OSL_ENSURE(m_vNumberFormat.size() == m_vColumnSize.size() && m_vColumnSize.size() == _pList->size(),"Illegal columns in list"); + Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier(); + Reference< XNumberFormats > xFormats = xSupplier->getNumberFormats(); + sal_Int32 minBothSize = std::min<sal_Int32>(m_vNumberFormat.size(), m_vColumnSize.size()); + sal_Int32 i = 0; + for (auto const& elem : *_pList) + { + if (i >= minBothSize) + break; + + sal_Int32 nDataType; + sal_Int32 nLength(0),nScale(0); + sal_Int16 nType = m_vNumberFormat[i] & ~NumberFormat::DEFINED; + + switch ( nType ) + { + case NumberFormat::ALL: + nDataType = DataType::DOUBLE; + break; + case NumberFormat::DEFINED: + nDataType = DataType::VARCHAR; + nLength = ((m_vColumnSize[i] % 10 ) ? m_vColumnSize[i]/ 10 + 1: m_vColumnSize[i]/ 10) * 10; + break; + case NumberFormat::DATE: + nDataType = DataType::DATE; + break; + case NumberFormat::TIME: + nDataType = DataType::TIME; + break; + case NumberFormat::DATETIME: + nDataType = DataType::TIMESTAMP; + break; + case NumberFormat::CURRENCY: + nDataType = DataType::NUMERIC; + nScale = 4; + nLength = 19; + break; + case NumberFormat::NUMBER: + case NumberFormat::SCIENTIFIC: + case NumberFormat::FRACTION: + case NumberFormat::PERCENT: + nDataType = DataType::DOUBLE; + break; + case NumberFormat::TEXT: + case NumberFormat::UNDEFINED: + case NumberFormat::LOGICAL: + default: + nDataType = DataType::VARCHAR; + nLength = ((m_vColumnSize[i] % 10 ) ? m_vColumnSize[i]/ 10 + 1: m_vColumnSize[i]/ 10) * 10; + break; + } + OTypeInfoMap::const_iterator aFind = _pInfoMap->find(nDataType); + if(aFind != _pInfoMap->end()) + { + elem->second->SetType(aFind->second); + elem->second->SetPrecision(std::min<sal_Int32>(aFind->second->nPrecision,nLength)); + elem->second->SetScale(std::min<sal_Int32>(aFind->second->nMaximumScale,nScale)); + + sal_Int32 nFormatKey = ::dbtools::getDefaultNumberFormat( nDataType, + elem->second->GetScale(), + elem->second->IsCurrency(), + Reference< XNumberFormatTypes>(xFormats,UNO_QUERY), + m_aLocale); + + elem->second->SetFormatKey(nFormatKey); + } + ++i; + } +} + +void ODatabaseExport::CreateDefaultColumn(const OUString& _rColumnName) +{ + Reference< XDatabaseMetaData> xDestMetaData(m_xConnection->getMetaData()); + sal_Int32 nMaxNameLen(xDestMetaData->getMaxColumnNameLength()); + OUString aAlias = _rColumnName; + if ( isSQL92CheckEnabled(m_xConnection) ) + aAlias = ::dbtools::convertName2SQLName(_rColumnName,xDestMetaData->getExtraNameCharacters()); + + if(nMaxNameLen && aAlias.getLength() > nMaxNameLen) + aAlias = aAlias.copy(0, std::min<sal_Int32>( nMaxNameLen-1, aAlias.getLength() ) ); + + OUString sName(aAlias); + if(m_aDestColumns.find(sName) != m_aDestColumns.end()) + { + sal_Int32 nPos = 0; + sal_Int32 nCount = 2; + while(m_aDestColumns.find(sName) != m_aDestColumns.end()) + { + sName = aAlias + + OUString::number(++nPos); + if(nMaxNameLen && sName.getLength() > nMaxNameLen) + { + aAlias = aAlias.copy(0,std::min<sal_Int32>( nMaxNameLen-nCount, aAlias.getLength() )); + sName = aAlias + + OUString::number(nPos); + ++nCount; + } + } + } + aAlias = sName; + // now create a column + OFieldDescription* pField = new OFieldDescription(); + pField->SetType(m_pTypeInfo); + pField->SetName(aAlias); + pField->SetPrecision(std::min<sal_Int32>(sal_Int32(255),m_pTypeInfo->nPrecision)); + pField->SetScale(0); + pField->SetIsNullable(ColumnValue::NULLABLE); + pField->SetAutoIncrement(false); + pField->SetPrimaryKey(false); + pField->SetCurrency(false); + + TColumns::const_iterator aFind = m_aDestColumns.find( aAlias ); + if ( aFind != m_aDestColumns.end() ) + { + delete aFind->second; + m_aDestColumns.erase(aFind); + } + + m_vDestVector.emplace_back(m_aDestColumns.emplace(aAlias,pField).first); +} + +void ODatabaseExport::createRowSet() +{ + m_pUpdateHelper = std::make_shared<OParameterUpdateHelper>(createPreparedStatment(m_xConnection->getMetaData(),m_xTable,m_vColumnPositions)); +} + +bool ODatabaseExport::executeWizard(const OUString& _rTableName, const Any& _aTextColor, const FontDescriptor& _rFont) +{ + bool bHaveDefaultTable = !m_sDefaultTableName.isEmpty(); + OUString sTableName( bHaveDefaultTable ? m_sDefaultTableName : _rTableName ); + OCopyTableWizard aWizard( + nullptr, + sTableName, + bHaveDefaultTable ? CopyTableOperation::AppendData : CopyTableOperation::CopyDefinitionAndData, + ODatabaseExport::TColumns(m_aDestColumns), + m_vDestVector, + m_xConnection, + m_xFormatter, + getTypeSelectionPageFactory(), + m_rInputStream, + m_xContext + ); + + bool bError = false; + try + { + if (aWizard.run()) + { + switch(aWizard.getOperation()) + { + case CopyTableOperation::CopyDefinitionAndData: + case CopyTableOperation::AppendData: + { + m_xTable = aWizard.returnTable(); + bError = !m_xTable.is(); + if(m_xTable.is()) + { + m_xTable->setPropertyValue(PROPERTY_FONT,Any(_rFont)); + if(_aTextColor.hasValue()) + m_xTable->setPropertyValue(PROPERTY_TEXTCOLOR,_aTextColor); + } + m_bIsAutoIncrement = aWizard.shouldCreatePrimaryKey(); + m_vColumnPositions = aWizard.GetColumnPositions(); + m_vColumnTypes = aWizard.GetColumnTypes(); + m_bAppendFirstLine = !aWizard.UseHeaderLine(); + } + break; + default: + bError = true; // there is no error but I have nothing more to do + } + } + else + bError = true; + + if(!bError) + createRowSet(); + } + catch( const SQLException&) + { + ::dbtools::showError( ::dbtools::SQLExceptionInfo( ::cppu::getCaughtException() ), aWizard.getDialog()->GetXWindow(), m_xContext ); + bError = true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return bError; +} + +void ODatabaseExport::showErrorDialog(const css::sdbc::SQLException& e) +{ + if(!m_bDontAskAgain) + { + OUString aMsg = e.Message + + "\n" + + DBA_RES( STR_QRY_CONTINUE ); + OSQLWarningBox aBox(nullptr, aMsg, MessBoxStyle::YesNo | MessBoxStyle::DefaultNo); + + if (aBox.run() == RET_YES) + m_bDontAskAgain = true; + else + m_bError = true; + } +} + +void ODatabaseExport::adjustFormat() +{ + if ( m_sTextToken.isEmpty() ) + return; + + sal_Int32 nNewPos = m_bIsAutoIncrement ? m_nColumnPos+1 : m_nColumnPos; + OSL_ENSURE(nNewPos < static_cast<sal_Int32>(m_vColumnPositions.size()),"Illegal index for vector"); + if ( nNewPos < static_cast<sal_Int32>(m_vColumnPositions.size()) ) + { + sal_Int32 nColPos = m_vColumnPositions[nNewPos].first; + if( nColPos != COLUMN_POSITION_NOT_FOUND) + { + --nColPos; + OSL_ENSURE((nColPos) < static_cast<sal_Int32>(m_vNumberFormat.size()),"m_vFormatKey: Illegal index for vector"); + OSL_ENSURE((nColPos) < static_cast<sal_Int32>(m_vColumnSize.size()),"m_vColumnSize: Illegal index for vector"); + m_vNumberFormat[nColPos] = CheckString(m_sTextToken,m_vNumberFormat[nColPos]); + m_vColumnSize[nColPos] = std::max<sal_Int32>(static_cast<sal_Int32>(m_vColumnSize[nColPos]), m_sTextToken.getLength()); + } + } + eraseTokens(); +} + +void ODatabaseExport::eraseTokens() +{ + m_sTextToken.clear(); + m_sNumToken.clear(); +} + +void ODatabaseExport::ensureFormatter() +{ + if ( !m_pFormatter ) + { + Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier(); + auto pSupplierImpl = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(xSupplier); + m_pFormatter = pSupplierImpl ? pSupplierImpl->GetNumberFormatter() : nullptr; + Reference<XPropertySet> xNumberFormatSettings = xSupplier->getNumberFormatSettings(); + xNumberFormatSettings->getPropertyValue("NullDate") >>= m_aNullDate; + } +} + +Reference< XPreparedStatement > ODatabaseExport::createPreparedStatment( const Reference<XDatabaseMetaData>& _xMetaData + ,const Reference<XPropertySet>& _xDestTable + ,const TPositions& _rvColumns) +{ + OUString sComposedTableName = ::dbtools::composeTableName( _xMetaData, _xDestTable, ::dbtools::EComposeRule::InDataManipulation, true ); + + OUStringBuffer aSql = "INSERT INTO " + + sComposedTableName + + " ( "; + + // set values and column names + OUStringBuffer aValues(" VALUES ( "); + + OUString aQuote; + if ( _xMetaData.is() ) + aQuote = _xMetaData->getIdentifierQuoteString(); + + Reference<XColumnsSupplier> xDestColsSup(_xDestTable,UNO_QUERY_THROW); + + // create sql string and set column types + Sequence< OUString> aDestColumnNames = xDestColsSup->getColumns()->getElementNames(); + if ( !aDestColumnNames.hasElements() ) + { + return Reference< XPreparedStatement > (); + } + const OUString* pIter = aDestColumnNames.getConstArray(); + std::vector< OUString> aInsertList; + aInsertList.resize(aDestColumnNames.getLength()+1); + for(size_t j=0; j < aInsertList.size(); ++j) + { + ODatabaseExport::TPositions::const_iterator aFind = std::find_if(_rvColumns.begin(),_rvColumns.end(), + [j] (const ODatabaseExport::TPositions::value_type& tPos) + { return tPos.second == static_cast<sal_Int32>(j+1); }); + if ( _rvColumns.end() != aFind && aFind->second != COLUMN_POSITION_NOT_FOUND && aFind->first != COLUMN_POSITION_NOT_FOUND ) + { + OSL_ENSURE((aFind->first) < static_cast<sal_Int32>(aInsertList.size()),"aInsertList: Illegal index for vector"); + aInsertList[aFind->first] = ::dbtools::quoteName( aQuote,*(pIter+j)); + } + } + + // create the sql string + for (auto const& elem : aInsertList) + { + if ( !elem.isEmpty() ) + { + aSql.append(elem); + aSql.append(","); + aValues.append("?,"); + } + } + + aSql[aSql.getLength()-1] = ')'; + aValues[aValues.getLength()-1] = ')'; + + aSql.append(aValues); + // now create,fill and execute the prepared statement + return _xMetaData->getConnection()->prepareStatement(aSql.makeStringAndClear()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/HtmlReader.cxx b/dbaccess/source/ui/misc/HtmlReader.cxx new file mode 100644 index 000000000..c2917a630 --- /dev/null +++ b/dbaccess/source/ui/misc/HtmlReader.cxx @@ -0,0 +1,481 @@ +/* -*- 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 <HtmlReader.hxx> +#include <connectivity/dbtools.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/stream.hxx> +#include <tools/tenccvt.hxx> +#include <comphelper/string.hxx> +#include <strings.hrc> +#include <osl/diagnose.h> +#include <core_resource.hxx> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/awt/FontStrikeout.hpp> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/FontUnderline.hpp> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <tools/color.hxx> +#include <WExtendPages.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> + +using namespace dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::awt; + +#define DBAUI_HTML_FONTSIZES 8 // like export, HTML-Options + +// OHTMLReader +OHTMLReader::OHTMLReader(SvStream& rIn,const SharedConnection& _rxConnection, + const Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext) + : HTMLParser(rIn) + , ODatabaseExport( _rxConnection, _rxNumberF, _rxContext, rIn ) + , m_nTableCount(0) + , m_nColumnWidth(87) +{ + SetSrcEncoding( GetExtendedCompatibilityTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) ); + // If the file starts with a BOM, switch to UCS2. + SetSwitchToUCS2( true ); +} + +OHTMLReader::OHTMLReader(SvStream& rIn, + sal_Int32 nRows, + TPositions&& _rColumnPositions, + const Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const TColumnVector* pList, + const OTypeInfoMap* _pInfoMap, + bool _bAutoIncrementEnabled) + : HTMLParser(rIn) + , ODatabaseExport( nRows, std::move(_rColumnPositions), _rxNumberF, _rxContext, pList, _pInfoMap, _bAutoIncrementEnabled, rIn ) + , m_nTableCount(0) + , m_nColumnWidth(87) +{ + SetSrcEncoding( GetExtendedCompatibilityTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) ); + // If the file starts with a BOM, switch to UCS2. + SetSwitchToUCS2( true ); +} + +OHTMLReader::~OHTMLReader() +{ +} + +SvParserState OHTMLReader::CallParser() +{ + rInput.Seek(STREAM_SEEK_TO_BEGIN); + rInput.ResetError(); + SvParserState eParseState = HTMLParser::CallParser(); + SetColumnTypes(m_pColumnList,m_pInfoMap); + return m_bFoundTable ? eParseState : SvParserState::Error; +} + +#if defined _MSC_VER +#pragma warning(disable: 4702) // unreachable code, bug in MSVC2015 +#endif +void OHTMLReader::NextToken( HtmlTokenId nToken ) +{ + if(m_bError || !m_nRows) // if there is an error or no more rows to check, return immediately + return; + if ( nToken == HtmlTokenId::META ) + setTextEncoding(); + + if(m_xConnection.is()) // names, which CTOR was called and hence, if a table should be created + { + switch(nToken) + { + case HtmlTokenId::TABLE_ON: + ++m_nTableCount; + { // can also be TD or TH, if there was no TABLE before + const HTMLOptions& rHtmlOptions = GetOptions(); + for (const auto & rOption : rHtmlOptions) + { + if( rOption.GetToken() == HtmlOptionId::WIDTH ) + { // percentage: of document width respectively outer cell + m_nColumnWidth = GetWidthPixel( rOption ); + } + } + } + [[fallthrough]]; + case HtmlTokenId::THEAD_ON: + case HtmlTokenId::TBODY_ON: + { + sal_uInt64 const nTell = rInput.Tell(); // perhaps alters position of the stream + if ( !m_xTable.is() ) + {// use first line as header + m_bError = !CreateTable(nToken); + if ( m_bAppendFirstLine ) + rInput.Seek(nTell); + } + } + break; + case HtmlTokenId::TABLE_OFF: + if(!--m_nTableCount) + { + m_xTable = nullptr; + } + break; + case HtmlTokenId::TABLEROW_ON: + if ( !m_pUpdateHelper ) + m_bError = true; + break; + case HtmlTokenId::TEXTTOKEN: + case HtmlTokenId::SINGLECHAR: + if ( m_bInTbl ) //&& !m_bSDNum ) // important, as otherwise we also get the names of the fonts + m_sTextToken += aToken; + break; + case HtmlTokenId::PARABREAK_OFF: + m_sCurrent += m_sTextToken; + break; + case HtmlTokenId::PARABREAK_ON: + m_sTextToken.clear(); + break; + case HtmlTokenId::TABLEDATA_ON: + fetchOptions(); + break; + case HtmlTokenId::TABLEDATA_OFF: + { + if ( !m_sCurrent.isEmpty() ) + m_sTextToken = m_sCurrent; + try + { + insertValueIntoColumn(); + } + catch(SQLException& e) + // handling update failure + { + showErrorDialog(e); + } + m_sCurrent.clear(); + m_nColumnPos++; + eraseTokens(); + m_bInTbl = false; + } + break; + case HtmlTokenId::TABLEROW_OFF: + if ( !m_pUpdateHelper ) + { + m_bError = true; + break; + } + try + { + m_nRowCount++; + if (m_bIsAutoIncrement) // if bSetAutoIncrement then I have to set the autoincrement + m_pUpdateHelper->updateInt(1,m_nRowCount); + m_pUpdateHelper->insertRow(); + } + catch(SQLException& e) + // handling update failure + { + showErrorDialog(e); + } + m_nColumnPos = 0; + break; + default: break; + } + } + else // branch only valid for type checking + { + switch(nToken) + { + case HtmlTokenId::THEAD_ON: + case HtmlTokenId::TBODY_ON: + // The head of the column is not included + if(m_bHead) + { + do + {} + while(GetNextToken() != HtmlTokenId::TABLEROW_OFF); + m_bHead = false; + } + break; + case HtmlTokenId::TABLEDATA_ON: + case HtmlTokenId::TABLEHEADER_ON: + fetchOptions(); + break; + case HtmlTokenId::TEXTTOKEN: + case HtmlTokenId::SINGLECHAR: + if ( m_bInTbl ) // && !m_bSDNum ) // important, as otherwise we also get the names of the fonts + m_sTextToken += aToken; + break; + case HtmlTokenId::PARABREAK_OFF: + m_sCurrent += m_sTextToken; + break; + case HtmlTokenId::PARABREAK_ON: + m_sTextToken.clear(); + break; + case HtmlTokenId::TABLEDATA_OFF: + if ( !m_sCurrent.isEmpty() ) + m_sTextToken = m_sCurrent; + adjustFormat(); + m_nColumnPos++; + m_bInTbl = false; + m_sCurrent.clear(); + break; + case HtmlTokenId::TABLEROW_OFF: + if ( !m_sCurrent.isEmpty() ) + m_sTextToken = m_sCurrent; + adjustFormat(); + m_nColumnPos = 0; + m_nRows--; + m_sCurrent.clear(); + break; + default: break; + } + } +} + +void OHTMLReader::fetchOptions() +{ + m_bInTbl = true; + const HTMLOptions& options = GetOptions(); + for (const auto & rOption : options) + { + switch( rOption.GetToken() ) + { + case HtmlOptionId::SDNUM: + m_sNumToken = rOption.GetString(); + break; + default: break; + } + } +} + +void OHTMLReader::TableDataOn(SvxCellHorJustify& eVal) +{ + const HTMLOptions& rHtmlOptions = GetOptions(); + for (const auto & rOption : rHtmlOptions) + { + switch( rOption.GetToken() ) + { + case HtmlOptionId::ALIGN: + { + const OUString& rOptVal = rOption.GetString(); + if (rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_right )) + eVal = SvxCellHorJustify::Right; + else if (rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_center )) + eVal = SvxCellHorJustify::Center; + else if (rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_left )) + eVal = SvxCellHorJustify::Left; + else + eVal = SvxCellHorJustify::Standard; + } + break; + default: break; + } + } +} + +void OHTMLReader::TableFontOn(FontDescriptor& _rFont, Color &_rTextColor) +{ + const HTMLOptions& rHtmlOptions = GetOptions(); + for (const auto & rOption : rHtmlOptions) + { + switch( rOption.GetToken() ) + { + case HtmlOptionId::COLOR: + { + Color aColor; + rOption.GetColor( aColor ); + _rTextColor = aColor.GetRGBColor(); + } + break; + case HtmlOptionId::FACE : + { + const OUString& rFace = rOption.GetString(); + OUStringBuffer aFontName; + sal_Int32 nPos = 0; + while( nPos != -1 ) + { + // list of fonts, VCL: semicolon as separator, HTML: comma + std::u16string_view aFName = o3tl::getToken(rFace, 0, ',', nPos ); + aFName = comphelper::string::strip(aFName, ' '); + if( !aFontName.isEmpty() ) + aFontName.append(";"); + aFontName.append(aFName); + } + if ( !aFontName.isEmpty() ) + _rFont.Name = aFontName.makeStringAndClear(); + } + break; + case HtmlOptionId::SIZE : + { + sal_Int16 nSize = static_cast<sal_Int16>(rOption.GetNumber()); + if ( nSize == 0 ) + nSize = 1; + else if ( nSize < DBAUI_HTML_FONTSIZES ) + nSize = DBAUI_HTML_FONTSIZES; + + _rFont.Height = nSize; + } + break; + default: break; + } + } +} + +sal_Int16 OHTMLReader::GetWidthPixel( const HTMLOption& rOption ) +{ + const OUString& rOptVal = rOption.GetString(); + if ( rOptVal.indexOf('%') != -1 ) + { // percentage + OSL_ENSURE( m_nColumnWidth, "WIDTH Option: m_nColumnWidth==0 and Width%" ); + return static_cast<sal_Int16>((rOption.GetNumber() * m_nColumnWidth) / 100); + } + else + { + if ( rOptVal.indexOf('*') != -1 ) + { // relative to what?!? +//TODO: collect ColArray of all relevant values and then MakeCol + return 0; + } + else + return static_cast<sal_Int16>(rOption.GetNumber()); // pixel + } +} + +bool OHTMLReader::CreateTable(HtmlTokenId nToken) +{ + OUString aTempName(DBA_RES(STR_TBL_TITLE)); + aTempName = aTempName.getToken(0,' '); + aTempName = ::dbtools::createUniqueName(m_xTables, aTempName); + + bool bCaption = false; + bool bTableHeader = false; + OUString aColumnName; + SvxCellHorJustify eVal; + + OUString aTableName; + FontDescriptor aFont = VCLUnoHelper::CreateFontDescriptor(Application::GetSettings().GetStyleSettings().GetAppFont()); + Color nTextColor; + do + { + switch (nToken) + { + case HtmlTokenId::TEXTTOKEN: + case HtmlTokenId::SINGLECHAR: + if(bTableHeader) + aColumnName += aToken; + if(bCaption) + aTableName += aToken; + break; + case HtmlTokenId::PARABREAK_OFF: + m_sCurrent += aColumnName; + break; + case HtmlTokenId::PARABREAK_ON: + m_sTextToken.clear(); + break; + case HtmlTokenId::TABLEDATA_ON: + case HtmlTokenId::TABLEHEADER_ON: + TableDataOn(eVal); + bTableHeader = true; + break; + case HtmlTokenId::TABLEDATA_OFF: + case HtmlTokenId::TABLEHEADER_OFF: + { + aColumnName = comphelper::string::strip(aColumnName, ' ' ); + if (aColumnName.isEmpty() || m_bAppendFirstLine ) + aColumnName = DBA_RES(STR_COLUMN_NAME); + else if ( !m_sCurrent.isEmpty() ) + aColumnName = m_sCurrent; + + aColumnName = comphelper::string::strip(aColumnName, ' '); + CreateDefaultColumn(aColumnName); + aColumnName.clear(); + m_sCurrent.clear(); + + eVal = SvxCellHorJustify::Standard; + bTableHeader = false; + } + break; + + case HtmlTokenId::TITLE_ON: + case HtmlTokenId::CAPTION_ON: + bCaption = true; + break; + case HtmlTokenId::TITLE_OFF: + case HtmlTokenId::CAPTION_OFF: + aTableName = comphelper::string::strip(aTableName, ' '); + if(aTableName.isEmpty()) + aTableName = ::dbtools::createUniqueName(m_xTables, aTableName); + else + aTableName = aTempName; + bCaption = false; + break; + case HtmlTokenId::FONT_ON: + TableFontOn(aFont,nTextColor); + break; + case HtmlTokenId::BOLD_ON: + aFont.Weight = css::awt::FontWeight::BOLD; + break; + case HtmlTokenId::ITALIC_ON: + aFont.Slant = css::awt::FontSlant_ITALIC; + break; + case HtmlTokenId::UNDERLINE_ON: + aFont.Underline = css::awt::FontUnderline::SINGLE; + break; + case HtmlTokenId::STRIKE_ON: + aFont.Strikeout = css::awt::FontStrikeout::SINGLE; + break; + default: break; + } + nToken = GetNextToken(); + } + while (nToken != HtmlTokenId::TABLEROW_OFF); + + if ( !m_sCurrent.isEmpty() ) + aColumnName = m_sCurrent; + aColumnName = comphelper::string::strip(aColumnName, ' '); + if(!aColumnName.isEmpty()) + CreateDefaultColumn(aColumnName); + + if ( m_vDestVector.empty() ) + return false; + + if(aTableName.isEmpty()) + aTableName = aTempName; + + m_bInTbl = false; + m_bFoundTable = true; + + if ( isCheckEnabled() ) + return true; + + return !executeWizard(aTableName,Any(nTextColor),aFont) && m_xTable.is(); +} + +void OHTMLReader::setTextEncoding() +{ + ParseMetaOptions(nullptr, nullptr); +} + +TypeSelectionPageFactory OHTMLReader::getTypeSelectionPageFactory() +{ + return &OWizHTMLExtend::Create; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/RowSetDrop.cxx b/dbaccess/source/ui/misc/RowSetDrop.cxx new file mode 100644 index 000000000..065fee9ce --- /dev/null +++ b/dbaccess/source/ui/misc/RowSetDrop.cxx @@ -0,0 +1,247 @@ + +/* -*- 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 <DExport.hxx> +#include <TokenWriter.hxx> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <core_resource.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <sqlmessage.hxx> +#include <com/sun/star/sdbc/XRowUpdate.hpp> + +using namespace dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::lang; + +// export data +ORowSetImportExport::ORowSetImportExport(weld::Window* pParent, + const Reference< XResultSetUpdate >& xResultSetUpdate, + const svx::ODataAccessDescriptor& aDataDescriptor, + const Reference< XComponentContext >& rM) + : ODatabaseImportExport(aDataDescriptor,rM,nullptr) + ,m_xTargetResultSetUpdate(xResultSetUpdate) + ,m_xTargetRowUpdate(xResultSetUpdate,UNO_QUERY) + ,m_pParent(pParent) + ,m_bAlreadyAsked(false) +{ + OSL_ENSURE(pParent,"Window can't be null!"); +} + +void ORowSetImportExport::initialize() +{ + ODatabaseImportExport::initialize(); + // do namemapping + Reference<XColumnLocate> xColumnLocate(m_xResultSet,UNO_QUERY); + OSL_ENSURE(xColumnLocate.is(),"The rowset normally should support this"); + + m_xTargetResultSetMetaData = Reference<XResultSetMetaDataSupplier>(m_xTargetResultSetUpdate,UNO_QUERY_THROW)->getMetaData(); + if(!m_xTargetResultSetMetaData.is() || !xColumnLocate.is() || !m_xResultSetMetaData.is() ) + throw SQLException(DBA_RES(STR_UNEXPECTED_ERROR),*this,"S1000",0,Any()); + + sal_Int32 nCount = m_xTargetResultSetMetaData->getColumnCount(); + m_aColumnMapping.reserve(nCount); + m_aColumnTypes.reserve(nCount); + for (sal_Int32 i = 1;i <= nCount; ++i) + { + sal_Int32 nPos = COLUMN_POSITION_NOT_FOUND; // means column is autoincrement or doesn't exist + if(!m_xTargetResultSetMetaData->isAutoIncrement(i)) + { + try + { + OUString sColumnName = m_xTargetResultSetMetaData->getColumnName(i); + nPos = xColumnLocate->findColumn(sColumnName); + } + catch(const SQLException&) + { + if(m_xTargetResultSetMetaData->isNullable(i)) + nPos = 0; // column doesn't exist but we could set it to null + } + } + + m_aColumnMapping.push_back(nPos); + if(nPos > 0) + m_aColumnTypes.push_back(m_xResultSetMetaData->getColumnType(nPos)); + else + m_aColumnTypes.push_back(DataType::OTHER); + } +} + +bool ORowSetImportExport::Write() +{ + return true; +} + +bool ORowSetImportExport::Read() +{ + // check if there is any column to copy + if(std::none_of(m_aColumnMapping.begin(),m_aColumnMapping.end(), + [](sal_Int32 n) { return n > 0; })) + return false; + bool bContinue = true; + if(m_aSelection.hasElements()) + { + const Any* pBegin = m_aSelection.getConstArray(); + const Any* pEnd = pBegin + m_aSelection.getLength(); + for(;pBegin != pEnd && bContinue;++pBegin) + { + sal_Int32 nPos = -1; + *pBegin >>= nPos; + OSL_ENSURE(nPos != -1,"Invalid position!"); + bContinue = (m_xResultSet.is() && m_xResultSet->absolute(nPos) && insertNewRow()); + } + } + else + { + Reference<XPropertySet> xProp(m_xResultSet,UNO_QUERY); + sal_Int32 nRowCount = 0; + if ( xProp.is() && xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_ISROWCOUNTFINAL) ) + { + bool bFinal = false; + xProp->getPropertyValue(PROPERTY_ISROWCOUNTFINAL) >>= bFinal; + if ( !bFinal ) + m_xResultSet->afterLast(); + xProp->getPropertyValue(PROPERTY_ROWCOUNT) >>= nRowCount; + } + if ( !nRowCount ) + { + m_xResultSet->afterLast(); + nRowCount = m_xResultSet->getRow(); + } + OSL_ENSURE(nRowCount,"RowCount is 0!"); + m_xResultSet->beforeFirst(); + while(m_xResultSet.is() && m_xResultSet->next() && bContinue && nRowCount ) + { + --nRowCount; + bContinue = insertNewRow(); + } + } + return true; +} + +bool ORowSetImportExport::insertNewRow() +{ + try + { + m_xTargetResultSetUpdate->moveToInsertRow(); + sal_Int32 i = 1; + for (auto const& column : m_aColumnMapping) + { + if(column > 0) + { + Any aValue; + switch(m_aColumnTypes[i-1]) + { + case DataType::CHAR: + case DataType::VARCHAR: + aValue <<= m_xRow->getString(column); + break; + case DataType::DECIMAL: + case DataType::NUMERIC: + aValue <<= m_xRow->getDouble(column); + break; + case DataType::BIGINT: + aValue <<= m_xRow->getLong(column); + break; + case DataType::FLOAT: + aValue <<= m_xRow->getFloat(column); + break; + case DataType::DOUBLE: + aValue <<= m_xRow->getDouble(column); + break; + case DataType::LONGVARCHAR: + aValue <<= m_xRow->getString(column); + break; + case DataType::LONGVARBINARY: + aValue <<= m_xRow->getBytes(column); + break; + case DataType::DATE: + aValue <<= m_xRow->getDate(column); + break; + case DataType::TIME: + aValue <<= m_xRow->getTime(column); + break; + case DataType::TIMESTAMP: + aValue <<= m_xRow->getTimestamp(column); + break; + case DataType::BIT: + case DataType::BOOLEAN: + aValue <<= m_xRow->getBoolean(column); + break; + case DataType::TINYINT: + aValue <<= m_xRow->getByte(column); + break; + case DataType::SMALLINT: + aValue <<= m_xRow->getShort(column); + break; + case DataType::INTEGER: + aValue <<= m_xRow->getInt(column); + break; + case DataType::REAL: + aValue <<= m_xRow->getDouble(column); + break; + case DataType::BINARY: + case DataType::VARBINARY: + aValue <<= m_xRow->getBytes(column); + break; + case DataType::BLOB: + aValue <<= m_xRow->getBlob(column); + break; + case DataType::CLOB: + aValue <<= m_xRow->getClob(column); + break; + default: + SAL_WARN("dbaccess.ui", "Unknown type"); + } + if(m_xRow->wasNull()) + m_xTargetRowUpdate->updateNull(i); + else + m_xTargetRowUpdate->updateObject(i,aValue); + } + else if(column == 0)//now we have know that we to set this column to null + m_xTargetRowUpdate->updateNull(i); + ++i; + } + m_xTargetResultSetUpdate->insertRow(); + } + catch(const SQLException&) + { + if(!m_bAlreadyAsked) + { + OUString sAskIfContinue = DBA_RES(STR_ERROR_OCCURRED_WHILE_COPYING); + OSQLWarningBox aDlg(m_pParent, sAskIfContinue, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes); + if (aDlg.run() == RET_YES) + m_bAlreadyAsked = true; + else + return false; + } + } + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/RtfReader.cxx b/dbaccess/source/ui/misc/RtfReader.cxx new file mode 100644 index 000000000..8895d494f --- /dev/null +++ b/dbaccess/source/ui/misc/RtfReader.cxx @@ -0,0 +1,309 @@ +/* -*- 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 <RtfReader.hxx> +#include <tools/stream.hxx> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/awt/FontStrikeout.hpp> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/FontUnderline.hpp> +#include <core_resource.hxx> +#include <svtools/rtftoken.h> +#include <toolkit/helper/vclunohelper.hxx> +#include <strings.hrc> +#include <connectivity/dbtools.hxx> +#include <comphelper/string.hxx> +#include <tools/color.hxx> +#include <WExtendPages.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> + +using namespace dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::awt; + +// ORTFReader +ORTFReader::ORTFReader( SvStream& rIn, + const SharedConnection& _rxConnection, + const Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext) + :SvRTFParser(rIn) + ,ODatabaseExport( _rxConnection, _rxNumberF, _rxContext, rIn ) +{ + m_bAppendFirstLine = false; +} + +ORTFReader::ORTFReader(SvStream& rIn, + sal_Int32 nRows, + TPositions&& _rColumnPositions, + const Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const TColumnVector* pList, + const OTypeInfoMap* _pInfoMap, + bool _bAutoIncrementEnabled) + :SvRTFParser(rIn) + ,ODatabaseExport( nRows, std::move(_rColumnPositions), _rxNumberF, _rxContext, pList, _pInfoMap, _bAutoIncrementEnabled, rIn ) +{ + m_bAppendFirstLine = false; +} + +ORTFReader::~ORTFReader() +{ +} + +SvParserState ORTFReader::CallParser() +{ + rInput.Seek(STREAM_SEEK_TO_BEGIN); + rInput.ResetError(); + SvParserState eParseState = SvRTFParser::CallParser(); + SetColumnTypes(m_pColumnList,m_pInfoMap); + return m_bFoundTable ? eParseState : SvParserState::Error; +} + +#if defined _MSC_VER +#pragma warning(disable: 4702) // unreachable code, bug in MSVC2015 +#endif + +void ORTFReader::NextToken( int nToken ) +{ + if(m_bError || !m_nRows) // if there is an error or no more rows to check, return immediately + return; + + if(m_xConnection.is()) // names, which CTOR was called and hence, if a table should be created + { + switch(nToken) + { + case RTF_COLORTBL: + { + + int nTmpToken2 = GetNextToken(); + do + { + Color aColor; + do + { + switch(nTmpToken2) + { + case RTF_RED: aColor.SetRed(static_cast<sal_uInt8>(nTokenValue)); break; + case RTF_BLUE: aColor.SetBlue(static_cast<sal_uInt8>(nTokenValue)); break; + case RTF_GREEN: aColor.SetGreen(static_cast<sal_uInt8>(nTokenValue)); break; + default: break; + } + nTmpToken2 = GetNextToken(); + } + while(aToken[0] != ';' && eState != SvParserState::Error && eState != SvParserState::Accepted); + m_vecColor.push_back(aColor.GetRGBColor()); + nTmpToken2 = GetNextToken(); + } + while(nTmpToken2 == RTF_RED && eState != SvParserState::Error && eState != SvParserState::Accepted); + SkipToken(); + } + break; + + case RTF_TROWD: + { + if ( !m_xTable.is() ) // use first line as header + { + sal_uInt64 const nTell = rInput.Tell(); // perhaps alters position of the stream + + m_bError = !CreateTable(nToken); + if ( m_bAppendFirstLine ) + { + rInput.Seek(nTell); + rInput.ResetError(); + } + } + } + break; + case RTF_INTBL: + if(m_bInTbl) + { + eraseTokens(); + } + + m_bInTbl = true; // Now we are in a table description + break; + case RTF_TEXTTOKEN: + case RTF_SINGLECHAR: + if(m_bInTbl) // important, as otherwise we also get the names of the fonts + m_sTextToken += aToken; + break; + case RTF_CELL: + { + try + { + insertValueIntoColumn(); + } + catch(SQLException& e) + // handling update failure + { + showErrorDialog(e); + } + m_nColumnPos++; + eraseTokens(); + } + break; + case RTF_ROW: + // it can happen that the last cell is not concluded with \cell + try + { + insertValueIntoColumn(); + m_nRowCount++; + if(m_bIsAutoIncrement) // if bSetAutoIncrement then I have to set the autoincrement + m_pUpdateHelper->updateInt(1,m_nRowCount); + m_pUpdateHelper->insertRow(); + } + catch(SQLException& e) + // handling update failure + { + showErrorDialog(e); + } + m_nColumnPos = 0; + break; + } + } + else // branch only valid for type checking + { + switch(nToken) + { + case RTF_TROWD: + // The head of the column is not included + if(m_bHead) + { + do + {} + while(GetNextToken() != RTF_ROW && eState != SvParserState::Error && eState != SvParserState::Accepted); + m_bHead = false; + } + break; + case RTF_INTBL: + m_bInTbl = true; + break; + case RTF_TEXTTOKEN: + case RTF_SINGLECHAR: + if(m_bInTbl) + m_sTextToken += aToken; + break; + case RTF_CELL: + adjustFormat(); + m_nColumnPos++; + break; + case RTF_ROW: + adjustFormat(); + m_nColumnPos = 0; + m_nRows--; + break; + } + } +} + +bool ORTFReader::CreateTable(int nToken) +{ + OUString aTableName(DBA_RES(STR_TBL_TITLE)); + aTableName = aTableName.getToken(0,' '); + aTableName = ::dbtools::createUniqueName(m_xTables, aTableName); + + OUString aColumnName; + + FontDescriptor aFont = VCLUnoHelper::CreateFontDescriptor(Application::GetSettings().GetStyleSettings().GetAppFont()); + do + { + switch (nToken) + { + case RTF_UNKNOWNCONTROL: + case RTF_UNKNOWNDATA: + m_bInTbl = false; + aColumnName.clear(); + break; + case RTF_INTBL: + if(m_bInTbl) + aColumnName.clear(); + + m_bInTbl = true; + break; + case RTF_TEXTTOKEN: + case RTF_SINGLECHAR: + if(m_bInTbl) + aColumnName += aToken; + break; + case RTF_CELL: + { + aColumnName = comphelper::string::strip(aColumnName, ' '); + if (aColumnName.isEmpty() || m_bAppendFirstLine ) + aColumnName = DBA_RES(STR_COLUMN_NAME); + + CreateDefaultColumn(aColumnName); + aColumnName.clear(); + } + break; + case RTF_CF: + break; + case RTF_B: + aFont.Weight = css::awt::FontWeight::BOLD; + break; + case RTF_I: + aFont.Slant = css::awt::FontSlant_ITALIC; + break; + case RTF_UL: + aFont.Underline = css::awt::FontUnderline::SINGLE; + break; + case RTF_STRIKE: + aFont.Strikeout = css::awt::FontStrikeout::SINGLE; + break; + } + nToken = GetNextToken(); + } + while(nToken != RTF_TROWD && eState != SvParserState::Error && eState != SvParserState::Accepted); + + bool bOk = !m_vDestVector.empty(); + if(bOk) + { + if ( !aColumnName.isEmpty() ) + { + if ( m_bAppendFirstLine ) + aColumnName = DBA_RES(STR_COLUMN_NAME); + CreateDefaultColumn(aColumnName); + } + + m_bInTbl = false; + m_bFoundTable = true; + + if ( isCheckEnabled() ) + return true; + Any aTextColor; + if(!m_vecColor.empty()) + aTextColor <<= m_vecColor[0]; + + bOk = !executeWizard(aTableName,aTextColor,aFont) && m_xTable.is(); + } + return bOk; +} + +TypeSelectionPageFactory ORTFReader::getTypeSelectionPageFactory() +{ + return &OWizRTFExtend::Create; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/TableCopyHelper.cxx b/dbaccess/source/ui/misc/TableCopyHelper.cxx new file mode 100644 index 000000000..c855b3b48 --- /dev/null +++ b/dbaccess/source/ui/misc/TableCopyHelper.cxx @@ -0,0 +1,306 @@ +/* -*- 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 <TableCopyHelper.hxx> +#include <core_resource.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <dbaccess/genericcontroller.hxx> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/sdb/application/CopyTableOperation.hpp> +#include <com/sun/star/sdb/application/CopyTableWizard.hpp> +#include <com/sun/star/sdb/DataAccessDescriptorFactory.hpp> +#include <com/sun/star/sdb/CommandType.hpp> + +#include <TokenWriter.hxx> +#include <UITools.hxx> +#include <dbaccess/dataview.hxx> +#include <svx/dbaexchange.hxx> +#include <unotools/ucbhelper.hxx> +#include <tools/urlobj.hxx> +#include <tools/diagnose_ex.h> +#include <sal/log.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <unotools/tempfile.hxx> +#include <cppuhelper/exc_hlp.hxx> + +namespace dbaui +{ +using namespace ::dbtools; +using namespace ::svx; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdb::application; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::ucb; + +OTableCopyHelper::OTableCopyHelper(OGenericUnoController* _pController) + :m_pController(_pController) +{ +} + +void OTableCopyHelper::insertTable( std::u16string_view i_rSourceDataSource, const Reference<XConnection>& i_rSourceConnection, + const OUString& i_rCommand, const sal_Int32 i_nCommandType, + const Reference< XResultSet >& i_rSourceRows, const Sequence< Any >& i_rSelection, const bool i_bBookmarkSelection, + std::u16string_view i_rDestDataSource, const Reference<XConnection>& i_rDestConnection) +{ + if ( CommandType::QUERY != i_nCommandType && CommandType::TABLE != i_nCommandType ) + { + SAL_WARN("dbaccess.ui", "OTableCopyHelper::insertTable: invalid call (no supported format found)!" ); + return; + } + + try + { + Reference<XConnection> xSrcConnection( i_rSourceConnection ); + if ( i_rSourceDataSource == i_rDestDataSource ) + xSrcConnection = i_rDestConnection; + + if ( !xSrcConnection.is() || !i_rDestConnection.is() ) + { + SAL_WARN("dbaccess.ui", "OTableCopyHelper::insertTable: no connection/s!" ); + return; + } + + Reference<XComponentContext> aContext( m_pController->getORB() ); + + Reference< XDataAccessDescriptorFactory > xFactory( DataAccessDescriptorFactory::get( aContext ) ); + + Reference< XPropertySet > xSource( xFactory->createDataAccessDescriptor(), UNO_SET_THROW ); + xSource->setPropertyValue( PROPERTY_COMMAND_TYPE, Any( i_nCommandType ) ); + xSource->setPropertyValue( PROPERTY_COMMAND, Any( i_rCommand ) ); + xSource->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( xSrcConnection ) ); + xSource->setPropertyValue( PROPERTY_RESULT_SET, Any( i_rSourceRows ) ); + xSource->setPropertyValue( PROPERTY_SELECTION, Any( i_rSelection ) ); + xSource->setPropertyValue( PROPERTY_BOOKMARK_SELECTION, Any( i_bBookmarkSelection ) ); + + Reference< XPropertySet > xDest( xFactory->createDataAccessDescriptor(), UNO_SET_THROW ); + xDest->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( i_rDestConnection ) ); + + auto xInteractionHandler = InteractionHandler::createWithParent(aContext, VCLUnoHelper::GetInterface(m_pController->getView())); + + Reference<XCopyTableWizard> xWizard(CopyTableWizard::createWithInteractionHandler(aContext, xSource, xDest, xInteractionHandler), UNO_SET_THROW); + + OUString sTableNameForAppend( GetTableNameForAppend() ); + xWizard->setDestinationTableName( GetTableNameForAppend() ); + + bool bAppendToExisting = !sTableNameForAppend.isEmpty(); + xWizard->setOperation( bAppendToExisting ? CopyTableOperation::AppendData : CopyTableOperation::CopyDefinitionAndData ); + + xWizard->execute(); + } + catch( const SQLException& ) + { + m_pController->showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OTableCopyHelper::pasteTable( const svx::ODataAccessDescriptor& _rPasteData, std::u16string_view i_rDestDataSourceName, + const SharedConnection& i_rDestConnection ) +{ + OUString sSrcDataSourceName = _rPasteData.getDataSource(); + + OUString sCommand; + _rPasteData[ DataAccessDescriptorProperty::Command ] >>= sCommand; + + Reference<XConnection> xSrcConnection; + if ( _rPasteData.has(DataAccessDescriptorProperty::Connection) ) + { + OSL_VERIFY( _rPasteData[DataAccessDescriptorProperty::Connection] >>= xSrcConnection ); + } + + Reference< XResultSet > xResultSet; + if ( _rPasteData.has(DataAccessDescriptorProperty::Cursor) ) + { + OSL_VERIFY( _rPasteData[ DataAccessDescriptorProperty::Cursor ] >>= xResultSet ); + } + + Sequence< Any > aSelection; + if ( _rPasteData.has( DataAccessDescriptorProperty::Selection ) ) + { + OSL_VERIFY( _rPasteData[ DataAccessDescriptorProperty::Selection ] >>= aSelection ); + OSL_ENSURE( _rPasteData.has( DataAccessDescriptorProperty::BookmarkSelection ), "OTableCopyHelper::pasteTable: you should specify BookmarkSelection, too, to be on the safe side!" ); + } + + bool bBookmarkSelection( true ); + if ( _rPasteData.has( DataAccessDescriptorProperty::BookmarkSelection ) ) + { + OSL_VERIFY( _rPasteData[ DataAccessDescriptorProperty::BookmarkSelection ] >>= bBookmarkSelection ); + } + OSL_ENSURE( bBookmarkSelection, "OTableCopyHelper::pasteTable: working with selection-indices (instead of bookmarks) is error-prone, and thus deprecated!" ); + + sal_Int32 nCommandType = CommandType::COMMAND; + if ( _rPasteData.has(DataAccessDescriptorProperty::CommandType) ) + _rPasteData[DataAccessDescriptorProperty::CommandType] >>= nCommandType; + + insertTable( sSrcDataSourceName, xSrcConnection, sCommand, nCommandType, + xResultSet, aSelection, bBookmarkSelection, + i_rDestDataSourceName, i_rDestConnection ); +} + +void OTableCopyHelper::pasteTable( SotClipboardFormatId _nFormatId + ,const TransferableDataHelper& _rTransData + ,std::u16string_view i_rDestDataSource + ,const SharedConnection& _xConnection) +{ + if ( _nFormatId == SotClipboardFormatId::DBACCESS_TABLE || _nFormatId == SotClipboardFormatId::DBACCESS_QUERY ) + { + if ( ODataAccessObjectTransferable::canExtractObjectDescriptor(_rTransData.GetDataFlavorExVector()) ) + { + svx::ODataAccessDescriptor aPasteData = ODataAccessObjectTransferable::extractObjectDescriptor(_rTransData); + pasteTable( aPasteData,i_rDestDataSource,_xConnection); + } + } + else if ( _rTransData.HasFormat(_nFormatId) ) + { + try + { + DropDescriptor aTrans; + bool bOk; + if ( _nFormatId != SotClipboardFormatId::RTF ) + bOk = _rTransData.GetSotStorageStream(SotClipboardFormatId::HTML ,aTrans.aHtmlRtfStorage); + else + bOk = _rTransData.GetSotStorageStream(SotClipboardFormatId::RTF,aTrans.aHtmlRtfStorage); + + aTrans.nType = E_TABLE; + aTrans.bHtml = SotClipboardFormatId::HTML == _nFormatId; + aTrans.sDefaultTableName = GetTableNameForAppend(); + if ( !bOk || !copyTagTable(aTrans,false,_xConnection) ) + m_pController->showError(SQLException(DBA_RES(STR_NO_TABLE_FORMAT_INSIDE), *m_pController, "S1000", 0, Any())); + } + catch(const SQLException&) + { + m_pController->showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + else + m_pController->showError(SQLException(DBA_RES(STR_NO_TABLE_FORMAT_INSIDE), *m_pController, "S1000", 0, Any())); +} + +void OTableCopyHelper::pasteTable( const TransferableDataHelper& _rTransData + ,std::u16string_view i_rDestDataSource + ,const SharedConnection& _xConnection) +{ + if ( _rTransData.HasFormat(SotClipboardFormatId::DBACCESS_TABLE) || _rTransData.HasFormat(SotClipboardFormatId::DBACCESS_QUERY) ) + pasteTable( SotClipboardFormatId::DBACCESS_TABLE,_rTransData,i_rDestDataSource,_xConnection); + else if ( _rTransData.HasFormat(SotClipboardFormatId::HTML) ) + pasteTable( SotClipboardFormatId::HTML,_rTransData,i_rDestDataSource,_xConnection); + else if ( _rTransData.HasFormat(SotClipboardFormatId::RTF) ) + pasteTable( SotClipboardFormatId::RTF,_rTransData,i_rDestDataSource,_xConnection); +} + +bool OTableCopyHelper::copyTagTable(OTableCopyHelper::DropDescriptor const & _rDesc, bool _bCheck, const SharedConnection& _xConnection) +{ + rtl::Reference<ODatabaseImportExport> pImport; + if ( _rDesc.bHtml ) + pImport = new OHTMLImportExport(_xConnection,getNumberFormatter(_xConnection, m_pController->getORB()),m_pController->getORB()); + else + pImport = new ORTFImportExport(_xConnection,getNumberFormatter(_xConnection, m_pController->getORB()),m_pController->getORB()); + + SvStream* pStream = _rDesc.aHtmlRtfStorage.get(); + if ( _bCheck ) + pImport->enableCheckOnly(); + + //set the selected tablename + pImport->setSTableName(_rDesc.sDefaultTableName); + + pImport->setStream(pStream); + return pImport->Read(); +} + +bool OTableCopyHelper::isTableFormat(const TransferableDataHelper& _rClipboard) +{ + bool bTableFormat = _rClipboard.HasFormat(SotClipboardFormatId::DBACCESS_TABLE) + || _rClipboard.HasFormat(SotClipboardFormatId::DBACCESS_QUERY) + || _rClipboard.HasFormat(SotClipboardFormatId::RTF) + || _rClipboard.HasFormat(SotClipboardFormatId::HTML); + + return bTableFormat; +} + +bool OTableCopyHelper::copyTagTable(const TransferableDataHelper& _aDroppedData + ,DropDescriptor& _rAsyncDrop + ,const SharedConnection& _xConnection) +{ + bool bRet = false; + bool bHtml = _aDroppedData.HasFormat(SotClipboardFormatId::HTML); + if ( bHtml || _aDroppedData.HasFormat(SotClipboardFormatId::RTF) ) + { + bool bOk; + if ( bHtml ) + bOk = _aDroppedData.GetSotStorageStream(SotClipboardFormatId::HTML ,_rAsyncDrop.aHtmlRtfStorage); + else + bOk = _aDroppedData.GetSotStorageStream(SotClipboardFormatId::RTF,_rAsyncDrop.aHtmlRtfStorage); + + _rAsyncDrop.bHtml = bHtml; + _rAsyncDrop.bError = !copyTagTable(_rAsyncDrop,true,_xConnection); + + bRet = ( !_rAsyncDrop.bError && bOk && _rAsyncDrop.aHtmlRtfStorage.is() ); + if ( bRet ) + { + // now we need to copy the stream + ::utl::TempFile aTmp; + _rAsyncDrop.aUrl = aTmp.GetURL(); + ::tools::SvRef<SotTempStream> aNew = new SotTempStream( aTmp.GetFileName() ); + _rAsyncDrop.aHtmlRtfStorage->Seek(STREAM_SEEK_TO_BEGIN); + _rAsyncDrop.aHtmlRtfStorage->CopyTo( aNew.get() ); + _rAsyncDrop.aHtmlRtfStorage = aNew; + } + else + _rAsyncDrop.aHtmlRtfStorage = nullptr; + } + return bRet; +} + +void OTableCopyHelper::asyncCopyTagTable( DropDescriptor& _rDesc + ,std::u16string_view i_rDestDataSource + ,const SharedConnection& _xConnection) +{ + if ( _rDesc.aHtmlRtfStorage.is() ) + { + copyTagTable(_rDesc,false,_xConnection); + _rDesc.aHtmlRtfStorage = nullptr; + // we now have to delete the temp file created in executeDrop + INetURLObject aURL; + aURL.SetURL(_rDesc.aUrl); + ::utl::UCBContentHelper::Kill(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE)); + } + else if ( !_rDesc.bError ) + pasteTable(_rDesc.aDroppedData,i_rDestDataSource,_xConnection); + else + m_pController->showError(SQLException(DBA_RES(STR_NO_TABLE_FORMAT_INSIDE), *m_pController, "S1000", 0, Any())); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/TokenWriter.cxx b/dbaccess/source/ui/misc/TokenWriter.cxx new file mode 100644 index 000000000..974337e8a --- /dev/null +++ b/dbaccess/source/ui/misc/TokenWriter.cxx @@ -0,0 +1,965 @@ +/* -*- 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 <TokenWriter.hxx> +#include <tools/diagnose_ex.h> +#include <tools/stream.hxx> +#include <osl/diagnose.h> +#include <rtl/tencinfo.h> +#include <sal/log.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <RtfReader.hxx> +#include <HtmlReader.hxx> +#include <strings.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XRowSet.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/awt/FontStrikeout.hpp> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/FontUnderline.hpp> +#include <com/sun/star/document/DocumentProperties.hpp> +#include <svtools/htmlkywd.hxx> +#include <svtools/rtfkeywd.hxx> +#include <tools/color.hxx> +#include <svtools/htmlout.hxx> +#include <sfx2/frmhtmlw.hxx> +#include <svl/numuno.hxx> +#include <vcl/svapp.hxx> +#include <UITools.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/outdev.hxx> +#include <vcl/settings.hxx> +#include <svtools/rtfout.hxx> +#include <svtools/htmlcfg.hxx> +#include <o3tl/string_view.hxx> +#include <connectivity/formattedcolumnvalue.hxx> +#include <memory> + +using namespace dbaui; +using namespace dbtools; +using namespace svx; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::util; + +#define CELL_X 1437 + +ODatabaseImportExport::ODatabaseImportExport(const svx::ODataAccessDescriptor& _aDataDescriptor, + const Reference< XComponentContext >& _rM, + const Reference< css::util::XNumberFormatter >& _rxNumberF) + :m_bBookmarkSelection( false ) + ,m_pStream(nullptr) + ,m_xFormatter(_rxNumberF) + ,m_xContext(_rM) + ,m_nCommandType(CommandType::TABLE) + ,m_bNeedToReInitialize(false) + ,m_bInInitialize(false) + ,m_bCheckOnly(false) +{ + m_eDestEnc = osl_getThreadTextEncoding(); + + osl_atomic_increment( &m_refCount ); + impl_initFromDescriptor( _aDataDescriptor, false ); + osl_atomic_decrement( &m_refCount ); +} + +// import data +ODatabaseImportExport::ODatabaseImportExport( const ::dbtools::SharedConnection& _rxConnection, + const Reference< XNumberFormatter >& _rxNumberF, const Reference< XComponentContext >& _rM ) + :m_bBookmarkSelection( false ) + ,m_pStream(nullptr) + ,m_xConnection(_rxConnection) + ,m_xFormatter(_rxNumberF) + ,m_xContext(_rM) + ,m_nCommandType(css::sdb::CommandType::TABLE) + ,m_bNeedToReInitialize(false) + ,m_bInInitialize(false) + ,m_bCheckOnly(false) +{ + m_eDestEnc = osl_getThreadTextEncoding(); +} + +ODatabaseImportExport::~ODatabaseImportExport() +{ + acquire(); + dispose(); +} + +void ODatabaseImportExport::dispose() +{ + // remove me as listener + Reference< XComponent > xComponent(m_xConnection, UNO_QUERY); + if (xComponent.is()) + { + Reference< XEventListener> xEvt(this); + xComponent->removeEventListener(xEvt); + } + m_xConnection.clear(); + + ::comphelper::disposeComponent(m_xRow); + + m_xObject.clear(); + m_xResultSetMetaData.clear(); + m_xResultSet.clear(); + m_xRow.clear(); + m_xRowLocate.clear(); + m_xFormatter.clear(); +} + +void SAL_CALL ODatabaseImportExport::disposing( const EventObject& Source ) +{ + Reference<XConnection> xCon(Source.Source,UNO_QUERY); + if(m_xConnection.is() && m_xConnection == xCon) + { + m_xConnection.clear(); + dispose(); + m_bNeedToReInitialize = true; + } +} + +void ODatabaseImportExport::initialize( const ODataAccessDescriptor& _aDataDescriptor ) +{ + impl_initFromDescriptor( _aDataDescriptor, true ); +} + +void ODatabaseImportExport::impl_initFromDescriptor( const ODataAccessDescriptor& _aDataDescriptor, bool _bPlusDefaultInit) +{ + if ( !_bPlusDefaultInit ) + { + m_sDataSourceName = _aDataDescriptor.getDataSource(); + _aDataDescriptor[DataAccessDescriptorProperty::CommandType] >>= m_nCommandType; + _aDataDescriptor[DataAccessDescriptorProperty::Command] >>= m_sName; + // some additional information + if(_aDataDescriptor.has(DataAccessDescriptorProperty::Connection)) + { + Reference< XConnection > xPureConn( _aDataDescriptor[DataAccessDescriptorProperty::Connection], UNO_QUERY ); + m_xConnection.reset( xPureConn, SharedConnection::NoTakeOwnership ); + Reference< XEventListener> xEvt(this); + Reference< XComponent > xComponent(m_xConnection, UNO_QUERY); + if (xComponent.is() && xEvt.is()) + xComponent->addEventListener(xEvt); + } + + if ( _aDataDescriptor.has( DataAccessDescriptorProperty::Selection ) ) + _aDataDescriptor[ DataAccessDescriptorProperty::Selection ] >>= m_aSelection; + + if ( _aDataDescriptor.has( DataAccessDescriptorProperty::BookmarkSelection ) ) + _aDataDescriptor[ DataAccessDescriptorProperty::BookmarkSelection ] >>= m_bBookmarkSelection; + + if ( _aDataDescriptor.has( DataAccessDescriptorProperty::Cursor ) ) + { + _aDataDescriptor[ DataAccessDescriptorProperty::Cursor ] >>= m_xResultSet; + m_xRowLocate.set( m_xResultSet, UNO_QUERY ); + } + + if ( m_aSelection.hasElements() ) + { + if ( !m_xResultSet.is() ) + { + SAL_WARN("dbaccess.ui", "ODatabaseImportExport::impl_initFromDescriptor: selection without result set is nonsense!" ); + m_aSelection.realloc( 0 ); + } + } + + if ( m_aSelection.hasElements() ) + { + if ( m_bBookmarkSelection && !m_xRowLocate.is() ) + { + SAL_WARN("dbaccess.ui", "ODatabaseImportExport::impl_initFromDescriptor: no XRowLocate -> no bookmarks!" ); + m_aSelection.realloc( 0 ); + } + } + } + else + initialize(); +} + +void ODatabaseImportExport::initialize() +{ + m_bInInitialize = true; + m_bNeedToReInitialize = false; + + if ( !m_xConnection.is() ) + { // we need a connection + OSL_ENSURE(!m_sDataSourceName.isEmpty(),"There must be a datsource name!"); + Reference<XNameAccess> xDatabaseContext( DatabaseContext::create(m_xContext), UNO_QUERY_THROW); + Reference< XEventListener> xEvt(this); + + Reference< XConnection > xConnection; + SQLExceptionInfo aInfo = ::dbaui::createConnection( m_sDataSourceName, xDatabaseContext, m_xContext, xEvt, xConnection ); + m_xConnection.reset( xConnection ); + + if(aInfo.isValid() && aInfo.getType() == SQLExceptionInfo::TYPE::SQLException) + throw *static_cast<const SQLException*>(aInfo); + } + + Reference<XNameAccess> xNameAccess; + switch(m_nCommandType) + { + case CommandType::TABLE: + { + // only for tables + Reference<XTablesSupplier> xSup(m_xConnection,UNO_QUERY); + if(xSup.is()) + xNameAccess = xSup->getTables(); + } + break; + case CommandType::QUERY: + { + Reference<XQueriesSupplier> xSup(m_xConnection,UNO_QUERY); + if(xSup.is()) + xNameAccess = xSup->getQueries(); + } + break; + } + if(xNameAccess.is() && xNameAccess->hasByName(m_sName)) + { + xNameAccess->getByName(m_sName) >>= m_xObject; + } + + if(m_xObject.is()) + { + try + { + if(m_xObject->getPropertySetInfo()->hasPropertyByName(PROPERTY_FONT)) + m_xObject->getPropertyValue(PROPERTY_FONT) >>= m_aFont; + + // the result set may be already set with the datadescriptor + if ( !m_xResultSet.is() ) + { + m_xResultSet.set( m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.sdb.RowSet", m_xContext), UNO_QUERY ); + Reference< XPropertySet > xProp( m_xResultSet, UNO_QUERY_THROW ); + xProp->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( m_xConnection.getTyped() ) ); + xProp->setPropertyValue( PROPERTY_COMMAND_TYPE, Any( m_nCommandType ) ); + xProp->setPropertyValue( PROPERTY_COMMAND, Any( m_sName ) ); + Reference< XRowSet > xRowSet( xProp, UNO_QUERY ); + xRowSet->execute(); + } + if ( !m_xRow.is() && m_xResultSet.is() ) + { + m_xRow.set( m_xResultSet, UNO_QUERY ); + m_xRowLocate.set( m_xResultSet, UNO_QUERY ); + m_xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(m_xRow,UNO_QUERY_THROW)->getMetaData(); + Reference<XColumnsSupplier> xSup(m_xResultSet,UNO_QUERY_THROW); + m_xRowSetColumns.set(xSup->getColumns(),UNO_QUERY_THROW); + } + } + catch(Exception& ) + { + m_xRow = nullptr; + m_xResultSetMetaData = nullptr; + ::comphelper::disposeComponent(m_xResultSet); + throw; + } + } + if ( m_aFont.Name.isEmpty() ) + { + vcl::Font aApplicationFont = OutputDevice::GetDefaultFont( + DefaultFontType::SANS_UNICODE, + Application::GetSettings().GetUILanguageTag().getLanguageType(), + GetDefaultFontFlags::OnlyOne + ); + m_aFont = VCLUnoHelper::CreateFontDescriptor( aApplicationFont ); + } + + m_bInInitialize = false; +} + +bool ODatabaseImportExport::Write() +{ + if ( m_bNeedToReInitialize ) + { + if ( !m_bInInitialize ) + initialize(); + } + return true; +} + +bool ODatabaseImportExport::Read() +{ + if ( m_bNeedToReInitialize ) + { + if ( !m_bInInitialize ) + initialize(); + } + return true; +} + +bool ORTFImportExport::Write() +{ + ODatabaseImportExport::Write(); + m_pStream->WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RTF ); + m_pStream->WriteCharPtr(OOO_STRING_SVTOOLS_RTF_ANSI); + if (sal_uInt32 nCpg = rtl_getWindowsCodePageFromTextEncoding(m_eDestEnc); nCpg && nCpg != 65001) + { + m_pStream->WriteCharPtr(OOO_STRING_SVTOOLS_RTF_ANSICPG).WriteUInt32AsString(nCpg); + } + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING); + + bool bBold = ( css::awt::FontWeight::BOLD == m_aFont.Weight ); + bool bItalic = ( css::awt::FontSlant_ITALIC == m_aFont.Slant ); + bool bUnderline = ( css::awt::FontUnderline::NONE != m_aFont.Underline ); + bool bStrikeout = ( css::awt::FontStrikeout::NONE != m_aFont.Strikeout ); + + ::Color aColor; + if(m_xObject.is()) + m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= aColor; + + OString aFonts(OUStringToOString(m_aFont.Name, RTL_TEXTENCODING_MS_1252)); + if (aFonts.isEmpty()) + { + OUString aName = Application::GetSettings().GetStyleSettings().GetAppFont().GetFamilyName(); + aFonts = OUStringToOString(aName, RTL_TEXTENCODING_MS_1252); + } + + m_pStream->WriteCharPtr( "{\\fonttbl" ); + if (!aFonts.isEmpty()) + { + sal_Int32 nIdx{0}; + sal_Int32 nTok{-1}; // to compensate pre-increment + do { + m_pStream->WriteCharPtr( "\\f" ); + m_pStream->WriteInt32AsString(++nTok); + m_pStream->WriteCharPtr( "\\fcharset0\\fnil " ); + m_pStream->WriteOString( o3tl::getToken(aFonts, 0, ';', nIdx) ); + m_pStream->WriteChar( ';' ); + } while (nIdx>=0); + } + m_pStream->WriteChar( '}' ) ; + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + // write the rtf color table + m_pStream->WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_COLORTBL ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RED ); + m_pStream->WriteUInt32AsString(aColor.GetRed()); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_GREEN ); + m_pStream->WriteUInt32AsString(aColor.GetGreen()); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_BLUE ); + m_pStream->WriteUInt32AsString(aColor.GetBlue()); + + m_pStream->WriteCharPtr( ";\\red255\\green255\\blue255;\\red192\\green192\\blue192;}" ) + .WriteCharPtr( SAL_NEWLINE_STRING ); + + static char const aCell1[] = "\\clbrdrl\\brdrs\\brdrcf0\\clbrdrt\\brdrs\\brdrcf0\\clbrdrb\\brdrs\\brdrcf0\\clbrdrr\\brdrs\\brdrcf0\\clshdng10000\\clcfpat2\\cellx"; + + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TROWD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TRGAPH ); + m_pStream->WriteInt32AsString(40); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + + if(m_xObject.is()) + { + Reference<XColumnsSupplier> xColSup(m_xObject,UNO_QUERY); + Reference<XNameAccess> xColumns = xColSup->getColumns(); + Sequence< OUString> aNames(xColumns->getElementNames()); + const OUString* pIter = aNames.getConstArray(); + + sal_Int32 nCount = aNames.getLength(); + bool bUseResultMetaData = false; + if ( !nCount ) + { + nCount = m_xResultSetMetaData->getColumnCount(); + bUseResultMetaData = true; + } + + for( sal_Int32 i=1; i<=nCount; ++i ) + { + m_pStream->WriteCharPtr( aCell1 ); + m_pStream->WriteInt32AsString(i*CELL_X); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + } + + // column description + m_pStream->WriteChar( '{' ).WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteCharPtr( "\\trrh-270\\pard\\intbl" ); + + std::unique_ptr<OString[]> pHorzChar(new OString[nCount]); + + for ( sal_Int32 i=1; i <= nCount; ++i ) + { + sal_Int32 nAlign = 0; + OUString sColumnName; + if ( bUseResultMetaData ) + sColumnName = m_xResultSetMetaData->getColumnName(i); + else + { + sColumnName = *pIter; + Reference<XPropertySet> xColumn; + xColumns->getByName(sColumnName) >>= xColumn; + xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign; + ++pIter; + } + + const char* pChar; + switch( nAlign ) + { + case 1: pChar = OOO_STRING_SVTOOLS_RTF_QC; break; + case 2: pChar = OOO_STRING_SVTOOLS_RTF_QR; break; + case 0: + default:pChar = OOO_STRING_SVTOOLS_RTF_QL; break; + } + + pHorzChar[i-1] = pChar; // to avoid to always rummage in the ITEMSET later on + + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteChar( '{' ); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_QC ); // column header always centered + + if ( bBold ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_B ); + if ( bItalic ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_I ); + if ( bUnderline ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_UL ); + if ( bStrikeout ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_STRIKE ); + + m_pStream->WriteCharPtr( "\\fs20\\f0\\cf0\\cb2" ); + m_pStream->WriteChar( ' ' ); + RTFOutFuncs::Out_String(*m_pStream, sColumnName, m_eDestEnc); + + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CELL ); + m_pStream->WriteChar( '}' ); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PARD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_INTBL ); + } + + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ROW ); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ).WriteChar( '}' ); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + + sal_Int32 k=1; + sal_Int32 kk=0; + if ( m_aSelection.hasElements() ) + { + const Any* pSelIter = m_aSelection.getConstArray(); + const Any* pEnd = pSelIter + m_aSelection.getLength(); + + bool bContinue = true; + for( ; pSelIter != pEnd && bContinue; ++pSelIter ) + { + if ( m_bBookmarkSelection ) + { + bContinue = m_xRowLocate->moveToBookmark( *pSelIter ); + } + else + { + sal_Int32 nPos = -1; + OSL_VERIFY( *pSelIter >>= nPos ); + bContinue = ( m_xResultSet->absolute( nPos ) ); + } + + if ( bContinue ) + appendRow( pHorzChar.get(), nCount, k, kk ); + } + } + else + { + m_xResultSet->beforeFirst(); // set back before the first row + while(m_xResultSet->next()) + { + appendRow(pHorzChar.get(),nCount,k,kk); + } + } + } + + m_pStream->WriteChar( '}' ).WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteUChar( 0 ); + return ((*m_pStream).GetError() == ERRCODE_NONE); +} + +void ORTFImportExport::appendRow(OString const * pHorzChar,sal_Int32 _nColumnCount,sal_Int32& k,sal_Int32& kk) +{ + ++kk; + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TROWD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TRGAPH ); + m_pStream->WriteInt32AsString(40); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + + static char const aCell2[] = "\\clbrdrl\\brdrs\\brdrcf2\\clbrdrt\\brdrs\\brdrcf2\\clbrdrb\\brdrs\\brdrcf2\\clbrdrr\\brdrs\\brdrcf2\\clshdng10000\\clcfpat1\\cellx"; + + for ( sal_Int32 i=1; i<=_nColumnCount; ++i ) + { + m_pStream->WriteCharPtr( aCell2 ); + m_pStream->WriteInt32AsString(i*CELL_X); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + } + + const bool bBold = ( css::awt::FontWeight::BOLD == m_aFont.Weight ); + const bool bItalic = ( css::awt::FontSlant_ITALIC == m_aFont.Slant ); + const bool bUnderline = ( css::awt::FontUnderline::NONE != m_aFont.Underline ); + const bool bStrikeout = ( css::awt::FontStrikeout::NONE != m_aFont.Strikeout ); + Reference< XRowSet > xRowSet(m_xRow,UNO_QUERY); + + m_pStream->WriteChar( '{' ); + m_pStream->WriteCharPtr( "\\trrh-270\\pard\\intbl" ); + for ( sal_Int32 i=1; i <= _nColumnCount; ++i ) + { + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteChar( '{' ); + m_pStream->WriteOString( pHorzChar[i-1] ); + + if ( bBold ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_B ); + if ( bItalic ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_I ); + if ( bUnderline ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_UL ); + if ( bStrikeout ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_STRIKE ); + + m_pStream->WriteCharPtr( "\\fs20\\f1\\cf0\\cb1 " ); + + try + { + Reference<XPropertySet> xColumn(m_xRowSetColumns->getByIndex(i-1),UNO_QUERY_THROW); + dbtools::FormattedColumnValue aFormatedValue(m_xContext,xRowSet,xColumn); + OUString sValue = aFormatedValue.getFormattedValue(); + if ( !sValue.isEmpty() ) + RTFOutFuncs::Out_String(*m_pStream,sValue,m_eDestEnc); + } + catch (Exception&) + { + SAL_WARN("dbaccess.ui","RTF WRITE!"); + } + + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CELL ); + m_pStream->WriteChar( '}' ); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PARD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_INTBL ); + } + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ROW ).WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteChar( '}' ); + ++k; +} + +bool ORTFImportExport::Read() +{ + ODatabaseImportExport::Read(); + SvParserState eState = SvParserState::Error; + if ( m_pStream ) + { + tools::SvRef<ORTFReader> xReader(new ORTFReader((*m_pStream),m_xConnection,m_xFormatter,m_xContext)); + if ( isCheckEnabled() ) + xReader->enableCheckOnly(); + eState = xReader->CallParser(); + } + + return eState != SvParserState::Error; +} + +const sal_Int16 OHTMLImportExport::nCellSpacing = 0; +const char OHTMLImportExport::sIndentSource[nIndentMax+1] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; + +OHTMLImportExport::OHTMLImportExport(const svx::ODataAccessDescriptor& _aDataDescriptor, + const Reference< XComponentContext >& _rM, + const Reference< css::util::XNumberFormatter >& _rxNumberF) + : ODatabaseImportExport(_aDataDescriptor,_rM,_rxNumberF) + ,m_nIndent(0) +#if OSL_DEBUG_LEVEL > 0 + ,m_bCheckFont(false) +#endif +{ + // set HTML configuration + m_eDestEnc = RTL_TEXTENCODING_UTF8; + strncpy( sIndent, sIndentSource ,std::min(sizeof(sIndent),sizeof(sIndentSource))); + sIndent[0] = 0; +} + +bool OHTMLImportExport::Write() +{ + ODatabaseImportExport::Write(); + if(m_xObject.is()) + { + m_pStream->WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype5 ).WriteChar( '>' ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( SAL_NEWLINE_STRING ); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_html).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + WriteHeader(); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + WriteBody(); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_html, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + return ((*m_pStream).GetError() == ERRCODE_NONE); + } + return false; +} + +bool OHTMLImportExport::Read() +{ + ODatabaseImportExport::Read(); + SvParserState eState = SvParserState::Error; + if ( m_pStream ) + { + tools::SvRef<OHTMLReader> xReader(new OHTMLReader((*m_pStream),m_xConnection,m_xFormatter,m_xContext)); + if ( isCheckEnabled() ) + xReader->enableCheckOnly(); + xReader->SetTableName(m_sDefaultTableName); + eState = xReader->CallParser(); + } + + return eState != SvParserState::Error; +} + +void OHTMLImportExport::WriteHeader() +{ + uno::Reference<document::XDocumentProperties> xDocProps( + document::DocumentProperties::create( m_xContext ) ); + if (xDocProps.is()) { + xDocProps->setTitle(m_sName); + } + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_head).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + SfxFrameHTMLWriter::Out_DocInfo( (*m_pStream), OUString(), + xDocProps, sIndent ); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + IncIndent(-1); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_head, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); +} + +void OHTMLImportExport::WriteBody() +{ + IncIndent(1); + m_pStream->WriteCharPtr( "<" ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_style ).WriteCharPtr( " " ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_type ).WriteCharPtr( "=\"text/css\">" ); + + m_pStream->WriteCharPtr( "<!-- " ); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body ).WriteCharPtr( " { " ).WriteCharPtr( "font-family: " ).WriteChar( '"' ).WriteOString( OUStringToOString(m_aFont.Name, osl_getThreadTextEncoding()) ).WriteChar( '\"' ); + // TODO : think about the encoding of the font name + m_pStream->WriteCharPtr( "; " ).WriteCharPtr( "font-size: " ); + m_pStream->WriteInt32AsString(m_aFont.Height); + m_pStream->WriteChar( '}' ); + + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + m_pStream->WriteCharPtr( " -->" ); + IncIndent(-1); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_style, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + // default Textcolour black + m_pStream->WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_text ).WriteChar( '=' ); + ::Color aColor; + if(m_xObject.is()) + m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= aColor; + HTMLOutFuncs::Out_Color( (*m_pStream), aColor ); + + m_pStream->WriteCharPtr( " " OOO_STRING_SVTOOLS_HTML_O_bgcolor "=" ); + HTMLOutFuncs::Out_Color( (*m_pStream), aColor ); + + m_pStream->WriteChar( '>' ); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + WriteTables(); + + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_body, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); +} + +void OHTMLImportExport::WriteTables() +{ + OString aStrOut = OOO_STRING_SVTOOLS_HTML_table + " " + OOO_STRING_SVTOOLS_HTML_frame + "=" + OOO_STRING_SVTOOLS_HTML_TF_void; + + Sequence< OUString> aNames; + Reference<XNameAccess> xColumns; + bool bUseResultMetaData = false; + if(m_xObject.is()) + { + Reference<XColumnsSupplier> xColSup(m_xObject,UNO_QUERY); + xColumns = xColSup->getColumns(); + aNames = xColumns->getElementNames(); + if ( !aNames.hasElements() ) + { + sal_Int32 nCount = m_xResultSetMetaData->getColumnCount(); + aNames.realloc(nCount); + auto aNamesRange = asNonConstRange(aNames); + for (sal_Int32 i= 0; i < nCount; ++i) + aNamesRange[i] = m_xResultSetMetaData->getColumnName(i+1); + bUseResultMetaData = true; + } + } + + aStrOut += " " + OOO_STRING_SVTOOLS_HTML_O_align + "=" + OOO_STRING_SVTOOLS_HTML_AL_left + " " + OOO_STRING_SVTOOLS_HTML_O_cellspacing + "=" + + OString::number(nCellSpacing) + + " " + OOO_STRING_SVTOOLS_HTML_O_cols + "=" + + OString::number(aNames.getLength()) + + " " + OOO_STRING_SVTOOLS_HTML_O_border + "=1"; + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, aStrOut.getStr()); + + FontOn(); + + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_caption); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_bold); + + m_pStream->WriteOString( OUStringToOString(m_sName, osl_getThreadTextEncoding()) ); + // TODO : think about the encoding of the name + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_bold, false); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_caption, false); + + FontOff(); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + // </FONT> + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_thead).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + if(m_xObject.is()) + { + std::unique_ptr<sal_Int32[]> pFormat(new sal_Int32[aNames.getLength()]); + + std::unique_ptr<const char *[]> pHorJustify(new const char*[aNames.getLength()]); + std::unique_ptr<sal_Int32[]> pColWidth(new sal_Int32[aNames.getLength()]); + + sal_Int32 nHeight = 0; + m_xObject->getPropertyValue(PROPERTY_ROW_HEIGHT) >>= nHeight; + + // 1. writing the column description + const OUString* pIter = aNames.getConstArray(); + const OUString* pEnd = pIter + aNames.getLength(); + + for( sal_Int32 i=0;pIter != pEnd; ++pIter,++i ) + { + sal_Int32 nAlign = 0; + pFormat[i] = 0; + pColWidth[i] = 100; + if ( !bUseResultMetaData ) + { + Reference<XPropertySet> xColumn; + xColumns->getByName(*pIter) >>= xColumn; + xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign; + pFormat[i] = ::comphelper::getINT32(xColumn->getPropertyValue(PROPERTY_FORMATKEY)); + pColWidth[i] = ::comphelper::getINT32(xColumn->getPropertyValue(PROPERTY_WIDTH)); + } + + switch( nAlign ) + { + case 1: pHorJustify[i] = OOO_STRING_SVTOOLS_HTML_AL_center; break; + case 2: pHorJustify[i] = OOO_STRING_SVTOOLS_HTML_AL_right; break; + default: pHorJustify[i] = OOO_STRING_SVTOOLS_HTML_AL_left; break; + } + + if(i == aNames.getLength()-1) + IncIndent(-1); + + WriteCell(pFormat[i],pColWidth[i],nHeight,pHorJustify[i],*pIter,OOO_STRING_SVTOOLS_HTML_tableheader); + } + + IncIndent(-1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_thead, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tbody).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + // 2. and now the data + Reference< XRowSet > xRowSet(m_xRow,UNO_QUERY); + m_xResultSet->beforeFirst(); // set back before the first row + while(m_xResultSet->next()) + { + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + for(sal_Int32 i=1;i<=aNames.getLength();++i) + { + if(i == aNames.getLength()) + IncIndent(-1); + + OUString aValue; + try + { + Reference<XPropertySet> xColumn(m_xRowSetColumns->getByIndex(i-1),UNO_QUERY_THROW); + dbtools::FormattedColumnValue aFormatedValue(m_xContext,xRowSet,xColumn); + OUString sValue = aFormatedValue.getFormattedValue(); + if (!sValue.isEmpty()) + { + aValue = sValue; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + WriteCell(pFormat[i-1],pColWidth[i-1],nHeight,pHorJustify[i-1],aValue,OOO_STRING_SVTOOLS_HTML_tabledata); + } + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + } + } + else + { + IncIndent(-1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_thead, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tbody).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + } + + IncIndent(-1); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tbody, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + IncIndent(-1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_table, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); +} + +void OHTMLImportExport::WriteCell( sal_Int32 nFormat, sal_Int32 nWidthPixel, sal_Int32 nHeightPixel, const char* pChar, + const OUString& rValue, const char* pHtmlTag) +{ + OString aStrTD = pHtmlTag; + + nWidthPixel = nWidthPixel ? nWidthPixel : 86; + nHeightPixel = nHeightPixel ? nHeightPixel : 17; + + // despite the <TABLE COLS=n> and <COL WIDTH=x> designation necessary, + // as Netscape is not paying attention to them. + // column width + aStrTD += " " + OOO_STRING_SVTOOLS_HTML_O_width + "=" + + OString::number(nWidthPixel) + + // line height + " " + OOO_STRING_SVTOOLS_HTML_O_height + "=" + + OString::number(nHeightPixel) + + " " + OOO_STRING_SVTOOLS_HTML_O_align + "=" + + pChar; + + SvNumberFormatsSupplierObj* pSupplierImpl = m_xFormatter.is() ? comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(m_xFormatter->getNumberFormatsSupplier()) : nullptr; + SvNumberFormatter* pFormatter = pSupplierImpl ? pSupplierImpl->GetNumberFormatter() : nullptr; + if(pFormatter) + { + double fVal = 0.0; + + try + { + fVal = m_xFormatter->convertStringToNumber(nFormat,rValue); + HTMLOutFuncs::CreateTableDataOptionsValNum(false, fVal,nFormat, *pFormatter); + } + catch(const Exception&) + { + HTMLOutFuncs::CreateTableDataOptionsValNum(false, fVal,nFormat, *pFormatter); + } + } + + HTMLOutFuncs::Out_AsciiTag(*m_pStream, aStrTD.getStr()); + + FontOn(); + + bool bBold = ( css::awt::FontWeight::BOLD == m_aFont.Weight ); + bool bItalic = ( css::awt::FontSlant_ITALIC == m_aFont.Slant ); + bool bUnderline = ( css::awt::FontUnderline::NONE != m_aFont.Underline ); + bool bStrikeout = ( css::awt::FontStrikeout::NONE != m_aFont.Strikeout ); + + if ( bBold ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_bold); + if ( bItalic ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_italic); + if ( bUnderline ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_underline); + if ( bStrikeout ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_strike); + + if ( rValue.isEmpty() ) + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_linebreak); // no completely empty cell + else + HTMLOutFuncs::Out_String( (*m_pStream), rValue ); + + if ( bStrikeout ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_strike, false); + if ( bUnderline ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_underline, false); + if ( bItalic ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_italic, false); + if ( bBold ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_bold, false); + + FontOff(); + + HTMLOutFuncs::Out_AsciiTag(*m_pStream, pHtmlTag, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); +} + +void OHTMLImportExport::FontOn() +{ +#if OSL_DEBUG_LEVEL > 0 + m_bCheckFont = true; +#endif + + // <FONT FACE="xxx"> + OString aStrOut = "<" + OOO_STRING_SVTOOLS_HTML_font + " " + OOO_STRING_SVTOOLS_HTML_O_face + "=" + "\"" + + OUStringToOString(m_aFont.Name,osl_getThreadTextEncoding()) + + // TODO : think about the encoding of the font name + "\"" + " " + OOO_STRING_SVTOOLS_HTML_O_color + "="; + m_pStream->WriteOString( aStrOut ); + + ::Color aColor; + if(m_xObject.is()) + m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= aColor; + + HTMLOutFuncs::Out_Color( (*m_pStream), aColor ); + m_pStream->WriteCharPtr( ">" ); +} + +inline void OHTMLImportExport::FontOff() +{ +#if OSL_DEBUG_LEVEL > 0 + OSL_ENSURE(m_bCheckFont,"No FontOn() called"); +#endif + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_font, false); +#if OSL_DEBUG_LEVEL > 0 + m_bCheckFont = false; +#endif +} + +void OHTMLImportExport::IncIndent( sal_Int16 nVal ) +{ + sIndent[m_nIndent] = '\t'; + m_nIndent = m_nIndent + nVal; + if ( m_nIndent < 0 ) + m_nIndent = 0; + else if ( m_nIndent > nIndentMax ) + m_nIndent = nIndentMax; + sIndent[m_nIndent] = 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/UITools.cxx b/dbaccess/source/ui/misc/UITools.cxx new file mode 100644 index 000000000..7a9553e49 --- /dev/null +++ b/dbaccess/source/ui/misc/UITools.cxx @@ -0,0 +1,1370 @@ +/* -*- 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 <UITools.hxx> +#include <sfx2/docfilt.hxx> +#include <core_resource.hxx> +#include <dlgsave.hxx> +#include <defaultobjectnamecheck.hxx> +#include <strings.hxx> +#include <comphelper/extract.hxx> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp> +#include <com/sun/star/sdb/XCompletedConnection.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/ucb/InteractiveIOException.hpp> +#include <com/sun/star/sdb/XDocumentDataSource.hpp> +#include <com/sun/star/ucb/IOErrorCode.hpp> +#include <vcl/syswin.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XHierarchicalNameContainer.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/awt/TextAlign.hpp> +#include <TypeInfo.hxx> +#include <FieldDescriptions.hxx> +#include <comphelper/stl_types.hxx> +#include <comphelper/types.hxx> +#include <comphelper/propertysequence.hxx> + +#include <svx/svxids.hrc> + +#include <sal/log.hxx> +#include <svl/numformat.hxx> +#include <svl/itempool.hxx> +#include <helpids.h> +#include <svl/itemset.hxx> +#include <sbagrid.hrc> +#include <svl/rngitem.hxx> +#include <svl/intitem.hxx> +#include <svx/numinf.hxx> +#include <svl/zforlist.hxx> +#include <dlgattr.hxx> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/util/NumberFormatter.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <strings.hrc> +#include <sqlmessage.hxx> +#include <dlgsize.hxx> +#include <svtools/editbrowsebox.hxx> +#include <tools/urlobj.hxx> +#include <tools/diagnose_ex.h> +#include <svl/numuno.hxx> +#include <svl/filenotation.hxx> +#include <connectivity/FValue.hxx> + +#include <editeng/justifyitem.hxx> +#include <memory> + +namespace dbaui +{ +using namespace ::dbtools; +using namespace ::comphelper; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::svt; +using ::com::sun::star::ucb::InteractiveIOException; +using ::com::sun::star::ucb::IOErrorCode_NO_FILE; +using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING; + +SQLExceptionInfo createConnection( const OUString& _rsDataSourceName, + const Reference< css::container::XNameAccess >& _xDatabaseContext, + const Reference< css::uno::XComponentContext >& _rxContext, + Reference< css::lang::XEventListener> const & _rEvtLst, + Reference< css::sdbc::XConnection>& _rOUTConnection ) +{ + Reference<XPropertySet> xProp; + try + { + xProp.set(_xDatabaseContext->getByName(_rsDataSourceName),UNO_QUERY); + } + catch(const Exception&) + { + } + + return createConnection(xProp,_rxContext,_rEvtLst,_rOUTConnection); +} + +SQLExceptionInfo createConnection( const Reference< css::beans::XPropertySet>& _xDataSource, + const Reference< css::uno::XComponentContext >& _rxContext, + Reference< css::lang::XEventListener> const & _rEvtLst, + Reference< css::sdbc::XConnection>& _rOUTConnection ) +{ + SQLExceptionInfo aInfo; + if ( !_xDataSource.is() ) + { + SAL_WARN("dbaccess.ui", "createConnection: could not retrieve the data source!"); + return aInfo; + } + + OUString sPwd, sUser; + bool bPwdReq = false; + try + { + _xDataSource->getPropertyValue(PROPERTY_PASSWORD) >>= sPwd; + bPwdReq = ::cppu::any2bool(_xDataSource->getPropertyValue(PROPERTY_ISPASSWORDREQUIRED)); + _xDataSource->getPropertyValue(PROPERTY_USER) >>= sUser; + } + catch(const Exception&) + { + SAL_WARN("dbaccess.ui", "createConnection: error while retrieving data source properties!"); + } + + try + { + if(bPwdReq && sPwd.isEmpty()) + { // password required, but empty -> connect using an interaction handler + Reference<XCompletedConnection> xConnectionCompletion(_xDataSource, UNO_QUERY); + if (!xConnectionCompletion.is()) + { + SAL_WARN("dbaccess.ui", "createConnection: missing an interface ... need an error message here!"); + } + else + { // instantiate the default SDB interaction handler + Reference< XInteractionHandler > xHandler = InteractionHandler::createWithParent(_rxContext, nullptr); + _rOUTConnection = xConnectionCompletion->connectWithCompletion(xHandler); + } + } + else + { + Reference<XDataSource> xDataSource(_xDataSource,UNO_QUERY); + _rOUTConnection = xDataSource->getConnection(sUser, sPwd); + } + // be notified when connection is in disposing + Reference< XComponent > xComponent(_rOUTConnection, UNO_QUERY); + if (xComponent.is() && _rEvtLst.is()) + xComponent->addEventListener(_rEvtLst); + } + catch(const SQLContext& e) { aInfo = SQLExceptionInfo(e); } + catch(const SQLWarning& e) { aInfo = SQLExceptionInfo(e); } + catch(const SQLException& e) { aInfo = SQLExceptionInfo(e); } + catch(const Exception&) { + TOOLS_WARN_EXCEPTION("dbaccess.ui", "SbaTableQueryBrowser::OnExpandEntry: could not connect - unknown exception"); + } + + return aInfo; +} + +Reference< XDataSource > getDataSourceByName( const OUString& _rDataSourceName, + weld::Window* _pErrorMessageParent, const Reference< XComponentContext >& _rxContext, ::dbtools::SQLExceptionInfo* _pErrorInfo ) +{ + Reference< XDatabaseContext > xDatabaseContext = DatabaseContext::create(_rxContext); + + Reference< XDataSource > xDatasource; + SQLExceptionInfo aSQLError; + try + { + xDatabaseContext->getByName( _rDataSourceName ) >>= xDatasource; + } + catch(const WrappedTargetException& e) + { + InteractiveIOException aIOException; + if ( ( e.TargetException >>= aIOException ) + && ( ( aIOException.Code == IOErrorCode_NO_FILE ) + || ( aIOException.Code == IOErrorCode_NOT_EXISTING ) + ) + ) + { + OUString sErrorMessage( DBA_RES( STR_FILE_DOES_NOT_EXIST ) ); + OFileNotation aTransformer( e.Message ); + sErrorMessage = sErrorMessage.replaceFirst( "$file$", aTransformer.get( OFileNotation::N_SYSTEM ) ); + aSQLError = SQLExceptionInfo( sErrorMessage ).get(); + } + else + { + aSQLError = SQLExceptionInfo( e.TargetException ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if ( xDatasource.is() ) + return xDatasource; + + if ( aSQLError.isValid() ) + { + if ( _pErrorInfo ) + { + *_pErrorInfo = aSQLError; + } + else + { + showError( aSQLError, _pErrorMessageParent ? _pErrorMessageParent->GetXWindow() : nullptr, _rxContext ); + } + } + + return Reference<XDataSource>(); +} + +Reference< XInterface > getDataSourceOrModel(const Reference< XInterface >& _xObject) +{ + Reference< XInterface > xRet; + Reference<XDocumentDataSource> xDocumentDataSource(_xObject,UNO_QUERY); + if ( xDocumentDataSource.is() ) + xRet = xDocumentDataSource->getDatabaseDocument(); + + if ( !xRet.is() ) + { + Reference<XOfficeDatabaseDocument> xOfficeDoc(_xObject,UNO_QUERY); + if ( xOfficeDoc.is() ) + xRet = xOfficeDoc->getDataSource(); + } + + return xRet; +} + +TOTypeInfoSP getTypeInfoFromType(const OTypeInfoMap& _rTypeInfo, + sal_Int32 _nType, + const OUString& _sTypeName, + const OUString& _sCreateParams, + sal_Int32 _nPrecision, + sal_Int32 _nScale, + bool _bAutoIncrement, + bool& _brForceToType) +{ + TOTypeInfoSP pTypeInfo; + _brForceToType = false; + // search for type + std::pair<OTypeInfoMap::const_iterator, OTypeInfoMap::const_iterator> aPair = _rTypeInfo.equal_range(_nType); + OTypeInfoMap::const_iterator aIter = aPair.first; + if(aIter != _rTypeInfo.end()) // compare with end is correct here + { + for(;aIter != aPair.second;++aIter) + { + // search the best matching type + #ifdef DBG_UTIL + OUString sDBTypeName = aIter->second->aTypeName; (void)sDBTypeName; + #endif + if ( ( + _sTypeName.isEmpty() + || (aIter->second->aTypeName.equalsIgnoreAsciiCase(_sTypeName)) + ) + && ( + ( + !aIter->second->aCreateParams.getLength() + && _sCreateParams.isEmpty() + ) + || ( + (aIter->second->nPrecision >= _nPrecision) + && (aIter->second->nMaximumScale >= _nScale) + && ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement ) + ) + ) + ) + break; + } + + if (aIter == aPair.second) + { + for(aIter = aPair.first; aIter != aPair.second; ++aIter) + { + sal_Int32 nPrec = aIter->second->nPrecision; + sal_Int32 nScale = aIter->second->nMaximumScale; + // search the best matching type (now comparing the local names) + if ( (aIter->second->aLocalTypeName.equalsIgnoreAsciiCase(_sTypeName)) + && (nPrec >= _nPrecision) + && (nScale >= _nScale) + && ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement ) + ) + { + SAL_WARN("dbaccess.ui", "getTypeInfoFromType: assuming column type " << + aIter->second->aTypeName << "\" (expected type name " << + _sTypeName << " matches the type's local name)."); + break; + } + } + } + + if (aIter == aPair.second) + { // no match for the names, no match for the local names + // -> drop the precision and the scale restriction, accept any type with the property + // type id (nType) + + for(aIter = aPair.first; aIter != aPair.second; ++aIter) + { + // search the best matching type (now comparing the local names) + sal_Int32 nPrec = aIter->second->nPrecision; + sal_Int32 nScale = aIter->second->nMaximumScale; + if ( (nPrec >= _nPrecision) + && (nScale >= _nScale) + && ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement ) + ) + break; + } + } + if (aIter == aPair.second) + { + if ( _bAutoIncrement ) + { + for(aIter = aPair.first; aIter != aPair.second; ++aIter) + { + // search the best matching type (now comparing the local names) + sal_Int32 nScale = aIter->second->nMaximumScale; + if ( (nScale >= _nScale) + && (aIter->second->bAutoIncrement == _bAutoIncrement) + ) + break; + } + if ( aIter == aPair.second ) + { + // try it without the auto increment flag + pTypeInfo = getTypeInfoFromType(_rTypeInfo, + _nType, + _sTypeName, + _sCreateParams, + _nPrecision, + _nScale, + false, + _brForceToType); + } + else + pTypeInfo = aIter->second; + } + else + { + pTypeInfo = aPair.first->second; + _brForceToType = true; + } + } + else + pTypeInfo = aIter->second; + } + else + { + ::comphelper::UStringMixEqual aCase(false); + // search for typeinfo where the typename is equal _sTypeName + for (auto const& elem : _rTypeInfo) + { + if ( aCase( elem.second->getDBName() , _sTypeName ) ) + { + pTypeInfo = elem.second; + break; + } + } + } + + OSL_ENSURE(pTypeInfo, "getTypeInfoFromType: no type info found for this type!"); + return pTypeInfo; +} + +void fillTypeInfo( const Reference< css::sdbc::XConnection>& _rxConnection, + std::u16string_view _rsTypeNames, + OTypeInfoMap& _rTypeInfoMap, + std::vector<OTypeInfoMap::iterator>& _rTypeInfoIters) +{ + if(!_rxConnection.is()) + return; + Reference< XResultSet> xRs = _rxConnection->getMetaData ()->getTypeInfo (); + Reference< XRow> xRow(xRs,UNO_QUERY); + // Information for a single SQL type + if(!xRs.is()) + return; + + Reference<XResultSetMetaData> xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(xRs,UNO_QUERY_THROW)->getMetaData(); + ::connectivity::ORowSetValue aValue; + std::vector<sal_Int32> aTypes; + std::vector<bool> aNullable; + // Loop on the result set until we reach end of file + while (xRs->next()) + { + TOTypeInfoSP pInfo = std::make_shared<OTypeInfo>(); + sal_Int32 nPos = 1; + if ( aTypes.empty() ) + { + sal_Int32 nCount = xResultSetMetaData->getColumnCount(); + if ( nCount < 1 ) + nCount = 18; + aTypes.reserve(nCount+1); + aTypes.push_back(-1); + aNullable.push_back(false); + for (sal_Int32 j = 1; j <= nCount ; ++j) + { + aTypes.push_back(xResultSetMetaData->getColumnType(j)); + aNullable.push_back(xResultSetMetaData->isNullable(j) != ColumnValue::NO_NULLS); + } + } + + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->aTypeName = aValue.getString(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nType = aValue.getInt32(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nPrecision = aValue.getInt32(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); // LiteralPrefix + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); //LiteralSuffix + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->aCreateParams = aValue.getString(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->bNullable = aValue.getInt32() == ColumnValue::NULLABLE; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + // bCaseSensitive + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nSearchType = aValue.getInt16(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + // bUnsigned + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->bCurrency = aValue.getBool(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->bAutoIncrement = aValue.getBool(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->aLocalTypeName = aValue.getString(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nMinimumScale = aValue.getInt16(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nMaximumScale = aValue.getInt16(); + assert(nPos == 15); + // 16 and 17 are unused + nPos = 18; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nNumPrecRadix = aValue.getInt32(); + + // check if values are less than zero like it happens in a oracle jdbc driver + if( pInfo->nPrecision < 0) + pInfo->nPrecision = 0; + if( pInfo->nMinimumScale < 0) + pInfo->nMinimumScale = 0; + if( pInfo->nMaximumScale < 0) + pInfo->nMaximumScale = 0; + if( pInfo->nNumPrecRadix <= 1) + pInfo->nNumPrecRadix = 10; + + std::u16string_view aName; + switch(pInfo->nType) + { + case DataType::CHAR: + aName = o3tl::getToken(_rsTypeNames, TYPE_CHAR, ';'); + break; + case DataType::VARCHAR: + aName = o3tl::getToken(_rsTypeNames, TYPE_TEXT, ';'); + break; + case DataType::DECIMAL: + aName = o3tl::getToken(_rsTypeNames, TYPE_DECIMAL, ';'); + break; + case DataType::NUMERIC: + aName = o3tl::getToken(_rsTypeNames, TYPE_NUMERIC, ';'); + break; + case DataType::BIGINT: + aName = o3tl::getToken(_rsTypeNames, TYPE_BIGINT, ';'); + break; + case DataType::FLOAT: + aName = o3tl::getToken(_rsTypeNames, TYPE_FLOAT, ';'); + break; + case DataType::DOUBLE: + aName = o3tl::getToken(_rsTypeNames, TYPE_DOUBLE, ';'); + break; + case DataType::LONGVARCHAR: + aName = o3tl::getToken(_rsTypeNames, TYPE_MEMO, ';'); + break; + case DataType::LONGVARBINARY: + aName = o3tl::getToken(_rsTypeNames, TYPE_IMAGE, ';'); + break; + case DataType::DATE: + aName = o3tl::getToken(_rsTypeNames, TYPE_DATE, ';'); + break; + case DataType::TIME: + aName = o3tl::getToken(_rsTypeNames, TYPE_TIME, ';'); + break; + case DataType::TIMESTAMP: + aName = o3tl::getToken(_rsTypeNames, TYPE_DATETIME, ';'); + break; + case DataType::BIT: + if ( !pInfo->aCreateParams.isEmpty() ) + { + aName = o3tl::getToken(_rsTypeNames, TYPE_BIT, ';'); + break; + } + [[fallthrough]]; + case DataType::BOOLEAN: + aName = o3tl::getToken(_rsTypeNames, TYPE_BOOL, ';'); + break; + case DataType::TINYINT: + aName = o3tl::getToken(_rsTypeNames, TYPE_TINYINT, ';'); + break; + case DataType::SMALLINT: + aName = o3tl::getToken(_rsTypeNames, TYPE_SMALLINT, ';'); + break; + case DataType::INTEGER: + aName = o3tl::getToken(_rsTypeNames, TYPE_INTEGER, ';'); + break; + case DataType::REAL: + aName = o3tl::getToken(_rsTypeNames, TYPE_REAL, ';'); + break; + case DataType::BINARY: + aName = o3tl::getToken(_rsTypeNames, TYPE_BINARY, ';'); + break; + case DataType::VARBINARY: + aName = o3tl::getToken(_rsTypeNames, TYPE_VARBINARY, ';'); + break; + case DataType::SQLNULL: + aName = o3tl::getToken(_rsTypeNames, TYPE_SQLNULL, ';'); + break; + case DataType::OBJECT: + aName = o3tl::getToken(_rsTypeNames, TYPE_OBJECT, ';'); + break; + case DataType::DISTINCT: + aName = o3tl::getToken(_rsTypeNames, TYPE_DISTINCT, ';'); + break; + case DataType::STRUCT: + aName = o3tl::getToken(_rsTypeNames, TYPE_STRUCT, ';'); + break; + case DataType::ARRAY: + aName = o3tl::getToken(_rsTypeNames, TYPE_ARRAY, ';'); + break; + case DataType::BLOB: + aName = o3tl::getToken(_rsTypeNames, TYPE_BLOB, ';'); + break; + case DataType::CLOB: + aName = o3tl::getToken(_rsTypeNames, TYPE_CLOB, ';'); + break; + case DataType::REF: + aName = o3tl::getToken(_rsTypeNames, TYPE_REF, ';'); + break; + case DataType::OTHER: + aName = o3tl::getToken(_rsTypeNames, TYPE_OTHER, ';'); + break; + } + if ( !aName.empty() ) + { + pInfo->aUIName = aName; + pInfo->aUIName += " [ "; + } + pInfo->aUIName += pInfo->aTypeName; + if ( !aName.empty() ) + pInfo->aUIName += " ]"; + // Now that we have the type info, save it in the multimap + _rTypeInfoMap.emplace(pInfo->nType,pInfo); + } + // for a faster index access + _rTypeInfoIters.reserve(_rTypeInfoMap.size()); + + OTypeInfoMap::iterator aIter = _rTypeInfoMap.begin(); + OTypeInfoMap::const_iterator aEnd = _rTypeInfoMap.end(); + for(;aIter != aEnd;++aIter) + _rTypeInfoIters.push_back(aIter); + + // Close the result set/statement. + + ::comphelper::disposeComponent(xRs); +} + +void setColumnProperties(const Reference<XPropertySet>& _rxColumn,const OFieldDescription* _pFieldDesc) +{ + _rxColumn->setPropertyValue(PROPERTY_NAME,Any(_pFieldDesc->GetName())); + _rxColumn->setPropertyValue(PROPERTY_TYPENAME,Any(_pFieldDesc->getTypeInfo()->aTypeName)); + _rxColumn->setPropertyValue(PROPERTY_TYPE,Any(_pFieldDesc->GetType())); + _rxColumn->setPropertyValue(PROPERTY_PRECISION,Any(_pFieldDesc->GetPrecision())); + _rxColumn->setPropertyValue(PROPERTY_SCALE,Any(_pFieldDesc->GetScale())); + _rxColumn->setPropertyValue(PROPERTY_ISNULLABLE, Any(_pFieldDesc->GetIsNullable())); + _rxColumn->setPropertyValue(PROPERTY_ISAUTOINCREMENT, css::uno::Any(_pFieldDesc->IsAutoIncrement())); + _rxColumn->setPropertyValue(PROPERTY_DESCRIPTION,Any(_pFieldDesc->GetDescription())); + if ( _rxColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ISCURRENCY) && _pFieldDesc->IsCurrency() ) + _rxColumn->setPropertyValue(PROPERTY_ISCURRENCY, css::uno::Any(_pFieldDesc->IsCurrency())); + // set autoincrement value when available + // and only set when the entry is not empty, that lets the value in the column untouched + if ( _pFieldDesc->IsAutoIncrement() && !_pFieldDesc->GetAutoIncrementValue().isEmpty() && _rxColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION) ) + _rxColumn->setPropertyValue(PROPERTY_AUTOINCREMENTCREATION,Any(_pFieldDesc->GetAutoIncrementValue())); +} + +OUString createDefaultName(const Reference< XDatabaseMetaData>& _xMetaData,const Reference<XNameAccess>& _xTables,const OUString& _sName) +{ + OSL_ENSURE(_xMetaData.is(),"No MetaData!"); + OUString sDefaultName = _sName; + try + { + OUString sCatalog,sSchema,sCompsedName; + if(_xMetaData->supportsCatalogsInTableDefinitions()) + { + try + { + Reference< XConnection> xCon = _xMetaData->getConnection(); + if ( xCon.is() ) + sCatalog = xCon->getCatalog(); + if ( sCatalog.isEmpty() ) + { + Reference<XResultSet> xRes = _xMetaData->getCatalogs(); + Reference<XRow> xRow(xRes,UNO_QUERY); + while(xRes.is() && xRes->next()) + { + sCatalog = xRow->getString(1); + if(!xRow->wasNull()) + break; + } + } + } + catch(const SQLException&) + { + } + } + if(_xMetaData->supportsSchemasInTableDefinitions()) + { + sSchema = _xMetaData->getUserName(); + } + sCompsedName = ::dbtools::composeTableName( _xMetaData, sCatalog, sSchema, _sName, false, ::dbtools::EComposeRule::InDataManipulation ); + sDefaultName = ::dbtools::createUniqueName(_xTables,sCompsedName); + } + catch(const SQLException&) + { + } + return sDefaultName; +} + +bool checkDataSourceAvailable(const OUString& _sDataSourceName,const Reference< css::uno::XComponentContext >& _xContext) +{ + Reference< XDatabaseContext > xDataBaseContext = DatabaseContext::create(_xContext); + bool bRet = xDataBaseContext->hasByName(_sDataSourceName); + if ( !bRet ) + { // try if this one is a URL + try + { + bRet = xDataBaseContext->getByName(_sDataSourceName).hasValue(); + } + catch(const Exception&) + { + } + } + return bRet; +} + +sal_Int32 mapTextAlign(const SvxCellHorJustify& _eAlignment) +{ + sal_Int32 nAlignment = css::awt::TextAlign::LEFT; + switch (_eAlignment) + { + case SvxCellHorJustify::Standard: + case SvxCellHorJustify::Left: nAlignment = css::awt::TextAlign::LEFT; break; + case SvxCellHorJustify::Center: nAlignment = css::awt::TextAlign::CENTER; break; + case SvxCellHorJustify::Right: nAlignment = css::awt::TextAlign::RIGHT; break; + default: + SAL_WARN("dbaccess.ui", "Invalid TextAlign!"); + } + return nAlignment; +} + +SvxCellHorJustify mapTextJustify(sal_Int32 _nAlignment) +{ + SvxCellHorJustify eJustify = SvxCellHorJustify::Left; + switch (_nAlignment) + { + case css::awt::TextAlign::LEFT : eJustify = SvxCellHorJustify::Left; break; + case css::awt::TextAlign::CENTER : eJustify = SvxCellHorJustify::Center; break; + case css::awt::TextAlign::RIGHT : eJustify = SvxCellHorJustify::Right; break; + default: + SAL_WARN("dbaccess.ui", "Invalid TextAlign!"); + } + return eJustify; +} + +void callColumnFormatDialog(const Reference<XPropertySet>& xAffectedCol, + const Reference<XPropertySet>& xField, + SvNumberFormatter* _pFormatter, + weld::Widget* _pParent) +{ + if (!(xAffectedCol.is() && xField.is())) + return; + + try + { + Reference< XPropertySetInfo > xInfo = xAffectedCol->getPropertySetInfo(); + bool bHasFormat = xInfo->hasPropertyByName(PROPERTY_FORMATKEY); + sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(PROPERTY_TYPE)); + + SvxCellHorJustify eJustify(SvxCellHorJustify::Standard); + Any aAlignment = xAffectedCol->getPropertyValue(PROPERTY_ALIGN); + if (aAlignment.hasValue()) + eJustify = dbaui::mapTextJustify(::comphelper::getINT16(aAlignment)); + sal_Int32 nFormatKey = 0; + if ( bHasFormat ) + nFormatKey = ::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_FORMATKEY)); + + if(callColumnFormatDialog(_pParent,_pFormatter,nDataType,nFormatKey,eJustify,bHasFormat)) + { + xAffectedCol->setPropertyValue(PROPERTY_ALIGN, Any(static_cast<sal_Int16>(dbaui::mapTextAlign(eJustify)))); + if (bHasFormat) + xAffectedCol->setPropertyValue(PROPERTY_FORMATKEY, Any(nFormatKey)); + + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +bool callColumnFormatDialog(weld::Widget* _pParent, + SvNumberFormatter* _pFormatter, + sal_Int32 _nDataType, + sal_Int32& _nFormatKey, + SvxCellHorJustify& _eJustify, + bool _bHasFormat) +{ + bool bRet = false; + + // UNO->ItemSet + static SfxItemInfo aItemInfos[] = + { + { 0, false }, + { SID_ATTR_NUMBERFORMAT_VALUE, true }, + { SID_ATTR_ALIGN_HOR_JUSTIFY, true }, + { SID_ATTR_NUMBERFORMAT_INFO, true }, + { SID_ATTR_NUMBERFORMAT_ONE_AREA, true } + }; + static const auto aAttrMap = svl::Items< + SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY, + SID_ATTR_NUMBERFORMAT_INFO, SID_ATTR_NUMBERFORMAT_INFO, + SID_ATTR_NUMBERFORMAT_ONE_AREA, SID_ATTR_NUMBERFORMAT_ONE_AREA + >; + + std::vector<SfxPoolItem*> pDefaults + { + new SfxRangeItem(SBA_DEF_RANGEFORMAT, SBA_DEF_FMTVALUE, SBA_ATTR_ALIGN_HOR_JUSTIFY), + new SfxUInt32Item(SBA_DEF_FMTVALUE), + new SvxHorJustifyItem(SvxCellHorJustify::Standard, SBA_ATTR_ALIGN_HOR_JUSTIFY), + new SvxNumberInfoItem(SID_ATTR_NUMBERFORMAT_INFO), + new SfxBoolItem(SID_ATTR_NUMBERFORMAT_ONE_AREA, false) + }; + + rtl::Reference<SfxItemPool> pPool(new SfxItemPool("GridBrowserProperties", SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY, aItemInfos, &pDefaults)); + pPool->SetDefaultMetric( MapUnit::MapTwip ); // ripped, don't understand why + pPool->FreezeIdRanges(); // the same + + std::optional<SfxItemSet> pFormatDescriptor(SfxItemSet(*pPool, aAttrMap)); + // fill it + pFormatDescriptor->Put(SvxHorJustifyItem(_eJustify, SBA_ATTR_ALIGN_HOR_JUSTIFY)); + bool bText = false; + if (_bHasFormat) + { + // if the col is bound to a text field we have to disallow all non-text formats + if ((DataType::CHAR == _nDataType) || (DataType::VARCHAR == _nDataType) || (DataType::LONGVARCHAR == _nDataType) || (DataType::CLOB == _nDataType)) + { + bText = true; + pFormatDescriptor->Put(SfxBoolItem(SID_ATTR_NUMBERFORMAT_ONE_AREA, true)); + if (!_pFormatter->IsTextFormat(_nFormatKey)) + // text fields can only have text formats + _nFormatKey = _pFormatter->GetStandardFormat(SvNumFormatType::TEXT, Application::GetSettings().GetLanguageTag().getLanguageType()); + } + + pFormatDescriptor->Put(SfxUInt32Item(SBA_DEF_FMTVALUE, _nFormatKey)); + } + + if (!bText) + { + SvxNumberInfoItem aFormatter(_pFormatter, 1234.56789, SID_ATTR_NUMBERFORMAT_INFO); + pFormatDescriptor->Put(aFormatter); + } + + { // want the dialog to be destroyed before our set + SbaSbAttrDlg aDlg(_pParent, &*pFormatDescriptor, _pFormatter, _bHasFormat); + if (RET_OK == aDlg.run()) + { + // ItemSet->UNO + // UNO-properties + const SfxItemSet* pSet = aDlg.GetExampleSet(); + // (of course we could put the modified items directly into the column, but then the UNO-model + // won't reflect these changes, and why do we have a model, then ?) + + // horizontal justify + const SvxHorJustifyItem* pHorJustify = pSet->GetItem<SvxHorJustifyItem>(SBA_ATTR_ALIGN_HOR_JUSTIFY); + + _eJustify = pHorJustify->GetValue(); + + // format key + if (_bHasFormat) + { + const SfxUInt32Item* pFormat = pSet->GetItem<SfxUInt32Item>(SBA_DEF_FMTVALUE); + _nFormatKey = static_cast<sal_Int32>(pFormat->GetValue()); + } + bRet = true; + } + // deleted formats + const SfxItemSet* pResult = aDlg.GetOutputItemSet(); + if (pResult) + { + const SfxPoolItem* pItem = pResult->GetItem( SID_ATTR_NUMBERFORMAT_INFO ); + const SvxNumberInfoItem* pInfoItem = static_cast<const SvxNumberInfoItem*>(pItem); + if (pInfoItem) + { + for (sal_uInt32 key : pInfoItem->GetDelFormats()) + _pFormatter->DeleteEntry(key); + } + } + } + + pFormatDescriptor.reset(); + pPool.clear(); + for (SfxPoolItem* pDefault : pDefaults) + delete pDefault; + + return bRet; +} + +std::shared_ptr<const SfxFilter> getStandardDatabaseFilter() +{ + std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetFilterByName("StarOffice XML (Base)"); + OSL_ENSURE(pFilter,"Filter: StarOffice XML (Base) could not be found!"); + return pFilter; +} + +bool appendToFilter(const Reference<XConnection>& _xConnection, + const OUString& _sName, + const Reference< XComponentContext >& _rxContext, + weld::Window* pParent) +{ + bool bRet = false; + Reference< XChild> xChild(_xConnection,UNO_QUERY); + if(xChild.is()) + { + Reference< XPropertySet> xProp(xChild->getParent(),UNO_QUERY); + if(xProp.is()) + { + Sequence< OUString > aFilter; + xProp->getPropertyValue(PROPERTY_TABLEFILTER) >>= aFilter; + // first check if we have something like SCHEMA.% + bool bHasToInsert = true; + for (const OUString& rItem : std::as_const(aFilter)) + { + if(rItem.indexOf('%') != -1) + { + sal_Int32 nLen = rItem.lastIndexOf('.'); + if(nLen != -1 && !rItem.compareTo(_sName,nLen)) + bHasToInsert = false; + else if(rItem.getLength() == 1) + bHasToInsert = false; + } + } + + bRet = true; + if(bHasToInsert) + { + if(! ::dbaui::checkDataSourceAvailable(::comphelper::getString(xProp->getPropertyValue(PROPERTY_NAME)),_rxContext)) + { + OUString aMessage(DBA_RES(STR_TABLEDESIGN_DATASOURCE_DELETED)); + OSQLWarningBox aWarning(pParent, aMessage); + aWarning.run(); + bRet = false; + } + else + { + aFilter.realloc(aFilter.getLength()+1); + aFilter.getArray()[aFilter.getLength()-1] = _sName; + xProp->setPropertyValue(PROPERTY_TABLEFILTER,Any(aFilter)); + } + } + } + } + return bRet; +} + +void notifySystemWindow(vcl::Window const * _pWindow, vcl::Window* _pToRegister, const ::comphelper::mem_fun1_t<TaskPaneList,vcl::Window*>& _rMemFunc) +{ + OSL_ENSURE(_pWindow,"Window can not be null!"); + SystemWindow* pSystemWindow = _pWindow ? _pWindow->GetSystemWindow() : nullptr; + if ( pSystemWindow ) + { + _rMemFunc( pSystemWindow->GetTaskPaneList(), _pToRegister ); + } +} + +void adjustBrowseBoxColumnWidth( ::svt::EditBrowseBox* _pBox, sal_uInt16 _nColId ) +{ + sal_Int32 nColSize = -1; + sal_uInt32 nDefaultWidth = _pBox->GetDefaultColumnWidth( _pBox->GetColumnTitle( _nColId ) ); + if ( nDefaultWidth != _pBox->GetColumnWidth( _nColId ) ) + { + Size aSizeMM = _pBox->PixelToLogic( Size( _pBox->GetColumnWidth( _nColId ), 0 ), MapMode( MapUnit::MapMM ) ); + nColSize = aSizeMM.Width() * 10; + } + + Size aDefaultMM = _pBox->PixelToLogic( Size( nDefaultWidth, 0 ), MapMode( MapUnit::MapMM ) ); + + DlgSize aColumnSizeDlg(_pBox->GetFrameWeld(), nColSize, false, aDefaultMM.Width() * 10); + if (aColumnSizeDlg.run() != RET_OK) + return; + + sal_Int32 nValue = aColumnSizeDlg.GetValue(); + if ( -1 == nValue ) + { // default width + nValue = _pBox->GetDefaultColumnWidth( _pBox->GetColumnTitle( _nColId ) ); + } + else + { + Size aSizeMM( nValue / 10, 0 ); + nValue = _pBox->LogicToPixel( aSizeMM, MapMode( MapUnit::MapMM ) ).Width(); + } + _pBox->SetColumnWidth( _nColId, nValue ); +} + +// check if SQL92 name checking is enabled +bool isSQL92CheckEnabled(const Reference<XConnection>& _xConnection) +{ + return ::dbtools::getBooleanDataSourceSetting( _xConnection, PROPERTY_ENABLESQL92CHECK ); +} + +bool isAppendTableAliasEnabled(const Reference<XConnection>& _xConnection) +{ + return ::dbtools::getBooleanDataSourceSetting( _xConnection, INFO_APPEND_TABLE_ALIAS ); +} + +bool generateAsBeforeTableAlias(const Reference<XConnection>& _xConnection) +{ + return ::dbtools::getBooleanDataSourceSetting( _xConnection, INFO_AS_BEFORE_CORRELATION_NAME ); +} + +void fillAutoIncrementValue(const Reference<XPropertySet>& _xDatasource, + bool& _rAutoIncrementValueEnabled, + OUString& _rsAutoIncrementValue) +{ + if ( !_xDatasource.is() ) + return; + + OSL_ENSURE(_xDatasource->getPropertySetInfo()->hasPropertyByName(PROPERTY_INFO),"NO datasource supplied!"); + Sequence<PropertyValue> aInfo; + _xDatasource->getPropertyValue(PROPERTY_INFO) >>= aInfo; + + // search the right propertyvalue + const PropertyValue* pValue =std::find_if(std::cbegin(aInfo), std::cend(aInfo), + [](const PropertyValue& lhs) + {return lhs.Name == PROPERTY_AUTOINCREMENTCREATION;} ); + + if ( pValue != std::cend(aInfo) ) + pValue->Value >>= _rsAutoIncrementValue; + pValue =std::find_if(std::cbegin(aInfo), std::cend(aInfo), + [](const PropertyValue& lhs) + {return lhs.Name == "IsAutoRetrievingEnabled";} ); + + if ( pValue != std::cend(aInfo) ) + pValue->Value >>= _rAutoIncrementValueEnabled; +} + +void fillAutoIncrementValue(const Reference<XConnection>& _xConnection, + bool& _rAutoIncrementValueEnabled, + OUString& _rsAutoIncrementValue) +{ + Reference< XChild> xChild(_xConnection,UNO_QUERY); + if(xChild.is()) + { + Reference< XPropertySet> xProp(xChild->getParent(),UNO_QUERY); + fillAutoIncrementValue(xProp,_rAutoIncrementValueEnabled,_rsAutoIncrementValue); + } +} + +OUString getStrippedDatabaseName(const Reference<XPropertySet>& _xDataSource,OUString& _rsDatabaseName) +{ + if ( _rsDatabaseName.isEmpty() && _xDataSource.is() ) + { + try + { + _xDataSource->getPropertyValue(PROPERTY_NAME) >>= _rsDatabaseName; + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + OUString sName = _rsDatabaseName; + INetURLObject aURL(sName); + if ( aURL.GetProtocol() != INetProtocol::NotValid ) + sName = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::Unambiguous); + return sName; +} + +void setEvalDateFormatForFormatter(Reference< css::util::XNumberFormatter > const & _rxFormatter) +{ + OSL_ENSURE( _rxFormatter.is(),"setEvalDateFormatForFormatter: Formatter is NULL!"); + if ( !_rxFormatter.is() ) + return; + + Reference< css::util::XNumberFormatsSupplier > xSupplier = _rxFormatter->getNumberFormatsSupplier(); + + auto pSupplierImpl = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(xSupplier); + OSL_ENSURE(pSupplierImpl,"No Supplier!"); + + if ( pSupplierImpl ) + { + SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter(); + pFormatter->SetEvalDateFormat(NF_EVALDATEFORMAT_FORMAT); + } +} + +TOTypeInfoSP queryPrimaryKeyType(const OTypeInfoMap& _rTypeInfo) +{ + TOTypeInfoSP pTypeInfo; + // first we search for a type which supports autoIncrement + for (auto const& elem : _rTypeInfo) + { + // OJ: we don't want to set an autoincrement column to be key + // because we don't have the possibility to know how to create + // such auto increment column later on + // so until we know how to do it, we create a column without autoincrement + // therefore we have searched + if ( elem.second->nType == DataType::INTEGER ) + { + pTypeInfo = elem.second; // alternative + break; + } + else if ( !pTypeInfo && elem.second->nType == DataType::DOUBLE ) + pTypeInfo = elem.second; // alternative + else if ( !pTypeInfo && elem.second->nType == DataType::REAL ) + pTypeInfo = elem.second; // alternative + } + if ( !pTypeInfo ) // just a fallback + pTypeInfo = queryTypeInfoByType(DataType::VARCHAR,_rTypeInfo); + + OSL_ENSURE(pTypeInfo,"checkColumns: can't find a type which is usable as a key!"); + return pTypeInfo; +} + +TOTypeInfoSP queryTypeInfoByType(sal_Int32 _nDataType,const OTypeInfoMap& _rTypeInfo) +{ + OTypeInfoMap::const_iterator aIter = _rTypeInfo.find(_nDataType); + if(aIter != _rTypeInfo.end()) + return aIter->second; + // fall back if the type is unknown + TOTypeInfoSP pTypeInfo; + switch(_nDataType) + { + case DataType::TINYINT: + if( (pTypeInfo = queryTypeInfoByType(DataType::SMALLINT,_rTypeInfo) ) ) + break; + [[fallthrough]]; + case DataType::SMALLINT: + if( (pTypeInfo = queryTypeInfoByType(DataType::INTEGER,_rTypeInfo) ) ) + break; + [[fallthrough]]; + case DataType::INTEGER: + if( (pTypeInfo = queryTypeInfoByType(DataType::FLOAT,_rTypeInfo) ) ) + break; + [[fallthrough]]; + case DataType::FLOAT: + if( (pTypeInfo = queryTypeInfoByType(DataType::REAL,_rTypeInfo) ) ) + break; + [[fallthrough]]; + case DataType::DATE: + case DataType::TIME: + if( DataType::DATE == _nDataType || DataType::TIME == _nDataType ) + { + if( (pTypeInfo = queryTypeInfoByType(DataType::TIMESTAMP,_rTypeInfo) ) ) + break; + } + [[fallthrough]]; + case DataType::TIMESTAMP: + case DataType::REAL: + case DataType::BIGINT: + if ( (pTypeInfo = queryTypeInfoByType(DataType::DOUBLE,_rTypeInfo) ) ) + break; + [[fallthrough]]; + case DataType::DOUBLE: + if ( (pTypeInfo = queryTypeInfoByType(DataType::NUMERIC,_rTypeInfo) ) ) + break; + [[fallthrough]]; + case DataType::NUMERIC: + pTypeInfo = queryTypeInfoByType(DataType::DECIMAL,_rTypeInfo); + break; + case DataType::DECIMAL: + if ( (pTypeInfo = queryTypeInfoByType(DataType::NUMERIC,_rTypeInfo) ) ) + break; + if ( (pTypeInfo = queryTypeInfoByType(DataType::DOUBLE,_rTypeInfo) ) ) + break; + break; + case DataType::VARCHAR: + if ( (pTypeInfo = queryTypeInfoByType(DataType::LONGVARCHAR,_rTypeInfo) ) ) + break; + break; + case DataType::LONGVARCHAR: + if ( (pTypeInfo = queryTypeInfoByType(DataType::CLOB,_rTypeInfo) ) ) + break; + break; + default: + ; + } + if ( !pTypeInfo ) + { + bool bForce = true; + pTypeInfo = ::dbaui::getTypeInfoFromType(_rTypeInfo,DataType::VARCHAR,OUString(),"x",50,0,false,bForce); + } + OSL_ENSURE(pTypeInfo,"Wrong DataType supplied!"); + return pTypeInfo; +} + +sal_Int32 askForUserAction(weld::Window* pParent, TranslateId pTitle, TranslateId pText, bool _bAll, std::u16string_view _sName) +{ + SolarMutexGuard aGuard; + OUString aMsg = DBA_RES(pText); + aMsg = aMsg.replaceFirst("%1", _sName); + OSQLMessageBox aAsk(pParent, DBA_RES(pTitle), aMsg, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes, MessageType::Query); + if ( _bAll ) + { + aAsk.add_button(DBA_RES(STR_BUTTON_TEXT_ALL), RET_ALL, HID_CONFIRM_DROP_BUTTON_ALL); + } + return aAsk.run(); +} + +namespace +{ + OUString lcl_createSDBCLevelStatement( const OUString& _rStatement, const Reference< XConnection >& _rxConnection ) + { + OUString sSDBCLevelStatement( _rStatement ); + try + { + Reference< XMultiServiceFactory > xAnalyzerFactory( _rxConnection, UNO_QUERY_THROW ); + Reference< XSingleSelectQueryAnalyzer > xAnalyzer( xAnalyzerFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW ); + xAnalyzer->setQuery( _rStatement ); + sSDBCLevelStatement = xAnalyzer->getQueryWithSubstitution(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return sSDBCLevelStatement; + } +} + +Reference< XPropertySet > createView( const OUString& _rName, const Reference< XConnection >& _rxConnection, + const OUString& _rCommand ) +{ + Reference<XViewsSupplier> xSup(_rxConnection,UNO_QUERY); + Reference< XNameAccess > xViews; + if(xSup.is()) + xViews = xSup->getViews(); + Reference<XDataDescriptorFactory> xFact(xViews,UNO_QUERY); + OSL_ENSURE(xFact.is(),"No XDataDescriptorFactory available!"); + if(!xFact.is()) + return nullptr; + + Reference<XPropertySet> xView = xFact->createDataDescriptor(); + if ( !xView.is() ) + return nullptr; + + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(_rxConnection->getMetaData(), + _rName, + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + + xView->setPropertyValue(PROPERTY_CATALOGNAME,Any(sCatalog)); + xView->setPropertyValue(PROPERTY_SCHEMANAME,Any(sSchema)); + xView->setPropertyValue(PROPERTY_NAME,Any(sTable)); + + xView->setPropertyValue( PROPERTY_COMMAND, Any( _rCommand ) ); + + Reference<XAppend> xAppend(xViews,UNO_QUERY); + if(xAppend.is()) + xAppend->appendByDescriptor(xView); + + xView = nullptr; + // we need to reget the view because after appending it, it is no longer valid + // but this time it isn't a view object it is a table object with type "VIEW" + Reference<XTablesSupplier> xTabSup(_rxConnection,UNO_QUERY); + Reference< XNameAccess > xTables; + if ( xTabSup.is() ) + { + xTables = xTabSup->getTables(); + if ( xTables.is() && xTables->hasByName( _rName ) ) + xTables->getByName( _rName ) >>= xView; + } + + return xView; +} + +Reference<XPropertySet> createView( const OUString& _rName, const Reference< XConnection >& _rxConnection + ,const Reference<XPropertySet>& _rxSourceObject) +{ + OUString sCommand; + Reference< XPropertySetInfo > xPSI( _rxSourceObject->getPropertySetInfo(), UNO_SET_THROW ); + if ( xPSI->hasPropertyByName( PROPERTY_COMMAND ) ) + { + _rxSourceObject->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand; + + bool bEscapeProcessing( false ); + OSL_VERIFY( _rxSourceObject->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bEscapeProcessing ); + if ( bEscapeProcessing ) + sCommand = lcl_createSDBCLevelStatement( sCommand, _rxConnection ); + } + else + { + sCommand = "SELECT * FROM " + composeTableNameForSelect( _rxConnection, _rxSourceObject ); + } + return createView( _rName, _rxConnection, sCommand ); +} + +bool insertHierarchyElement(weld::Window* pParent, const Reference< XComponentContext >& _rxContext, + const Reference<XHierarchicalNameContainer>& _xNames, + const OUString& _sParentFolder, + bool _bForm, + bool _bCollection, + const Reference<XContent>& _xContent, + bool _bMove) +{ + OSL_ENSURE( _xNames.is(), "insertHierarchyElement: illegal name container!" ); + if ( !_xNames.is() ) + return false; + + Reference<XNameAccess> xNameAccess( _xNames, UNO_QUERY ); + if ( _xNames->hasByHierarchicalName(_sParentFolder) ) + { + Reference<XChild> xChild(_xNames->getByHierarchicalName(_sParentFolder),UNO_QUERY); + xNameAccess.set(xChild,UNO_QUERY); + if ( !xNameAccess.is() && xChild.is() ) + xNameAccess.set(xChild->getParent(),UNO_QUERY); + } + + OSL_ENSURE( xNameAccess.is(), "insertHierarchyElement: could not find the proper name container!" ); + if ( !xNameAccess.is() ) + return false; + + OUString sNewName; + Reference<XPropertySet> xProp(_xContent,UNO_QUERY); + if ( xProp.is() ) + xProp->getPropertyValue(PROPERTY_NAME) >>= sNewName; + + if ( !_bMove || sNewName.isEmpty() ) + { + if ( sNewName.isEmpty() || xNameAccess->hasByName(sNewName) ) + { + OUString sLabel, sTargetName; + if ( !sNewName.isEmpty() ) + sTargetName = sNewName; + else + sTargetName = DBA_RES( _bCollection ? STR_NEW_FOLDER : ((_bForm) ? RID_STR_FORM : RID_STR_REPORT)); + sLabel = DBA_RES( _bCollection ? STR_FOLDER_LABEL : ((_bForm) ? STR_FRM_LABEL : STR_RPT_LABEL)); + sTargetName = ::dbtools::createUniqueName(xNameAccess,sTargetName); + + // here we have everything needed to create a new query object ... + HierarchicalNameCheck aNameChecker( _xNames, _sParentFolder ); + // ... ehm, except a new name + OSaveAsDlg aAskForName(pParent, + _rxContext, + sTargetName, + sLabel, + aNameChecker, + SADFlags::AdditionalDescription | SADFlags::TitlePasteAs); + if ( RET_OK != aAskForName.run() ) + // cancelled by the user + return false; + + sNewName = aAskForName.getName(); + } + } + else if ( xNameAccess->hasByName(sNewName) ) + { + OUString sError(DBA_RES(STR_NAME_ALREADY_EXISTS)); + sError = sError.replaceFirst("#",sNewName); + throw SQLException(sError,nullptr,"S1000",0,Any()); + } + + try + { + Reference<XMultiServiceFactory> xORB( xNameAccess, UNO_QUERY_THROW ); + uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence( + { + {"Name", uno::Any(sNewName)}, // set as folder + {"Parent", uno::Any(xNameAccess)}, + {PROPERTY_EMBEDDEDOBJECT, uno::Any(_xContent)}, + })); + OUString sServiceName(_bCollection ? (_bForm ? OUString(SERVICE_NAME_FORM_COLLECTION) : OUString(SERVICE_NAME_REPORT_COLLECTION)) : OUString(SERVICE_SDB_DOCUMENTDEFINITION)); + + Reference<XContent > xNew( xORB->createInstanceWithArguments( sServiceName, aArguments ), UNO_QUERY_THROW ); + Reference< XNameContainer > xNameContainer( xNameAccess, UNO_QUERY_THROW ); + xNameContainer->insertByName( sNewName, Any( xNew ) ); + } + catch( const IllegalArgumentException& e ) + { + ::dbtools::throwGenericSQLException( e.Message, e.Context ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + return false; + } + + return true; +} + +Reference< XNumberFormatter > getNumberFormatter(const Reference< XConnection >& _rxConnection, const Reference< css::uno::XComponentContext >& _rxContext ) +{ + // create a formatter working with the connections format supplier + Reference< XNumberFormatter > xFormatter; + + try + { + Reference< css::util::XNumberFormatsSupplier > xSupplier(::dbtools::getNumberFormats(_rxConnection, true, _rxContext)); + + if ( xSupplier.is() ) + { + // create a new formatter + xFormatter.set(util::NumberFormatter::create( _rxContext ), UNO_QUERY_THROW); + xFormatter->attachNumberFormatsSupplier(xSupplier); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return xFormatter; +} + +} // dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/UpdateHelperImpl.hxx b/dbaccess/source/ui/misc/UpdateHelperImpl.hxx new file mode 100644 index 000000000..9f8d0d399 --- /dev/null +++ b/dbaccess/source/ui/misc/UpdateHelperImpl.hxx @@ -0,0 +1,74 @@ +/* -*- 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/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <IUpdateHelper.hxx> + +namespace dbaui +{ + class OParameterUpdateHelper : public IUpdateHelper + { + css::uno::Reference< css::sdbc::XPreparedStatement > m_xPrepared; + css::uno::Reference< css::sdbc::XParameters > m_xParameters; + + public: + explicit OParameterUpdateHelper(const css::uno::Reference< css::sdbc::XPreparedStatement >& _xPrepared) + :m_xPrepared(_xPrepared) + ,m_xParameters(_xPrepared,css::uno::UNO_QUERY) + { + } + virtual ~OParameterUpdateHelper() {} + virtual void updateString(sal_Int32 _nPos, const OUString& _sValue) override + { + m_xParameters->setString(_nPos, _sValue); + } + virtual void updateDouble(sal_Int32 _nPos,const double& _nValue) override + { + m_xParameters->setDouble(_nPos, _nValue); + } + virtual void updateDate(sal_Int32 _nPos,const css::util::Date& _nValue) override + { + m_xParameters->setDate(_nPos, _nValue); + } + virtual void updateTime(sal_Int32 _nPos,const css::util::Time& _nValue) override + { + m_xParameters->setTime(_nPos, _nValue); + } + virtual void updateTimestamp(sal_Int32 _nPos,const css::util::DateTime& _nValue) override + { + m_xParameters->setTimestamp(_nPos, _nValue); + } + virtual void updateInt(sal_Int32 _nPos, sal_Int32 _nValue) override + { + m_xParameters->setInt(_nPos, _nValue); + } + virtual void updateNull(sal_Int32 _nPos, ::sal_Int32 sqlType) override + { + m_xParameters->setNull(_nPos,sqlType); + } + virtual void insertRow() override + { + m_xPrepared->executeUpdate(); + } + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WCPage.cxx b/dbaccess/source/ui/misc/WCPage.cxx new file mode 100644 index 000000000..602edd2d6 --- /dev/null +++ b/dbaccess/source/ui/misc/WCPage.cxx @@ -0,0 +1,325 @@ +/* -*- 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 <WCPage.hxx> +#include <WCopyTable.hxx> + +#include <defaultobjectnamecheck.hxx> +#include <strings.hrc> +#include <core_resource.hxx> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdb/application/CopyTableOperation.hpp> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> + +using namespace ::dbaui; +using namespace ::dbtools; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; + +namespace CopyTableOperation = css::sdb::application::CopyTableOperation; + +OCopyTable::OCopyTable(weld::Container* pPage, OCopyTableWizard* pWizard) + : OWizardPage(pPage, pWizard, "dbaccess/ui/copytablepage.ui", "CopyTablePage") + , m_bPKeyAllowed(false) + , m_bUseHeaderAllowed(true) + , m_nOldOperation(0) + , m_xEdTableName(m_xBuilder->weld_entry("name")) + , m_xRB_DefData(m_xBuilder->weld_radio_button("defdata")) + , m_xRB_Def(m_xBuilder->weld_radio_button("def")) + , m_xRB_View(m_xBuilder->weld_radio_button("view")) + , m_xRB_AppendData(m_xBuilder->weld_radio_button("data")) + , m_xCB_UseHeaderLine(m_xBuilder->weld_check_button("firstline")) + , m_xCB_PrimaryColumn(m_xBuilder->weld_check_button("primarykey")) + , m_xFT_KeyName(m_xBuilder->weld_label("keynamelabel")) + , m_xEdKeyName(m_xBuilder->weld_entry("keyname")) +{ + if ( m_pParent->m_xDestConnection.is() ) + { + if (!m_pParent->supportsViews()) + m_xRB_View->set_sensitive(false); + + m_xCB_UseHeaderLine->set_active(true); + m_bPKeyAllowed = m_pParent->supportsPrimaryKey(); + + m_xCB_PrimaryColumn->set_sensitive(m_bPKeyAllowed); + + m_xRB_AppendData->connect_toggled( LINK( this, OCopyTable, RadioChangeHdl ) ); + m_xRB_DefData->connect_toggled( LINK( this, OCopyTable, RadioChangeHdl ) ); + m_xRB_Def->connect_toggled( LINK( this, OCopyTable, RadioChangeHdl ) ); + m_xRB_View->connect_toggled( LINK( this, OCopyTable, RadioChangeHdl ) ); + + m_xCB_PrimaryColumn->connect_toggled(LINK( this, OCopyTable, KeyClickHdl ) ); + + m_xFT_KeyName->set_sensitive(false); + m_xEdKeyName->set_sensitive(false); + m_xEdKeyName->set_text(m_pParent->createUniqueName("ID")); + + const sal_Int32 nMaxLen = m_pParent->getMaxColumnNameLength(); + m_xEdKeyName->set_max_length(nMaxLen); + } + + SetPageTitle(DBA_RES(STR_COPYTABLE_TITLE_COPY)); +} + +OCopyTable::~OCopyTable() +{ +} + +void OCopyTable::SetAppendDataRadio() +{ + m_pParent->EnableNextButton(true); + m_xFT_KeyName->set_sensitive(false); + m_xCB_PrimaryColumn->set_sensitive(false); + m_xEdKeyName->set_sensitive(false); + m_pParent->setOperation(CopyTableOperation::AppendData); +} + +IMPL_LINK(OCopyTable, RadioChangeHdl, weld::Toggleable&, rButton, void) +{ + if (!rButton.get_active()) + return; + if (m_xRB_AppendData->get_active()) + { + SetAppendDataRadio(); + return; + } + m_pParent->EnableNextButton(!m_xRB_View->get_active()); + bool bKey = m_bPKeyAllowed && !m_xRB_View->get_active(); + m_xFT_KeyName->set_sensitive(bKey && m_xCB_PrimaryColumn->get_active()); + m_xEdKeyName->set_sensitive(bKey && m_xCB_PrimaryColumn->get_active()); + m_xCB_PrimaryColumn->set_sensitive(bKey); + m_xCB_UseHeaderLine->set_sensitive(m_bUseHeaderAllowed && IsOptionDefData()); + + // set type what to do + if( IsOptionDefData() ) + m_pParent->setOperation( CopyTableOperation::CopyDefinitionAndData ); + else if( IsOptionDef() ) + m_pParent->setOperation( CopyTableOperation::CopyDefinitionOnly ); + else if( IsOptionView() ) + m_pParent->setOperation( CopyTableOperation::CreateAsView ); +} + +IMPL_LINK_NOARG( OCopyTable, KeyClickHdl, weld::Toggleable&, void ) +{ + m_xEdKeyName->set_sensitive(m_xCB_PrimaryColumn->get_active()); + m_xFT_KeyName->set_sensitive(m_xCB_PrimaryColumn->get_active()); +} + +bool OCopyTable::LeavePage() +{ + m_pParent->m_bCreatePrimaryKeyColumn = m_bPKeyAllowed && m_xCB_PrimaryColumn->get_sensitive() && m_xCB_PrimaryColumn->get_active(); + m_pParent->m_aKeyName = m_pParent->m_bCreatePrimaryKeyColumn ? m_xEdKeyName->get_text() : OUString(); + m_pParent->setUseHeaderLine( m_xCB_UseHeaderLine->get_active() ); + + // first check if the table already exists in the database + if( m_pParent->getOperation() != CopyTableOperation::AppendData ) + { + m_pParent->clearDestColumns(); + DynamicTableOrQueryNameCheck aNameCheck( m_pParent->m_xDestConnection, CommandType::TABLE ); + SQLExceptionInfo aErrorInfo; + if ( !aNameCheck.isNameValid( m_xEdTableName->get_text(), aErrorInfo ) ) + { + aErrorInfo.append( SQLExceptionInfo::TYPE::SQLContext, DBA_RES( STR_SUGGEST_APPEND_TABLE_DATA ) ); + m_pParent->showError(aErrorInfo.get()); + + return false; + } + + // have to check the length of the table name + Reference< XDatabaseMetaData > xMeta = m_pParent->m_xDestConnection->getMetaData(); + OUString sCatalog; + OUString sSchema; + OUString sTable; + ::dbtools::qualifiedNameComponents( xMeta, + m_xEdTableName->get_text(), + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + sal_Int32 nMaxLength = xMeta->getMaxTableNameLength(); + if ( nMaxLength && sTable.getLength() > nMaxLength ) + { + m_pParent->showError(DBA_RES(STR_INVALID_TABLE_NAME_LENGTH)); + return false; + } + + // now we have to check if the name of the primary key already exists + if ( m_pParent->m_bCreatePrimaryKeyColumn + && m_pParent->m_aKeyName != m_pParent->createUniqueName(m_pParent->m_aKeyName) ) + { + m_pParent->showError(DBA_RES(STR_WIZ_NAME_ALREADY_DEFINED) + " " + m_pParent->m_aKeyName); + return false; + } + } + + if (m_xEdTableName->get_value_changed_from_saved()) + { // table exists and name has changed + if ( m_pParent->getOperation() == CopyTableOperation::AppendData ) + { + if(!checkAppendData()) + return false; + } + else if ( m_nOldOperation == CopyTableOperation::AppendData ) + { + m_xEdTableName->save_value(); + return LeavePage(); + } + } + else + { // table exist and is not new or doesn't exist and so on + if ( CopyTableOperation::AppendData == m_pParent->getOperation() ) + { + if( !checkAppendData() ) + return false; + } + } + m_pParent->m_sName = m_xEdTableName->get_text(); + m_xEdTableName->save_value(); + + if(m_pParent->m_sName.isEmpty()) + { + m_pParent->showError(DBA_RES(STR_INVALID_TABLE_NAME)); + return false; + } + + return true; +} + +void OCopyTable::Activate() +{ + m_pParent->GetOKButton().set_sensitive(true); + m_nOldOperation = m_pParent->getOperation(); + m_xEdTableName->grab_focus(); + m_xCB_UseHeaderLine->set_active(m_pParent->UseHeaderLine()); +} + +OUString OCopyTable::GetTitle() const +{ + return DBA_RES(STR_WIZ_TABLE_COPY); +} + +void OCopyTable::Reset() +{ + m_bFirstTime = false; + + m_xEdTableName->set_text( m_pParent->m_sName ); + m_xEdTableName->save_value(); +} + +bool OCopyTable::checkAppendData() +{ + m_pParent->clearDestColumns(); + Reference< XPropertySet > xTable; + Reference< XTablesSupplier > xSup( m_pParent->m_xDestConnection, UNO_QUERY ); + Reference<XNameAccess> xTables; + if (xSup.is()) + xTables = xSup->getTables(); + if (xTables.is() && xTables->hasByName(m_xEdTableName->get_text())) + { + const ODatabaseExport::TColumnVector& rSrcColumns = m_pParent->getSrcVector(); + const sal_uInt32 nSrcSize = rSrcColumns.size(); + m_pParent->m_vColumnPositions.resize( nSrcSize, ODatabaseExport::TPositions::value_type( COLUMN_POSITION_NOT_FOUND, COLUMN_POSITION_NOT_FOUND ) ); + m_pParent->m_vColumnTypes.resize( nSrcSize , COLUMN_POSITION_NOT_FOUND ); + + // set new destination + xTables->getByName( m_xEdTableName->get_text() ) >>= xTable; + ObjectCopySource aTableCopySource( m_pParent->m_xDestConnection, xTable ); + m_pParent->loadData( aTableCopySource, m_pParent->m_vDestColumns, m_pParent->m_aDestVec ); + const ODatabaseExport::TColumnVector& rDestColumns = m_pParent->getDestVector(); + const sal_uInt32 nMinSrcDestSize = std::min<sal_uInt32>(nSrcSize, rDestColumns.size()); + sal_uInt32 i = 0; + for (auto const& column : rDestColumns) + { + if (i >= nMinSrcDestSize) + break; + bool bNotConvert = true; + m_pParent->m_vColumnPositions[i] = ODatabaseExport::TPositions::value_type(i+1,i+1); + TOTypeInfoSP pTypeInfo = m_pParent->convertType(column->second->getSpecialTypeInfo(),bNotConvert); + if ( !bNotConvert ) + { + m_pParent->showColumnTypeNotSupported(column->first); + return false; + } + + if ( pTypeInfo ) + m_pParent->m_vColumnTypes[i] = pTypeInfo->nType; + else + m_pParent->m_vColumnTypes[i] = DataType::VARCHAR; + ++i; + } + + } + + if ( !xTable.is() ) + { + m_pParent->showError(DBA_RES(STR_INVALID_TABLE_NAME)); + return false; + } + return true; +} + +void OCopyTable::setCreatePrimaryKey( bool _bDoCreate, const OUString& _rSuggestedName ) +{ + bool bCreatePK = m_bPKeyAllowed && _bDoCreate; + m_xCB_PrimaryColumn->set_active( bCreatePK ); + m_xEdKeyName->set_text( _rSuggestedName ); + + m_xFT_KeyName->set_sensitive( bCreatePK ); + m_xEdKeyName->set_sensitive( bCreatePK ); +} + +void OCopyTable::setCreateStyleAction() +{ + // reselect the last action before + switch (m_pParent->getOperation()) + { + case CopyTableOperation::CopyDefinitionAndData: + m_xRB_DefData->set_active(true); + RadioChangeHdl(*m_xRB_DefData); + break; + case CopyTableOperation::CopyDefinitionOnly: + m_xRB_Def->set_active(true); + RadioChangeHdl(*m_xRB_Def); + break; + case CopyTableOperation::AppendData: + m_xRB_AppendData->set_active(true); + SetAppendDataRadio(); + break; + case CopyTableOperation::CreateAsView: + if (m_xRB_View->get_sensitive()) + { + m_xRB_View->set_active(true); + RadioChangeHdl(*m_xRB_View); + } + else + { + m_xRB_DefData->set_active(true); + RadioChangeHdl(*m_xRB_DefData); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WColumnSelect.cxx b/dbaccess/source/ui/misc/WColumnSelect.cxx new file mode 100644 index 000000000..8937cfb2d --- /dev/null +++ b/dbaccess/source/ui/misc/WColumnSelect.cxx @@ -0,0 +1,403 @@ +/* -*- 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 <WColumnSelect.hxx> +#include <strings.hrc> +#include <osl/diagnose.h> +#include <WCopyTable.hxx> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <core_resource.hxx> +#include <com/sun/star/sdb/application/CopyTableOperation.hpp> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace dbaui; + +namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation; + +OUString OWizColumnSelect::GetTitle() const { return DBA_RES(STR_WIZ_COLUMN_SELECT_TITLE); } + +OWizardPage::OWizardPage(weld::Container* pPage, OCopyTableWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID) + : ::vcl::OWizardPage(pPage, pWizard, rUIXMLDescription, rID) + , m_pParent(pWizard) + , m_bFirstTime(true) +{ +} + +OWizardPage::~OWizardPage() +{ +} + +// OWizColumnSelect +OWizColumnSelect::OWizColumnSelect(weld::Container* pPage, OCopyTableWizard* pWizard) + : OWizardPage(pPage, pWizard, "dbaccess/ui/applycolpage.ui", "ApplyColPage") + , m_xOrgColumnNames(m_xBuilder->weld_tree_view("from")) + , m_xColumn_RH(m_xBuilder->weld_button("colrh")) + , m_xColumns_RH(m_xBuilder->weld_button("colsrh")) + , m_xColumn_LH(m_xBuilder->weld_button("collh")) + , m_xColumns_LH(m_xBuilder->weld_button("colslh")) + , m_xNewColumnNames(m_xBuilder->weld_tree_view("to")) +{ + m_xColumn_RH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl)); + m_xColumn_LH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl)); + m_xColumns_RH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl)); + m_xColumns_LH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl)); + + m_xOrgColumnNames->set_selection_mode(SelectionMode::Multiple); + m_xNewColumnNames->set_selection_mode(SelectionMode::Multiple); + + m_xOrgColumnNames->connect_row_activated(LINK(this,OWizColumnSelect,ListDoubleClickHdl)); + m_xNewColumnNames->connect_row_activated(LINK(this,OWizColumnSelect,ListDoubleClickHdl)); +} + +OWizColumnSelect::~OWizColumnSelect() +{ + while (m_xNewColumnNames->n_children()) + { + delete weld::fromId<OFieldDescription*>(m_xNewColumnNames->get_id(0)); + m_xNewColumnNames->remove(0); + } +} + +void OWizColumnSelect::Reset() +{ + // restore original state + clearListBox(*m_xOrgColumnNames); + clearListBox(*m_xNewColumnNames); + m_pParent->m_mNameMapping.clear(); + + // insert the source columns in the left listbox + const ODatabaseExport::TColumnVector& rSrcColumns = m_pParent->getSrcVector(); + + for (auto const& column : rSrcColumns) + { + OUString sId(weld::toId(column->second)); + m_xOrgColumnNames->append(sId, column->first); + } + + if (m_xOrgColumnNames->n_children()) + m_xOrgColumnNames->select(0); + + m_bFirstTime = false; +} + +void OWizColumnSelect::Activate( ) +{ + // if there are no dest columns reset the left side with the original columns + if(m_pParent->getDestColumns().empty()) + Reset(); + + clearListBox(*m_xNewColumnNames); + + const ODatabaseExport::TColumnVector& rDestColumns = m_pParent->getDestVector(); + + // tdf#113923, the added columns must exist in the table + // in the case where: + // 1: we enabled the creation of a primary key + // 2: we come back here from the "Back" button of the next page, + // we want to avoid to list the new column generated in the next page + const ODatabaseExport::TColumns& rSrcColumns = m_pParent->getSourceColumns(); + + for (auto const& column : rDestColumns) + { + if (rSrcColumns.find(column->first) != rSrcColumns.end()) + { + OUString sId(weld::toId(new OFieldDescription(*(column->second)))); + m_xNewColumnNames->append(sId, column->first); + int nRemove = m_xOrgColumnNames->find_text(column->first); + if (nRemove != -1) + m_xOrgColumnNames->remove(nRemove); + } + } + m_pParent->GetOKButton().set_sensitive(m_xNewColumnNames->n_children() != 0); + m_pParent->EnableNextButton(m_xNewColumnNames->n_children() && m_pParent->getOperation() != CopyTableOperation::AppendData); + m_xColumns_RH->grab_focus(); +} + +bool OWizColumnSelect::LeavePage() +{ + + m_pParent->clearDestColumns(); + + for(sal_Int32 i=0 ; i< m_xNewColumnNames->n_children();++i) + { + OFieldDescription* pField = weld::fromId<OFieldDescription*>(m_xNewColumnNames->get_id(i)); + OSL_ENSURE(pField,"The field information can not be null!"); + m_pParent->insertColumn(i,pField); + } + + clearListBox(*m_xNewColumnNames); + + if ( m_pParent->GetPressedButton() == OCopyTableWizard::WIZARD_NEXT + || m_pParent->GetPressedButton() == OCopyTableWizard::WIZARD_FINISH + ) + return !m_pParent->getDestColumns().empty(); + else + return true; +} + +IMPL_LINK(OWizColumnSelect, ButtonClickHdl, weld::Button&, rButton, void) +{ + weld::TreeView *pLeft = nullptr; + weld::TreeView *pRight = nullptr; + bool bAll = false; + + if (&rButton == m_xColumn_RH.get()) + { + pLeft = m_xOrgColumnNames.get(); + pRight = m_xNewColumnNames.get(); + } + else if (&rButton == m_xColumn_LH.get()) + { + pLeft = m_xNewColumnNames.get(); + pRight = m_xOrgColumnNames.get(); + } + else if (&rButton == m_xColumns_RH.get()) + { + pLeft = m_xOrgColumnNames.get(); + pRight = m_xNewColumnNames.get(); + bAll = true; + } + else if (&rButton == m_xColumns_LH.get()) + { + pLeft = m_xNewColumnNames.get(); + pRight = m_xOrgColumnNames.get(); + bAll = true; + } + + if (!pLeft || !pRight) + return; + + Reference< XDatabaseMetaData > xMetaData( m_pParent->m_xDestConnection->getMetaData() ); + OUString sExtraChars = xMetaData->getExtraNameCharacters(); + sal_Int32 nMaxNameLen = m_pParent->getMaxColumnNameLength(); + + ::comphelper::UStringMixEqual aCase(xMetaData->supportsMixedCaseQuotedIdentifiers()); + std::vector< OUString> aRightColumns; + fillColumns(pRight,aRightColumns); + + if(!bAll) + { + auto aRows = pLeft->get_selected_rows(); + std::sort(aRows.begin(), aRows.end()); + + for (auto it = aRows.begin(); it != aRows.end(); ++it) + moveColumn(pRight,pLeft,aRightColumns,pLeft->get_text(*it),sExtraChars,nMaxNameLen,aCase); + + for (auto it = aRows.rbegin(); it != aRows.rend(); ++it) + pLeft->remove(*it); + } + else + { + const sal_Int32 nEntries = pLeft->n_children(); + for(sal_Int32 i=0; i < nEntries; ++i) + moveColumn(pRight,pLeft,aRightColumns,pLeft->get_text(i),sExtraChars,nMaxNameLen,aCase); + for(sal_Int32 j=pLeft->n_children(); j ; ) + pLeft->remove(--j); + } + + enableButtons(); + + if (m_xOrgColumnNames->n_children()) + m_xOrgColumnNames->select(0); +} + +IMPL_LINK( OWizColumnSelect, ListDoubleClickHdl, weld::TreeView&, rListBox, bool ) +{ + weld::TreeView *pLeft,*pRight; + if (&rListBox == m_xOrgColumnNames.get()) + { + pLeft = m_xOrgColumnNames.get(); + pRight = m_xNewColumnNames.get(); + } + else + { + pRight = m_xOrgColumnNames.get(); + pLeft = m_xNewColumnNames.get(); + } + + // If database is able to process PrimaryKeys, set PrimaryKey + Reference< XDatabaseMetaData > xMetaData( m_pParent->m_xDestConnection->getMetaData() ); + OUString sExtraChars = xMetaData->getExtraNameCharacters(); + sal_Int32 nMaxNameLen = m_pParent->getMaxColumnNameLength(); + + ::comphelper::UStringMixEqual aCase(xMetaData->supportsMixedCaseQuotedIdentifiers()); + std::vector< OUString> aRightColumns; + fillColumns(pRight,aRightColumns); + + auto aRows = pLeft->get_selected_rows(); + std::sort(aRows.begin(), aRows.end()); + + for (auto it = aRows.begin(); it != aRows.end(); ++it) + moveColumn(pRight,pLeft,aRightColumns,pLeft->get_text(*it),sExtraChars,nMaxNameLen,aCase); + + for (auto it = aRows.rbegin(); it != aRows.rend(); ++it) + pLeft->remove(*it); + + enableButtons(); + + return true; +} + +void OWizColumnSelect::clearListBox(weld::TreeView& rListBox) +{ + rListBox.clear(); +} + +void OWizColumnSelect::fillColumns(weld::TreeView const * pRight,std::vector< OUString> &_rRightColumns) +{ + const sal_Int32 nCount = pRight->n_children(); + _rRightColumns.reserve(nCount); + for (sal_Int32 i=0; i < nCount; ++i) + _rRightColumns.push_back(pRight->get_text(i)); +} + +void OWizColumnSelect::createNewColumn( weld::TreeView* _pListbox, + OFieldDescription const * _pSrcField, + std::vector< OUString>& _rRightColumns, + const OUString& _sColumnName, + std::u16string_view _sExtraChars, + sal_Int32 _nMaxNameLen, + const ::comphelper::UStringMixEqual& _aCase) +{ + OUString sConvertedName = m_pParent->convertColumnName(TMultiListBoxEntryFindFunctor(&_rRightColumns,_aCase), + _sColumnName, + _sExtraChars, + _nMaxNameLen); + OFieldDescription* pNewField = new OFieldDescription(*_pSrcField); + pNewField->SetName(sConvertedName); + bool bNotConvert = true; + pNewField->SetType(m_pParent->convertType(_pSrcField->getSpecialTypeInfo(),bNotConvert)); + if ( !m_pParent->supportsPrimaryKey() ) + pNewField->SetPrimaryKey(false); + + _pListbox->append(weld::toId(pNewField), sConvertedName); + _rRightColumns.push_back(sConvertedName); + + if ( !bNotConvert ) + m_pParent->showColumnTypeNotSupported(sConvertedName); +} + +void OWizColumnSelect::moveColumn( weld::TreeView* _pRight, + weld::TreeView const * _pLeft, + std::vector< OUString>& _rRightColumns, + const OUString& _sColumnName, + std::u16string_view _sExtraChars, + sal_Int32 _nMaxNameLen, + const ::comphelper::UStringMixEqual& _aCase) +{ + if(_pRight == m_xNewColumnNames.get()) + { + // we copy the column into the new format for the dest + OFieldDescription* pSrcField = weld::fromId<OFieldDescription*>(_pLeft->get_id(_pLeft->find_text(_sColumnName))); + createNewColumn(_pRight,pSrcField,_rRightColumns,_sColumnName,_sExtraChars,_nMaxNameLen,_aCase); + } + else + { + // find the new column in the dest name mapping to obtain the old column + OCopyTableWizard::TNameMapping::const_iterator aIter = std::find_if(m_pParent->m_mNameMapping.begin(),m_pParent->m_mNameMapping.end(), + [&_aCase, &_sColumnName] (const OCopyTableWizard::TNameMapping::value_type& nameMap) { + return _aCase(nameMap.second, _sColumnName); + }); + + OSL_ENSURE(aIter != m_pParent->m_mNameMapping.end(),"Column must be defined"); + if ( aIter == m_pParent->m_mNameMapping.end() ) + return; // do nothing + const ODatabaseExport::TColumns& rSrcColumns = m_pParent->getSourceColumns(); + ODatabaseExport::TColumns::const_iterator aSrcIter = rSrcColumns.find((*aIter).first); + if ( aSrcIter != rSrcColumns.end() ) + { + // we need also the old position of this column to insert it back on that position again + const ODatabaseExport::TColumnVector& rSrcVector = m_pParent->getSrcVector(); + ODatabaseExport::TColumnVector::const_iterator aPos = std::find(rSrcVector.begin(), rSrcVector.end(), aSrcIter); + OSL_ENSURE( aPos != rSrcVector.end(),"Invalid position for the iterator here!"); + ODatabaseExport::TColumnVector::size_type nPos = (aPos - rSrcVector.begin()) - adjustColumnPosition(_pLeft, _sColumnName, (aPos - rSrcVector.begin()), _aCase); + + OUString sId(weld::toId(aSrcIter->second)); + const OUString& rStr = (*aIter).first; + _pRight->insert(nullptr, nPos, &rStr, &sId, nullptr, nullptr, false, nullptr); + _rRightColumns.push_back(rStr); + m_pParent->removeColumnNameFromNameMap(_sColumnName); + } + } +} + +// Simply returning fields back to their original position is +// not enough. We need to take into account what fields have +// been removed earlier and adjust accordingly. Based on the +// algorithm employed in moveColumn(). +sal_Int32 OWizColumnSelect::adjustColumnPosition(weld::TreeView const * _pLeft, + std::u16string_view _sColumnName, + ODatabaseExport::TColumnVector::size_type nCurrentPos, + const ::comphelper::UStringMixEqual& _aCase) +{ + sal_Int32 nAdjustedPos = 0; + + // if returning all entries to their original position, + // then there is no need to adjust the positions. + if (m_xColumns_LH->has_focus()) + return nAdjustedPos; + + const sal_Int32 nCount = _pLeft->n_children(); + OUString sColumnString; + for(sal_Int32 i=0; i < nCount; ++i) + { + sColumnString = _pLeft->get_text(i); + if(_sColumnName != sColumnString) + { + // find the new column in the dest name mapping to obtain the old column + OCopyTableWizard::TNameMapping::const_iterator aIter = std::find_if(m_pParent->m_mNameMapping.begin(),m_pParent->m_mNameMapping.end(), + [&_aCase, &sColumnString] (const OCopyTableWizard::TNameMapping::value_type& nameMap) { + return _aCase(nameMap.second, sColumnString); + }); + + OSL_ENSURE(aIter != m_pParent->m_mNameMapping.end(),"Column must be defined"); + const ODatabaseExport::TColumns& rSrcColumns = m_pParent->getSourceColumns(); + ODatabaseExport::TColumns::const_iterator aSrcIter = rSrcColumns.find((*aIter).first); + if ( aSrcIter != rSrcColumns.end() ) + { + // we need also the old position of this column to insert it back on that position again + const ODatabaseExport::TColumnVector& rSrcVector = m_pParent->getSrcVector(); + ODatabaseExport::TColumnVector::const_iterator aPos = std::find(rSrcVector.begin(), rSrcVector.end(), aSrcIter); + ODatabaseExport::TColumnVector::size_type nPos = aPos - rSrcVector.begin(); + if( nPos < nCurrentPos) + { + nAdjustedPos++; + } + } + } + } + + return nAdjustedPos; +} + +void OWizColumnSelect::enableButtons() +{ + bool bEntries = m_xNewColumnNames->n_children() != 0; + if (!bEntries) + m_pParent->m_mNameMapping.clear(); + + m_pParent->GetOKButton().set_sensitive(bEntries); + m_pParent->EnableNextButton(bEntries && m_pParent->getOperation() != CopyTableOperation::AppendData); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WCopyTable.cxx b/dbaccess/source/ui/misc/WCopyTable.cxx new file mode 100644 index 000000000..64301bccd --- /dev/null +++ b/dbaccess/source/ui/misc/WCopyTable.cxx @@ -0,0 +1,1554 @@ +/* -*- 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 <strings.hrc> +#include <strings.hxx> +#include <core_resource.hxx> +#include <sqlmessage.hxx> +#include <UITools.hxx> +#include <WColumnSelect.hxx> +#include <WCopyTable.hxx> +#include <WCPage.hxx> +#include <WExtendPages.hxx> +#include <WNameMatch.hxx> +#include <WTypeSelect.hxx> + +#include <com/sun/star/sdb/application/CopyTableOperation.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XStatement.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XKeysSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> + +#include <comphelper/interaction.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbmetadata.hxx> +#include <connectivity/dbexception.hxx> +#include <o3tl/safeint.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <tools/diagnose_ex.h> + +#include <algorithm> + +using namespace ::dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::task; +using namespace dbtools; + +namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation; + +#define MAX_PAGES 4 // max. number of pages, which are shown + +namespace +{ + void clearColumns(ODatabaseExport::TColumns& _rColumns, ODatabaseExport::TColumnVector& _rColumnsVec) + { + for (auto const& column : _rColumns) + delete column.second; + + _rColumnsVec.clear(); + _rColumns.clear(); + } +} + +// ICopyTableSourceObject +ICopyTableSourceObject::~ICopyTableSourceObject() +{ +} + +// ObjectCopySource +ObjectCopySource::ObjectCopySource( const Reference< XConnection >& _rxConnection, const Reference< XPropertySet >& _rxObject ) + :m_xConnection( _rxConnection, UNO_SET_THROW ) + ,m_xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW ) + ,m_xObject( _rxObject, UNO_SET_THROW ) + ,m_xObjectPSI( _rxObject->getPropertySetInfo(), UNO_SET_THROW ) + ,m_xObjectColumns( Reference< XColumnsSupplier >( _rxObject, UNO_QUERY_THROW )->getColumns(), UNO_SET_THROW ) +{ +} + +OUString ObjectCopySource::getQualifiedObjectName() const +{ + OUString sName; + + if ( !m_xObjectPSI->hasPropertyByName( PROPERTY_COMMAND ) ) + sName = ::dbtools::composeTableName( m_xMetaData, m_xObject, ::dbtools::EComposeRule::InDataManipulation, false ); + else + m_xObject->getPropertyValue( PROPERTY_NAME ) >>= sName; + return sName; +} + +bool ObjectCopySource::isView() const +{ + bool bIsView = false; + try + { + if ( m_xObjectPSI->hasPropertyByName( PROPERTY_TYPE ) ) + { + OUString sObjectType; + OSL_VERIFY( m_xObject->getPropertyValue( PROPERTY_TYPE ) >>= sObjectType ); + bIsView = sObjectType == "VIEW"; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bIsView; +} + +void ObjectCopySource::copyUISettingsTo( const Reference< XPropertySet >& _rxObject ) const +{ + const OUString aCopyProperties[] = { + OUString(PROPERTY_FONT), OUString(PROPERTY_ROW_HEIGHT), OUString(PROPERTY_TEXTCOLOR),OUString(PROPERTY_TEXTLINECOLOR),OUString(PROPERTY_TEXTEMPHASIS),OUString(PROPERTY_TEXTRELIEF) + }; + for (const auto & aCopyProperty : aCopyProperties) + { + if ( m_xObjectPSI->hasPropertyByName( aCopyProperty ) ) + _rxObject->setPropertyValue( aCopyProperty, m_xObject->getPropertyValue( aCopyProperty ) ); + } +} + +void ObjectCopySource::copyFilterAndSortingTo( const Reference< XConnection >& _xConnection,const Reference< XPropertySet >& _rxObject ) const +{ + std::pair< OUString, OUString > aProperties[] = { + std::pair< OUString, OUString >(PROPERTY_FILTER,OUString(" AND ")) + ,std::pair< OUString, OUString >(PROPERTY_ORDER,OUString(" ORDER BY ")) + }; + + try + { + const OUString sSourceName = ::dbtools::composeTableNameForSelect(m_xConnection,m_xObject) + "."; + const OUString sTargetName = ::dbtools::composeTableNameForSelect(_xConnection,_rxObject); + const OUString sTargetNameTemp = sTargetName + "."; + + OUStringBuffer sStatement = "SELECT * FROM " + sTargetName + " WHERE 0=1"; + + for (const std::pair<OUString,OUString> & aProperty : aProperties) + { + if ( m_xObjectPSI->hasPropertyByName( aProperty.first ) ) + { + OUString sFilter; + m_xObject->getPropertyValue( aProperty.first ) >>= sFilter; + if ( !sFilter.isEmpty() ) + { + sStatement.append(aProperty.second); + sFilter = sFilter.replaceFirst(sSourceName,sTargetNameTemp); + _rxObject->setPropertyValue( aProperty.first, Any(sFilter) ); + sStatement.append(sFilter); + } + } + } + + _xConnection->createStatement()->executeQuery(sStatement.makeStringAndClear()); + + if ( m_xObjectPSI->hasPropertyByName( PROPERTY_APPLYFILTER ) ) + _rxObject->setPropertyValue( PROPERTY_APPLYFILTER, m_xObject->getPropertyValue( PROPERTY_APPLYFILTER ) ); + } + catch(Exception&) + { + } +} + +Sequence< OUString > ObjectCopySource::getColumnNames() const +{ + return m_xObjectColumns->getElementNames(); +} + +Sequence< OUString > ObjectCopySource::getPrimaryKeyColumnNames() const +{ + const Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(m_xObject); + Sequence< OUString > aKeyColNames; + if ( xPrimaryKeyColumns.is() ) + aKeyColNames = xPrimaryKeyColumns->getElementNames(); + return aKeyColNames; +} + +OFieldDescription* ObjectCopySource::createFieldDescription( const OUString& _rColumnName ) const +{ + Reference< XPropertySet > xColumn( m_xObjectColumns->getByName( _rColumnName ), UNO_QUERY_THROW ); + return new OFieldDescription( xColumn ); +} + +OUString ObjectCopySource::getSelectStatement() const +{ + OUString sSelectStatement; + if ( m_xObjectPSI->hasPropertyByName( PROPERTY_COMMAND ) ) + { // query + OSL_VERIFY( m_xObject->getPropertyValue( PROPERTY_COMMAND ) >>= sSelectStatement ); + } + else + { // table + OUStringBuffer aSQL; + aSQL.append( "SELECT " ); + + // we need to create the sql stmt with column names + // otherwise it is possible that names don't match + const OUString sQuote = m_xMetaData->getIdentifierQuoteString(); + + Sequence< OUString > aColumnNames = getColumnNames(); + const OUString* pColumnName = aColumnNames.getConstArray(); + const OUString* pEnd = pColumnName + aColumnNames.getLength(); + for ( ; pColumnName != pEnd; ) + { + aSQL.append( ::dbtools::quoteName( sQuote, *pColumnName++ ) ); + + if ( pColumnName == pEnd ) + aSQL.append( " " ); + else + aSQL.append( ", " ); + } + + aSQL.append( "FROM " + ::dbtools::composeTableNameForSelect( m_xConnection, m_xObject ) ); + + sSelectStatement = aSQL.makeStringAndClear(); + } + + return sSelectStatement; +} + +::utl::SharedUNOComponent< XPreparedStatement > ObjectCopySource::getPreparedSelectStatement() const +{ + ::utl::SharedUNOComponent< XPreparedStatement > xStatement( + m_xConnection->prepareStatement( getSelectStatement() ), + ::utl::SharedUNOComponent< XPreparedStatement >::TakeOwnership + ); + return xStatement; +} + +// NamedTableCopySource +NamedTableCopySource::NamedTableCopySource( const Reference< XConnection >& _rxConnection, const OUString& _rTableName ) + :m_xConnection( _rxConnection, UNO_SET_THROW ) + ,m_xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW ) + ,m_sTableName( _rTableName ) +{ + ::dbtools::qualifiedNameComponents( m_xMetaData, m_sTableName, m_sTableCatalog, m_sTableSchema, m_sTableBareName, ::dbtools::EComposeRule::Complete ); + impl_ensureColumnInfo_throw(); +} + +OUString NamedTableCopySource::getQualifiedObjectName() const +{ + return m_sTableName; +} + +bool NamedTableCopySource::isView() const +{ + OUString sTableType; + try + { + Reference< XResultSet > xTableDesc( m_xMetaData->getTables( Any( m_sTableCatalog ), m_sTableSchema, m_sTableBareName, + Sequence< OUString >() ) ); + Reference< XRow > xTableDescRow( xTableDesc, UNO_QUERY_THROW ); + OSL_VERIFY( xTableDesc->next() ); + sTableType = xTableDescRow->getString( 4 ); + OSL_ENSURE( !xTableDescRow->wasNull(), "NamedTableCopySource::isView: invalid table type!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return sTableType == "VIEW"; +} + +void NamedTableCopySource::copyUISettingsTo( const Reference< XPropertySet >& /*_rxObject*/ ) const +{ + // not supported: we do not have UI settings to copy +} + +void NamedTableCopySource::copyFilterAndSortingTo( const Reference< XConnection >& ,const Reference< XPropertySet >& /*_rxObject*/ ) const +{ +} + +void NamedTableCopySource::impl_ensureColumnInfo_throw() +{ + if ( !m_aColumnInfo.empty() ) + return; + + Reference< XResultSetMetaDataSupplier > xStatementMetaSupp( impl_ensureStatement_throw().getTyped(), UNO_QUERY_THROW ); + Reference< XResultSetMetaData > xStatementMeta( xStatementMetaSupp->getMetaData(), UNO_SET_THROW ); + + sal_Int32 nColCount( xStatementMeta->getColumnCount() ); + for ( sal_Int32 i = 1; i <= nColCount; ++i ) + { + OFieldDescription aDesc; + + aDesc.SetName( xStatementMeta->getColumnName( i ) ); + aDesc.SetHelpText( xStatementMeta->getColumnLabel( i ) ); + aDesc.SetTypeValue( xStatementMeta->getColumnType( i ) ); + aDesc.SetTypeName( xStatementMeta->getColumnTypeName( i ) ); + aDesc.SetPrecision( xStatementMeta->getPrecision( i ) ); + aDesc.SetScale( xStatementMeta->getScale( i ) ); + aDesc.SetIsNullable( xStatementMeta->isNullable( i ) ); + aDesc.SetCurrency( xStatementMeta->isCurrency( i ) ); + aDesc.SetAutoIncrement( xStatementMeta->isAutoIncrement( i ) ); + + m_aColumnInfo.push_back( aDesc ); + } +} + +::utl::SharedUNOComponent< XPreparedStatement > const & NamedTableCopySource::impl_ensureStatement_throw() +{ + if ( !m_xStatement.is() ) + m_xStatement.set( m_xConnection->prepareStatement( getSelectStatement() ), UNO_SET_THROW ); + return m_xStatement; +} + +Sequence< OUString > NamedTableCopySource::getColumnNames() const +{ + Sequence< OUString > aNames( m_aColumnInfo.size() ); + std::transform(m_aColumnInfo.begin(), m_aColumnInfo.end(), aNames.getArray(), + [](const auto& elem) { return elem.GetName(); }); + + return aNames; +} + +Sequence< OUString > NamedTableCopySource::getPrimaryKeyColumnNames() const +{ + Sequence< OUString > aPKColNames; + + try + { + Reference< XResultSet > xPKDesc( m_xMetaData->getPrimaryKeys( Any( m_sTableCatalog ), m_sTableSchema, m_sTableBareName ) ); + Reference< XRow > xPKDescRow( xPKDesc, UNO_QUERY_THROW ); + while ( xPKDesc->next() ) + { + sal_Int32 len( aPKColNames.getLength() ); + aPKColNames.realloc( len + 1 ); + aPKColNames.getArray()[ len ] = xPKDescRow->getString( 4 ); // COLUMN_NAME + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return aPKColNames; +} + +OFieldDescription* NamedTableCopySource::createFieldDescription( const OUString& _rColumnName ) const +{ + for (auto const& elem : m_aColumnInfo) + if ( elem.GetName() == _rColumnName ) + return new OFieldDescription(elem); + + return nullptr; +} + +OUString NamedTableCopySource::getSelectStatement() const +{ + return "SELECT * FROM " + + ::dbtools::composeTableNameForSelect( m_xConnection, m_sTableCatalog, m_sTableSchema, m_sTableBareName ); +} + +::utl::SharedUNOComponent< XPreparedStatement > NamedTableCopySource::getPreparedSelectStatement() const +{ + return const_cast< NamedTableCopySource* >( this )->impl_ensureStatement_throw(); +} + +namespace { + +// DummyCopySource +class DummyCopySource : public ICopyTableSourceObject +{ +public: + DummyCopySource() { } + + static const DummyCopySource& Instance(); + + // ICopyTableSourceObject overridables + virtual OUString getQualifiedObjectName() const override; + virtual bool isView() const override; + virtual void copyUISettingsTo( const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override; + virtual void copyFilterAndSortingTo(const css::uno::Reference< css::sdbc::XConnection >& _xConnection, const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override; + virtual css::uno::Sequence< OUString > + getColumnNames() const override; + virtual css::uno::Sequence< OUString > + getPrimaryKeyColumnNames() const override; + virtual OFieldDescription* createFieldDescription( const OUString& _rColumnName ) const override; + virtual OUString getSelectStatement() const override; + virtual ::utl::SharedUNOComponent< XPreparedStatement > + getPreparedSelectStatement() const override; +}; + +} + +const DummyCopySource& DummyCopySource::Instance() +{ + static DummyCopySource s_aTheInstance; + return s_aTheInstance; +} + +OUString DummyCopySource::getQualifiedObjectName() const +{ + SAL_WARN("dbaccess.ui", "DummyCopySource::getQualifiedObjectName: not to be called!" ); + return OUString(); +} + +bool DummyCopySource::isView() const +{ + SAL_WARN("dbaccess.ui", "DummyCopySource::isView: not to be called!" ); + return false; +} + +void DummyCopySource::copyUISettingsTo( const Reference< XPropertySet >& /*_rxObject*/ ) const +{ + // no support +} + +void DummyCopySource::copyFilterAndSortingTo( const Reference< XConnection >& ,const Reference< XPropertySet >& /*_rxObject*/ ) const +{ +} + +Sequence< OUString > DummyCopySource::getColumnNames() const +{ + return Sequence< OUString >(); +} + +Sequence< OUString > DummyCopySource::getPrimaryKeyColumnNames() const +{ + SAL_WARN("dbaccess.ui", "DummyCopySource::getPrimaryKeyColumnNames: not to be called!" ); + return Sequence< OUString >(); +} + +OFieldDescription* DummyCopySource::createFieldDescription( const OUString& /*_rColumnName*/ ) const +{ + SAL_WARN("dbaccess.ui", "DummyCopySource::createFieldDescription: not to be called!" ); + return nullptr; +} + +OUString DummyCopySource::getSelectStatement() const +{ + SAL_WARN("dbaccess.ui", "DummyCopySource::getSelectStatement: not to be called!" ); + return OUString(); +} + +::utl::SharedUNOComponent< XPreparedStatement > DummyCopySource::getPreparedSelectStatement() const +{ + SAL_WARN("dbaccess.ui", "DummyCopySource::getPreparedSelectStatement: not to be called!" ); + return ::utl::SharedUNOComponent< XPreparedStatement >(); +} + +namespace +{ + bool lcl_canCreateViewFor_nothrow( const Reference< XConnection >& _rxConnection ) + { + Reference< XViewsSupplier > xSup( _rxConnection, UNO_QUERY ); + Reference< XDataDescriptorFactory > xViewFac; + if ( xSup.is() ) + xViewFac.set( xSup->getViews(), UNO_QUERY ); + return xViewFac.is(); + } + + bool lcl_sameConnection_throw( const Reference< XConnection >& _rxLHS, const Reference< XConnection >& _rxRHS ) + { + Reference< XDatabaseMetaData > xMetaLHS( _rxLHS->getMetaData(), UNO_SET_THROW ); + Reference< XDatabaseMetaData > xMetaRHS( _rxRHS->getMetaData(), UNO_SET_THROW ); + return xMetaLHS->getURL() == xMetaRHS->getURL(); + } +} + +// OCopyTableWizard +OCopyTableWizard::OCopyTableWizard(weld::Window* pParent, const OUString& _rDefaultName, sal_Int16 _nOperation, + const ICopyTableSourceObject& _rSourceObject, const Reference< XConnection >& _xSourceConnection, + const Reference< XConnection >& _xConnection, const Reference< XComponentContext >& _rxContext, + const Reference< XInteractionHandler>& _xInteractionHandler) + : vcl::RoadmapWizardMachine(pParent) + , m_mNameMapping(_xConnection->getMetaData().is() && _xConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) + , m_xDestConnection( _xConnection ) + , m_rSourceObject( _rSourceObject ) + , m_xFormatter( getNumberFormatter( _xConnection, _rxContext ) ) + , m_xContext(_rxContext) + , m_xInteractionHandler(_xInteractionHandler) + , m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES)) + , m_nPageCount(0) + , m_bDeleteSourceColumns(true) + , m_bInterConnectionCopy( _xSourceConnection != _xConnection ) + , m_sName( _rDefaultName ) + , m_nOperation( _nOperation ) + , m_ePressed( WIZARD_NONE ) + , m_bCreatePrimaryKeyColumn(false) + , m_bUseHeaderLine(false) +{ + construct(); + + // extract table name + OUString sInitialTableName( _rDefaultName ); + try + { + m_sSourceName = m_rSourceObject.getQualifiedObjectName(); + OSL_ENSURE( !m_sSourceName.isEmpty(), "OCopyTableWizard::OCopyTableWizard: unable to retrieve the source object's name!" ); + + if ( sInitialTableName.isEmpty() ) + sInitialTableName = m_sSourceName; + + if ( m_sName.isEmpty() ) + { + if ( _xSourceConnection == m_xDestConnection ) + { + Reference< XTablesSupplier > xSup( m_xDestConnection, UNO_QUERY_THROW ); + m_sName = ::dbtools::createUniqueName( xSup->getTables(), sInitialTableName, false ); + } + else + m_sName = sInitialTableName; + } + } + catch ( const Exception& ) + { + m_sName = sInitialTableName; + } + + ::dbaui::fillTypeInfo( _xSourceConnection, m_sTypeNames, m_aTypeInfo, m_aTypeInfoIndex ); + ::dbaui::fillTypeInfo( m_xDestConnection, m_sTypeNames, m_aDestTypeInfo, m_aDestTypeInfoIndex ); + loadData( m_rSourceObject, m_vSourceColumns, m_vSourceVec ); + + bool bAllowViews = true; + // if the source is a, don't allow creating views + if ( m_rSourceObject.isView() ) + bAllowViews = false; + // no views if the target connection does not support creating them + if ( !lcl_canCreateViewFor_nothrow( m_xDestConnection ) ) + bAllowViews = false; + // no views if we're copying to a different database + if ( !lcl_sameConnection_throw( _xSourceConnection, m_xDestConnection ) ) + bAllowViews = false; + + if ( m_bInterConnectionCopy ) + { + Reference< XDatabaseMetaData > xSrcMeta = _xSourceConnection->getMetaData(); + OUString sCatalog; + OUString sSchema; + OUString sTable; + ::dbtools::qualifiedNameComponents( xSrcMeta, + m_sName, + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + + m_sName = ::dbtools::composeTableName(m_xDestConnection->getMetaData(),sCatalog,sSchema,sTable,false,::dbtools::EComposeRule::InTableDefinitions); + } + + std::unique_ptr<OCopyTable> xPage1(new OCopyTable(CreatePageContainer(), this)); + xPage1->disallowUseHeaderLine(); + if ( !bAllowViews ) + xPage1->disallowViews(); + xPage1->setCreateStyleAction(); + AddWizardPage(std::move(xPage1)); + + AddWizardPage( std::make_unique<OWizNameMatching>(CreatePageContainer(), this)); + AddWizardPage( std::make_unique<OWizColumnSelect>(CreatePageContainer(), this)); + AddWizardPage( std::make_unique<OWizNormalExtend>(CreatePageContainer(), this)); + ActivatePage(); + + m_xAssistant->set_current_page(0); +} + +weld::Container* OCopyTableWizard::CreatePageContainer() +{ + OString sIdent(OString::number(m_nPageCount)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + return pPageContainer; +} + +OCopyTableWizard::OCopyTableWizard( weld::Window* pParent, const OUString& _rDefaultName, sal_Int16 _nOperation, + ODatabaseExport::TColumns&& _rSourceColumns, const ODatabaseExport::TColumnVector& _rSourceColVec, + const Reference< XConnection >& _xConnection, const Reference< XNumberFormatter >& _xFormatter, + TypeSelectionPageFactory _pTypeSelectionPageFactory, SvStream& _rTypeSelectionPageArg, const Reference< XComponentContext >& _rxContext ) + : vcl::RoadmapWizardMachine(pParent) + , m_vSourceColumns(std::move(_rSourceColumns)) + , m_mNameMapping(_xConnection->getMetaData().is() && _xConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) + , m_xDestConnection( _xConnection ) + , m_rSourceObject( DummyCopySource::Instance() ) + , m_xFormatter(_xFormatter) + , m_xContext(_rxContext) + , m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES)) + , m_nPageCount(0) + , m_bDeleteSourceColumns(false) + , m_bInterConnectionCopy( false ) + , m_sName(_rDefaultName) + , m_nOperation( _nOperation ) + , m_ePressed( WIZARD_NONE ) + , m_bCreatePrimaryKeyColumn(false) + , m_bUseHeaderLine(false) +{ + construct(); + for (auto const& sourceCol : _rSourceColVec) + { + m_vSourceVec.emplace_back(m_vSourceColumns.find(sourceCol->first)); + } + + ::dbaui::fillTypeInfo( _xConnection, m_sTypeNames, m_aTypeInfo, m_aTypeInfoIndex ); + ::dbaui::fillTypeInfo( _xConnection, m_sTypeNames, m_aDestTypeInfo, m_aDestTypeInfoIndex ); + + m_xInteractionHandler = InteractionHandler::createWithParent(m_xContext, nullptr); + + std::unique_ptr<OCopyTable> xPage1(new OCopyTable(CreatePageContainer(), this)); + xPage1->disallowViews(); + xPage1->setCreateStyleAction(); + AddWizardPage(std::move(xPage1)); + + AddWizardPage(std::make_unique<OWizNameMatching>(CreatePageContainer(), this)); + AddWizardPage(std::make_unique<OWizColumnSelect>(CreatePageContainer(), this)); + AddWizardPage((*_pTypeSelectionPageFactory)(CreatePageContainer(), this, _rTypeSelectionPageArg)); + + ActivatePage(); + + m_xAssistant->set_current_page(0); +} + +void OCopyTableWizard::construct() +{ + m_xAssistant->set_size_request(700, 350); + + m_xPrevPage->set_label(DBA_RES(STR_WIZ_PB_PREV)); + m_xNextPage->set_label(DBA_RES(STR_WIZ_PB_NEXT)); + m_xFinish->set_label(DBA_RES(STR_WIZ_PB_OK)); + + m_xHelp->show(); + m_xCancel->show(); + m_xPrevPage->show(); + m_xNextPage->show(); + m_xFinish->show(); + + m_xPrevPage->connect_clicked( LINK( this, OCopyTableWizard, ImplPrevHdl ) ); + m_xNextPage->connect_clicked( LINK( this, OCopyTableWizard, ImplNextHdl ) ); + m_xFinish->connect_clicked( LINK( this, OCopyTableWizard, ImplOKHdl ) ); + + m_xNextPage->grab_focus(); + + if (!m_vDestColumns.empty()) + // source is a html or rtf table + m_xAssistant->change_default_widget(nullptr, m_xNextPage.get()); + else + m_xAssistant->change_default_widget(nullptr, m_xFinish.get()); + + m_pTypeInfo = std::make_shared<OTypeInfo>(); + m_pTypeInfo->aUIName = m_sTypeNames.getToken(TYPE_OTHER, ';'); + m_bAddPKFirstTime = true; +} + +OCopyTableWizard::~OCopyTableWizard() +{ + if ( m_bDeleteSourceColumns ) + clearColumns(m_vSourceColumns,m_vSourceVec); + + clearColumns(m_vDestColumns,m_aDestVec); + + // clear the type information + m_aTypeInfoIndex.clear(); + m_aTypeInfo.clear(); + m_aDestTypeInfoIndex.clear(); + m_aDestTypeInfo.clear(); +} + +IMPL_LINK_NOARG(OCopyTableWizard, ImplPrevHdl, weld::Button&, void) +{ + m_ePressed = WIZARD_PREV; + if ( GetCurLevel() ) + { + if ( getOperation() != CopyTableOperation::AppendData ) + { + if(GetCurLevel() == 2) + ShowPage(GetCurLevel()-2); + else + ShowPrevPage(); + } + else + ShowPrevPage(); + } +} + +IMPL_LINK_NOARG(OCopyTableWizard, ImplNextHdl, weld::Button&, void) +{ + m_ePressed = WIZARD_NEXT; + if ( GetCurLevel() < MAX_PAGES ) + { + if ( getOperation() != CopyTableOperation::AppendData ) + { + if(GetCurLevel() == 0) + ShowPage(GetCurLevel()+2); + else + ShowNextPage(); + } + else + ShowNextPage(); + } +} + +bool OCopyTableWizard::CheckColumns(sal_Int32& _rnBreakPos) +{ + bool bRet = true; + m_vColumnPositions.clear(); + m_vColumnTypes.clear(); + + OSL_ENSURE( m_xDestConnection.is(), "OCopyTableWizard::CheckColumns: No connection!" ); + // If database is able to process PrimaryKeys, set PrimaryKey + if ( m_xDestConnection.is() ) + { + bool bPKeyAllowed = supportsPrimaryKey(); + + bool bContainsColumns = !m_vDestColumns.empty(); + + if ( bPKeyAllowed && shouldCreatePrimaryKey() ) + { + // add extra column for the primary key + TOTypeInfoSP pTypeInfo = queryPrimaryKeyType(m_aDestTypeInfo); + if ( pTypeInfo ) + { + if ( m_bAddPKFirstTime ) + { + // tdf#114955: since we chose to create a primary key + // be sure all other columns won't be in primary key + for (auto const& elem : m_vDestColumns) + elem.second->SetPrimaryKey(false); + OFieldDescription* pField = new OFieldDescription(); + pField->SetName(m_aKeyName); + pField->FillFromTypeInfo(pTypeInfo,true,true); + pField->SetPrimaryKey(true); + m_bAddPKFirstTime = false; + insertColumn(0,pField); + } + m_vColumnPositions.emplace_back(1,1); + m_vColumnTypes.push_back(pTypeInfo->nType); + } + } + + if ( bContainsColumns ) + { // we have dest columns so look for the matching column + for (auto const& elemSource : m_vSourceVec) + { + ODatabaseExport::TColumns::const_iterator aDestIter = m_vDestColumns.find(m_mNameMapping[elemSource->first]); + + if ( aDestIter != m_vDestColumns.end() ) + { + ODatabaseExport::TColumnVector::const_iterator aFind = std::find(m_aDestVec.begin(),m_aDestVec.end(),aDestIter); + assert(aFind != m_aDestVec.end()); + sal_Int32 nPos = (aFind - m_aDestVec.begin())+1; + m_vColumnPositions.emplace_back(nPos,nPos); + m_vColumnTypes.push_back((*aFind)->second->GetType()); + } + else + { + m_vColumnPositions.emplace_back( COLUMN_POSITION_NOT_FOUND, COLUMN_POSITION_NOT_FOUND ); + m_vColumnTypes.push_back(0); + } + } + } + else + { + Reference< XDatabaseMetaData > xMetaData( m_xDestConnection->getMetaData() ); + OUString sExtraChars = xMetaData->getExtraNameCharacters(); + sal_Int32 nMaxNameLen = getMaxColumnNameLength(); + + _rnBreakPos=0; + for (auto const& elemSource : m_vSourceVec) + { + OFieldDescription* pField = new OFieldDescription(*elemSource->second); + pField->SetName(convertColumnName(TExportColumnFindFunctor(&m_vDestColumns),elemSource->first,sExtraChars,nMaxNameLen)); + TOTypeInfoSP pType = convertType(elemSource->second->getSpecialTypeInfo(),bRet); + pField->SetType(pType); + if ( !bPKeyAllowed ) + pField->SetPrimaryKey(false); + + // now create a column + insertColumn(m_vDestColumns.size(),pField); + m_vColumnPositions.emplace_back(m_vDestColumns.size(),m_vDestColumns.size()); + m_vColumnTypes.push_back(elemSource->second->GetType()); + ++_rnBreakPos; + if (!bRet) + break; + } + } + } + return bRet; +} + +IMPL_LINK_NOARG(OCopyTableWizard, ImplOKHdl, weld::Button&, void) +{ + m_ePressed = WIZARD_FINISH; + bool bFinish = DeactivatePage(); + + if(!bFinish) + return; + + weld::WaitObject aWait(m_xAssistant.get()); + switch(getOperation()) + { + case CopyTableOperation::CopyDefinitionAndData: + case CopyTableOperation::CopyDefinitionOnly: + { + bool bOnFirstPage = GetCurLevel() == 0; + if ( bOnFirstPage ) + { + // we came from the first page so we have to clear + // all column information already collected + clearDestColumns(); + m_mNameMapping.clear(); + } + sal_Int32 nBreakPos = 0; + bool bCheckOk = CheckColumns(nBreakPos); + if ( bOnFirstPage && !bCheckOk ) + { + showColumnTypeNotSupported(m_vSourceVec[nBreakPos-1]->first); + OWizTypeSelect* pPage = static_cast<OWizTypeSelect*>(GetPage(3)); + if ( pPage ) + { + m_mNameMapping.clear(); + pPage->setDisplayRow(nBreakPos); + ShowPage(3); + return; + } + } + if ( m_xDestConnection.is() ) + { + if ( supportsPrimaryKey() ) + { + bool noPrimaryKey = std::none_of(m_vDestColumns.begin(),m_vDestColumns.end(), + [] (const ODatabaseExport::TColumns::value_type& tCol) { return tCol.second->IsPrimaryKey(); }); + if ( noPrimaryKey && m_xInteractionHandler.is() ) + { + + OUString sMsg(DBA_RES(STR_TABLEDESIGN_NO_PRIM_KEY)); + SQLContext aError; + aError.Message = sMsg; + ::rtl::Reference xRequest( new ::comphelper::OInteractionRequest( Any( aError ) ) ); + ::rtl::Reference xYes = new ::comphelper::OInteractionApprove; + xRequest->addContinuation( xYes ); + xRequest->addContinuation( new ::comphelper::OInteractionDisapprove ); + ::rtl::Reference< ::comphelper::OInteractionAbort > xAbort = new ::comphelper::OInteractionAbort; + xRequest->addContinuation( xAbort ); + + m_xInteractionHandler->handle( xRequest ); + + if ( xYes->wasSelected() ) + { + OCopyTable* pPage = static_cast<OCopyTable*>(GetPage(0)); + m_bCreatePrimaryKeyColumn = true; + m_aKeyName = pPage->GetKeyName(); + if ( m_aKeyName.isEmpty() ) + m_aKeyName = "ID"; + m_aKeyName = createUniqueName( m_aKeyName ); + sal_Int32 nBreakPos2 = 0; + CheckColumns(nBreakPos2); + } + else if ( xAbort->wasSelected() ) + { + ShowPage(3); + return; + } + } + } + } + break; + } + case CopyTableOperation::AppendData: + case CopyTableOperation::CreateAsView: + break; + default: + { + SAL_WARN("dbaccess.ui", "OCopyTableWizard::ImplOKHdl: invalid creation style!"); + } + } + + m_xAssistant->response(RET_OK); +} + +void OCopyTableWizard::setCreatePrimaryKey( bool _bDoCreate, const OUString& _rSuggestedName ) +{ + m_bCreatePrimaryKeyColumn = _bDoCreate; + if ( !_rSuggestedName.isEmpty() ) + m_aKeyName = _rSuggestedName; + + OCopyTable* pSettingsPage = dynamic_cast< OCopyTable* >( GetPage( 0 ) ); + OSL_ENSURE( pSettingsPage, "OCopyTableWizard::setCreatePrimaryKey: page should have been added in the ctor!" ); + if ( pSettingsPage ) + pSettingsPage->setCreatePrimaryKey( _bDoCreate, _rSuggestedName ); +} + +void OCopyTableWizard::ActivatePage() +{ + OWizardPage* pCurrent = static_cast<OWizardPage*>(GetPage(GetCurLevel())); + if (pCurrent) + { + bool bFirstTime = pCurrent->IsFirstTime(); + if(bFirstTime) + pCurrent->Reset(); + + CheckButtons(); + + m_xAssistant->set_title(pCurrent->GetTitle()); + } +} + +void OCopyTableWizard::CheckButtons() +{ + if(GetCurLevel() == 0) // the first page has no back button + { + if(m_nPageCount > 1) + m_xNextPage->set_sensitive(true); + else + m_xNextPage->set_sensitive(false); + + m_xPrevPage->set_sensitive(false); + } + else if(GetCurLevel() == m_nPageCount-1) // the last page has no next button + { + m_xNextPage->set_sensitive(false); + m_xPrevPage->set_sensitive(true); + } + else + { + m_xPrevPage->set_sensitive(true); + // next already has its state + } +} + +void OCopyTableWizard::EnableNextButton(bool bEnable) +{ + m_xNextPage->set_sensitive(bEnable); +} + +bool OCopyTableWizard::DeactivatePage() +{ + OWizardPage* pPage = static_cast<OWizardPage*>(GetPage(GetCurLevel())); + return pPage && pPage->LeavePage(); +} + +void OCopyTableWizard::AddWizardPage(std::unique_ptr<OWizardPage> xPage) +{ + AddPage(std::move(xPage)); + ++m_nPageCount; +} + +void OCopyTableWizard::insertColumn(sal_Int32 _nPos,OFieldDescription* _pField) +{ + OSL_ENSURE(_pField,"FieldDescrioption is null!"); + if ( !_pField ) + return; + + ODatabaseExport::TColumns::const_iterator aFind = m_vDestColumns.find(_pField->GetName()); + if ( aFind != m_vDestColumns.end() ) + { + delete aFind->second; + m_vDestColumns.erase(aFind); + } + + m_aDestVec.insert(m_aDestVec.begin() + _nPos, + m_vDestColumns.emplace(_pField->GetName(),_pField).first); + m_mNameMapping[_pField->GetName()] = _pField->GetName(); +} + +void OCopyTableWizard::replaceColumn(sal_Int32 _nPos,OFieldDescription* _pField,const OUString& _sOldName) +{ + OSL_ENSURE(_pField,"FieldDescrioption is null!"); + if ( _pField ) + { + m_vDestColumns.erase(_sOldName); + OSL_ENSURE( m_vDestColumns.find(_pField->GetName()) == m_vDestColumns.end(),"Column with that name already exist!"); + + m_aDestVec[_nPos] = m_vDestColumns.emplace(_pField->GetName(),_pField).first; + } +} + +void OCopyTableWizard::loadData( const ICopyTableSourceObject& _rSourceObject, ODatabaseExport::TColumns& _rColumns, ODatabaseExport::TColumnVector& _rColVector ) +{ + for (auto const& column : _rColumns) + delete column.second; + + _rColVector.clear(); + _rColumns.clear(); + + OFieldDescription* pActFieldDescr = nullptr; + OUString const sCreateParam("x"); + // ReadOnly-Flag + // On drop no line must be editable. + // On add only empty lines must be editable. + // On Add and Drop all lines can be edited. + Sequence< OUString > aColumns( _rSourceObject.getColumnNames() ); + const OUString* pColumn = aColumns.getConstArray(); + const OUString* pColumnEnd = pColumn + aColumns.getLength(); + + for ( ; pColumn != pColumnEnd; ++pColumn ) + { + // get the properties of the column + pActFieldDescr = _rSourceObject.createFieldDescription( *pColumn ); + OSL_ENSURE( pActFieldDescr, "OCopyTableWizard::loadData: illegal field description!" ); + if ( !pActFieldDescr ) + continue; + + sal_Int32 nType = pActFieldDescr->GetType(); + sal_Int32 nScale = pActFieldDescr->GetScale(); + sal_Int32 nPrecision = pActFieldDescr->GetPrecision(); + bool bAutoIncrement = pActFieldDescr->IsAutoIncrement(); + OUString sTypeName = pActFieldDescr->GetTypeName(); + + // search for type + bool bForce; + TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,sCreateParam,nPrecision,nScale,bAutoIncrement,bForce); + if ( !pTypeInfo ) + pTypeInfo = m_pTypeInfo; + + pActFieldDescr->FillFromTypeInfo(pTypeInfo,true,false); + _rColVector.emplace_back(_rColumns.emplace(pActFieldDescr->GetName(),pActFieldDescr).first); + } + + // determine which columns belong to the primary key + Sequence< OUString > aPrimaryKeyColumns( _rSourceObject.getPrimaryKeyColumnNames() ); + const OUString* pKeyColName = aPrimaryKeyColumns.getConstArray(); + const OUString* pKeyColEnd = pKeyColName + aPrimaryKeyColumns.getLength(); + + for( ; pKeyColName != pKeyColEnd; ++pKeyColName ) + { + ODatabaseExport::TColumns::const_iterator keyPos = _rColumns.find( *pKeyColName ); + if ( keyPos != _rColumns.end() ) + { + keyPos->second->SetPrimaryKey( true ); + keyPos->second->SetIsNullable( ColumnValue::NO_NULLS ); + } + } +} + +void OCopyTableWizard::clearDestColumns() +{ + clearColumns(m_vDestColumns,m_aDestVec); + m_bAddPKFirstTime = true; + m_mNameMapping.clear(); +} + +void OCopyTableWizard::appendColumns( Reference<XColumnsSupplier> const & _rxColSup, const ODatabaseExport::TColumnVector* _pVec, bool _bKeyColumns) +{ + // now append the columns + OSL_ENSURE(_rxColSup.is(),"No columns supplier"); + if(!_rxColSup.is()) + return; + Reference<XNameAccess> xColumns = _rxColSup->getColumns(); + OSL_ENSURE(xColumns.is(),"No columns"); + Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); + + Reference<XAppend> xAppend(xColumns,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + for (auto const& elem : *_pVec) + { + OFieldDescription* pField = elem->second; + if(!pField) + continue; + + Reference<XPropertySet> xColumn; + if(pField->IsPrimaryKey() || !_bKeyColumns) + xColumn = xColumnFactory->createDataDescriptor(); + if(xColumn.is()) + { + if(!_bKeyColumns) + dbaui::setColumnProperties(xColumn,pField); + else + xColumn->setPropertyValue(PROPERTY_NAME,Any(pField->GetName())); + + xAppend->appendByDescriptor(xColumn); + xColumn = nullptr; + // now only the settings are missing + if(xColumns->hasByName(pField->GetName())) + { + xColumn.set(xColumns->getByName(pField->GetName()),UNO_QUERY); + OSL_ENSURE(xColumn.is(),"OCopyTableWizard::appendColumns: Column is NULL!"); + if ( xColumn.is() ) + pField->copyColumnSettingsTo(xColumn); + } + else + { + SAL_WARN("dbaccess.ui", "OCopyTableWizard::appendColumns: invalid field name!"); + } + + } + } +} + +void OCopyTableWizard::appendKey( Reference<XKeysSupplier> const & _rxSup, const ODatabaseExport::TColumnVector* _pVec) +{ + if(!_rxSup.is()) + return; // the database doesn't support keys + OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!"); + Reference<XDataDescriptorFactory> xKeyFactory(_rxSup->getKeys(),UNO_QUERY); + OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!"); + if ( !xKeyFactory.is() ) + return; + Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor(); + OSL_ENSURE(xKey.is(),"Key is null!"); + xKey->setPropertyValue(PROPERTY_TYPE,Any(KeyType::PRIMARY)); + + Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY); + if(xColSup.is()) + { + appendColumns(xColSup,_pVec,true); + Reference<XNameAccess> xColumns = xColSup->getColumns(); + if(xColumns.is() && xColumns->getElementNames().hasElements()) + xAppend->appendByDescriptor(xKey); + } + +} + +Reference< XPropertySet > OCopyTableWizard::createView() const +{ + OUString sCommand( m_rSourceObject.getSelectStatement() ); + OSL_ENSURE( !sCommand.isEmpty(), "OCopyTableWizard::createView: no statement in the source object!" ); + // there are legitimate cases in which getSelectStatement does not provide a statement, + // but in all those cases, this method here should never be called. + return ::dbaui::createView( m_sName, m_xDestConnection, sCommand ); +} + +Reference< XPropertySet > OCopyTableWizard::returnTable() +{ + if ( getOperation() == CopyTableOperation::AppendData ) + return getTable(); + else + return createTable(); +} + +Reference< XPropertySet > OCopyTableWizard::getTable() const +{ + Reference< XPropertySet > xTable; + + Reference<XTablesSupplier> xSup( m_xDestConnection, UNO_QUERY ); + Reference< XNameAccess > xTables; + if(xSup.is()) + xTables = xSup->getTables(); + if(xTables.is() && xTables->hasByName(m_sName)) + xTables->getByName(m_sName) >>= xTable; + + return xTable; +} + +Reference< XPropertySet > OCopyTableWizard::createTable() +{ + Reference< XPropertySet > xTable; + + Reference<XTablesSupplier> xSup( m_xDestConnection, UNO_QUERY ); + Reference< XNameAccess > xTables; + if(xSup.is()) + xTables = xSup->getTables(); + Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY); + OSL_ENSURE(xFact.is(),"No XDataDescriptorFactory available!"); + if(!xFact.is()) + return nullptr; + + xTable = xFact->createDataDescriptor(); + OSL_ENSURE(xTable.is(),"Could not create a new object!"); + if(!xTable.is()) + return nullptr; + + OUString sCatalog,sSchema,sTable; + Reference< XDatabaseMetaData> xMetaData = m_xDestConnection->getMetaData(); + ::dbtools::qualifiedNameComponents(xMetaData, + m_sName, + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + + if ( sCatalog.isEmpty() && xMetaData->supportsCatalogsInTableDefinitions() ) + { + sCatalog = m_xDestConnection->getCatalog(); + } + + if ( sSchema.isEmpty() && xMetaData->supportsSchemasInTableDefinitions() ) + { + // query of current schema is quite inconsistent. In case of some + // DBMS's each user has their own schema. + sSchema = xMetaData->getUserName(); + // In case of mysql it is not that simple + if(xMetaData->getDatabaseProductName() == "MySQL") + { + Reference< XStatement > xSelect = m_xDestConnection->createStatement(); + Reference< XResultSet > xRs = xSelect->executeQuery("select database()"); + (void)xRs->next(); // first and only result + Reference< XRow > xRow( xRs, UNO_QUERY_THROW ); + sSchema = xRow->getString(1); + } + } + + xTable->setPropertyValue(PROPERTY_CATALOGNAME,Any(sCatalog)); + xTable->setPropertyValue(PROPERTY_SCHEMANAME,Any(sSchema)); + xTable->setPropertyValue(PROPERTY_NAME,Any(sTable)); + + Reference< XColumnsSupplier > xSuppDestinationColumns( xTable, UNO_QUERY ); + // now append the columns + const ODatabaseExport::TColumnVector& rVec = getDestVector(); + appendColumns( xSuppDestinationColumns, &rVec ); + // now append the primary key + Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY); + appendKey(xKeySup, &rVec); + + Reference<XAppend> xAppend(xTables,UNO_QUERY); + if(xAppend.is()) + xAppend->appendByDescriptor(xTable); + + // xTable = NULL; + // we need to reget the table because after appending it, it is no longer valid + if(xTables->hasByName(m_sName)) + xTables->getByName(m_sName) >>= xTable; + else + { + OUString sComposedName( + ::dbtools::composeTableName( m_xDestConnection->getMetaData(), xTable, ::dbtools::EComposeRule::InDataManipulation, false ) ); + if(xTables->hasByName(sComposedName)) + { + xTables->getByName(sComposedName) >>= xTable; + m_sName = sComposedName; + } + else + xTable = nullptr; + } + + if(xTable.is()) + { + xSuppDestinationColumns.set( xTable, UNO_QUERY_THROW ); + // insert new table name into table filter + ::dbaui::appendToFilter(m_xDestConnection, m_sName, GetComponentContext(), m_xAssistant.get()); + + // copy ui settings + m_rSourceObject.copyUISettingsTo( xTable ); + //copy filter and sorting + m_rSourceObject.copyFilterAndSortingTo(m_xDestConnection,xTable); + // set column mappings + Reference<XNameAccess> xNameAccess = xSuppDestinationColumns->getColumns(); + Sequence< OUString> aSeq = xNameAccess->getElementNames(); + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + + for(sal_Int32 nNewPos=1;pIter != pEnd;++pIter,++nNewPos) + { + ODatabaseExport::TColumns::const_iterator aDestIter = m_vDestColumns.find(*pIter); + + if ( aDestIter != m_vDestColumns.end() ) + { + ODatabaseExport::TColumnVector::const_iterator aFind = std::find(m_aDestVec.begin(),m_aDestVec.end(),aDestIter); + sal_Int32 nPos = (aFind - m_aDestVec.begin())+1; + + ODatabaseExport::TPositions::iterator aPosFind = std::find_if( + m_vColumnPositions.begin(), + m_vColumnPositions.end(), + [nPos] (const ODatabaseExport::TPositions::value_type& tPos) { + return tPos.first == nPos; + } + ); + + if ( m_vColumnPositions.end() != aPosFind ) + { + aPosFind->second = nNewPos; + OSL_ENSURE( m_vColumnTypes.size() > o3tl::make_unsigned( aPosFind - m_vColumnPositions.begin() ), + "Invalid index for vector!" ); + m_vColumnTypes[ aPosFind - m_vColumnPositions.begin() ] = (*aFind)->second->GetType(); + } + } + } + } + + return xTable; +} + +bool OCopyTableWizard::supportsPrimaryKey( const Reference< XConnection >& _rxConnection ) +{ + OSL_PRECOND( _rxConnection.is(), "OCopyTableWizard::supportsPrimaryKey: invalid connection!" ); + if ( !_rxConnection.is() ) + return false; + + ::dbtools::DatabaseMetaData aMetaData( _rxConnection ); + return aMetaData.supportsPrimaryKeys(); +} + +bool OCopyTableWizard::supportsViews( const Reference< XConnection >& _rxConnection ) +{ + OSL_PRECOND( _rxConnection.is(), "OCopyTableWizard::supportsViews: invalid connection!" ); + if ( !_rxConnection.is() ) + return false; + + bool bSupportsViews( false ); + try + { + Reference< XDatabaseMetaData > xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW ); + Reference< XViewsSupplier > xViewSups( _rxConnection, UNO_QUERY ); + bSupportsViews = xViewSups.is(); + if ( !bSupportsViews ) + { + try + { + Reference< XResultSet > xRs( xMetaData->getTableTypes(), UNO_SET_THROW ); + Reference< XRow > xRow( xRs, UNO_QUERY_THROW ); + while ( xRs->next() ) + { + OUString sValue = xRow->getString( 1 ); + if ( !xRow->wasNull() && sValue.equalsIgnoreAsciiCase("View") ) + { + bSupportsViews = true; + break; + } + } + } + catch( const SQLException& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bSupportsViews; +} + +sal_Int32 OCopyTableWizard::getMaxColumnNameLength() const +{ + sal_Int32 nLen = 0; + if ( m_xDestConnection.is() ) + { + try + { + Reference< XDatabaseMetaData > xMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW ); + nLen = xMetaData->getMaxColumnNameLength(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + return nLen; +} + +void OCopyTableWizard::setOperation( const sal_Int16 _nOperation ) +{ + m_nOperation = _nOperation; +} + + +OUString OCopyTableWizard::convertColumnName(const TColumnFindFunctor& _rCmpFunctor, + const OUString& _sColumnName, + std::u16string_view _sExtraChars, + sal_Int32 _nMaxNameLen) +{ + OUString sAlias = _sColumnName; + if ( isSQL92CheckEnabled( m_xDestConnection ) ) + sAlias = ::dbtools::convertName2SQLName(_sColumnName,_sExtraChars); + if((_nMaxNameLen && sAlias.getLength() > _nMaxNameLen) || _rCmpFunctor(sAlias)) + { + sal_Int32 nDiff = 1; + do + { + ++nDiff; + if(_nMaxNameLen && sAlias.getLength() >= _nMaxNameLen) + sAlias = sAlias.copy(0,sAlias.getLength() - (sAlias.getLength()-_nMaxNameLen+nDiff)); + + OUString sName(sAlias); + sal_Int32 nPos = 1; + sName += OUString::number(nPos); + + while(_rCmpFunctor(sName)) + { + sName = sAlias + OUString::number(++nPos); + } + sAlias = sName; + // we have to check again, it could happen that the name is already too long + } + while(_nMaxNameLen && sAlias.getLength() > _nMaxNameLen); + } + OSL_ENSURE(m_mNameMapping.find(_sColumnName) == m_mNameMapping.end(),"name doubled!"); + m_mNameMapping[_sColumnName] = sAlias; + return sAlias; +} + +void OCopyTableWizard::removeColumnNameFromNameMap(const OUString& _sName) +{ + m_mNameMapping.erase(_sName); +} + +bool OCopyTableWizard::supportsType(sal_Int32 _nDataType, sal_Int32& _rNewDataType) +{ + bool bRet = m_aDestTypeInfo.find(_nDataType) != m_aDestTypeInfo.end(); + if ( bRet ) + _rNewDataType = _nDataType; + return bRet; +} + +TOTypeInfoSP OCopyTableWizard::convertType(const TOTypeInfoSP& _pType, bool& _bNotConvert) +{ + if ( !m_bInterConnectionCopy ) + // no need to convert if the source and destination connection are the same + return _pType; + + bool bForce; + TOTypeInfoSP pType = ::dbaui::getTypeInfoFromType(m_aDestTypeInfo,_pType->nType,_pType->aTypeName,_pType->aCreateParams,_pType->nPrecision,_pType->nMaximumScale,_pType->bAutoIncrement,bForce); + if ( !pType || bForce ) + { // no type found so we have to find the correct one ourself + sal_Int32 nDefaultType = DataType::VARCHAR; + switch(_pType->nType) + { + case DataType::TINYINT: + if(supportsType(DataType::SMALLINT,nDefaultType)) + break; + [[fallthrough]]; + case DataType::SMALLINT: + if(supportsType(DataType::INTEGER,nDefaultType)) + break; + [[fallthrough]]; + case DataType::INTEGER: + if(supportsType(DataType::FLOAT,nDefaultType)) + break; + [[fallthrough]]; + case DataType::FLOAT: + if(supportsType(DataType::REAL,nDefaultType)) + break; + [[fallthrough]]; + case DataType::DATE: + case DataType::TIME: + if( DataType::DATE == _pType->nType || DataType::TIME == _pType->nType ) + { + if(supportsType(DataType::TIMESTAMP,nDefaultType)) + break; + } + [[fallthrough]]; + case DataType::TIMESTAMP: + case DataType::REAL: + case DataType::BIGINT: + if ( supportsType(DataType::DOUBLE,nDefaultType) ) + break; + [[fallthrough]]; + case DataType::DOUBLE: + if ( supportsType(DataType::NUMERIC,nDefaultType) ) + break; + [[fallthrough]]; + case DataType::NUMERIC: + supportsType(DataType::DECIMAL,nDefaultType); + break; + case DataType::DECIMAL: + if ( supportsType(DataType::NUMERIC,nDefaultType) ) + break; + if ( supportsType(DataType::DOUBLE,nDefaultType) ) + break; + break; + case DataType::VARCHAR: + if ( supportsType(DataType::LONGVARCHAR,nDefaultType) ) + break; + break; + case DataType::LONGVARCHAR: + if ( supportsType(DataType::CLOB,nDefaultType) ) + break; + break; + case DataType::BINARY: + if ( supportsType(DataType::VARBINARY,nDefaultType) ) + break; + break; + case DataType::VARBINARY: + if ( supportsType(DataType::LONGVARBINARY,nDefaultType) ) + break; + break; + case DataType::LONGVARBINARY: + if ( supportsType(DataType::BLOB,nDefaultType) ) + break; + if ( supportsType(DataType::LONGVARCHAR,nDefaultType) ) + break; + if ( supportsType(DataType::CLOB,nDefaultType) ) + break; + break; + default: + nDefaultType = DataType::VARCHAR; + } + pType = ::dbaui::getTypeInfoFromType(m_aDestTypeInfo,nDefaultType,_pType->aTypeName,_pType->aCreateParams,_pType->nPrecision,_pType->nMaximumScale,_pType->bAutoIncrement,bForce); + if ( !pType ) + { + _bNotConvert = false; + pType = ::dbaui::getTypeInfoFromType(m_aDestTypeInfo,DataType::VARCHAR,_pType->aTypeName,"x",50,0,false,bForce); + if ( !pType ) + pType = m_pTypeInfo; + } + else if ( bForce ) + _bNotConvert = false; + } + return pType; +} + +OUString OCopyTableWizard::createUniqueName(const OUString& _sName) +{ + OUString sName = _sName; + Sequence< OUString > aColumnNames( m_rSourceObject.getColumnNames() ); + if ( aColumnNames.hasElements() ) + sName = ::dbtools::createUniqueName( aColumnNames, sName, false ); + else + { + if ( m_vSourceColumns.find(sName) != m_vSourceColumns.end()) + { + sal_Int32 nPos = 0; + while(m_vSourceColumns.find(sName) != m_vSourceColumns.end()) + { + sName = _sName + OUString::number(++nPos); + } + } + } + return sName; +} + +void OCopyTableWizard::showColumnTypeNotSupported(std::u16string_view _rColumnName) +{ + OUString sMessage( DBA_RES( STR_UNKNOWN_TYPE_FOUND ) ); + sMessage = sMessage.replaceFirst("#1",_rColumnName); + showError(sMessage); +} + +void OCopyTableWizard::showError(const OUString& _sErrorMessage) +{ + SQLExceptionInfo aInfo(_sErrorMessage); + showError(aInfo.get()); +} + +void OCopyTableWizard::showError(const Any& _aError) +{ + if ( _aError.hasValue() && m_xInteractionHandler.is() ) + { + try + { + ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( _aError ) ); + m_xInteractionHandler->handle( xRequest ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WExtendPages.cxx b/dbaccess/source/ui/misc/WExtendPages.cxx new file mode 100644 index 000000000..c7eac9181 --- /dev/null +++ b/dbaccess/source/ui/misc/WExtendPages.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 <WExtendPages.hxx> +#include <RtfReader.hxx> +#include <HtmlReader.hxx> +#include <WCopyTable.hxx> + +using namespace com::sun::star; + +namespace dbaui +{ + +void OWizHTMLExtend::createReaderAndCallParser(sal_Int32 _nRows) +{ + tools::SvRef<OHTMLReader> xParser = new OHTMLReader(*m_pParserStream, + _nRows, + std::vector(m_pParent->GetColumnPositions()), + m_pParent->GetFormatter(), + m_pParent->GetComponentContext(), + &m_pParent->getDestVector(), + &m_pParent->getTypeInfo(), + m_pParent->shouldCreatePrimaryKey()); + xParser->CallParser(); +} + +void OWizRTFExtend::createReaderAndCallParser(sal_Int32 _nRows) +{ + tools::SvRef<ORTFReader> xParser = new ORTFReader(*m_pParserStream, + _nRows, + std::vector(m_pParent->GetColumnPositions()), + m_pParent->GetFormatter(), + m_pParent->GetComponentContext(), + &m_pParent->getDestVector(), + &m_pParent->getTypeInfo(), + m_pParent->shouldCreatePrimaryKey()); + xParser->CallParser(); +} + +void OWizNormalExtend::createReaderAndCallParser(sal_Int32 /*_nRows*/) +{ +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WNameMatch.cxx b/dbaccess/source/ui/misc/WNameMatch.cxx new file mode 100644 index 000000000..a6bb59da8 --- /dev/null +++ b/dbaccess/source/ui/misc/WNameMatch.cxx @@ -0,0 +1,330 @@ +/* -*- 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 <WNameMatch.hxx> +#include <osl/diagnose.h> +#include <FieldDescriptions.hxx> +#include <WCopyTable.hxx> +#include <core_resource.hxx> +#include <strings.hrc> +#include <bitmaps.hlst> +#include <com/sun/star/sdbc/DataType.hpp> + +using namespace ::dbaui; + +// OWizColumnSelect +OWizNameMatching::OWizNameMatching(weld::Container* pPage, OCopyTableWizard* pWizard) + : OWizardPage(pPage, pWizard, "dbaccess/ui/namematchingpage.ui", "NameMatching") + , m_xTABLE_LEFT(m_xBuilder->weld_label("leftlabel")) + , m_xTABLE_RIGHT(m_xBuilder->weld_label("rightlabel")) + , m_xCTRL_LEFT(m_xBuilder->weld_tree_view("left")) + , m_xCTRL_RIGHT(m_xBuilder->weld_tree_view("right")) + , m_xColumn_up(m_xBuilder->weld_button("up")) + , m_xColumn_down(m_xBuilder->weld_button("down")) + , m_xColumn_up_right(m_xBuilder->weld_button("up_right")) + , m_xColumn_down_right(m_xBuilder->weld_button("down_right")) + , m_xAll(m_xBuilder->weld_button("all")) + , m_xNone(m_xBuilder->weld_button("none")) +{ + OUString aImgUp(BMP_UP); + OUString aImgDown(BMP_DOWN); + m_xColumn_up->set_from_icon_name(aImgUp); + m_xColumn_down->set_from_icon_name(aImgDown); + m_xColumn_up_right->set_from_icon_name(aImgUp); + m_xColumn_down_right->set_from_icon_name(aImgDown); + + m_xColumn_up->connect_clicked(LINK(this,OWizNameMatching,ButtonClickHdl)); + m_xColumn_down->connect_clicked(LINK(this,OWizNameMatching,ButtonClickHdl)); + + m_xColumn_up_right->connect_clicked(LINK(this,OWizNameMatching,RightButtonClickHdl)); + m_xColumn_down_right->connect_clicked(LINK(this,OWizNameMatching,RightButtonClickHdl)); + + m_xAll->connect_clicked(LINK(this,OWizNameMatching,AllNoneClickHdl)); + m_xNone->connect_clicked(LINK(this,OWizNameMatching,AllNoneClickHdl)); + + m_xCTRL_LEFT->enable_toggle_buttons(weld::ColumnToggleType::Check); + + m_xCTRL_LEFT->connect_changed(LINK(this,OWizNameMatching,TableListClickHdl)); + m_xCTRL_RIGHT->connect_changed(LINK(this,OWizNameMatching,TableListRightSelectHdl)); + + m_sSourceText = m_xTABLE_LEFT->get_label() + "\n"; + m_sDestText = m_xTABLE_RIGHT->get_label() + "\n"; +} + +OWizNameMatching::~OWizNameMatching() +{ +} + +void OWizNameMatching::Reset() +{ + m_bFirstTime = false; +} + +void OWizNameMatching::Activate( ) +{ + // set source table name + OUString aName = m_sSourceText + m_pParent->m_sSourceName; + + m_xTABLE_LEFT->set_label(aName); + + // set dest table name + aName = m_sDestText + m_pParent->m_sName; + m_xTABLE_RIGHT->set_label(aName); + + FillListBox(*m_xCTRL_LEFT, m_pParent->getSrcVector(), true); + FillListBox(*m_xCTRL_RIGHT, m_pParent->getDestVector(), false); + + m_xColumn_up->set_sensitive( m_xCTRL_LEFT->n_children() > 1 ); + m_xColumn_down->set_sensitive( m_xCTRL_LEFT->n_children() > 1 ); + + m_xColumn_up_right->set_sensitive( m_xCTRL_RIGHT->n_children() > 1 ); + m_xColumn_down_right->set_sensitive( m_xCTRL_RIGHT->n_children() > 1 ); + + m_pParent->EnableNextButton(false); + m_xCTRL_LEFT->grab_focus(); + TableListClickHdl(*m_xCTRL_LEFT); +} + +bool OWizNameMatching::LeavePage() +{ + + const ODatabaseExport::TColumnVector& rSrcColumns = m_pParent->getSrcVector(); + + m_pParent->m_vColumnPositions.clear(); + m_pParent->m_vColumnTypes.clear(); + m_pParent->m_vColumnPositions.resize( rSrcColumns.size(), ODatabaseExport::TPositions::value_type( COLUMN_POSITION_NOT_FOUND, COLUMN_POSITION_NOT_FOUND ) ); + m_pParent->m_vColumnTypes.resize( rSrcColumns.size(), COLUMN_POSITION_NOT_FOUND ); + + std::unique_ptr<weld::TreeIter> xLeftEntry = m_xCTRL_LEFT->make_iterator(); + std::unique_ptr<weld::TreeIter> xRightEntry = m_xCTRL_RIGHT->make_iterator(); + + sal_Int32 nParamPos = 0; + bool bLeftEntry = m_xCTRL_LEFT->get_iter_first(*xLeftEntry); + bool bRightEntry = m_xCTRL_RIGHT->get_iter_first(*xRightEntry); + while (bLeftEntry && bRightEntry) + { + OFieldDescription* pSrcField = weld::fromId<OFieldDescription*>(m_xCTRL_LEFT->get_id(*xLeftEntry)); + OSL_ENSURE(pSrcField,"OWizNameMatching: OColumn can not be null!"); + + sal_Int32 nPos = 0; + for (auto const& column : rSrcColumns) + { + if (column->second == pSrcField) + break; + ++nPos; + } + + if (m_xCTRL_LEFT->get_toggle(*xLeftEntry) == TRISTATE_TRUE) + { + OFieldDescription* pDestField = weld::fromId<OFieldDescription*>(m_xCTRL_RIGHT->get_id(*xRightEntry)); + OSL_ENSURE(pDestField,"OWizNameMatching: OColumn can not be null!"); + const ODatabaseExport::TColumnVector& rDestColumns = m_pParent->getDestVector(); + sal_Int32 nPosDest = 1; + bool bDestColumnFound = false; + TOTypeInfoSP typeInfoSPFound; + for (auto const& column : rDestColumns) + { + if (column->second == pDestField) + { + bDestColumnFound = true; + typeInfoSPFound = column->second->getSpecialTypeInfo(); + break; + } + ++nPosDest; + } + + OSL_ENSURE((nPos) < static_cast<sal_Int32>(m_pParent->m_vColumnPositions.size()),"m_pParent->m_vColumnPositions: Illegal index for vector"); + m_pParent->m_vColumnPositions[nPos].first = ++nParamPos; + m_pParent->m_vColumnPositions[nPos].second = nPosDest; + + TOTypeInfoSP pTypeInfo; + + assert(bDestColumnFound); + if (bDestColumnFound) + { + bool bNotConvert = true; + pTypeInfo = m_pParent->convertType(typeInfoSPFound, bNotConvert); + } + + sal_Int32 nType = css::sdbc::DataType::VARCHAR; + if ( pTypeInfo ) + nType = pTypeInfo->nType; + m_pParent->m_vColumnTypes[nPos] = nType; + } + else + { + m_pParent->m_vColumnPositions[nPos].first = COLUMN_POSITION_NOT_FOUND; + m_pParent->m_vColumnPositions[nPos].second = COLUMN_POSITION_NOT_FOUND; + } + + bLeftEntry = m_xCTRL_LEFT->iter_next(*xLeftEntry); + bRightEntry = m_xCTRL_RIGHT->iter_next(*xRightEntry); + } + + return true; +} + +OUString OWizNameMatching::GetTitle() const { return DBA_RES(STR_WIZ_NAME_MATCHING_TITLE); } + +IMPL_LINK(OWizNameMatching, ButtonClickHdl, weld::Button&, rButton, void) +{ + int nPos = m_xCTRL_LEFT->get_selected_index(); + if (nPos == -1) + return; + + int nOrigPos = nPos; + if (&rButton == m_xColumn_up.get() && nPos) + --nPos; + else if (&rButton == m_xColumn_down.get() && nPos < m_xCTRL_LEFT->n_children() - 1) + ++nPos; + + m_xCTRL_LEFT->swap(nOrigPos, nPos); + + m_xCTRL_LEFT->scroll_to_row(nPos); + + TableListClickHdl(*m_xCTRL_LEFT); +} + +IMPL_LINK( OWizNameMatching, RightButtonClickHdl, weld::Button&, rButton, void ) +{ + int nPos = m_xCTRL_RIGHT->get_selected_index(); + if (nPos == -1) + return; + + int nOrigPos = nPos; + if (&rButton == m_xColumn_up_right.get() && nPos) + --nPos; + else if (&rButton == m_xColumn_down_right.get() && nPos < m_xCTRL_RIGHT->n_children() - 1) + ++nPos; + + m_xCTRL_RIGHT->swap(nOrigPos, nPos); + + m_xCTRL_RIGHT->scroll_to_row(nPos); + + TableListRightSelectHdl(*m_xCTRL_RIGHT); +} + +namespace +{ + int GetFirstEntryInView(weld::TreeView& rTreeView) + { + int nFirstEntryInView = -1; + + rTreeView.visible_foreach([&nFirstEntryInView, &rTreeView](weld::TreeIter& rEntry){ + nFirstEntryInView = rTreeView.get_iter_index_in_parent(rEntry); + // stop after first entry + return true; + }); + + return nFirstEntryInView; + } +} + +IMPL_LINK_NOARG(OWizNameMatching, TableListClickHdl, weld::TreeView&, void) +{ + int nPos = m_xCTRL_LEFT->get_selected_index(); + if (nPos == -1) + return; + + int nOldEntry = m_xCTRL_RIGHT->get_selected_index(); + if (nOldEntry != -1 && nPos != nOldEntry) + { + m_xCTRL_RIGHT->unselect(nOldEntry); + if (nPos < m_xCTRL_RIGHT->n_children()) + { + int nNewPos = GetFirstEntryInView(*m_xCTRL_LEFT); + if ( nNewPos - nPos == 1 ) + --nNewPos; + m_xCTRL_RIGHT->scroll_to_row(nNewPos); + m_xCTRL_RIGHT->select(nPos); + } + } + else if (nOldEntry == -1) + { + if (nPos < m_xCTRL_RIGHT->n_children()) + m_xCTRL_RIGHT->select(nPos); + } +} + +IMPL_LINK_NOARG( OWizNameMatching, TableListRightSelectHdl, weld::TreeView&, void ) +{ + int nPos = m_xCTRL_RIGHT->get_selected_index(); + if (nPos == -1) + return; + + OFieldDescription* pColumn = weld::fromId<OFieldDescription*>(m_xCTRL_RIGHT->get_id(nPos)); + if (pColumn->IsAutoIncrement()) + { + m_xCTRL_RIGHT->unselect(nPos); + return; + } + + int nOldEntry = m_xCTRL_LEFT->get_selected_index(); + if (nOldEntry != -1 && nPos != nOldEntry) + { + m_xCTRL_LEFT->unselect(nOldEntry); + if (nPos < m_xCTRL_LEFT->n_children()) + { + int nNewPos = GetFirstEntryInView(*m_xCTRL_RIGHT); + if ( nNewPos - nPos == 1 ) + nNewPos--; + m_xCTRL_LEFT->scroll_to_row(nNewPos); + m_xCTRL_LEFT->select(nPos); + } + } + else if (nOldEntry == -1) + { + if (nPos < m_xCTRL_LEFT->n_children()) + m_xCTRL_LEFT->select(nPos); + } +} + +IMPL_LINK(OWizNameMatching, AllNoneClickHdl, weld::Button&, rButton, void) +{ + bool bAll = &rButton == m_xAll.get(); + m_xCTRL_LEFT->all_foreach([this, bAll](weld::TreeIter& rEntry){ + m_xCTRL_LEFT->set_toggle(rEntry, bAll ? TRISTATE_TRUE : TRISTATE_FALSE); + return false; + }); +} + +void OWizNameMatching::FillListBox(weld::TreeView& rTreeView, const ODatabaseExport::TColumnVector& rList, bool bCheckButtons) +{ + rTreeView.clear(); + + int nRow(0); + + for (auto const& elem : rList) + { + rTreeView.append(); + if (bCheckButtons) + { + bool bChecked = !elem->second->IsAutoIncrement(); + rTreeView.set_toggle(nRow, bChecked ? TRISTATE_TRUE : TRISTATE_FALSE); + } + rTreeView.set_text(nRow, elem->first, 0); + rTreeView.set_id(nRow, weld::toId(elem->second)); + ++nRow; + } + + if (rTreeView.n_children()) + rTreeView.select(0); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WTypeSelect.cxx b/dbaccess/source/ui/misc/WTypeSelect.cxx new file mode 100644 index 000000000..d5462ed3f --- /dev/null +++ b/dbaccess/source/ui/misc/WTypeSelect.cxx @@ -0,0 +1,417 @@ +/* -*- 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 <WTypeSelect.hxx> +#include <bitmaps.hlst> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <FieldDescriptions.hxx> +#include <WCopyTable.hxx> +#include <strings.hrc> +#include <tools/stream.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/svapp.hxx> +#include <UITools.hxx> +#include <core_resource.hxx> +#include <FieldControls.hxx> + +using namespace ::dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdbc; + +// OWizTypeSelectControl +OWizTypeSelectControl::OWizTypeSelectControl(weld::Container* pPage, OWizTypeSelect* pParentTabPage) + : OFieldDescControl(pPage, nullptr) + , m_pParentTabPage(pParentTabPage) +{ +} + +OWizTypeSelectControl::~OWizTypeSelectControl() +{ +} + +void OWizTypeSelectControl::ActivateAggregate( EControlType eType ) +{ + switch(eType ) + { + case tpFormat: + case tpDefault: + case tpAutoIncrement: + case tpAutoIncrementValue: + break; + default: + OFieldDescControl::ActivateAggregate( eType ); + } +} + +void OWizTypeSelectControl::DeactivateAggregate( EControlType eType ) +{ + switch(eType ) + { + case tpFormat: + case tpDefault: + case tpAutoIncrement: + case tpAutoIncrementValue: + break; + default: + OFieldDescControl::DeactivateAggregate( eType ); + } +} + +void OWizTypeSelectControl::CellModified(sal_Int32 nRow, sal_uInt16 nColId ) +{ + OSL_ENSURE(nRow == -1,"nRow must be -1!"); + + weld::TreeView* pListBox = m_pParentTabPage->m_xColumnNames->GetWidget(); + + OFieldDescription* pCurFieldDescr = getCurrentFieldDescData(); + + const sal_Int32 nPos = pListBox->find_text(pCurFieldDescr->GetName()); + pCurFieldDescr = weld::fromId<OFieldDescription*>(pListBox->get_id(nPos)); + OSL_ENSURE( pCurFieldDescr, "OWizTypeSelectControl::CellModified: Columnname/type not found in the listbox!" ); + if ( !pCurFieldDescr ) + return; + setCurrentFieldDescData( pCurFieldDescr ); + + OUString sName = pCurFieldDescr->GetName(); + OUString sNewName; + const OPropColumnEditCtrl* pColumnName = getColumnCtrl(); + if ( pColumnName ) + sNewName = pColumnName->get_text(); + + switch(nColId) + { + case FIELD_PROPERTY_COLUMNNAME: + { + OCopyTableWizard* pWiz = m_pParentTabPage->m_pParent; + // first we have to check if this name already exists + bool bDoubleName = false; + bool bCase = true; + if ( getMetaData().is() && !getMetaData()->supportsMixedCaseQuotedIdentifiers() ) + { + bCase = false; + const sal_Int32 nCount = pListBox->n_children(); + for (sal_Int32 i=0 ; !bDoubleName && i < nCount ; ++i) + { + OUString sEntry(pListBox->get_text(i)); + bDoubleName = sNewName.equalsIgnoreAsciiCase(sEntry); + } + if ( !bDoubleName && pWiz->shouldCreatePrimaryKey() ) + bDoubleName = sNewName.equalsIgnoreAsciiCase(pWiz->getPrimaryKeyName()); + + } + else + bDoubleName = ((pListBox->find_text(sNewName) != -1) + || ( pWiz->shouldCreatePrimaryKey() + && pWiz->getPrimaryKeyName() == sNewName) ); + + if ( bDoubleName ) + { + OUString strMessage = DBA_RES(STR_TABLEDESIGN_DUPLICATE_NAME); + strMessage = strMessage.replaceFirst("$column$", sNewName); + pWiz->showError(strMessage); + pCurFieldDescr->SetName(sName); + DisplayData(pCurFieldDescr); + m_pParentTabPage->setDuplicateName(true); + return; + } + + OUString sOldName = pCurFieldDescr->GetName(); + pCurFieldDescr->SetName(sNewName); + m_pParentTabPage->setDuplicateName(false); + + // now we change the name + + ::comphelper::UStringMixEqual aCase(bCase); + for (auto & elem : pWiz->m_mNameMapping) + { + if ( aCase(elem.second,sName) ) + { + elem.second = sNewName; + break; + } + } + + pListBox->remove(nPos); + pListBox->insert_text(nPos, pCurFieldDescr->GetName()); + pListBox->set_id(nPos, weld::toId(pCurFieldDescr)); + + pWiz->replaceColumn(nPos,pCurFieldDescr,sOldName); + } + break; + } + saveCurrentFieldDescData(); +} + +css::lang::Locale OWizTypeSelectControl::GetLocale() const +{ + return m_pParentTabPage->m_pParent->GetLocale(); +} + +Reference< XNumberFormatter > OWizTypeSelectControl::GetFormatter() const +{ + return m_pParentTabPage->m_pParent->GetFormatter(); +} + +TOTypeInfoSP OWizTypeSelectControl::getTypeInfo(sal_Int32 _nPos) +{ + return m_pParentTabPage->m_pParent->getDestTypeInfo(_nPos); +} + +const OTypeInfoMap* OWizTypeSelectControl::getTypeInfo() const +{ + return &m_pParentTabPage->m_pParent->getDestTypeInfo(); +} + +css::uno::Reference< css::sdbc::XDatabaseMetaData> OWizTypeSelectControl::getMetaData() +{ + return m_pParentTabPage->m_pParent->m_xDestConnection->getMetaData(); +} + +css::uno::Reference< css::sdbc::XConnection> OWizTypeSelectControl::getConnection() +{ + return m_pParentTabPage->m_pParent->m_xDestConnection; +} + +bool OWizTypeSelectControl::isAutoIncrementValueEnabled() const +{ + return m_pParentTabPage->m_bAutoIncrementEnabled; +} + +OUString OWizTypeSelectControl::getAutoIncrementValue() const +{ + return m_pParentTabPage->m_sAutoIncrementValue; +} + +OWizTypeSelect::OWizTypeSelect(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream* pStream) + : OWizardPage(pPage, pWizard, "dbaccess/ui/typeselectpage.ui", "TypeSelect") + , m_xColumnNames(new OWizTypeSelectList(m_xBuilder->weld_tree_view("columnnames"))) + , m_xColumns(m_xBuilder->weld_label("columns")) + , m_xControlContainer(m_xBuilder->weld_container("control_container")) + , m_xTypeControl(new OWizTypeSelectControl(m_xControlContainer.get(), this)) + , m_xAutoType(m_xBuilder->weld_label("autotype")) + , m_xAutoFt(m_xBuilder->weld_label("autolabel")) + , m_xAutoEt(m_xBuilder->weld_spin_button("auto")) + , m_xAutoPb(m_xBuilder->weld_button("autobutton")) + , m_pParserStream(pStream) + , m_nDisplayRow(0) + , m_bAutoIncrementEnabled(false) + , m_bDuplicateName(false) +{ + m_xColumnNames->connect_changed(LINK(this,OWizTypeSelect,ColumnSelectHdl)); + + m_xTypeControl->Init(); + + m_xAutoEt->set_text("10"); + m_xAutoEt->set_digits(0); + m_xAutoPb->connect_clicked(LINK(this,OWizTypeSelect,ButtonClickHdl)); + m_xColumnNames->set_selection_mode(SelectionMode::Multiple); + + try + { + m_xColumnNames->SetPKey( m_pParent->supportsPrimaryKey() ); + ::dbaui::fillAutoIncrementValue( m_pParent->m_xDestConnection, m_bAutoIncrementEnabled, m_sAutoIncrementValue ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +OWizTypeSelect::~OWizTypeSelect() +{ +} + +OUString OWizTypeSelect::GetTitle() const +{ + return DBA_RES(STR_WIZ_TYPE_SELECT_TITLE); +} + +IMPL_LINK_NOARG(OWizTypeSelect, ColumnSelectHdl, weld::TreeView&, void) +{ + OFieldDescription* pField = weld::fromId<OFieldDescription*>(m_xColumnNames->get_selected_id()); + if (pField) + m_xTypeControl->DisplayData(pField); + + m_xTypeControl->Enable(m_xColumnNames->count_selected_rows() == 1); +} + +void OWizTypeSelect::Reset() +{ + // restore original state + m_xColumnNames->clear(); + sal_Int32 nCount(0), nBreakPos; + m_pParent->CheckColumns(nBreakPos); + + const ODatabaseExport::TColumnVector& rDestColumns = m_pParent->getDestVector(); + for (auto const& column : rDestColumns) + { + OUString sId(weld::toId(column->second)); + m_xColumnNames->append(sId, column->first); + if (column->second->IsPrimaryKey()) + m_xColumnNames->set_image(nCount, BMP_PRIMARY_KEY); + ++nCount; + } + m_bFirstTime = false; +} + +void OWizTypeSelect::Activate( ) +{ + bool bOldFirstTime = m_bFirstTime; + Reset(); + m_bFirstTime = bOldFirstTime; + + m_xColumnNames->select(m_nDisplayRow); + m_nDisplayRow = 0; + ColumnSelectHdl(*m_xColumnNames->GetWidget()); +} + +bool OWizTypeSelect::LeavePage() +{ + bool bDuplicateName = false; + OFieldDescription* pField = weld::fromId<OFieldDescription*>(m_xColumnNames->get_selected_id()); + if ( pField ) + { + m_xTypeControl->SaveData(pField); + bDuplicateName = m_bDuplicateName; + } + return !bDuplicateName; +} + +void OWizTypeSelect::EnableAuto(bool bEnable) +{ + m_xAutoFt->set_visible(bEnable); + m_xAutoEt->set_visible(bEnable); + m_xAutoPb->set_visible(bEnable); + m_xAutoType->set_visible(bEnable); +} + +IMPL_LINK_NOARG(OWizTypeSelect, ButtonClickHdl, weld::Button&, void) +{ + sal_Int32 nBreakPos; + m_pParent->CheckColumns(nBreakPos); + + // fill column list + sal_uInt32 nRows = m_xAutoEt->get_text().toInt32(); + if(m_pParserStream) + { + sal_uInt64 const nTell = m_pParserStream->Tell(); // might change seek position of stream + + createReaderAndCallParser(nRows); + m_pParserStream->Seek(nTell); + } + + Activate(); +} + +OWizTypeSelectList::OWizTypeSelectList(std::unique_ptr<weld::TreeView> xControl) + : m_xControl(std::move(xControl)) + , m_bPKey(false) +{ + m_xControl->connect_popup_menu(LINK(this, OWizTypeSelectList, CommandHdl)); +} + +bool OWizTypeSelectList::IsPrimaryKeyAllowed() const +{ + auto aRows = m_xControl->get_selected_rows(); + std::sort(aRows.begin(), aRows.end()); + + const sal_Int32 nCount = aRows.size(); + + for( sal_Int32 j = 0; m_bPKey && j < nCount; ++j ) + { + OFieldDescription* pField = weld::fromId<OFieldDescription*>(m_xControl->get_id(aRows[j])); + if(!pField || pField->getTypeInfo()->nSearchType == ColumnSearch::NONE) + return false; + } + return true; +} + +void OWizTypeSelectList::setPrimaryKey(OFieldDescription* _pFieldDescr, sal_uInt16 _nPos, bool _bSet) +{ + _pFieldDescr->SetPrimaryKey(_bSet); + if( _bSet ) + { + m_xControl->set_image(_nPos, BMP_PRIMARY_KEY); + } + else if( _pFieldDescr->getTypeInfo()->bNullable ) + { + _pFieldDescr->SetControlDefault(Any()); + m_xControl->set_image(_nPos, OUString()); + } +} + +IMPL_LINK(OWizTypeSelectList, CommandHdl, const CommandEvent&, rCEvt, bool) +{ + if (rCEvt.GetCommand() != CommandEventId::ContextMenu) + return false; + if (!IsPrimaryKeyAllowed()) + return false; + + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xControl.get(), "dbaccess/ui/keymenu.ui")); + auto xContextMenu = xBuilder->weld_menu("menu"); + // Should primary key checkbox be checked? + const sal_Int32 nCount = m_xControl->n_children(); + bool bCheckOk = false; + for(sal_Int32 j = 0 ; j < nCount ; ++j) + { + OFieldDescription* pFieldDescr = weld::fromId<OFieldDescription*>(m_xControl->get_id(j)); + // if at least one of the fields is selected but not in the primary key, + // or is in the primary key but not selected, then don't check the + // primary key checkbox. + if( pFieldDescr && pFieldDescr->IsPrimaryKey() != m_xControl->is_selected(j) ) + { + bCheckOk = false; + break; + } + if (!bCheckOk && m_xControl->is_selected(j)) + bCheckOk = true; + } + + if (bCheckOk) + xContextMenu->set_active("primarykey", true); + + OString sCommand(xContextMenu->popup_at_rect(m_xControl.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)))); + if (sCommand != "primarykey") + return true; + + for (sal_Int32 j = 0 ; j < nCount; ++j) + { + OFieldDescription* pFieldDescr = weld::fromId<OFieldDescription*>(m_xControl->get_id(j)); + if (pFieldDescr) + { + if(!bCheckOk && m_xControl->is_selected(j)) + { + setPrimaryKey(pFieldDescr,j,true); + } + else + { + setPrimaryKey(pFieldDescr,j); + } + } + } + m_aChangeHdl.Call(*m_xControl); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/asyncmodaldialog.cxx b/dbaccess/source/ui/misc/asyncmodaldialog.cxx new file mode 100644 index 000000000..3c59a58f8 --- /dev/null +++ b/dbaccess/source/ui/misc/asyncmodaldialog.cxx @@ -0,0 +1,91 @@ +/* -*- 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 <asyncmodaldialog.hxx> + +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +#include <vcl/svapp.hxx> +#include <tools/diagnose_ex.h> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::ui::dialogs::XExecutableDialog; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::uno::Exception; + + namespace { + + // AsyncDialogExecutor + class DialogExecutor_Impl + { + Reference< XExecutableDialog > m_xDialog; + + public: + explicit DialogExecutor_Impl( const Reference< XExecutableDialog >& _rxDialog ) + :m_xDialog( _rxDialog ) + { + } + + void execute() + { + Application::PostUserEvent( LINK( this, DialogExecutor_Impl, onExecute ) ); + } + + protected: + ~DialogExecutor_Impl() + { + } + + private: + DECL_LINK( onExecute, void*, void ); + }; + + } + + IMPL_LINK_NOARG( DialogExecutor_Impl, onExecute, void*, void ) + { + try + { + m_xDialog->execute(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + delete this; + } + + // AsyncDialogExecutor + void AsyncDialogExecutor::executeModalDialogAsync( const Reference< XExecutableDialog >& _rxDialog ) + { + if ( !_rxDialog.is() ) + throw IllegalArgumentException(); + + DialogExecutor_Impl* pExecutor = new DialogExecutor_Impl( _rxDialog ); + pExecutor->execute(); + // will delete itself + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/charsets.cxx b/dbaccess/source/ui/misc/charsets.cxx new file mode 100644 index 000000000..546d21cb0 --- /dev/null +++ b/dbaccess/source/ui/misc/charsets.cxx @@ -0,0 +1,130 @@ +/* -*- 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 <charsets.hxx> +#include <core_resource.hxx> +#include <osl/diagnose.h> +#include <strings.hrc> +#include <rtl/tencinfo.h> +#include <svx/txenctab.hxx> + +namespace dbaui +{ + using namespace ::dbtools; + + // OCharsetDisplay + OCharsetDisplay::OCharsetDisplay() + : m_aSystemDisplayName(DBA_RES( STR_RSC_CHARSETS )) + { + } + + bool OCharsetDisplay::approveEncoding( const rtl_TextEncoding _eEncoding, const rtl_TextEncodingInfo& _rInfo ) const + { + if ( !OCharsetMap::approveEncoding( _eEncoding, _rInfo ) ) + return false; + + if ( RTL_TEXTENCODING_DONTKNOW == _eEncoding ) + return true; + + return !SvxTextEncodingTable::GetTextString(_eEncoding).isEmpty(); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::begin() const + { + return const_iterator( this, OCharsetMap::begin() ); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::end() const + { + return const_iterator( this, OCharsetMap::end() ); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::findEncoding(const rtl_TextEncoding _eEncoding) const + { + OCharsetMap::const_iterator aBaseIter = OCharsetMap::find(_eEncoding); + return const_iterator( this, aBaseIter ); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::findIanaName(const OUString& _rIanaName) const + { + OCharsetMap::const_iterator aBaseIter = OCharsetMap::findIanaName(_rIanaName); + return const_iterator( this, aBaseIter ); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::findDisplayName(const OUString& _rDisplayName) const + { + rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW; + if ( _rDisplayName != m_aSystemDisplayName ) + { + eEncoding = SvxTextEncodingTable::GetTextEncoding(_rDisplayName); + OSL_ENSURE( RTL_TEXTENCODING_DONTKNOW != eEncoding, + "OCharsetDisplay::find: non-empty display name, but DONTKNOW!" ); + } + return const_iterator( this, OCharsetMap::find( eEncoding ) ); + } + + // CharsetDisplayDerefHelper + CharsetDisplayDerefHelper::CharsetDisplayDerefHelper(const CharsetDisplayDerefHelper& _rSource) + :CharsetDisplayDerefHelper_Base(_rSource) + ,m_sDisplayName(_rSource.m_sDisplayName) + { + } + + CharsetDisplayDerefHelper::CharsetDisplayDerefHelper(const ::dbtools::CharsetIteratorDerefHelper& _rBase, const OUString& _rDisplayName) + :CharsetDisplayDerefHelper_Base(_rBase) + ,m_sDisplayName(_rDisplayName) + { + OSL_ENSURE( !m_sDisplayName.isEmpty(), "CharsetDisplayDerefHelper::CharsetDisplayDerefHelper: invalid display name!" ); + } + + // OCharsetDisplay::ExtendedCharsetIterator + OCharsetDisplay::ExtendedCharsetIterator::ExtendedCharsetIterator( const OCharsetDisplay* _pContainer, const base_iterator& _rPosition ) + :m_pContainer(_pContainer) + ,m_aPosition(_rPosition) + { + OSL_ENSURE(m_pContainer, "OCharsetDisplay::ExtendedCharsetIterator::ExtendedCharsetIterator : invalid container!"); + } + + CharsetDisplayDerefHelper OCharsetDisplay::ExtendedCharsetIterator::operator*() const + { + OSL_ENSURE( m_aPosition != m_pContainer->OCharsetDisplay_Base::end(), "OCharsetDisplay::ExtendedCharsetIterator::operator* : invalid position!"); + + rtl_TextEncoding eEncoding = (*m_aPosition).getEncoding(); + return CharsetDisplayDerefHelper( + *m_aPosition, + RTL_TEXTENCODING_DONTKNOW == eEncoding ? m_pContainer->m_aSystemDisplayName : SvxTextEncodingTable::GetTextString(eEncoding) + ); + } + + const OCharsetDisplay::ExtendedCharsetIterator& OCharsetDisplay::ExtendedCharsetIterator::operator++() + { + OSL_ENSURE( m_aPosition != m_pContainer->OCharsetDisplay_Base::end(), "OCharsetDisplay::ExtendedCharsetIterator::operator++ : invalid position!"); + if ( m_aPosition != m_pContainer->OCharsetDisplay_Base::end() ) + ++m_aPosition; + return *this; + } + + bool operator==(const OCharsetDisplay::ExtendedCharsetIterator& lhs, const OCharsetDisplay::ExtendedCharsetIterator& rhs) + { + return (lhs.m_pContainer == rhs.m_pContainer) && (lhs.m_aPosition == rhs.m_aPosition); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/controllerframe.cxx b/dbaccess/source/ui/misc/controllerframe.cxx new file mode 100644 index 000000000..3634a56eb --- /dev/null +++ b/dbaccess/source/ui/misc/controllerframe.cxx @@ -0,0 +1,390 @@ +/* -*- 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 <dbaccess/controllerframe.hxx> +#include <dbaccess/IController.hxx> + +#include <com/sun/star/awt/XTopWindow.hpp> +#include <com/sun/star/awt/XWindow2.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/document/XDocumentEventBroadcaster.hpp> +#include <com/sun/star/frame/XController2.hpp> + +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> +#include <sfx2/objsh.hxx> +#include <tools/diagnose_ex.h> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/window.hxx> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::frame::XFrame; + using ::com::sun::star::frame::FrameAction; + using ::com::sun::star::frame::FrameAction_FRAME_ACTIVATED; + using ::com::sun::star::frame::FrameAction_FRAME_UI_ACTIVATED; + using ::com::sun::star::frame::FrameAction_FRAME_DEACTIVATING; + using ::com::sun::star::frame::FrameAction_FRAME_UI_DEACTIVATING; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::frame::XController; + using ::com::sun::star::frame::XController2; + using ::com::sun::star::awt::XTopWindow; + using ::com::sun::star::awt::XTopWindowListener; + using ::com::sun::star::awt::XWindow2; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::document::XDocumentEventBroadcaster; + using ::com::sun::star::awt::XWindow; + + // FrameWindowActivationListener + typedef ::cppu::WeakImplHelper< XTopWindowListener + > FrameWindowActivationListener_Base; + + namespace { + + class FrameWindowActivationListener : public FrameWindowActivationListener_Base + { + public: + explicit FrameWindowActivationListener( ControllerFrame_Data& _rData ); + + void dispose(); + + protected: + virtual ~FrameWindowActivationListener() override; + + // XTopWindowListener + virtual void SAL_CALL windowOpened( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowClosing( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowClosed( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowMinimized( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowNormalized( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowActivated( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowDeactivated( const css::lang::EventObject& e ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + private: + void impl_checkDisposed_throw() const; + void impl_registerOnFrameContainerWindow_nothrow( bool _bRegister ); + + private: + ControllerFrame_Data* m_pData; + }; + + } + + // ControllerFrame_Data + struct ControllerFrame_Data + { + explicit ControllerFrame_Data( IController& _rController ) + :m_rController( _rController ) + ,m_bActive( false ) + ,m_bIsTopLevelDocumentWindow( false ) + { + } + + IController& m_rController; + Reference< XFrame > m_xFrame; + Reference< XDocumentEventBroadcaster > m_xDocEventBroadcaster; + ::rtl::Reference< FrameWindowActivationListener > m_pListener; + bool m_bActive; + bool m_bIsTopLevelDocumentWindow; + }; + + // helper + static void lcl_setFrame_nothrow( ControllerFrame_Data& _rData, const Reference< XFrame >& _rxFrame ) + { + // release old listener + if (_rData.m_pListener) + { + _rData.m_pListener->dispose(); + _rData.m_pListener = nullptr; + } + + // remember new frame + _rData.m_xFrame = _rxFrame; + + // create new listener + if ( _rData.m_xFrame.is() ) + _rData.m_pListener = new FrameWindowActivationListener( _rData ); + + // at this point in time, we can assume the controller also has a model set, if it supports models + try + { + Reference< XController > xController( _rData.m_rController.getXController(), UNO_SET_THROW ); + Reference< XModel > xModel( xController->getModel() ); + if ( xModel.is() ) + _rData.m_xDocEventBroadcaster.set( xModel, UNO_QUERY ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + static bool lcl_isActive_nothrow( const Reference< XFrame >& _rxFrame ) + { + bool bIsActive = false; + try + { + if ( _rxFrame.is() ) + { + Reference< XWindow2 > xWindow( _rxFrame->getContainerWindow(), UNO_QUERY_THROW ); + bIsActive = xWindow->isActive(); + } + + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bIsActive; + } + + /** updates various global and local states with a new active component + + In particular, the following are updated + * the global working document (aka Basic's ThisComponent in the application + Basic), with our controller's model, or the controller itself if there is no such + model. + */ + static void lcl_updateActiveComponents_nothrow( const ControllerFrame_Data& _rData ) + { + try + { + Reference< XController > xCompController( _rData.m_rController.getXController() ); + OSL_ENSURE( xCompController.is(), "lcl_updateActiveComponents_nothrow: can't do anything without a controller!" ); + if ( !xCompController.is() ) + return; + + if ( _rData.m_bActive && _rData.m_bIsTopLevelDocumentWindow ) + { + // set the "current component" at the SfxObjectShell + Reference< XModel > xModel( xCompController->getModel() ); + Reference< XInterface > xCurrentComponent; + if ( xModel.is() ) + xCurrentComponent = xModel; + else + xCurrentComponent = xCompController; + SfxObjectShell::SetCurrentComponent( xCurrentComponent ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + /** broadcasts the OnFocus resp. OnUnfocus event + */ + static void lcl_notifyFocusChange_nothrow( ControllerFrame_Data& _rData, bool _bActive ) + { + try + { + if ( _rData.m_xDocEventBroadcaster.is() ) + { + OUString sEventName = _bActive ? OUString("OnFocus") : OUString("OnUnfocus"); + Reference< XController2 > xController( _rData.m_rController.getXController(), UNO_QUERY_THROW ); + _rData.m_xDocEventBroadcaster->notifyDocumentEvent( sEventName, xController, Any() ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + static void lcl_updateActive_nothrow( ControllerFrame_Data& _rData, bool _bActive ) + { + if ( _rData.m_bActive == _bActive ) + return; + _rData.m_bActive = _bActive; + + lcl_updateActiveComponents_nothrow( _rData ); + lcl_notifyFocusChange_nothrow( _rData, _bActive ); + } + + FrameWindowActivationListener::FrameWindowActivationListener( ControllerFrame_Data& _rData ) + :m_pData( &_rData ) + { + impl_registerOnFrameContainerWindow_nothrow( true ); + } + + FrameWindowActivationListener::~FrameWindowActivationListener() + { + } + + void FrameWindowActivationListener::dispose() + { + impl_registerOnFrameContainerWindow_nothrow( false ); + m_pData = nullptr; + } + + void FrameWindowActivationListener::impl_registerOnFrameContainerWindow_nothrow( bool _bRegister ) + { + OSL_ENSURE( m_pData && m_pData->m_xFrame.is(), "FrameWindowActivationListener::impl_registerOnFrameContainerWindow_nothrow: no frame!" ); + if ( !m_pData || !m_pData->m_xFrame.is() ) + return; + + try + { + void ( SAL_CALL XTopWindow::*pListenerAction )( const Reference< XTopWindowListener >& ) = + _bRegister ? &XTopWindow::addTopWindowListener : &XTopWindow::removeTopWindowListener; + + const Reference< XWindow > xContainerWindow( m_pData->m_xFrame->getContainerWindow(), UNO_SET_THROW ); + if ( _bRegister ) + { + const vcl::Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow ); + ENSURE_OR_THROW( pContainerWindow, "no Window implementation for the frame's container window!" ); + + m_pData->m_bIsTopLevelDocumentWindow = bool( pContainerWindow->GetExtendedStyle() & WindowExtendedStyle::Document ); + } + + const Reference< XTopWindow > xFrameContainer( xContainerWindow, UNO_QUERY ); + if ( xFrameContainer.is() ) + (xFrameContainer.get()->*pListenerAction)( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void FrameWindowActivationListener::impl_checkDisposed_throw() const + { + if ( !m_pData ) + throw DisposedException( OUString(), *const_cast< FrameWindowActivationListener* >( this ) ); + } + + void SAL_CALL FrameWindowActivationListener::windowOpened( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowClosing( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowClosed( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowMinimized( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowNormalized( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowActivated( const EventObject& /*_rEvent*/ ) + { + impl_checkDisposed_throw(); + lcl_updateActive_nothrow( *m_pData, true ); + } + + void SAL_CALL FrameWindowActivationListener::windowDeactivated( const EventObject& /*_rEvent*/ ) + { + impl_checkDisposed_throw(); + lcl_updateActive_nothrow( *m_pData, false ); + } + + void SAL_CALL FrameWindowActivationListener::disposing( const EventObject& /*_rEvent*/ ) + { + dispose(); + } + + // ControllerFrame + ControllerFrame::ControllerFrame( IController& _rController ) + :m_pData( new ControllerFrame_Data( _rController ) ) + { + } + + ControllerFrame::~ControllerFrame() + { + } + + const Reference< XFrame >& ControllerFrame::attachFrame( const Reference< XFrame >& _rxFrame ) + { + // set new frame, including listener handling + lcl_setFrame_nothrow( *m_pData, _rxFrame ); + + // determine whether we're active + m_pData->m_bActive = lcl_isActive_nothrow( m_pData->m_xFrame ); + + // update active component + if ( m_pData->m_bActive ) + { + lcl_updateActiveComponents_nothrow( *m_pData ); + lcl_notifyFocusChange_nothrow( *m_pData, true ); + } + + return m_pData->m_xFrame; + } + + const Reference< XFrame >& ControllerFrame::getFrame() const + { + return m_pData->m_xFrame; + } + + bool ControllerFrame::isActive() const + { + return m_pData->m_bActive; + } + + void ControllerFrame::frameAction( FrameAction _eAction ) + { + bool bActive = m_pData->m_bActive; + + switch ( _eAction ) + { + case FrameAction_FRAME_ACTIVATED: + case FrameAction_FRAME_UI_ACTIVATED: + bActive = true; + break; + + case FrameAction_FRAME_DEACTIVATING: + case FrameAction_FRAME_UI_DEACTIVATING: + bActive = false; + break; + + default: + break; + } + + lcl_updateActive_nothrow( *m_pData, bActive ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/databaseobjectview.cxx b/dbaccess/source/ui/misc/databaseobjectview.cxx new file mode 100644 index 000000000..cb4478295 --- /dev/null +++ b/dbaccess/source/ui/misc/databaseobjectview.cxx @@ -0,0 +1,280 @@ +/* -*- 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 <databaseobjectview.hxx> +#include <strings.hxx> +#include <asyncmodaldialog.hxx> + +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/frame/TaskCreator.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/application/XTableUIProvider.hpp> +#include <com/sun/star/beans/NamedValue.hpp> + +#include <connectivity/dbtools.hxx> +#include <osl/diagnose.h> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/window.hxx> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::sdb::application; + using namespace ::com::sun::star::ui::dialogs; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::awt; + + // DatabaseObjectView + DatabaseObjectView::DatabaseObjectView( const Reference< XComponentContext >& _rxORB, + const Reference< XDatabaseDocumentUI >& _rxApplication, + const Reference< XFrame >& _rxParentFrame, + const OUString& _rComponentURL ) + :m_xORB ( _rxORB ) + ,m_xParentFrame ( _rxParentFrame ) + ,m_xApplication ( _rxApplication ) + ,m_sComponentURL ( _rComponentURL ) + { + OSL_ENSURE( m_xORB.is(), "DatabaseObjectView::DatabaseObjectView: invalid service factory!" ); + OSL_ENSURE( m_xApplication.is(), "DatabaseObjectView::DatabaseObjectView: invalid connection!" ); + } + + Reference< XConnection > DatabaseObjectView::getConnection() const + { + Reference< XConnection > xConnection; + if ( m_xApplication.is() ) + xConnection = m_xApplication->getActiveConnection(); + return xConnection; + } + + Reference< XComponent > DatabaseObjectView::createNew( const Reference< XDataSource >& _xDataSource, const ::comphelper::NamedValueCollection& i_rDispatchArgs ) + { + return doCreateView( Any( _xDataSource ), OUString(), i_rDispatchArgs ); + } + + Reference< XComponent > DatabaseObjectView::openExisting( const Any& _rDataSource, const OUString& _rName, + const ::comphelper::NamedValueCollection& i_rDispatchArgs ) + { + return doCreateView( _rDataSource, _rName, i_rDispatchArgs ); + } + + Reference< XComponent > DatabaseObjectView::doCreateView( const Any& _rDataSource, const OUString& _rObjectName, + const ::comphelper::NamedValueCollection& i_rCreationArgs ) + { + ::comphelper::NamedValueCollection aDispatchArgs; + + aDispatchArgs.merge( i_rCreationArgs, false ); // false => do not overwrite + fillDispatchArgs( aDispatchArgs, _rDataSource, _rObjectName ); + aDispatchArgs.merge( i_rCreationArgs, true ); // true => do overwrite + + return doDispatch( aDispatchArgs ); + } + + Reference< XComponent > DatabaseObjectView::doDispatch( const ::comphelper::NamedValueCollection& i_rDispatchArgs ) + { + Reference< XComponent > xReturn; + if ( m_xORB.is() ) + { + try + { + // if we have no externally provided frame, create one + if ( !m_xFrameLoader.is() ) + { + Reference< XSingleServiceFactory > xFact = TaskCreator::create(m_xORB); + Sequence< Any > lArgs{ Any(NamedValue("ParentFrame", Any(m_xParentFrame))), + Any(NamedValue("TopWindow", Any(true))), + Any(NamedValue("SupportPersistentWindowState", + Any(true))) }; + + m_xFrameLoader.set(xFact->createInstanceWithArguments(lArgs), UNO_QUERY_THROW); + + // everything we load can be considered a "top level document", so set the respective bit at the window. + // This, amongst other things, triggers that the component in this task participates in the + // "ThisComponent"-game for the global application Basic. + const Reference< XFrame > xFrame( m_xFrameLoader, UNO_QUERY_THROW ); + const Reference< XWindow > xFrameWindow( xFrame->getContainerWindow(), UNO_SET_THROW ); + VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( xFrameWindow ); + ENSURE_OR_THROW( pContainerWindow, "no implementation access to the frame's container window!" ); + pContainerWindow->SetExtendedStyle( pContainerWindow->GetExtendedStyle() | WindowExtendedStyle::Document ); + } + + Reference< XComponentLoader > xFrameLoader( m_xFrameLoader, UNO_SET_THROW ); + xReturn = xFrameLoader->loadComponentFromURL( + m_sComponentURL, + "_self", + 0, + i_rDispatchArgs.getPropertyValues() + ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + return xReturn; + } + + void DatabaseObjectView::fillDispatchArgs( + ::comphelper::NamedValueCollection& i_rDispatchArgs, + const Any& _aDataSource, + const OUString& /* _rName */ + ) + { + OUString sDataSource; + Reference<XDataSource> xDataSource; + if ( _aDataSource >>= sDataSource ) + { + i_rDispatchArgs.put( PROPERTY_DATASOURCENAME, sDataSource ); + } + else if ( _aDataSource >>= xDataSource ) + { + i_rDispatchArgs.put( PROPERTY_DATASOURCE, xDataSource ); + } + + i_rDispatchArgs.put( PROPERTY_ACTIVE_CONNECTION, getConnection() ); + } + + // QueryDesigner + QueryDesigner::QueryDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, + const Reference< XFrame >& _rxParentFrame, bool _bCreateView ) + :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, _bCreateView ? OUString(URL_COMPONENT_VIEWDESIGN) : OUString(URL_COMPONENT_QUERYDESIGN) ) + ,m_nCommandType( _bCreateView ? CommandType::TABLE : CommandType::QUERY ) + { + } + + void QueryDesigner::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource, + const OUString& _rObjectName ) + { + DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rObjectName ); + + const bool bIncludeQueryName = !_rObjectName.isEmpty(); + const bool bGraphicalDesign = i_rDispatchArgs.getOrDefault( PROPERTY_GRAPHICAL_DESIGN, true ); + const bool bEditViewAsSQLCommand = ( m_nCommandType == CommandType::TABLE ) && !bGraphicalDesign; + + i_rDispatchArgs.put( PROPERTY_COMMAND_TYPE, m_nCommandType ); + + if ( bIncludeQueryName ) + { + i_rDispatchArgs.put( PROPERTY_COMMAND, _rObjectName ); + } + + if ( bEditViewAsSQLCommand ) + { + i_rDispatchArgs.put( PROPERTY_ESCAPE_PROCESSING, false ); + } + } + + // TableDesigner + TableDesigner::TableDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame ) + :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast< OUString >( URL_COMPONENT_TABLEDESIGN ) ) + { + } + + void TableDesigner::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource, + const OUString& _rObjectName ) + { + DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rObjectName ); + + if ( !_rObjectName.isEmpty() ) + { + i_rDispatchArgs.put( PROPERTY_CURRENTTABLE, _rObjectName ); + } + } + + Reference< XComponent > TableDesigner::doCreateView( const Any& _rDataSource, const OUString& _rObjectName, + const ::comphelper::NamedValueCollection& i_rCreationArgs ) + { + bool bIsNewDesign = _rObjectName.isEmpty(); + + // let's see whether the connection can provide a dedicated table designer + Reference< XInterface > xDesigner; + if ( !bIsNewDesign ) + xDesigner = impl_getConnectionProvidedDesigner_nothrow( _rObjectName ); + + if ( !xDesigner.is() ) + return DatabaseObjectView::doCreateView( _rDataSource, _rObjectName, i_rCreationArgs ); + + // try whether the designer is a dialog + Reference< XExecutableDialog > xDialog( xDesigner, UNO_QUERY_THROW ); + try { AsyncDialogExecutor::executeModalDialogAsync( xDialog ); } + catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); } + return nullptr; + } + + Reference< XInterface > TableDesigner::impl_getConnectionProvidedDesigner_nothrow( const OUString& _rTableName ) + { + Reference< XInterface > xDesigner; + try + { + Reference< XTableUIProvider > xTableUIProv( getConnection(), UNO_QUERY ); + if ( xTableUIProv.is() ) + xDesigner = xTableUIProv->getTableEditor( getApplicationUI(), _rTableName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return xDesigner; + } + + // ResultSetBrowser + ResultSetBrowser::ResultSetBrowser( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame, + bool _bTable ) + :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast < OUString >( URL_COMPONENT_DATASOURCEBROWSER ) ) + ,m_bTable(_bTable) + { + } + + void ResultSetBrowser::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource, + const OUString& _rQualifiedName) + { + DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rQualifiedName ); + OSL_ENSURE( !_rQualifiedName.isEmpty(),"A Table name must be set"); + OUString sCatalog; + OUString sSchema; + OUString sTable; + if ( m_bTable ) + ::dbtools::qualifiedNameComponents( getConnection()->getMetaData(), _rQualifiedName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation ); + + i_rDispatchArgs.put( PROPERTY_COMMAND_TYPE, (m_bTable ? CommandType::TABLE : CommandType::QUERY) ); + i_rDispatchArgs.put( PROPERTY_COMMAND, _rQualifiedName ); + i_rDispatchArgs.put( PROPERTY_ENABLE_BROWSER, false ); + + if ( m_bTable ) + { + i_rDispatchArgs.put( PROPERTY_UPDATE_CATALOGNAME, sCatalog ); + i_rDispatchArgs.put( PROPERTY_UPDATE_SCHEMANAME, sSchema ); + i_rDispatchArgs.put( PROPERTY_UPDATE_TABLENAME, sTable ); + } + } + + // RelationDesigner + RelationDesigner::RelationDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame ) + :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast< OUString >( URL_COMPONENT_RELATIONDESIGN ) ) + { + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/datasourceconnector.cxx b/dbaccess/source/ui/misc/datasourceconnector.cxx new file mode 100644 index 000000000..49053e569 --- /dev/null +++ b/dbaccess/source/ui/misc/datasourceconnector.cxx @@ -0,0 +1,202 @@ +/* -*- 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 <core_resource.hxx> +#include <datasourceconnector.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdb/XCompletedConnection.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <comphelper/namedvaluecollection.hxx> +#include <connectivity/dbexception.hxx> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <UITools.hxx> +#include <vcl/outdev.hxx> +#include <vcl/stdtext.hxx> +#include <vcl/weld.hxx> +#include <tools/diagnose_ex.h> +#include <cppuhelper/exc_hlp.hxx> +#include <strings.hrc> +#include <strings.hxx> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::task; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::frame; + using namespace ::dbtools; + + // ODatasourceConnector + ODatasourceConnector::ODatasourceConnector(const Reference< XComponentContext >& _rxContext, weld::Window* _pMessageParent) + :m_pErrorMessageParent(_pMessageParent) + ,m_xContext(_rxContext) + { + } + + ODatasourceConnector::ODatasourceConnector( const Reference< XComponentContext >& _rxContext, weld::Window* _pMessageParent, + const OUString& _rContextInformation ) + :m_pErrorMessageParent(_pMessageParent) + ,m_xContext(_rxContext) + ,m_sContextInformation( _rContextInformation ) + { + } + + Reference< XConnection > ODatasourceConnector::connect( const OUString& _rDataSourceName, + ::dbtools::SQLExceptionInfo* _pErrorInfo ) const + { + Reference< XConnection > xConnection; + + OSL_ENSURE(isValid(), "ODatasourceConnector::connect: invalid object!"); + if (!isValid()) + return xConnection; + + // get the data source + Reference< XDataSource > xDatasource = + getDataSourceByName( _rDataSourceName, m_pErrorMessageParent, m_xContext, _pErrorInfo ); + + if ( xDatasource.is() ) + xConnection = connect( xDatasource, _pErrorInfo ); + return xConnection; + } + + Reference< XConnection > ODatasourceConnector::connect(const Reference< XDataSource>& _xDataSource, + ::dbtools::SQLExceptionInfo* _pErrorInfo ) const + { + Reference< XConnection > xConnection; + + OSL_ENSURE( isValid() && _xDataSource.is(), "ODatasourceConnector::connect: invalid object or argument!" ); + if ( !isValid() || !_xDataSource.is() ) + return xConnection; + + // get user/password + OUString sPassword, sUser; + bool bPwdRequired = false; + Reference<XPropertySet> xProp(_xDataSource,UNO_QUERY); + try + { + xProp->getPropertyValue(PROPERTY_PASSWORD) >>= sPassword; + xProp->getPropertyValue(PROPERTY_ISPASSWORDREQUIRED) >>= bPwdRequired; + xProp->getPropertyValue(PROPERTY_USER) >>= sUser; + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + // try to connect + SQLExceptionInfo aInfo; + try + { + if (bPwdRequired && sPassword.isEmpty()) + { // password required, but empty -> connect using an interaction handler + Reference< XCompletedConnection > xConnectionCompletion( _xDataSource, UNO_QUERY_THROW ); + + Reference< XModel > xModel( getDataSourceOrModel( _xDataSource ), UNO_QUERY_THROW ); + ::comphelper::NamedValueCollection aArgs( xModel->getArgs() ); + Reference< XInteractionHandler > xHandler( aArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) ); + + if ( !xHandler.is() ) + { + // instantiate the default SDB interaction handler + xHandler = InteractionHandler::createWithParent(m_xContext, m_pErrorMessageParent ? m_pErrorMessageParent->GetXWindow() : nullptr); + } + + xConnection = xConnectionCompletion->connectWithCompletion(xHandler); + } + else + { + xConnection = _xDataSource->getConnection(sUser, sPassword); + } + } + catch( const SQLException& ) + { + aInfo = ::cppu::getCaughtException(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if ( !aInfo.isValid() ) + { + // there was no error during connecting, but perhaps a warning? + Reference< XWarningsSupplier > xConnectionWarnings( xConnection, UNO_QUERY ); + if ( xConnectionWarnings.is() ) + { + try + { + Any aWarnings( xConnectionWarnings->getWarnings() ); + if ( aWarnings.hasValue() ) + { + OUString sMessage( DBA_RES( STR_WARNINGS_DURING_CONNECT ) ); + sMessage = sMessage.replaceFirst( "$buttontext$", GetStandardText( StandardButtonType::More ) ); + sMessage = OutputDevice::GetNonMnemonicString( sMessage ); + + SQLWarning aContext; + aContext.Message = sMessage; + aContext.NextException = aWarnings; + aInfo = aContext; + } + xConnectionWarnings->clearWarnings(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + else + { + if ( !m_sContextInformation.isEmpty() ) + { + SQLException aError; + aError.Message = m_sContextInformation; + aError.NextException = aInfo.get(); + + aInfo = aError; + } + } + + // was there an error? + if ( aInfo.isValid() ) + { + if ( _pErrorInfo ) + { + *_pErrorInfo = aInfo; + } + else + { + showError(aInfo, m_pErrorMessageParent ? m_pErrorMessageParent->GetXWindow() : nullptr, m_xContext); + } + } + return xConnection; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/dbaundomanager.cxx b/dbaccess/source/ui/misc/dbaundomanager.cxx new file mode 100644 index 000000000..9ed72bbdf --- /dev/null +++ b/dbaccess/source/ui/misc/dbaundomanager.cxx @@ -0,0 +1,324 @@ +/* -*- 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 <dbaccess/dbaundomanager.hxx> + +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> + +#include <svl/undo.hxx> +#include <vcl/svapp.hxx> +#include <framework/undomanagerhelper.hxx> +#include <framework/imutex.hxx> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::document::XUndoManager; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::document::XUndoAction; + using ::com::sun::star::document::XUndoManagerListener; + using ::com::sun::star::lang::NoSupportException; + + // UndoManager_Impl + struct UndoManager_Impl : public ::framework::IUndoManagerImplementation + { + UndoManager_Impl( UndoManager& i_antiImpl, ::cppu::OWeakObject& i_parent, ::osl::Mutex& i_mutex ) + :rAntiImpl( i_antiImpl ) + ,rParent( i_parent ) + ,rMutex( i_mutex ) + ,bDisposed( false ) + ,aUndoHelper( *this ) + { + } + + virtual ~UndoManager_Impl() + { + } + + UndoManager& rAntiImpl; + ::cppu::OWeakObject& rParent; + ::osl::Mutex& rMutex; + bool bDisposed; + SfxUndoManager aUndoManager; + ::framework::UndoManagerHelper aUndoHelper; + + // IUndoManagerImplementation + virtual SfxUndoManager& getImplUndoManager() override; + virtual Reference< XUndoManager > getThis() override; + }; + + SfxUndoManager& UndoManager_Impl::getImplUndoManager() + { + return aUndoManager; + } + + Reference< XUndoManager > UndoManager_Impl::getThis() + { + return static_cast< XUndoManager* >( &rAntiImpl ); + } + + namespace { + + // OslMutexFacade + class OslMutexFacade : public ::framework::IMutex + { + public: + explicit OslMutexFacade( ::osl::Mutex& i_mutex ) + :m_rMutex( i_mutex ) + { + } + + virtual ~OslMutexFacade() {} + + virtual void acquire() override; + virtual void release() override; + + private: + ::osl::Mutex& m_rMutex; + }; + + } + + void OslMutexFacade::acquire() + { + m_rMutex.acquire(); + } + + void OslMutexFacade::release() + { + m_rMutex.release(); + } + + namespace { + + // UndoManagerMethodGuard + /** guard for public UNO methods of the UndoManager + */ + class UndoManagerMethodGuard : public ::framework::IMutexGuard + { + public: + explicit UndoManagerMethodGuard( UndoManager_Impl& i_impl ) + :m_aGuard( i_impl.rMutex ) + ,m_aMutexFacade( i_impl.rMutex ) + { + // throw if the instance is already disposed + if ( i_impl.bDisposed ) + throw DisposedException( OUString(), i_impl.getThis() ); + } + virtual ~UndoManagerMethodGuard() + { + } + + // IMutexGuard + virtual void clear() override; + virtual ::framework::IMutex& getGuardedMutex() override; + + private: + osl::ClearableMutexGuard m_aGuard; + OslMutexFacade m_aMutexFacade; + }; + + } + + ::framework::IMutex& UndoManagerMethodGuard::getGuardedMutex() + { + return m_aMutexFacade; + } + + void UndoManagerMethodGuard::clear() + { + m_aGuard.clear(); + } + + // UndoManager + UndoManager::UndoManager( ::cppu::OWeakObject& i_parent, ::osl::Mutex& i_mutex ) + :m_xImpl( new UndoManager_Impl( *this, i_parent, i_mutex ) ) + { + } + + UndoManager::~UndoManager() + { + } + + SfxUndoManager& UndoManager::GetSfxUndoManager() const + { + return m_xImpl->aUndoManager; + } + + void SAL_CALL UndoManager::acquire( ) noexcept + { + m_xImpl->rParent.acquire(); + } + + void SAL_CALL UndoManager::release( ) noexcept + { + m_xImpl->rParent.release(); + } + + void UndoManager::disposing() + { + { + ::osl::MutexGuard aGuard( m_xImpl->rMutex ); + m_xImpl->bDisposed = true; + } + m_xImpl->aUndoHelper.disposing(); + } + + void SAL_CALL UndoManager::enterUndoContext( const OUString& i_title ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.enterUndoContext( i_title, aGuard ); + } + + void SAL_CALL UndoManager::enterHiddenUndoContext( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.enterHiddenUndoContext( aGuard ); + } + + void SAL_CALL UndoManager::leaveUndoContext( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.leaveUndoContext( aGuard ); + } + + void SAL_CALL UndoManager::addUndoAction( const Reference< XUndoAction >& i_action ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.addUndoAction( i_action, aGuard ); + } + + void SAL_CALL UndoManager::undo( ) + { + SolarMutexGuard aSolarGuard; + // (all our UndoActions work directly on VCL code, usually, so ...) + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.undo( aGuard ); + } + + void SAL_CALL UndoManager::redo( ) + { + SolarMutexGuard aSolarGuard; + // (all our UndoActions work directly on VCL code, usually, so ...) + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.redo( aGuard ); + } + + sal_Bool SAL_CALL UndoManager::isUndoPossible( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.isUndoPossible(); + } + + sal_Bool SAL_CALL UndoManager::isRedoPossible( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.isRedoPossible(); + } + + OUString SAL_CALL UndoManager::getCurrentUndoActionTitle( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.getCurrentUndoActionTitle(); + } + + OUString SAL_CALL UndoManager::getCurrentRedoActionTitle( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.getCurrentRedoActionTitle(); + } + + Sequence< OUString > SAL_CALL UndoManager::getAllUndoActionTitles( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.getAllUndoActionTitles(); + } + + Sequence< OUString > SAL_CALL UndoManager::getAllRedoActionTitles( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.getAllRedoActionTitles(); + } + + void SAL_CALL UndoManager::clear( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.clear( aGuard ); + } + + void SAL_CALL UndoManager::clearRedo( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.clearRedo( aGuard ); + } + + void SAL_CALL UndoManager::reset( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.reset( aGuard ); + } + + void SAL_CALL UndoManager::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.addUndoManagerListener( i_listener ); + } + + void SAL_CALL UndoManager::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.removeUndoManagerListener( i_listener ); + } + + void SAL_CALL UndoManager::lock( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.lock(); + } + + void SAL_CALL UndoManager::unlock( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.unlock(); + } + + sal_Bool SAL_CALL UndoManager::isLocked( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.isLocked(); + } + + Reference< XInterface > SAL_CALL UndoManager::getParent( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->rParent; + } + + void SAL_CALL UndoManager::setParent( const Reference< XInterface >& ) + { + throw NoSupportException( OUString(), m_xImpl->getThis() ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx b/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx new file mode 100644 index 000000000..467a6e925 --- /dev/null +++ b/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx @@ -0,0 +1,606 @@ +/* -*- 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 <browserids.hxx> +#include <commontypes.hxx> +#include <core_resource.hxx> +#include <dbaccess/dataview.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <dbaccess/dbsubcomponentcontroller.hxx> + +#include <com/sun/star/frame/XUntitledNumbers.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/sdb/XDocumentDataSource.hpp> +#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/util/NumberFormatter.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbmetadata.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +namespace dbaui +{ + + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::container::XChild; + using ::com::sun::star::sdbc::XDataSource; + using ::com::sun::star::util::NumberFormatter; + using ::com::sun::star::util::XNumberFormatter; + using ::com::sun::star::util::XNumberFormatsSupplier; + using ::com::sun::star::frame::XFrame; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::sdb::XOfficeDatabaseDocument; + using ::com::sun::star::awt::XWindow; + using ::com::sun::star::sdbc::XDatabaseMetaData; + using ::com::sun::star::sdb::XDocumentDataSource; + using ::com::sun::star::document::XEmbeddedScripts; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::frame::XUntitledNumbers; + + namespace { + + class DataSourceHolder + { + public: + DataSourceHolder() + { + } + + explicit DataSourceHolder(const Reference< XDataSource >& _rxDataSource) + : m_xDataSource(_rxDataSource) + { + Reference< XDocumentDataSource > xDocDS( m_xDataSource, UNO_QUERY ); + if ( xDocDS.is() ) + m_xDocument = xDocDS->getDatabaseDocument(); + + m_xDataSourceProps.set( m_xDataSource, UNO_QUERY ); + } + + const Reference< XDataSource >& getDataSource() const { return m_xDataSource; } + const Reference< XPropertySet >& getDataSourceProps() const { return m_xDataSourceProps; } + const Reference< XOfficeDatabaseDocument >& getDatabaseDocument() const { return m_xDocument; } + + bool is() const { return m_xDataSource.is(); } + + void clear() + { + m_xDataSource.clear(); + m_xDocument.clear(); + } + + private: + Reference< XDataSource > m_xDataSource; + Reference< XPropertySet > m_xDataSourceProps; + Reference< XOfficeDatabaseDocument > m_xDocument; + }; + + } + + struct DBSubComponentController_Impl + { + private: + ::std::optional< bool > m_aDocScriptSupport; + + public: + ::dbtools::SQLExceptionInfo m_aCurrentError; + + ::comphelper::OInterfaceContainerHelper3<css::util::XModifyListener> + m_aModifyListeners; + + // <properties> + SharedConnection m_xConnection; + ::dbtools::DatabaseMetaData m_aSdbMetaData; + // </properties> + OUString m_sDataSourceName; // the data source we're working for + DataSourceHolder m_aDataSource; + Reference< XNumberFormatter > m_xFormatter; // a number formatter working with the connection's NumberFormatsSupplier + sal_Int32 m_nDocStartNumber; + bool m_bSuspended; // is true when the controller was already suspended + bool m_bEditable; // is the control readonly or not + bool m_bModified; // is the data modified + bool m_bNotAttached; + + explicit DBSubComponentController_Impl(osl::Mutex& i_rMutex) + :m_aModifyListeners( i_rMutex ) + ,m_nDocStartNumber(0) + ,m_bSuspended( false ) + ,m_bEditable(true) + ,m_bModified(false) + ,m_bNotAttached(true) + { + } + + bool documentHasScriptSupport() const + { + OSL_PRECOND( !!m_aDocScriptSupport, + "DBSubComponentController_Impl::documentHasScriptSupport: not completely initialized, yet - don't know!?" ); + return !!m_aDocScriptSupport && *m_aDocScriptSupport; + } + + void setDocumentScriptSupport( const bool _bSupport ) + { + OSL_PRECOND( !m_aDocScriptSupport, + "DBSubComponentController_Impl::setDocumentScriptSupport: already initialized!" ); + m_aDocScriptSupport = ::std::optional< bool >( _bSupport ); + } + }; + + // DBSubComponentController + DBSubComponentController::DBSubComponentController(const Reference< XComponentContext >& _rxORB) + :DBSubComponentController_Base( _rxORB ) + ,m_pImpl( new DBSubComponentController_Impl( getMutex() ) ) + { + } + + DBSubComponentController::~DBSubComponentController() + { + } + + void DBSubComponentController::impl_initialize() + { + OGenericUnoController::impl_initialize(); + + const ::comphelper::NamedValueCollection& rArguments( getInitParams() ); + + Reference< XConnection > xConnection; + xConnection = rArguments.getOrDefault( PROPERTY_ACTIVE_CONNECTION, xConnection ); + + if ( !xConnection.is() ) + ::dbtools::isEmbeddedInDatabase( getModel(), xConnection ); + + if ( xConnection.is() ) + initializeConnection( xConnection ); + + bool bShowError = true; + if ( !isConnected() ) + { + reconnect( false ); + bShowError = false; + } + if ( !isConnected() ) + { + if ( bShowError ) + connectionLostMessage(); + throw IllegalArgumentException(); + } + } + + Any SAL_CALL DBSubComponentController::queryInterface(const Type& _rType) + { + if ( _rType.equals( cppu::UnoType<XScriptInvocationContext>::get() ) ) + { + if ( m_pImpl->documentHasScriptSupport() ) + return Any( Reference< XScriptInvocationContext >( this ) ); + return Any(); + } + + return DBSubComponentController_Base::queryInterface( _rType ); + } + + Sequence< Type > SAL_CALL DBSubComponentController::getTypes( ) + { + Sequence< Type > aTypes( DBSubComponentController_Base::getTypes() ); + if ( !m_pImpl->documentHasScriptSupport() ) + { + auto [begin, end] = asNonConstRange(aTypes); + auto newEnd = std::remove_if( begin, end, + [](const Type& type) + { return type == cppu::UnoType<XScriptInvocationContext>::get(); } ); + aTypes.realloc( std::distance(begin, newEnd) ); + } + return aTypes; + } + + void DBSubComponentController::initializeConnection( const Reference< XConnection >& _rxForeignConn ) + { + DBG_ASSERT( !isConnected(), "DBSubComponentController::initializeConnection: not to be called when already connected!" ); + // usually this gets called from within initialize of derived classes ... + if ( isConnected() ) + disconnect(); + + m_pImpl->m_xConnection.reset( _rxForeignConn, SharedConnection::NoTakeOwnership ); + m_pImpl->m_aSdbMetaData.reset( m_pImpl->m_xConnection ); + startConnectionListening( m_pImpl->m_xConnection ); + + // get the data source the connection belongs to + try + { + // determine our data source + OSL_PRECOND( !m_pImpl->m_aDataSource.is(), "DBSubComponentController::initializeConnection: already a data source in this phase?" ); + { + Reference< XChild > xConnAsChild( m_pImpl->m_xConnection, UNO_QUERY ); + Reference< XDataSource > xDS; + if ( xConnAsChild.is() ) + xDS.set( xConnAsChild->getParent(), UNO_QUERY ); + + // (take the indirection through XDataSource to ensure we have a correct object...) + m_pImpl->m_aDataSource = DataSourceHolder(xDS); + } + SAL_WARN_IF( !m_pImpl->m_aDataSource.is(), "dbaccess.ui", "DBSubComponentController::initializeConnection: unable to obtain the data source object!" ); + + if ( m_pImpl->m_bNotAttached ) + { + Reference< XUntitledNumbers > xUntitledProvider( getDatabaseDocument(), UNO_QUERY ); + m_pImpl->m_nDocStartNumber = 1; + if ( xUntitledProvider.is() ) + m_pImpl->m_nDocStartNumber = xUntitledProvider->leaseNumber( static_cast< XWeak* >( this ) ); + } + + // determine the availability of script support in our document. Our own XScriptInvocationContext + // interface depends on this + m_pImpl->setDocumentScriptSupport( Reference< XEmbeddedScripts >( getDatabaseDocument(), UNO_QUERY ).is() ); + + // get a number formatter + Reference< XPropertySet > xDataSourceProps( m_pImpl->m_aDataSource.getDataSourceProps(), UNO_SET_THROW ); + xDataSourceProps->getPropertyValue( PROPERTY_NAME ) >>= m_pImpl->m_sDataSourceName; + DBG_ASSERT( !m_pImpl->m_sDataSourceName.isEmpty(), "DBSubComponentController::initializeConnection: invalid data source name!" ); + Reference< XNumberFormatsSupplier> xSupplier = ::dbtools::getNumberFormats(m_pImpl->m_xConnection); + if(xSupplier.is()) + { + m_pImpl->m_xFormatter.set(NumberFormatter::create(getORB()), UNO_QUERY_THROW); + m_pImpl->m_xFormatter->attachNumberFormatsSupplier(xSupplier); + } + OSL_ENSURE(m_pImpl->m_xFormatter.is(),"No NumberFormatter!"); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void DBSubComponentController::reconnect( bool _bUI ) + { + OSL_ENSURE(!m_pImpl->m_bSuspended, "Cannot reconnect while suspended!"); + + stopConnectionListening( m_pImpl->m_xConnection ); + m_pImpl->m_aSdbMetaData.reset( nullptr ); + m_pImpl->m_xConnection.clear(); + + // reconnect + bool bReConnect = true; + if ( _bUI ) + { + std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(getFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + DBA_RES(STR_QUERY_CONNECTION_LOST))); + bReConnect = (RET_YES == xQuery->run()); + } + + // now really reconnect ... + if ( bReConnect ) + { + m_pImpl->m_xConnection.reset( connect( m_pImpl->m_aDataSource.getDataSource() ), SharedConnection::TakeOwnership ); + m_pImpl->m_aSdbMetaData.reset( m_pImpl->m_xConnection ); + } + + // invalidate all slots + InvalidateAll(); + } + + void DBSubComponentController::disconnect() + { + stopConnectionListening(m_pImpl->m_xConnection); + m_pImpl->m_aSdbMetaData.reset( nullptr ); + m_pImpl->m_xConnection.clear(); + + InvalidateAll(); + } + + void DBSubComponentController::losingConnection() + { + // our connection was disposed so we need a new one + reconnect( true ); + InvalidateAll(); + } + + void SAL_CALL DBSubComponentController::disposing() + { + DBSubComponentController_Base::disposing(); + + disconnect(); + + attachFrame( Reference < XFrame >() ); + + m_pImpl->m_aDataSource.clear(); + } + + void SAL_CALL DBSubComponentController::disposing(const EventObject& _rSource) + { + if ( _rSource.Source == getConnection() ) + { + if ( !m_pImpl->m_bSuspended // when already suspended then we don't have to reconnect + && !getBroadcastHelper().bInDispose + && !getBroadcastHelper().bDisposed + && isConnected() + ) + { + losingConnection(); + } + else + { + m_pImpl->m_xConnection.reset( m_pImpl->m_xConnection, SharedConnection::NoTakeOwnership ); + // this prevents the "disposeComponent" call in disconnect + disconnect(); + } + } + else + DBSubComponentController_Base::disposing( _rSource ); + } + + void DBSubComponentController::appendError( const OUString& _rErrorMessage ) + { + m_pImpl->m_aCurrentError.append( ::dbtools::SQLExceptionInfo::TYPE::SQLException, _rErrorMessage, + getStandardSQLState( ::dbtools::StandardSQLState::GENERAL_ERROR ), + 1000 ); + } + void DBSubComponentController::clearError() + { + m_pImpl->m_aCurrentError = ::dbtools::SQLExceptionInfo(); + } + + bool DBSubComponentController::hasError() const + { + return m_pImpl->m_aCurrentError.isValid(); + } + + const ::dbtools::SQLExceptionInfo& DBSubComponentController::getError() const + { + return m_pImpl->m_aCurrentError; + } + + void DBSubComponentController::displayError() + { + showError( m_pImpl->m_aCurrentError ); + } + + sal_Bool SAL_CALL DBSubComponentController::suspend(sal_Bool bSuspend) + { + m_pImpl->m_bSuspended = bSuspend; + if ( !bSuspend && !isConnected() ) + reconnect(true); + + return true; + } + + sal_Bool SAL_CALL DBSubComponentController::attachModel( const Reference< XModel > & _rxModel) + { + if ( !_rxModel.is() ) + return false; + if ( !DBSubComponentController_Base::attachModel( _rxModel ) ) + return false; + + m_pImpl->m_bNotAttached = false; + if ( m_pImpl->m_nDocStartNumber == 1 ) + releaseNumberForComponent(); + + Reference< XUntitledNumbers > xUntitledProvider( _rxModel, UNO_QUERY ); + m_pImpl->m_nDocStartNumber = 1; + if ( xUntitledProvider.is() ) + m_pImpl->m_nDocStartNumber = xUntitledProvider->leaseNumber( static_cast< XWeak* >( this ) ); + + return true; + } + + void DBSubComponentController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& _rArgs) + { + if ( _nId == ID_BROWSER_CLOSE ) + { + closeTask(); + return; + } + + DBSubComponentController_Base::Execute( _nId, _rArgs ); + InvalidateFeature( _nId ); + } + + OUString DBSubComponentController::getDataSourceName() const + { + OUString sName; + Reference< XPropertySet > xDataSourceProps( m_pImpl->m_aDataSource.getDataSourceProps() ); + if ( xDataSourceProps.is() ) + xDataSourceProps->getPropertyValue(PROPERTY_NAME) >>= sName; + return sName; + } + void DBSubComponentController::connectionLostMessage() const + { + OUString aMessage(DBA_RES(RID_STR_CONNECTION_LOST)); + Reference< XWindow > xWindow = getTopMostContainerWindow(); + vcl::Window* pWin = nullptr; + if ( xWindow.is() ) + pWin = VCLUnoHelper::GetWindow(xWindow); + if ( !pWin ) + pWin = getView()->Window::GetParent(); + + std::unique_ptr<weld::MessageDialog> xInfo(Application::CreateMessageDialog(pWin ? pWin->GetFrameWeld() : nullptr, + VclMessageType::Info, VclButtonsType::Ok, aMessage)); + xInfo->run(); + } + const Reference< XConnection >& DBSubComponentController::getConnection() const + { + return m_pImpl->m_xConnection; + } + + bool DBSubComponentController::isReadOnly() const + { + return !m_pImpl->m_bEditable; + } + + bool DBSubComponentController::isEditable() const + { + return m_pImpl->m_bEditable; + } + + void DBSubComponentController::setEditable(bool _bEditable) + { + m_pImpl->m_bEditable = _bEditable; + } + + const ::dbtools::DatabaseMetaData& DBSubComponentController::getSdbMetaData() const + { + return m_pImpl->m_aSdbMetaData; + } + + bool DBSubComponentController::isConnected() const + { + return m_pImpl->m_xConnection.is(); + } + + Reference< XDatabaseMetaData > DBSubComponentController::getMetaData( ) const + { + Reference< XDatabaseMetaData > xMeta; + try + { + if ( isConnected() ) + xMeta.set( m_pImpl->m_xConnection->getMetaData(), UNO_SET_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return xMeta; + } + + const Reference< XPropertySet >& DBSubComponentController::getDataSource() const + { + return m_pImpl->m_aDataSource.getDataSourceProps(); + } + + bool DBSubComponentController::haveDataSource() const + { + return m_pImpl->m_aDataSource.is(); + } + + Reference< XModel > DBSubComponentController::getDatabaseDocument() const + { + return Reference< XModel >( m_pImpl->m_aDataSource.getDatabaseDocument(), UNO_QUERY ); + } + + Reference< XNumberFormatter > const & DBSubComponentController::getNumberFormatter() const + { + return m_pImpl->m_xFormatter; + } + + Reference< XModel > DBSubComponentController::getPrivateModel() const + { + return getDatabaseDocument(); + } + // XTitle + OUString SAL_CALL DBSubComponentController::getTitle() + { + ::osl::MutexGuard aGuard( getMutex() ); + if ( m_bExternalTitle ) + return impl_getTitleHelper_throw()->getTitle (); + + OUStringBuffer sTitle; + Reference< XTitle > xTitle(getPrivateModel(),UNO_QUERY); + if ( xTitle.is() ) + { + sTitle.append( xTitle->getTitle() ); + sTitle.append(" : "); + } + sTitle.append( getPrivateTitle() ); + return sTitle.makeStringAndClear(); + } + + sal_Int32 DBSubComponentController::getCurrentStartNumber() const + { + return m_pImpl->m_nDocStartNumber; + } + + Reference< XEmbeddedScripts > SAL_CALL DBSubComponentController::getScriptContainer() + { + ::osl::MutexGuard aGuard( getMutex() ); + if ( !m_pImpl->documentHasScriptSupport() ) + return nullptr; + + return Reference< XEmbeddedScripts >( getDatabaseDocument(), UNO_QUERY_THROW ); + } + + void SAL_CALL DBSubComponentController::addModifyListener( const Reference< XModifyListener >& i_Listener ) + { + ::osl::MutexGuard aGuard( getMutex() ); + m_pImpl->m_aModifyListeners.addInterface( i_Listener ); + } + + void SAL_CALL DBSubComponentController::removeModifyListener( const Reference< XModifyListener >& i_Listener ) + { + ::osl::MutexGuard aGuard( getMutex() ); + m_pImpl->m_aModifyListeners.removeInterface( i_Listener ); + } + + sal_Bool SAL_CALL DBSubComponentController::isModified( ) + { + ::osl::MutexGuard aGuard( getMutex() ); + return impl_isModified(); + } + + void SAL_CALL DBSubComponentController::setModified( sal_Bool i_bModified ) + { + ::osl::ClearableMutexGuard aGuard( getMutex() ); + + if ( m_pImpl->m_bModified == bool(i_bModified) ) + return; + + m_pImpl->m_bModified = i_bModified; + impl_onModifyChanged(); + + EventObject aEvent( *this ); + aGuard.clear(); + m_pImpl->m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent ); + } + + bool DBSubComponentController::impl_isModified() const + { + return m_pImpl->m_bModified; + } + + void DBSubComponentController::impl_onModifyChanged() + { + InvalidateFeature( ID_BROWSER_SAVEDOC ); + if ( isFeatureSupported( ID_BROWSER_SAVEASDOC ) ) + InvalidateFeature( ID_BROWSER_SAVEASDOC ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/defaultobjectnamecheck.cxx b/dbaccess/source/ui/misc/defaultobjectnamecheck.cxx new file mode 100644 index 000000000..53ef26fa3 --- /dev/null +++ b/dbaccess/source/ui/misc/defaultobjectnamecheck.cxx @@ -0,0 +1,160 @@ +/* -*- 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 <core_resource.hxx> +#include <defaultobjectnamecheck.hxx> + +#include <strings.hrc> + +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/tools/XConnectionTools.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <connectivity/dbexception.hxx> +#include <connectivity/dbmetadata.hxx> + +#include <rtl/ustrbuf.hxx> + +#include <tools/diagnose_ex.h> +#include <cppuhelper/exc_hlp.hxx> + +#include <memory> +#include <string_view> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::container::XHierarchicalNameAccess; + using ::com::sun::star::sdbc::SQLException; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::sdb::tools::XObjectNames; + using ::com::sun::star::sdb::tools::XConnectionTools; + using ::com::sun::star::uno::UNO_QUERY; + + using namespace dbtools; + + namespace CommandType = ::com::sun::star::sdb::CommandType; + + // helper + namespace + { + void lcl_fillNameExistsError( std::u16string_view _rObjectName, SQLExceptionInfo& _out_rErrorToDisplay ) + { + SQLException aError; + OUString sErrorMessage = DBA_RES(STR_NAMED_OBJECT_ALREADY_EXISTS); + aError.Message = sErrorMessage.replaceAll("$#$", _rObjectName); + _out_rErrorToDisplay = aError; + } + + } + + // HierarchicalNameCheck_Impl + struct HierarchicalNameCheck_Impl + { + Reference< XHierarchicalNameAccess > xHierarchicalNames; + OUString sRelativeRoot; + }; + + // HierarchicalNameCheck + HierarchicalNameCheck::HierarchicalNameCheck( const Reference< XHierarchicalNameAccess >& _rxNames, const OUString& _rRelativeRoot ) + :m_pImpl( new HierarchicalNameCheck_Impl ) + { + m_pImpl->xHierarchicalNames = _rxNames; + m_pImpl->sRelativeRoot = _rRelativeRoot; + + if ( !m_pImpl->xHierarchicalNames.is() ) + throw IllegalArgumentException(); + } + + HierarchicalNameCheck::~HierarchicalNameCheck() + { + } + + bool HierarchicalNameCheck::isNameValid( const OUString& _rObjectName, SQLExceptionInfo& _out_rErrorToDisplay ) const + { + try + { + OUStringBuffer aCompleteName; + if ( !m_pImpl->sRelativeRoot.isEmpty() ) + { + aCompleteName.append( m_pImpl->sRelativeRoot ); + aCompleteName.append( "/" ); + } + aCompleteName.append( _rObjectName ); + + OUString sCompleteName( aCompleteName.makeStringAndClear() ); + if ( !m_pImpl->xHierarchicalNames->hasByHierarchicalName( sCompleteName ) ) + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + lcl_fillNameExistsError( _rObjectName, _out_rErrorToDisplay ); + return false; + } + + // DynamicTableOrQueryNameCheck_Impl + struct DynamicTableOrQueryNameCheck_Impl + { + sal_Int32 nCommandType; + Reference< XObjectNames > xObjectNames; + }; + + // DynamicTableOrQueryNameCheck + DynamicTableOrQueryNameCheck::DynamicTableOrQueryNameCheck( const Reference< XConnection >& _rxSdbLevelConnection, sal_Int32 _nCommandType ) + :m_pImpl( new DynamicTableOrQueryNameCheck_Impl ) + { + Reference< XConnectionTools > xConnTools( _rxSdbLevelConnection, UNO_QUERY ); + if ( xConnTools.is() ) + m_pImpl->xObjectNames.set( xConnTools->getObjectNames() ); + if ( !m_pImpl->xObjectNames.is() ) + throw IllegalArgumentException(); + + if ( ( _nCommandType != CommandType::QUERY ) && ( _nCommandType != CommandType::TABLE ) ) + throw IllegalArgumentException(); + m_pImpl->nCommandType = _nCommandType; + } + + DynamicTableOrQueryNameCheck::~DynamicTableOrQueryNameCheck() + { + } + + bool DynamicTableOrQueryNameCheck::isNameValid( const OUString& _rObjectName, ::dbtools::SQLExceptionInfo& _out_rErrorToDisplay ) const + { + try + { + m_pImpl->xObjectNames->checkNameForCreate( m_pImpl->nCommandType, _rObjectName ); + return true; + } + catch( const SQLException& ) + { + _out_rErrorToDisplay = ::dbtools::SQLExceptionInfo( ::cppu::getCaughtException() ); + } + return false; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/dsmeta.cxx b/dbaccess/source/ui/misc/dsmeta.cxx new file mode 100644 index 000000000..286ce63aa --- /dev/null +++ b/dbaccess/source/ui/misc/dsmeta.cxx @@ -0,0 +1,182 @@ +/* -*- 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 <dsmeta.hxx> +#include <connectivity/DriversConfig.hxx> +#include <dsntypes.hxx> +#include <comphelper/processfactory.hxx> + +#include <map> +#include <utility> + +namespace dbaui +{ + + using namespace dbaccess; + using namespace ::com::sun::star; + + namespace { + + struct FeatureSupport + { + // authentication mode of the data source + AuthenticationMode eAuthentication; + + FeatureSupport() + :eAuthentication( AuthUserPwd ) + { + } + + explicit FeatureSupport(AuthenticationMode Auth) + :eAuthentication( Auth ) + { + } + }; + + struct FeatureMapping + { + /// one of the items from dsitems.hxx + ItemID nItemID; + OUString pAsciiFeatureName; + }; + + // global tables + const FeatureMapping s_aMappings[] = { + { DSID_AUTORETRIEVEENABLED, "GeneratedValues" }, + { DSID_AUTOINCREMENTVALUE, "GeneratedValues" }, + { DSID_AUTORETRIEVEVALUE, "GeneratedValues" }, + { DSID_SQL92CHECK, "UseSQL92NamingConstraints" }, + { DSID_APPEND_TABLE_ALIAS, "AppendTableAliasInSelect" }, + { DSID_AS_BEFORE_CORRNAME, "UseKeywordAsBeforeAlias" }, + { DSID_ENABLEOUTERJOIN, "UseBracketedOuterJoinSyntax" }, + { DSID_IGNOREDRIVER_PRIV, "IgnoreDriverPrivileges" }, + { DSID_PARAMETERNAMESUBST, "ParameterNameSubstitution" }, + { DSID_SUPPRESSVERSIONCL, "DisplayVersionColumns" }, + { DSID_CATALOG, "UseCatalogInSelect" }, + { DSID_SCHEMA, "UseSchemaInSelect" }, + { DSID_INDEXAPPENDIX, "UseIndexDirectionKeyword" }, + { DSID_DOSLINEENDS, "UseDOSLineEnds" }, + { DSID_BOOLEANCOMPARISON, "BooleanComparisonMode" }, + { DSID_CHECK_REQUIRED_FIELDS, "FormsCheckRequiredFields" }, + { DSID_IGNORECURRENCY, "IgnoreCurrency" }, + { DSID_ESCAPE_DATETIME, "EscapeDateTime" }, + { DSID_PRIMARY_KEY_SUPPORT, "PrimaryKeySupport" }, + { DSID_RESPECTRESULTSETTYPE, "RespectDriverResultSetType" }, + { DSID_MAX_ROW_SCAN, "MaxRowScan" }, + }; + } + + static const FeatureSet& lcl_getFeatureSet( const OUString& _rURL ) + { + typedef std::map< OUString, FeatureSet > FeatureSets; + static FeatureSets s_aFeatureSets = []() + { + FeatureSets tmp; + ::connectivity::DriversConfig aDriverConfig( ::comphelper::getProcessComponentContext() ); + const uno::Sequence< OUString > aPatterns = aDriverConfig.getURLs(); + for ( auto const & pattern : aPatterns ) + { + FeatureSet aCurrentSet; + const ::comphelper::NamedValueCollection aCurrentFeatures( aDriverConfig.getFeatures( pattern ).getNamedValues() ); + + for ( const FeatureMapping& rFeatureMapping : s_aMappings ) + { + if ( aCurrentFeatures.has( rFeatureMapping.pAsciiFeatureName ) ) + aCurrentSet.put( rFeatureMapping.nItemID ); + } + + tmp[ pattern ] = aCurrentSet; + } + return tmp; + }(); + + OSL_ENSURE( s_aFeatureSets.find( _rURL ) != s_aFeatureSets.end(), "invalid URL/pattern!" ); + return s_aFeatureSets[ _rURL ]; + } + + static AuthenticationMode getAuthenticationMode( const OUString& _sURL ) + { + static std::map< OUString, FeatureSupport > s_aSupport = []() + { + std::map< OUString, FeatureSupport > tmp; + ::connectivity::DriversConfig aDriverConfig(::comphelper::getProcessComponentContext()); + const uno::Sequence< OUString > aURLs = aDriverConfig.getURLs(); + const OUString* pIter = aURLs.getConstArray(); + const OUString* pEnd = pIter + aURLs.getLength(); + for(;pIter != pEnd;++pIter) + { + FeatureSupport aInit( AuthNone ); + const ::comphelper::NamedValueCollection& aMetaData = aDriverConfig.getMetaData(*pIter); + if ( aMetaData.has("Authentication") ) + { + OUString sAuth; + aMetaData.get("Authentication") >>= sAuth; + if ( sAuth == "UserPassword" ) + aInit = FeatureSupport(AuthUserPwd); + else if ( sAuth == "Password" ) + aInit = FeatureSupport(AuthPwd); + } + tmp.insert(std::make_pair(*pIter,aInit)); + } + return tmp; + }(); + OSL_ENSURE(s_aSupport.find(_sURL) != s_aSupport.end(),"Illegal URL!"); + return s_aSupport[ _sURL ].eAuthentication; + } + + // DataSourceMetaData_Impl + class DataSourceMetaData_Impl + { + public: + explicit DataSourceMetaData_Impl(const OUString& rURL); + + const OUString& getType() const { return m_sURL; } + + private: + const OUString m_sURL; + }; + + DataSourceMetaData_Impl::DataSourceMetaData_Impl( const OUString& _sURL ) + :m_sURL( _sURL ) + { + } + + // DataSourceMetaData + DataSourceMetaData::DataSourceMetaData( const OUString& _sURL ) + :m_pImpl( std::make_shared<DataSourceMetaData_Impl>( _sURL ) ) + { + } + + DataSourceMetaData::~DataSourceMetaData() + { + } + + const FeatureSet& DataSourceMetaData::getFeatureSet() const + { + return lcl_getFeatureSet( m_pImpl->getType() ); + } + + AuthenticationMode DataSourceMetaData::getAuthentication( const OUString& _sURL ) + { + return getAuthenticationMode( _sURL ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/imageprovider.cxx b/dbaccess/source/ui/misc/imageprovider.cxx new file mode 100644 index 000000000..b69ec70e6 --- /dev/null +++ b/dbaccess/source/ui/misc/imageprovider.cxx @@ -0,0 +1,202 @@ +/* -*- 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 <imageprovider.hxx> +#include <bitmaps.hlst> + +#include <com/sun/star/graphic/GraphicColorMode.hpp> +#include <com/sun/star/sdb/application/XTableUIProvider.hpp> +#include <com/sun/star/sdb/application/DatabaseObject.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> + +#include <tools/diagnose_ex.h> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::container::XNameAccess; + using ::com::sun::star::graphic::XGraphic; + using ::com::sun::star::sdb::application::XTableUIProvider; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::sdbcx::XViewsSupplier; + using ::com::sun::star::uno::UNO_SET_THROW; + + namespace GraphicColorMode = css::graphic::GraphicColorMode; + namespace DatabaseObject = css::sdb::application::DatabaseObject; + + // ImageProvider_Data + struct ImageProvider_Data + { + /// the connection we work with + Reference< XConnection > xConnection; + /// the views of the connection, if the DB supports views + Reference< XNameAccess > xViews; + /// interface for providing table's UI + Reference< XTableUIProvider > xTableUI; + }; + + namespace + { + void lcl_getConnectionProvidedTableIcon_nothrow( const ImageProvider_Data& _rData, + const OUString& _rName, Reference< XGraphic >& _out_rxGraphic ) + { + try + { + if ( _rData.xTableUI.is() ) + _out_rxGraphic = _rData.xTableUI->getTableIcon( _rName, GraphicColorMode::NORMAL ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void lcl_getTableImageResourceID_nothrow( const ImageProvider_Data& _rData, const OUString& _rName, + OUString& _out_rResourceID) + { + _out_rResourceID = OUString(); + try + { + bool bIsView = _rData.xViews.is() && _rData.xViews->hasByName( _rName ); + if ( bIsView ) + { + _out_rResourceID = VIEW_TREE_ICON; + } + else + { + _out_rResourceID = TABLE_TREE_ICON; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + // ImageProvider + ImageProvider::ImageProvider() + :m_pData( std::make_shared<ImageProvider_Data>() ) + { + } + + ImageProvider::ImageProvider( const Reference< XConnection >& _rxConnection ) + :m_pData( std::make_shared<ImageProvider_Data>() ) + { + m_pData->xConnection = _rxConnection; + try + { + Reference< XViewsSupplier > xSuppViews( m_pData->xConnection, UNO_QUERY ); + if ( xSuppViews.is() ) + m_pData->xViews.set( xSuppViews->getViews(), UNO_SET_THROW ); + + m_pData->xTableUI.set( _rxConnection, UNO_QUERY ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + OUString ImageProvider::getImageId(const OUString& _rName, const sal_Int32 _nDatabaseObjectType) + { + if (_nDatabaseObjectType != DatabaseObject::TABLE) + { + // for types other than tables, the icon does not depend on the concrete object + return getDefaultImageResourceID( _nDatabaseObjectType ); + } + else + { + // no -> determine by type + OUString sImageResourceID; + lcl_getTableImageResourceID_nothrow( *m_pData, _rName, sImageResourceID ); + return sImageResourceID; + } + } + + Reference<XGraphic> ImageProvider::getXGraphic(const OUString& _rName, const sal_Int32 _nDatabaseObjectType) + { + Reference<XGraphic> xGraphic; + if (_nDatabaseObjectType == DatabaseObject::TABLE) + { + // check whether the connection can give us an icon + lcl_getConnectionProvidedTableIcon_nothrow( *m_pData, _rName, xGraphic ); + } + return xGraphic; + } + + OUString ImageProvider::getDefaultImageResourceID( sal_Int32 _nDatabaseObjectType) + { + OUString sImageResourceID; + switch ( _nDatabaseObjectType ) + { + case DatabaseObject::QUERY: + sImageResourceID = QUERY_TREE_ICON; + break; + case DatabaseObject::FORM: + sImageResourceID = FORM_TREE_ICON; + break; + case DatabaseObject::REPORT: + sImageResourceID = REPORT_TREE_ICON; + break; + case DatabaseObject::TABLE: + sImageResourceID = TABLE_TREE_ICON; + break; + default: + OSL_FAIL( "ImageProvider::getDefaultImage: invalid database object type!" ); + break; + } + return sImageResourceID; + } + + OUString ImageProvider::getFolderImageId( sal_Int32 _nDatabaseObjectType ) + { + OUString sImageResourceID; + switch ( _nDatabaseObjectType ) + { + case DatabaseObject::QUERY: + sImageResourceID = QUERYFOLDER_TREE_ICON; + break; + case DatabaseObject::FORM: + sImageResourceID = FORMFOLDER_TREE_ICON; + break; + case DatabaseObject::REPORT: + sImageResourceID = REPORTFOLDER_TREE_ICON; + break; + case DatabaseObject::TABLE: + sImageResourceID = TABLEFOLDER_TREE_ICON; + break; + default: + OSL_FAIL( "ImageProvider::getDefaultImage: invalid database object type!" ); + break; + } + + return sImageResourceID; + } + + OUString ImageProvider::getDatabaseImage() + { + return DATABASE_TREE_ICON; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/indexcollection.cxx b/dbaccess/source/ui/misc/indexcollection.cxx new file mode 100644 index 000000000..1b9377362 --- /dev/null +++ b/dbaccess/source/ui/misc/indexcollection.cxx @@ -0,0 +1,328 @@ +/* -*- 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 <indexcollection.hxx> +#include <tools/diagnose_ex.h> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <comphelper/extract.hxx> +#include <com/sun/star/sdbcx/XDrop.hpp> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::sdbcx; + using namespace ::com::sun::star::sdbc; + + // OIndexCollection + OIndexCollection::OIndexCollection() + { + } + + OIndexCollection::OIndexCollection(const OIndexCollection& _rSource) + { + *this = _rSource; + } + + OIndexCollection& OIndexCollection::operator=(const OIndexCollection& _rSource) + { + detach(); + m_xIndexes = _rSource.m_xIndexes; + m_aIndexes = _rSource.m_aIndexes; + return *this; + } + + void OIndexCollection::attach(const Reference< XNameAccess >& _rxIndexes) + { + implConstructFrom(_rxIndexes); + } + + void OIndexCollection::detach() + { + m_xIndexes.clear(); + m_aIndexes.clear(); + } + + Indexes::const_iterator OIndexCollection::find(const OUString& _rName) const + { + // loop'n'compare + return std::find_if(m_aIndexes.cbegin(), m_aIndexes.cend(), + [&_rName](const OIndex& rIndex) { return rIndex.sName == _rName; }); + } + + Indexes::iterator OIndexCollection::find(const OUString& _rName) + { + // loop'n'compare + return std::find_if(m_aIndexes.begin(), m_aIndexes.end(), + [&_rName](const OIndex& rIndex) { return rIndex.sName == _rName; }); + } + + Indexes::const_iterator OIndexCollection::findOriginal(const OUString& _rName) const + { + // loop'n'compare + return std::find_if(m_aIndexes.cbegin(), m_aIndexes.cend(), + [&_rName](const OIndex& rIndex) { return rIndex.getOriginalName() == _rName; }); + } + + Indexes::iterator OIndexCollection::findOriginal(const OUString& _rName) + { + // loop'n'compare + return std::find_if(m_aIndexes.begin(), m_aIndexes.end(), + [&_rName](const OIndex& rIndex) { return rIndex.getOriginalName() == _rName; }); + } + + void OIndexCollection::commitNewIndex(const Indexes::iterator& _rPos) + { + OSL_ENSURE(_rPos->isNew(), "OIndexCollection::commitNewIndex: index must be new!"); + + try + { + Reference< XDataDescriptorFactory > xIndexFactory(m_xIndexes, UNO_QUERY); + Reference< XAppend > xAppendIndex(xIndexFactory, UNO_QUERY); + if (!xAppendIndex.is()) + { + OSL_FAIL("OIndexCollection::commitNewIndex: missing an interface of the index container!"); + return; + } + + Reference< XPropertySet > xIndexDescriptor = xIndexFactory->createDataDescriptor(); + Reference< XColumnsSupplier > xColsSupp(xIndexDescriptor, UNO_QUERY); + Reference< XNameAccess > xCols; + if (xColsSupp.is()) + xCols = xColsSupp->getColumns(); + + Reference< XDataDescriptorFactory > xColumnFactory(xCols, UNO_QUERY); + Reference< XAppend > xAppendCols(xColumnFactory, UNO_QUERY); + if (!xAppendCols.is()) + { + OSL_FAIL("OIndexCollection::commitNewIndex: invalid index descriptor returned!"); + return; + } + + // set the properties + static constexpr OUStringLiteral s_sNamePropertyName = u"Name"; + // the index' own props + xIndexDescriptor->setPropertyValue("IsUnique", css::uno::Any(_rPos->bUnique)); + xIndexDescriptor->setPropertyValue(s_sNamePropertyName, Any(_rPos->sName)); + + // the fields + for (auto const& field : _rPos->aFields) + { + OSL_ENSURE(!xCols->hasByName(field.sFieldName), "OIndexCollection::commitNewIndex: double column name (need to prevent this outside)!"); + + Reference< XPropertySet > xColDescriptor = xColumnFactory->createDataDescriptor(); + OSL_ENSURE(xColDescriptor.is(), "OIndexCollection::commitNewIndex: invalid column descriptor!"); + if (xColDescriptor.is()) + { + xColDescriptor->setPropertyValue("IsAscending", css::uno::Any(field.bSortAscending)); + xColDescriptor->setPropertyValue(s_sNamePropertyName, Any(field.sFieldName)); + xAppendCols->appendByDescriptor(xColDescriptor); + } + } + + xAppendIndex->appendByDescriptor(xIndexDescriptor); + + _rPos->flagAsCommitted(GrantIndexAccess()); + _rPos->clearModified(); + } + catch(SQLException&) + { // allowed to pass + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + bool OIndexCollection::dropNoRemove(const Indexes::iterator& _rPos) + { + try + { + OSL_ENSURE(m_xIndexes->hasByName(_rPos->getOriginalName()), "OIndexCollection::drop: invalid name!"); + + Reference< XDrop > xDropIndex(m_xIndexes, UNO_QUERY); + if (!xDropIndex.is()) + { + OSL_FAIL("OIndexCollection::drop: no XDrop interface!"); + return false; + } + + xDropIndex->dropByName(_rPos->getOriginalName()); + } + catch(SQLException&) + { // allowed to pass + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + return false; + } + + // adjust the OIndex structure + Indexes::iterator aDropped = findOriginal(_rPos->getOriginalName()); + OSL_ENSURE(aDropped != m_aIndexes.end(), "OIndexCollection::drop: invalid original name, but successful commit?!"); + aDropped->flagAsNew(GrantIndexAccess()); + + return true; + } + + bool OIndexCollection::drop(const Indexes::iterator& _rPos) + { + OSL_ENSURE((_rPos >= m_aIndexes.begin()) && (_rPos < m_aIndexes.end()), + "OIndexCollection::drop: invalid position (fasten your seatbelt... this will crash)!"); + + if (!_rPos->isNew()) + if (!dropNoRemove(_rPos)) + return false; + + // adjust the index array + m_aIndexes.erase(_rPos); + return true; + } + + void OIndexCollection::implFillIndexInfo(OIndex& _rIndex) + { + // get the UNO descriptor for the index + Reference< XPropertySet > xIndex; + m_xIndexes->getByName(_rIndex.getOriginalName()) >>= xIndex; + if (!xIndex.is()) + { + OSL_FAIL("OIndexCollection::implFillIndexInfo: got an invalid index object!"); + } + else + implFillIndexInfo(_rIndex, xIndex); + } + + void OIndexCollection::implFillIndexInfo(OIndex& _rIndex, const Reference< XPropertySet >& _rxDescriptor) + { + _rIndex.bPrimaryKey = ::cppu::any2bool(_rxDescriptor->getPropertyValue("IsPrimaryKeyIndex")); + _rIndex.bUnique = ::cppu::any2bool(_rxDescriptor->getPropertyValue("IsUnique")); + _rxDescriptor->getPropertyValue("Catalog") >>= _rIndex.sDescription; + + // the columns + Reference< XColumnsSupplier > xSuppCols(_rxDescriptor, UNO_QUERY); + Reference< XNameAccess > xCols; + if (xSuppCols.is()) + xCols = xSuppCols->getColumns(); + OSL_ENSURE(xCols.is(), "OIndexCollection::implFillIndexInfo: the index does not have columns!"); + if (!xCols.is()) + return; + + Sequence< OUString > aFieldNames = xCols->getElementNames(); + _rIndex.aFields.resize(aFieldNames.getLength()); + + const OUString* pFieldNames = aFieldNames.getConstArray(); + const OUString* pFieldNamesEnd = pFieldNames + aFieldNames.getLength(); + IndexFields::iterator aCopyTo = _rIndex.aFields.begin(); + + Reference< XPropertySet > xIndexColumn; + for (;pFieldNames < pFieldNamesEnd; ++pFieldNames, ++aCopyTo) + { + // extract the column + xIndexColumn.clear(); + xCols->getByName(*pFieldNames) >>= xIndexColumn; + if (!xIndexColumn.is()) + { + OSL_FAIL("OIndexCollection::implFillIndexInfo: invalid index column!"); + --aCopyTo; + continue; + } + + // get the relevant properties + aCopyTo->sFieldName = *pFieldNames; + aCopyTo->bSortAscending = ::cppu::any2bool(xIndexColumn->getPropertyValue("IsAscending")); + } + + _rIndex.aFields.resize(aCopyTo - _rIndex.aFields.begin()); + // (just in case some fields were invalid ...) + } + + void OIndexCollection::resetIndex(const Indexes::iterator& _rPos) + { + OSL_ENSURE(_rPos >= m_aIndexes.begin() && _rPos < m_aIndexes.end(), + "OIndexCollection::resetIndex: invalid position!"); + + try + { + _rPos->sName = _rPos->getOriginalName(); + implFillIndexInfo(*_rPos); + + _rPos->clearModified(); + _rPos->flagAsCommitted(GrantIndexAccess()); + } + catch(SQLException&) + { // allowed to pass + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + Indexes::iterator OIndexCollection::insert(const OUString& _rName) + { + OSL_ENSURE(end() == find(_rName), "OIndexCollection::insert: invalid new name!"); + OIndex aNewIndex((OUString())); // the empty string indicates the index is a new one + aNewIndex.sName = _rName; + m_aIndexes.push_back(aNewIndex); + return m_aIndexes.end() - 1; // the last element is the new one ... + } + + void OIndexCollection::implConstructFrom(const Reference< XNameAccess >& _rxIndexes) + { + detach(); + + m_xIndexes = _rxIndexes; + if (!m_xIndexes.is()) + return; + + // loop through all the indexes + Sequence< OUString > aNames = m_xIndexes->getElementNames(); + const OUString* pNames = aNames.getConstArray(); + const OUString* pEnd = pNames + aNames.getLength(); + for (; pNames < pEnd; ++pNames) + { + // extract the index object + Reference< XPropertySet > xIndex; + m_xIndexes->getByName(*pNames) >>= xIndex; + if (!xIndex.is()) + { + OSL_FAIL("OIndexCollection::implConstructFrom: got an invalid index object ... ignoring!"); + continue; + } + + // fill the OIndex structure + OIndex aCurrentIndex(*pNames); + implFillIndexInfo(aCurrentIndex); + m_aIndexes.push_back(aCurrentIndex); + } + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/linkeddocuments.cxx b/dbaccess/source/ui/misc/linkeddocuments.cxx new file mode 100644 index 000000000..192331ced --- /dev/null +++ b/dbaccess/source/ui/misc/linkeddocuments.cxx @@ -0,0 +1,354 @@ +/* -*- 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 <core_resource.hxx> +#include <linkeddocuments.hxx> +#include <osl/diagnose.h> +#include <tools/diagnose_ex.h> +#include <unotools/confignode.hxx> +#include <comphelper/classids.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/ucb/OpenCommandArgument.hpp> +#include <com/sun/star/ucb/OpenMode.hpp> +#include <com/sun/star/task/XJobExecutor.hpp> +#include <comphelper/types.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <svl/filenotation.hxx> +#include <browserids.hxx> +#include <com/sun/star/container/XHierarchicalNameContainer.hpp> +#include <comphelper/mimeconfighelper.hxx> +#include <vcl/weld.hxx> + +#include <cppuhelper/exc_hlp.hxx> +#include <connectivity/dbtools.hxx> +#include <com/sun/star/io/WrongFormatException.hpp> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::ucb; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::sdb::application; + using namespace ::com::sun::star::task; + using namespace ::svt; + + namespace + { + Sequence< sal_Int8 > lcl_GetSequenceClassID( sal_uInt32 n1, sal_uInt16 n2, sal_uInt16 n3, + sal_uInt8 b8, sal_uInt8 b9, sal_uInt8 b10, sal_uInt8 b11, + sal_uInt8 b12, sal_uInt8 b13, sal_uInt8 b14, sal_uInt8 b15 ) + { + Sequence< sal_Int8 > aResult{ /* [ 0] */ static_cast<sal_Int8>(n1 >> 24), + /* [ 1] */ static_cast<sal_Int8>(( n1 << 8 ) >> 24), + /* [ 2] */ static_cast<sal_Int8>(( n1 << 16 ) >> 24), + /* [ 3] */ static_cast<sal_Int8>(( n1 << 24 ) >> 24), + /* [ 4] */ static_cast<sal_Int8>(n2 >> 8), + /* [ 5] */ static_cast<sal_Int8>(( n2 << 8 ) >> 8), + /* [ 6] */ static_cast<sal_Int8>(n3 >> 8), + /* [ 7] */ static_cast<sal_Int8>(( n3 << 8 ) >> 8), + /* [ 8] */ static_cast<sal_Int8>(b8), + /* [ 9] */ static_cast<sal_Int8>(b9), + /* [10] */ static_cast<sal_Int8>(b10), + /* [11] */ static_cast<sal_Int8>(b11), + /* [12] */ static_cast<sal_Int8>(b12), + /* [13] */ static_cast<sal_Int8>(b13), + /* [14] */ static_cast<sal_Int8>(b14), + /* [15] */ static_cast<sal_Int8>(b15) }; + return aResult; + } + } + + // OLinkedDocumentsAccess + OLinkedDocumentsAccess::OLinkedDocumentsAccess( weld::Window* pDialogParent, const Reference< XDatabaseDocumentUI >& i_rDocumentUI, + const Reference< XComponentContext >& _rxContext, const Reference< XNameAccess >& _rxContainer, + const Reference< XConnection>& _xConnection, const OUString& _sDataSourceName ) + :m_xContext(_rxContext) + ,m_xDocumentContainer(_rxContainer) + ,m_xConnection(_xConnection) + ,m_xDocumentUI( i_rDocumentUI ) + ,m_pDialogParent(pDialogParent) + ,m_sDataSourceName(_sDataSourceName) + { + OSL_ENSURE(m_xContext.is(), "OLinkedDocumentsAccess::OLinkedDocumentsAccess: invalid service factory!"); + assert(m_pDialogParent && "OLinkedDocumentsAccess::OLinkedDocumentsAccess: really need a dialog parent!"); + } + OLinkedDocumentsAccess::~OLinkedDocumentsAccess() + { + } + Reference< XComponent> OLinkedDocumentsAccess::impl_open( const OUString& _rLinkName, Reference< XComponent >& _xDefinition, + ElementOpenMode _eOpenMode, const ::comphelper::NamedValueCollection& _rAdditionalArgs ) + { + Reference< XComponent> xRet; + OSL_ENSURE(m_xDocumentContainer.is(), "OLinkedDocumentsAccess::OLinkedDocumentsAccess: invalid document container!"); + Reference< XComponentLoader > xComponentLoader(m_xDocumentContainer,UNO_QUERY); + if ( !xComponentLoader.is() ) + return xRet; + + weld::WaitObject aWaitCursor(m_pDialogParent); + + ::comphelper::NamedValueCollection aArguments; + OUString sOpenMode; + switch ( _eOpenMode ) + { + case E_OPEN_NORMAL: + sOpenMode = "open"; + break; + + case E_OPEN_FOR_MAIL: + aArguments.put( "Hidden", true ); + [[fallthrough]]; + + case E_OPEN_DESIGN: + sOpenMode = "openDesign"; + break; + + default: + OSL_FAIL( "OLinkedDocumentsAccess::implOpen: invalid open mode!" ); + break; + } + aArguments.put( "OpenMode", sOpenMode ); + + aArguments.put( PROPERTY_ACTIVE_CONNECTION, m_xConnection ); + + Reference<XHierarchicalNameContainer> xHier(m_xDocumentContainer,UNO_QUERY); + if ( xHier.is() && xHier->hasByHierarchicalName(_rLinkName) ) + { + _xDefinition.set(xHier->getByHierarchicalName(_rLinkName),UNO_QUERY); + } + + aArguments.merge( _rAdditionalArgs, true ); + + xRet = xComponentLoader->loadComponentFromURL( _rLinkName, OUString(), 0, aArguments.getPropertyValues() ); + + return xRet; + } + void OLinkedDocumentsAccess::impl_newWithPilot( const char* _pWizardService, + const sal_Int32 _nCommandType, const OUString& _rObjectName ) + { + try + { + ::comphelper::NamedValueCollection aArgs; + aArgs.put( "DataSourceName", m_sDataSourceName ); + + if ( m_xConnection.is() ) + aArgs.put( "ActiveConnection", m_xConnection ); + + if ( !_rObjectName.isEmpty() && ( _nCommandType != -1 ) ) + { + aArgs.put( "CommandType", _nCommandType ); + aArgs.put( "Command", _rObjectName ); + } + + aArgs.put( "DocumentUI", m_xDocumentUI ); + + Reference< XJobExecutor > xWizard; + { + weld::WaitObject aWaitCursor(m_pDialogParent); + xWizard.set( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + OUString::createFromAscii( _pWizardService ), + aArgs.getWrappedPropertyValues(), + m_xContext + ), UNO_QUERY_THROW ); + } + + xWizard->trigger( "start" ); + ::comphelper::disposeComponent( xWizard ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + void OLinkedDocumentsAccess::newFormWithPilot( const sal_Int32 _nCommandType,const OUString& _rObjectName ) + { + impl_newWithPilot( "com.sun.star.wizards.form.CallFormWizard", _nCommandType, _rObjectName ); + } + + void OLinkedDocumentsAccess::newReportWithPilot( const sal_Int32 _nCommandType, const OUString& _rObjectName ) + { + impl_newWithPilot( "com.sun.star.wizards.report.CallReportWizard", _nCommandType, _rObjectName ); + } + void OLinkedDocumentsAccess::newTableWithPilot() + { + impl_newWithPilot( "com.sun.star.wizards.table.CallTableWizard", -1, OUString() ); + } + void OLinkedDocumentsAccess::newQueryWithPilot() + { + impl_newWithPilot( "com.sun.star.wizards.query.CallQueryWizard", -1, OUString() ); + } + Reference< XComponent > OLinkedDocumentsAccess::newDocument( sal_Int32 i_nActionID, + const ::comphelper::NamedValueCollection& i_rCreationArgs, Reference< XComponent >& o_rDefinition ) + { + OSL_ENSURE(m_xDocumentContainer.is(), "OLinkedDocumentsAccess::newDocument: invalid document container!"); + // determine the class ID to use for the new document + Sequence<sal_Int8> aClassId; + if ( !i_rCreationArgs.has( "ClassID" ) + && !i_rCreationArgs.has( "MediaType" ) + && !i_rCreationArgs.has( "DocumentServiceName" ) + ) + { + switch ( i_nActionID ) + { + case ID_FORM_NEW_TEXT: + aClassId = lcl_GetSequenceClassID(SO3_SW_CLASSID); + OSL_ENSURE(aClassId == comphelper::MimeConfigurationHelper::GetSequenceClassID(SO3_SW_CLASSID),"Not equal"); + break; + + case ID_FORM_NEW_CALC: + aClassId = lcl_GetSequenceClassID(SO3_SC_CLASSID); + break; + + case ID_FORM_NEW_IMPRESS: + aClassId = lcl_GetSequenceClassID(SO3_SIMPRESS_CLASSID); + break; + + case ID_REPORT_NEW_TEXT: + aClassId = comphelper::MimeConfigurationHelper::GetSequenceClassID(SO3_RPT_CLASSID_90); + break; + + default: + OSL_FAIL( "OLinkedDocumentsAccess::newDocument: please use newFormWithPilot!" ); + return Reference< XComponent >(); + + } + } + + // load the document as template + Reference< XComponent > xNewDocument; + try + { // get the desktop object + + Reference<XMultiServiceFactory> xORB(m_xDocumentContainer,UNO_QUERY); + if ( xORB.is() ) + { + ::comphelper::NamedValueCollection aCreationArgs( i_rCreationArgs ); + if ( aClassId.hasElements() ) + aCreationArgs.put( "ClassID", aClassId ); + aCreationArgs.put( PROPERTY_ACTIVE_CONNECTION, m_xConnection ); + + // separate values which are real creation args from args relevant for opening the doc + ::comphelper::NamedValueCollection aCommandArgs; + if ( aCreationArgs.has( "Hidden" ) ) + { + aCommandArgs.put( "Hidden", aCreationArgs.get( "Hidden" ) ); + aCreationArgs.remove( "Hidden" ); + } + + Reference< XCommandProcessor > xContent( xORB->createInstanceWithArguments( + SERVICE_SDB_DOCUMENTDEFINITION, + aCreationArgs.getWrappedPropertyValues() + ), + UNO_QUERY_THROW + ); + o_rDefinition.set( xContent, UNO_QUERY ); + + // put the OpenMode into the OpenArgs + OpenCommandArgument aOpenModeArg; + aOpenModeArg.Mode = OpenMode::DOCUMENT; + aCommandArgs.put( "OpenMode", aOpenModeArg ); + + Command aCommand; + aCommand.Name = "openDesign"; + aCommand.Argument <<= aCommandArgs.getPropertyValues(); + weld::WaitObject aWaitCursor(m_pDialogParent); + xNewDocument.set( xContent->execute( aCommand, xContent->createCommandIdentifier(), nullptr ), UNO_QUERY ); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return xNewDocument; + } + + Reference< XComponent > OLinkedDocumentsAccess::open( const OUString& _rLinkName, Reference< XComponent >& _xDefinition, + ElementOpenMode _eOpenMode, const ::comphelper::NamedValueCollection& _rAdditionalArgs ) + { + dbtools::SQLExceptionInfo aInfo; + Reference< XComponent > xRet; + try + { + xRet = impl_open( _rLinkName, _xDefinition, _eOpenMode, _rAdditionalArgs ); + if ( !xRet.is() ) + { + OUString sMessage = DBA_RES(STR_COULDNOTOPEN_LINKEDDOC); + sMessage = sMessage.replaceFirst("$file$",_rLinkName); + + css::sdbc::SQLException aSQLException; + aSQLException.Message = sMessage; + aInfo = dbtools::SQLExceptionInfo(aSQLException); + } + } + catch(const css::io::WrongFormatException &e) + { + css::sdbc::SQLException aSQLException; + aSQLException.Message = e.Message; + aSQLException.Context = e.Context; + aInfo = dbtools::SQLExceptionInfo(aSQLException); + + // more like a hack, insert an empty message + OUString sText( DBA_RES( RID_STR_EXTENSION_NOT_PRESENT ) ); + sText = sText.replaceFirst("$file$",_rLinkName); + aInfo.prepend(sText); + + OUString sMessage = DBA_RES(STR_COULDNOTOPEN_LINKEDDOC); + sMessage = sMessage.replaceFirst("$file$",_rLinkName); + aInfo.prepend(sMessage); + } + catch(const Exception& e) + { + Any aAny = ::cppu::getCaughtException(); + css::sdbc::SQLException a; + if ( !(aAny >>= a) || (a.ErrorCode != dbtools::ParameterInteractionCancelled) ) + { + css::sdbc::SQLException aSQLException; + aSQLException.Message = e.Message; + aSQLException.Context = e.Context; + aInfo = dbtools::SQLExceptionInfo(aSQLException); + + // more like a hack, insert an empty message + aInfo.prepend(" \n"); + + OUString sMessage = DBA_RES(STR_COULDNOTOPEN_LINKEDDOC); + sMessage = sMessage.replaceFirst("$file$",_rLinkName); + aInfo.prepend(sMessage); + } + } + if (aInfo.isValid()) + { + showError(aInfo, m_pDialogParent->GetXWindow(), m_xContext); + } + return xRet; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/propertystorage.cxx b/dbaccess/source/ui/misc/propertystorage.cxx new file mode 100644 index 000000000..c3c504994 --- /dev/null +++ b/dbaccess/source/ui/misc/propertystorage.cxx @@ -0,0 +1,106 @@ +/* -*- 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 <propertystorage.hxx> + +#include <svl/itemset.hxx> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> + +#include <osl/diagnose.h> + +#include <cassert> +#include <memory> + +namespace dbaui +{ + + using ::com::sun::star::uno::Any; + + // helper + namespace + { + template < class ITEMTYPE, class UNOTYPE > + class ItemAdapter + { + public: + static bool trySet( SfxItemSet& _rSet, sal_uInt16 _nItemId, const Any& _rValue ) + { + const SfxPoolItem& rItem( _rSet.Get( _nItemId ) ); + const ITEMTYPE* pTypedItem = dynamic_cast< const ITEMTYPE* >( &rItem ); + if ( !pTypedItem ) + return false; + + UNOTYPE aValue( pTypedItem->GetValue() ); + OSL_VERIFY( _rValue >>= aValue ); + // TODO: one could throw an IllegalArgumentException here - finally, this method + // is (to be) used from within an XPropertySet::setPropertyValue implementation, + // where this would be the appropriate reaction on wrong value types + ITEMTYPE* pCloneItem = dynamic_cast< ITEMTYPE* >( pTypedItem->Clone() ); + if(!pCloneItem) + { + return false; + } + std::unique_ptr< ITEMTYPE > pClone( pCloneItem); + assert(pClone.get()); + pClone->SetValue( aValue ); + _rSet.Put( std::move(pClone) ); + return true; + } + + static bool tryGet( const SfxPoolItem& _rItem, Any& _out_rValue ) + { + const ITEMTYPE* pTypedItem = dynamic_cast< const ITEMTYPE* >( &_rItem ); + if ( !pTypedItem ) + return false; + + _out_rValue <<= UNOTYPE( pTypedItem->GetValue() ); + return true; + } + }; + } + + // SetItemPropertyStorage + void SetItemPropertyStorage::getPropertyValue( Any& _out_rValue ) const + { + const SfxPoolItem& rItem( m_rItemSet.Get( m_nItemID ) ); + + // try some known item types + if ( ItemAdapter< SfxBoolItem, bool >::tryGet( rItem, _out_rValue ) + || ItemAdapter< SfxStringItem, OUString >::tryGet( rItem, _out_rValue ) + ) + return; + + OSL_FAIL( "SetItemPropertyStorage::getPropertyValue: unsupported item type!" ); + } + + void SetItemPropertyStorage::setPropertyValue( const Any& _rValue ) + { + // try some known item types + if ( ItemAdapter< SfxBoolItem, bool >::trySet( m_rItemSet, m_nItemID, _rValue ) + || ItemAdapter< SfxStringItem, OUString >::trySet( m_rItemSet, m_nItemID, _rValue ) + ) + return; + + OSL_FAIL( "SetItemPropertyStorage::setPropertyValue: unsupported item type!" ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/singledoccontroller.cxx b/dbaccess/source/ui/misc/singledoccontroller.cxx new file mode 100644 index 000000000..28b0c9e77 --- /dev/null +++ b/dbaccess/source/ui/misc/singledoccontroller.cxx @@ -0,0 +1,184 @@ +/* -*- 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 <dbaccess/dbaundomanager.hxx> +#include <dbaccess/dataview.hxx> +#include <core_resource.hxx> +#include <singledoccontroller.hxx> +#include <browserids.hxx> +#include <strings.hrc> + +#include <svl/undo.hxx> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::document::XUndoManager; + using ::com::sun::star::beans::PropertyValue; + + // OSingleDocumentController_Data + struct OSingleDocumentController_Data + { + // no Reference! see UndoManager::acquire + std::unique_ptr<UndoManager> m_pUndoManager; + + OSingleDocumentController_Data( ::cppu::OWeakObject& i_parent, ::osl::Mutex& i_mutex ) + : m_pUndoManager(new UndoManager(i_parent, i_mutex)) + { + } + }; + + // OSingleDocumentController + OSingleDocumentController::OSingleDocumentController( const Reference< XComponentContext >& _rxORB ) + :OSingleDocumentController_Base( _rxORB ) + ,m_pData( new OSingleDocumentController_Data( *this, getMutex() ) ) + { + } + + OSingleDocumentController::~OSingleDocumentController() + { + } + + void SAL_CALL OSingleDocumentController::disposing() + { + OSingleDocumentController_Base::disposing(); + ClearUndoManager(); + m_pData->m_pUndoManager->disposing(); + } + + void OSingleDocumentController::ClearUndoManager() + { + GetUndoManager().Clear(); + } + + SfxUndoManager& OSingleDocumentController::GetUndoManager() const + { + return m_pData->m_pUndoManager->GetSfxUndoManager(); + } + + void OSingleDocumentController::addUndoActionAndInvalidate(std::unique_ptr<SfxUndoAction> _pAction) + { + // add undo action + GetUndoManager().AddUndoAction( std::move(_pAction) ); + + // when we add an undo action the controller was modified + setModified( true ); + + // now inform me that or states changed + InvalidateFeature( ID_BROWSER_UNDO ); + InvalidateFeature( ID_BROWSER_REDO ); + } + + Reference< XUndoManager > SAL_CALL OSingleDocumentController::getUndoManager( ) + { + // see UndoManager::acquire + return m_pData->m_pUndoManager.get(); + } + + FeatureState OSingleDocumentController::GetState(sal_uInt16 _nId) const + { + FeatureState aReturn; + switch ( _nId ) + { + case ID_BROWSER_UNDO: + aReturn.bEnabled = isEditable() && GetUndoManager().GetUndoActionCount() != 0; + if ( aReturn.bEnabled ) + { + OUString sUndo = DBA_RES(STR_UNDO_COLON) + " " + + GetUndoManager().GetUndoActionComment(); + aReturn.sTitle = sUndo; + } + break; + + case ID_BROWSER_REDO: + aReturn.bEnabled = isEditable() && GetUndoManager().GetRedoActionCount() != 0; + if ( aReturn.bEnabled ) + { + OUString sRedo = DBA_RES(STR_REDO_COLON) + " " + + GetUndoManager().GetRedoActionComment(); + aReturn.sTitle = sRedo; + } + break; + + case SID_GETUNDOSTRINGS: + { + size_t nCount(GetUndoManager().GetUndoActionCount()); + Sequence<OUString> aSeq(nCount); + auto aSeqRange = asNonConstRange(aSeq); + for (size_t n = 0; n < nCount; ++n) + aSeqRange[n] = GetUndoManager().GetUndoActionComment(n); + aReturn.aValue <<= aSeq; + aReturn.bEnabled = true; + break; + } + + case SID_GETREDOSTRINGS: + { + size_t nCount(GetUndoManager().GetRedoActionCount()); + Sequence<OUString> aSeq(nCount); + auto aSeqRange = asNonConstRange(aSeq); + for (size_t n = 0; n < nCount; ++n) + aSeqRange[n] = GetUndoManager().GetRedoActionComment(n); + aReturn.aValue <<= aSeq; + aReturn.bEnabled = true; + break; + } + + default: + aReturn = OSingleDocumentController_Base::GetState(_nId); + } + return aReturn; + } + void OSingleDocumentController::Execute( sal_uInt16 _nId, const Sequence< PropertyValue >& _rArgs ) + { + switch ( _nId ) + { + case ID_BROWSER_UNDO: + case ID_BROWSER_REDO: + { + sal_Int16 nCount(1); + if (_rArgs.hasElements() && _rArgs[0].Name != "KeyModifier") + _rArgs[0].Value >>= nCount; + + while (nCount--) + { + if (_nId == ID_BROWSER_UNDO) + GetUndoManager().Undo(); + else + GetUndoManager().Redo(); + } + + InvalidateFeature( ID_BROWSER_UNDO ); + InvalidateFeature( ID_BROWSER_REDO ); + break; + } + + default: + OSingleDocumentController_Base::Execute( _nId, _rArgs ); + break; + } + InvalidateFeature(_nId); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/stringlistitem.cxx b/dbaccess/source/ui/misc/stringlistitem.cxx new file mode 100644 index 000000000..97e75fe6d --- /dev/null +++ b/dbaccess/source/ui/misc/stringlistitem.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 <stringlistitem.hxx> + +namespace dbaui +{ +using namespace ::com::sun::star::uno; + +// OStringListItem +OStringListItem::OStringListItem(sal_Int16 _nWhich, const Sequence<OUString>& _rList) + : SfxPoolItem(_nWhich) + , m_aList(_rList) +{ +} + +OStringListItem::OStringListItem(const OStringListItem& _rSource) + : SfxPoolItem(_rSource) + , m_aList(_rSource.m_aList) +{ +} + +bool OStringListItem::operator==(const SfxPoolItem& _rItem) const +{ + if (!SfxPoolItem::operator==(_rItem)) + return false; + const OStringListItem* pCompare = static_cast<const OStringListItem*>(&_rItem); + if (pCompare->m_aList.getLength() != m_aList.getLength()) + return false; + + // compare all strings individually + for (sal_Int32 i = 0; i < m_aList.getLength(); ++i) + if (m_aList[i] != pCompare->m_aList[i]) + return false; + + return true; +} + +OStringListItem* OStringListItem::Clone(SfxItemPool* /* _pPool */) const +{ + return new OStringListItem(*this); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/ConnectionLine.cxx b/dbaccess/source/ui/querydesign/ConnectionLine.cxx new file mode 100644 index 000000000..77a67004e --- /dev/null +++ b/dbaccess/source/ui/querydesign/ConnectionLine.cxx @@ -0,0 +1,356 @@ +/* -*- 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 <ConnectionLine.hxx> +#include <ConnectionLineData.hxx> +#include <TableWindow.hxx> +#include <TableWindowListBox.hxx> +#include <TableConnection.hxx> +#include <vcl/svapp.hxx> +#include <math.h> +#include <osl/diagnose.h> +#include <vcl/lineinfo.hxx> +#include <vcl/settings.hxx> + +using namespace dbaui; +const tools::Long DESCRIPT_LINE_WIDTH = 15; +const tools::Long HIT_SENSITIVE_RADIUS = 5; + +namespace +{ + /** calcRect creates a new rectangle with the given points + @param _rBase the base point + @param _aVector the vector which will be added + */ + tools::Rectangle calcRect(const Point& _rBase,const Point& _aVector) + { + return tools::Rectangle( _rBase - _aVector, _rBase + _aVector ); + } + /** GetTextPos calculate the rectangle for the connection to be drawn + @param _pWin the table window where to draw it + @param _aConnPos the connection point + @param _aDescrLinePos the description line pos + */ + tools::Rectangle GetTextPos(const OTableWindow* _pWin, const Point& _aConnPos,const Point& _aDescrLinePos) + { + VclPtr<OTableWindowListBox> pListBox = _pWin ? _pWin->GetListBox() : nullptr; + OSL_ENSURE(_pWin && pListBox, "OConnectionLine::GetSourceTextPos : invalid call !"); + + tools::Rectangle aReturn; + if ( pListBox ) + { + const tools::Long nRowHeight = pListBox->get_widget().get_height_rows(1); + aReturn.SetTop( _aConnPos.Y() - nRowHeight ); + aReturn.SetBottom( aReturn.Top() + nRowHeight ); + if (_aDescrLinePos.X() < _aConnPos.X()) + { + aReturn.SetLeft( _aDescrLinePos.X() ); + aReturn.SetRight( aReturn.Left() + _aConnPos.X() - _aDescrLinePos.X() ); + } + else + { + aReturn.SetLeft( _aConnPos.X() ); + aReturn.SetRight( aReturn.Left() + _aDescrLinePos.X() - _aConnPos.X() ); + } + } + + return aReturn; + } + /** calcPointsYValue calculate the points Y value in relation to the listbox entry + @param _pWin the corresponding window + @param _nEntry the source or dest entry + @param _rNewConPos (in/out) the connection pos + @param _rNewDescrPos (in/out) the description pos + */ + void calcPointsYValue(const OTableWindow* _pWin, int _nEntry, Point& _rNewConPos, Point& _rNewDescrPos) + { + const OTableWindowListBox* pListBox = _pWin->GetListBox(); + _rNewConPos.setY( _pWin->GetPosPixel().Y() ); + + std::unique_ptr<weld::TreeIter> xEntry; + const weld::TreeView& rTreeView = pListBox->get_widget(); + + if (_nEntry != -1) + { + _rNewConPos.AdjustY(pListBox->GetPosPixel().Y() ); + xEntry = rTreeView.make_iterator(); + if (!rTreeView.get_iter_first(*xEntry) || !rTreeView.iter_nth_sibling(*xEntry, _nEntry)) + xEntry.reset(); + } + + if (xEntry) + { + auto nEntryPos = rTreeView.get_row_area(*xEntry).Center().Y(); + + if( nEntryPos >= 0 ) + { + _rNewConPos.AdjustY(nEntryPos); + } + else + { + const auto nRowHeight = rTreeView.get_height_rows(1); + _rNewConPos.AdjustY( -static_cast<tools::Long>( 0.5 * nRowHeight ) ); + } + + tools::Long nListBoxBottom = _pWin->GetPosPixel().Y() + + pListBox->GetPosPixel().Y() + + pListBox->GetSizePixel().Height(); + if( _rNewConPos.Y() > nListBoxBottom ) + _rNewConPos.setY( nListBoxBottom + 2 ); + } + else + _rNewConPos.AdjustY(static_cast<sal_Int32>(pListBox->GetPosPixel().Y()*0.5) ); + + _rNewDescrPos.setY( _rNewConPos.Y() ); + } +} + +OConnectionLine::OConnectionLine( OTableConnection* _pConn, OConnectionLineDataRef const & _pLineData ) + : m_pTabConn( _pConn ) + , m_pData( _pLineData ) +{ +} + +OConnectionLine::OConnectionLine( const OConnectionLine& _rLine ) + : m_pTabConn(nullptr) +{ + m_pData = new OConnectionLineData( *_rLine.GetData() ); + *this = _rLine; +} + +OConnectionLine::~OConnectionLine() +{ +} + +OConnectionLine& OConnectionLine::operator=( const OConnectionLine& rLine ) +{ + if( &rLine != this ) + { + // as the data does not belong to me, I don't delete the old one + m_pData->CopyFrom(*rLine.GetData()); + // CopyFrom is virtual, therefore it is not a problem, if m_pData is of a type derived from OTableConnectionData + + m_pTabConn = rLine.m_pTabConn; + m_aSourceConnPos = rLine.m_aSourceConnPos; + m_aDestConnPos = rLine.m_aDestConnPos; + m_aSourceDescrLinePos = rLine.m_aSourceDescrLinePos; + m_aDestDescrLinePos = rLine.m_aDestDescrLinePos; + } + + return *this; +} + +tools::Rectangle OConnectionLine::GetBoundingRect() const +{ + // determine surrounding rectangle + tools::Rectangle aBoundingRect( Point(0,0), Point(0,0) ); + if( !IsValid() ) + return aBoundingRect; + + Point aTopLeft; + Point aBottomRight; + + if( m_aSourceDescrLinePos.Y() <= m_aDestDescrLinePos.Y() ) + { + aTopLeft.setY( m_aSourceDescrLinePos.Y() ); + aBottomRight.setY( m_aDestDescrLinePos.Y() ); + } + else + { + aTopLeft.setY( m_aDestDescrLinePos.Y() ); + aBottomRight.setY( m_aSourceDescrLinePos.Y() ); + } + + if( m_aSourceDescrLinePos.X() <= m_aDestDescrLinePos.X() ) + { + aTopLeft.setX( m_aSourceDescrLinePos.X() ); + aBottomRight.setX( m_aDestDescrLinePos.X() ); + } + else + { + aTopLeft.setX( m_aDestDescrLinePos.X() ); + aBottomRight.setX( m_aSourceDescrLinePos.X() ); + } + + const OTableWindow* pSourceWin = m_pTabConn->GetSourceWin(); + const OTableWindow* pDestWin = m_pTabConn->GetDestWin(); + // line proceeds in z-Form + if( pSourceWin == pDestWin || std::abs(m_aSourceConnPos.X() - m_aDestConnPos.X()) > std::abs(m_aSourceDescrLinePos.X() - m_aDestDescrLinePos.X()) ) + { + aTopLeft.AdjustX( -DESCRIPT_LINE_WIDTH ); + aBottomRight.AdjustX(DESCRIPT_LINE_WIDTH ); + } + + aBoundingRect = tools::Rectangle( aTopLeft-Point(2,17), aBottomRight+Point(2,2) ); + + return aBoundingRect; +} + +static void calcPointX1(const OTableWindow* _pWin,Point& _rNewConPos,Point& _rNewDescrPos) +{ + _rNewConPos.setX( _pWin->GetPosPixel().X() + _pWin->GetSizePixel().Width() ); + _rNewDescrPos.setX( _rNewConPos.X() ); + _rNewConPos.AdjustX(DESCRIPT_LINE_WIDTH ); +} + +static void calcPointX2(const OTableWindow* _pWin,Point& _rNewConPos,Point& _rNewDescrPos) +{ + _rNewConPos.setX( _pWin->GetPosPixel().X() ); + _rNewDescrPos.setX( _rNewConPos.X() ); + _rNewConPos.AdjustX( -DESCRIPT_LINE_WIDTH ); +} + +bool OConnectionLine::RecalcLine() +{ + // Windows and entries must be set + const OTableWindow* pSourceWin = m_pTabConn->GetSourceWin(); + const OTableWindow* pDestWin = m_pTabConn->GetDestWin(); + + if( !pSourceWin || !pDestWin ) + return false; + + int nSourceEntry = pSourceWin->GetListBox()->GetEntryFromText( GetData()->GetSourceFieldName() ); + int nDestEntry = pDestWin->GetListBox()->GetEntryFromText( GetData()->GetDestFieldName() ); + + // determine X-coordinates + Point aSourceCenter( 0, 0 ); + Point aDestCenter( 0, 0 ); + + aSourceCenter.setX( pSourceWin->GetPosPixel().X() + static_cast<tools::Long>( 0.5*pSourceWin->GetSizePixel().Width() ) ); + aDestCenter.setX( pDestWin->GetPosPixel().X() + static_cast<tools::Long>( 0.5*pDestWin->GetSizePixel().Width() ) ); + + const OTableWindow* pFirstWin = pDestWin; + const OTableWindow* pSecondWin = pSourceWin; + Point* pFirstConPos = &m_aDestConnPos; + Point* pFirstDescrPos = &m_aDestDescrLinePos; + Point* pSecondConPos = &m_aSourceConnPos; + Point* pSecondDescrPos = &m_aSourceDescrLinePos; + if( aDestCenter.X() > aSourceCenter.X() ) + { + pFirstWin = pSourceWin; + pSecondWin = pDestWin; + pFirstConPos = &m_aSourceConnPos; + pFirstDescrPos = &m_aSourceDescrLinePos; + pSecondConPos = &m_aDestConnPos; + pSecondDescrPos = &m_aDestDescrLinePos; + } + + if (pFirstWin == pSecondWin && nSourceEntry != nDestEntry) + calcPointX2(pFirstWin,*pFirstConPos,*pFirstDescrPos); + else + calcPointX1(pFirstWin,*pFirstConPos,*pFirstDescrPos); + calcPointX2(pSecondWin,*pSecondConPos,*pSecondDescrPos); + + // determine aSourceConnPosY + calcPointsYValue(pSourceWin, nSourceEntry, m_aSourceConnPos,m_aSourceDescrLinePos); + + // determine aDestConnPosY + calcPointsYValue(pDestWin, nDestEntry, m_aDestConnPos,m_aDestDescrLinePos); + + return true; +} + +void OConnectionLine::Draw( OutputDevice* pOutDev ) +{ + const sal_uInt16 nRectSize = 3; + + // calculate new dimension + if( !RecalcLine() ) + return; + + // draw lines + if (m_pTabConn->IsSelected()) + pOutDev->SetLineColor(Application::GetSettings().GetStyleSettings().GetHighlightColor()); + else + pOutDev->SetLineColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor()); + + LineInfo aLineInfo; + if ( m_pTabConn->IsSelected() ) + aLineInfo.SetWidth(3); + tools::Polygon aPoly; + aPoly.Insert(0,m_aSourceDescrLinePos); + aPoly.Insert(1,m_aSourceConnPos); + aPoly.Insert(2,m_aDestConnPos); + aPoly.Insert(3,m_aDestDescrLinePos); + pOutDev->DrawPolyLine(aPoly,aLineInfo); + + // draw the connection rectangles + pOutDev->SetFillColor(Application::GetSettings().GetStyleSettings().GetWindowColor()); + + Point aVector(nRectSize,nRectSize); + pOutDev->DrawRect( calcRect(m_aSourceDescrLinePos,aVector) ); + pOutDev->DrawRect( calcRect( m_aDestDescrLinePos,aVector) ); +} + +bool OConnectionLine::IsValid() const +{ + return m_pData.is(); +} + +static double dist_Euklid(const Point &p1, const Point& p2,const Point& pM, Point& q) +{ + Point v(p2 - p1); + Point w(pM - p1); + double a = std::hypot(v.X(), v.Y()); + double l = (v.X() * w.Y() - v.Y() * w.X()) / a; + double a2 = w.X()*v.X()+w.Y()*v.Y(); + a = a2 / (a * a); + q.setX( tools::Long(p1.X() + a * v.X()) ); + q.setY( tools::Long(p1.Y() + a * v.Y()) ); + return l; +} + +bool OConnectionLine::CheckHit( const Point& rMousePos ) const +{ + /* + course of action with HitTest: + the distance is calculated according to Euklid. + */ + Point q; + double l = fabs(dist_Euklid(m_aSourceConnPos,m_aDestConnPos,rMousePos,q)); + if( l < HIT_SENSITIVE_RADIUS) + { + if(std::min(m_aSourceConnPos.X(),m_aDestConnPos.X()) <= q.X() && std::min(m_aSourceConnPos.Y(),m_aDestConnPos.Y()) <= q.Y() + && q.X() <= std::max(m_aDestConnPos.X(),m_aSourceConnPos.X()) && q.Y() <= std::max(m_aDestConnPos.Y(),m_aSourceConnPos.Y())) + return true; + } + + return false; +} + +tools::Rectangle OConnectionLine::GetSourceTextPos() const +{ + return GetTextPos(m_pTabConn->GetSourceWin(),m_aSourceConnPos,m_aSourceDescrLinePos); +} + +tools::Rectangle OConnectionLine::GetDestTextPos() const +{ + return GetTextPos(m_pTabConn->GetDestWin(),m_aDestConnPos,m_aDestDescrLinePos); +} + +Point OConnectionLine::getMidPoint() const +{ + Point aDest = m_aDestConnPos - m_aSourceConnPos; + aDest.setX( aDest.X() / 2 ); + aDest.setY( aDest.Y() / 2 ); + + return m_aSourceConnPos + aDest; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/ConnectionLineAccess.cxx b/dbaccess/source/ui/querydesign/ConnectionLineAccess.cxx new file mode 100644 index 000000000..f11ca853c --- /dev/null +++ b/dbaccess/source/ui/querydesign/ConnectionLineAccess.cxx @@ -0,0 +1,187 @@ +/* -*- 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 <ConnectionLineAccess.hxx> +#include <ConnectionLine.hxx> +#include <JoinTableView.hxx> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <TableConnection.hxx> +#include <TableWindow.hxx> +#include <comphelper/sequence.hxx> + +namespace dbaui +{ + using namespace ::com::sun::star::accessibility; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star; + + OConnectionLineAccess::OConnectionLineAccess(OTableConnection* _pLine) + : VCLXAccessibleComponent(_pLine->GetComponentInterface().is() ? _pLine->GetWindowPeer() : nullptr) + ,m_pLine(_pLine) + { + } + void SAL_CALL OConnectionLineAccess::disposing() + { + m_pLine = nullptr; + VCLXAccessibleComponent::disposing(); + } + Any SAL_CALL OConnectionLineAccess::queryInterface( const Type& aType ) + { + Any aRet(VCLXAccessibleComponent::queryInterface( aType )); + return aRet.hasValue() ? aRet : OConnectionLineAccess_BASE::queryInterface( aType ); + } + Sequence< Type > SAL_CALL OConnectionLineAccess::getTypes( ) + { + return ::comphelper::concatSequences(VCLXAccessibleComponent::getTypes(),OConnectionLineAccess_BASE::getTypes()); + } + OUString SAL_CALL OConnectionLineAccess::getImplementationName() + { + return "org.openoffice.comp.dbu.ConnectionLineAccessibility"; + } + // XAccessibleContext + sal_Int32 SAL_CALL OConnectionLineAccess::getAccessibleChildCount( ) + { + return 0; + } + Reference< XAccessible > SAL_CALL OConnectionLineAccess::getAccessibleChild( sal_Int32 /*i*/ ) + { + return Reference< XAccessible >(); + } + sal_Int32 SAL_CALL OConnectionLineAccess::getAccessibleIndexInParent( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + sal_Int32 nIndex = -1; + if( m_pLine ) + { + // search the position of our table window in the table window map + // TODO JNA Shouldn't nIndex begin at 0? + nIndex = m_pLine->GetParent()->GetTabWinMap().size(); + const auto& rVec = m_pLine->GetParent()->getTableConnections(); + bool bFound = false; + for (auto const& elem : rVec) + { + if (elem.get() == m_pLine) + { + bFound = true; + break; + } + ++nIndex; + } + nIndex = bFound ? nIndex : -1; + } + return nIndex; + } + sal_Int16 SAL_CALL OConnectionLineAccess::getAccessibleRole( ) + { + return AccessibleRole::UNKNOWN; // ? or may be an AccessibleRole::WINDOW + } + OUString SAL_CALL OConnectionLineAccess::getAccessibleDescription( ) + { + return "Relation"; + } + Reference< XAccessibleRelationSet > SAL_CALL OConnectionLineAccess::getAccessibleRelationSet( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return this; + } + // XAccessibleComponent + Reference< XAccessible > SAL_CALL OConnectionLineAccess::getAccessibleAtPoint( const awt::Point& /*_aPoint*/ ) + { + return Reference< XAccessible >(); + } + awt::Rectangle SAL_CALL OConnectionLineAccess::getBounds( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + tools::Rectangle aRect(m_pLine ? m_pLine->GetBoundingRect() : tools::Rectangle()); + return awt::Rectangle(aRect.Left(),aRect.Top(),aRect.getWidth(),aRect.getHeight()); + } + awt::Point SAL_CALL OConnectionLineAccess::getLocation( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Point aPoint(m_pLine ? m_pLine->GetBoundingRect().TopLeft() : Point()); + return awt::Point(aPoint.X(),aPoint.Y()); + } + awt::Point SAL_CALL OConnectionLineAccess::getLocationOnScreen( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Point aPoint(m_pLine ? m_pLine->GetParent()->ScreenToOutputPixel(m_pLine->GetBoundingRect().TopLeft()) : Point()); + return awt::Point(aPoint.X(),aPoint.Y()); + } + awt::Size SAL_CALL OConnectionLineAccess::getSize( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Size aSize(m_pLine ? m_pLine->GetBoundingRect().GetSize() : Size()); + return awt::Size(aSize.Width(),aSize.Height()); + } + // XAccessibleRelationSet + sal_Int32 SAL_CALL OConnectionLineAccess::getRelationCount( ) + { + return 1; + } + AccessibleRelation SAL_CALL OConnectionLineAccess::getRelation( sal_Int32 nIndex ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if( nIndex < 0 || nIndex >= getRelationCount() ) + throw IndexOutOfBoundsException(); + + Sequence< Reference<XInterface> > aSeq; + if( m_pLine ) + { + aSeq = { m_pLine->GetSourceWin()->GetAccessible(), + m_pLine->GetDestWin()->GetAccessible() }; + } + + return AccessibleRelation(AccessibleRelationType::CONTROLLED_BY,aSeq); + } + sal_Bool SAL_CALL OConnectionLineAccess::containsRelation( sal_Int16 aRelationType ) + { + return AccessibleRelationType::CONTROLLED_BY == aRelationType; + } + AccessibleRelation SAL_CALL OConnectionLineAccess::getRelationByType( sal_Int16 aRelationType ) + { + if( AccessibleRelationType::CONTROLLED_BY == aRelationType ) + return getRelation(0); + return AccessibleRelation(); + } + Reference< XAccessible > OTableConnection::CreateAccessible() + { + return new OConnectionLineAccess(this); + } + OTableConnection::~OTableConnection() + { + disposeOnce(); + } + void OTableConnection::dispose() + { + // clear vector + clearLineData(); + m_pParent.clear(); + vcl::Window::dispose(); + } + Reference< XAccessibleContext > SAL_CALL OConnectionLineAccess::getAccessibleContext( ) + { + return this; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/ConnectionLineData.cxx b/dbaccess/source/ui/querydesign/ConnectionLineData.cxx new file mode 100644 index 000000000..db7177294 --- /dev/null +++ b/dbaccess/source/ui/querydesign/ConnectionLineData.cxx @@ -0,0 +1,76 @@ +/* -*- 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 <ConnectionLineData.hxx> + +using namespace dbaui; +OConnectionLineData::OConnectionLineData() +{ +} + +OConnectionLineData::OConnectionLineData( const OUString& rSourceFieldName, const OUString& rDestFieldName ) + :m_aSourceFieldName( rSourceFieldName ) + ,m_aDestFieldName( rDestFieldName ) +{ +} + +OConnectionLineData::OConnectionLineData( const OConnectionLineData& rConnLineData ) + : ::salhelper::SimpleReferenceObject() +{ + *this = rConnLineData; +} + +OConnectionLineData::~OConnectionLineData() +{ +} + +void OConnectionLineData::CopyFrom(const OConnectionLineData& rSource) +{ + *this = rSource; + // Here I rely on the (non-virtual) operator=, which only copies my members +} + +OConnectionLineData& OConnectionLineData::operator=( const OConnectionLineData& rConnLineData ) +{ + if (&rConnLineData == this) + return *this; + + m_aSourceFieldName = rConnLineData.GetSourceFieldName(); + m_aDestFieldName = rConnLineData.GetDestFieldName(); + + return *this; +} + +void OConnectionLineData::Reset() +{ + m_aDestFieldName.clear(); + m_aSourceFieldName.clear(); +} + +namespace dbaui +{ +bool operator==(const OConnectionLineData& lhs, const OConnectionLineData& rhs) +{ + return (lhs.m_aSourceFieldName == rhs.m_aSourceFieldName) + && (lhs.m_aDestFieldName == rhs.m_aDestFieldName); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/JAccess.cxx b/dbaccess/source/ui/querydesign/JAccess.cxx new file mode 100644 index 000000000..8068f0fa7 --- /dev/null +++ b/dbaccess/source/ui/querydesign/JAccess.cxx @@ -0,0 +1,91 @@ +/* -*- 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 <JAccess.hxx> +#include <JoinTableView.hxx> +#include <TableWindow.hxx> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <TableConnection.hxx> +#include <o3tl/safeint.hxx> + +namespace dbaui +{ + using namespace ::com::sun::star::accessibility; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + + OJoinDesignViewAccess::OJoinDesignViewAccess(OJoinTableView* _pTableView) + :VCLXAccessibleComponent(_pTableView->GetComponentInterface().is() ? _pTableView->GetWindowPeer() : nullptr) + ,m_pTableView(_pTableView) + { + } + OUString SAL_CALL OJoinDesignViewAccess::getImplementationName() + { + return "org.openoffice.comp.dbu.JoinViewAccessibility"; + } + void OJoinDesignViewAccess::clearTableView() + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_pTableView = nullptr; + } + // XAccessibleContext + sal_Int32 SAL_CALL OJoinDesignViewAccess::getAccessibleChildCount( ) + { + // TODO may be this will change to only visible windows + // this is the same assumption mt implements + ::osl::MutexGuard aGuard( m_aMutex ); + sal_Int32 nChildCount = 0; + if ( m_pTableView ) + nChildCount = m_pTableView->GetTabWinCount() + m_pTableView->getTableConnections().size(); + return nChildCount; + } + Reference< XAccessible > SAL_CALL OJoinDesignViewAccess::getAccessibleChild( sal_Int32 i ) + { + Reference< XAccessible > aRet; + ::osl::MutexGuard aGuard( m_aMutex ); + if(i < 0 || i >= getAccessibleChildCount() || !m_pTableView) + throw IndexOutOfBoundsException(); + // check if we should return a table window or a connection + sal_Int32 nTableWindowCount = m_pTableView->GetTabWinCount(); + if( i < nTableWindowCount ) + { + OJoinTableView::OTableWindowMap::const_iterator aIter = std::next(m_pTableView->GetTabWinMap().begin(), i); + aRet = aIter->second->GetAccessible(); + } + else if( o3tl::make_unsigned(i - nTableWindowCount) < m_pTableView->getTableConnections().size() ) + aRet = m_pTableView->getTableConnections()[i - nTableWindowCount]->GetAccessible(); + return aRet; + } + sal_Int16 SAL_CALL OJoinDesignViewAccess::getAccessibleRole( ) + { + return AccessibleRole::VIEW_PORT; + } + Reference< XAccessibleContext > SAL_CALL OJoinDesignViewAccess::getAccessibleContext( ) + { + return this; + } + // XInterface + IMPLEMENT_FORWARD_XINTERFACE2( OJoinDesignViewAccess, VCLXAccessibleComponent, OJoinDesignViewAccess_BASE ) + // XTypeProvider + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OJoinDesignViewAccess, VCLXAccessibleComponent, OJoinDesignViewAccess_BASE ) +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/JoinController.cxx b/dbaccess/source/ui/querydesign/JoinController.cxx new file mode 100644 index 000000000..0857e0448 --- /dev/null +++ b/dbaccess/source/ui/querydesign/JoinController.cxx @@ -0,0 +1,406 @@ +/* -*- 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 <browserids.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <connectivity/dbexception.hxx> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <JoinController.hxx> +#include <TableWindowData.hxx> +#include <TableWindow.hxx> +#include <TableConnectionData.hxx> +#include <adtabdlg.hxx> +#include <vcl/svapp.hxx> +#include <osl/mutex.hxx> +#include <osl/diagnose.h> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::dbtools; +using namespace ::comphelper; + +namespace dbaui +{ + +// AddTableDialogContext +class AddTableDialogContext : public IAddTableDialogContext +{ + OJoinController& m_rController; + +public: + explicit AddTableDialogContext( OJoinController& _rController ) + :m_rController( _rController ) + { + } + + virtual ~AddTableDialogContext() {} + + // IAddTableDialogContext + virtual css::uno::Reference< css::sdbc::XConnection > + getConnection() const override; + virtual bool allowViews() const override; + virtual bool allowQueries() const override; + virtual bool allowAddition() const override; + virtual void addTableWindow( const OUString& _rQualifiedTableName, const OUString& _rAliasName ) override; + virtual void onWindowClosing() override; + +private: + OJoinTableView* getTableView() const; +}; + +Reference< XConnection > AddTableDialogContext::getConnection() const +{ + return m_rController.getConnection(); +} + +bool AddTableDialogContext::allowViews() const +{ + return m_rController.allowViews(); +} + +bool AddTableDialogContext::allowQueries() const +{ + return m_rController.allowQueries(); +} + +bool AddTableDialogContext::allowAddition() const +{ + return m_rController.getJoinView()->getTableView()->IsAddAllowed(); +} + +void AddTableDialogContext::addTableWindow( const OUString& _rQualifiedTableName, const OUString& _rAliasName ) +{ + getTableView()->AddTabWin( _rQualifiedTableName, _rAliasName, true ); +} + +void AddTableDialogContext::onWindowClosing() +{ + if (!m_rController.getView()) + return; + m_rController.InvalidateFeature( ID_BROWSER_ADDTABLE ); + m_rController.getView()->GrabFocus(); +} + +OJoinTableView* AddTableDialogContext::getTableView() const +{ + if ( m_rController.getJoinView() ) + return m_rController.getJoinView()->getTableView(); + return nullptr; +} + +// OJoinController + +OJoinController::OJoinController(const Reference< XComponentContext >& _rM) + : OJoinController_BASE(_rM) +{ +} + +OJoinController::~OJoinController() +{ +} + +OJoinDesignView* OJoinController::getJoinView() +{ + return static_cast< OJoinDesignView* >( getView() ); +} + +void OJoinController::disposing() +{ + if (m_xAddTableDialog) + { + m_xAddTableDialog->response(RET_CLOSE); + m_xAddTableDialog.reset(); + } + + OJoinController_BASE::disposing(); + + clearView(); + + m_vTableConnectionData.clear(); + m_vTableData.clear(); +} + +void OJoinController::reconnect( bool _bUI ) +{ + OJoinController_BASE::reconnect( _bUI ); + if ( isConnected() && m_xAddTableDialog ) + m_xAddTableDialog->Update(); +} + +void OJoinController::impl_onModifyChanged() +{ + OJoinController_BASE::impl_onModifyChanged(); + InvalidateFeature( SID_RELATION_ADD_RELATION ); +} + +void OJoinController::SaveTabWinPosSize(OTableWindow const * pTabWin, tools::Long nOffsetX, tools::Long nOffsetY) +{ + // the data for the window + const TTableWindowData::value_type& pData = pTabWin->GetData(); + OSL_ENSURE(pData != nullptr, "SaveTabWinPosSize : TabWin has no data !"); + + // set Position & Size of data anew (with current window parameters) + Point aPos = pTabWin->GetPosPixel(); + aPos.AdjustX(nOffsetX ); + aPos.AdjustY(nOffsetY ); + pData->SetPosition(aPos); + pData->SetSize(pTabWin->GetSizePixel()); + +} + +FeatureState OJoinController::GetState(sal_uInt16 _nId) const +{ + FeatureState aReturn; + // (disabled automatically) + aReturn.bEnabled = true; + + switch (_nId) + { + case ID_BROWSER_EDITDOC: + aReturn.bChecked = isEditable(); + break; + case ID_BROWSER_ADDTABLE: + aReturn.bEnabled = ( getView() != nullptr ) + && const_cast< OJoinController* >( this )->getJoinView()->getTableView()->IsAddAllowed(); + aReturn.bChecked = aReturn.bEnabled && m_xAddTableDialog; + if ( aReturn.bEnabled ) + aReturn.sTitle = OAddTableDlg::getDialogTitleForContext( impl_getDialogContext() ); + break; + + default: + aReturn = OJoinController_BASE::GetState(_nId); + } + return aReturn; +} + +AddTableDialogContext& OJoinController::impl_getDialogContext() const +{ + if (!m_pDialogContext) + { + OJoinController* pNonConstThis = const_cast< OJoinController* >( this ); + pNonConstThis->m_pDialogContext.reset( new AddTableDialogContext( *pNonConstThis ) ); + } + assert(m_pDialogContext && "always exists at this point"); + return *m_pDialogContext; +} + +void OJoinController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs) +{ + switch(_nId) + { + case ID_BROWSER_EDITDOC: + if(isEditable()) + { // the state should be changed to not editable + switch (saveModified()) + { + case RET_CANCEL: + // don't change anything here so return + return; + case RET_NO: + reset(); + setModified(false); // and we are not modified yet + break; + default: + break; + } + } + setEditable(!isEditable()); + getJoinView()->setReadOnly(!isEditable()); + InvalidateAll(); + return; + case ID_BROWSER_ADDTABLE: + if (m_xAddTableDialog) + { + m_xAddTableDialog->response(RET_CLOSE); + getView()->GrabFocus(); + } + else + { + runDialogAsync(); + } + break; + default: + OJoinController_BASE::Execute(_nId,aArgs); + } + InvalidateFeature(_nId); +} + +void OJoinController::runDialogAsync() +{ + assert(!m_xAddTableDialog); + m_xAddTableDialog = std::make_shared<OAddTableDlg>(getFrameWeld(), impl_getDialogContext()); + { + weld::WaitObject aWaitCursor(getFrameWeld()); + m_xAddTableDialog->Update(); + } + weld::DialogController::runAsync(m_xAddTableDialog, [this](sal_Int32 /*nResult*/){ + m_xAddTableDialog->OnClose(); + m_xAddTableDialog.reset(); + }); +} + +void OJoinController::SaveTabWinsPosSize( OJoinTableView::OTableWindowMap* pTabWinList, tools::Long nOffsetX, tools::Long nOffsetY ) +{ + // Deletion and recreation of the old implementation with the current model is not correct anymore: + // The TabWins have a pointer to their data, but they are managed by me. When I delete the old ones, the TabWins suddenly have a pointer to objects, which no longer exist. + // If the TabWins had a SetData, I could save that effort... but they don't, further I also would still have to set information anew, which actually didn't change. + // So I don't delete the TabWinDatas, but only update them. + OSL_ENSURE(m_vTableData.size() == pTabWinList->size(), + "OJoinController::SaveTabWinsPosSize : inconsistent state : should have as many TabWinDatas as TabWins !"); + + for (auto const& tabWin : *pTabWinList) + SaveTabWinPosSize(tabWin.second, nOffsetX, nOffsetY); +} + +void OJoinController::removeConnectionData(const TTableConnectionData::value_type& _pData) +{ + m_vTableConnectionData.erase( std::remove(m_vTableConnectionData.begin(),m_vTableConnectionData.end(),_pData),m_vTableConnectionData.end()); +} + +void OJoinController::describeSupportedFeatures() +{ + OJoinController_BASE::describeSupportedFeatures(); + implDescribeSupportedFeature( ".uno:Redo", ID_BROWSER_REDO, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVEDOC, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:Undo", ID_BROWSER_UNDO, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:AddTable", ID_BROWSER_ADDTABLE,CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:EditDoc", ID_BROWSER_EDITDOC, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:GetUndoStrings", SID_GETUNDOSTRINGS ); + implDescribeSupportedFeature( ".uno:GetRedoStrings", SID_GETREDOSTRINGS ); +} + +sal_Bool SAL_CALL OJoinController::suspend(sal_Bool _bSuspend) +{ + if ( getBroadcastHelper().bInDispose || getBroadcastHelper().bDisposed ) + return true; + + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + if ( getView() && getView()->IsInModalMode() ) + return false; + bool bCheck = true; + if ( _bSuspend ) + { + bCheck = saveModified() != RET_CANCEL; + if ( bCheck ) + OSingleDocumentController::suspend(_bSuspend); + } + return bCheck; +} + +void OJoinController::loadTableWindows( const ::comphelper::NamedValueCollection& i_rViewSettings ) +{ + m_vTableData.clear(); + + m_aMinimumTableViewSize = Point(); + + Sequence< PropertyValue > aWindowData; + aWindowData = i_rViewSettings.getOrDefault( "Tables", aWindowData ); + + const PropertyValue* pTablesIter = aWindowData.getConstArray(); + const PropertyValue* pTablesEnd = pTablesIter + aWindowData.getLength(); + for ( ; pTablesIter != pTablesEnd; ++pTablesIter ) + { + ::comphelper::NamedValueCollection aSingleTableData( pTablesIter->Value ); + loadTableWindow( aSingleTableData ); + } + if ( m_aMinimumTableViewSize != Point() ) + { + getJoinView()->getScrollHelper()->resetRange( m_aMinimumTableViewSize ); + } +} + +void OJoinController::loadTableWindow( const ::comphelper::NamedValueCollection& i_rTableWindowSettings ) +{ + sal_Int32 nX = -1, nY = -1, nHeight = -1, nWidth = -1; + + OUString sComposedName,sTableName,sWindowName; + bool bShowAll = false; + + sComposedName = i_rTableWindowSettings.getOrDefault( "ComposedName", sComposedName ); + sTableName = i_rTableWindowSettings.getOrDefault( "TableName", sTableName ); + sWindowName = i_rTableWindowSettings.getOrDefault( "WindowName", sWindowName ); + nY = i_rTableWindowSettings.getOrDefault( "WindowTop", nY ); + nX = i_rTableWindowSettings.getOrDefault( "WindowLeft", nX ); + nWidth = i_rTableWindowSettings.getOrDefault( "WindowWidth", nWidth ); + nHeight = i_rTableWindowSettings.getOrDefault( "WindowHeight", nHeight ); + bShowAll = i_rTableWindowSettings.getOrDefault( "ShowAll", bShowAll ); + + TTableWindowData::value_type pData = createTableWindowData(sComposedName,sTableName,sWindowName); + if ( pData ) + { + pData->SetPosition(Point(nX,nY)); + pData->SetSize( Size( nWidth, nHeight ) ); + pData->ShowAll(bShowAll); + m_vTableData.push_back(pData); + if ( m_aMinimumTableViewSize.X() < (nX+nWidth) ) + m_aMinimumTableViewSize.setX( nX+nWidth ); + if ( m_aMinimumTableViewSize.Y() < (nY+nHeight) ) + m_aMinimumTableViewSize.setY( nY+nHeight ); + } +} + +void OJoinController::saveTableWindows( ::comphelper::NamedValueCollection& o_rViewSettings ) const +{ + if ( m_vTableData.empty() ) + return; + + ::comphelper::NamedValueCollection aAllTablesData; + + sal_Int32 i = 1; + for (auto const& elem : m_vTableData) + { + ::comphelper::NamedValueCollection aWindowData; + aWindowData.put( "ComposedName", elem->GetComposedName() ); + aWindowData.put( "TableName", elem->GetTableName() ); + aWindowData.put( "WindowName", elem->GetWinName() ); + aWindowData.put( "WindowTop", static_cast<sal_Int32>(elem->GetPosition().Y()) ); + aWindowData.put( "WindowLeft", static_cast<sal_Int32>(elem->GetPosition().X()) ); + aWindowData.put( "WindowWidth", static_cast<sal_Int32>(elem->GetSize().Width()) ); + aWindowData.put( "WindowHeight", static_cast<sal_Int32>(elem->GetSize().Height()) ); + aWindowData.put( "ShowAll", elem->IsShowAll() ); + + const OUString sTableName( "Table" + OUString::number( i++ ) ); + aAllTablesData.put( sTableName, aWindowData.getPropertyValues() ); + } + + o_rViewSettings.put( "Tables", aAllTablesData.getPropertyValues() ); +} + +TTableWindowData::value_type OJoinController::createTableWindowData(const OUString& _sComposedName,const OUString& _sTableName,const OUString& _sWindowName) +{ + OJoinDesignView* pView = getJoinView(); + if( pView ) + return pView->getTableView()->createTableWindowData(_sComposedName,_sTableName,_sWindowName); + OSL_FAIL("We should never ever reach this point!"); + + return TTableWindowData::value_type(); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/JoinDesignView.cxx b/dbaccess/source/ui/querydesign/JoinDesignView.cxx new file mode 100644 index 000000000..c0d3ea81c --- /dev/null +++ b/dbaccess/source/ui/querydesign/JoinDesignView.cxx @@ -0,0 +1,100 @@ +/* -*- 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 <JoinDesignView.hxx> +#include <JoinTableView.hxx> +#include <JoinController.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; + +namespace dbaui +{ + +// OJoinDesignView +OJoinDesignView::OJoinDesignView(vcl::Window* _pParent, OJoinController& _rController,const Reference< XComponentContext >& _rxContext) + :ODataView( _pParent, _rController, _rxContext ) + ,m_pTableView(nullptr) + ,m_rController( _rController ) +{ + m_pScrollWindow = VclPtr<OScrollWindowHelper>::Create(this); +} + +OJoinDesignView::~OJoinDesignView() +{ + disposeOnce(); +} + +void OJoinDesignView::dispose() +{ + m_pTableView.disposeAndClear(); + m_pScrollWindow.disposeAndClear(); + ODataView::dispose(); +} + +void OJoinDesignView::Construct() +{ + m_pScrollWindow->setTableView(m_pTableView); + m_pScrollWindow->Show(); + m_pTableView->Show(); + + SetBackground( Wallpaper( Application::GetSettings().GetStyleSettings().GetFaceColor()) ); + + ODataView::Construct(); +} + +void OJoinDesignView::initialize() +{ +} + +void OJoinDesignView::resizeDocumentView(tools::Rectangle& _rPlayground) +{ + m_pScrollWindow->SetPosSizePixel( _rPlayground.TopLeft(), _rPlayground.GetSize() ); + + // just for completeness: there is no space left, we occupied it all ... + _rPlayground.SetPos( _rPlayground.BottomRight() ); + _rPlayground.SetSize( Size( 0, 0 ) ); +} + +void OJoinDesignView::setReadOnly(bool /*_bReadOnly*/) +{ +} + +void OJoinDesignView::SaveTabWinUIConfig(OTableWindow const * pWin) +{ + OJoinController::SaveTabWinPosSize(pWin, m_pScrollWindow->GetHScrollBar().GetThumbPos(), m_pScrollWindow->GetVScrollBar().GetThumbPos()); +} + +void OJoinDesignView::KeyInput( const KeyEvent& rEvt ) +{ + if ( m_pTableView && m_pTableView->IsVisible() ) + m_pTableView->KeyInput( rEvt ); + else + ODataView::KeyInput(rEvt); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/JoinExchange.cxx b/dbaccess/source/ui/querydesign/JoinExchange.cxx new file mode 100644 index 000000000..0dc88e2cc --- /dev/null +++ b/dbaccess/source/ui/querydesign/JoinExchange.cxx @@ -0,0 +1,114 @@ +/* -*- 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 <JoinExchange.hxx> +#include <sot/formats.hxx> +#include <comphelper/servicehelper.hxx> + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::datatransfer; + + void OJoinExchObj::setDescriptors(const OJoinExchangeData& jxdSource,bool _bFirstEntry) + { + m_bFirstEntry = _bFirstEntry; + m_jxdSourceDescription = jxdSource; + } + + OJoinExchObj::OJoinExchObj() + : m_bFirstEntry(false) + { + } + + OJoinExchObj::~OJoinExchObj() + { + } + + bool OJoinExchObj::isFormatAvailable( const DataFlavorExVector& _rFormats ,SotClipboardFormatId _nSlotID) + { + for (auto const& format : _rFormats) + { + if ( _nSlotID == format.mnSotId ) + return true; + } + return false; + } + + OJoinExchangeData OJoinExchObj::GetSourceDescription(const Reference< XTransferable >& _rxObject) + { + OJoinExchangeData aReturn; + auto pImplementation = comphelper::getFromUnoTunnel<OJoinExchObj>(_rxObject); + if (pImplementation) + aReturn = pImplementation->m_jxdSourceDescription; + return aReturn; + } + + const Sequence< sal_Int8 > & OJoinExchObj::getUnoTunnelId() + { + static const comphelper::UnoIdInit implId; + return implId.getSeq(); + } + + sal_Int64 SAL_CALL OJoinExchObj::getSomething( const Sequence< sal_Int8 >& _rIdentifier ) + { + return comphelper::getSomethingImpl(_rIdentifier, this); + } + + void OJoinExchObj::AddSupportedFormats() + { + AddFormat( SotClipboardFormatId::SBA_JOIN ); + if ( m_bFirstEntry ) + AddFormat( SotClipboardFormatId::SBA_TABID ); + } + + bool OJoinExchObj::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ ) + { + SotClipboardFormatId nFormat = SotExchange::GetFormat(rFlavor); + if ( SotClipboardFormatId::SBA_JOIN == nFormat ) + // this is a HACK + // we don't really copy our data, the instances using us have to call GetSourceDescription... + // if, one day, we have a _lot_ of time, this hack should be removed... + return true; + + return false; + } + + Any SAL_CALL OJoinExchObj::queryInterface( const Type& _rType ) + { + Any aReturn = TransferDataContainer::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = OJoinExchObj_Base::queryInterface(_rType); + return aReturn; + } + + void SAL_CALL OJoinExchObj::acquire( ) noexcept + { + TransferDataContainer::acquire( ); + } + + void SAL_CALL OJoinExchObj::release( ) noexcept + { + TransferDataContainer::release( ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/JoinTableView.cxx b/dbaccess/source/ui/querydesign/JoinTableView.cxx new file mode 100644 index 000000000..055628133 --- /dev/null +++ b/dbaccess/source/ui/querydesign/JoinTableView.cxx @@ -0,0 +1,1568 @@ +/* -*- 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 <JoinTableView.hxx> +#include <osl/diagnose.h> +#include <JoinController.hxx> +#include <JoinDesignView.hxx> +#include <TableWindow.hxx> +#include <TableWindowListBox.hxx> +#include <TableConnection.hxx> +#include <TableConnectionData.hxx> +#include <ConnectionLine.hxx> +#include <ConnectionLineData.hxx> +#include <browserids.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include "QueryMoveTabWinUndoAct.hxx" +#include "QuerySizeTabWinUndoAct.hxx" +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/ptrstyle.hxx> +#include <vcl/weldutils.hxx> +#include <TableWindowData.hxx> +#include <JAccess.hxx> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <connectivity/dbtools.hxx> +#include <tools/diagnose_ex.h> +#include <algorithm> +#include <functional> + +using namespace dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +#define LINE_SIZE 50 +// Constants for the window layout +#define TABWIN_SPACING_X 17 +#define TABWIN_SPACING_Y 17 + +#define TABWIN_WIDTH_STD 120 +#define TABWIN_HEIGHT_STD 120 + +OScrollWindowHelper::OScrollWindowHelper( vcl::Window* pParent) : Window( pParent) + ,m_aHScrollBar( VclPtr<ScrollBar>::Create(this, WB_HSCROLL|WB_REPEAT|WB_DRAG) ) + ,m_aVScrollBar( VclPtr<ScrollBar>::Create(this, WB_VSCROLL|WB_REPEAT|WB_DRAG) ) + ,m_pCornerWindow(VclPtr<ScrollBarBox>::Create(this, WB_3DLOOK)) + ,m_pTableView(nullptr) +{ + + // ScrollBars + + GetHScrollBar().SetRange( Range(0, 1000) ); + GetVScrollBar().SetRange( Range(0, 1000) ); + + GetHScrollBar().SetLineSize( LINE_SIZE ); + GetVScrollBar().SetLineSize( LINE_SIZE ); + + GetHScrollBar().Show(); + GetVScrollBar().Show(); + m_pCornerWindow->Show(); + + // normally we should be SCROLL_PANE + SetAccessibleRole(AccessibleRole::SCROLL_PANE); +} + +OScrollWindowHelper::~OScrollWindowHelper() +{ + disposeOnce(); +} + +void OScrollWindowHelper::dispose() +{ + m_aHScrollBar.disposeAndClear(); + m_aVScrollBar.disposeAndClear(); + m_pCornerWindow.disposeAndClear(); + m_pTableView.clear(); + vcl::Window::dispose(); +} + +void OScrollWindowHelper::setTableView(OJoinTableView* _pTableView) +{ + m_pTableView = _pTableView; + // ScrollBars + GetHScrollBar().SetScrollHdl( LINK(m_pTableView, OJoinTableView, ScrollHdl) ); + GetVScrollBar().SetScrollHdl( LINK(m_pTableView, OJoinTableView, ScrollHdl) ); +} + +void OScrollWindowHelper::resetRange(const Point& _aSize) +{ + Point aPos = PixelToLogic(_aSize); + GetHScrollBar().SetRange( Range(0, aPos.X() + TABWIN_SPACING_X) ); + GetVScrollBar().SetRange( Range(0, aPos.Y() + TABWIN_SPACING_Y) ); +} + +void OScrollWindowHelper::Resize() +{ + Window::Resize(); + + Size aTotalOutputSize = GetOutputSizePixel(); + tools::Long nHScrollHeight = GetHScrollBar().GetSizePixel().Height(); + tools::Long nVScrollWidth = GetVScrollBar().GetSizePixel().Width(); + + GetHScrollBar().SetPosSizePixel( + Point( 0, aTotalOutputSize.Height()-nHScrollHeight ), + Size( aTotalOutputSize.Width()-nVScrollWidth, nHScrollHeight ) + ); + + GetVScrollBar().SetPosSizePixel( + Point( aTotalOutputSize.Width()-nVScrollWidth, 0 ), + Size( nVScrollWidth, aTotalOutputSize.Height()-nHScrollHeight ) + ); + + m_pCornerWindow->SetPosSizePixel( + Point( aTotalOutputSize.Width() - nVScrollWidth, aTotalOutputSize.Height() - nHScrollHeight), + Size( nVScrollWidth, nHScrollHeight ) + ); + + GetHScrollBar().SetPageSize( aTotalOutputSize.Width() ); + GetHScrollBar().SetVisibleSize( aTotalOutputSize.Width() ); + + GetVScrollBar().SetPageSize( aTotalOutputSize.Height() ); + GetVScrollBar().SetVisibleSize( aTotalOutputSize.Height() ); + + // adjust the ranges of the scrollbars if necessary + tools::Long lRange = GetHScrollBar().GetRange().Max() - GetHScrollBar().GetRange().Min(); + if (m_pTableView->GetScrollOffset().X() + aTotalOutputSize.Width() > lRange) + GetHScrollBar().SetRangeMax(m_pTableView->GetScrollOffset().X() + aTotalOutputSize.Width() + GetHScrollBar().GetRange().Min()); + + lRange = GetVScrollBar().GetRange().Max() - GetVScrollBar().GetRange().Min(); + if (m_pTableView->GetScrollOffset().Y() + aTotalOutputSize.Height() > lRange) + GetVScrollBar().SetRangeMax(m_pTableView->GetScrollOffset().Y() + aTotalOutputSize.Height() + GetVScrollBar().GetRange().Min()); + + m_pTableView->SetPosSizePixel(Point( 0, 0 ),Size( aTotalOutputSize.Width()-nVScrollWidth, aTotalOutputSize.Height()-nHScrollHeight )); +} + + +OJoinTableView::OJoinTableView( vcl::Window* pParent, OJoinDesignView* pView ) + :Window( pParent,WB_BORDER ) + ,DropTargetHelper(this) + ,m_aDragScrollIdle("dbaccess OJoinTableView m_aDragScrollIdle") + ,m_aDragOffset( Point(0,0) ) + ,m_aScrollOffset( Point(0,0) ) + ,m_pDragWin( nullptr ) + ,m_pSizingWin( nullptr ) + ,m_pSelectedConn( nullptr ) + ,m_pLastFocusTabWin(nullptr) + ,m_pView( pView ) +{ + SetSizePixel( Size(1000, 1000) ); + + InitColors(); + + m_aDragScrollIdle.SetInvokeHandler(LINK(this, OJoinTableView, OnDragScrollTimer)); +} + +OJoinTableView::~OJoinTableView() +{ + disposeOnce(); +} + +void OJoinTableView::dispose() +{ + if( m_pAccessible ) + { + m_pAccessible->clearTableView(); + m_pAccessible = nullptr; + } + // delete lists + clearLayoutInformation(); + m_pDragWin.clear(); + m_pSizingWin.clear(); + m_pSelectedConn.clear(); + m_pLastFocusTabWin.clear(); + m_pView.clear(); + m_vTableConnection.clear(); + vcl::Window::dispose(); +} + +IMPL_LINK( OJoinTableView, ScrollHdl, ScrollBar*, pScrollBar, void ) +{ + // move all windows + ScrollPane( pScrollBar->GetDelta(), (pScrollBar == &GetHScrollBar()), false ); +} + +void OJoinTableView::Resize() +{ + Window::Resize(); + m_aOutputSize = GetSizePixel(); + + // tab win positions may not be up-to-date + if (m_aTableMap.empty()) + // no tab wins ... + return; + + // we have at least one table so resize it + m_aScrollOffset.setX( GetHScrollBar().GetThumbPos() ); + m_aScrollOffset.setY( GetVScrollBar().GetThumbPos() ); + + VclPtr<OTableWindow> pCheck = m_aTableMap.begin()->second; + Point aRealPos = pCheck->GetPosPixel(); + Point aAssumedPos = pCheck->GetData()->GetPosition() - GetScrollOffset(); + + if (aRealPos == aAssumedPos) + // all ok + return; + + for (auto const& elem : m_aTableMap) + { + OTableWindow* pCurrent = elem.second; + Point aPos(pCurrent->GetData()->GetPosition() - GetScrollOffset()); + pCurrent->SetPosPixel(aPos); + } +} + +sal_uLong OJoinTableView::GetTabWinCount() const +{ + return m_aTableMap.size(); +} + +bool OJoinTableView::RemoveConnection(VclPtr<OTableConnection>& rConn, bool _bDelete) +{ + VclPtr<OTableConnection> xConn(rConn); + + DeselectConn(xConn); + + // to force a redraw + xConn->InvalidateConnection(); + + m_pView->getController().removeConnectionData(xConn->GetData()); + + m_vTableConnection.erase(std::find(m_vTableConnection.begin(), m_vTableConnection.end(), xConn)); + + modified(); + if ( m_pAccessible ) + m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD, + Any(xConn->GetAccessible()), + Any()); + if (_bDelete) + xConn->disposeOnce(); + + return true; +} + +OTableWindow* OJoinTableView::GetTabWindow( const OUString& rName ) +{ + OTableWindowMap::const_iterator aIter = m_aTableMap.find(rName); + + return aIter == m_aTableMap.end() ? nullptr : aIter->second; +} + +TTableWindowData::value_type OJoinTableView::createTableWindowData(const OUString& _rComposedName + ,const OUString& _sTableName + ,const OUString& _rWinName) +{ + TTableWindowData::value_type pData( CreateImpl(_rComposedName, _sTableName,_rWinName) ); + OJoinDesignView* pParent = getDesignView(); + try + { + if ( !pData->init(pParent->getController().getConnection(),allowQueries()) ) + { + if ( pData->isValid() ) + onNoColumns_throw(); + else + pData.reset(); + } + } + catch ( const SQLException& ) + { + ::dbtools::showError( ::dbtools::SQLExceptionInfo( ::cppu::getCaughtException() ), + VCLUnoHelper::GetInterface(pParent), pParent->getController().getORB() ); + } + catch( const WrappedTargetException& e ) + { + SQLException aSql; + if ( e.TargetException >>= aSql ) + ::dbtools::showError( ::dbtools::SQLExceptionInfo( aSql ), VCLUnoHelper::GetInterface(pParent), pParent->getController().getORB() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return pData; +} + +std::shared_ptr<OTableWindowData> OJoinTableView::CreateImpl(const OUString& _rComposedName + ,const OUString& _sTableName + ,const OUString& _rWinName) +{ + return std::make_shared<OTableWindowData>( nullptr,_rComposedName,_sTableName, _rWinName ); +} + +void OJoinTableView::AddTabWin(const OUString& _rComposedName, const OUString& rWinName, bool /*bNewTable*/) +{ + OSL_ENSURE(!_rComposedName.isEmpty(),"There must be a table name supplied!"); + + TTableWindowData::value_type pNewTabWinData(createTableWindowData( _rComposedName, rWinName,rWinName )); + + // insert new window in window list + VclPtr<OTableWindow> pNewTabWin = createWindow( pNewTabWinData ); + if ( pNewTabWin->Init() ) + { + m_pView->getController().getTableWindowData().push_back( pNewTabWinData); + // when we already have a table with this name insert the full qualified one instead + if(m_aTableMap.find(rWinName) != m_aTableMap.end()) + m_aTableMap[_rComposedName] = pNewTabWin; + else + m_aTableMap[rWinName] = pNewTabWin; + + SetDefaultTabWinPosSize( pNewTabWin ); + pNewTabWin->Show(); + + modified(); + if ( m_pAccessible ) + m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD, + Any(), + Any(pNewTabWin->GetAccessible())); + } + else + { + pNewTabWin->clearListBox(); + pNewTabWin.disposeAndClear(); + } +} + +void OJoinTableView::RemoveTabWin( OTableWindow* pTabWin ) +{ + // first delete all connections of this window to others + bool bRemove = true; + TTableWindowData::value_type pData = pTabWin->GetData(); + sal_Int32 nCount = m_vTableConnection.size(); + auto aIter = m_vTableConnection.rbegin(); + while(aIter != m_vTableConnection.rend() && bRemove) + { + VclPtr<OTableConnection>& rTabConn = *aIter; + if ( + (pData == rTabConn->GetData()->getReferencingTable()) || + (pData == rTabConn->GetData()->getReferencedTable()) + ) + { + bRemove = RemoveConnection(rTabConn, true); + aIter = m_vTableConnection.rbegin(); + } + else + ++aIter; + } + + // then delete the window itself + if ( bRemove ) + { + if ( m_pAccessible ) + m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD, + Any(pTabWin->GetAccessible()),Any() + ); + + pTabWin->Hide(); + OJoinController& rController = m_pView->getController(); + TTableWindowData::iterator aFind = std::find(rController.getTableWindowData().begin(), rController.getTableWindowData().end(), pData); + if(aFind != rController.getTableWindowData().end()) + { + rController.getTableWindowData().erase(aFind); + rController.setModified(true); + } + + if ( !m_aTableMap.erase( pTabWin->GetWinName() ) ) + m_aTableMap.erase( pTabWin->GetComposedName() ); + + if (pTabWin == m_pLastFocusTabWin) + m_pLastFocusTabWin = nullptr; + + pTabWin->clearListBox(); + pTabWin->disposeOnce(); + } + + if ( static_cast<sal_Int32>(m_vTableConnection.size()) < (nCount-1) ) // if some connections could be removed + modified(); +} + +namespace +{ + bool isScrollAllowed( OJoinTableView* _pView,tools::Long nDelta, bool bHoriz) + { + // adjust ScrollBar-Positions + ScrollBar& rBar = bHoriz ? _pView->GetHScrollBar() : _pView->GetVScrollBar() ; + + tools::Long nOldThumbPos = rBar.GetThumbPos(); + tools::Long nNewThumbPos = nOldThumbPos + nDelta; + if( nNewThumbPos < 0 ) + nNewThumbPos = 0; + else if( nNewThumbPos > rBar.GetRangeMax() ) + nNewThumbPos = rBar.GetRangeMax(); + + if ( bHoriz ) + { + if( nNewThumbPos == _pView->GetScrollOffset().X() ) + return false; + } + else if ( nNewThumbPos == _pView->GetScrollOffset().Y() ) + return false; + + return true; + } + bool getMovementImpl(OJoinTableView* _pView,const Point& _rPoint,const Size& _rSize,tools::Long& _nScrollX,tools::Long& _nScrollY) + { + _nScrollY = _nScrollX = 0; + // data about the tab win + Point aUpperLeft = _rPoint; + // normalize with respect to visibility + aUpperLeft -= _pView->GetScrollOffset(); + Point aLowerRight(aUpperLeft.X() + _rSize.Width(), aUpperLeft.Y() + _rSize.Height()); + + // data about ourself + Size aSize = _pView->getRealOutputSize(); //GetOutputSizePixel(); + + bool bVisible = true; + bool bFitsHor = (aUpperLeft.X() >= 0) && (aLowerRight.X() <= aSize.Width()); + bool bFitsVert= (aUpperLeft.Y() >= 0) && (aLowerRight.Y() <= aSize.Height()); + if (!bFitsHor || !bFitsVert) + { + if (!bFitsHor) + { + // ensure the visibility of the right border + if ( aLowerRight.X() > aSize.Width() ) + _nScrollX = aLowerRight.X() - aSize.Width() + TABWIN_SPACING_X; + + // ensure the visibility of the left border (higher priority) + if ( aUpperLeft.X() < 0 ) + _nScrollX = aUpperLeft.X() - TABWIN_SPACING_X; + } + + if (!bFitsVert) + { + // lower border + if ( aLowerRight.Y() > aSize.Height() ) + _nScrollY = aLowerRight.Y() - aSize.Height() + TABWIN_SPACING_Y; + // upper border + if ( aUpperLeft.Y() < 0 ) + _nScrollY = aUpperLeft.Y() - TABWIN_SPACING_Y; + } + + if ( _nScrollX ) // aSize.Width() > _rSize.Width() && + bVisible = isScrollAllowed(_pView,_nScrollX, true); + + if ( _nScrollY ) // aSize.Height() > _rSize.Height() && + bVisible = bVisible && isScrollAllowed(_pView,_nScrollY, false); + + if ( bVisible ) + { + sal_Int32 nHRangeMax = _pView->GetHScrollBar().GetRangeMax(); + sal_Int32 nVRangeMax = _pView->GetVScrollBar().GetRangeMax(); + + if ( aSize.Width() + _pView->GetHScrollBar().GetThumbPos() + _nScrollX > nHRangeMax ) + bVisible = false; + if ( bVisible && aSize.Height() + _pView->GetVScrollBar().GetThumbPos() + _nScrollY > nVRangeMax ) + bVisible = false; + } + } + + return bVisible; + } +} // end of ano namespace + +bool OJoinTableView::isMovementAllowed(const Point& _rPoint,const Size& _rSize) +{ + tools::Long nX,nY; + return getMovementImpl(this,_rPoint,_rSize,nX,nY); +} + +void OJoinTableView::EnsureVisible(const OTableWindow* _pWin) +{ + // data about the tab win + TTableWindowData::value_type pData = _pWin->GetData(); + EnsureVisible( pData->GetPosition() , pData->GetSize()); + Invalidate(InvalidateFlags::NoChildren); +} + +void OJoinTableView::EnsureVisible(const Point& _rPoint,const Size& _rSize) +{ + tools::Long nScrollX,nScrollY; + + if ( getMovementImpl(this,_rPoint,_rSize,nScrollX,nScrollY) ) + { + bool bVisible = true; + if (nScrollX) + bVisible = ScrollPane(nScrollX, true, true); + + if (nScrollY && bVisible) + ScrollPane(nScrollY, false, true); + } +} + +void OJoinTableView::SetDefaultTabWinPosSize( OTableWindow* pTabWin ) +{ + // determine position: + // the window is divided into lines with height TABWIN_SPACING_Y+TABWIN_HEIGHT_STD. + // Then for each line is checked, if there is space for another window. + // If there is no space, the next line is checked. + Size aOutSize = GetSizePixel(); + Point aNewPos( 0,0 ); + sal_uInt16 nRow = 0; + bool bEnd = false; + while( !bEnd ) + { + // Set new position to start of line + aNewPos.setX( TABWIN_SPACING_X ); + aNewPos.setY( (nRow+1) * TABWIN_SPACING_Y ); + + // determine rectangle for the corresponding line + tools::Rectangle aRowRect( Point(0,0), aOutSize ); + aRowRect.SetTop( nRow * ( TABWIN_SPACING_Y + TABWIN_HEIGHT_STD ) ); + aRowRect.SetBottom( (nRow+1) * ( TABWIN_SPACING_Y + TABWIN_HEIGHT_STD ) ); + + // check occupied areas of this line + for (auto const& elem : m_aTableMap) + { + OTableWindow* pOtherTabWin = elem.second; + tools::Rectangle aOtherTabWinRect( pOtherTabWin->GetPosPixel(), pOtherTabWin->GetSizePixel() ); + + if( + ( (aOtherTabWinRect.Top()>aRowRect.Top()) && (aOtherTabWinRect.Top()<aRowRect.Bottom()) ) || + ( (aOtherTabWinRect.Bottom()>aRowRect.Top()) && (aOtherTabWinRect.Bottom()<aRowRect.Bottom()) ) + ) + { + // TabWin is in the line + if( aOtherTabWinRect.Right()>aNewPos.X() ) + aNewPos.setX( aOtherTabWinRect.Right() + TABWIN_SPACING_X ); + } + } + + // Is there space left in this line? + if( (aNewPos.X()+TABWIN_WIDTH_STD)<aRowRect.Right() ) + { + aNewPos.setY( aRowRect.Top() + TABWIN_SPACING_Y ); + bEnd = true; + } + else + { + if( (aRowRect.Bottom()+aRowRect.GetHeight()) > aOutSize.Height() ) + { + // insert it in the first row + sal_Int32 nCount = m_aTableMap.size() % (nRow+1); + ++nCount; + aNewPos.setY( nCount * TABWIN_SPACING_Y + (nCount-1)*CalcZoom(TABWIN_HEIGHT_STD) ); + bEnd = true; + } + else + nRow++; + + } + } + + // determine size + Size aNewSize( CalcZoom(TABWIN_WIDTH_STD), CalcZoom(TABWIN_HEIGHT_STD) ); + + // check if the new position in inside the scrollbars ranges + Point aBottom(aNewPos); + aBottom.AdjustX(aNewSize.Width() ); + aBottom.AdjustY(aNewSize.Height() ); + + if(!GetHScrollBar().GetRange().Contains(aBottom.X())) + GetHScrollBar().SetRange( Range(0, aBottom.X()) ); + if(!GetVScrollBar().GetRange().Contains(aBottom.Y())) + GetVScrollBar().SetRange( Range(0, aBottom.Y()) ); + + pTabWin->SetPosSizePixel( aNewPos, aNewSize ); +} + +void OJoinTableView::DataChanged(const DataChangedEvent& rDCEvt) +{ + if (rDCEvt.GetType() == DataChangedEventType::SETTINGS) + { + // consider the worst case: the colors changed, so adjust me + InitColors(); + Invalidate(InvalidateFlags::NoChildren); + // due to the Invalidate, the connections are redrawn, so that they are also pictured in the new colors + } +} + +void OJoinTableView::InitColors() +{ + // the colors for the illustration should be the system colors + StyleSettings aSystemStyle = Application::GetSettings().GetStyleSettings(); + SetBackground(Wallpaper(aSystemStyle.GetDialogColor())); +} + +void OJoinTableView::BeginChildMove( OTableWindow* pTabWin, const Point& rMousePos ) +{ + + if (m_pView->getController().isReadOnly()) + return; + + m_pDragWin = pTabWin; + SetPointer(PointerStyle::Move); + Point aMousePos = ScreenToOutputPixel( rMousePos ); + m_aDragOffset = aMousePos - pTabWin->GetPosPixel(); + m_pDragWin->SetZOrder(nullptr, ZOrderFlags::First); + StartTracking(); +} + +void OJoinTableView::NotifyTitleClicked( OTableWindow* pTabWin, const Point& rMousePos ) +{ + DeselectConn(GetSelectedConn()); + BeginChildMove(pTabWin, rMousePos); +} + +void OJoinTableView::BeginChildSizing( OTableWindow* pTabWin, PointerStyle nPointer ) +{ + + if (m_pView->getController().isReadOnly()) + return; + + SetPointer( nPointer ); + m_pSizingWin = pTabWin; + StartTracking(); +} + +bool OJoinTableView::ScrollPane( tools::Long nDelta, bool bHoriz, bool bPaintScrollBars ) +{ + bool bRet = true; + + // adjust ScrollBar-Positions + if( bPaintScrollBars ) + { + if( bHoriz ) + { + tools::Long nOldThumbPos = GetHScrollBar().GetThumbPos(); + tools::Long nNewThumbPos = nOldThumbPos + nDelta; + if( nNewThumbPos < 0 ) + { + nNewThumbPos = 0; + bRet = false; + } + if( nNewThumbPos > GetHScrollBar().GetRange().Max() ) + { + nNewThumbPos = GetHScrollBar().GetRange().Max(); + bRet = false; + } + GetHScrollBar().SetThumbPos( nNewThumbPos ); + nDelta = GetHScrollBar().GetThumbPos() - nOldThumbPos; + } + else + { + tools::Long nOldThumbPos = GetVScrollBar().GetThumbPos(); + tools::Long nNewThumbPos = nOldThumbPos+nDelta; + if( nNewThumbPos < 0 ) + { + nNewThumbPos = 0; + bRet = false; + } + if( nNewThumbPos > GetVScrollBar().GetRange().Max() ) + { + nNewThumbPos = GetVScrollBar().GetRange().Max(); + bRet = false; + } + GetVScrollBar().SetThumbPos( nNewThumbPos ); + nDelta = GetVScrollBar().GetThumbPos() - nOldThumbPos; + } + } + + // If ScrollOffset hitting borders, no redrawing. + if( (GetHScrollBar().GetThumbPos()==m_aScrollOffset.X()) && + (GetVScrollBar().GetThumbPos()==m_aScrollOffset.Y()) ) + return false; + + // set ScrollOffset anew + if (bHoriz) + m_aScrollOffset.setX( GetHScrollBar().GetThumbPos() ); + else + m_aScrollOffset.setY( GetVScrollBar().GetThumbPos() ); + + // move all windows + OTableWindow* pTabWin; + Point aPos; + + for (auto const& elem : m_aTableMap) + { + pTabWin = elem.second; + aPos = pTabWin->GetPosPixel(); + + if( bHoriz ) + aPos.AdjustX( -nDelta ); + else aPos.AdjustY( -nDelta ); + + pTabWin->SetPosPixel( aPos ); + } + + Invalidate(); // InvalidateFlags::NoChildren + + return bRet; +} + +void OJoinTableView::Tracking( const TrackingEvent& rTEvt ) +{ + HideTracking(); + + if (rTEvt.IsTrackingEnded()) + { + if( m_pDragWin ) + { + if (m_aDragScrollIdle.IsActive()) + m_aDragScrollIdle.Stop(); + + // adjust position of child after moving + // windows are not allowed to leave display range + Point aDragWinPos = rTEvt.GetMouseEvent().GetPosPixel() - m_aDragOffset; + Size aDragWinSize = m_pDragWin->GetSizePixel(); + if( aDragWinPos.X() < 0 ) + aDragWinPos.setX( 0 ); + if( aDragWinPos.Y() < 0 ) + aDragWinPos.setY( 0 ); + if( (aDragWinPos.X() + aDragWinSize.Width()) > m_aOutputSize.Width() ) + aDragWinPos.setX( m_aOutputSize.Width() - aDragWinSize.Width() - 1 ); + if( (aDragWinPos.Y() + aDragWinSize.Height()) > m_aOutputSize.Height() ) + aDragWinPos.setY( m_aOutputSize.Height() - aDragWinSize.Height() - 1 ); + if( aDragWinPos.X() < 0 ) + aDragWinPos.setX( 0 ); + if( aDragWinPos.Y() < 0 ) + aDragWinPos.setY( 0 ); + // TODO : don't position window anew, if it is leaving range, but just expand the range + + // position window + EndTracking(); + m_pDragWin->SetZOrder(nullptr, ZOrderFlags::First); + // check, if I really moved + // (this prevents setting the modified-Flag, when there actually was no change0 + TTableWindowData::value_type pData = m_pDragWin->GetData(); + if ( ! (pData && pData->HasPosition() && (pData->GetPosition() == aDragWinPos))) + { + // old logic coordinates + Point ptOldPos = m_pDragWin->GetPosPixel() + Point(GetHScrollBar().GetThumbPos(), GetVScrollBar().GetThumbPos()); + // new positioning + m_pDragWin->SetPosPixel(aDragWinPos); + TabWinMoved(m_pDragWin, ptOldPos); + + m_pDragWin->GrabFocus(); + } + m_pDragWin = nullptr; + SetPointer(PointerStyle::Arrow); + } + // else we handle the resizing + else if( m_pSizingWin ) + { + SetPointer( PointerStyle::Arrow ); + EndTracking(); + + // old physical coordinates + + Size szOld = m_pSizingWin->GetSizePixel(); + Point ptOld = m_pSizingWin->GetPosPixel(); + Size aNewSize(CalcZoom(m_aSizingRect.GetSize().Width()),CalcZoom(m_aSizingRect.GetSize().Height())); + m_pSizingWin->SetPosSizePixel( m_aSizingRect.TopLeft(), aNewSize ); + TabWinSized(m_pSizingWin, ptOld, szOld); + + m_pSizingWin->Invalidate( m_aSizingRect ); + m_pSizingWin = nullptr; + } + } + else if (rTEvt.IsTrackingCanceled()) + { + if (m_aDragScrollIdle.IsActive()) + m_aDragScrollIdle.Stop(); + EndTracking(); + } + else + { + if( m_pDragWin ) + { + m_ptPrevDraggingPos = rTEvt.GetMouseEvent().GetPosPixel(); + // scroll at window borders + ScrollWhileDragging(); + } + + if( m_pSizingWin ) + { + Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel(); + m_aSizingRect = m_pSizingWin->getSizingRect(aMousePos,m_aOutputSize); + PaintImmediately(); + ShowTracking( m_aSizingRect, ShowTrackFlags::Small | ShowTrackFlags::TrackWindow ); + } + } +} + +void OJoinTableView::ConnDoubleClicked(VclPtr<OTableConnection>& /*rConnection*/) +{ +} + +void OJoinTableView::MouseButtonDown( const MouseEvent& rEvt ) +{ + GrabFocus(); + Window::MouseButtonDown(rEvt); +} + +void OJoinTableView::MouseButtonUp( const MouseEvent& rEvt ) +{ + Window::MouseButtonUp(rEvt); + // Has a connection been selected? + if( m_vTableConnection.empty() ) + return; + + DeselectConn(GetSelectedConn()); + + for (auto & elem : m_vTableConnection) + { + if( elem->CheckHit(rEvt.GetPosPixel()) ) + { + SelectConn(elem); + + // Double-click + if( rEvt.GetClicks() == 2 ) + ConnDoubleClicked(elem); + + break; + } + } +} + +void OJoinTableView::KeyInput( const KeyEvent& rEvt ) +{ + sal_uInt16 nCode = rEvt.GetKeyCode().GetCode(); + bool bShift = rEvt.GetKeyCode().IsShift(); + bool bCtrl = rEvt.GetKeyCode().IsMod1(); + + if( !bCtrl && !bShift && (nCode==KEY_DELETE) ) + { + if (GetSelectedConn()) + RemoveConnection(GetSelectedConn(), true); + } + else + Window::KeyInput( rEvt ); +} + +void OJoinTableView::DeselectConn(OTableConnection* pConn) +{ + if (!pConn || !pConn->IsSelected()) + return; + + // deselect the corresponding entries in the ListBox of the table window + OTableWindow* pWin = pConn->GetSourceWin(); + if (pWin && pWin->GetListBox()) + pWin->GetListBox()->get_widget().unselect_all(); + + pWin = pConn->GetDestWin(); + if (pWin && pWin->GetListBox()) + pWin->GetListBox()->get_widget().unselect_all(); + + pConn->Deselect(); + m_pSelectedConn = nullptr; +} + +void OJoinTableView::SelectConn(OTableConnection* pConn) +{ + DeselectConn(GetSelectedConn()); + + pConn->Select(); + m_pSelectedConn = pConn; + GrabFocus(); // has to be called here because a table window may still be focused + + // select the concerned entries in the windows + OTableWindow* pConnSource = pConn->GetSourceWin(); + OTableWindow* pConnDest = pConn->GetDestWin(); + if (!(pConnSource && pConnDest)) + return; + + OTableWindowListBox* pSourceBox = pConnSource->GetListBox().get(); + OTableWindowListBox* pDestBox = pConnDest->GetListBox().get(); + if (!(pSourceBox && pDestBox)) + return; + + pSourceBox->get_widget().unselect_all(); + pDestBox->get_widget().unselect_all(); + + bool bScrolled = false; + + const std::vector<std::unique_ptr<OConnectionLine>>& rLines = pConn->GetConnLineList(); + auto aIter = rLines.rbegin(); + for(;aIter != rLines.rend();++aIter) + { + if ((*aIter)->IsValid()) + { + int nSourceEntry = pSourceBox->GetEntryFromText((*aIter)->GetData()->GetSourceFieldName()); + if (nSourceEntry != -1) + { + pSourceBox->get_widget().select(nSourceEntry); + pSourceBox->get_widget().scroll_to_row(nSourceEntry); + bScrolled = true; + } + + int nDestEntry = pDestBox->GetEntryFromText((*aIter)->GetData()->GetDestFieldName()); + if (nDestEntry != -1) + { + pDestBox->get_widget().select(nDestEntry); + pDestBox->get_widget().scroll_to_row(nDestEntry); + bScrolled = true; + } + } + } + + if (bScrolled) + { + // scrolling was done -> redraw + Invalidate(InvalidateFlags::NoChildren); + } +} + +void OJoinTableView::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + DrawConnections(rRenderContext, rRect); +} + +void OJoinTableView::InvalidateConnections() +{ + // draw Joins + for (auto & conn : m_vTableConnection) + conn->InvalidateConnection(); +} + +void OJoinTableView::DrawConnections(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + // draw Joins + for(const auto& connection : m_vTableConnection) + connection->Draw(rRenderContext, rRect); + // finally redraw the selected one above all others + if (GetSelectedConn()) + GetSelectedConn()->Draw(rRenderContext, rRect); +} + +std::vector<VclPtr<OTableConnection> >::const_iterator OJoinTableView::getTableConnections(const OTableWindow* _pFromWin) const +{ + return std::find_if( m_vTableConnection.begin(), + m_vTableConnection.end(), + [_pFromWin](OTableConnection * p) { return p->isTableConnection(_pFromWin); }); +} + +sal_Int32 OJoinTableView::getConnectionCount(const OTableWindow* _pFromWin) const +{ + return std::count_if( m_vTableConnection.begin(), + m_vTableConnection.end(), + [_pFromWin](OTableConnection * p) { return p->isTableConnection(_pFromWin); }); +} + +bool OJoinTableView::ExistsAConn(const OTableWindow* pFrom) const +{ + return getTableConnections(pFrom) != m_vTableConnection.end(); +} + +void OJoinTableView::ClearAll() +{ + SetUpdateMode(false); + + HideTabWins(); + + // and the same with the Connections + for (auto & elem : m_vTableConnection) + { + RemoveConnection(elem, true); + } + m_vTableConnection.clear(); + + m_pLastFocusTabWin = nullptr; + m_pSelectedConn = nullptr; + + // scroll to the upper left + ScrollPane(-GetScrollOffset().X(), true, true); + ScrollPane(-GetScrollOffset().Y(), false, true); + Invalidate(); +} + +void OJoinTableView::ScrollWhileDragging() +{ + OSL_ENSURE(m_pDragWin != nullptr, "OJoinTableView::ScrollWhileDragging must not be called when a window is being dragged !"); + + // kill the timer + if (m_aDragScrollIdle.IsActive()) + m_aDragScrollIdle.Stop(); + + Point aDragWinPos = m_ptPrevDraggingPos - m_aDragOffset; + Size aDragWinSize = m_pDragWin->GetSizePixel(); + Point aLowerRight(aDragWinPos.X() + aDragWinSize.Width(), aDragWinPos.Y() + aDragWinSize.Height()); + + if (aDragWinPos == m_pDragWin->GetPosPixel()) + return; + + // avoid illustration errors (when scrolling with active TrackingRect) + HideTracking(); + + bool bScrolling = false; + bool bNeedScrollTimer = false; + + // scroll at window borders + // TODO : only catch, if window would disappear completely (don't, if there is still a pixel visible) + if( aDragWinPos.X() < 5 ) + { + bScrolling = ScrollPane( -LINE_SIZE, true, true ); + if( !bScrolling && (aDragWinPos.X()<0) ) + aDragWinPos.setX( 0 ); + + // do I need further (timer controlled) scrolling ? + bNeedScrollTimer = bScrolling && (aDragWinPos.X() < 5); + } + + if( aLowerRight.X() > m_aOutputSize.Width() - 5 ) + { + bScrolling = ScrollPane( LINE_SIZE, true, true ) ; + if( !bScrolling && ( aLowerRight.X() > m_aOutputSize.Width() ) ) + aDragWinPos.setX( m_aOutputSize.Width() - aDragWinSize.Width() ); + + // do I need further (timer controlled) scrolling ? + bNeedScrollTimer = bScrolling && (aLowerRight.X() > m_aOutputSize.Width() - 5); + } + + if( aDragWinPos.Y() < 5 ) + { + bScrolling = ScrollPane( -LINE_SIZE, false, true ); + if( !bScrolling && (aDragWinPos.Y()<0) ) + aDragWinPos.setY( 0 ); + + bNeedScrollTimer = bScrolling && (aDragWinPos.Y() < 5); + } + + if( aLowerRight.Y() > m_aOutputSize.Height() - 5 ) + { + bScrolling = ScrollPane( LINE_SIZE, false, true ); + if( !bScrolling && ( (aDragWinPos.Y() + aDragWinSize.Height()) > m_aOutputSize.Height() ) ) + aDragWinPos.setY( m_aOutputSize.Height() - aDragWinSize.Height() ); + + bNeedScrollTimer = bScrolling && (aLowerRight.Y() > m_aOutputSize.Height() - 5); + } + + // resetting timer, if still necessary + if (bNeedScrollTimer) + { + m_aDragScrollIdle.SetPriority( TaskPriority::HIGH_IDLE ); + m_aDragScrollIdle.Start(); + } + + // redraw DraggingRect + m_aDragRect = tools::Rectangle(m_ptPrevDraggingPos - m_aDragOffset, m_pDragWin->GetSizePixel()); + PaintImmediately(); + ShowTracking( m_aDragRect, ShowTrackFlags::Small | ShowTrackFlags::TrackWindow ); +} + +IMPL_LINK_NOARG(OJoinTableView, OnDragScrollTimer, Timer *, void) +{ + ScrollWhileDragging(); +} + +void OJoinTableView::invalidateAndModify(std::unique_ptr<SfxUndoAction> _pAction) +{ + Invalidate(InvalidateFlags::NoChildren); + m_pView->getController().addUndoActionAndInvalidate(std::move(_pAction)); +} + +void OJoinTableView::TabWinMoved(OTableWindow* ptWhich, const Point& ptOldPosition) +{ + Point ptThumbPos(GetHScrollBar().GetThumbPos(), GetVScrollBar().GetThumbPos()); + ptWhich->GetData()->SetPosition(ptWhich->GetPosPixel() + ptThumbPos); + + invalidateAndModify(std::make_unique<OJoinMoveTabWinUndoAct>(this, ptOldPosition, ptWhich)); +} + +void OJoinTableView::TabWinSized(OTableWindow* ptWhich, const Point& ptOldPosition, const Size& szOldSize) +{ + ptWhich->GetData()->SetSize(ptWhich->GetSizePixel()); + ptWhich->GetData()->SetPosition(ptWhich->GetPosPixel()); + + invalidateAndModify(std::make_unique<OJoinSizeTabWinUndoAct>(this, ptOldPosition, szOldSize, ptWhich)); +} + +bool OJoinTableView::IsAddAllowed() +{ + + // not, if Db readonly + if (m_pView->getController().isReadOnly()) + return false; + + try + { + Reference< XConnection> xConnection = m_pView->getController().getConnection(); + if(!xConnection.is()) + return false; + // not, if too many tables already + Reference < XDatabaseMetaData > xMetaData( xConnection->getMetaData() ); + + sal_Int32 nMax = xMetaData.is() ? xMetaData->getMaxTablesInSelect() : 0; + if (nMax && nMax <= static_cast<sal_Int32>(m_aTableMap.size())) + return false; + } + catch(SQLException&) + { + return false; + } + + return true; +} + +void OJoinTableView::executePopup(const Point& rPos, VclPtr<OTableConnection>& rSelConnection) +{ + ::tools::Rectangle aRect(rPos, Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/joinviewmenu.ui")); + std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu")); + OString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect); + if (sIdent == "delete") + RemoveConnection(rSelConnection, true); + else if (sIdent == "edit") + ConnDoubleClicked(rSelConnection); // is the same as double clicked +} + +void OJoinTableView::Command(const CommandEvent& rEvt) +{ + + bool bHandled = false; + + switch (rEvt.GetCommand()) + { + case CommandEventId::ContextMenu: + { + if( m_vTableConnection.empty() ) + return; + + VclPtr<OTableConnection>& rSelConnection = GetSelectedConn(); + // when it wasn't a mouse event use the selected connection + if (!rEvt.IsMouseEvent()) + { + if (rSelConnection) + { + const std::vector<std::unique_ptr<OConnectionLine>>& rLines = rSelConnection->GetConnLineList(); + auto aIter = std::find_if(rLines.begin(), rLines.end(),std::mem_fn(&OConnectionLine::IsValid)); + if( aIter != rLines.end() ) + executePopup((*aIter)->getMidPoint(), rSelConnection); + } + } + else + { + DeselectConn(rSelConnection); + + const Point& aMousePos = rEvt.GetMousePosPixel(); + for (auto & elem : m_vTableConnection) + { + if( elem->CheckHit(aMousePos) ) + { + SelectConn(elem); + if(!getDesignView()->getController().isReadOnly() && getDesignView()->getController().isConnected()) + executePopup(rEvt.GetMousePosPixel(),elem); + break; + } + } + } + bHandled = true; + } + break; + default: break; + } + if (!bHandled) + Window::Command(rEvt); +} + +OTableConnection* OJoinTableView::GetTabConn(const OTableWindow* pLhs,const OTableWindow* pRhs,bool _bSuppressCrossOrNaturalJoin) const +{ + OTableConnection* pConn = nullptr; + OSL_ENSURE(pRhs || pLhs, "OJoinTableView::GetTabConn : invalid args !"); + // only one NULL-arg allowed + + if ((!pLhs || pLhs->ExistsAConn()) && (!pRhs || pRhs->ExistsAConn())) + { + for(VclPtr<OTableConnection> const & pData : m_vTableConnection) + { + if ( ( (pData->GetSourceWin() == pLhs) + && ( (pData->GetDestWin() == pRhs) + || (nullptr == pRhs) + ) + ) + || ( (pData->GetSourceWin() == pRhs) + && ( (pData->GetDestWin() == pLhs) + || (nullptr == pLhs) + ) + ) + ) + { + if ( _bSuppressCrossOrNaturalJoin ) + { + if ( suppressCrossNaturalJoin(pData->GetData()) ) + continue; + } + pConn = pData; + break; + } + } + } + return pConn; +} + +bool OJoinTableView::PreNotify(NotifyEvent& rNEvt) +{ + bool bHandled = false; + switch (rNEvt.GetType()) + { + case MouseNotifyEvent::COMMAND: + { + const CommandEvent* pCommand = rNEvt.GetCommandEvent(); + if (pCommand->GetCommand() == CommandEventId::Wheel) + { + const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData(); + if (pData->GetMode() == CommandWheelMode::SCROLL) + { + if (pData->GetDelta() > 0) + ScrollPane(-10 * pData->GetScrollLines(), pData->IsHorz(), true); + else + ScrollPane(10 * pData->GetScrollLines(), pData->IsHorz(), true); + bHandled = true; + } + } + } + break; + case MouseNotifyEvent::KEYINPUT: + { + if (m_aTableMap.empty()) + // no tab wins -> no conns -> no traveling + break; + + const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); + if (!pKeyEvent->GetKeyCode().IsMod1()) + { + switch (pKeyEvent->GetKeyCode().GetCode()) + { + case KEY_TAB: + { + if (!HasChildPathFocus()) + break; + + bool bForward = !pKeyEvent->GetKeyCode().IsShift(); + // is there an active tab win ? + OTableWindowMap::const_iterator aIter = std::find_if(m_aTableMap.begin(), m_aTableMap.end(), + [](const OTableWindowMap::value_type& rEntry) { return rEntry.second && rEntry.second->HasChildPathFocus(); }); + + OTableWindow* pNextWin = nullptr; + OTableConnection* pNextConn = nullptr; + + if (aIter != m_aTableMap.end()) + { // there is a currently active tab win + // check if there is an "overflow" and we should select a conn instead of a win + if (!m_vTableConnection.empty()) + { + if ((aIter->second == m_aTableMap.rbegin()->second) && bForward) + // the last win is active and we're travelling forward -> select the first conn + pNextConn = m_vTableConnection.begin()->get(); + if ((aIter == m_aTableMap.begin()) && !bForward) + // the first win is active and we're traveling backward -> select the last conn + pNextConn = m_vTableConnection.rbegin()->get(); + } + + if (!pNextConn) + { + // no conn for any reason -> select the next or previous tab win + if(bForward) + { + if ( aIter->second == m_aTableMap.rbegin()->second ) + pNextWin = m_aTableMap.begin()->second; + else + { + ++aIter; + pNextWin = aIter->second; + } + } + else + { + if (aIter == m_aTableMap.begin()) + pNextWin = m_aTableMap.rbegin()->second; + else + { + --aIter; + pNextWin = aIter->second; + } + } + } + } + else + { // no active tab win -> travel the connections + // find the currently selected conn within the conn list + sal_Int32 i(0); + for (auto const& elem : m_vTableConnection) + { + if ( elem.get() == GetSelectedConn() ) + break; + ++i; + } + if (i == sal_Int32(m_vTableConnection.size() - 1) && bForward) + // the last conn is active and we're travelling forward -> select the first win + pNextWin = m_aTableMap.begin()->second; + if ((i == 0) && !bForward && !m_aTableMap.empty()) + // the first conn is active and we're travelling backward -> select the last win + pNextWin = m_aTableMap.rbegin()->second; + + if (pNextWin) + DeselectConn(GetSelectedConn()); + else + // no win for any reason -> select the next or previous conn + if (i < static_cast<sal_Int32>(m_vTableConnection.size())) + // there is a currently active conn + pNextConn = m_vTableConnection[(i + (bForward ? 1 : m_vTableConnection.size() - 1)) % m_vTableConnection.size()].get(); + else + { // no tab win selected, no conn selected + if (!m_vTableConnection.empty()) + pNextConn = m_vTableConnection[bForward ? 0 : m_vTableConnection.size() - 1].get(); + else if (!m_aTableMap.empty()) + { + if(bForward) + pNextWin = m_aTableMap.begin()->second; + else + pNextWin = m_aTableMap.rbegin()->second; + } + } + } + + // now select the object + if (pNextWin) + { + if (pNextWin->GetListBox()) + pNextWin->GetListBox()->GrabFocus(); + else + pNextWin->GrabFocus(); + EnsureVisible(pNextWin); + } + else if (pNextConn) + { + GrabFocus(); + // necessary : a conn may be selected even if a tab win has the focus, in this case + // the next travel would select the same conn again if we would not reset the focus ... + SelectConn(pNextConn); + } + } + break; + case KEY_RETURN: + { + if (!pKeyEvent->GetKeyCode().IsShift() && GetSelectedConn() && HasFocus()) + ConnDoubleClicked(GetSelectedConn()); + break; + } + } + } + } + break; + case MouseNotifyEvent::GETFOCUS: + { + if (m_aTableMap.empty()) + // no tab wins -> no conns -> no focus change + break; + vcl::Window* pSource = rNEvt.GetWindow(); + if (pSource) + { + vcl::Window* pSearchFor = nullptr; + if (pSource->GetParent() == this) + // it may be one of the tab wins + pSearchFor = pSource; + else if (pSource->GetParent() && (pSource->GetParent()->GetParent() == this)) + // it may be one of th list boxes of one of the tab wins + pSearchFor = pSource->GetParent(); + + if (pSearchFor) + { + for (auto const& elem : m_aTableMap) + { + if (elem.second == pSearchFor) + { + m_pLastFocusTabWin = elem.second; + break; + } + } + } + } + } + break; + default: + break; + } + + if (!bHandled) + return Window::PreNotify(rNEvt); + return true; +} + +void OJoinTableView::GrabTabWinFocus() +{ + if (m_pLastFocusTabWin && m_pLastFocusTabWin->IsVisible()) + { + if (m_pLastFocusTabWin->GetListBox()) + m_pLastFocusTabWin->GetListBox()->GrabFocus(); + else + m_pLastFocusTabWin->GrabFocus(); + } + else if (!m_aTableMap.empty() && m_aTableMap.begin()->second && m_aTableMap.begin()->second->IsVisible()) + { + VclPtr<OTableWindow> pFirstWin = m_aTableMap.begin()->second; + if (pFirstWin->GetListBox()) + pFirstWin->GetListBox()->GrabFocus(); + else + pFirstWin->GrabFocus(); + } +} + +void OJoinTableView::StateChanged( StateChangedType nType ) +{ + Window::StateChanged( nType ); + + // FIXME RenderContext + if ( nType != StateChangedType::Zoom ) + return; + + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + vcl::Font aFont = rStyleSettings.GetGroupFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetZoomedPointFont(*GetOutDev(), aFont); + + for (auto const& elem : m_aTableMap) + { + elem.second->SetZoom(GetZoom()); + Size aSize(CalcZoom(elem.second->GetSizePixel().Width()),CalcZoom(elem.second->GetSizePixel().Height())); + elem.second->SetSizePixel(aSize); + } + Resize(); +} + +void OJoinTableView::HideTabWins() +{ + SetUpdateMode(false); + + OTableWindowMap& rTabWins = GetTabWinMap(); + + // working on a copy because the real list will be cleared in inner calls + OTableWindowMap aCopy(rTabWins); + for (auto const& elem : aCopy) + RemoveTabWin(elem.second); + + m_pView->getController().setModified(true); + + SetUpdateMode(true); + +} + +sal_Int8 OJoinTableView::AcceptDrop( const AcceptDropEvent& /*_rEvt*/ ) +{ + return DND_ACTION_NONE; +} + +sal_Int8 OJoinTableView::ExecuteDrop( const ExecuteDropEvent& /*_rEvt*/ ) +{ + return DND_ACTION_NONE; +} + +void OJoinTableView::dragFinished( ) +{ +} + +void OJoinTableView::clearLayoutInformation() +{ + m_pLastFocusTabWin = nullptr; + m_pSelectedConn = nullptr; + // delete lists + for (auto & elem : m_aTableMap) + { + if ( elem.second ) + elem.second->clearListBox(); + elem.second.disposeAndClear(); + } + + m_aTableMap.clear(); + + for (auto & elem : m_vTableConnection) + elem.disposeAndClear(); + + m_vTableConnection.clear(); +} + +void OJoinTableView::lookForUiActivities() +{ +} + +void OJoinTableView::LoseFocus() +{ + DeselectConn(GetSelectedConn()); + Window::LoseFocus(); +} + +void OJoinTableView::GetFocus() +{ + Window::GetFocus(); + if ( !m_aTableMap.empty() && !GetSelectedConn() ) + GrabTabWinFocus(); +} + +Reference< XAccessible > OJoinTableView::CreateAccessible() +{ + m_pAccessible = new OJoinDesignViewAccess(this); + return m_pAccessible; +} + +void OJoinTableView::modified() +{ + OJoinController& rController = m_pView->getController(); + rController.setModified( true ); + rController.InvalidateFeature(ID_BROWSER_ADDTABLE); + rController.InvalidateFeature(SID_RELATION_ADD_RELATION); +} + +void OJoinTableView::addConnection(OTableConnection* _pConnection,bool _bAddData) +{ + if ( _bAddData ) + { +#if OSL_DEBUG_LEVEL > 0 + TTableConnectionData& rTabConnDataList = m_pView->getController().getTableConnectionData(); + OSL_ENSURE( std::find(rTabConnDataList.begin(), rTabConnDataList.end(),_pConnection->GetData()) == rTabConnDataList.end(),"Data already in vector!"); +#endif + m_pView->getController().getTableConnectionData().push_back(_pConnection->GetData()); + } + m_vTableConnection.emplace_back(_pConnection); + _pConnection->RecalcLines(); + _pConnection->InvalidateConnection(); + + modified(); + if ( m_pAccessible ) + m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD, + Any(), + Any(_pConnection->GetAccessible())); +} + +bool OJoinTableView::allowQueries() const +{ + return true; +} + +void OJoinTableView::onNoColumns_throw() +{ + OSL_FAIL( "OTableWindow::onNoColumns_throw: cannot really handle this!" ); + throw SQLException(); +} + +bool OJoinTableView::suppressCrossNaturalJoin(const TTableConnectionData::value_type& ) const +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QTableConnection.cxx b/dbaccess/source/ui/querydesign/QTableConnection.cxx new file mode 100644 index 000000000..c5db155f2 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableConnection.cxx @@ -0,0 +1,73 @@ +/* -*- 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 "QTableConnection.hxx" +#include <osl/diagnose.h> +#include <QueryTableView.hxx> + +using namespace dbaui; + +OQueryTableConnection::OQueryTableConnection(OQueryTableView* pContainer, const TTableConnectionData::value_type& pTabConnData) + : OTableConnection(pContainer, pTabConnData) + , m_bVisited(false) +{ +} + +OQueryTableConnection::OQueryTableConnection(const OQueryTableConnection& rConn) + : VclReferenceBase(), + OTableConnection( rConn ) + , m_bVisited(false) +{ + // no own members, so base class functionality is sufficient +} + +OQueryTableConnection& OQueryTableConnection::operator=(const OQueryTableConnection& rConn) +{ + if (&rConn == this) + return *this; + + OTableConnection::operator=(rConn); + // no own members ... + return *this; +} + +bool OQueryTableConnection::operator==(const OQueryTableConnection& rCompare) const +{ + OSL_ENSURE(GetData() && rCompare.GetData(), "OQueryTableConnection::operator== : one of the two participants has no data!"); + + // I don't have to compare all too much (especially not all the members) : merely the windows, which we are connected to, and the indices in the corresponding table have to match. + OQueryTableConnectionData* pMyData = static_cast<OQueryTableConnectionData*>(GetData().get()); + OQueryTableConnectionData* pCompData = static_cast<OQueryTableConnectionData*>(rCompare.GetData().get()); + + // Connections are seen as equal, if source and destination window names and source and destination field Indices match... + return ( ( (pMyData->getReferencedTable() == pCompData->getReferencedTable()) && + (pMyData->getReferencingTable() == pCompData->getReferencingTable()) && + (pMyData->GetFieldIndex(JTCS_TO) == pCompData->GetFieldIndex(JTCS_TO)) && + (pMyData->GetFieldIndex(JTCS_FROM) == pCompData->GetFieldIndex(JTCS_FROM)) + ) + || // ... or this cross matching is given + ( (pMyData->getReferencingTable() == pCompData->getReferencedTable()) && + (pMyData->getReferencedTable() == pCompData->getReferencingTable()) && + (pMyData->GetFieldIndex(JTCS_TO) == pCompData->GetFieldIndex(JTCS_FROM)) && + (pMyData->GetFieldIndex(JTCS_FROM) == pCompData->GetFieldIndex(JTCS_TO)) + ) + ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QTableConnection.hxx b/dbaccess/source/ui/querydesign/QTableConnection.hxx new file mode 100644 index 000000000..c6bd2e10d --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableConnection.hxx @@ -0,0 +1,46 @@ +/* -*- 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 <TableConnection.hxx> +#include "QTableConnectionData.hxx" +#include <QEnumTypes.hxx> + +namespace dbaui +{ + class OQueryTableView; + class OQueryTableConnection : public OTableConnection + { + bool m_bVisited; // is true if the conn was already visited through the join algorithm + public: + OQueryTableConnection(OQueryTableView* pContainer, const TTableConnectionData::value_type& pTabConnData); + OQueryTableConnection(const OQueryTableConnection& rConn); + + OQueryTableConnection& operator=(const OQueryTableConnection& rConn); + bool operator==(const OQueryTableConnection& rCompare) const; + + OUString const & GetAliasName(EConnectionSide nWhich) const { return static_cast<OQueryTableConnectionData*>(GetData().get())->GetAliasName(nWhich); } + + bool IsVisited() const { return m_bVisited; } + void SetVisited(bool bVisited) { m_bVisited = bVisited; } + + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QTableConnectionData.cxx b/dbaccess/source/ui/querydesign/QTableConnectionData.cxx new file mode 100644 index 000000000..ce66828fa --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableConnectionData.cxx @@ -0,0 +1,112 @@ +/* -*- 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 "QTableConnectionData.hxx" +#include "QTableWindow.hxx" + +#include <osl/diagnose.h> + +using namespace dbaui; + +OQueryTableConnectionData::OQueryTableConnectionData() + : m_nFromEntryIndex(0) + , m_nDestEntryIndex(0) + , m_eJoinType (INNER_JOIN) + , m_bNatural(false) +{ +} + +OQueryTableConnectionData::OQueryTableConnectionData( const OQueryTableConnectionData& rConnData ) + : OTableConnectionData( rConnData ) + , m_nFromEntryIndex(rConnData.m_nFromEntryIndex) + , m_nDestEntryIndex(rConnData.m_nDestEntryIndex) + , m_eJoinType(rConnData.m_eJoinType) + , m_bNatural(rConnData.m_bNatural) +{ +} + +OQueryTableConnectionData::OQueryTableConnectionData(const TTableWindowData::value_type& _pReferencingTable, + const TTableWindowData::value_type& _pReferencedTable) + : OTableConnectionData( _pReferencingTable,_pReferencedTable ) + , m_nFromEntryIndex(0) + , m_nDestEntryIndex(0) + , m_eJoinType (INNER_JOIN) + , m_bNatural(false) +{ +} + +OQueryTableConnectionData::~OQueryTableConnectionData() +{ +} + +void OQueryTableConnectionData::CopyFrom(const OTableConnectionData& rSource) +{ + // same as in base class, use of (non-virtual) operator= + *this = static_cast<const OQueryTableConnectionData&>(rSource); +} + +OQueryTableConnectionData& OQueryTableConnectionData::operator=(const OQueryTableConnectionData& rConnData) +{ + if (&rConnData == this) + return *this; + + OTableConnectionData::operator=(rConnData); + + m_nFromEntryIndex = rConnData.m_nFromEntryIndex; + m_nDestEntryIndex = rConnData.m_nDestEntryIndex; + + m_eJoinType = rConnData.m_eJoinType; + m_bNatural = rConnData.m_bNatural; + + return *this; +} + +OUString const & OQueryTableConnectionData::GetAliasName(EConnectionSide nWhich) const +{ + return nWhich == JTCS_FROM ? m_pReferencingTable->GetWinName() : m_pReferencedTable->GetWinName(); +} + +void OQueryTableConnectionData::InitFromDrag(const OTableFieldDescRef& rDragLeft, const OTableFieldDescRef& rDragRight) +{ + // convert Information in rDrag into parameters for the base class init + OQueryTableWindow* pSourceWin = static_cast<OQueryTableWindow*>(rDragLeft->GetTabWindow()); + OQueryTableWindow* pDestWin = static_cast<OQueryTableWindow*>(rDragRight->GetTabWindow()); + OSL_ENSURE(pSourceWin,"NO Source window found!"); + OSL_ENSURE(pDestWin,"NO Dest window found!"); + m_pReferencingTable = pSourceWin->GetData(); + m_pReferencedTable = pDestWin->GetData(); + + // set members + SetFieldIndex(JTCS_FROM, rDragLeft->GetFieldIndex()); + SetFieldIndex(JTCS_TO, rDragRight->GetFieldIndex()); + + AppendConnLine(rDragLeft->GetField(), rDragRight->GetField()); +} + +std::shared_ptr<OTableConnectionData> OQueryTableConnectionData::NewInstance() const +{ + return std::make_shared<OQueryTableConnectionData>(); +} + +bool OQueryTableConnectionData::Update() +{ + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QTableConnectionData.hxx b/dbaccess/source/ui/querydesign/QTableConnectionData.hxx new file mode 100644 index 000000000..7ccbb03ac --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableConnectionData.hxx @@ -0,0 +1,67 @@ +/* -*- 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 <TableConnectionData.hxx> +#include <TableFieldDescription.hxx> +#include <QEnumTypes.hxx> + +namespace dbaui +{ + class OQueryTableConnectionData final : public OTableConnectionData + { + sal_Int32 m_nFromEntryIndex; + sal_Int32 m_nDestEntryIndex; + EJoinType m_eJoinType; + bool m_bNatural; + + OQueryTableConnectionData& operator=( const OQueryTableConnectionData& rConnData ); + public: + OQueryTableConnectionData(); + OQueryTableConnectionData( const OQueryTableConnectionData& rConnData ); + OQueryTableConnectionData( const TTableWindowData::value_type& _pReferencingTable,const TTableWindowData::value_type& _pReferencedTable ); + virtual ~OQueryTableConnectionData() override; + + virtual void CopyFrom(const OTableConnectionData& rSource) override; + virtual std::shared_ptr<OTableConnectionData> NewInstance() const override; + + + /** Update create a new connection + + @return true if successful + */ + virtual bool Update() override; + + OUString const & GetAliasName(EConnectionSide nWhich) const; + + sal_Int32 GetFieldIndex(EConnectionSide nWhich) const { return nWhich==JTCS_TO ? m_nDestEntryIndex : m_nFromEntryIndex; } + void SetFieldIndex(EConnectionSide nWhich, sal_Int32 nVal) { if (nWhich==JTCS_TO) m_nDestEntryIndex=nVal; else m_nFromEntryIndex=nVal; } + + void InitFromDrag(const OTableFieldDescRef& rDragLeft, const OTableFieldDescRef& rDragRight); + + EJoinType GetJoinType() const { return m_eJoinType; }; + void SetJoinType(const EJoinType& eJT) { m_eJoinType = eJT; }; + + void setNatural(bool _bNatural) { m_bNatural = _bNatural; } + bool isNatural() const { return m_bNatural; } + }; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QTableWindow.cxx b/dbaccess/source/ui/querydesign/QTableWindow.cxx new file mode 100644 index 000000000..6b129c32d --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableWindow.cxx @@ -0,0 +1,175 @@ +/* -*- 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 "QTableWindow.hxx" +#include <QueryTableView.hxx> +#include <JoinController.hxx> +#include <JoinDesignView.hxx> +#include <osl/diagnose.h> +#include <helpids.h> +#include <browserids.hxx> +#include <TableWindowListBox.hxx> +#include <strings.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include "TableFieldInfo.hxx" +#include <comphelper/stl_types.hxx> +#include <comphelper/types.hxx> + +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace dbaui; +OQueryTableWindow::OQueryTableWindow( vcl::Window* pParent, const TTableWindowData::value_type& pTabWinData) + :OTableWindow( pParent, pTabWinData ) + ,m_nAliasNum(0) +{ + m_strInitialAlias = GetAliasName(); + + // if table name matches alias, do not pass to InitialAlias, + // as the appending of a possible token could not succeed... + if (m_strInitialAlias == pTabWinData->GetTableName()) + m_strInitialAlias.clear(); + + SetHelpId(HID_CTL_QRYDGNTAB); +} + +bool OQueryTableWindow::Init() +{ + bool bSuccess = OTableWindow::Init(); + if (!bSuccess) + return bSuccess; + + OQueryTableView* pContainer = static_cast<OQueryTableView*>(getTableView()); + + // first determine Alias + OUString sAliasName; + + TTableWindowData::value_type pWinData = GetData(); + + if (!m_strInitialAlias.isEmpty() ) + // Alias was explicitly given + sAliasName = m_strInitialAlias; + else if ( GetTable().is() ) + GetTable()->getPropertyValue( PROPERTY_NAME ) >>= sAliasName; + else + return false; + + // Alias with successive number + if (pContainer->CountTableAlias(sAliasName, m_nAliasNum)) + { + sAliasName += "_" + OUString::number(m_nAliasNum); + } + + sAliasName = sAliasName.replaceAll("\"", ""); + SetAliasName(sAliasName); + // SetAliasName passes it as WinName, hence it uses the base class + // reset the title + m_xTitle->SetText( pWinData->GetWinName() ); + m_xTitle->Show(); + + getTableView()->getDesignView()->getController().InvalidateFeature(ID_BROWSER_QUERY_EXECUTE); + return bSuccess; +} + +void* OQueryTableWindow::createUserData(const Reference< XPropertySet>& _xColumn,bool _bPrimaryKey) +{ + OTableFieldInfo* pInfo = new OTableFieldInfo(); + pInfo->SetKey(_bPrimaryKey ? TAB_PRIMARY_FIELD : TAB_NORMAL_FIELD); + if ( _xColumn.is() ) + pInfo->SetDataType(::comphelper::getINT32(_xColumn->getPropertyValue(PROPERTY_TYPE))); + return pInfo; +} + +void OQueryTableWindow::deleteUserData(void*& _pUserData) +{ + delete static_cast<OTableFieldInfo*>(_pUserData); + _pUserData = nullptr; +} + +void OQueryTableWindow::OnEntryDoubleClicked(weld::TreeIter& rEntry) +{ + if (getTableView()->getDesignView()->getController().isReadOnly()) + return; + + weld::TreeView& rTreeView = m_xListBox->get_widget(); + OTableFieldInfo* pInf = weld::fromId<OTableFieldInfo*>(rTreeView.get_id(rEntry)); + OSL_ENSURE(pInf != nullptr, "OQueryTableWindow::OnEntryDoubleClicked : field doesn't have FieldInfo !"); + + // build up DragInfo + OTableFieldDescRef aInfo = new OTableFieldDesc(GetTableName(), rTreeView.get_text(rEntry)); + aInfo->SetTabWindow(this); + aInfo->SetAlias(GetAliasName()); + aInfo->SetFieldIndex(rTreeView.get_iter_index_in_parent(rEntry)); + aInfo->SetDataType(pInf->GetDataType()); + + // and insert corresponding field + static_cast<OQueryTableView*>(getTableView())->InsertField(aInfo); +} + +bool OQueryTableWindow::ExistsField(const OUString& strFieldName, OTableFieldDescRef const & rInfo) +{ + OSL_ENSURE(m_xListBox != nullptr, "OQueryTableWindow::ExistsField : doesn't have css::form::ListBox !"); + OSL_ENSURE(rInfo.is(),"OQueryTableWindow::ExistsField: invalid argument for OTableFieldDescRef!"); + Reference< XConnection> xConnection = getTableView()->getDesignView()->getController().getConnection(); + bool bExists = false; + if(xConnection.is()) + { + weld::TreeView& rTreeView = m_xListBox->get_widget(); + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + bool bEntry = rTreeView.get_iter_first(*xEntry); + try + { + Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData(); + ::comphelper::UStringMixEqual bCase(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers()); + + while (bEntry) + { + if (bCase(strFieldName, rTreeView.get_text(*xEntry))) + { + OTableFieldInfo* pInf = weld::fromId<OTableFieldInfo*>(rTreeView.get_id(*xEntry)); + assert(pInf && "OQueryTableWindow::ExistsField : field doesn't have FieldInfo !"); + + rInfo->SetTabWindow(this); + rInfo->SetField(strFieldName); + rInfo->SetTable(GetTableName()); + rInfo->SetAlias(GetAliasName()); + rInfo->SetFieldIndex(rTreeView.get_iter_index_in_parent(*xEntry)); + rInfo->SetDataType(pInf->GetDataType()); + bExists = true; + break; + } + bEntry = rTreeView.iter_next(*xEntry); + } + } + catch(SQLException&) + { + } + } + + return bExists; +} + +bool OQueryTableWindow::ExistsAVisitedConn() const +{ + return static_cast<const OQueryTableView*>(getTableView())->ExistsAVisitedConn(this); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QTableWindow.hxx b/dbaccess/source/ui/querydesign/QTableWindow.hxx new file mode 100644 index 000000000..72c698c83 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableWindow.hxx @@ -0,0 +1,76 @@ +/* -*- 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 <TableWindow.hxx> +#include "QTableWindowData.hxx" +#include <TableFieldDescription.hxx> + +namespace dbaui +{ + class OQueryTableWindow : public OTableWindow + { + sal_Int32 m_nAliasNum; + OUString m_strInitialAlias; + public: + OQueryTableWindow( vcl::Window* pParent, const TTableWindowData::value_type& pTabWinData ); + + OUString const & GetAliasName() const + { + return static_cast<OQueryTableWindowData*>(GetData().get())->GetAliasName(); + } + void SetAliasName(const OUString& strNewAlias) + { + static_cast<OQueryTableWindowData*>(GetData().get())->SetAliasName(strNewAlias); + } + + // late Constructor, the base class CREATES Listbox on first call + virtual bool Init() override; + + bool ExistsField(const OUString& strFieldName, OTableFieldDescRef const & rInfo); + bool ExistsAVisitedConn() const; + + virtual OUString GetName() const override { return GetWinName(); } + + protected: + + virtual void OnEntryDoubleClicked(weld::TreeIter& rEntry) override; + // is called from DoubleClickHdl of the ListBox + /** delete the user data with the equal type as created within createUserData + @param _pUserData + The user data store in the listbox entries. Created with a call to createUserData. + _pUserData may be <NULL/>. + */ + virtual void deleteUserData(void*& _pUserData) override; + + /** creates user information that will be append at the ListBoxentry + @param _xColumn + The corresponding column, can be <NULL/>. + @param _bPrimaryKey + <TRUE/> when the column belongs to the primary key + @return + the user data which will be append at the listbox entry, may be <NULL/> + */ + virtual void* createUserData(const css::uno::Reference< + css::beans::XPropertySet>& _xColumn, + bool _bPrimaryKey) override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QTableWindowData.cxx b/dbaccess/source/ui/querydesign/QTableWindowData.cxx new file mode 100644 index 000000000..d8f2f2efd --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableWindowData.cxx @@ -0,0 +1,34 @@ +/* -*- 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 "QTableWindowData.hxx" + +using namespace dbaui; +using namespace ::com::sun::star::uno; + +OQueryTableWindowData::OQueryTableWindowData(const OUString& _rComposedName, const OUString& rTableName, const OUString& rTableAlias ) + :OTableWindowData(nullptr,_rComposedName, rTableName, rTableAlias) +{ +} + +OQueryTableWindowData::~OQueryTableWindowData() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QTableWindowData.hxx b/dbaccess/source/ui/querydesign/QTableWindowData.hxx new file mode 100644 index 000000000..327dc27f1 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableWindowData.hxx @@ -0,0 +1,38 @@ +/* -*- 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 <TableWindowData.hxx> + + +namespace dbaui +{ + class OQueryTableWindowData : public OTableWindowData + { + public: + explicit OQueryTableWindowData(const OUString& _rComposedName, const OUString& rTableName, const OUString& rTableAlias); + virtual ~OQueryTableWindowData() override; + + OUString const & GetAliasName() const { return GetWinName(); } + void SetAliasName(const OUString& rNewAlias) { SetWinName(rNewAlias); } + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryAddTabConnUndoAction.hxx b/dbaccess/source/ui/querydesign/QueryAddTabConnUndoAction.hxx new file mode 100644 index 000000000..dd641be1d --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryAddTabConnUndoAction.hxx @@ -0,0 +1,49 @@ +/* -*- 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 "QueryTabConnUndoAction.hxx" + +namespace dbaui +{ + // OQueryAddTabConnUndoAction - Undo class for inserting a connection + + class OQueryTableView; + class OQueryAddTabConnUndoAction : public OQueryTabConnUndoAction + { + public: + explicit OQueryAddTabConnUndoAction(OQueryTableView* pOwner); + + virtual void Undo() override; + virtual void Redo() override; + }; + + // OQueryDelTabConnUndoAction - Undo class for inserting a connection + + class OQueryDelTabConnUndoAction : public OQueryTabConnUndoAction + { + public: + explicit OQueryDelTabConnUndoAction(OQueryTableView* pOwner); + + virtual void Undo() override; + virtual void Redo() override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryDesignFieldUndoAct.hxx b/dbaccess/source/ui/querydesign/QueryDesignFieldUndoAct.hxx new file mode 100644 index 000000000..13262f570 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryDesignFieldUndoAct.hxx @@ -0,0 +1,138 @@ +/* -*- 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 <GeneralUndo.hxx> +#include <strings.hrc> +#include "SelectionBrowseBox.hxx" +#include <osl/diagnose.h> + +namespace dbaui +{ + // OQueryDesignFieldUndoAct - Basisclass for undo's in the fieldlist of a query design + + class OQueryDesignFieldUndoAct : public OCommentUndoAction + { + protected: + VclPtr<OSelectionBrowseBox> pOwner; + sal_uInt16 m_nColumnPosition; + + virtual void Undo() override = 0; + virtual void Redo() override = 0; + + public: + OQueryDesignFieldUndoAct(OSelectionBrowseBox* pSelBrwBox, TranslateId pCommentID); + virtual ~OQueryDesignFieldUndoAct() override; + + void SetColumnPosition(sal_uInt16 _nColumnPosition) + { + m_nColumnPosition = _nColumnPosition; + OSL_ENSURE(m_nColumnPosition != BROWSER_INVALIDID,"Column position was not set add the undo action!"); + OSL_ENSURE(m_nColumnPosition < pOwner->GetColumnCount(),"Position outside the column count!"); + } + }; + + // OTabFieldCellModifiedUndoAct - undo class to change a line of the column description + + class OTabFieldCellModifiedUndoAct final : public OQueryDesignFieldUndoAct + { + OUString m_strNextCellContents; + sal_Int32 m_nCellIndex; + + public: + explicit OTabFieldCellModifiedUndoAct(OSelectionBrowseBox* pSelBrwBox) + : OQueryDesignFieldUndoAct(pSelBrwBox, STR_QUERY_UNDO_MODIFY_CELL) + ,m_nCellIndex(BROWSER_INVALIDID){ } + + void SetCellContents(const OUString& str) { m_strNextCellContents = str; } + void SetCellIndex(sal_Int32 nIndex) { m_nCellIndex = nIndex; } + + virtual void Undo() override; + virtual void Redo() override { Undo(); } + }; + + // OTabFieldSizedUndoAct - undo class to change the column width + + class OTabFieldSizedUndoAct final : public OQueryDesignFieldUndoAct + { + tools::Long m_nNextWidth; + + public: + explicit OTabFieldSizedUndoAct(OSelectionBrowseBox* pSelBrwBox) : OQueryDesignFieldUndoAct(pSelBrwBox, STR_QUERY_UNDO_SIZE_COLUMN), m_nNextWidth(0) { } + + void SetOriginalWidth(tools::Long nWidth) { m_nNextWidth = nWidth; } + + virtual void Undo() override; + virtual void Redo() override { Undo(); } + }; + + // OTabFieldUndoAct - base class for undos in the fieldlist of a query design, which are used to change complete field descriptions + + class OTabFieldUndoAct : public OQueryDesignFieldUndoAct + { + protected: + OTableFieldDescRef pDescr; // the deleted column description + + public: + OTabFieldUndoAct(OSelectionBrowseBox* pSelBrwBox, TranslateId pCommentID) : OQueryDesignFieldUndoAct(pSelBrwBox, pCommentID) { } + + void SetTabFieldDescr(OTableFieldDescRef const & pDescription) { pDescr = pDescription; } + }; + + // OTabFieldDelUndoAct - undo class to delete a field + + class OTabFieldDelUndoAct : public OTabFieldUndoAct + { + protected: + virtual void Undo() override { pOwner->EnterUndoMode();pOwner->InsertColumn(pDescr, m_nColumnPosition);pOwner->LeaveUndoMode(); } + virtual void Redo() override { pOwner->EnterUndoMode();pOwner->RemoveColumn(pDescr->GetColumnId());pOwner->LeaveUndoMode(); } + + public: + explicit OTabFieldDelUndoAct(OSelectionBrowseBox* pSelBrwBox) : OTabFieldUndoAct(pSelBrwBox, STR_QUERY_UNDO_TABFIELDDELETE) { } + }; + + // OTabFieldCreateUndoAct - undo class for creating a field + + class OTabFieldCreateUndoAct : public OTabFieldUndoAct + { + protected: + virtual void Undo() override { pOwner->EnterUndoMode();pOwner->RemoveColumn(pDescr->GetColumnId());pOwner->LeaveUndoMode();} + virtual void Redo() override { pOwner->EnterUndoMode();pOwner->InsertColumn(pDescr, m_nColumnPosition);pOwner->LeaveUndoMode();} + + public: + explicit OTabFieldCreateUndoAct(OSelectionBrowseBox* pSelBrwBox) : OTabFieldUndoAct(pSelBrwBox, STR_QUERY_UNDO_TABFIELDCREATE) { } + }; + + // OTabFieldMovedUndoAct - Undo class when a field was moved inside the selection + + class OTabFieldMovedUndoAct : public OTabFieldUndoAct + { + protected: + virtual void Undo() override; + virtual void Redo() override + { + Undo(); + } + + public: + explicit OTabFieldMovedUndoAct(OSelectionBrowseBox* pSelBrwBox) : OTabFieldUndoAct(pSelBrwBox, STR_QUERY_UNDO_TABFIELDMOVED) { } + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryDesignUndoAction.hxx b/dbaccess/source/ui/querydesign/QueryDesignUndoAction.hxx new file mode 100644 index 000000000..8a8742393 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryDesignUndoAction.hxx @@ -0,0 +1,39 @@ +/* -*- 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 <GeneralUndo.hxx> +#include <JoinTableView.hxx> +#include <vcl/vclptr.hxx> + +namespace dbaui +{ + // OQueryDesignUndoAction - undo base class for actions in graphical query design (without field list) + class OJoinTableView; + class OQueryDesignUndoAction : public OCommentUndoAction + { + protected: + VclPtr<OJoinTableView> m_pOwner; // in this container it all happens + + public: + OQueryDesignUndoAction(OJoinTableView* pOwner, TranslateId pCommentID) : OCommentUndoAction(pCommentID), m_pOwner(pOwner) { } + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryDesignView.cxx b/dbaccess/source/ui/querydesign/QueryDesignView.cxx new file mode 100644 index 000000000..f5e4288e9 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryDesignView.cxx @@ -0,0 +1,3441 @@ +/* -*- 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 <QueryDesignView.hxx> +#include <QueryTableView.hxx> +#include "QTableWindow.hxx" +#include <querycontroller.hxx> +#include <sqlbison.hxx> +#include <vcl/split.hxx> +#include <tools/diagnose_ex.h> +#include <o3tl/safeint.hxx> +#include <o3tl/string_view.hxx> +#include <osl/diagnose.h> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <browserids.hxx> +#include "SelectionBrowseBox.hxx" +#include <strings.hrc> +#include <strings.hxx> +#include <comphelper/string.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbexception.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <connectivity/PColumn.hxx> +#include "QTableConnection.hxx" +#include <ConnectionLineData.hxx> +#include "QTableConnectionData.hxx" +#include <core_resource.hxx> +#include <UITools.hxx> +#include <querycontainerwindow.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/syslocale.hxx> +#include <memory> +#include <set> +#include <string_view> + +using namespace ::dbaui; +using namespace ::utl; +using namespace ::connectivity; +using namespace ::dbtools; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; + +// here we define our functions used in the anonymous namespace to get our header file smaller +// please look at the book LargeScale C++ to know why +namespace +{ + const char C_AND[] = " AND "; + const char C_OR[] = " OR "; + + bool InsertJoin( const OQueryDesignView* _pView, + const ::connectivity::OSQLParseNode *pNode); + + SqlParseError InstallFields(OQueryDesignView* _pView, + const ::connectivity::OSQLParseNode* pNode, + OJoinTableView::OTableWindowMap* pTabList ); + + SqlParseError GetGroupCriteria( OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode* pSelectRoot ); + + SqlParseError GetHavingCriteria(OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode* pSelectRoot, + sal_uInt16& rLevel ); + + SqlParseError GetOrderCriteria( OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode* pParseRoot ); + + SqlParseError AddFunctionCondition(OQueryDesignView const * _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode * pCondition, + const sal_uInt16 nLevel, + bool bHaving, + bool _bAddOrOnOneLine); + + OUString quoteTableAlias(bool _bQuote, const OUString& _sAliasName, const OUString& _sQuote) + { + OUString sRet; + if ( _bQuote && !_sAliasName.isEmpty() ) + { + sRet = ::dbtools::quoteName(_sQuote,_sAliasName) + "."; + } + return sRet; + } + OUString getTableRange(const OQueryDesignView* _pView,const ::connectivity::OSQLParseNode* _pTableRef) + { + Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection(); + OUString sTableRange; + if ( _pTableRef ) + { + sTableRange = ::connectivity::OSQLParseNode::getTableRange(_pTableRef); + if ( sTableRange.isEmpty() ) + _pTableRef->parseNodeToStr(sTableRange,xConnection,nullptr,false,false); + } + return sTableRange; + } + void insertConnection(const OQueryDesignView* _pView,const EJoinType& _eJoinType, const OTableFieldDescRef& _aDragLeft, const OTableFieldDescRef& _aDragRight, bool _bNatural = false) + { + OQueryTableView* pTableView = static_cast<OQueryTableView*>(_pView->getTableView()); + OQueryTableConnection* pConn = static_cast<OQueryTableConnection*>( pTableView->GetTabConn(static_cast<OTableWindow*>(_aDragLeft->GetTabWindow()),static_cast<OTableWindow*>(_aDragRight->GetTabWindow()),true)); + + if ( !pConn ) + { + auto xInfoData = std::make_shared<OQueryTableConnectionData>(); + xInfoData->InitFromDrag(_aDragLeft, _aDragRight); + xInfoData->SetJoinType(_eJoinType); + + if ( _bNatural ) + { + xInfoData->ResetConnLines(); + xInfoData->setNatural(_bNatural); + try + { + Reference<XNameAccess> xReferencedTableColumns(xInfoData->getReferencedTable()->getColumns()); + Sequence< OUString> aSeq = xInfoData->getReferencingTable()->getColumns()->getElementNames(); + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + for(;pIter != pEnd;++pIter) + { + if ( xReferencedTableColumns->hasByName(*pIter) ) + xInfoData->AppendConnLine(*pIter,*pIter); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + ScopedVclPtrInstance< OQueryTableConnection > aInfo(pTableView, xInfoData); + // Because OQueryTableConnection never takes ownership of the data passed to it, but only remembers the pointer, + // this pointer to a local variable is not critical, as xInfoData and aInfo have the same lifetime + pTableView->NotifyTabConnection( *aInfo ); + } + else + { + OUString aSourceFieldName(_aDragLeft->GetField()); + OUString aDestFieldName(_aDragRight->GetField()); + // the connection could point on the other side + if(pConn->GetSourceWin() == _aDragRight->GetTabWindow()) + { + OUString aTmp(aSourceFieldName); + aSourceFieldName = aDestFieldName; + aDestFieldName = aTmp; + } + pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName); + pConn->UpdateLineList(); + // Modified-Flag + // SetModified(); + // and redraw + pConn->RecalcLines(); + // for the following Invalidate, the new Connection must first be able + // to determine its BoundingRect + pConn->InvalidateConnection(); + } + } + OUString ParseCondition( OQueryController& rController + ,const ::connectivity::OSQLParseNode* pCondition + ,const OUString& _sDecimal + ,const css::lang::Locale& _rLocale + ,sal_uInt32 _nStartIndex) + { + OUString aCondition; + Reference< XConnection> xConnection = rController.getConnection(); + if ( xConnection.is() ) + { + sal_uInt32 nCount = pCondition->count(); + for(sal_uInt32 i = _nStartIndex ; i < nCount ; ++i) + pCondition->getChild(i)->parseNodeToPredicateStr(aCondition, + xConnection, + rController.getNumberFormatter(), + _rLocale, + _sDecimal, + &rController.getParser().getContext()); + } + return aCondition; + } + SqlParseError FillOuterJoins(OQueryDesignView const * _pView, + const ::connectivity::OSQLParseNode* pTableRefList) + { + SqlParseError eErrorCode = eOk; + sal_uInt32 nCount = pTableRefList->count(); + bool bError = false; + for (sal_uInt32 i=0; !bError && i < nCount; ++i) + { + const ::connectivity::OSQLParseNode* pParseNode = pTableRefList->getChild(i); + const ::connectivity::OSQLParseNode* pJoinNode = nullptr; + + if ( SQL_ISRULE( pParseNode, qualified_join ) || SQL_ISRULE( pParseNode, joined_table ) || SQL_ISRULE( pParseNode, cross_union ) ) + pJoinNode = pParseNode; + else if( SQL_ISRULE(pParseNode,table_ref) + && pParseNode->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}' + pJoinNode = pParseNode->getChild(2); + + if ( pJoinNode ) + { + if ( !InsertJoin(_pView,pJoinNode) ) + bError = true; + } + } + // check if error occurred + if ( bError ) + eErrorCode = eIllegalJoin; + + return eErrorCode; + } + + /** FillDragInfo fills the field description out of the table + */ + SqlParseError FillDragInfo( const OQueryDesignView* _pView, + const ::connectivity::OSQLParseNode* pColumnRef, + OTableFieldDescRef const & _rDragInfo) + { + SqlParseError eErrorCode = eOk; + + bool bErg = false; + + OUString aTableRange,aColumnName; + ::connectivity::OSQLParseTreeIterator& rParseIter = static_cast<OQueryController&>(_pView->getController()).getParseIterator(); + rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange ); + + if ( !aTableRange.isEmpty() ) + { + OQueryTableWindow* pSTW = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( aTableRange ); + bErg = (pSTW && pSTW->ExistsField( aColumnName, _rDragInfo ) ); + } + if ( !bErg ) + { + sal_uInt16 nCntAccount; + bErg = static_cast<OQueryTableView*>(_pView->getTableView())->FindTableFromField(aColumnName, _rDragInfo, nCntAccount); + if ( !bErg ) + bErg = _pView->HasFieldByAliasName(aColumnName, _rDragInfo); + } + if ( !bErg ) + { + eErrorCode = eColumnNotFound; + OUString sError(DBA_RES(STR_QRY_COLUMN_NOT_FOUND)); + sError = sError.replaceFirst("$name$",aColumnName); + _pView->getController().appendError( sError ); + + try + { + Reference<XDatabaseMetaData> xMeta = _pView->getController().getConnection()->getMetaData(); + if ( xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers() ) + _pView->getController().appendError(DBA_RES(STR_QRY_CHECK_CASESENSITIVE)); + } + catch(Exception&) + { + } + } + + return eErrorCode; + } + OUString BuildJoinCriteria( const Reference< XConnection>& _xConnection, + const OConnectionLineDataVec* pLineDataList, + const OQueryTableConnectionData* pData) + { + OUStringBuffer aCondition; + if ( _xConnection.is() ) + { + try + { + const Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData(); + const OUString aQuote = xMetaData->getIdentifierQuoteString(); + + for (auto const& lineData : *pLineDataList) + { + if(!aCondition.isEmpty()) + aCondition.append(C_AND); + aCondition.append(quoteTableAlias(true,pData->GetAliasName(JTCS_FROM),aQuote)); + aCondition.append(::dbtools::quoteName(aQuote, lineData->GetFieldName(JTCS_FROM) )); + aCondition.append(" = "); + aCondition.append(quoteTableAlias(true,pData->GetAliasName(JTCS_TO),aQuote)); + aCondition.append(::dbtools::quoteName(aQuote, lineData->GetFieldName(JTCS_TO) )); + } + } + catch(SQLException&) + { + OSL_FAIL("Failure while building Join criteria!"); + } + } + + return aCondition.makeStringAndClear(); + } + /** JoinCycle looks for a join cycle and append it to the string + @param _xConnection the connection + @param _pEntryConn the table connection which holds the data + @param _pEntryTabTo the corresponding table window + @param _rJoin the String which will contain the resulting string + */ + void JoinCycle( const Reference< XConnection>& _xConnection, + OQueryTableConnection* _pEntryConn, + const OQueryTableWindow* _pEntryTabTo, + OUString& _rJoin ) + { + OSL_ENSURE(_pEntryConn,"TableConnection can not be null!"); + + OQueryTableConnectionData* pData = static_cast< OQueryTableConnectionData*>(_pEntryConn->GetData().get()); + if ( !(pData->GetJoinType() != INNER_JOIN && _pEntryTabTo->ExistsAVisitedConn()) ) + return; + + bool bBrace = false; + if(_rJoin.endsWith(")")) + { + bBrace = true; + _rJoin = _rJoin.replaceAt(_rJoin.getLength()-1,1, u" "); + } + _rJoin += C_AND + BuildJoinCriteria(_xConnection,&pData->GetConnLineDataList(),pData); + if(bBrace) + _rJoin += ")"; + _pEntryConn->SetVisited(true); + } + OUString BuildTable( const Reference< XConnection>& _xConnection, + const OQueryTableWindow* pEntryTab, + bool _bForce = false + ) + { + OUString aDBName(pEntryTab->GetComposedName()); + + if( _xConnection.is() ) + { + try + { + Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData(); + + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents( xMetaData, aDBName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation ); + OUString aTableListStr = ::dbtools::composeTableNameForSelect( _xConnection, sCatalog, sSchema, sTable ); + + OUString aQuote = xMetaData->getIdentifierQuoteString(); + if ( _bForce || isAppendTableAliasEnabled( _xConnection ) || pEntryTab->GetAliasName() != aDBName ) + { + aTableListStr += " "; + if ( generateAsBeforeTableAlias( _xConnection ) ) + aTableListStr += "AS "; + aTableListStr += ::dbtools::quoteName( aQuote, pEntryTab->GetAliasName() ); + } + aDBName = aTableListStr; + } + catch(const SQLException&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + return aDBName; + } + OUString BuildJoin( const Reference< XConnection>& _xConnection, + const OUString& rLh, + std::u16string_view rRh, + const OQueryTableConnectionData* pData) + { + + OUString aErg(rLh); + if ( pData->isNatural() && pData->GetJoinType() != CROSS_JOIN ) + aErg += " NATURAL "; + switch(pData->GetJoinType()) + { + case LEFT_JOIN: + aErg += " LEFT OUTER "; + break; + case RIGHT_JOIN: + aErg += " RIGHT OUTER "; + break; + case CROSS_JOIN: + OSL_ENSURE(!pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!"); + aErg += " CROSS "; + break; + case INNER_JOIN: + OSL_ENSURE(pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!"); + aErg += " INNER "; + break; + default: + aErg += " FULL OUTER "; + break; + } + aErg += OUString::Concat("JOIN ") + rRh; + if ( CROSS_JOIN != pData->GetJoinType() && !pData->isNatural() ) + { + aErg += " ON " + BuildJoinCriteria(_xConnection,&pData->GetConnLineDataList(),pData); + } + + return aErg; + } + OUString BuildJoin( const Reference< XConnection>& _xConnection, + const OQueryTableWindow* pLh, + const OQueryTableWindow* pRh, + const OQueryTableConnectionData* pData + ) + { + bool bForce = pData->GetJoinType() == CROSS_JOIN || pData->isNatural(); + return BuildJoin(_xConnection,BuildTable(_xConnection,pLh,bForce),BuildTable(_xConnection,pRh,bForce),pData); + } + OUString BuildJoin( const Reference< XConnection>& _xConnection, + const OUString &rLh, + const OQueryTableWindow* pRh, + const OQueryTableConnectionData* pData + ) + { + return BuildJoin(_xConnection,rLh,BuildTable(_xConnection,pRh),pData); + } + OUString BuildJoin( const Reference< XConnection>& _xConnection, + const OQueryTableWindow* pLh, + const OUString &rRh, + const OQueryTableConnectionData* pData + ) + { + // strict ANSI SQL: + // - does not support any bracketing of JOINS + // - supports nested joins only in the LEFT HAND SIDE + // In this case, we are trying to build a join with a nested join + // in the right hand side. + // So switch the direction of the join and both hand sides. + OQueryTableConnectionData data(*pData); + switch (data.GetJoinType()) + { + case LEFT_JOIN: + data.SetJoinType(RIGHT_JOIN); + break; + case RIGHT_JOIN: + data.SetJoinType(LEFT_JOIN); + break; + default: + // the other join types are symmetric, so nothing to change + break; + } + return BuildJoin(_xConnection, rRh, BuildTable(_xConnection,pLh), &data); + } + void addConnectionTableNames( const Reference< XConnection>& _xConnection, + const OQueryTableConnection* const pEntryConn, + std::set<OUString> &_rTableNames ) + { + // insert tables into table list to avoid double entries + const OQueryTableWindow* const pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin()); + const OQueryTableWindow* const pEntryTabTo = static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin()); + _rTableNames.insert(BuildTable(_xConnection,pEntryTabFrom)); + _rTableNames.insert(BuildTable(_xConnection,pEntryTabTo)); + } + void GetNextJoin( const Reference< XConnection>& _xConnection, + OQueryTableConnection* pEntryConn, + OQueryTableWindow const * pEntryTabTo, + OUString &aJoin, + std::set<OUString> &_rTableNames) + { + OQueryTableConnectionData* pEntryConnData = static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get()); + if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() ) + return; + + if(aJoin.isEmpty()) + { + addConnectionTableNames(_xConnection, pEntryConn, _rTableNames); + OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin()); + aJoin = BuildJoin(_xConnection,pEntryTabFrom,pEntryTabTo,pEntryConnData); + } + else if(pEntryTabTo == pEntryConn->GetDestWin()) + { + addConnectionTableNames(_xConnection, pEntryConn, _rTableNames); + aJoin = BuildJoin(_xConnection,aJoin,pEntryTabTo,pEntryConnData); + } + else if(pEntryTabTo == pEntryConn->GetSourceWin()) + { + addConnectionTableNames(_xConnection, pEntryConn, _rTableNames); + aJoin = BuildJoin(_xConnection,pEntryTabTo,aJoin,pEntryConnData); + } + + pEntryConn->SetVisited(true); + + // first search for the "to" window + const auto& rConnections = pEntryConn->GetParent()->getTableConnections(); + bool bFound = false; + for (auto const& connection : rConnections) + { + OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(connection.get()); + if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabTo || pNext->GetDestWin() == pEntryTabTo)) + { + OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabTo ? static_cast<OQueryTableWindow*>(pNext->GetDestWin()) : static_cast<OQueryTableWindow*>(pNext->GetSourceWin()); + // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited + JoinCycle(_xConnection,pNext,pEntryTab,aJoin); + if(!pNext->IsVisited()) + GetNextJoin(_xConnection, pNext, pEntryTab, aJoin, _rTableNames); + bFound = true; + } + } + + // when nothing found look for the "from" window + if(bFound) + return; + + OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin()); + for (auto const& connection : rConnections) + { + OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(connection.get()); + if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabFrom || pNext->GetDestWin() == pEntryTabFrom)) + { + OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabFrom ? static_cast<OQueryTableWindow*>(pNext->GetDestWin()) : static_cast<OQueryTableWindow*>(pNext->GetSourceWin()); + // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited + JoinCycle(_xConnection,pNext,pEntryTab,aJoin); + if(!pNext->IsVisited()) + GetNextJoin(_xConnection, pNext, pEntryTab, aJoin, _rTableNames); + } + } + } + SqlParseError InsertJoinConnection( const OQueryDesignView* _pView, + const ::connectivity::OSQLParseNode *pNode, + const EJoinType& _eJoinType, + const ::connectivity::OSQLParseNode *pLeftTable, + const ::connectivity::OSQLParseNode *pRightTable) + { + SqlParseError eErrorCode = eOk; + if (pNode->count() == 3 && // statement between brackets + SQL_ISPUNCTUATION(pNode->getChild(0),"(") && + SQL_ISPUNCTUATION(pNode->getChild(2),")")) + { + eErrorCode = InsertJoinConnection(_pView,pNode->getChild(1), _eJoinType,pLeftTable,pRightTable); + } + else if (SQL_ISRULEOR2(pNode,search_condition,boolean_term) && // AND/OR-joints: + pNode->count() == 3) + { + // only allow AND joints + if (!SQL_ISTOKEN(pNode->getChild(1),AND)) + eErrorCode = eIllegalJoinCondition; + else if ( eOk == (eErrorCode = InsertJoinConnection(_pView,pNode->getChild(0), _eJoinType,pLeftTable,pRightTable)) ) + eErrorCode = InsertJoinConnection(_pView,pNode->getChild(2), _eJoinType,pLeftTable,pRightTable); + } + else if (SQL_ISRULE(pNode,comparison_predicate)) + { + // only the comparison of columns is allowed + OSL_ENSURE(pNode->count() == 3,"OQueryDesignView::InsertJoinConnection: Error in Parse Tree"); + if (!(SQL_ISRULE(pNode->getChild(0),column_ref) && + SQL_ISRULE(pNode->getChild(2),column_ref) && + pNode->getChild(1)->getNodeType() == SQLNodeType::Equal)) + { + OUString sError(DBA_RES(STR_QRY_JOIN_COLUMN_COMPARE)); + _pView->getController().appendError( sError ); + return eIllegalJoin; + } + + OTableFieldDescRef aDragLeft = new OTableFieldDesc(); + OTableFieldDescRef aDragRight = new OTableFieldDesc(); + eErrorCode = FillDragInfo(_pView,pNode->getChild(0),aDragLeft); + if ( eOk != eErrorCode ) + return eErrorCode; + eErrorCode = FillDragInfo(_pView,pNode->getChild(2),aDragRight); + if ( eOk != eErrorCode ) + return eErrorCode; + + if ( pLeftTable ) + { + OQueryTableWindow* pLeftWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pLeftTable->getByRule(OSQLParseNode::table_ref) )); + if ( pLeftWindow == aDragLeft->GetTabWindow() ) + insertConnection(_pView,_eJoinType,aDragLeft,aDragRight); + else + insertConnection(_pView,_eJoinType,aDragRight,aDragLeft); + } + else + insertConnection(_pView,_eJoinType,aDragLeft,aDragRight); + } + else + eErrorCode = eIllegalJoin; + return eErrorCode; + } + bool GetInnerJoinCriteria( const OQueryDesignView* _pView, + const ::connectivity::OSQLParseNode *pCondition) + { + return InsertJoinConnection(_pView,pCondition, INNER_JOIN,nullptr,nullptr) != eOk; + } + OUString GenerateSelectList( const OQueryDesignView* _pView, + OTableFields& _rFieldList, + bool bAlias) + { + Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection(); + if ( !xConnection.is() ) + return OUString(); + + OUStringBuffer aTmpStr,aFieldListStr; + + bool bAsterisk = false; + int nVis = 0; + for (auto const& field : _rFieldList) + { + if ( field->IsVisible() ) + { + if ( field->GetField().toChar() == '*' ) + bAsterisk = true; + ++nVis; + } + } + if(nVis == 1) + bAsterisk = false; + + try + { + const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); + const OUString aQuote = xMetaData->getIdentifierQuoteString(); + + OJoinTableView::OTableWindowMap& rTabList = _pView->getTableView()->GetTabWinMap(); + + for (auto const& field : _rFieldList) + { + OUString rFieldName = field->GetField(); + if ( !rFieldName.isEmpty() && field->IsVisible() ) + { + aTmpStr = ""; + const OUString rAlias = field->GetAlias(); + const OUString rFieldAlias = field->GetFieldAlias(); + + aTmpStr.append(quoteTableAlias((bAlias || bAsterisk),rAlias,aQuote)); + + // if we have a none numeric field, the table alias could be in the name + // otherwise we are not allowed to do this (e.g. 0.1 * PRICE ) + if ( !field->isOtherFunction() ) + { + // we have to look if we have alias.* here but before we have to check if the column doesn't already exist + OTableFieldDescRef aInfo = new OTableFieldDesc(); + for (auto const& table : rTabList) + { + OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get()); + + if ( pTabWin->ExistsField( rFieldName, aInfo ) ) + { + rFieldName = aInfo->GetField(); + break; + } + } + if ( ( rFieldName.toChar() != '*' ) && ( rFieldName.indexOf( aQuote ) == -1 ) ) + { + OSL_ENSURE(!field->GetTable().isEmpty(),"No table field name!"); + aTmpStr.append(::dbtools::quoteName(aQuote, rFieldName)); + } + else + aTmpStr.append(rFieldName); + } + else + aTmpStr.append(rFieldName); + + if ( field->isAggregateFunction() ) + { + OSL_ENSURE(!field->GetFunction().isEmpty(),"Function name must not be empty! ;-("); + OUStringBuffer aTmpStr2( field->GetFunction() + "(" + aTmpStr + ")"); + aTmpStr = aTmpStr2; + } + + if (!rFieldAlias.isEmpty() && + (rFieldName.toChar() != '*' || + field->isNumericOrAggregateFunction() || + field->isOtherFunction())) + { + aTmpStr.append(" AS "); + aTmpStr.append(::dbtools::quoteName(aQuote, rFieldAlias)); + } + aFieldListStr.append(aTmpStr); + aTmpStr.setLength(0); + aFieldListStr.append(", "); + } + } + if(!aFieldListStr.isEmpty()) + aFieldListStr.setLength(aFieldListStr.getLength()-2); + } + catch(SQLException&) + { + OSL_FAIL("Failure while building select list!"); + } + return aFieldListStr.makeStringAndClear(); + } + bool GenerateCriterias( OQueryDesignView const * _pView, + OUStringBuffer& rRetStr, + OUStringBuffer& rHavingStr, + OTableFields& _rFieldList, + bool bMulti ) + { + Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection(); + if(!xConnection.is()) + return false; + + OUString aFieldName,aCriteria,aWhereStr,aHavingStr,aWork/*,aOrderStr*/; + // print line by line joined with AND + sal_uInt16 nMaxCriteria = 0; + for (auto const& field : _rFieldList) + { + nMaxCriteria = std::max<sal_uInt16>(nMaxCriteria,static_cast<sal_uInt16>(field->GetCriteria().size())); + } + try + { + const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); + const OUString aQuote = xMetaData->getIdentifierQuoteString(); + const IParseContext& rContext = static_cast<OQueryController&>(_pView->getController()).getParser().getContext(); + // * must not contain a filter : have I already shown the correct warning ? + bool bCritsOnAsteriskWarning = false; // ** TMFS ** + + for (sal_uInt16 i=0 ; i < nMaxCriteria ; i++) + { + aHavingStr.clear(); + aWhereStr.clear(); + + for (auto const& field : _rFieldList) + { + aFieldName = field->GetField(); + + if (aFieldName.isEmpty()) + continue; + aCriteria = field->GetCriteria( i ); + if ( !aCriteria.isEmpty() ) + { + // * is not allowed to contain any filter, only when used in combination an aggregate function + if ( aFieldName.toChar() == '*' && field->isNoneFunction() ) + { + // only show the messagebox the first time + if (!bCritsOnAsteriskWarning) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(_pView->GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + DBA_RES(STR_QRY_CRITERIA_ON_ASTERISK))); + xBox->run(); + } + bCritsOnAsteriskWarning = true; + continue; + } + aWork = quoteTableAlias(bMulti,field->GetAlias(),aQuote); + + if ( (field->GetFunctionType() & (FKT_OTHER|FKT_NUMERIC)) || (aFieldName.toChar() == '*') ) + aWork += aFieldName; + else + aWork += ::dbtools::quoteName(aQuote, aFieldName); + + if ( field->isAggregateFunction() || field->IsGroupBy() ) + { + if (aHavingStr.isEmpty()) // no more criteria + aHavingStr += "("; // bracket + else + aHavingStr += C_AND; + + if ( field->isAggregateFunction() ) + { + OSL_ENSURE(!field->GetFunction().isEmpty(),"No function name for aggregate given!"); + aHavingStr += field->GetFunction() + "(" + aWork + ")"; // bracket + } + else + aHavingStr += aWork; + + OUString aErrorMsg; + Reference<XPropertySet> xColumn; + std::unique_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(field,aCriteria,aErrorMsg,xColumn)); + if (pParseNode) + { + if (bMulti && !(field->isOtherFunction() || (aFieldName.toChar() == '*'))) + pParseNode->replaceNodeValue(field->GetAlias(),aFieldName); + OUString sHavingStr = aHavingStr; + + sal_uInt32 nCount = pParseNode->count(); + for( sal_uInt32 node = 1 ; node < nCount ; ++node) + pParseNode->getChild(node)->parseNodeToStr( sHavingStr, + xConnection, + &rContext, + false, + !field->isOtherFunction()); + aHavingStr = sHavingStr; + } + else + aHavingStr += aCriteria; + } + else + { + if ( aWhereStr.isEmpty() ) // no more criteria + aWhereStr += "("; // bracket + else + aWhereStr += C_AND; + + aWhereStr += " "; + // aCriteria could have some German numbers so I have to be sure here + OUString aErrorMsg; + Reference<XPropertySet> xColumn; + std::unique_ptr< ::connectivity::OSQLParseNode> pParseNode( _pView->getPredicateTreeFromEntry(field,aCriteria,aErrorMsg,xColumn)); + if (pParseNode) + { + if (bMulti && !(field->isOtherFunction() || (aFieldName.toChar() == '*'))) + pParseNode->replaceNodeValue(field->GetAlias(),aFieldName); + OUString aWhere = aWhereStr; + pParseNode->parseNodeToStr( aWhere, + xConnection, + &rContext, + false, + !field->isOtherFunction() ); + aWhereStr = aWhere; + } + else + { + aWhereStr += aWork + "=" + aCriteria; + } + } + } + // only once for each field + else if ( !i && field->isCondition() ) + { + if (aWhereStr.isEmpty()) // no more criteria + aWhereStr += "("; // bracket + else + aWhereStr += C_AND; + aWhereStr += field->GetField(); + } + } + if (!aWhereStr.isEmpty()) + { + aWhereStr += ")"; // close bracket for the AND branch + if (!rRetStr.isEmpty()) // are there conditions on the field? + rRetStr.append(C_OR); + else // open bracket for the OR branch + rRetStr.append('('); + rRetStr.append(aWhereStr); + } + if (!aHavingStr.isEmpty()) + { + aHavingStr += ")"; // close bracket for the AND branch + if (!rHavingStr.isEmpty()) // are there conditions on the field? + rHavingStr.append(C_OR); + else // Open bracket for the OR branch + rHavingStr.append('('); + rHavingStr.append(aHavingStr); + } + } + + if (!rRetStr.isEmpty()) + rRetStr.append(')'); // close bracket for the OR branch + if (!rHavingStr.isEmpty()) + rHavingStr.append(')'); // close bracket for the OR branch + } + catch(SQLException&) + { + OSL_FAIL("Failure while building where clause!"); + } + return true; + } + SqlParseError GenerateOrder( OQueryDesignView const * _pView, + OTableFields& _rFieldList, + bool bMulti, + OUString& _rsRet) + { + const OQueryController& rController = static_cast<OQueryController&>(_pView->getController()); + const Reference< XConnection>& xConnection = rController.getConnection(); + if ( !xConnection.is() ) + return eNoConnection; + + SqlParseError eErrorCode = eOk; + + OUString aColumnName; + OUString aWorkStr; + try + { + const bool bColumnAliasInOrderBy = rController.getSdbMetaData().supportsColumnAliasInOrderBy(); + Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); + OUString aQuote = xMetaData->getIdentifierQuoteString(); + // * must not contain filter - have I already shown the warning? + bool bCritsOnAsteriskWarning = false; // ** TMFS ** + for (auto const& field : _rFieldList) + { + EOrderDir eOrder = field->GetOrderDir(); + // only create a sort expression when the table name and the sort criteria are defined + // otherwise they will be built in GenerateCriteria + if ( eOrder != ORDER_NONE ) + { + aColumnName = field->GetField(); + if(aColumnName.toChar() == '*') + { + // only show the MessageBox the first time + if (!bCritsOnAsteriskWarning) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(_pView->GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + DBA_RES(STR_QRY_ORDERBY_ON_ASTERISK))); + xBox->run(); + } + bCritsOnAsteriskWarning = true; + continue; + } + + if ( bColumnAliasInOrderBy && !field->GetFieldAlias().isEmpty() ) + { + aWorkStr += ::dbtools::quoteName(aQuote, field->GetFieldAlias()); + } + else if ( field->isNumericOrAggregateFunction() ) + { + OSL_ENSURE(!field->GetFunction().isEmpty(),"Function name cannot be empty! ;-("); + aWorkStr += field->GetFunction() + "(" + + quoteTableAlias( + bMulti, field->GetAlias(), aQuote); + // only quote column name when we don't have a numeric + if ( field->isNumeric() ) + aWorkStr += aColumnName; + else + aWorkStr += ::dbtools::quoteName(aQuote, aColumnName); + + aWorkStr += ")"; + } + else if ( field->isOtherFunction() ) + { + aWorkStr += aColumnName; + } + else + { + aWorkStr += quoteTableAlias(bMulti,field->GetAlias(),aQuote) + ::dbtools::quoteName(aQuote, aColumnName); + } + aWorkStr += OUString::Concat(" ") + o3tl::getToken( u";ASC;DESC", static_cast<sal_uInt16>(eOrder), ';' ) + ","; + } + } + + { + OUString sTemp(comphelper::string::stripEnd(aWorkStr, ',')); + aWorkStr = sTemp; + } + + if ( !aWorkStr.isEmpty() ) + { + const sal_Int32 nMaxOrder = xMetaData->getMaxColumnsInOrderBy(); + if ( nMaxOrder && nMaxOrder < comphelper::string::getTokenCount(aWorkStr, ',') ) + eErrorCode = eStatementTooLong; + else + { + _rsRet = " ORDER BY " + aWorkStr; + } + } + } + catch(SQLException&) + { + OSL_FAIL("Failure while building group by!"); + } + + return eErrorCode; + } + + void GenerateInnerJoinCriterias(const Reference< XConnection>& _xConnection, + OUString& _rJoinCrit, + const std::vector<VclPtr<OTableConnection> >& _rConnList) + { + for (auto const& connection : _rConnList) + { + const OQueryTableConnection* pEntryConn = static_cast<const OQueryTableConnection*>(connection.get()); + OQueryTableConnectionData* pEntryConnData = static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get()); + if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() ) + { + if(!_rJoinCrit.isEmpty()) + _rJoinCrit += C_AND; + _rJoinCrit += BuildJoinCriteria(_xConnection,&pEntryConnData->GetConnLineDataList(),pEntryConnData); + } + } + } + void searchAndAppendName(const Reference< XConnection>& _xConnection, + const OQueryTableWindow* _pTableWindow, + std::set<OUString>& _rTableNames, + OUString& _rsTableListStr + ) + { + OUString sTabName(BuildTable(_xConnection,_pTableWindow)); + + if(_rTableNames.insert(sTabName).second) + { + _rsTableListStr += sTabName + ","; + } + } + OUString GenerateFromClause( const Reference< XConnection>& _xConnection, + const OQueryTableView::OTableWindowMap* pTabList, + const std::vector<VclPtr<OTableConnection> >& rConnList + ) + { + + OUString aTableListStr; + // used to avoid putting a table twice in FROM clause + std::set<OUString> aTableNames; + + // generate outer join clause in from + if(!rConnList.empty()) + { + std::map<OTableWindow*,sal_Int32> aConnectionCount; + auto aEnd = rConnList.end(); + for (auto const& connection : rConnList) + { + static_cast<OQueryTableConnection*>(connection.get())->SetVisited(false); + ++aConnectionCount[connection->GetSourceWin()]; + ++aConnectionCount[connection->GetDestWin()]; + } + std::multimap<sal_Int32 , OTableWindow*> aMulti; + for (auto const& elem : aConnectionCount) + { + aMulti.emplace(elem.second,elem.first); + } + + const bool bUseEscape = ::dbtools::getBooleanDataSourceSetting( _xConnection, PROPERTY_OUTERJOINESCAPE ); + std::multimap<sal_Int32 , OTableWindow*>::const_reverse_iterator aRIter = aMulti.rbegin(); + std::multimap<sal_Int32 , OTableWindow*>::const_reverse_iterator aREnd = aMulti.rend(); + for(;aRIter != aREnd;++aRIter) + { + auto aConIter = aRIter->second->getTableView()->getTableConnections(aRIter->second); + for(;aConIter != aEnd;++aConIter) + { + OQueryTableConnection* pEntryConn = static_cast<OQueryTableConnection*>((*aConIter).get()); + if(!pEntryConn->IsVisited() && pEntryConn->GetSourceWin() == aRIter->second ) + { + OUString aJoin; + GetNextJoin(_xConnection, + pEntryConn, + static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin()), + aJoin, + aTableNames); + + if(!aJoin.isEmpty()) + { + OUString aStr; + switch(static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get())->GetJoinType()) + { + case LEFT_JOIN: + case RIGHT_JOIN: + case FULL_JOIN: + { + // create outer join + if ( bUseEscape ) + aStr += "{ oj "; + aStr += aJoin; + if ( bUseEscape ) + aStr += " }"; + } + break; + default: + aStr += aJoin; + break; + } + aStr += ","; + aTableListStr += aStr; + } + } + } + } + + // and now all inner joins + // these are implemented as + // "FROM tbl1, tbl2 WHERE tbl1.col1=tlb2.col2" + // rather than + // "FROM tbl1 INNER JOIN tbl2 ON tbl1.col1=tlb2.col2" + for (auto const& connection : rConnList) + { + OQueryTableConnection* pEntryConn = static_cast<OQueryTableConnection*>(connection.get()); + if(!pEntryConn->IsVisited()) + { + searchAndAppendName(_xConnection, + static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin()), + aTableNames, + aTableListStr); + + searchAndAppendName(_xConnection, + static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin()), + aTableNames, + aTableListStr); + } + } + } + // all tables that haven't a connection to anyone + for (auto const& table : *pTabList) + { + const OQueryTableWindow* pEntryTab = static_cast<const OQueryTableWindow*>(table.second.get()); + if(!pEntryTab->ExistsAConn()) + { + aTableListStr += BuildTable(_xConnection,pEntryTab) + ","; + } + } + + if(!aTableListStr.isEmpty()) + aTableListStr = aTableListStr.replaceAt(aTableListStr.getLength()-1,1, u"" ); + return aTableListStr; + } + OUString GenerateGroupBy(const OQueryDesignView* _pView,OTableFields& _rFieldList, bool bMulti ) + { + OQueryController& rController = static_cast<OQueryController&>(_pView->getController()); + const Reference< XConnection> xConnection = rController.getConnection(); + if(!xConnection.is()) + return OUString(); + + std::map< OUString,bool> aGroupByNames; + + OUString aGroupByStr; + try + { + const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); + const OUString aQuote = xMetaData->getIdentifierQuoteString(); + + for (auto const& field : _rFieldList) + { + if ( field->IsGroupBy() ) + { + OSL_ENSURE(!field->GetField().isEmpty(),"No Field Name available!;-("); + OUString sGroupByPart = quoteTableAlias(bMulti,field->GetAlias(),aQuote); + + // only quote the field name when it isn't calculated + if ( field->isNoneFunction() ) + { + sGroupByPart += ::dbtools::quoteName(aQuote, field->GetField()); + } + else + { + OUString aTmp = field->GetField(); + OUString aErrorMsg; + Reference<XPropertySet> xColumn; + std::unique_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(field,aTmp,aErrorMsg,xColumn)); + if (pParseNode) + { + OUString sGroupBy; + pParseNode->getChild(0)->parseNodeToStr( sGroupBy, + xConnection, + &rController.getParser().getContext(), + false, + !field->isOtherFunction()); + sGroupByPart += sGroupBy; + } + else + sGroupByPart += field->GetField(); + } + if ( aGroupByNames.find(sGroupByPart) == aGroupByNames.end() ) + { + aGroupByNames.emplace(sGroupByPart,true); + aGroupByStr += sGroupByPart + ","; + } + } + } + if ( !aGroupByStr.isEmpty() ) + { + aGroupByStr = aGroupByStr.replaceAt(aGroupByStr.getLength()-1,1, u" " ); + OUString aGroupByStr2 = " GROUP BY " + aGroupByStr; + aGroupByStr = aGroupByStr2; + } + } + catch(SQLException&) + { + OSL_FAIL("Failure while building group by!"); + } + return aGroupByStr; + } + SqlParseError GetORCriteria(OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode * pCondition, + sal_uInt16& nLevel , + bool bHaving = false, + bool bAddOrOnOneLine = false); + SqlParseError GetSelectionCriteria( OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode* pNode, + sal_uInt16& rLevel ) + { + if (!pNode || !SQL_ISRULE(pNode, select_statement)) + return eNoSelectStatement; + + // nyi: more checking for the correct structure! + pNode = pNode->getChild(3)->getChild(1); + // no where clause found + if (!pNode || pNode->isLeaf()) + return eOk; + + // Next free sentence... + SqlParseError eErrorCode = eOk; + ::connectivity::OSQLParseNode * pCondition = pNode->getChild(1); + if ( pCondition ) // no where clause + { + // now we have to check the other conditions + // first make the logical easier + ::connectivity::OSQLParseNode::negateSearchCondition(pCondition); + ::connectivity::OSQLParseNode *pNodeTmp = pNode->getChild(1); + + ::connectivity::OSQLParseNode::disjunctiveNormalForm(pNodeTmp); + pNodeTmp = pNode->getChild(1); + ::connectivity::OSQLParseNode::absorptions(pNodeTmp); + pNodeTmp = pNode->getChild(1); + // compress sort the criteria @see https://bz.apache.org/ooo/show_bug.cgi?id=24079 + OSQLParseNode::compress(pNodeTmp); + pNodeTmp = pNode->getChild(1); + + // first extract the inner joins conditions + GetInnerJoinCriteria(_pView,pNodeTmp); + // now simplify again, join are checked in ComparisonPredicate + ::connectivity::OSQLParseNode::absorptions(pNodeTmp); + pNodeTmp = pNode->getChild(1); + + // it could happen that pCondition is not more valid + eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pNodeTmp, rLevel); + } + return eErrorCode; + } + SqlParseError GetANDCriteria( OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode * pCondition, + sal_uInt16& nLevel, + bool bHaving, + bool bAddOrOnOneLine); + SqlParseError ComparisonPredicate(OQueryDesignView const * _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode * pCondition, + const sal_uInt16 nLevel, + bool bHaving, + bool bAddOrOnOneLine); + SqlParseError GetORCriteria(OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode * pCondition, + sal_uInt16& nLevel , + bool bHaving, + bool bAddOrOnOneLine) + { + SqlParseError eErrorCode = eOk; + + // round brackets around the printout + if (pCondition->count() == 3 && + SQL_ISPUNCTUATION(pCondition->getChild(0),"(") && + SQL_ISPUNCTUATION(pCondition->getChild(2),")")) + { + eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pCondition->getChild(1),nLevel,bHaving,bAddOrOnOneLine); + } + // OR condition + // a searchcondition can only look like this: search_condition SQL_TOKEN_OR boolean_term + else if (SQL_ISRULE(pCondition,search_condition)) + { + for (int i = 0; i < 3 && eErrorCode == eOk ; i+=2) + { + const ::connectivity::OSQLParseNode* pChild = pCondition->getChild(i); + if ( SQL_ISRULE(pChild,search_condition) ) + eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pChild,nLevel,bHaving,bAddOrOnOneLine); + else + { + eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pChild, nLevel,bHaving, i != 0 && bAddOrOnOneLine); + if ( !bAddOrOnOneLine) + nLevel++; + } + } + } + else + eErrorCode = GetANDCriteria( _pView,_pSelectionBrw,pCondition, nLevel, bHaving,bAddOrOnOneLine ); + + return eErrorCode; + } + bool CheckOrCriteria(const ::connectivity::OSQLParseNode* _pCondition,::connectivity::OSQLParseNode* _pFirstColumnRef) + { + bool bRet = true; + ::connectivity::OSQLParseNode* pFirstColumnRef = _pFirstColumnRef; + for (size_t i = 0; bRet && i < _pCondition->count(); ++i) + { + const ::connectivity::OSQLParseNode* pChild = _pCondition->getChild(i); + if ( pChild->isToken() ) + continue; + else if ( SQL_ISRULE(pChild,search_condition) ) + bRet = CheckOrCriteria(pChild,pFirstColumnRef); + else + { + // this is a simple way to test columns are the same, may be we have to adjust this algo a little bit in future. :-) + ::connectivity::OSQLParseNode* pSecondColumnRef = pChild->getByRule(::connectivity::OSQLParseNode::column_ref); + if ( pFirstColumnRef && pSecondColumnRef ) + bRet = *pFirstColumnRef == *pSecondColumnRef; + else if ( !pFirstColumnRef ) + pFirstColumnRef = pSecondColumnRef; + } + } + return bRet; + } + SqlParseError GetANDCriteria( OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode * pCondition, + sal_uInt16& nLevel, + bool bHaving, + bool bAddOrOnOneLine) + { + const css::lang::Locale aLocale = _pView->getLocale(); + const OUString sDecimal = _pView->getDecimalSeparator(); + + // I will need a cast pointer to my css::sdbcx::Container + OQueryController& rController = static_cast<OQueryController&>(_pView->getController()); + SqlParseError eErrorCode = eOk; + + // round brackets + if (SQL_ISRULE(pCondition,boolean_primary)) + { + // check if we have to put the or criteria on one line. + const ::connectivity::OSQLParseNode* pSearchCondition = pCondition->getChild(1); + bool bMustAddOrOnOneLine = CheckOrCriteria(pSearchCondition,nullptr); + if ( SQL_ISRULE( pSearchCondition, search_condition) ) // we have a or + { + _pSelectionBrw->DuplicateConditionLevel( nLevel); + eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(0), nLevel,bHaving,bMustAddOrOnOneLine ); + if ( eErrorCode == eOk ) + { + ++nLevel; + eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(2), nLevel,bHaving,bMustAddOrOnOneLine ); + } + } + else + eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition, nLevel,bHaving,bMustAddOrOnOneLine ); + } + // The first element is (again) an AND condition + else if ( SQL_ISRULE(pCondition,boolean_term) ) + { + OSL_ENSURE(pCondition->count() == 3,"Illegal definition of boolean_term"); + eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pCondition->getChild(0), nLevel,bHaving,bAddOrOnOneLine ); + if ( eErrorCode == eOk ) + eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pCondition->getChild(2), nLevel,bHaving,bAddOrOnOneLine ); + } + else if (SQL_ISRULE( pCondition, comparison_predicate)) + { + eErrorCode = ComparisonPredicate(_pView,_pSelectionBrw,pCondition,nLevel,bHaving,bAddOrOnOneLine); + } + else if( SQL_ISRULE(pCondition,like_predicate) ) + { + const ::connectivity::OSQLParseNode* pValueExp = pCondition->getChild(0); + if (SQL_ISRULE(pValueExp, column_ref ) ) + { + OUString aCondition; + Reference< XConnection> xConnection = rController.getConnection(); + if ( xConnection.is() ) + { + OUString aColumnName; + // the international doesn't matter I have a string + pCondition->parseNodeToPredicateStr(aCondition, + xConnection, + rController.getNumberFormatter(), + aLocale, + sDecimal, + &rController.getParser().getContext()); + + pValueExp->parseNodeToPredicateStr( aColumnName, + xConnection, + rController.getNumberFormatter(), + aLocale, + sDecimal, + &rController.getParser().getContext()); + + // don't display the column name + aCondition = aCondition.copy(aColumnName.getLength()); + aCondition = aCondition.trim(); + } + + OTableFieldDescRef aDragLeft = new OTableFieldDesc(); + if ( eOk == ( eErrorCode = FillDragInfo(_pView,pValueExp,aDragLeft) )) + { + if ( bHaving ) + aDragLeft->SetGroupBy(true); + _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine); + } + } + else if(SQL_ISRULEOR3(pValueExp, general_set_fct, set_fct_spec, position_exp) || + SQL_ISRULEOR3(pValueExp, extract_exp, fold, char_substring_fct) || + SQL_ISRULEOR2(pValueExp, length_exp, char_value_fct)) + { + AddFunctionCondition( _pView, + _pSelectionBrw, + pCondition, + nLevel, + bHaving, + bAddOrOnOneLine); + } + else + { + eErrorCode = eNoColumnInLike; + OUString sError(DBA_RES(STR_QRY_LIKE_LEFT_NO_COLUMN)); + _pView->getController().appendError( sError ); + } + } + else if( SQL_ISRULEOR2(pCondition,test_for_null,in_predicate) + || SQL_ISRULEOR2(pCondition,all_or_any_predicate,between_predicate)) + { + if ( SQL_ISRULEOR2(pCondition->getChild(0), set_fct_spec , general_set_fct ) ) + { + AddFunctionCondition( _pView, + _pSelectionBrw, + pCondition, + nLevel, + bHaving, + bAddOrOnOneLine); + } + else if ( SQL_ISRULE(pCondition->getChild(0), column_ref ) ) + { + // parse condition + OUString sCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,1); + OTableFieldDescRef aDragLeft = new OTableFieldDesc(); + if ( eOk == ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(0),aDragLeft)) ) + { + if ( bHaving ) + aDragLeft->SetGroupBy(true); + _pSelectionBrw->AddCondition(aDragLeft, sCondition, nLevel,bAddOrOnOneLine); + } + } + else + { + // Parse the function condition + OUString sCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,1); + Reference< XConnection> xConnection = rController.getConnection(); + // the international doesn't matter I have a string + OUString sName; + pCondition->getChild(0)->parseNodeToPredicateStr(sName, + xConnection, + rController.getNumberFormatter(), + aLocale, + sDecimal, + &rController.getParser().getContext()); + + OTableFieldDescRef aDragLeft = new OTableFieldDesc(); + aDragLeft->SetField(sName); + aDragLeft->SetFunctionType(FKT_OTHER); + + if ( bHaving ) + aDragLeft->SetGroupBy(true); + _pSelectionBrw->AddCondition(aDragLeft, sCondition, nLevel,bAddOrOnOneLine); + } + } + else if( SQL_ISRULEOR2(pCondition,existence_test,unique_test) ) + { + // Parse the function condition + OUString aCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,0); + + OTableFieldDescRef aDragLeft = new OTableFieldDesc(); + aDragLeft->SetField(aCondition); + aDragLeft->SetFunctionType(FKT_CONDITION); + + eErrorCode = _pSelectionBrw->InsertField(aDragLeft,BROWSER_INVALIDID,false).is() ? eOk : eTooManyColumns; + } + else //! TODO not supported yet + eErrorCode = eStatementTooComplex; + // Pass on the error code + return eErrorCode; + } + SqlParseError AddFunctionCondition(OQueryDesignView const * _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode * pCondition, + const sal_uInt16 nLevel, + bool bHaving, + bool bAddOrOnOneLine) + { + SqlParseError eErrorCode = eOk; + OQueryController& rController = static_cast<OQueryController&>(_pView->getController()); + + OSQLParseNode* pFunction = pCondition->getChild(0); + + OSL_ENSURE(SQL_ISRULEOR3(pFunction, general_set_fct, set_fct_spec, position_exp) || + SQL_ISRULEOR3(pFunction, extract_exp, fold, char_substring_fct) || + SQL_ISRULEOR2(pFunction,length_exp,char_value_fct), + "Illegal call!"); + + Reference< XConnection> xConnection = rController.getConnection(); + if(xConnection.is()) + { + OUString aCondition; + OUString aColumnName; + OTableFieldDescRef aDragLeft = new OTableFieldDesc(); + pCondition->parseNodeToPredicateStr(aCondition, + xConnection, + rController.getNumberFormatter(), + _pView->getLocale(), + _pView->getDecimalSeparator(), + &rController.getParser().getContext()); + + pFunction->parseNodeToStr( aColumnName, + xConnection, + &rController.getParser().getContext(), + true); // quote is to true because we need quoted elements inside the function + // don't display the column name + aCondition = aCondition.copy(aColumnName.getLength()); + aCondition = aCondition.trim(); + if ( aCondition.startsWith("=") ) // ignore the equal sign + aCondition = aCondition.copy(1); + + if ( SQL_ISRULE(pFunction, general_set_fct ) ) + { + sal_Int32 nFunctionType = FKT_AGGREGATE; + OSQLParseNode* pParamNode = pFunction->getChild(pFunction->count()-2); + if ( pParamNode && pParamNode->getTokenValue().toChar() == '*' ) + { + OJoinTableView::OTableWindowMap& rTabList = _pView->getTableView()->GetTabWinMap(); + for (auto const& table : rTabList) + { + OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get()); + if (pTabWin->ExistsField( "*", aDragLeft )) + { + aDragLeft->SetAlias(OUString()); + aDragLeft->SetTable(OUString()); + break; + } + } + } + else if (pParamNode) + { + eErrorCode = FillDragInfo(_pView,pParamNode,aDragLeft); + if ( eOk != eErrorCode && SQL_ISRULE(pParamNode,num_value_exp)) + { + OUString sParameterValue; + pParamNode->parseNodeToStr( sParameterValue, + xConnection, + &rController.getParser().getContext()); + nFunctionType |= FKT_NUMERIC; + aDragLeft->SetField(sParameterValue); + eErrorCode = eOk; + } + } + aDragLeft->SetFunctionType(nFunctionType); + if ( bHaving ) + aDragLeft->SetGroupBy(true); + aDragLeft->SetFunction(aColumnName.getToken(0, '(')); + } + else + { + // for an unknown function we write the whole text in the field + aDragLeft->SetField(aColumnName); + if(bHaving) + aDragLeft->SetGroupBy(true); + aDragLeft->SetFunctionType(FKT_OTHER|FKT_NUMERIC); + } + _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine); + } + + return eErrorCode; + } + SqlParseError ComparisonPredicate(OQueryDesignView const * _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode * pCondition, + const sal_uInt16 nLevel, + bool bHaving + ,bool bAddOrOnOneLine) + { + SqlParseError eErrorCode = eOk; + OQueryController& rController = static_cast<OQueryController&>(_pView->getController()); + + OSL_ENSURE(SQL_ISRULE( pCondition, comparison_predicate),"ComparisonPredicate: pCondition is not a Comparison Predicate"); + if ( SQL_ISRULE(pCondition->getChild(0), column_ref ) + || SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref) ) + { + OUString aCondition; + OTableFieldDescRef aDragLeft = new OTableFieldDesc(); + + if ( SQL_ISRULE(pCondition->getChild(0), column_ref ) && SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref ) ) + { + OTableFieldDescRef aDragRight = new OTableFieldDesc(); + eErrorCode = FillDragInfo(_pView,pCondition->getChild(0),aDragLeft); + if (eOk != eErrorCode) + return eErrorCode; + eErrorCode = FillDragInfo(_pView,pCondition->getChild(2),aDragRight); + if (eOk != eErrorCode) + return eErrorCode; + + OQueryTableConnection* pConn = static_cast<OQueryTableConnection*>( + _pView->getTableView()->GetTabConn(static_cast<OQueryTableWindow*>(aDragLeft->GetTabWindow()), + static_cast<OQueryTableWindow*>(aDragRight->GetTabWindow()), + true)); + if ( pConn ) + { + OConnectionLineDataVec& rLineDataList = pConn->GetData()->GetConnLineDataList(); + for (auto const& lineData : rLineDataList) + { + if(lineData->GetSourceFieldName() == aDragLeft->GetField() || + lineData->GetDestFieldName() == aDragLeft->GetField() ) + return eOk; + } + } + } + + sal_uInt32 nPos = 0; + if(SQL_ISRULE(pCondition->getChild(0), column_ref )) + { + nPos = 0; + sal_uInt32 i=1; + + // don't display the equal + if (pCondition->getChild(i)->getNodeType() == SQLNodeType::Equal) + i++; + + // parse the condition + aCondition = ParseCondition(rController + ,pCondition + ,_pView->getDecimalSeparator() + ,_pView->getLocale() + ,i); + } + else if( SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref ) ) + { + nPos = pCondition->count()-1; + + sal_Int32 i = static_cast<sal_Int32>(pCondition->count() - 2); + switch (pCondition->getChild(i)->getNodeType()) + { + case SQLNodeType::Equal: + // don't display the equal + i--; + break; + case SQLNodeType::Less: + // take the opposite as we change the order + i--; + aCondition += ">"; + break; + case SQLNodeType::LessEq: + // take the opposite as we change the order + i--; + aCondition += ">="; + break; + case SQLNodeType::Great: + // take the opposite as we change the order + i--; + aCondition += "<"; + break; + case SQLNodeType::GreatEq: + // take the opposite as we change the order + i--; + aCondition += "<="; + break; + default: + break; + } + + // go backward + Reference< XConnection> xConnection = rController.getConnection(); + if(xConnection.is()) + { + for (; i >= 0; i--) + pCondition->getChild(i)->parseNodeToPredicateStr(aCondition, + xConnection, + rController.getNumberFormatter(), + _pView->getLocale(), + _pView->getDecimalSeparator(), + &rController.getParser().getContext()); + } + } + // else ??? + + if( eOk == ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(nPos),aDragLeft))) + { + if(bHaving) + aDragLeft->SetGroupBy(true); + _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine); + } + } + else if( SQL_ISRULEOR2(pCondition->getChild(0), set_fct_spec , general_set_fct ) ) + { + AddFunctionCondition( _pView, + _pSelectionBrw, + pCondition, + nLevel, + bHaving, + bAddOrOnOneLine); + } + else // it can only be an Expr + { + OUString aName,aCondition; + + // Field name + Reference< XConnection> xConnection = rController.getConnection(); + if(xConnection.is()) + { + ::connectivity::OSQLParseNode *pLhs = pCondition->getChild(0); + ::connectivity::OSQLParseNode *pRhs = pCondition->getChild(2); + pLhs->parseNodeToStr(aName, + xConnection, + &rController.getParser().getContext(), + true); + // Criteria + aCondition = pCondition->getChild(1)->getTokenValue(); + pRhs->parseNodeToPredicateStr(aCondition, + xConnection, + rController.getNumberFormatter(), + _pView->getLocale(), + _pView->getDecimalSeparator(), + &rController.getParser().getContext()); + } + + OTableFieldDescRef aDragLeft = new OTableFieldDesc(); + aDragLeft->SetField(aName); + aDragLeft->SetFunctionType(FKT_OTHER|FKT_NUMERIC); + // and add it on + _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine); + } + return eErrorCode; + } + + OQueryTableWindow* lcl_findColumnInTables( const OUString& _rColumName, const OJoinTableView::OTableWindowMap& _rTabList, OTableFieldDescRef const & _rInfo ) + { + for (auto const& table : _rTabList) + { + OQueryTableWindow* pTabWin = static_cast< OQueryTableWindow* >( table.second.get() ); + if ( pTabWin && pTabWin->ExistsField( _rColumName, _rInfo ) ) + return pTabWin; + } + return nullptr; + } + + void InsertColumnRef(const OQueryDesignView* _pView, + const ::connectivity::OSQLParseNode * pColumnRef, + OUString& aColumnName, + const OUString& aColumnAlias, + OUString& aTableRange, + OTableFieldDescRef const & _raInfo, + OJoinTableView::OTableWindowMap const * pTabList) + { + + // Put the table names together + ::connectivity::OSQLParseTreeIterator& rParseIter = static_cast<OQueryController&>(_pView->getController()).getParseIterator(); + rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange ); + + bool bFound(false); + OSL_ENSURE(!aColumnName.isEmpty(),"Column name must not be empty"); + if (aTableRange.isEmpty()) + { + // SELECT column, ... + bFound = nullptr != lcl_findColumnInTables( aColumnName, *pTabList, _raInfo ); + if ( bFound && ( aColumnName.toChar() != '*' ) ) + _raInfo->SetFieldAlias(aColumnAlias); + } + else + { + // SELECT range.column, ... + OQueryTableWindow* pTabWin = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable(aTableRange); + + if (pTabWin && pTabWin->ExistsField(aColumnName, _raInfo)) + { + if(aColumnName.toChar() != '*') + _raInfo->SetFieldAlias(aColumnAlias); + bFound = true; + } + } + if (!bFound) + { + _raInfo->SetTable(OUString()); + _raInfo->SetAlias(OUString()); + _raInfo->SetField(aColumnName); + _raInfo->SetFieldAlias(aColumnAlias); // nyi : here it continues Expr_1, Expr_2 ... + _raInfo->SetFunctionType(FKT_OTHER); + } + } + bool checkJoinConditions( const OQueryDesignView* _pView, + const ::connectivity::OSQLParseNode* _pNode ) + { + const ::connectivity::OSQLParseNode* pJoinNode = nullptr; + bool bRet = true; + if (SQL_ISRULE(_pNode,qualified_join)) + pJoinNode = _pNode; + else if (SQL_ISRULE(_pNode,table_ref) + && _pNode->count() == 3 + && SQL_ISPUNCTUATION(_pNode->getChild(0),"(") + && SQL_ISPUNCTUATION(_pNode->getChild(2),")") ) // '(' joined_table ')' + pJoinNode = _pNode->getChild(1); + else if (! ( SQL_ISRULE(_pNode, table_ref) && _pNode->count() == 2) ) // table_node table_primary_as_range_column + bRet = false; + + if (pJoinNode && !InsertJoin(_pView,pJoinNode)) + bRet = false; + return bRet; + } + bool InsertJoin(const OQueryDesignView* _pView, + const ::connectivity::OSQLParseNode *pNode) + { + OSL_ENSURE( SQL_ISRULE( pNode, qualified_join ) || SQL_ISRULE( pNode, joined_table ) || SQL_ISRULE( pNode, cross_union ), + "OQueryDesignView::InsertJoin: Error in the Parse Tree"); + + if (SQL_ISRULE(pNode,joined_table)) + return InsertJoin(_pView,pNode->getChild(1)); + + // first check the left and right side + const ::connectivity::OSQLParseNode* pRightTableRef = pNode->getChild(3); // table_ref + if ( SQL_ISRULE(pNode, qualified_join) && SQL_ISTOKEN(pNode->getChild(1),NATURAL) ) + pRightTableRef = pNode->getChild(4); // table_ref + + if ( !checkJoinConditions(_pView,pNode->getChild(0)) || !checkJoinConditions(_pView,pRightTableRef)) + return false; + + // named column join may be implemented later + // SQL_ISRULE(pNode->getChild(4),named_columns_join) + EJoinType eJoinType = INNER_JOIN; + bool bNatural = false; + if ( SQL_ISRULE(pNode, qualified_join) ) + { + ::connectivity::OSQLParseNode* pJoinType = pNode->getChild(1); // join_type + if ( SQL_ISTOKEN(pJoinType,NATURAL) ) + { + bNatural = true; + pJoinType = pNode->getChild(2); + } + + if (SQL_ISRULE(pJoinType,join_type) && (!pJoinType->count() || SQL_ISTOKEN(pJoinType->getChild(0),INNER))) + { + eJoinType = INNER_JOIN; + } + else + { + if (SQL_ISRULE(pJoinType,join_type)) // one level deeper + pJoinType = pJoinType->getChild(0); + + if (SQL_ISTOKEN(pJoinType->getChild(0),LEFT)) + eJoinType = LEFT_JOIN; + else if(SQL_ISTOKEN(pJoinType->getChild(0),RIGHT)) + eJoinType = RIGHT_JOIN; + else + eJoinType = FULL_JOIN; + } + if ( SQL_ISRULE(pNode->getChild(4),join_condition) ) + { + if ( InsertJoinConnection(_pView,pNode->getChild(4)->getChild(1), eJoinType,pNode->getChild(0),pRightTableRef) != eOk ) + return false; + } + } + else if ( SQL_ISRULE(pNode, cross_union) ) + { + eJoinType = CROSS_JOIN; + pRightTableRef = pNode->getChild(pNode->count() - 1); + } + else + return false; + + if ( eJoinType != CROSS_JOIN && !bNatural ) + return true; + + OQueryTableWindow* pLeftWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pNode->getChild(0)) ); + OQueryTableWindow* pRightWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pRightTableRef) ); + OSL_ENSURE(pLeftWindow && pRightWindow,"Table Windows could not be found!"); + if ( !pLeftWindow || !pRightWindow ) + return false; + + OTableFieldDescRef aDragLeft = new OTableFieldDesc(); + aDragLeft->SetTabWindow(pLeftWindow); + aDragLeft->SetTable(pLeftWindow->GetTableName()); + aDragLeft->SetAlias(pLeftWindow->GetAliasName()); + + OTableFieldDescRef aDragRight = new OTableFieldDesc(); + aDragRight->SetTabWindow(pRightWindow); + aDragRight->SetTable(pRightWindow->GetTableName()); + aDragRight->SetAlias(pRightWindow->GetAliasName()); + + insertConnection(_pView,eJoinType,aDragLeft,aDragRight,bNatural); + + return true; + } + void insertUnUsedFields(OQueryDesignView const * _pView,OSelectionBrowseBox* _pSelectionBrw) + { + // now we have to insert the fields which aren't in the statement + OQueryController& rController = static_cast<OQueryController&>(_pView->getController()); + OTableFields& rUnUsedFields = rController.getUnUsedFields(); + for (auto & unusedField : rUnUsedFields) + if(_pSelectionBrw->InsertField(unusedField,BROWSER_INVALIDID,false,false).is()) + unusedField = nullptr; + OTableFields().swap( rUnUsedFields ); + } + + SqlParseError InitFromParseNodeImpl(OQueryDesignView* _pView,OSelectionBrowseBox* _pSelectionBrw) + { + SqlParseError eErrorCode = eOk; + + OQueryController& rController = static_cast<OQueryController&>(_pView->getController()); + + _pSelectionBrw->PreFill(); + _pSelectionBrw->SetReadOnly(rController.isReadOnly()); + _pSelectionBrw->Fill(); + + ::connectivity::OSQLParseTreeIterator& aIterator = rController.getParseIterator(); + const ::connectivity::OSQLParseNode* pParseTree = aIterator.getParseTree(); + + do + { + if ( !pParseTree ) + { + // now we have to insert the fields which aren't in the statement + insertUnUsedFields(_pView,_pSelectionBrw); + break; + } + + if ( !rController.isEscapeProcessing() ) // not allowed in this mode + { + eErrorCode = eNativeMode; + break; + } + + if ( !( SQL_ISRULE( pParseTree, select_statement ) ) ) + { + eErrorCode = eNoSelectStatement; + break; + } + + const OSQLParseNode* pTableExp = pParseTree->getChild(3); + if ( pTableExp->getChild(7)->count() > 0 || pTableExp->getChild(8)->count() > 0) + { + eErrorCode = eStatementTooComplex; + break; + } + + Reference< XConnection> xConnection = rController.getConnection(); + if ( !xConnection.is() ) + { + OSL_FAIL( "InitFromParseNodeImpl: no connection? no connection!" ); + break; + } + + const OSQLTables& aMap = aIterator.getTables(); + ::comphelper::UStringMixLess aTmp(aMap.key_comp()); + ::comphelper::UStringMixEqual aKeyComp( aTmp.isCaseSensitive() ); + + Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); + try + { + sal_Int32 nMax = xMetaData->getMaxTablesInSelect(); + if ( nMax && nMax < static_cast<sal_Int32>(aMap.size()) ) + { + eErrorCode = eTooManyTables; + break; + } + + OUString sComposedName; + OUString sAlias; + + OQueryTableView* pTableView = static_cast<OQueryTableView*>(_pView->getTableView()); + pTableView->clearLayoutInformation(); + for (auto const& elem : aMap) + { + OSQLTable xTable = elem.second; + Reference< XPropertySet > xTableProps( xTable, UNO_QUERY_THROW ); + + sAlias = elem.first; + + // check whether this is a query + Reference< XPropertySetInfo > xPSI = xTableProps->getPropertySetInfo(); + bool bIsQuery = xPSI.is() && xPSI->hasPropertyByName( PROPERTY_COMMAND ); + + if ( bIsQuery ) + OSL_VERIFY( xTableProps->getPropertyValue( PROPERTY_NAME ) >>= sComposedName ); + else + { + sComposedName = ::dbtools::composeTableName( xMetaData, xTableProps, ::dbtools::EComposeRule::InDataManipulation, false ); + + // if the alias is the complete (composed) table, then shorten it + if ( aKeyComp( sComposedName, elem.first ) ) + { + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents( xMetaData, sComposedName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation ); + sAlias = sTable; + } + } + + // find the existent window for this alias + OQueryTableWindow* pExistentWin = pTableView->FindTable( sAlias ); + if ( !pExistentWin ) + { + pTableView->AddTabWin( sComposedName, sAlias ); // don't create data here + } + else + { + // there already exists a window for this alias... + if ( !aKeyComp( pExistentWin->GetData()->GetComposedName(), sComposedName ) ) + // ... but for another complete table name -> new window + pTableView->AddTabWin(sComposedName, sAlias); + } + } + + // now delete the data for which we haven't any tablewindow + OJoinTableView::OTableWindowMap aTableMap(pTableView->GetTabWinMap()); + for (auto const& table : aTableMap) + { + if(aMap.find(table.second->GetComposedName()) == aMap.end() && + aMap.find(table.first) == aMap.end()) + pTableView->RemoveTabWin(table.second); + } + + if ( eOk == (eErrorCode = FillOuterJoins(_pView,pTableExp->getChild(0)->getChild(1))) ) + { + // check if we have a distinct statement + if(SQL_ISTOKEN(pParseTree->getChild(1),DISTINCT)) + { + rController.setDistinct(true); + rController.InvalidateFeature(SID_QUERY_DISTINCT_VALUES); + } + else + { + rController.setDistinct(false); + } + + ///check if query has a limit + if( pTableExp->getChild(6)->count() >= 2 && pTableExp->getChild(6)->getChild(1) ) + { + rController.setLimit( + pTableExp->getChild(6)->getChild(1)->getTokenValue().toInt64() ); + } + else + { + rController.setLimit(-1); + } + + if ( (eErrorCode = InstallFields(_pView, pParseTree, &pTableView->GetTabWinMap())) == eOk ) + { + // GetSelectionCriteria must be called before GetHavingCriteria + sal_uInt16 nLevel=0; + + if ( eOk == (eErrorCode = GetSelectionCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) ) + { + if ( eOk == (eErrorCode = GetGroupCriteria(_pView,_pSelectionBrw,pParseTree)) ) + { + if ( eOk == (eErrorCode = GetHavingCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) ) + { + if ( eOk == (eErrorCode = GetOrderCriteria(_pView,_pSelectionBrw,pParseTree)) ) + insertUnUsedFields(_pView,_pSelectionBrw); + } + } + } + } + } + } + catch(SQLException&) + { + OSL_FAIL("getMaxTablesInSelect!"); + } + } + while ( false ); + + // New Undo-Actions were created in the Manager by the regeneration + rController.ClearUndoManager(); + _pSelectionBrw->Invalidate(); + return eErrorCode; + } + /** fillSelectSubList + @return + <TRUE/> when columns could be inserted otherwise <FALSE/> + */ + SqlParseError fillSelectSubList( OQueryDesignView* _pView, + OJoinTableView::OTableWindowMap* _pTabList) + { + SqlParseError eErrorCode = eOk; + bool bFirstField = true; + for (auto const& table : *_pTabList) + { + OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get()); + OTableFieldDescRef aInfo = new OTableFieldDesc(); + if (pTabWin->ExistsField( "*", aInfo )) + { + eErrorCode = _pView->InsertField(aInfo, bFirstField); + bFirstField = false; + if (eErrorCode != eOk) + break; + } + } + return eErrorCode; + } + SqlParseError InstallFields(OQueryDesignView* _pView, + const ::connectivity::OSQLParseNode* pNode, + OJoinTableView::OTableWindowMap* pTabList ) + { + if( pNode==nullptr || !SQL_ISRULE(pNode,select_statement)) + return eNoSelectStatement; + + ::connectivity::OSQLParseNode* pParseTree = pNode->getChild(2); // selection + bool bFirstField = true; // When initializing, the first field must be reactivated + + SqlParseError eErrorCode = eOk; + + if ( pParseTree->isRule() && SQL_ISPUNCTUATION(pParseTree->getChild(0),"*") ) + { + // SELECT * ... + eErrorCode = fillSelectSubList(_pView,pTabList); + } + else if (SQL_ISRULE(pParseTree,scalar_exp_commalist) ) + { + // SELECT column, ... + OQueryController& rController = static_cast<OQueryController&>(_pView->getController()); + Reference< XConnection> xConnection = rController.getConnection(); + + OUString aColumnName,aTableRange; + for (size_t i = 0; i < pParseTree->count() && eOk == eErrorCode ; ++i) + { + ::connectivity::OSQLParseNode * pColumnRef = pParseTree->getChild(i); + + do { + + if ( SQL_ISRULE(pColumnRef,select_sublist) ) + { + eErrorCode = fillSelectSubList(_pView,pTabList); + break; + } + + if ( SQL_ISRULE(pColumnRef,derived_column) ) + { + OUString aColumnAlias(connectivity::OSQLParseTreeIterator::getColumnAlias(pColumnRef)); // might be empty + pColumnRef = pColumnRef->getChild(0); + OTableFieldDescRef aInfo = new OTableFieldDesc(); + + if ( pColumnRef->getKnownRuleID() != OSQLParseNode::subquery && + pColumnRef->count() == 3 && + SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") && + SQL_ISPUNCTUATION(pColumnRef->getChild(2),")") + ) + pColumnRef = pColumnRef->getChild(1); + + if (SQL_ISRULE(pColumnRef,column_ref)) + { + InsertColumnRef(_pView,pColumnRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList); + eErrorCode = _pView->InsertField(aInfo, bFirstField); + bFirstField = false; + } + else if(SQL_ISRULEOR3(pColumnRef, general_set_fct, set_fct_spec, position_exp) || + SQL_ISRULEOR3(pColumnRef, extract_exp, fold, char_substring_fct) || + SQL_ISRULEOR2(pColumnRef,length_exp,char_value_fct)) + { + OUString aColumns; + pColumnRef->parseNodeToPredicateStr(aColumns, + xConnection, + rController.getNumberFormatter(), + _pView->getLocale(), + _pView->getDecimalSeparator(), + &rController.getParser().getContext()); + + sal_Int32 nFunctionType = FKT_NONE; + ::connectivity::OSQLParseNode* pParamRef = nullptr; + sal_Int32 nColumnRefPos = pColumnRef->count() - 2; + if ( nColumnRefPos >= 0 && o3tl::make_unsigned(nColumnRefPos) < pColumnRef->count() ) + pParamRef = pColumnRef->getChild(nColumnRefPos); + + if ( SQL_ISRULE(pColumnRef,general_set_fct) + && pParamRef && SQL_ISRULE(pParamRef,column_ref) ) + { + // Check the parameters for Column references + InsertColumnRef(_pView,pParamRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList); + } + else if ( SQL_ISRULE(pColumnRef,general_set_fct) ) + { + if ( pParamRef && pParamRef->getTokenValue().toChar() == '*' ) + { + for (auto const& table : *pTabList) + { + OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get()); + if (pTabWin->ExistsField( "*", aInfo )) + { + aInfo->SetAlias(OUString()); + aInfo->SetTable(OUString()); + break; + } + } + } + else + { + OUString sFieldName = aColumns; + if ( pParamRef ) + { // we got an aggregate function but without column name inside + // so we set the whole argument of the function as field name + nFunctionType |= FKT_NUMERIC; + sFieldName.clear(); + pParamRef->parseNodeToStr( sFieldName, + xConnection, + &rController.getParser().getContext(), + true); // quote is to true because we need quoted elements inside the function + } + aInfo->SetDataType(DataType::DOUBLE); + aInfo->SetFieldType(TAB_NORMAL_FIELD); + aInfo->SetField(sFieldName); + } + aInfo->SetTabWindow(nullptr); + aInfo->SetFieldAlias(aColumnAlias); + } + else + { + _pView->fillFunctionInfo(pColumnRef,aColumns,aInfo); + aInfo->SetFieldAlias(aColumnAlias); + } + + if ( SQL_ISRULE(pColumnRef,general_set_fct) ) + { + aInfo->SetFunctionType(nFunctionType|FKT_AGGREGATE); + aInfo->SetFunction(OUString(comphelper::string::stripEnd(o3tl::getToken(aColumns,0,'('), ' '))); + } + else + aInfo->SetFunctionType(nFunctionType|FKT_OTHER); + + eErrorCode = _pView->InsertField(aInfo, bFirstField); + bFirstField = false; + } + else + { + OUString aColumns; + pColumnRef->parseNodeToStr( aColumns, + xConnection, + &rController.getParser().getContext(), + true); // quote is to true because we need quoted elements inside the function + + aInfo->SetTabWindow( nullptr ); + + // since we support queries in queries, the thingie might belong to an existing "table" + OQueryTableWindow* pExistingTable = lcl_findColumnInTables( aColumns, *pTabList, aInfo ); + if ( pExistingTable ) + { + aInfo->SetTabWindow( pExistingTable ); + aInfo->SetTable( pExistingTable->GetTableName() ); + aInfo->SetAlias( pExistingTable->GetAliasName() ); + } + + aInfo->SetDataType(DataType::DOUBLE); + aInfo->SetFieldType(TAB_NORMAL_FIELD); + aInfo->SetField(aColumns); + aInfo->SetFieldAlias(aColumnAlias); + aInfo->SetFunctionType(FKT_NUMERIC | FKT_OTHER); + + eErrorCode = _pView->InsertField(aInfo, bFirstField); + bFirstField = false; + } + + break; + } + + OSL_FAIL( "InstallFields: don't know how to interpret this parse node!" ); + + } while ( false ); + } + } + else + eErrorCode = eStatementTooComplex; + + return eErrorCode; + } + SqlParseError GetOrderCriteria( OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode* pParseRoot ) + { + SqlParseError eErrorCode = eOk; + if (!pParseRoot->getChild(3)->getChild(ORDER_BY_CHILD_POS)->isLeaf()) + { + ::connectivity::OSQLParseNode* pNode = pParseRoot->getChild(3)->getChild(ORDER_BY_CHILD_POS)->getChild(2); + ::connectivity::OSQLParseNode* pParamRef = nullptr; + + OQueryController& rController = static_cast<OQueryController&>(_pView->getController()); + EOrderDir eOrderDir; + for( size_t i=0 ; i<pNode->count() ; i++ ) + { + OTableFieldDescRef aDragLeft = new OTableFieldDesc(); + eOrderDir = ORDER_ASC; + ::connectivity::OSQLParseNode* pChild = pNode->getChild( i ); + + if (SQL_ISTOKEN( pChild->getChild(1), DESC ) ) + eOrderDir = ORDER_DESC; + + ::connectivity::OSQLParseNode* pArgument = pChild->getChild(0); + + if(SQL_ISRULE(pArgument,column_ref)) + { + if( eOk == FillDragInfo(_pView,pArgument,aDragLeft)) + _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i); + else // it could be an alias name for a field + { + OUString aTableRange,aColumnName; + ::connectivity::OSQLParseTreeIterator& rParseIter = rController.getParseIterator(); + rParseIter.getColumnRange( pArgument, aColumnName, aTableRange ); + + OTableFields& aList = rController.getTableFieldDesc(); + for (auto const& elem : aList) + { + if(elem.is() && elem->GetFieldAlias() == aColumnName) + elem->SetOrderDir( eOrderDir ); + } + } + } + else if(SQL_ISRULE(pArgument, general_set_fct ) && + SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref) && + eOk == FillDragInfo(_pView,pParamRef,aDragLeft)) + _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i ); + else if( SQL_ISRULE(pArgument, set_fct_spec ) ) + { + + Reference< XConnection> xConnection = rController.getConnection(); + if(xConnection.is()) + { + OUString sCondition; + pArgument->parseNodeToPredicateStr(sCondition, + xConnection, + rController.getNumberFormatter(), + _pView->getLocale(), + _pView->getDecimalSeparator(), + &rController.getParser().getContext()); + _pView->fillFunctionInfo(pArgument,sCondition,aDragLeft); + aDragLeft->SetFunctionType(FKT_OTHER); + aDragLeft->SetOrderDir(eOrderDir); + aDragLeft->SetVisible(false); + _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i ); + } + else + eErrorCode = eColumnNotFound; + } + else + eErrorCode = eColumnNotFound; + } + } + return eErrorCode; + } + SqlParseError GetHavingCriteria( OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode* pSelectRoot, + sal_uInt16& rLevel ) + { + SqlParseError eErrorCode = eOk; + if (!pSelectRoot->getChild(3)->getChild(3)->isLeaf()) + eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSelectRoot->getChild(3)->getChild(3)->getChild(1),rLevel, true); + return eErrorCode; + } + SqlParseError GetGroupCriteria( OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode* pSelectRoot ) + { + SqlParseError eErrorCode = eOk; + if (!pSelectRoot->getChild(3)->getChild(2)->isLeaf()) // opt_group_by_clause + { + OQueryController& rController = static_cast<OQueryController&>(_pView->getController()); + ::connectivity::OSQLParseNode* pGroupBy = pSelectRoot->getChild(3)->getChild(2)->getChild(2); + + for( size_t i=0 ; i < pGroupBy->count() && eOk == eErrorCode; ++i ) + { + OTableFieldDescRef aDragInfo = new OTableFieldDesc(); + ::connectivity::OSQLParseNode* pParamRef = nullptr; + ::connectivity::OSQLParseNode* pArgument = pGroupBy->getChild( i ); + if(SQL_ISRULE(pArgument,column_ref)) + { + if ( eOk == (eErrorCode = FillDragInfo(_pView,pArgument,aDragInfo)) ) + { + aDragInfo->SetGroupBy(true); + _pSelectionBrw->AddGroupBy(aDragInfo); + } + } + else if(SQL_ISRULE(pArgument, general_set_fct ) && + SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref) && + eOk == FillDragInfo(_pView,pParamRef,aDragInfo)) + { + aDragInfo->SetGroupBy(true); + _pSelectionBrw->AddGroupBy( aDragInfo ); + } + else if( SQL_ISRULE(pArgument, set_fct_spec ) ) + { + Reference< XConnection> xConnection = rController.getConnection(); + if(xConnection.is()) + { + OUString sGroupByExpression; + pArgument->parseNodeToStr( sGroupByExpression, + xConnection, + &rController.getParser().getContext(), + true); // quote is to true because we need quoted elements inside the function + _pView->fillFunctionInfo(pArgument,sGroupByExpression,aDragInfo); + aDragInfo->SetFunctionType(FKT_OTHER); + aDragInfo->SetGroupBy(true); + aDragInfo->SetVisible(false); + _pSelectionBrw->AddGroupBy( aDragInfo ); + } + else + eErrorCode = eColumnNotFound; + } + } + } + return eErrorCode; + } + + OUString getParseErrorMessage( SqlParseError _eErrorCode ) + { + TranslateId pResId; + switch (_eErrorCode) + { + case eIllegalJoin: + pResId = STR_QRY_ILLEGAL_JOIN; + break; + case eStatementTooLong: + pResId = STR_QRY_TOO_LONG_STATEMENT; + break; + case eNoConnection: + pResId = STR_QRY_SYNTAX; + break; + case eNoSelectStatement: + pResId = STR_QRY_NOSELECT; + break; + case eNoColumnInLike: + pResId = STR_QRY_SYNTAX; + break; + case eColumnNotFound: + pResId = STR_QRY_SYNTAX; + break; + case eNativeMode: + pResId = STR_QRY_NATIVE; + break; + case eTooManyTables: + pResId = STR_QRY_TOO_MANY_TABLES; + break; + case eTooManyColumns: + pResId = STR_QRY_TOO_MANY_COLUMNS; + break; + case eStatementTooComplex: + pResId = STR_QRY_TOOCOMPLEX; + break; + default: + pResId = STR_QRY_SYNTAX; + break; + } + return DBA_RES(pResId); + } +} + +// end of anonymous namespace + +OQueryDesignView::OQueryDesignView( OQueryContainerWindow* _pParent, + OQueryController& _rController, + const Reference< XComponentContext >& _rxContext) + :OJoinDesignView( _pParent, _rController, _rxContext ) + ,m_aSplitter( VclPtr<Splitter>::Create(this) ) + ,m_eChildFocus(NONE) + ,m_bInSplitHandler( false ) +{ + + try + { + SvtSysLocale aSysLocale; + m_aLocale = aSysLocale.GetLanguageTag().getLocale(); + m_sDecimalSep = aSysLocale.GetLocaleData().getNumDecimalSep(); + } + catch(Exception&) + { + } + + m_pSelectionBox = VclPtr<OSelectionBrowseBox>::Create(this); + + setNoneVisibleRow(static_cast<OQueryController&>(getController()).getVisibleRows()); + m_pSelectionBox->Show(); + // setup Splitter + m_aSplitter->SetSplitHdl(LINK(this, OQueryDesignView,SplitHdl)); + m_aSplitter->Show(); + +} + +OQueryDesignView::~OQueryDesignView() +{ + disposeOnce(); +} + +void OQueryDesignView::dispose() +{ + if ( m_pTableView ) + ::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::RemoveWindow)); + m_pSelectionBox.disposeAndClear(); + m_aSplitter.disposeAndClear(); + OJoinDesignView::dispose(); +} + +IMPL_LINK_NOARG( OQueryDesignView, SplitHdl, Splitter*, void ) +{ + if (!getController().isReadOnly()) + { + m_bInSplitHandler = true; + m_aSplitter->SetPosPixel( Point( m_aSplitter->GetPosPixel().X(),m_aSplitter->GetSplitPosPixel() ) ); + static_cast<OQueryController&>(getController()).setSplitPos(m_aSplitter->GetSplitPosPixel()); + static_cast<OQueryController&>(getController()).setModified( true ); + Resize(); + m_bInSplitHandler = true; + } +} + +void OQueryDesignView::Construct() +{ + m_pTableView = VclPtr<OQueryTableView>::Create(m_pScrollWindow,this); + ::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::AddWindow)); + OJoinDesignView::Construct(); +} + +void OQueryDesignView::initialize() +{ + if(static_cast<OQueryController&>(getController()).getSplitPos() != -1) + { + m_aSplitter->SetPosPixel( Point( m_aSplitter->GetPosPixel().X(),static_cast<OQueryController&>(getController()).getSplitPos() ) ); + m_aSplitter->SetSplitPosPixel(static_cast<OQueryController&>(getController()).getSplitPos()); + } + m_pSelectionBox->initialize(); + reset(); +} + +void OQueryDesignView::resizeDocumentView(tools::Rectangle& _rPlayground) +{ + Point aPlaygroundPos( _rPlayground.TopLeft() ); + Size aPlaygroundSize( _rPlayground.GetSize() ); + + // calc the split pos, and forward it to the controller + sal_Int32 nSplitPos = static_cast<OQueryController&>(getController()).getSplitPos(); + if ( 0 != aPlaygroundSize.Height() ) + { + if ( ( -1 == nSplitPos ) + || ( nSplitPos >= aPlaygroundSize.Height() ) + ) + { + // let the selection browse box determine an optimal size + Size aSelectionBoxSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize ); + nSplitPos = aPlaygroundSize.Height() - aSelectionBoxSize.Height() - m_aSplitter->GetSizePixel().Height(); + // still an invalid size? + if ( nSplitPos == -1 || nSplitPos >= aPlaygroundSize.Height() ) + nSplitPos = sal_Int32(aPlaygroundSize.Height()*0.6); + + static_cast<OQueryController&>(getController()).setSplitPos(nSplitPos); + } + + if ( !m_bInSplitHandler ) + { // the resize is triggered by something else than the split handler + // our main focus is to try to preserve the size of the selectionbrowse box + Size aSelBoxSize = m_pSelectionBox->GetSizePixel(); + if ( aSelBoxSize.Height() ) + { + // keep the size of the sel box constant + nSplitPos = aPlaygroundSize.Height() - m_aSplitter->GetSizePixel().Height() - aSelBoxSize.Height(); + + // and if the box is smaller than the optimal size, try to do something about it + Size aSelBoxOptSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize ); + if ( aSelBoxOptSize.Height() > aSelBoxSize.Height() ) + { + nSplitPos = aPlaygroundSize.Height() - m_aSplitter->GetSizePixel().Height() - aSelBoxOptSize.Height(); + } + + static_cast< OQueryController& >(getController()).setSplitPos( nSplitPos ); + } + } + } + + // normalize the split pos + Point aSplitPos( _rPlayground.Left(), nSplitPos ); + Size aSplitSize( _rPlayground.GetSize().Width(), m_aSplitter->GetSizePixel().Height() ); + + if( ( aSplitPos.Y() + aSplitSize.Height() ) > ( aPlaygroundSize.Height() )) + aSplitPos.setY( aPlaygroundSize.Height() - aSplitSize.Height() ); + + if( aSplitPos.Y() <= aPlaygroundPos.Y() ) + aSplitPos.setY( aPlaygroundPos.Y() + sal_Int32(aPlaygroundSize.Height() * 0.2) ); + + // position the table + Size aTableViewSize(aPlaygroundSize.Width(), aSplitPos.Y() - aPlaygroundPos.Y()); + m_pScrollWindow->SetPosSizePixel(aPlaygroundPos, aTableViewSize); + + // position the selection browse box + Point aPos( aPlaygroundPos.X(), aSplitPos.Y() + aSplitSize.Height() ); + m_pSelectionBox->SetPosSizePixel( aPos, Size( aPlaygroundSize.Width(), aPlaygroundSize.Height() - aSplitSize.Height() - aTableViewSize.Height() )); + + // set the size of the splitter + m_aSplitter->SetPosSizePixel( aSplitPos, aSplitSize ); + m_aSplitter->SetDragRectPixel( _rPlayground ); + + // just for completeness: there is no space left, we occupied it all ... + _rPlayground.SetPos( _rPlayground.BottomRight() ); + _rPlayground.SetSize( Size( 0, 0 ) ); +} + +void OQueryDesignView::setReadOnly(bool _bReadOnly) +{ + m_pSelectionBox->SetReadOnly(_bReadOnly); +} + +void OQueryDesignView::clear() +{ + m_pSelectionBox->ClearAll(); // clear the whole selection + m_pTableView->ClearAll(); +} + +void OQueryDesignView::copy() +{ + if( m_eChildFocus == SELECTION) + m_pSelectionBox->copy(); +} + +bool OQueryDesignView::isCutAllowed() const +{ + bool bAllowed = false; + if ( SELECTION == m_eChildFocus ) + bAllowed = m_pSelectionBox->isCutAllowed(); + return bAllowed; +} + +bool OQueryDesignView::isPasteAllowed() const +{ + bool bAllowed = false; + if ( SELECTION == m_eChildFocus ) + bAllowed = m_pSelectionBox->isPasteAllowed(); + return bAllowed; +} + +bool OQueryDesignView::isCopyAllowed() const +{ + bool bAllowed = false; + if ( SELECTION == m_eChildFocus ) + bAllowed = m_pSelectionBox->isCopyAllowed(); + return bAllowed; +} + +void OQueryDesignView::stopTimer() +{ + m_pSelectionBox->stopTimer(); +} + +void OQueryDesignView::startTimer() +{ + m_pSelectionBox->startTimer(); +} + +void OQueryDesignView::cut() +{ + if( m_eChildFocus == SELECTION) + { + m_pSelectionBox->cut(); + static_cast<OQueryController&>(getController()).setModified(true); + } +} + +void OQueryDesignView::paste() +{ + if( m_eChildFocus == SELECTION) + { + m_pSelectionBox->paste(); + static_cast<OQueryController&>(getController()).setModified(true); + } +} + +void OQueryDesignView::TableDeleted(const OUString& rAliasName) +{ + // message that the table was removed from the window + m_pSelectionBox->DeleteFields( rAliasName ); + static_cast<OQueryController&>(getController()).InvalidateFeature(ID_BROWSER_ADDTABLE); // inform the view again +} + +bool OQueryDesignView::HasFieldByAliasName(std::u16string_view rFieldName, OTableFieldDescRef const & rInfo) const +{ + return m_pSelectionBox->HasFieldByAliasName( rFieldName, rInfo); +} + +SqlParseError OQueryDesignView::InsertField( const OTableFieldDescRef& rInfo, bool bActivate) +{ + return m_pSelectionBox->InsertField( rInfo, BROWSER_INVALIDID, true/*bVis*/, bActivate ).is() ? eOk : eTooManyColumns; +} + +sal_Int32 OQueryDesignView::getColWidth(sal_uInt16 _nColPos) const +{ + static sal_Int32 s_nDefaultWidth = GetTextWidth("0") * 15; + sal_Int32 nWidth = static_cast<OQueryController&>(getController()).getColWidth(_nColPos); + if ( !nWidth ) + nWidth = s_nDefaultWidth; + return nWidth; +} + +void OQueryDesignView::fillValidFields(std::u16string_view sAliasName, weld::ComboBox& rFieldList) +{ + rFieldList.clear(); + + bool bAllTables = sAliasName.empty(); + + OJoinTableView::OTableWindowMap& rTabWins = m_pTableView->GetTabWinMap(); + OUString strCurrentPrefix; + std::vector< OUString> aFields; + for (auto const& tabWin : rTabWins) + { + OQueryTableWindow* pCurrentWin = static_cast<OQueryTableWindow*>(tabWin.second.get()); + if (bAllTables || (pCurrentWin->GetAliasName() == sAliasName)) + { + strCurrentPrefix = pCurrentWin->GetAliasName() + "."; + + pCurrentWin->EnumValidFields(aFields); + + for (auto const& field : aFields) + { + if (bAllTables || field.toChar() == '*') + rFieldList.append_text(strCurrentPrefix + field); + else + rFieldList.append_text(field); + } + + if (!bAllTables) + // this means that I came into this block because the table name was exactly what I was looking for so I can end here + // (and I prevent that fields get added more than once, if a table is repeated in TabWin) + break; + } + } +} + +bool OQueryDesignView::PreNotify(NotifyEvent& rNEvt) +{ + if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + { + if ( m_pSelectionBox && m_pSelectionBox->HasChildPathFocus() ) + m_eChildFocus = SELECTION; + else + m_eChildFocus = TABLEVIEW; + } + + return OJoinDesignView::PreNotify(rNEvt); +} + +// check if the statement is correct when not returning false +bool OQueryDesignView::checkStatement() +{ + bool bRet = true; + if ( m_pSelectionBox ) + bRet = m_pSelectionBox->Save(); // an error occurred so we return no + return bRet; +} + +OUString OQueryDesignView::getStatement() +{ + OQueryController& rController = static_cast<OQueryController&>(getController()); + m_rController.clearError(); + // used for fields which aren't any longer in the statement + OTableFields& rUnUsedFields = rController.getUnUsedFields(); + OTableFields().swap( rUnUsedFields ); + + // create the select columns + sal_uInt32 nFieldcount = 0; + OTableFields& rFieldList = rController.getTableFieldDesc(); + for (auto const& field : rFieldList) + { + if (!field->GetField().isEmpty() && field->IsVisible() ) + ++nFieldcount; + else if (!field->GetField().isEmpty() && + !field->HasCriteria() && + field->isNoneFunction() && + field->GetOrderDir() == ORDER_NONE && + !field->IsGroupBy() && + field->GetFunction().isEmpty() ) + rUnUsedFields.push_back(field); + } + if ( !nFieldcount ) // no visible fields so return + { + rUnUsedFields = rFieldList; + return OUString(); + } + + OQueryTableView::OTableWindowMap& rTabList = m_pTableView->GetTabWinMap(); + sal_uInt32 nTabcount = rTabList.size(); + + OUString aFieldListStr(GenerateSelectList(this,rFieldList,nTabcount>1)); + if( aFieldListStr.isEmpty() ) + return OUString(); + + // Exception handling, if no fields have been passed we should not + // change the tab page + // TabBarSelectHdl will query the SQL-OUString for STATEMENT_NOFIELDS + // and trigger an error message + // ----------------- Build table list ---------------------- + + const auto& rConnList = m_pTableView->getTableConnections(); + Reference< XConnection> xConnection = rController.getConnection(); + OUString aTableListStr(GenerateFromClause(xConnection,&rTabList,rConnList)); + OSL_ENSURE(!aTableListStr.isEmpty(), "OQueryDesignView::getStatement() : unexpected : have Fields, but no Tables !"); + // if fields exist now, these only can be created by inserting from an already existing table; if on the other hand + // a table is deleted, also the belonging fields will be deleted -> therefore it CANNOT occur that fields + // exist but no tables exist (and aFieldListStr has its length, I secure this above) + OUStringBuffer aHavingStr,aCriteriaListStr; + + // ----------------- build the criteria ---------------------- + if (!GenerateCriterias(this,aCriteriaListStr,aHavingStr,rFieldList, nTabcount > 1)) + return OUString(); + + OUString aJoinCrit; + GenerateInnerJoinCriterias(xConnection,aJoinCrit,rConnList); + if(!aJoinCrit.isEmpty()) + { + OUString aTmp = "( " + aJoinCrit + " )"; + if(!aCriteriaListStr.isEmpty()) + { + aTmp += C_AND; + } + aCriteriaListStr.insert(0, aTmp); + } + // ----------------- construct statement ---------------------- + OUStringBuffer aSqlCmd("SELECT "); + if(rController.isDistinct()) + aSqlCmd.append(" DISTINCT "); + aSqlCmd.append(aFieldListStr); + aSqlCmd.append(" FROM "); + aSqlCmd.append(aTableListStr); + + if (!aCriteriaListStr.isEmpty()) + { + aSqlCmd.append(" WHERE "); + aSqlCmd.append(aCriteriaListStr); + } + Reference<XDatabaseMetaData> xMeta; + if ( xConnection.is() ) + xMeta = xConnection->getMetaData(); + bool bUseAlias = nTabcount > 1; + if ( xMeta.is() ) + bUseAlias = bUseAlias || !xMeta->supportsGroupByUnrelated(); + + aSqlCmd.append(GenerateGroupBy(this,rFieldList,bUseAlias)); + // ----------------- construct GroupBy and attach ------------ + if(!aHavingStr.isEmpty()) + { + aSqlCmd.append(" HAVING "); + aSqlCmd.append(aHavingStr); + } + // ----------------- construct sorting and attach ------------ + OUString sOrder; + SqlParseError eErrorCode = eOk; + if ( (eErrorCode = GenerateOrder(this,rFieldList,nTabcount > 1,sOrder)) == eOk) + aSqlCmd.append(sOrder); + else + { + if ( !m_rController.hasError() ) + m_rController.appendError( getParseErrorMessage( eErrorCode ) ); + + m_rController.displayError(); + } + // --------------------- Limit Clause ------------------- + { + const sal_Int64 nLimit = rController.getLimit(); + if( nLimit != -1 ) + { + aSqlCmd.append( " LIMIT " + OUString::number(nLimit) ); + } + } + + OUString sSQL = aSqlCmd.makeStringAndClear(); + if ( xConnection.is() ) + { + ::connectivity::OSQLParser& rParser( rController.getParser() ); + OUString sErrorMessage; + std::unique_ptr<OSQLParseNode> pParseNode( rParser.parseTree( sErrorMessage, sSQL, true ) ); + if (pParseNode) + { + OSQLParseNode* pNode = pParseNode->getChild(3)->getChild(1); + if ( pNode->count() > 1 ) + { + ::connectivity::OSQLParseNode * pCondition = pNode->getChild(1); + if ( pCondition ) // no where clause + { + OSQLParseNode::compress(pCondition); + OUString sTemp; + pParseNode->parseNodeToStr(sTemp,xConnection); + sSQL = sTemp; + } + } + } + } + return sSQL; +} + +void OQueryDesignView::setSlotEnabled(sal_Int32 _nSlotId, bool _bEnable) +{ + sal_uInt16 nRow; + switch (_nSlotId) + { + case SID_QUERY_VIEW_FUNCTIONS: + nRow = BROW_FUNCTION_ROW; + break; + case SID_QUERY_VIEW_TABLES: + nRow = BROW_TABLE_ROW; + break; + case SID_QUERY_VIEW_ALIASES: + nRow = BROW_COLUMNALIAS_ROW; + break; + default: + // ???????????? + nRow = 0; + break; + } + m_pSelectionBox->SetRowVisible(nRow,_bEnable); + m_pSelectionBox->Invalidate(); +} + +bool OQueryDesignView::isSlotEnabled(sal_Int32 _nSlotId) +{ + sal_uInt16 nRow; + switch (_nSlotId) + { + case SID_QUERY_VIEW_FUNCTIONS: + nRow = BROW_FUNCTION_ROW; + break; + case SID_QUERY_VIEW_TABLES: + nRow = BROW_TABLE_ROW; + break; + case SID_QUERY_VIEW_ALIASES: + nRow = BROW_COLUMNALIAS_ROW; + break; + default: + // ????????? + nRow = 0; + break; + } + return m_pSelectionBox->IsRowVisible(nRow); +} + +void OQueryDesignView::SaveUIConfig() +{ + OQueryController& rCtrl = static_cast<OQueryController&>(getController()); + rCtrl.SaveTabWinsPosSize( &m_pTableView->GetTabWinMap(), m_pScrollWindow->GetHScrollBar().GetThumbPos(), m_pScrollWindow->GetVScrollBar().GetThumbPos() ); + rCtrl.setVisibleRows( m_pSelectionBox->GetNoneVisibleRows() ); + if ( m_aSplitter->GetSplitPosPixel() != 0 ) + rCtrl.setSplitPos( m_aSplitter->GetSplitPosPixel() ); +} + +std::unique_ptr<OSQLParseNode> OQueryDesignView::getPredicateTreeFromEntry(const OTableFieldDescRef& pEntry, + const OUString& _sCriteria, + OUString& _rsErrorMessage, + Reference<XPropertySet>& _rxColumn) const +{ + OSL_ENSURE(pEntry.is(),"Entry is null!"); + if(!pEntry.is()) + return nullptr; + Reference< XConnection> xConnection = static_cast<OQueryController&>(getController()).getConnection(); + if(!xConnection.is()) + return nullptr; + + ::connectivity::OSQLParser& rParser( static_cast<OQueryController&>(getController()).getParser() ); + OQueryTableWindow* pWin = static_cast<OQueryTableWindow*>(pEntry->GetTabWindow()); + + // special handling for functions + if ( pEntry->GetFunctionType() & (FKT_OTHER | FKT_AGGREGATE | FKT_NUMERIC) ) + { + // we have a function here so we have to distinguish the type of return value + OUString sFunction; + if ( pEntry->isNumericOrAggregateFunction() ) + sFunction = pEntry->GetFunction().getToken(0, '('); + + if ( sFunction.isEmpty() ) + sFunction = pEntry->GetField().getToken(0, '('); + + sal_Int32 nType = ::connectivity::OSQLParser::getFunctionReturnType(sFunction,&rParser.getContext()); + if ( nType == DataType::OTHER || (sFunction.isEmpty() && pEntry->isNumericOrAggregateFunction()) ) + { + // first try the international version + OUString sSql = "SELECT * FROM x WHERE " + pEntry->GetField() + _sCriteria; + std::unique_ptr<OSQLParseNode> pParseNode( rParser.parseTree( _rsErrorMessage, sSql, true ) ); + nType = DataType::DOUBLE; + if (pParseNode) + { + OSQLParseNode* pColumnRef = pParseNode->getByRule(OSQLParseNode::column_ref); + if ( pColumnRef ) + { + OTableFieldDescRef aField = new OTableFieldDesc(); + if ( eOk == FillDragInfo(this,pColumnRef,aField) ) + { + nType = aField->GetDataType(); + } + } + } + } + + Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData(); + rtl::Reference<parse::OParseColumn> pColumn = new parse::OParseColumn( pEntry->GetField(), + OUString(), + OUString(), + OUString(), + ColumnValue::NULLABLE_UNKNOWN, + 0, + 0, + nType, + false, + false, + xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(), + OUString(), + OUString(), + OUString()); + _rxColumn = pColumn; + pColumn->setFunction(true); + pColumn->setRealName(pEntry->GetField()); + } + else + { + if (pWin) + { + Reference<XNameAccess> xColumns = pWin->GetOriginalColumns(); + if (xColumns.is() && xColumns->hasByName(pEntry->GetField())) + xColumns->getByName(pEntry->GetField()) >>= _rxColumn; + } + } + + // _rxColumn, if it is a "lookup" column, not a computed column, + // is guaranteed to be the column taken from the *source* of the column, + // that is either a table or another query. + // _rxColumn is *not* taken from the columns of the query we are constructing + // (and rightfully so, since it may not be part of these columns; SELECT A FROM t WHERE B = foo) + // If it is a computed column, we just constructed it above, with same Name and RealName. + // In all cases, we should use the "external" name of the column, not the "RealName"; + // the latter is the name that the column had in the source of the source query. + // An example: we are designing "SELECT A, B FROM q WHERE C='foo'" + // q itself is query "SELECT aye AS A, bee as B, cee as C FROM t" + // We are currently treating the entry "C='foo'" + // Then _rxColumn has Name "C" and RealName "cee". We should *obviously* use "C", not "cee". + std::unique_ptr<OSQLParseNode> pParseNode = rParser.predicateTree( _rsErrorMessage, + _sCriteria, + static_cast<OQueryController&>(getController()).getNumberFormatter(), + _rxColumn, + false); + return pParseNode; +} + +void OQueryDesignView::GetFocus() +{ + OJoinDesignView::GetFocus(); + if ( m_pSelectionBox && !m_pSelectionBox->HasChildPathFocus() ) + { + // first we have to deactivate the current cell to refill when necessary + m_pSelectionBox->DeactivateCell(); + m_pSelectionBox->ActivateCell(m_pSelectionBox->GetCurRow(), m_pSelectionBox->GetCurColumnId()); + m_pSelectionBox->GrabFocus(); + } +} + +void OQueryDesignView::reset() +{ + m_pTableView->ClearAll(); + m_pTableView->ReSync(); +} + +void OQueryDesignView::setNoneVisibleRow(sal_Int32 _nRows) +{ + m_pSelectionBox->SetNoneVisibleRow(_nRows); +} + +void OQueryDesignView::initByFieldDescriptions( const Sequence< PropertyValue >& i_rFieldDescriptions ) +{ + OQueryController& rController = static_cast< OQueryController& >( getController() ); + + m_pSelectionBox->PreFill(); + m_pSelectionBox->SetReadOnly( rController.isReadOnly() ); + m_pSelectionBox->Fill(); + + for ( auto const & field : i_rFieldDescriptions ) + { + ::rtl::Reference< OTableFieldDesc > pField( new OTableFieldDesc() ); + pField->Load( field, true ); + InsertField( pField, false ); + } + + rController.ClearUndoManager(); + m_pSelectionBox->Invalidate(); +} + +bool OQueryDesignView::initByParseIterator( ::dbtools::SQLExceptionInfo* _pErrorInfo ) +{ + SqlParseError eErrorCode = eNativeMode; + m_rController.clearError(); + + try + { + eErrorCode = InitFromParseNodeImpl( this, m_pSelectionBox ); + + if ( eErrorCode != eOk ) + { + if ( !m_rController.hasError() ) + m_rController.appendError( getParseErrorMessage( eErrorCode ) ); + + if ( _pErrorInfo ) + { + *_pErrorInfo = m_rController.getError(); + } + else + { + m_rController.displayError(); + } + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return eErrorCode == eOk; +} + +// Utility function for fillFunctionInfo +namespace { + sal_Int32 char_datatype(const::connectivity::OSQLParseNode* pDataType, const unsigned int offset) { + int cnt = pDataType->count() - offset; + if ( cnt < 0 ) + { + OSL_FAIL("internal error in decoding character datatype specification"); + return DataType::VARCHAR; + } + else if ( cnt == 0 ) + { + if ( offset == 0 ) + { + // The datatype is the node itself + if ( SQL_ISTOKENOR2 (pDataType, CHARACTER, CHAR) ) + return DataType::CHAR; + else if ( SQL_ISTOKEN (pDataType, VARCHAR) ) + return DataType::VARCHAR; + else if ( SQL_ISTOKEN (pDataType, CLOB) ) + return DataType::CLOB; + else + { + OSL_FAIL("unknown/unexpected token in decoding character datatype specification"); + return DataType::VARCHAR; + } + } + else + { + // No child left to read! + OSL_FAIL("incomplete datatype in decoding character datatype specification"); + return DataType::VARCHAR; + } + } + + if ( SQL_ISTOKEN(pDataType->getChild(offset), NATIONAL) ) + return char_datatype(pDataType, offset+1); + else if ( SQL_ISTOKENOR3(pDataType->getChild(offset), CHARACTER, CHAR, NCHAR) ) + { + if ( cnt > 2 && SQL_ISTOKEN(pDataType->getChild(offset+1), LARGE) && SQL_ISTOKEN(pDataType->getChild(offset+2), OBJECT) ) + return DataType::CLOB; + else if ( cnt > 1 && SQL_ISTOKEN(pDataType->getChild(offset+1), VARYING) ) + return DataType::VARCHAR; + else + return DataType::CHAR; + } + else if ( SQL_ISTOKEN (pDataType->getChild(offset), VARCHAR) ) + return DataType::VARCHAR; + else if ( SQL_ISTOKENOR2 (pDataType->getChild(offset), CLOB, NCLOB) ) + return DataType::CLOB; + + OSL_FAIL("unrecognised character datatype"); + return DataType::VARCHAR; + } +} + +// Try to guess the type of an expression in simple cases. +// Originally meant to be called only on a function call (hence the misnomer), +// but now tries to do the best it can also in other cases. +// Don't completely rely on fillFunctionInfo, +// it won't look at the function's arguments to find the return type +// (in particular, in the case of general_set_fct, +// the return type is the type of the argument; +// if that is (as is typical) a column reference, +// it is the type of the column). +// TODO: There is similar "guess the expression's type" code in several places: +// SelectionBrowseBox.cxx: OSelectionBrowseBox::saveField +// QueryDesignView.cxx: InstallFields, GetOrderCriteria, GetGroupCriteria +// If possible, they should be factorised into this function +// (which should then be renamed...) + +void OQueryDesignView::fillFunctionInfo( const ::connectivity::OSQLParseNode* pNode + ,const OUString& sFunctionTerm + ,OTableFieldDescRef& aInfo) +{ + // get the type of the expression, as far as easily possible + OQueryController& rController = static_cast<OQueryController&>(getController()); + sal_Int32 nDataType = DataType::DOUBLE; + switch(pNode->getNodeType()) + { + case SQLNodeType::Concat: + case SQLNodeType::String: + nDataType = DataType::VARCHAR; + break; + case SQLNodeType::IntNum: + nDataType = DataType::INTEGER; + break; + case SQLNodeType::ApproxNum: + nDataType = DataType::DOUBLE; + break; + case SQLNodeType::AccessDate: + nDataType = DataType::TIMESTAMP; + break; + case SQLNodeType::Equal: + case SQLNodeType::Less: + case SQLNodeType::Great: + case SQLNodeType::LessEq: + case SQLNodeType::GreatEq: + case SQLNodeType::NotEqual: + nDataType = DataType::BOOLEAN; + break; + case SQLNodeType::Name: + case SQLNodeType::ListRule: + case SQLNodeType::CommaListRule: + case SQLNodeType::Keyword: + case SQLNodeType::Punctuation: + OSL_FAIL("Unexpected SQL Node Type"); + break; + case SQLNodeType::Rule: + switch(pNode->getKnownRuleID()) + { + case OSQLParseNode::select_statement: + case OSQLParseNode::table_exp: + case OSQLParseNode::table_ref_commalist: + case OSQLParseNode::table_ref: + case OSQLParseNode::catalog_name: + case OSQLParseNode::schema_name: + case OSQLParseNode::table_name: + case OSQLParseNode::opt_column_commalist: + case OSQLParseNode::column_commalist: + case OSQLParseNode::column_ref_commalist: + case OSQLParseNode::column_ref: + case OSQLParseNode::opt_order_by_clause: + case OSQLParseNode::ordering_spec_commalist: + case OSQLParseNode::ordering_spec: + case OSQLParseNode::opt_asc_desc: + case OSQLParseNode::where_clause: + case OSQLParseNode::opt_where_clause: + case OSQLParseNode::opt_escape: + case OSQLParseNode::scalar_exp_commalist: + case OSQLParseNode::scalar_exp: // Seems to never be generated? + case OSQLParseNode::parameter_ref: + case OSQLParseNode::parameter: + case OSQLParseNode::range_variable: + case OSQLParseNode::delete_statement_positioned: + case OSQLParseNode::delete_statement_searched: + case OSQLParseNode::update_statement_positioned: + case OSQLParseNode::update_statement_searched: + case OSQLParseNode::assignment_commalist: + case OSQLParseNode::assignment: + case OSQLParseNode::insert_statement: + case OSQLParseNode::insert_atom_commalist: + case OSQLParseNode::insert_atom: + case OSQLParseNode::from_clause: + case OSQLParseNode::qualified_join: + case OSQLParseNode::cross_union: + case OSQLParseNode::select_sublist: + case OSQLParseNode::join_type: + case OSQLParseNode::named_columns_join: + case OSQLParseNode::joined_table: + case OSQLParseNode::sql_not: + case OSQLParseNode::manipulative_statement: + case OSQLParseNode::value_exp_commalist: + case OSQLParseNode::union_statement: + case OSQLParseNode::outer_join_type: + case OSQLParseNode::selection: + case OSQLParseNode::base_table_def: + case OSQLParseNode::base_table_element_commalist: + case OSQLParseNode::data_type: + case OSQLParseNode::column_def: + case OSQLParseNode::table_node: + case OSQLParseNode::as_clause: + case OSQLParseNode::opt_as: + case OSQLParseNode::op_column_commalist: + case OSQLParseNode::table_primary_as_range_column: + case OSQLParseNode::character_string_type: + case OSQLParseNode::comparison: + OSL_FAIL("Unexpected SQL RuleID"); + break; + case OSQLParseNode::column: + case OSQLParseNode::column_val: + OSL_FAIL("Cannot guess column type"); + break; + case OSQLParseNode::values_or_query_spec: + OSL_FAIL("Cannot guess VALUES type"); + break; + case OSQLParseNode::derived_column: + OSL_FAIL("Cannot guess computed column type"); + break; + case OSQLParseNode::subquery: + OSL_FAIL("Cannot guess subquery return type"); + break; + case OSQLParseNode::search_condition: + case OSQLParseNode::comparison_predicate: + case OSQLParseNode::between_predicate: + case OSQLParseNode::like_predicate: + case OSQLParseNode::test_for_null: + case OSQLParseNode::boolean_term: + case OSQLParseNode::boolean_primary: + case OSQLParseNode::in_predicate: + case OSQLParseNode::existence_test: + case OSQLParseNode::unique_test: + case OSQLParseNode::all_or_any_predicate: + case OSQLParseNode::join_condition: + case OSQLParseNode::boolean_factor: + case OSQLParseNode::comparison_predicate_part_2: + case OSQLParseNode::parenthesized_boolean_value_expression: + case OSQLParseNode::other_like_predicate_part_2: + case OSQLParseNode::between_predicate_part_2: + nDataType = DataType::BOOLEAN; + break; + case OSQLParseNode::num_value_exp: + case OSQLParseNode::extract_exp: + case OSQLParseNode::term: + case OSQLParseNode::factor: + // Might by an integer or a float; take the most generic + nDataType = DataType::DOUBLE; + break; + case OSQLParseNode::value_exp_primary: + case OSQLParseNode::value_exp: + case OSQLParseNode::odbc_call_spec: + // Really, we don't know. Let the default. + break; + case OSQLParseNode::position_exp: + case OSQLParseNode::length_exp: + nDataType = DataType::INTEGER; + break; + case OSQLParseNode::char_value_exp: + case OSQLParseNode::char_value_fct: + case OSQLParseNode::fold: + case OSQLParseNode::char_substring_fct: + case OSQLParseNode::char_factor: + case OSQLParseNode::concatenation: + nDataType = DataType::VARCHAR; + break; + case OSQLParseNode::datetime_primary: + nDataType = DataType::TIMESTAMP; + break; + case OSQLParseNode::bit_value_fct: + nDataType = DataType::BINARY; + break; + case OSQLParseNode::general_set_fct: // May depend on argument; ignore that for now + case OSQLParseNode::set_fct_spec: + { + if (pNode->count() == 0) + { + // This is not a function call, no sense to continue with a function return type lookup + OSL_FAIL("Got leaf SQL node where non-leaf expected"); + break; + } + const OSQLParseNode* pFunctionName = pNode->getChild(0); + if ( SQL_ISPUNCTUATION(pFunctionName,"{") ) + { + if ( pNode->count() == 3 ) + return fillFunctionInfo( pNode->getChild(1), sFunctionTerm, aInfo ); + else + OSL_FAIL("ODBC escape not in recognised form"); + break; + } + else + { + if ( SQL_ISRULEOR2(pNode,length_exp,char_value_fct) ) + pFunctionName = pFunctionName->getChild(0); + + OUString sFunctionName = pFunctionName->getTokenValue(); + if ( sFunctionName.isEmpty() ) + sFunctionName = OStringToOUString(OSQLParser::TokenIDToStr(pFunctionName->getTokenID()),RTL_TEXTENCODING_UTF8); + + nDataType = OSQLParser::getFunctionReturnType( + sFunctionName + ,&rController.getParser().getContext()); + } + break; + } + case OSQLParseNode::odbc_fct_spec: + { + if (pNode->count() != 2) + { + OSL_FAIL("interior of ODBC escape not in recognised shape"); + break; + } + + const OSQLParseNode* const pEscapeType = pNode->getChild(0); + if (SQL_ISTOKEN(pEscapeType, TS)) + nDataType = DataType::TIMESTAMP; + else if (SQL_ISTOKEN(pEscapeType, D)) + nDataType = DataType::DATE; + else if (SQL_ISTOKEN(pEscapeType, T)) + nDataType = DataType::TIME; + else if (SQL_ISTOKEN(pEscapeType, FN)) + return fillFunctionInfo( pNode->getChild(1), sFunctionTerm, aInfo ); + else + OSL_FAIL("Unknown ODBC escape"); + break; + } + case OSQLParseNode::cast_spec: + { + if ( pNode->count() != 6 || !SQL_ISTOKEN(pNode->getChild(3), AS) ) + { + OSL_FAIL("CAST not in recognised shape"); + break; + } + const OSQLParseNode *pCastTarget = pNode->getChild(4); + if ( SQL_ISTOKENOR2(pCastTarget, INTEGER, INT) ) + nDataType = DataType::INTEGER; + else if ( SQL_ISTOKEN(pCastTarget, SMALLINT) ) + nDataType = DataType::SMALLINT; + else if ( SQL_ISTOKEN(pCastTarget, BIGINT) ) + nDataType = DataType::BIGINT; + else if ( SQL_ISTOKEN(pCastTarget, FLOAT) ) + nDataType = DataType::FLOAT; + else if ( SQL_ISTOKEN(pCastTarget, REAL) ) + nDataType = DataType::REAL; + else if ( SQL_ISTOKEN(pCastTarget, DOUBLE) ) + nDataType = DataType::DOUBLE; + else if ( SQL_ISTOKEN(pCastTarget, BOOLEAN) ) + nDataType = DataType::BOOLEAN; + else if ( SQL_ISTOKEN(pCastTarget, DATE) ) + nDataType = DataType::DATE; + else if ( pCastTarget->count() > 0 ) + { + const OSQLParseNode *pDataType = pCastTarget->getChild(0); + while (pDataType->count() > 0) + { + pCastTarget = pDataType; + pDataType = pDataType->getChild(0); + } + if ( SQL_ISTOKEN (pDataType, TIME) ) + nDataType = DataType::TIME; + else if ( SQL_ISTOKEN (pDataType, TIMESTAMP) ) + nDataType = DataType::TIMESTAMP; + else if ( SQL_ISTOKENOR3 (pDataType, CHARACTER, CHAR, NCHAR) ) + nDataType = char_datatype(pCastTarget, 0); + else if ( SQL_ISTOKEN (pDataType, VARCHAR) ) + nDataType = DataType::VARCHAR; + else if ( SQL_ISTOKEN (pDataType, CLOB) ) + nDataType = DataType::CLOB; + else if ( SQL_ISTOKEN (pDataType, NATIONAL) ) + nDataType = char_datatype(pCastTarget, 1); + else if ( SQL_ISTOKEN (pDataType, BINARY) ) + { + if ( pCastTarget->count() > 2 && SQL_ISTOKEN(pCastTarget->getChild(1), LARGE) && SQL_ISTOKEN(pCastTarget->getChild(2), OBJECT) ) + nDataType = DataType::BLOB; + else if ( pCastTarget->count() > 1 && SQL_ISTOKEN(pCastTarget->getChild(1), VARYING) ) + nDataType = DataType::VARBINARY; + else + nDataType = DataType::BINARY; + } + else if ( SQL_ISTOKEN (pDataType, VARBINARY) ) + nDataType = DataType::VARBINARY; + else if ( SQL_ISTOKEN (pDataType, BLOB) ) + nDataType = DataType::BLOB; + else if ( SQL_ISTOKEN (pDataType, NUMERIC) ) + nDataType = DataType::NUMERIC; + else if ( SQL_ISTOKENOR2 (pDataType, DECIMAL, DEC) ) + nDataType = DataType::DECIMAL; + else if ( SQL_ISTOKEN (pDataType, FLOAT) ) + nDataType = DataType::FLOAT; + else if ( SQL_ISTOKEN (pDataType, DOUBLE) ) + nDataType = DataType::DOUBLE; + else if ( SQL_ISTOKEN (pDataType, INTERVAL) ) + // Not in DataType published constant (because not in JDBC...) + nDataType = DataType::VARCHAR; + else + OSL_FAIL("Failed to decode CAST target"); + } + else + OSL_FAIL("Could not decipher CAST target"); + break; + } + default: + OSL_FAIL("Unknown SQL RuleID"); + break; + } + break; + default: + OSL_FAIL("Unknown SQL Node Type"); + break; + } + + aInfo->SetDataType(nDataType); + aInfo->SetFieldType(TAB_NORMAL_FIELD); + aInfo->SetField(sFunctionTerm); + aInfo->SetTabWindow(nullptr); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.cxx b/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.cxx new file mode 100644 index 000000000..398732815 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.cxx @@ -0,0 +1,40 @@ +/* -*- 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 "QueryMoveTabWinUndoAct.hxx" +#include <JoinTableView.hxx> + +using namespace dbaui; +void OJoinMoveTabWinUndoAct::TogglePosition() +{ + Point ptFrameScrollPos(m_pOwner->GetHScrollBar().GetThumbPos(), + m_pOwner->GetVScrollBar().GetThumbPos()); + Point ptNext = m_pTabWin->GetPosPixel() + ptFrameScrollPos; + + m_pTabWin->SetPosPixel(m_ptNextPosition - ptFrameScrollPos); + + // it looks like ptFrameScrollPos is meaningless, then I subtract it here and add it to ptNext, and + // next time I subtract again... + // Albeit ptFrameScrollPos could have changed next time... + m_pOwner->EnsureVisible(m_pTabWin); + + m_ptNextPosition = ptNext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.hxx b/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.hxx new file mode 100644 index 000000000..e6b58956e --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.hxx @@ -0,0 +1,54 @@ +/* -*- 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 "QueryDesignUndoAction.hxx" +#include <strings.hrc> +#include <JoinTableView.hxx> +#include <TableWindow.hxx> +#include <tools/gen.hxx> + +namespace dbaui +{ + + // OQueryMoveTabWinUndoAct - Undo class for moving a TabWin + class OTableWindow; + class OJoinMoveTabWinUndoAct final : public OQueryDesignUndoAction + { + Point m_ptNextPosition; + VclPtr<OTableWindow> m_pTabWin; + + void TogglePosition(); + + public: + OJoinMoveTabWinUndoAct(OJoinTableView* pOwner, const Point& ptOriginalPosition, OTableWindow* pTabWin); + + virtual void Undo() override { TogglePosition(); } + virtual void Redo() override { TogglePosition(); } + }; + + inline OJoinMoveTabWinUndoAct::OJoinMoveTabWinUndoAct(OJoinTableView* pOwner, const Point& ptOriginalPosition, OTableWindow* pTabWin) + :OQueryDesignUndoAction(pOwner, STR_QUERY_UNDO_MOVETABWIN) + ,m_ptNextPosition(ptOriginalPosition) + ,m_pTabWin(pTabWin) + { + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QuerySizeTabWinUndoAct.hxx b/dbaccess/source/ui/querydesign/QuerySizeTabWinUndoAct.hxx new file mode 100644 index 000000000..de244ccb5 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QuerySizeTabWinUndoAct.hxx @@ -0,0 +1,70 @@ +/* -*- 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 "QueryDesignUndoAction.hxx" +#include <strings.hrc> +#include <TableWindow.hxx> + +namespace dbaui +{ + + // OQuerySizeTabWinUndoAct - undo class to change size of TabWins + class OTableWindow; + class OJoinSizeTabWinUndoAct final : public OQueryDesignUndoAction + { + Point m_ptNextPosition; + Size m_szNextSize; + VclPtr<OTableWindow> m_pTabWin; + + inline void ToggleSizePosition(); + + public: + OJoinSizeTabWinUndoAct(OJoinTableView* pOwner, const Point& ptOriginalPos, const Size& szOriginalSize, OTableWindow* pTabWin); + // Boundary condition: while retrieving size/position scrolling is not allowed, meaning the position + // here returns physical and not logical coordinates + // (in contrary to QueryMoveTabWinUndoAct) + + virtual void Undo() override { ToggleSizePosition(); } + virtual void Redo() override { ToggleSizePosition(); } + }; + + inline OJoinSizeTabWinUndoAct::OJoinSizeTabWinUndoAct(OJoinTableView* pOwner, const Point& ptOriginalPos, const Size& szOriginalSize, OTableWindow* pTabWin) + :OQueryDesignUndoAction(pOwner, STR_QUERY_UNDO_SIZETABWIN) + ,m_ptNextPosition(ptOriginalPos) + ,m_szNextSize(szOriginalSize) + ,m_pTabWin(pTabWin) + { + } + + inline void OJoinSizeTabWinUndoAct::ToggleSizePosition() + { + Point ptNext = m_pTabWin->GetPosPixel(); + Size szNext = m_pTabWin->GetSizePixel(); + + m_pOwner->Invalidate(InvalidateFlags::NoChildren); + m_pTabWin->SetPosSizePixel(m_ptNextPosition, m_szNextSize); + m_pOwner->Invalidate(InvalidateFlags::NoChildren); + + m_ptNextPosition = ptNext; + m_szNextSize = szNext; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.cxx b/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.cxx new file mode 100644 index 000000000..e3b6cd0e9 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.cxx @@ -0,0 +1,117 @@ +/* -*- 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 "QueryTabConnUndoAction.hxx" +#include "QTableConnection.hxx" +#include <QueryTableView.hxx> +#include "QueryAddTabConnUndoAction.hxx" +#include "QueryTabWinShowUndoAct.hxx" +#include <strings.hrc> + +using namespace dbaui; + +OQueryTabConnUndoAction::~OQueryTabConnUndoAction() +{ + if (m_bOwnerOfConn) + { // I have the connection -> delete + m_pOwner->DeselectConn(m_pConnection); + m_pConnection.disposeAndClear(); + } +} + +OQueryTabConnUndoAction::OQueryTabConnUndoAction(OQueryTableView* pOwner, TranslateId pCommentID) + : OQueryDesignUndoAction(pOwner, pCommentID) + , m_pConnection(nullptr) + , m_bOwnerOfConn(false) +{ +} + +OQueryAddTabConnUndoAction::OQueryAddTabConnUndoAction(OQueryTableView* pOwner) + : OQueryTabConnUndoAction(pOwner, STR_QUERY_UNDO_INSERTCONNECTION) +{ +} + +void OQueryAddTabConnUndoAction::Undo() +{ + static_cast<OQueryTableView*>(m_pOwner.get())->DropConnection(m_pConnection); + SetOwnership(true); +} + +void OQueryAddTabConnUndoAction::Redo() +{ + static_cast<OQueryTableView*>(m_pOwner.get())->GetConnection(m_pConnection); + SetOwnership(false); +} + +OQueryDelTabConnUndoAction::OQueryDelTabConnUndoAction(OQueryTableView* pOwner) + : OQueryTabConnUndoAction(pOwner, STR_QUERY_UNDO_REMOVECONNECTION) +{ +} + +void OQueryDelTabConnUndoAction::Undo() +{ + static_cast<OQueryTableView*>(m_pOwner.get())->GetConnection(m_pConnection); + SetOwnership(false); +} + +void OQueryDelTabConnUndoAction::Redo() +{ + static_cast<OQueryTableView*>(m_pOwner.get())->DropConnection(m_pConnection); + SetOwnership(true); +} + +OQueryTabWinShowUndoAct::OQueryTabWinShowUndoAct(OQueryTableView* pOwner) + : OQueryTabWinUndoAct(pOwner, STR_QUERY_UNDO_TABWINSHOW) +{ +} + +OQueryTabWinShowUndoAct::~OQueryTabWinShowUndoAct() {} + +void OQueryTabWinShowUndoAct::Undo() +{ + static_cast<OQueryTableView*>(m_pOwner.get())->HideTabWin(m_pTabWin, this); + SetOwnership(true); +} + +void OQueryTabWinShowUndoAct::Redo() +{ + static_cast<OQueryTableView*>(m_pOwner.get())->ShowTabWin(m_pTabWin, this, true); + SetOwnership(false); +} + +OQueryTabWinDelUndoAct::OQueryTabWinDelUndoAct(OQueryTableView* pOwner) + : OQueryTabWinUndoAct(pOwner, STR_QUERY_UNDO_TABWINDELETE) +{ +} + +OQueryTabWinDelUndoAct::~OQueryTabWinDelUndoAct() {} + +void OQueryTabWinDelUndoAct::Undo() +{ + static_cast<OQueryTableView*>(m_pOwner.get())->ShowTabWin(m_pTabWin, this, true); + SetOwnership(false); +} + +void OQueryTabWinDelUndoAct::Redo() +{ + static_cast<OQueryTableView*>(m_pOwner.get())->HideTabWin(m_pTabWin, this); + SetOwnership(true); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.hxx b/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.hxx new file mode 100644 index 000000000..21077074e --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.hxx @@ -0,0 +1,50 @@ +/* -*- 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 "QueryDesignUndoAction.hxx" +#include "QTableConnection.hxx" +#include <JoinTableView.hxx> + +namespace dbaui +{ + class OQueryTableConnection; + class OQueryTableView; + class OQueryTabConnUndoAction : public OQueryDesignUndoAction + { + protected: + VclPtr<OQueryTableConnection> m_pConnection; + bool m_bOwnerOfConn; + // am I the only owner of the connection? (changes with every redo and undo) + + public: + OQueryTabConnUndoAction(OQueryTableView* pOwner, TranslateId pCommentID); + virtual ~OQueryTabConnUndoAction() override; + + virtual void Undo() override = 0; + virtual void Redo() override = 0; + + void SetConnection(OQueryTableConnection* pConn) { m_pConnection = pConn; } + // now SetOwnership please + void SetOwnership(bool bTakeIt) { m_bOwnerOfConn = bTakeIt; } + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryTabWinShowUndoAct.hxx b/dbaccess/source/ui/querydesign/QueryTabWinShowUndoAct.hxx new file mode 100644 index 000000000..95b740de9 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTabWinShowUndoAct.hxx @@ -0,0 +1,51 @@ +/* -*- 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 "QueryTabWinUndoAct.hxx" + +namespace dbaui +{ + // OQueryTabWinShowUndoAct - undo class to show a TabWins + + class OQueryTabWinShowUndoAct : public OQueryTabWinUndoAct + { + public: + explicit OQueryTabWinShowUndoAct(OQueryTableView* pOwner); + virtual ~OQueryTabWinShowUndoAct() override; + + virtual void Undo() override; + virtual void Redo() override; + }; + + // OQueryTabWinDelUndoAct - undo class to delete a TabWins + + class OQueryTabWinDelUndoAct : public OQueryTabWinUndoAct + { + public: + explicit OQueryTabWinDelUndoAct(OQueryTableView* pOwner); + virtual ~OQueryTabWinDelUndoAct() override; + + virtual void Undo() override; + virtual void Redo() override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.cxx b/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.cxx new file mode 100644 index 000000000..2afe74db4 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.cxx @@ -0,0 +1,112 @@ +/* -*- 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 "QueryTabWinUndoAct.hxx" +#include <osl/diagnose.h> +#include "QTableWindow.hxx" +#include "QueryDesignFieldUndoAct.hxx" +#include <QueryTableView.hxx> + +using namespace dbaui; +OQueryDesignFieldUndoAct::OQueryDesignFieldUndoAct(OSelectionBrowseBox* pSelBrwBox, TranslateId pCommentID) + : OCommentUndoAction(pCommentID) + , pOwner(pSelBrwBox) + , m_nColumnPosition(BROWSER_INVALIDID) +{ +} + +OQueryDesignFieldUndoAct::~OQueryDesignFieldUndoAct() +{ + pOwner = nullptr; +} + +OQueryTabWinUndoAct::OQueryTabWinUndoAct(OQueryTableView* pOwner, TranslateId pCommentID) + : OQueryDesignUndoAction(pOwner, pCommentID) + , m_pTabWin(nullptr) + , m_bOwnerOfObjects(false) +{ +} + +OQueryTabWinUndoAct::~OQueryTabWinUndoAct() +{ + if (!m_bOwnerOfObjects) + return; + + // I should take care to delete the window if I am the only owner + OSL_ENSURE(m_pTabWin != nullptr, "OQueryTabWinUndoAct::~OQueryTabWinUndoAct() : m_pTabWin must not be NULL"); + OSL_ENSURE(!m_pTabWin->IsVisible(), "OQueryTabWinUndoAct::~OQueryTabWinUndoAct() : *m_pTabWin must not be visible"); + + if ( m_pTabWin ) + m_pTabWin->clearListBox(); + m_pTabWin.disposeAndClear(); + + // and of course the corresponding connections + for (auto & connection : m_vTableConnection) + { + m_pOwner->DeselectConn(connection); + connection.disposeAndClear(); + } + m_vTableConnection.clear(); +} + +void OTabFieldCellModifiedUndoAct::Undo() +{ + pOwner->EnterUndoMode(); + OSL_ENSURE(m_nColumnPosition != BROWSER_INVALIDID,"Column position was not set add the undo action!"); + OSL_ENSURE(m_nColumnPosition < pOwner->GetColumnCount(),"Position outside the column count!"); + if ( m_nColumnPosition != BROWSER_INVALIDID ) + { + sal_uInt16 nColumnId = pOwner->GetColumnId(m_nColumnPosition); + OUString strNext = pOwner->GetCellContents(m_nCellIndex, nColumnId); + pOwner->SetCellContents(m_nCellIndex, nColumnId, m_strNextCellContents); + m_strNextCellContents = strNext; + } + pOwner->LeaveUndoMode(); +} + +void OTabFieldSizedUndoAct::Undo() +{ + pOwner->EnterUndoMode(); + OSL_ENSURE(m_nColumnPosition != BROWSER_INVALIDID,"Column position was not set add the undo action!"); + if ( m_nColumnPosition != BROWSER_INVALIDID ) + { + sal_uInt16 nColumnId = pOwner->GetColumnId(m_nColumnPosition); + tools::Long nNextWidth = pOwner->GetColumnWidth(nColumnId); + pOwner->SetColWidth(nColumnId, m_nNextWidth); + m_nNextWidth = nNextWidth; + } + pOwner->LeaveUndoMode(); +} + +void OTabFieldMovedUndoAct::Undo() +{ + pOwner->EnterUndoMode(); + OSL_ENSURE(m_nColumnPosition != BROWSER_INVALIDID,"Column position was not set add the undo action!"); + if ( m_nColumnPosition != BROWSER_INVALIDID ) + { + sal_uInt16 nId = pDescr->GetColumnId(); + sal_uInt16 nOldPos = pOwner->GetColumnPos(nId); + pOwner->SetColumnPos(nId,m_nColumnPosition); + pOwner->ColumnMoved(nId,false); + m_nColumnPosition = nOldPos; + } + pOwner->LeaveUndoMode(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.hxx b/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.hxx new file mode 100644 index 000000000..9b4330542 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.hxx @@ -0,0 +1,61 @@ +/* -*- 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 "QueryDesignUndoAction.hxx" +#include "QTableWindow.hxx" +#include <TableConnection.hxx> +#include <vector> + +namespace dbaui +{ + // OQueryTabWinUndoAct - undo base class for all which is concerned with insert/remove TabWins + + class OQueryTableWindow; + class OTableConnection; + class OQueryTableView; + class OQueryTabWinUndoAct : public OQueryDesignUndoAction + { + protected: + std::vector<VclPtr<OTableConnection> > m_vTableConnection; + VclPtr<OQueryTableWindow> m_pTabWin; + bool m_bOwnerOfObjects; + // am I the only owner of the managed objects? (changes with every redo or undo) + + public: + OQueryTabWinUndoAct(OQueryTableView* pOwner, TranslateId pCommentID); + virtual ~OQueryTabWinUndoAct() override; + + void SetOwnership(bool bTakeIt) { m_bOwnerOfObjects = bTakeIt; } + + virtual void Undo() override = 0; + virtual void Redo() override = 0; + + // access to the TabWin + void SetTabWin(OQueryTableWindow* pTW) { m_pTabWin = pTW; } + // now SetOwnership should be invoked + + std::vector<VclPtr<OTableConnection> >& GetTabConnList() { return m_vTableConnection; } + + void InsertConnection( OTableConnection* pConnection ) { m_vTableConnection.push_back(pConnection); } + }; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryTableView.cxx b/dbaccess/source/ui/querydesign/QueryTableView.cxx new file mode 100644 index 000000000..399697b09 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTableView.cxx @@ -0,0 +1,889 @@ +/* -*- 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 <QueryTableView.hxx> +#include <TableFieldDescription.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <helpids.h> +#include "QTableWindow.hxx" +#include "QTableConnection.hxx" +#include "QTableConnectionData.hxx" +#include <QueryDesignView.hxx> +#include "QueryAddTabConnUndoAction.hxx" +#include "QueryTabWinShowUndoAct.hxx" +#include <browserids.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <JAccess.hxx> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <connectivity/dbtools.hxx> +#include <comphelper/sequence.hxx> +#include "querydlg.hxx" +#include <core_resource.hxx> +#include <strings.hrc> +#include <strings.hxx> + +using namespace dbaui; +using namespace ::com::sun::star::uno; +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::accessibility; + +namespace +{ + /** appends a new TabAdd Undo action at controller + @param _pView the view which we use + @param _pUndoAction the undo action which should be added + @param _pConnection the connection for which the undo action should be appended + @param _bOwner is the undo action the owner + */ + void addUndoAction( OQueryTableView const * _pView, + std::unique_ptr<OQueryTabConnUndoAction> _pUndoAction, + OQueryTableConnection* _pConnection, + bool _bOwner = false) + { + _pUndoAction->SetOwnership(_bOwner); + _pUndoAction->SetConnection(_pConnection); + _pView->getDesignView()->getController().addUndoActionAndInvalidate(std::move(_pUndoAction)); + } + /** openJoinDialog opens the join dialog with this connection data + @param _pView the view which we use + @param _pConnectionData the connection data + + @return true when OK was pressed otherwise false + */ + bool openJoinDialog(OQueryTableView* _pView,const TTableConnectionData::value_type& _pConnectionData,bool _bSelectableTables) + { + OQueryTableConnectionData* pData = static_cast< OQueryTableConnectionData*>(_pConnectionData.get()); + + DlgQryJoin aDlg(_pView,_pConnectionData,&_pView->GetTabWinMap(),_pView->getDesignView()->getController().getConnection(),_bSelectableTables); + bool bOk = aDlg.run() == RET_OK; + if( bOk ) + { + pData->SetJoinType(aDlg.GetJoinType()); + _pView->getDesignView()->getController().setModified(true); + } + + return bOk; + } + /** connectionModified adds an undo action for the modified connection and forces a redraw + @param _pView the view which we use + @param _pConnection the connection which was modified + @param _bAddUndo true when an undo action should be appended + */ + void connectionModified(OQueryTableView* _pView, + OTableConnection* _pConnection, + bool _bAddUndo) + { + OSL_ENSURE(_pConnection,"Invalid connection!"); + _pConnection->UpdateLineList(); + + // add an undo action + if ( _bAddUndo ) + addUndoAction( _pView, + std::make_unique<OQueryAddTabConnUndoAction>(_pView), + static_cast< OQueryTableConnection*>(_pConnection)); + // redraw + _pConnection->RecalcLines(); + // force an invalidation of the bounding rectangle + _pConnection->InvalidateConnection(); + + _pView->Invalidate(InvalidateFlags::NoChildren); + } + void addConnections(OQueryTableView* _pView, + const OQueryTableWindow& _rSource, + const OQueryTableWindow& _rDest, + const Reference<XNameAccess>& _rxSourceForeignKeyColumns) + { + if ( _rSource.GetData()->isQuery() || _rDest.GetData()->isQuery() ) + // nothing to do if one of both denotes a query + return; + + // we found a table in our view where we can insert some connections + // the key columns have a property called RelatedColumn + // build OQueryTableConnectionData + auto xNewConnData = std::make_shared<OQueryTableConnectionData>( _rSource.GetData(), _rDest.GetData() ); + + OUString sRelatedColumn; + + // iterate through all foreignkey columns to create the connections + const Sequence<OUString> aKeyCols = _rxSourceForeignKeyColumns->getElementNames(); + for(const OUString& rElement : aKeyCols) + { + Reference<XPropertySet> xColumn; + if ( !( _rxSourceForeignKeyColumns->getByName(rElement) >>= xColumn ) ) + { + OSL_FAIL( "addConnections: invalid foreign key column!" ); + continue; + } + + xColumn->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedColumn; + + { + sal_Int32 nFindIndex = ::comphelper::findValue(_rSource.GetOriginalColumns()->getElementNames(),rElement); + if(nFindIndex != -1) + xNewConnData->SetFieldIndex(JTCS_FROM,nFindIndex+1); + else + OSL_FAIL("Column not found!"); + } + // get the position inside the table + Reference<XNameAccess> xRefColumns = _rDest.GetOriginalColumns(); + if(xRefColumns.is()) + { + sal_Int32 nFindIndex = ::comphelper::findValue(xRefColumns->getElementNames(),sRelatedColumn); + if(nFindIndex != -1) + xNewConnData->SetFieldIndex(JTCS_TO,nFindIndex+1); + else + OSL_FAIL("Column not found!"); + } + xNewConnData->AppendConnLine(rElement,sRelatedColumn); + + // now add the Conn itself + ScopedVclPtrInstance< OQueryTableConnection > aNewConn(_pView, xNewConnData); + // referring to the local variable is not important, as NotifyQueryTabConn creates a new copy + // to add me (if not existent) + _pView->NotifyTabConnection(*aNewConn, false); + // don't create an Undo-Action for the new connection : the connection is + // covered by the Undo-Action for the tabwin, as the "Undo the insert" will + // automatically remove all connections adjacent to the win. + // (Because of this automatism we would have an ownership ambiguity for + // the connection data if we would insert the conn-Undo-Action) + } + } +} + +OQueryTableView::OQueryTableView( vcl::Window* pParent,OQueryDesignView* pView) + : OJoinTableView( pParent,pView) +{ + SetHelpId(HID_CTL_QRYDGNTAB); +} + +sal_Int32 OQueryTableView::CountTableAlias(const OUString& rName, sal_Int32& rMax) +{ + sal_Int32 nRet = 0; + + OTableWindowMap::const_iterator aIter = GetTabWinMap().find(rName); + while(aIter != GetTabWinMap().end()) + { + OUString aNewName = rName + "_" + OUString::number(++nRet); + aIter = GetTabWinMap().find(aNewName); + } + + rMax = nRet; + + return nRet; +} + +void OQueryTableView::ReSync() +{ + TTableWindowData& rTabWinDataList = m_pView->getController().getTableWindowData(); + OSL_ENSURE((getTableConnections().empty()) && (GetTabWinMap().empty()), + "before calling OQueryTableView::ReSync() please call ClearAll !"); + + // I need a collection of all window names that cannot be created so that I do not initialize connections for them. + std::vector<OUString> arrInvalidTables; + + TTableWindowData::const_reverse_iterator aIter = rTabWinDataList.rbegin(); + // Create the window and add it + + for(;aIter != rTabWinDataList.rend();++aIter) + { + OQueryTableWindowData* pData = static_cast<OQueryTableWindowData*>(aIter->get()); + VclPtr<OTableWindow> pTabWin = createWindow(*aIter); + + // I don't use ShowTabWin as this adds the window data to the list of documents. + // This would be bad as I am getting them from there. + // Instead, I do it step by step + if (!pTabWin->Init()) + { + // The initialisation has gone wrong, this TabWin is not available, so + // I must clean up the data and the document + pTabWin->clearListBox(); + pTabWin.disposeAndClear(); + arrInvalidTables.push_back(pData->GetAliasName()); + + rTabWinDataList.erase( std::remove(rTabWinDataList.begin(), rTabWinDataList.end(), *aIter), rTabWinDataList.end()); + continue; + } + + GetTabWinMap()[pData->GetAliasName()] = pTabWin; // add at the beginning as I am going backwards through the DataList + // Use the default if there is no position or size + if (!pData->HasPosition() && !pData->HasSize()) + SetDefaultTabWinPosSize(pTabWin); + + pTabWin->Show(); + } + + // Add the connections + TTableConnectionData& rTabConnDataList = m_pView->getController().getTableConnectionData(); + TTableConnectionData::const_reverse_iterator aConIter = rTabConnDataList.rbegin(); + + for(;aConIter != rTabConnDataList.rend();++aConIter) + { + OQueryTableConnectionData* pTabConnData = static_cast<OQueryTableConnectionData*>(aConIter->get()); + + // do both tables for the connection exist ? + OUString strTabExistenceTest = pTabConnData->getReferencingTable()->GetWinName(); + bool bInvalid = std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end(); + strTabExistenceTest = pTabConnData->getReferencedTable()->GetWinName(); + bInvalid = bInvalid && std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end(); + + if (bInvalid) + { + // no -> bad luck, no connection + rTabConnDataList.erase( std::remove(rTabConnDataList.begin(), rTabConnDataList.end(), *aConIter), rTabConnDataList.end()); + continue; + } + + // adds a new connection to join view and notifies our accessible and invalidates the controller + addConnection(VclPtr<OQueryTableConnection>::Create(this, *aConIter)); + } +} + +void OQueryTableView::ClearAll() +{ + OJoinTableView::ClearAll(); + + SetUpdateMode(true); + m_pView->getController().setModified(true); +} + +VclPtr<OTableWindow> OQueryTableView::createWindow(const TTableWindowData::value_type& _pData) +{ + return VclPtr<OQueryTableWindow>::Create(this,_pData); +} + +void OQueryTableView::NotifyTabConnection(const OQueryTableConnection& rNewConn, bool _bCreateUndoAction) +{ + // let's first check if I have the connection already + OQueryTableConnection* pTabConn = nullptr; + const auto& rConnections = getTableConnections(); + auto aEnd = rConnections.end(); + auto aIter = std::find( rConnections.begin(), + aEnd, + VclPtr<OTableConnection>(const_cast<OTableConnection*>(static_cast<const OTableConnection*>(&rNewConn))) + ); + if(aIter == aEnd) + { + for (auto const& connection : rConnections) + { + if(*static_cast<OQueryTableConnection*>(connection.get()) == rNewConn) + { + pTabConn = static_cast<OQueryTableConnection*>(connection.get()); + break; + } + } + } + else + pTabConn = static_cast<OQueryTableConnection*>((*aIter).get()); + + // no -> insert + if (pTabConn == nullptr) + { + // the new data ... + auto pNewData = std::static_pointer_cast<OQueryTableConnectionData>(rNewConn.GetData()->NewInstance()); + pNewData->CopyFrom(*rNewConn.GetData()); + VclPtrInstance<OQueryTableConnection> pNewConn(this, pNewData); + GetConnection(pNewConn); + + connectionModified(this,pNewConn,_bCreateUndoAction); + } +} + +std::shared_ptr<OTableWindowData> OQueryTableView::CreateImpl(const OUString& _rComposedName + ,const OUString& _sTableName + ,const OUString& _rWinName) +{ + return std::make_shared<OQueryTableWindowData>( _rComposedName, _sTableName,_rWinName ); +} + +void OQueryTableView::AddTabWin(const OUString& _rTableName, const OUString& _rAliasName, bool bNewTable) +{ + // this method has been inherited from the base class, linking back to the parent and which constructs + // an Alias and which passes on to my other AddTabWin + + // pity _rTableName is fully qualified, OQueryDesignView expects a string which only + // contains schema and tables but no catalog. + Reference< XConnection> xConnection = m_pView->getController().getConnection(); + if(!xConnection.is()) + return; + try + { + Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents(xMetaData, + _rTableName, + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + OUString sRealName(sSchema); + if (!sRealName.isEmpty()) + sRealName += "."; + sRealName += sTable; + + AddTabWin(_rTableName, sRealName, _rAliasName, bNewTable); + } + catch(SQLException&) + { + OSL_FAIL("qualifiedNameComponents"); + } +} + +// find the table which has a foreign key with this referencedTable name +static Reference<XPropertySet> getKeyReferencedTo(const Reference<XIndexAccess>& _rxKeys,std::u16string_view _rReferencedTable) +{ + if(!_rxKeys.is()) + return Reference<XPropertySet>(); + + // search the one and only primary key + const sal_Int32 nCount = _rxKeys->getCount(); + for(sal_Int32 i=0;i<nCount ;++i) + { + Reference<XPropertySet> xKey(_rxKeys->getByIndex(i),UNO_QUERY); + if(xKey.is()) + { + sal_Int32 nKeyType = 0; + xKey->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; + if(KeyType::FOREIGN == nKeyType) + { + OUString sReferencedTable; + xKey->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= sReferencedTable; + // TODO check case + if(sReferencedTable == _rReferencedTable) + return xKey; + } + } + } + return Reference<XPropertySet>(); +} + +void OQueryTableView::AddTabWin(const OUString& _rComposedName, const OUString& _rTableName, const OUString& strAlias, bool bNewTable) +{ + OSL_ENSURE(!_rTableName.isEmpty() || !strAlias.isEmpty(), "OQueryTableView::AddTabWin : no tables or aliases !"); + // If the table is not set, then it is a dummy window, but at least the alias must be set + + // build a new data structure + // first check if this already has its data + bool bAppend = bNewTable; + TTableWindowData::value_type pNewTabWinData; + TTableWindowData& rWindowData = getDesignView()->getController().getTableWindowData(); + bool bFoundElem = false; + for (auto const& elem : rWindowData) + { + pNewTabWinData = elem; + if (pNewTabWinData && pNewTabWinData->GetWinName() == strAlias && pNewTabWinData->GetComposedName() == _rComposedName && pNewTabWinData->GetTableName() == _rTableName) + { + bFoundElem = true; + break; + } + } + if ( !bAppend ) + bAppend = !bFoundElem; + if ( bAppend ) + pNewTabWinData = createTableWindowData(_rComposedName, _rTableName, strAlias); + // I do not need to add TabWinData to the DocShell list, ShowTabWin does that. + + // Create a new window + VclPtr<OQueryTableWindow> pNewTabWin = static_cast<OQueryTableWindow*>(createWindow(pNewTabWinData).get()); + // No need to initialize, as that happens in ShowTabWin + + // New UndoAction + std::unique_ptr<OQueryTabWinShowUndoAct> pUndoAction(new OQueryTabWinShowUndoAct(this)); + pUndoAction->SetTabWin(pNewTabWin); // Window + bool bSuccess = ShowTabWin(pNewTabWin, pUndoAction.get(), bAppend); + if(!bSuccess) + { + // reset table window + pUndoAction->SetTabWin(nullptr); + pUndoAction->SetOwnership(false); + return; + } + + // Show the relations between the individual tables + OTableWindowMap& rTabWins = GetTabWinMap(); + if(bNewTable && !rTabWins.empty() && !_rTableName.isEmpty()) + { + modified(); + if ( m_pAccessible ) + m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD, + Any(), + Any(pNewTabWin->GetAccessible()) + ); + + do { + + if ( pNewTabWin->GetData()->isQuery() ) + break; + + try + { + // find relations between the table and the tables already inserted + Reference< XIndexAccess> xKeyIndex = pNewTabWin->GetData()->getKeys(); + if ( !xKeyIndex.is() ) + break; + + Reference<XNameAccess> xFKeyColumns; + OUString aReferencedTable; + Reference<XColumnsSupplier> xColumnsSupplier; + + const sal_Int32 nKeyCount = xKeyIndex->getCount(); + for ( sal_Int32 i=0; i<nKeyCount ; ++i ) + { + Reference< XPropertySet > xProp( xKeyIndex->getByIndex(i), UNO_QUERY_THROW ); + xColumnsSupplier.set( xProp, UNO_QUERY_THROW ); + xFKeyColumns.set( xColumnsSupplier->getColumns(), UNO_SET_THROW ); + + sal_Int32 nKeyType = 0; + xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; + + switch ( nKeyType ) + { + case KeyType::FOREIGN: + { // our new table has a foreign key + // so look if the referenced table is already in our list + xProp->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= aReferencedTable; + OSL_ENSURE(!aReferencedTable.isEmpty(),"Foreign key without referencedTableName"); + + OTableWindowMap::const_iterator aIter = rTabWins.find(aReferencedTable); + OTableWindowMap::const_iterator aEnd = rTabWins.end(); + if(aIter == aEnd) + { + for(aIter = rTabWins.begin();aIter != aEnd;++aIter) + { + OQueryTableWindow* pTabWinTmp = static_cast<OQueryTableWindow*>(aIter->second.get()); + OSL_ENSURE( pTabWinTmp,"TableWindow is null!" ); + if ( pTabWinTmp != pNewTabWin && pTabWinTmp->GetComposedName() == aReferencedTable ) + break; + } + } + if ( aIter != aEnd && pNewTabWin.get() != aIter->second.get() ) + addConnections( this, *pNewTabWin, *static_cast<OQueryTableWindow*>(aIter->second.get()), xFKeyColumns ); + } + break; + + case KeyType::PRIMARY: + { + // we have a primary key so look in our list if there exists a key which this is referred to + for (auto const& tabWin : rTabWins) + { + OQueryTableWindow* pTabWinTmp = static_cast<OQueryTableWindow*>(tabWin.second.get()); + if ( pTabWinTmp == pNewTabWin ) + continue; + + if ( pTabWinTmp->GetData()->isQuery() ) + continue; + + OSL_ENSURE(pTabWinTmp,"TableWindow is null!"); + Reference< XPropertySet > xFKKey = getKeyReferencedTo( pTabWinTmp->GetData()->getKeys(), pNewTabWin->GetComposedName() ); + if ( !xFKKey.is() ) + continue; + + Reference<XColumnsSupplier> xFKColumnsSupplier( xFKKey, UNO_QUERY_THROW ); + Reference< XNameAccess > xTColumns( xFKColumnsSupplier->getColumns(), UNO_SET_THROW ); + addConnections( this, *pTabWinTmp, *pNewTabWin, xTColumns ); + } + } + break; + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + } while ( false ); + } + + // My parent needs to be informed about the delete + m_pView->getController().addUndoActionAndInvalidate( std::move(pUndoAction) ); +} + +void OQueryTableView::AddConnection(const OJoinExchangeData& jxdSource, const OJoinExchangeData& jxdDest) +{ + OQueryTableWindow* pSourceWin = static_cast< OQueryTableWindow*>(jxdSource.pListBox->GetTabWin()); + OQueryTableWindow* pDestWin = static_cast< OQueryTableWindow*>(jxdDest.pListBox->GetTabWin()); + + OUString aSourceFieldName, aDestFieldName; + weld::TreeView& rSourceTreeView = jxdSource.pListBox->get_widget(); + aSourceFieldName = rSourceTreeView.get_text(jxdSource.nEntry); + weld::TreeView& rDestTreeView = jxdDest.pListBox->get_widget(); + aDestFieldName = rDestTreeView.get_text(jxdDest.nEntry); + + OTableConnection* pConn = GetTabConn(pSourceWin,pDestWin,true); + if ( !pConn ) + { + // new data object + auto xNewConnectionData = std::make_shared<OQueryTableConnectionData>(pSourceWin->GetData(), pDestWin->GetData()); + + sal_uInt32 nSourceFieldIndex, nDestFieldIndex; + + // Get name/position of both affected fields ... + // Source + nSourceFieldIndex = jxdSource.nEntry; + // Dest + nDestFieldIndex = jxdDest.nEntry; + + // ... and set them + xNewConnectionData->SetFieldIndex(JTCS_FROM, nSourceFieldIndex); + xNewConnectionData->SetFieldIndex(JTCS_TO, nDestFieldIndex); + + xNewConnectionData->AppendConnLine( aSourceFieldName,aDestFieldName ); + + ScopedVclPtrInstance< OQueryTableConnection > aNewConnection(this, xNewConnectionData); + NotifyTabConnection(*aNewConnection); + // As usual with NotifyTabConnection, using a local variable is fine because a copy is made + } + else + { + // the connection could point on the other side + if(pConn->GetSourceWin() == pDestWin) + { + OUString aTmp(aSourceFieldName); + aSourceFieldName = aDestFieldName; + aDestFieldName = aTmp; + } + + pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName ); + + connectionModified(this,pConn,false); + } +} + +void OQueryTableView::ConnDoubleClicked(VclPtr<OTableConnection>& rConnection) +{ + if (openJoinDialog(this, rConnection->GetData(), false)) + { + connectionModified(this, rConnection, false); + SelectConn(rConnection); + } +} + +void OQueryTableView::createNewConnection() +{ + TTableConnectionData::value_type pData = std::make_shared<OQueryTableConnectionData>(); + if( !openJoinDialog(this,pData,true) ) + return; + + OTableWindowMap& rMap = GetTabWinMap(); + OQueryTableWindow* pSourceWin = static_cast< OQueryTableWindow*>(rMap[pData->getReferencingTable()->GetWinName()].get()); + OQueryTableWindow* pDestWin = static_cast< OQueryTableWindow*>(rMap[pData->getReferencedTable()->GetWinName()].get()); + // first we have to look if the this connection already exists + OTableConnection* pConn = GetTabConn(pSourceWin,pDestWin,true); + bool bNew = true; + if ( pConn ) + { + pConn->GetData()->CopyFrom( *pData ); + bNew = false; + } + else + { + // create a new connection and append it + VclPtrInstance<OQueryTableConnection> pQConn(this, pData); + GetConnection(pQConn); + pConn = pQConn; + } + connectionModified(this,pConn,bNew); + if ( !bNew && pConn == GetSelectedConn() ) // our connection was selected before so we have to reselect it + SelectConn( pConn ); +} + +bool OQueryTableView::RemoveConnection(VclPtr<OTableConnection>& rConnection, bool /*_bDelete*/) +{ + VclPtr<OQueryTableConnection> xConnection(static_cast<OQueryTableConnection*>(rConnection.get())); + + // we don't want that our connection will be deleted, we put it in the undo manager + bool bRet = OJoinTableView::RemoveConnection(rConnection, false); + + // add undo action + addUndoAction(this, + std::make_unique<OQueryDelTabConnUndoAction>(this), + xConnection.get(), + true); + + return bRet; +} + +OQueryTableWindow* OQueryTableView::FindTable(const OUString& rAliasName) +{ + OSL_ENSURE(!rAliasName.isEmpty(), "OQueryTableView::FindTable : the AliasName should not be empty !"); + // (it is harmless but does not make sense and indicates that there is probably an error in the caller) + OTableWindowMap::const_iterator aIter = GetTabWinMap().find(rAliasName); + if(aIter != GetTabWinMap().end()) + return static_cast<OQueryTableWindow*>(aIter->second.get()); + return nullptr; +} + +bool OQueryTableView::FindTableFromField(const OUString& rFieldName, OTableFieldDescRef const & rInfo, sal_uInt16& rCnt) +{ + rCnt = 0; + for (auto const& tabWin : GetTabWinMap()) + { + if(static_cast<OQueryTableWindow*>(tabWin.second.get())->ExistsField(rFieldName, rInfo)) + ++rCnt; + } + // TODO JNA : what should we rCnt > 1? + + return rCnt == 1; +} + +bool OQueryTableView::ContainsTabWin(const OTableWindow& rTabWin) +{ + + for (auto const& tabWin : GetTabWinMap()) + { + if ( tabWin.second == &rTabWin ) + { + return true; + } + } + + return false; +} + +void OQueryTableView::RemoveTabWin(OTableWindow* pTabWin) +{ + OSL_ENSURE(pTabWin != nullptr, "OQueryTableView::RemoveTabWin : Window should not be NULL !"); + + if(!(pTabWin && ContainsTabWin(*pTabWin))) // #i122589# check if registered before deleting + return; + + // I need my parent so it can be informed about the deletion + OQueryDesignView* pParent = static_cast<OQueryDesignView*>(getDesignView()); + + SfxUndoManager& rUndoMgr = m_pView->getController().GetUndoManager(); + rUndoMgr.EnterListAction(DBA_RES(STR_QUERY_UNDO_TABWINDELETE) , OUString(), 0, ViewShellId(-1)); + + // add the Undo-Action + std::unique_ptr<OQueryTabWinDelUndoAct> pUndoAction(new OQueryTabWinDelUndoAct(this)); + pUndoAction->SetTabWin(static_cast< OQueryTableWindow*>(pTabWin)); + + // and hide the window + HideTabWin(static_cast< OQueryTableWindow*>(pTabWin), pUndoAction.get()); + + // Undo Actions and delete the fields in SelectionBrowseBox + pParent->TableDeleted( static_cast< OQueryTableWindowData*>(pTabWin->GetData().get())->GetAliasName() ); + + m_pView->getController().addUndoActionAndInvalidate( std::move(pUndoAction) ); + rUndoMgr.LeaveListAction(); + + modified(); + if ( m_pAccessible ) + m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD, + Any(pTabWin->GetAccessible()), + Any() + ); +} + +void OQueryTableView::EnsureVisible(const OTableWindow* pWin) +{ + + Invalidate(InvalidateFlags::NoChildren); + OJoinTableView::EnsureVisible(pWin); +} + +void OQueryTableView::GetConnection(OQueryTableConnection* pConn) +{ + // add to me and the document + + addConnection( pConn ); +} + +void OQueryTableView::DropConnection(VclPtr<OQueryTableConnection> const & rConn) +{ + // Pay attention to the selection + // remove from me and the document + VclPtr<OTableConnection> xConn(rConn.get()); + RemoveConnection(xConn, false); +} + +void OQueryTableView::HideTabWin( OQueryTableWindow* pTabWin, OQueryTabWinUndoAct* pUndoAction ) +{ + OTableWindowMap& rTabWins = GetTabWinMap(); + + // Window + // save the position in its data + getDesignView()->SaveTabWinUIConfig(pTabWin); + // (I need to go via the parent, as only the parent knows the position of the scrollbars) + // and then out of the TabWins list and hide + OTableWindowMap::const_iterator aIter = std::find_if(rTabWins.begin(), rTabWins.end(), + [&pTabWin](const OTableWindowMap::value_type& rEntry) { return rEntry.second == pTabWin; }); + if (aIter != rTabWins.end()) + rTabWins.erase( aIter ); + + pTabWin->Hide(); // do not destroy it, as it is still in the undo list!! + + // the TabWin data must also be passed out of my responsibility + TTableWindowData& rTabWinDataList = m_pView->getController().getTableWindowData(); + rTabWinDataList.erase( std::remove(rTabWinDataList.begin(), rTabWinDataList.end(), pTabWin->GetData()), rTabWinDataList.end()); + // The data should not be destroyed as TabWin itself - which is still alive - needs them + // Either it goes back into my responsibility, (via ShowTabWin), then I add the data back, + // or the Undo-Action, which currently has full responsibility for the window + // and its data, gets destroyed and destroys both the window and its data + + if (m_pLastFocusTabWin == pTabWin) + m_pLastFocusTabWin = nullptr; + + // collect connections belonging to the window and pass to UndoAction + sal_Int16 nCnt = 0; + const auto& rTabConList = getTableConnections(); + auto aIter2 = rTabConList.begin(); + for(;aIter2 != rTabConList.end();)// the end may change + { + VclPtr<OTableConnection> xTmpEntry = *aIter2; + OQueryTableConnection* pTmpEntry = static_cast<OQueryTableConnection*>(xTmpEntry.get()); + OSL_ENSURE(pTmpEntry,"OQueryTableConnection is null!"); + if( pTmpEntry->GetAliasName(JTCS_FROM) == pTabWin->GetAliasName() || + pTmpEntry->GetAliasName(JTCS_TO) == pTabWin->GetAliasName() ) + { + // add to undo list + pUndoAction->InsertConnection(xTmpEntry); + + // call base class because we append an undo action + // but this time we are in an undo action list + OJoinTableView::RemoveConnection(xTmpEntry, false); + aIter2 = rTabConList.begin(); + ++nCnt; + } + else + ++aIter2; + } + + if (nCnt) + InvalidateConnections(); + + m_pView->getController().InvalidateFeature(ID_BROWSER_ADDTABLE); + + // inform the UndoAction that the window and connections belong to it + pUndoAction->SetOwnership(true); + + // by doing so, we have modified the document + m_pView->getController().setModified( true ); + m_pView->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY); +} + +bool OQueryTableView::ShowTabWin( OQueryTableWindow* pTabWin, OQueryTabWinUndoAct* pUndoAction, bool _bAppend ) +{ + + bool bSuccess = false; + + if (pTabWin) + { + if (pTabWin->Init()) + { + TTableWindowData::value_type pData = pTabWin->GetData(); + OSL_ENSURE(pData != nullptr, "OQueryTableView::ShowTabWin : TabWin has no data !"); + // If there is a position and size defined, we use them + if (pData->HasPosition() && pData->HasSize()) + { + Size aSize(CalcZoom(pData->GetSize().Width()),CalcZoom(pData->GetSize().Height())); + pTabWin->SetPosSizePixel(pData->GetPosition(), aSize); + } + else + // else set a default position + SetDefaultTabWinPosSize(pTabWin); + + // Show the window and add to the list + OUString sName = static_cast< OQueryTableWindowData*>(pData.get())->GetAliasName(); + OSL_ENSURE(GetTabWinMap().find(sName) == GetTabWinMap().end(),"Alias name already in list!"); + GetTabWinMap().emplace(sName,pTabWin); + + pTabWin->Show(); + + pTabWin->PaintImmediately(); + // We must call Update() in order to show the connections in the window correctly. This sounds strange, + // but the Listbox has an internal Member which is initialized when the Listbox is first shown (after the Listbox + // is filled in Init). This Member will eventually be needed for + // GetEntryPos, and then in turn by the Connection, when its starting point to the window must be determined. + + // the Connections + auto rTableCon = pUndoAction->GetTabConnList(); + for(const auto& conn : rTableCon) + addConnection(conn); // add all connections from the undo action + + rTableCon.clear(); + + // and add the window's data to the list (of the document) + if(_bAppend) + m_pView->getController().getTableWindowData().push_back(pTabWin->GetData()); + + m_pView->getController().InvalidateFeature(ID_BROWSER_ADDTABLE); + + // and inform the UndoAction that the window belongs to me + pUndoAction->SetOwnership(false); + + bSuccess = true; + } + else + { + // Initialisation failed + // (for example when the Connection to the database is not available at the moment) + pTabWin->clearListBox(); + pTabWin->disposeOnce(); + } + } + + // show that I have changed the document + if(!m_pView->getController().isReadOnly()) + m_pView->getController().setModified( true ); + + m_pView->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY); + + return bSuccess; +} + +void OQueryTableView::InsertField(const OTableFieldDescRef& rInfo) +{ + OSL_ENSURE(getDesignView() != nullptr, "OQueryTableView::InsertField : has no Parent !"); + static_cast<OQueryDesignView*>(getDesignView())->InsertField(rInfo); +} + +bool OQueryTableView::ExistsAVisitedConn(const OQueryTableWindow* pFrom) const +{ + for(const auto& conn : getTableConnections()) + { + OQueryTableConnection* pTemp = static_cast<OQueryTableConnection*>(conn.get()); + if (pTemp->IsVisited() && + (pFrom == static_cast< OQueryTableWindow*>(pTemp->GetSourceWin()) || pFrom == static_cast< OQueryTableWindow*>(pTemp->GetDestWin()))) + return true; + } + + return false; +} + +void OQueryTableView::onNoColumns_throw() +{ + OUString sError(DBA_RES(STR_STATEMENT_WITHOUT_RESULT_SET)); + ::dbtools::throwSQLException( sError, ::dbtools::StandardSQLState::GENERAL_ERROR, nullptr ); +} + +bool OQueryTableView::suppressCrossNaturalJoin(const TTableConnectionData::value_type& _pData) const +{ + OQueryTableConnectionData* pQueryData = static_cast<OQueryTableConnectionData*>(_pData.get()); + return pQueryData && (pQueryData->GetJoinType() == CROSS_JOIN); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryTextView.cxx b/dbaccess/source/ui/querydesign/QueryTextView.cxx new file mode 100644 index 000000000..daeb6ee14 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTextView.cxx @@ -0,0 +1,177 @@ +/* -*- 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 <svx/svxids.hrc> +#include <QueryTextView.hxx> +#include <querycontainerwindow.hxx> +#include <helpids.h> +#include <querycontroller.hxx> +#include <sqledit.hxx> +#include <undosqledit.hxx> + +using namespace dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +// end of temp classes +OQueryTextView::OQueryTextView(OQueryContainerWindow* pParent, OQueryController& rController) + : InterimItemWindow(pParent, "dbaccess/ui/queryview.ui", "QueryView") + , m_rController(rController) + , m_xSQL(new SQLEditView(m_xBuilder->weld_scrolled_window("scrolledwindow", true))) + , m_xSQLEd(new weld::CustomWeld(*m_xBuilder, "sql", *m_xSQL)) + , m_timerUndoActionCreation("dbaccess OQueryTextView m_timerUndoActionCreation") + , m_timerInvalidate("dbaccess OQueryTextView m_timerInvalidate") + , m_bStopTimer(false) +{ + m_xSQL->DisableInternalUndo(); + m_xSQL->SetHelpId(HID_CTL_QRYSQLEDIT); + m_xSQL->SetModifyHdl(LINK(this, OQueryTextView, ModifyHdl)); + m_xSQL->SetAcceptsTab(true); + + m_timerUndoActionCreation.SetTimeout(1000); + m_timerUndoActionCreation.SetInvokeHandler(LINK(this, OQueryTextView, OnUndoActionTimer)); + + m_timerInvalidate.SetTimeout(200); + m_timerInvalidate.SetInvokeHandler(LINK(this, OQueryTextView, OnInvalidateTimer)); + m_timerInvalidate.Start(); +} + +IMPL_LINK_NOARG(OQueryTextView, ModifyHdl, LinkParamNone*, void) +{ + if (m_timerUndoActionCreation.IsActive()) + m_timerUndoActionCreation.Stop(); + m_timerUndoActionCreation.Start(); + + if (!m_rController.isModified()) + m_rController.setModified(true); + + m_rController.InvalidateFeature(SID_SBA_QRY_EXECUTE); + m_rController.InvalidateFeature(SID_CUT); + m_rController.InvalidateFeature(SID_COPY); +} + +IMPL_LINK_NOARG(OQueryTextView, OnUndoActionTimer, Timer*, void) +{ + OUString aText = m_xSQL->GetText(); + if (aText == m_strOrigText) + return; + + SfxUndoManager& rUndoMgr = m_rController.GetUndoManager(); + std::unique_ptr<OSqlEditUndoAct> xUndoAct(new OSqlEditUndoAct(*this)); + + xUndoAct->SetOriginalText(m_strOrigText); + rUndoMgr.AddUndoAction(std::move(xUndoAct)); + + m_rController.InvalidateFeature(SID_UNDO); + m_rController.InvalidateFeature(SID_REDO); + + m_strOrigText = aText; +} + +IMPL_LINK_NOARG(OQueryTextView, OnInvalidateTimer, Timer*, void) +{ + m_rController.InvalidateFeature(SID_CUT); + m_rController.InvalidateFeature(SID_COPY); + if (!m_bStopTimer) + m_timerInvalidate.Start(); +} + +void OQueryTextView::startTimer() +{ + m_bStopTimer = false; + if (!m_timerInvalidate.IsActive()) + m_timerInvalidate.Start(); +} + +void OQueryTextView::stopTimer() +{ + m_bStopTimer = true; + if (m_timerInvalidate.IsActive()) + m_timerInvalidate.Stop(); +} + +OQueryTextView::~OQueryTextView() { disposeOnce(); } + +void OQueryTextView::dispose() +{ + if (m_timerUndoActionCreation.IsActive()) + m_timerUndoActionCreation.Stop(); + + m_xSQLEd.reset(); + m_xSQL.reset(); + InterimItemWindow::dispose(); +} + +void OQueryTextView::GetFocus() +{ + if (m_xSQL) + { + m_xSQL->GrabFocus(); + m_strOrigText = m_xSQL->GetText(); + } + InterimItemWindow::GetFocus(); +} + +OUString OQueryTextView::getStatement() const { return m_xSQL->GetText(); } + +void OQueryTextView::clear() +{ + std::unique_ptr<OSqlEditUndoAct> xUndoAct(new OSqlEditUndoAct(*this)); + + xUndoAct->SetOriginalText(m_xSQL->GetText()); + m_rController.addUndoActionAndInvalidate(std::move(xUndoAct)); + + SetSQLText(OUString()); +} + +void OQueryTextView::setStatement(const OUString& rsStatement) { SetSQLText(rsStatement); } + +OUString OQueryTextView::GetSQLText() const { return m_xSQL->GetText(); } + +void OQueryTextView::SetSQLText(const OUString& rNewText) +{ + if (m_timerUndoActionCreation.IsActive()) + { + // create the trailing undo-actions + m_timerUndoActionCreation.Stop(); + OnUndoActionTimer(nullptr); + } + + m_xSQL->SetTextAndUpdate(rNewText); + + m_strOrigText = rNewText; +} + +void OQueryTextView::copy() { m_xSQL->Copy(); } + +bool OQueryTextView::isCutAllowed() const { return m_xSQL->HasSelection(); } + +void OQueryTextView::cut() +{ + m_xSQL->Cut(); + m_rController.setModified(true); +} + +void OQueryTextView::paste() +{ + m_xSQL->Paste(); + m_rController.setModified(true); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryViewSwitch.cxx b/dbaccess/source/ui/querydesign/QueryViewSwitch.cxx new file mode 100644 index 000000000..a51f2941a --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryViewSwitch.cxx @@ -0,0 +1,292 @@ +/* -*- 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 <QueryViewSwitch.hxx> +#include <QueryDesignView.hxx> +#include <QueryTextView.hxx> +#include <querycontainerwindow.hxx> +#include <adtabdlg.hxx> +#include <querycontroller.hxx> + +using namespace dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +OQueryViewSwitch::OQueryViewSwitch(OQueryContainerWindow* _pParent, OQueryController& _rController,const Reference< XComponentContext >& _rxContext) +: m_bAddTableDialogWasVisible(false) +{ + + m_pTextView = VclPtr<OQueryTextView>::Create(_pParent, _rController); + m_pDesignView = VclPtr<OQueryDesignView>::Create( _pParent, _rController, _rxContext ); +} + +OQueryViewSwitch::~OQueryViewSwitch() +{ + // destroy children + m_pDesignView.disposeAndClear(); + m_pTextView.disposeAndClear(); +} + +void OQueryViewSwitch::Construct() +{ + m_pDesignView->Construct( ); +} + +void OQueryViewSwitch::initialize() +{ + // initially be in SQL mode + m_pTextView->Show(); + m_pDesignView->initialize(); +} + +bool OQueryViewSwitch::checkStatement() +{ + if(m_pTextView->IsVisible()) + return true; + return m_pDesignView->checkStatement(); +} + +OUString OQueryViewSwitch::getStatement() +{ + if(m_pTextView->IsVisible()) + return m_pTextView->getStatement(); + return m_pDesignView->getStatement(); +} + +void OQueryViewSwitch::clear() +{ + if(m_pTextView->IsVisible()) + m_pTextView->clear(); + else + m_pDesignView->clear(); +} + +void OQueryViewSwitch::GrabFocus() +{ + if ( m_pTextView && m_pTextView->IsVisible() ) + m_pTextView->GrabFocus(); + else if ( m_pDesignView && m_pDesignView->IsVisible() ) + m_pDesignView->GrabFocus(); +} + +void OQueryViewSwitch::setStatement(const OUString& _rsStatement) +{ + if(m_pTextView->IsVisible()) + m_pTextView->setStatement(_rsStatement); +} + +void OQueryViewSwitch::copy() +{ + if(m_pTextView->IsVisible()) + m_pTextView->copy(); + else + m_pDesignView->copy(); +} + +bool OQueryViewSwitch::isCutAllowed() const +{ + if(m_pTextView->IsVisible()) + return m_pTextView->isCutAllowed(); + return m_pDesignView->isCutAllowed(); +} + +bool OQueryViewSwitch::isCopyAllowed() const +{ + if(m_pTextView->IsVisible()) + return true; + return m_pDesignView->isCopyAllowed(); +} + +bool OQueryViewSwitch::isPasteAllowed() const +{ + if(m_pTextView->IsVisible()) + return true; + return m_pDesignView->isPasteAllowed(); +} + +void OQueryViewSwitch::cut() +{ + if(m_pTextView->IsVisible()) + m_pTextView->cut(); + else + m_pDesignView->cut(); +} + +void OQueryViewSwitch::paste() +{ + if(m_pTextView->IsVisible()) + m_pTextView->paste(); + else + m_pDesignView->paste(); +} + +OQueryContainerWindow* OQueryViewSwitch::getContainer() const +{ + vcl::Window* pDesignParent = getDesignView() ? getDesignView()->GetParent() : nullptr; + return static_cast< OQueryContainerWindow* >( pDesignParent ); +} + +void OQueryViewSwitch::impl_forceSQLView() +{ + OAddTableDlg* pAddTabDialog( getAddTableDialog() ); + + // hide the "Add Table" dialog + m_bAddTableDialogWasVisible = pAddTabDialog != nullptr; + if (m_bAddTableDialogWasVisible) + pAddTabDialog->response(RET_CLOSE); + + // tell the views they're in/active + m_pDesignView->stopTimer(); + m_pTextView->startTimer(); + + // set the most recent statement at the text view + m_pTextView->clear(); + m_pTextView->setStatement(static_cast<OQueryController&>(m_pDesignView->getController()).getStatement()); +} + +void OQueryViewSwitch::forceInitialView() +{ + OQueryController& rQueryController( static_cast< OQueryController& >( m_pDesignView->getController() ) ); + const bool bGraphicalDesign = rQueryController.isGraphicalDesign(); + if ( !bGraphicalDesign ) + impl_forceSQLView(); + else + { + // tell the text view it's inactive now + m_pTextView->stopTimer(); + + // update the "Add Table" dialog + OAddTableDlg* pAddTabDialog( getAddTableDialog() ); + if ( pAddTabDialog ) + pAddTabDialog->Update(); + + // initialize the design view + m_pDesignView->initByFieldDescriptions( rQueryController.getFieldInformation() ); + + // tell the design view it's active now + m_pDesignView->startTimer(); + } + + impl_postViewSwitch( bGraphicalDesign, true ); +} + +bool OQueryViewSwitch::switchView( ::dbtools::SQLExceptionInfo* _pErrorInfo ) +{ + bool bRet = true; + bool bGraphicalDesign = static_cast<OQueryController&>(m_pDesignView->getController()).isGraphicalDesign(); + + if ( !bGraphicalDesign ) + { + impl_forceSQLView(); + } + else + { + // tell the text view it's inactive now + m_pTextView->stopTimer(); + + // update the "Add Table" dialog + OAddTableDlg* pAddTabDialog( getAddTableDialog() ); + if ( pAddTabDialog ) + pAddTabDialog->Update(); + + // initialize the design view + bRet = m_pDesignView->initByParseIterator( _pErrorInfo ); + + // tell the design view it's active now + m_pDesignView->startTimer(); + } + + return impl_postViewSwitch( bGraphicalDesign, bRet ); +} + +bool OQueryViewSwitch::impl_postViewSwitch( const bool i_bGraphicalDesign, const bool i_bSuccess ) +{ + if ( i_bSuccess ) + { + m_pTextView->Show ( !i_bGraphicalDesign ); + m_pDesignView->Show ( i_bGraphicalDesign ); + OAddTableDlg* pAddTabDialog( getAddTableDialog() ); + if ( pAddTabDialog ) + if ( i_bGraphicalDesign && m_bAddTableDialogWasVisible ) + m_pDesignView->getController().runDialogAsync(); + + GrabFocus(); + } + + OQueryContainerWindow* pContainer = getContainer(); + if ( pContainer ) + pContainer->Resize(); + + m_pDesignView->getController().ClearUndoManager(); + m_pDesignView->getController().InvalidateAll(); + + return i_bSuccess; +} + +OAddTableDlg* OQueryViewSwitch::getAddTableDialog() +{ + if ( !m_pDesignView ) + return nullptr; + return m_pDesignView->getController().getAddTableDialog(); +} + +bool OQueryViewSwitch::isSlotEnabled(sal_Int32 _nSlotId) +{ + return m_pDesignView->isSlotEnabled(_nSlotId); +} + +void OQueryViewSwitch::setSlotEnabled(sal_Int32 _nSlotId, bool _bEnable) +{ + m_pDesignView->setSlotEnabled(_nSlotId,_bEnable); +} + +void OQueryViewSwitch::SaveUIConfig() +{ + if(m_pDesignView->IsVisible()) + m_pDesignView->SaveUIConfig(); +} + +void OQueryViewSwitch::SetPosSizePixel( Point _rPt,Size _rSize) +{ + m_pDesignView->SetPosSizePixel( _rPt,_rSize); + m_pDesignView->Resize(); + m_pTextView->SetPosSizePixel( _rPt,_rSize); +} + +Reference< XComponentContext > const & OQueryViewSwitch::getORB() const +{ + return m_pDesignView->getORB(); +} + +void OQueryViewSwitch::reset() +{ + m_pDesignView->reset(); + if ( !m_pDesignView->initByParseIterator( nullptr ) ) + return; + + switchView( nullptr ); +} + +void OQueryViewSwitch::setNoneVisibleRow(sal_Int32 _nRows) +{ + if(m_pDesignView) + m_pDesignView->setNoneVisibleRow(_nRows); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx b/dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx new file mode 100644 index 000000000..414d6bbdc --- /dev/null +++ b/dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx @@ -0,0 +1,2720 @@ +/* -*- 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 <string_view> + +#include "SelectionBrowseBox.hxx" +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <JoinExchange.hxx> +#include <QueryDesignView.hxx> +#include <querycontroller.hxx> +#include <sqlbison.hxx> +#include <QueryTableView.hxx> +#include <browserids.hxx> +#include <comphelper/stl_types.hxx> +#include <comphelper/string.hxx> +#include "TableFieldInfo.hxx" +#include <core_resource.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <helpids.h> +#include "QTableWindow.hxx" +#include <vcl/weld.hxx> +#include <vcl/settings.hxx> +#include "QueryDesignFieldUndoAct.hxx" +#include <sqlmessage.hxx> +#include <UITools.hxx> +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> +#include <i18nlangtag/languagetag.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/svapp.hxx> +#include <tools/diagnose_ex.h> +#include <o3tl/string_view.hxx> + +using namespace ::svt; +using namespace ::dbaui; +using namespace ::connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::accessibility; + +#define DEFAULT_QUERY_COLS 20 +#define DEFAULT_SIZE GetTextWidth("0") * 30 +#define HANDLE_ID 0 +#define HANDLE_COLUMN_WIDTH 70 +#define SORT_COLUMN_NONE 0xFFFFFFFF + +namespace +{ + bool isFieldNameAsterisk(const OUString& _sFieldName ) + { + bool bAsterisk = _sFieldName.isEmpty() || _sFieldName.toChar() == '*'; + if ( !bAsterisk ) + { + sal_Int32 nTokenCount = comphelper::string::getTokenCount(_sFieldName, '.'); + if ( (nTokenCount == 2 && o3tl::getToken(_sFieldName,1,'.')[0] == '*' ) + || (nTokenCount == 3 && o3tl::getToken(_sFieldName,2,'.')[0] == '*' ) ) + { + bAsterisk = true; + } + } + return bAsterisk; + } + bool lcl_SupportsCoreSQLGrammar(const Reference< XConnection>& _xConnection) + { + bool bSupportsCoreGrammar = false; + if ( _xConnection.is() ) + { + try + { + Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData(); + bSupportsCoreGrammar = xMetaData.is() && xMetaData->supportsCoreSQLGrammar(); + } + catch(Exception&) + { + } + } + return bSupportsCoreGrammar; + } +} + +OSelectionBrowseBox::OSelectionBrowseBox( vcl::Window* pParent ) + :EditBrowseBox( pParent,EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT, WB_3DLOOK, BrowserMode::COLUMNSELECTION | BrowserMode::KEEPHIGHLIGHT | BrowserMode::HIDESELECT | + BrowserMode::HIDECURSOR | BrowserMode::HLINES | BrowserMode::VLINES ) + ,m_timerInvalidate("dbaccess OSelectionBrowseBox m_timerInvalidate") + ,m_nSeekRow(0) + ,m_nMaxColumns(0) + ,m_aFunctionStrings(DBA_RES(STR_QUERY_FUNCTIONS)) + ,m_nVisibleCount(0) + ,m_nLastSortColumn(SORT_COLUMN_NONE) + ,m_bOrderByUnRelated(true) + ,m_bGroupByUnRelated(true) + ,m_bStopTimer(false) + ,m_bWasEditing(false) + ,m_bDisableErrorBox(false) + ,m_bInUndoMode(false) +{ + SetHelpId(HID_CTL_QRYDGNCRIT); + + m_nMode = BrowserMode::COLUMNSELECTION | BrowserMode::HIDESELECT + | BrowserMode::KEEPHIGHLIGHT | BrowserMode::HIDECURSOR + | BrowserMode::HLINES | BrowserMode::VLINES + | BrowserMode::HEADERBAR_NEW ; + + m_pTextCell = VclPtr<EditControl>::Create(&GetDataWindow()); + m_pVisibleCell = VclPtr<CheckBoxControl>::Create(&GetDataWindow()); + m_pTableCell = VclPtr<ListBoxControl>::Create(&GetDataWindow()); + m_pFieldCell = VclPtr<ComboBoxControl>::Create(&GetDataWindow()); + m_pOrderCell = VclPtr<ListBoxControl>::Create(&GetDataWindow()); + m_pFunctionCell = VclPtr<ListBoxControl>::Create(&GetDataWindow()); + + m_pVisibleCell->SetHelpId(HID_QRYDGN_ROW_VISIBLE); + m_pTableCell->SetHelpId(HID_QRYDGN_ROW_TABLE); + m_pFieldCell->SetHelpId(HID_QRYDGN_ROW_FIELD); + weld::ComboBox& rOrderBox = m_pOrderCell->get_widget(); + m_pOrderCell->SetHelpId(HID_QRYDGN_ROW_ORDER); + m_pFunctionCell->SetHelpId(HID_QRYDGN_ROW_FUNCTION); + + // switch off triState of css::form::CheckBox + m_pVisibleCell->EnableTriState( false ); + + vcl::Font aTitleFont = OutputDevice::GetDefaultFont( DefaultFontType::SANS_UNICODE,Window::GetSettings().GetLanguageTag().getLanguageType(),GetDefaultFontFlags::OnlyOne); + aTitleFont.SetFontSize(Size(0, 6)); + SetTitleFont(aTitleFont); + + const OUString aTxt(DBA_RES(STR_QUERY_SORTTEXT)); + for (sal_Int32 nIdx {0}; nIdx>=0;) + rOrderBox.append_text(OUString(o3tl::getToken(aTxt, 0, ';', nIdx))); + + m_bVisibleRow.insert(m_bVisibleRow.end(), BROW_ROW_CNT, true); + + m_bVisibleRow[BROW_FUNCTION_ROW] = false; // first hide + + m_timerInvalidate.SetTimeout(200); + m_timerInvalidate.SetInvokeHandler(LINK(this, OSelectionBrowseBox, OnInvalidateTimer)); + m_timerInvalidate.Start(); +} + +OSelectionBrowseBox::~OSelectionBrowseBox() +{ + disposeOnce(); +} + +void OSelectionBrowseBox::dispose() +{ + m_pTextCell.disposeAndClear(); + m_pVisibleCell.disposeAndClear(); + m_pFieldCell.disposeAndClear(); + m_pTableCell.disposeAndClear(); + m_pOrderCell.disposeAndClear(); + m_pFunctionCell.disposeAndClear(); + ::svt::EditBrowseBox::dispose(); +} + +void OSelectionBrowseBox::initialize() +{ + Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection(); + if(xConnection.is()) + { + const IParseContext& rContext = static_cast<OQueryController&>(getDesignView()->getController()).getParser().getContext(); + const IParseContext::InternationalKeyCode eFunctions[] = { + IParseContext::InternationalKeyCode::Avg,IParseContext::InternationalKeyCode::Count,IParseContext::InternationalKeyCode::Max + ,IParseContext::InternationalKeyCode::Min,IParseContext::InternationalKeyCode::Sum + ,IParseContext::InternationalKeyCode::Every + ,IParseContext::InternationalKeyCode::Any + ,IParseContext::InternationalKeyCode::Some + ,IParseContext::InternationalKeyCode::StdDevPop + ,IParseContext::InternationalKeyCode::StdDevSamp + ,IParseContext::InternationalKeyCode::VarSamp + ,IParseContext::InternationalKeyCode::VarPop + ,IParseContext::InternationalKeyCode::Collect + ,IParseContext::InternationalKeyCode::Fusion + ,IParseContext::InternationalKeyCode::Intersection + }; + + OUString sGroup = m_aFunctionStrings.copy(m_aFunctionStrings.lastIndexOf(';')+1); + m_aFunctionStrings = m_aFunctionStrings.getToken(0, ';'); + + for (IParseContext::InternationalKeyCode eFunction : eFunctions) + { + m_aFunctionStrings += ";" + OStringToOUString(rContext.getIntlKeywordAscii(eFunction), RTL_TEXTENCODING_UTF8); + } + m_aFunctionStrings += ";" + sGroup; + + // Aggregate functions in general available only with Core SQL + // We slip in a few optionals one, too. + if ( lcl_SupportsCoreSQLGrammar(xConnection) ) + { + weld::ComboBox& rComboBox = m_pFunctionCell->get_widget(); + for (sal_Int32 nIdx {0}; nIdx>=0;) + rComboBox.append_text(m_aFunctionStrings.getToken(0, ';', nIdx)); + } + else // else only COUNT(*) and COUNT("table".*) + { + weld::ComboBox& rComboBox = m_pFunctionCell->get_widget(); + rComboBox.append_text(m_aFunctionStrings.getToken(0, ';')); + rComboBox.append_text(m_aFunctionStrings.getToken(2, ';')); // 2 -> COUNT + } + try + { + Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); + if ( xMetaData.is() ) + { + m_bOrderByUnRelated = xMetaData->supportsOrderByUnrelated(); + m_bGroupByUnRelated = xMetaData->supportsGroupByUnrelated(); + } + } + catch(Exception&) + { + } + } + + Init(); +} + +OQueryDesignView* OSelectionBrowseBox::getDesignView() +{ + OSL_ENSURE(static_cast<const OQueryDesignView*>(GetParent()),"Parent isn't an OQueryDesignView!"); + return static_cast<OQueryDesignView*>(GetParent()); +} + +OQueryDesignView* OSelectionBrowseBox::getDesignView() const +{ + OSL_ENSURE(static_cast<const OQueryDesignView*>(GetParent()),"Parent isn't an OQueryDesignView!"); + return static_cast<OQueryDesignView*>(GetParent()); +} + +namespace +{ + class OSelectionBrwBoxHeader : public ::svt::EditBrowserHeader + { + VclPtr<OSelectionBrowseBox> m_pBrowseBox; + protected: + virtual void Select() override; + public: + explicit OSelectionBrwBoxHeader(OSelectionBrowseBox* pParent); + virtual ~OSelectionBrwBoxHeader() override { disposeOnce(); } + virtual void dispose() override { m_pBrowseBox.clear(); ::svt::EditBrowserHeader::dispose(); } + }; + OSelectionBrwBoxHeader::OSelectionBrwBoxHeader(OSelectionBrowseBox* pParent) + : ::svt::EditBrowserHeader(pParent,WB_BUTTONSTYLE|WB_DRAG) + ,m_pBrowseBox(pParent) + { + } + + void OSelectionBrwBoxHeader::Select() + { + EditBrowserHeader::Select(); + m_pBrowseBox->GrabFocus(); + + BrowserMode nMode = m_pBrowseBox->GetMode(); + if ( 0 == m_pBrowseBox->GetSelectColumnCount() ) + { + m_pBrowseBox->DeactivateCell(); + // we are in the right mode if a row has been selected row + if ( nMode & BrowserMode::HIDESELECT ) + { + nMode &= ~BrowserMode::HIDESELECT; + nMode |= BrowserMode::MULTISELECTION; + m_pBrowseBox->SetMode( nMode ); + } + } + m_pBrowseBox->SelectColumnId( GetCurItemId() ); + m_pBrowseBox->DeactivateCell(); + } +} + +VclPtr<BrowserHeader> OSelectionBrowseBox::imp_CreateHeaderBar(BrowseBox* /*pParent*/) +{ + return VclPtr<OSelectionBrwBoxHeader>::Create(this); +} + +void OSelectionBrowseBox::ColumnMoved( sal_uInt16 nColId, bool _bCreateUndo ) +{ + EditBrowseBox::ColumnMoved( nColId ); + // swap the two columns + sal_uInt16 nNewPos = GetColumnPos( nColId ); + OTableFields& rFields = getFields(); + if ( rFields.size() > o3tl::make_unsigned(nNewPos-1) ) + { + sal_uInt16 nOldPos = 0; + bool bFoundElem = false; + for (auto const& field : rFields) + { + if (field->GetColumnId() == nColId) + { + bFoundElem = true; + break; + } + ++nOldPos; + } + + OSL_ENSURE( (nNewPos-1) != nOldPos && nOldPos < rFields.size(),"Old and new position are equal!"); + if (bFoundElem) + { + OTableFieldDescRef pOldEntry = rFields[nOldPos]; + rFields.erase(rFields.begin() + nOldPos); + rFields.insert(rFields.begin() + nNewPos - 1,pOldEntry); + + // create the undo action + if ( !m_bInUndoMode && _bCreateUndo ) + { + std::unique_ptr<OTabFieldMovedUndoAct> pUndoAct(new OTabFieldMovedUndoAct(this)); + pUndoAct->SetColumnPosition( nOldPos + 1); + pUndoAct->SetTabFieldDescr(pOldEntry); + + getDesignView()->getController().addUndoActionAndInvalidate(std::move(pUndoAct)); + } + } + } + else + OSL_FAIL("Invalid column id!"); +} + +void OSelectionBrowseBox::Init() +{ + + EditBrowseBox::Init(); + + // set the header bar + VclPtr<BrowserHeader> pNewHeaderBar = CreateHeaderBar(this); + pNewHeaderBar->SetMouseTransparent(false); + + SetHeaderBar(pNewHeaderBar); + SetMode(m_nMode); + + vcl::Font aFont( GetDataWindow().GetFont() ); + aFont.SetWeight( WEIGHT_NORMAL ); + GetDataWindow().SetFont( aFont ); + + Size aHeight; + const Control* pControls[] = { m_pTextCell,m_pVisibleCell,m_pTableCell,m_pFieldCell }; + + for (const Control* pControl : pControls) + { + const Size aTemp(pControl->GetOptimalSize()); + if ( aTemp.Height() > aHeight.Height() ) + aHeight.setHeight( aTemp.Height() ); + } + SetDataRowHeight(aHeight.Height()); + SetTitleLines(1); + // get number of visible rows + for(tools::Long i=0;i<BROW_ROW_CNT;i++) + { + if(m_bVisibleRow[i]) + m_nVisibleCount++; + } + RowInserted(0, m_nVisibleCount, false); + try + { + Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection(); + if(xConnection.is()) + { + Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); + m_nMaxColumns = xMetaData.is() ? xMetaData->getMaxColumnsInSelect() : 0; + + } + else + m_nMaxColumns = 0; + } + catch(const SQLException&) + { + TOOLS_WARN_EXCEPTION( "dbaccess", "Caught Exception when asking for database metadata options!"); + m_nMaxColumns = 0; + } +} + +void OSelectionBrowseBox::PreFill() +{ + SetUpdateMode(false); + + if (GetCurRow() != 0) + GoToRow(0); + + static_cast< OQueryController& >( getDesignView()->getController() ).clearFields(); + + DeactivateCell(); + + RemoveColumns(); + InsertHandleColumn( HANDLE_COLUMN_WIDTH ); + SetUpdateMode(true); +} + +void OSelectionBrowseBox::ClearAll() +{ + SetUpdateMode(false); + + OTableFields::const_reverse_iterator aIter = getFields().rbegin(); + for ( ;aIter != getFields().rend(); ++aIter ) + { + if ( !(*aIter)->IsEmpty() ) + { + RemoveField( (*aIter)->GetColumnId() ); + aIter = getFields().rbegin(); + } + } + m_nLastSortColumn = SORT_COLUMN_NONE; + SetUpdateMode(true); +} + +void OSelectionBrowseBox::SetReadOnly(bool bRO) +{ + if (bRO) + { + DeactivateCell(); + m_nMode &= ~BrowserMode::HIDECURSOR; + SetMode(m_nMode); + } + else + { + m_nMode |= BrowserMode::HIDECURSOR; + SetMode(m_nMode); + ActivateCell(); + } +} + +CellController* OSelectionBrowseBox::GetController(sal_Int32 nRow, sal_uInt16 nColId) +{ + if ( nColId > getFields().size() ) + return nullptr; + OTableFieldDescRef pEntry = getFields()[nColId-1]; + OSL_ENSURE(pEntry.is(), "OSelectionBrowseBox::GetController : invalid FieldDescription !"); + + if (!pEntry.is()) + return nullptr; + + if (static_cast<OQueryController&>(getDesignView()->getController()).isReadOnly()) + return nullptr; + + sal_Int32 nCellIndex = GetRealRow(nRow); + switch (nCellIndex) + { + case BROW_FIELD_ROW: + return new ComboBoxCellController(m_pFieldCell); + case BROW_TABLE_ROW: + return new ListBoxCellController(m_pTableCell); + case BROW_VIS_ROW: + return new CheckBoxCellController(m_pVisibleCell); + case BROW_ORDER_ROW: + return new ListBoxCellController(m_pOrderCell); + case BROW_FUNCTION_ROW: + return new ListBoxCellController(m_pFunctionCell); + default: + return new EditCellController(m_pTextCell); + } +} + +void OSelectionBrowseBox::InitController(CellControllerRef& /*rController*/, sal_Int32 nRow, sal_uInt16 nColId) +{ + OSL_ENSURE(nColId != BROWSER_INVALIDID,"An Invalid Id was set!"); + if ( nColId == BROWSER_INVALIDID ) + return; + sal_uInt16 nPos = GetColumnPos(nColId); + if ( nPos == 0 || nPos == BROWSER_INVALIDID || nPos > getFields().size() ) + return; + OTableFieldDescRef pEntry = getFields()[nPos-1]; + OSL_ENSURE(pEntry.is(), "OSelectionBrowseBox::InitController : invalid FieldDescription !"); + sal_Int32 nCellIndex = GetRealRow(nRow); + + switch (nCellIndex) + { + case BROW_FIELD_ROW: + { + weld::ComboBox& rComboBox = m_pFieldCell->get_widget(); + rComboBox.clear(); + rComboBox.set_entry_text(OUString()); + + OUString aField(pEntry->GetField()); + OUString aTable(pEntry->GetAlias()); + + getDesignView()->fillValidFields(aTable, rComboBox); + + // replace with alias.* + if (o3tl::trim(aField) == u"*") + { + aField = aTable + ".*"; + } + rComboBox.set_entry_text(aField); + } break; + case BROW_TABLE_ROW: + { + weld::ComboBox& rComboBox = m_pTableCell->get_widget(); + rComboBox.clear(); + enableControl(pEntry, m_pTableCell); + if ( !pEntry->isCondition() ) + { + for (auto const& tabWin : getDesignView()->getTableView()->GetTabWinMap()) + rComboBox.append_text(static_cast<OQueryTableWindow*>(tabWin.second.get())->GetAliasName()); + + rComboBox.insert_text(0, DBA_RES(STR_QUERY_NOTABLE)); + if (!pEntry->GetAlias().isEmpty()) + rComboBox.set_active_text(pEntry->GetAlias()); + else + rComboBox.set_active_text(DBA_RES(STR_QUERY_NOTABLE)); + } + } break; + case BROW_VIS_ROW: + { + m_pVisibleCell->GetBox().set_active(pEntry->IsVisible()); + m_pVisibleCell->GetBox().save_state(); + + enableControl(pEntry,m_pTextCell); + + if(!pEntry->IsVisible() && pEntry->GetOrderDir() != ORDER_NONE && !m_bOrderByUnRelated) + { + // a column has to visible in order to show up in ORDER BY + pEntry->SetVisible(); + m_pVisibleCell->GetBox().set_active(pEntry->IsVisible()); + m_pVisibleCell->GetBox().save_state(); + m_pVisibleCell->GetBox().set_sensitive(false); + OUString aMessage(DBA_RES(STR_QRY_ORDERBY_UNRELATED)); + OQueryDesignView* paDView = getDesignView(); + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(paDView ? paDView->GetFrameWeld() : nullptr, + VclMessageType::Info, VclButtonsType::Ok, + aMessage)); + xInfoBox->run(); + } + } break; + case BROW_ORDER_ROW: + { + weld::ComboBox& rComboBox = m_pOrderCell->get_widget(); + rComboBox.set_active( + sal::static_int_cast< sal_uInt16 >(pEntry->GetOrderDir())); + enableControl(pEntry,m_pOrderCell); + break; + } + case BROW_COLUMNALIAS_ROW: + setTextCellContext(pEntry,pEntry->GetFieldAlias(),HID_QRYDGN_ROW_ALIAS); + break; + case BROW_FUNCTION_ROW: + setFunctionCell(pEntry); + break; + default: + { + sal_uInt16 nIdx = sal_uInt16(nCellIndex - BROW_CRIT1_ROW); + setTextCellContext(pEntry,pEntry->GetCriteria( nIdx ),HID_QRYDGN_ROW_CRIT); + } + } + Controller()->SaveValue(); +} + +void OSelectionBrowseBox::notifyTableFieldChanged(const OUString& _sOldAlias, std::u16string_view _sAlias, bool& _bListAction, sal_uInt16 _nColumnId) +{ + appendUndoAction(_sOldAlias,_sAlias,BROW_TABLE_ROW,_bListAction); + if ( m_bVisibleRow[BROW_TABLE_ROW] ) + RowModified(GetBrowseRow(BROW_TABLE_ROW), _nColumnId); +} + +void OSelectionBrowseBox::notifyFunctionFieldChanged(const OUString& _sOldFunctionName, std::u16string_view _sFunctionName, bool& _bListAction, sal_uInt16 _nColumnId) +{ + appendUndoAction(_sOldFunctionName,_sFunctionName,BROW_FUNCTION_ROW,_bListAction); + if ( !m_bVisibleRow[BROW_FUNCTION_ROW] ) + SetRowVisible(BROW_FUNCTION_ROW, true); + RowModified(GetBrowseRow(BROW_FUNCTION_ROW), _nColumnId); +} + +void OSelectionBrowseBox::clearEntryFunctionField(const OUString& _sFieldName,OTableFieldDescRef const & _pEntry, bool& _bListAction,sal_uInt16 _nColumnId) +{ + if ( !(isFieldNameAsterisk( _sFieldName ) && (!_pEntry->isNoneFunction() || _pEntry->IsGroupBy())) ) + return; + + OUString sFunctionName; + GetFunctionName(SQL_TOKEN_COUNT,sFunctionName); + OUString sOldLocalizedFunctionName = _pEntry->GetFunction(); + if ( sOldLocalizedFunctionName != sFunctionName || _pEntry->IsGroupBy() ) + { + // append undo action for the function field + _pEntry->SetFunctionType(FKT_NONE); + _pEntry->SetFunction(OUString()); + _pEntry->SetGroupBy(false); + notifyFunctionFieldChanged(sOldLocalizedFunctionName,_pEntry->GetFunction(),_bListAction,_nColumnId); + } +} + +bool OSelectionBrowseBox::fillColumnRef(const OSQLParseNode* _pColumnRef, const Reference< XConnection >& _rxConnection, OTableFieldDescRef const & _pEntry, bool& _bListAction ) +{ + OSL_ENSURE(_pColumnRef,"No valid parsenode!"); + OUString sColumnName,sTableRange; + OSQLParseTreeIterator::getColumnRange(_pColumnRef,_rxConnection,sColumnName,sTableRange); + return fillColumnRef(sColumnName,sTableRange,_rxConnection->getMetaData(),_pEntry,_bListAction); +} + +bool OSelectionBrowseBox::fillColumnRef(const OUString& _sColumnName, std::u16string_view _sTableRange, const Reference<XDatabaseMetaData>& _xMetaData, OTableFieldDescRef const & _pEntry, bool& _bListAction) +{ + bool bError = false; + ::comphelper::UStringMixEqual bCase(_xMetaData->supportsMixedCaseQuotedIdentifiers()); + // check if the table name is the same + if ( !_sTableRange.empty() && (bCase(_pEntry->GetTable(),_sTableRange) || bCase(_pEntry->GetAlias(),_sTableRange)) ) + { // a table was already inserted and the tables contains that column name + + if ( !_pEntry->GetTabWindow() ) + { // fill tab window + OUString sOldAlias = _pEntry->GetAlias(); + if ( !fillEntryTable(_pEntry,_pEntry->GetTable()) ) + fillEntryTable(_pEntry,_pEntry->GetAlias()); // only when the first failed + if ( !bCase(sOldAlias,_pEntry->GetAlias()) ) + notifyTableFieldChanged(sOldAlias,_pEntry->GetAlias(),_bListAction,GetCurColumnId()); + } + } + // check if the table window + OQueryTableWindow* pEntryTab = static_cast<OQueryTableWindow*>(_pEntry->GetTabWindow()); + if ( !pEntryTab ) // no table found with this name so we have to travel through all tables + { + sal_uInt16 nTabCount = 0; + if ( !static_cast<OQueryTableView*>(getDesignView()->getTableView())->FindTableFromField(_sColumnName,_pEntry,nTabCount) ) // error occurred: column not in table window + { + OUString sErrorMsg(DBA_RES(RID_STR_FIELD_DOESNT_EXIST)); + sErrorMsg = sErrorMsg.replaceFirst("$name$",_sColumnName); + OSQLErrorBox aWarning(GetFrameWeld(), sErrorMsg); + aWarning.run(); + bError = true; + } + else + { + pEntryTab = static_cast<OQueryTableWindow*>(_pEntry->GetTabWindow()); + notifyTableFieldChanged(OUString(),_pEntry->GetAlias(),_bListAction,GetCurColumnId()); + } + } + if ( pEntryTab ) // here we got a valid table + _pEntry->SetField(_sColumnName); + + return bError; +} + +bool OSelectionBrowseBox::saveField(OUString& _sFieldName ,OTableFieldDescRef const & _pEntry, bool& _bListAction) +{ + bool bError = false; + + OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController()); + + // first look if the name can be found in our tables + sal_uInt16 nTabCount = 0; + OUString sOldAlias = _pEntry->GetAlias(); + if ( static_cast<OQueryTableView*>(getDesignView()->getTableView())->FindTableFromField(_sFieldName,_pEntry,nTabCount) ) + { + // append undo action for the alias name + _pEntry->SetField(_sFieldName); + notifyTableFieldChanged(sOldAlias,_pEntry->GetAlias(),_bListAction,GetCurColumnId()); + clearEntryFunctionField(_sFieldName,_pEntry,_bListAction,_pEntry->GetColumnId()); + return bError; + } + + Reference<XConnection> xConnection( rController.getConnection() ); + Reference< XDatabaseMetaData > xMetaData; + if ( xConnection.is() ) + xMetaData = xConnection->getMetaData(); + OSL_ENSURE( xMetaData.is(), "OSelectionBrowseBox::saveField: invalid connection/meta data!" ); + if ( !xMetaData.is() ) + return true; + + OUString sErrorMsg; + // second test if the name can be set as select columns in a pseudo statement + // we have to look which entries we should quote + + const OUString sFieldAlias = _pEntry->GetFieldAlias(); + ::connectivity::OSQLParser& rParser( rController.getParser() ); + { + // automatically add parentheses around subqueries + OUString devnull; + std::unique_ptr<OSQLParseNode> pParseNode = rParser.parseTree( devnull, _sFieldName, true ); + if (pParseNode == nullptr) + pParseNode = rParser.parseTree( devnull, _sFieldName ); + if (pParseNode != nullptr && SQL_ISRULE(pParseNode, select_statement)) + _sFieldName = "(" + _sFieldName + ")"; + } + + std::unique_ptr<OSQLParseNode> pParseNode; + { + // 4 passes in trying to interpret the field name + // - don't quote the field name, parse internationally + // - don't quote the field name, parse en-US + // - quote the field name, parse internationally + // - quote the field name, parse en-US + size_t nPass = 4; + OUString sQuotedFullFieldName(::dbtools::quoteName( xMetaData->getIdentifierQuoteString(), _sFieldName )); + OUString sFullFieldName(_sFieldName); + + if ( _pEntry->isAggregateFunction() ) + { + OSL_ENSURE(!_pEntry->GetFunction().isEmpty(),"No empty Function name allowed here! ;-("); + sQuotedFullFieldName = _pEntry->GetFunction() + "(" + sQuotedFullFieldName + ")"; + sFullFieldName = _pEntry->GetFunction() + "(" + sFullFieldName + ")"; + } + + do + { + bool bQuote = ( nPass <= 2 ); + bool bInternational = ( nPass % 2 ) == 0; + + OUString sSql {"SELECT "}; + if ( bQuote ) + sSql += sQuotedFullFieldName; + else + sSql += sFullFieldName; + + if ( !sFieldAlias.isEmpty() ) + { // always quote the alias name: there cannot be a function in it + sSql += " " + ::dbtools::quoteName( xMetaData->getIdentifierQuoteString(), sFieldAlias ); + } + sSql += " FROM x"; + + pParseNode = rParser.parseTree( sErrorMsg, sSql, bInternational ); + } + while ( ( pParseNode == nullptr ) && ( --nPass > 0 ) ); + } + + if ( pParseNode == nullptr ) + { + // something different which we have to check + OUString sErrorMessage( DBA_RES( STR_QRY_COLUMN_NOT_FOUND ) ); + sErrorMessage = sErrorMessage.replaceFirst("$name$",_sFieldName); + OSQLErrorBox aWarning(GetFrameWeld(), sErrorMessage); + aWarning.run(); + + return true; + } + + // we got a valid select column + // find what type of column has be inserted + ::connectivity::OSQLParseNode* pSelection = pParseNode->getChild(2); + if ( SQL_ISRULE(pSelection,selection) ) // we found the asterisk + { + _pEntry->SetField(_sFieldName); + clearEntryFunctionField(_sFieldName,_pEntry,_bListAction,_pEntry->GetColumnId()); + } + else // travel through the select column parse node + { + OTableFieldDescRef aSelEntry = _pEntry; + sal_uInt16 nColumnId = aSelEntry->GetColumnId(); + + sal_uInt32 nCount = pSelection->count(); + for (sal_uInt32 i = 0; i < nCount; ++i) + { + if ( i > 0 ) // may we have to append more than one field + { + sal_uInt16 nColumnPosition; + aSelEntry = FindFirstFreeCol(nColumnPosition); + if ( !aSelEntry.is() ) + { + AppendNewCol(); + aSelEntry = FindFirstFreeCol(nColumnPosition); + } + ++nColumnPosition; + nColumnId = GetColumnId(nColumnPosition); + } + + ::connectivity::OSQLParseNode* pChild = pSelection->getChild( i ); + OSL_ENSURE(SQL_ISRULE(pChild,derived_column), "No derived column found!"); + // get the column alias + OUString sColumnAlias = OSQLParseTreeIterator::getColumnAlias(pChild); + if ( !sColumnAlias.isEmpty() ) // we found an as clause + { + OUString aSelectionAlias = aSelEntry->GetFieldAlias(); + aSelEntry->SetFieldAlias( sColumnAlias ); + // append undo + appendUndoAction(aSelectionAlias,aSelEntry->GetFieldAlias(),BROW_COLUMNALIAS_ROW,_bListAction); + if ( m_bVisibleRow[BROW_COLUMNALIAS_ROW] ) + RowModified(GetBrowseRow(BROW_COLUMNALIAS_ROW), nColumnId); + } + + ::connectivity::OSQLParseNode* pColumnRef = pChild->getChild(0); + if ( + pColumnRef->getKnownRuleID() != OSQLParseNode::subquery && + pColumnRef->count() == 3 && + SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") && + SQL_ISPUNCTUATION(pColumnRef->getChild(2),")") + ) + pColumnRef = pColumnRef->getChild(1); + + if ( SQL_ISRULE(pColumnRef,column_ref) ) // we found a valid column name or more column names + { + // look if we can find the corresponding table + bError = fillColumnRef( pColumnRef, xConnection, aSelEntry, _bListAction ); + + // we found a simple column so we must clear the function fields but only when the column name is '*' + // and the function is different to count + clearEntryFunctionField(_sFieldName,aSelEntry,_bListAction,nColumnId); + } + // do we have an aggregate function and only a function? + else if ( SQL_ISRULE(pColumnRef,general_set_fct) ) + { + OUString sLocalizedFunctionName; + if ( GetFunctionName(pColumnRef->getChild(0)->getTokenID(),sLocalizedFunctionName) ) + { + OUString sOldLocalizedFunctionName = aSelEntry->GetFunction(); + aSelEntry->SetFunction(sLocalizedFunctionName); + sal_uInt32 nFunCount = pColumnRef->count() - 1; + sal_Int32 nFunctionType = FKT_AGGREGATE; + bool bQuote = false; + // may be there exists only one parameter which is a column, fill all information into our fields + if ( nFunCount == 4 && SQL_ISRULE(pColumnRef->getChild(3),column_ref) ) + bError = fillColumnRef( pColumnRef->getChild(3), xConnection, aSelEntry, _bListAction ); + else if ( nFunCount == 3 ) // we have a COUNT(*) here, so take the first table + bError = fillColumnRef( "*", std::u16string_view(), xMetaData, aSelEntry, _bListAction ); + else + { + nFunctionType |= FKT_NUMERIC; + bQuote = true; + aSelEntry->SetDataType(DataType::DOUBLE); + aSelEntry->SetFieldType(TAB_NORMAL_FIELD); + } + + // now parse the parameters + OUString sParameters; + for(sal_uInt32 function = 2; function < nFunCount; ++function) // we only want to parse the parameters of the function + pColumnRef->getChild(function)->parseNodeToStr( sParameters, xConnection, &rParser.getContext(), true, bQuote ); + + aSelEntry->SetFunctionType(nFunctionType); + aSelEntry->SetField(sParameters); + if ( aSelEntry->IsGroupBy() ) + { + sOldLocalizedFunctionName = m_aFunctionStrings.copy(m_aFunctionStrings.lastIndexOf(';')+1); + aSelEntry->SetGroupBy(false); + } + + // append undo action + notifyFunctionFieldChanged(sOldLocalizedFunctionName,sLocalizedFunctionName,_bListAction, nColumnId); + } + else + OSL_FAIL("Unsupported function inserted!"); + + } + else + { + // so we first clear the function field + clearEntryFunctionField(_sFieldName,aSelEntry,_bListAction,nColumnId); + OUString sFunction; + pColumnRef->parseNodeToStr( sFunction, + xConnection, + &rController.getParser().getContext(), + true); // quote is to true because we need quoted elements inside the function + + getDesignView()->fillFunctionInfo(pColumnRef,sFunction,aSelEntry); + + if( SQL_ISRULEOR3(pColumnRef, position_exp, extract_exp, fold) || + SQL_ISRULEOR3(pColumnRef, char_substring_fct, length_exp, char_value_fct) ) + // a calculation has been found ( can be calc and function ) + { + // now parse the whole statement + sal_uInt32 nFunCount = pColumnRef->count(); + OUString sParameters; + for(sal_uInt32 function = 0; function < nFunCount; ++function) + pColumnRef->getChild(function)->parseNodeToStr( sParameters, xConnection, &rParser.getContext(), true ); + + sOldAlias = aSelEntry->GetAlias(); + sal_Int32 nNewFunctionType = aSelEntry->GetFunctionType() | FKT_NUMERIC | FKT_OTHER; + aSelEntry->SetFunctionType(nNewFunctionType); + aSelEntry->SetField(sParameters); + } + else + { + aSelEntry->SetFieldAlias(sColumnAlias); + if ( SQL_ISRULE(pColumnRef,set_fct_spec) ) + aSelEntry->SetFunctionType(/*FKT_NUMERIC | */FKT_OTHER); + else + aSelEntry->SetFunctionType(FKT_NUMERIC | FKT_OTHER); + } + + aSelEntry->SetAlias(OUString()); + notifyTableFieldChanged(sOldAlias,aSelEntry->GetAlias(),_bListAction, nColumnId); + } + + if ( i > 0 && !InsertField(aSelEntry,BROWSER_INVALIDID,true,false).is() ) // may we have to append more than one field + { // the field could not be inserted + OUString sErrorMessage( DBA_RES( RID_STR_FIELD_DOESNT_EXIST ) ); + sErrorMessage = sErrorMessage.replaceFirst("$name$",aSelEntry->GetField()); + OSQLErrorBox aWarning(GetFrameWeld(), sErrorMessage); + aWarning.run(); + bError = true; + } + } + } + + return bError; +} + +bool OSelectionBrowseBox::SaveModified() +{ + OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController()); + OTableFieldDescRef pEntry; + sal_uInt16 nCurrentColumnPos = GetColumnPos(GetCurColumnId()); + if(getFields().size() > o3tl::make_unsigned(nCurrentColumnPos - 1)) + pEntry = getEntry(nCurrentColumnPos - 1); + + bool bWasEmpty = pEntry.is() && pEntry->IsEmpty(); + bool bError = false; + bool bListAction = false; + + if (pEntry.is() && Controller().is() && Controller()->IsValueChangedFromSaved()) + { + // for the Undo-action + OUString strOldCellContents,sNewValue; + sal_Int32 nRow = GetRealRow(GetCurRow()); + bool bAppendRow = false; + switch (nRow) + { + case BROW_VIS_ROW: + { + bool bOldValue = m_pVisibleCell->GetBox().get_saved_state() != TRISTATE_FALSE; + strOldCellContents + = bOldValue ? std::u16string_view(u"1") : std::u16string_view(u"0"); + sNewValue + = !bOldValue ? std::u16string_view(u"1") : std::u16string_view(u"0"); + } + if((m_bOrderByUnRelated || pEntry->GetOrderDir() == ORDER_NONE) && + (m_bGroupByUnRelated || !pEntry->IsGroupBy())) + { + pEntry->SetVisible(m_pVisibleCell->GetBox().get_active()); + } + else + { + pEntry->SetVisible(); + m_pVisibleCell->GetBox().set_active(true); + } + break; + + case BROW_FIELD_ROW: + { + weld::ComboBox& rComboBox = m_pFieldCell->get_widget(); + OUString aFieldName(rComboBox.get_active_text()); + try + { + if (aFieldName.isEmpty()) + { + OTableFieldDescRef pNewEntry = new OTableFieldDesc(); + pNewEntry->SetColumnId( pEntry->GetColumnId() ); + std::replace(getFields().begin(),getFields().end(),pEntry,pNewEntry); + sal_uInt16 nCol = GetCurColumnId(); + for (int i = 0; i < m_nVisibleCount; i++) // redraw column + RowModified(i,nCol); + } + else + { + strOldCellContents = pEntry->GetField(); + bListAction = true; + if ( !m_bInUndoMode ) + rController.GetUndoManager().EnterListAction(OUString(),OUString(),0,ViewShellId(-1)); + + sal_Int32 nPos = rComboBox.find_text(aFieldName); + OUString aAliasName = pEntry->GetAlias(); + if ( nPos != -1 && aAliasName.isEmpty() && aFieldName.indexOf('.') >= 0 ) + { // special case, we have a table field so we must cut the table name + OUString sTableAlias = aFieldName.getToken(0,'.'); + pEntry->SetAlias(sTableAlias); + OUString sColumnName = aFieldName.copy(sTableAlias.getLength()+1); + const Reference<XConnection>& xConnection = rController.getConnection(); + if ( !xConnection.is() ) + return false; + bError = fillColumnRef( sColumnName, sTableAlias, xConnection->getMetaData(), pEntry, bListAction ); + } + else + bError = true; + + if ( bError ) + bError = saveField(aFieldName,pEntry,bListAction); + } + } + catch(Exception&) + { + bError = true; + } + if ( bError ) + { + sNewValue = aFieldName; + if ( !m_bInUndoMode ) + static_cast<OQueryController&>(getDesignView()->getController()).GetUndoManager().LeaveListAction(); + bListAction = false; + } + else + sNewValue = pEntry->GetField(); + rController.InvalidateFeature( ID_BROWSER_QUERY_EXECUTE ); + } + break; + + case BROW_TABLE_ROW: + { + weld::ComboBox& rComboBox = m_pTableCell->get_widget(); + OUString aAliasName = rComboBox.get_active_text(); + strOldCellContents = pEntry->GetAlias(); + if (rComboBox.get_active() != 0) + { + pEntry->SetAlias(aAliasName); + // we have to set the table name as well as the table window + OJoinTableView::OTableWindowMap& rTabWinList = getDesignView()->getTableView()->GetTabWinMap(); + OJoinTableView::OTableWindowMap::const_iterator aIter = rTabWinList.find(aAliasName); + if(aIter != rTabWinList.end()) + { + OQueryTableWindow* pEntryTab = static_cast<OQueryTableWindow*>(aIter->second.get()); + if (pEntryTab) + { + pEntry->SetTable(pEntryTab->GetTableName()); + pEntry->SetTabWindow(pEntryTab); + } + } + } + else + { + pEntry->SetAlias(OUString()); + pEntry->SetTable(OUString()); + pEntry->SetTabWindow(nullptr); + } + sNewValue = pEntry->GetAlias(); + + } break; + + case BROW_ORDER_ROW: + { + strOldCellContents = OUString::number(static_cast<sal_uInt16>(pEntry->GetOrderDir())); + weld::ComboBox& rComboBox = m_pOrderCell->get_widget(); + sal_Int32 nIdx = rComboBox.get_active(); + if (nIdx == -1) + nIdx = 0; + pEntry->SetOrderDir(EOrderDir(nIdx)); + if(!m_bOrderByUnRelated) + { + pEntry->SetVisible(); + m_pVisibleCell->GetBox().set_active(true); + RowModified(GetBrowseRow(BROW_VIS_ROW), GetCurColumnId()); + } + sNewValue = OUString::number(static_cast<sal_uInt16>(pEntry->GetOrderDir())); + } break; + + case BROW_COLUMNALIAS_ROW: + strOldCellContents = pEntry->GetFieldAlias(); + pEntry->SetFieldAlias(m_pTextCell->get_widget().get_text()); + sNewValue = pEntry->GetFieldAlias(); + break; + case BROW_FUNCTION_ROW: + { + strOldCellContents = pEntry->GetFunction(); + weld::ComboBox& rComboBox = m_pFunctionCell->get_widget(); + sal_Int32 nPos = rComboBox.get_active(); + // these functions are only available in CORE + OUString sFunctionName = rComboBox.get_text(nPos); + std::u16string_view sGroupFunctionName = m_aFunctionStrings.subView(m_aFunctionStrings.lastIndexOf(';')+1); + bool bGroupBy = false; + if ( sGroupFunctionName == sFunctionName ) // check if the function name is GROUP + { + bGroupBy = true; + + if ( !m_bGroupByUnRelated && !pEntry->IsVisible() ) + { + // we have to change the visible flag, so we must append also an undo action + pEntry->SetVisible(); + m_pVisibleCell->GetBox().set_active(true); + appendUndoAction("0",u"1",BROW_VIS_ROW,bListAction); + RowModified(GetBrowseRow(BROW_VIS_ROW), GetCurColumnId()); + } + + pEntry->SetFunction(OUString()); + pEntry->SetFunctionType(pEntry->GetFunctionType() & ~FKT_AGGREGATE ); + } + else if ( nPos ) // we found an aggregate function + { + pEntry->SetFunctionType(pEntry->GetFunctionType() | FKT_AGGREGATE ); + pEntry->SetFunction(sFunctionName); + } + else + { + sFunctionName.clear(); + pEntry->SetFunction(OUString()); + pEntry->SetFunctionType(pEntry->GetFunctionType() & ~FKT_AGGREGATE ); + } + + pEntry->SetGroupBy(bGroupBy); + + sNewValue = sFunctionName; + } + break; + default: + { + Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection(); + if(!xConnection.is()) + break; + + sal_uInt16 nIdx = sal_uInt16(nRow - BROW_CRIT1_ROW); + OUString aText = comphelper::string::stripStart(m_pTextCell->get_widget().get_text(), ' '); + + OUString aCrit; + if(!aText.isEmpty()) + { + OUString aErrorMsg; + Reference<XPropertySet> xColumn; + std::unique_ptr<OSQLParseNode> pParseNode = getDesignView()->getPredicateTreeFromEntry(pEntry,aText,aErrorMsg,xColumn); + + if (pParseNode) + { + pParseNode->parseNodeToPredicateStr(aCrit, + xConnection, + static_cast<OQueryController&>(getDesignView()->getController()).getNumberFormatter(), + xColumn, + pEntry->GetAlias(), + getDesignView()->getLocale(), + getDesignView()->getDecimalSeparator(), + &(static_cast<OQueryController&>(getDesignView()->getController()).getParser().getContext())); + } + else + { + if(xColumn.is()) + { + sal_Int32 nType = 0; + xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType; + switch(nType) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + case DataType::CLOB: + if(!aText.startsWith("'") || !aText.endsWith("'")) + { + aText = aText.replaceAll("'", "''"); + aText = "'" + aText + "'"; + } + break; + default: + ; + } + ::connectivity::OSQLParser& rParser = static_cast<OQueryController&>(getDesignView()->getController()).getParser(); + pParseNode = rParser.predicateTree(aErrorMsg, + aText, + static_cast<OQueryController&>(getDesignView()->getController()).getNumberFormatter(), + xColumn); + if (pParseNode) + { + pParseNode->parseNodeToPredicateStr(aCrit, + xConnection, + static_cast<OQueryController&>(getDesignView()->getController()).getNumberFormatter(), + xColumn, + pEntry->GetAlias(), + getDesignView()->getLocale(), + getDesignView()->getDecimalSeparator(), + &(static_cast<OQueryController&>(getDesignView()->getController()).getParser().getContext())); + } + else + { + if ( !m_bDisableErrorBox ) + { + OSQLWarningBox aWarning(GetFrameWeld(), aErrorMsg); + aWarning.run(); + } + bError = true; + } + } + else + { + if ( !m_bDisableErrorBox ) + { + OSQLWarningBox aWarning(GetFrameWeld(), aErrorMsg); + aWarning.run(); + } + bError = true; + } + } + } + strOldCellContents = pEntry->GetCriteria(nIdx); + pEntry->SetCriteria(nIdx, aCrit); + sNewValue = pEntry->GetCriteria(nIdx); + if(!aCrit.isEmpty() && nRow >= (GetRowCount()-1)) + bAppendRow = true; + } + } + if( !bError && Controller().is() ) + Controller()->SaveValue(); + + RowModified(GetCurRow(), GetCurColumnId()); + + if ( bAppendRow ) + { + RowInserted( GetRowCount()-1 ); + m_bVisibleRow.push_back(true); + ++m_nVisibleCount; + } + + if(!bError) + { + // and now the undo-action for the total + appendUndoAction(strOldCellContents,sNewValue,nRow); + + } + } + + // did I store data in a FieldDescription which was empty before and which is not empty anymore after the changes? + if ( pEntry.is() && bWasEmpty && !pEntry->IsEmpty() && !bError ) + { + // Default to visible + pEntry->SetVisible(); + appendUndoAction("0",u"1",BROW_VIS_ROW,bListAction); + RowModified(BROW_VIS_ROW, GetCurColumnId()); + + // if required add empty columns + sal_uInt16 nDummy; + CheckFreeColumns(nDummy); + } + + if ( bListAction && !m_bInUndoMode ) + static_cast<OQueryController&>(getDesignView()->getController()).GetUndoManager().LeaveListAction(); + + return pEntry != nullptr && !bError; +} + +bool OSelectionBrowseBox::SeekRow(sal_Int32 nRow) +{ + m_nSeekRow = nRow; + return nRow < m_nVisibleCount; +} + +void OSelectionBrowseBox::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId) const +{ + rDev.SetClipRegion(vcl::Region(rRect)); + + OTableFieldDescRef pEntry; + sal_uInt16 nPos = GetColumnPos(nColumnId); + if(getFields().size() > o3tl::make_unsigned(nPos - 1)) + pEntry = getFields()[nPos - 1]; + + if (!pEntry.is()) + return; + + sal_Int32 nRow = GetRealRow(m_nSeekRow); + if (nRow == BROW_VIS_ROW) + PaintTristate(rRect, pEntry->IsVisible() ? TRISTATE_TRUE : TRISTATE_FALSE); + else + rDev.DrawText(rRect, GetCellText(nRow, nColumnId),DrawTextFlags::VCenter); + + rDev.SetClipRegion( ); +} + +void OSelectionBrowseBox::PaintStatusCell(OutputDevice& rDev, const tools::Rectangle& rRect) const +{ + tools::Rectangle aRect(rRect); + aRect.TopLeft().AdjustY( -2 ); + OUString aLabel(DBA_RES(STR_QUERY_HANDLETEXT)); + + // from BROW_CRIT2_ROW onwards all rows are shown "or" + sal_Int32 nToken = (m_nSeekRow >= GetBrowseRow(BROW_CRIT2_ROW)) + ? BROW_CRIT2_ROW : GetRealRow(m_nSeekRow); + rDev.DrawText(aRect, aLabel.getToken(nToken, ';'),DrawTextFlags::VCenter); +} + +void OSelectionBrowseBox::RemoveColumn(sal_uInt16 _nColumnId) +{ + OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController()); + + sal_uInt16 nPos = GetColumnPos(_nColumnId); + // the control should always have exactly one more column: the HandleColumn + OSL_ENSURE((nPos == 0) || (nPos <= getFields().size()), "OSelectionBrowseBox::RemoveColumn : invalid parameter nColId"); + // ColId is synonymous to Position, and the condition should be valid + + sal_uInt16 nCurCol = GetCurColumnId(); + sal_Int32 nCurrentRow = GetCurRow(); + + DeactivateCell(); + + getFields().erase( getFields().begin() + (nPos - 1) ); + OTableFieldDescRef pEntry = new OTableFieldDesc(); + pEntry->SetColumnId(_nColumnId); + getFields().push_back(pEntry); + + EditBrowseBox::RemoveColumn( _nColumnId ); + InsertDataColumn( _nColumnId , OUString(), DEFAULT_SIZE ); + + // redraw + tools::Rectangle aInvalidRect = GetInvalidRect( _nColumnId ); + Invalidate( aInvalidRect ); + + ActivateCell( nCurrentRow, nCurCol ); + + rController.setModified( true ); + + invalidateUndoRedo(); +} + +void OSelectionBrowseBox::RemoveField(sal_uInt16 nColumnId ) +{ + OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController()); + + sal_uInt16 nPos = GetColumnPos(nColumnId); + OSL_ENSURE(getFields().size() > o3tl::make_unsigned(nPos-1),"ID is to great!"); + + OTableFieldDescRef pDesc = getEntry(static_cast<sal_uInt32>(nPos - 1)) ; + pDesc->SetColWidth( static_cast<sal_uInt16>(GetColumnWidth(nColumnId)) ); // was not stored this before + + // trigger UndoAction + if ( !m_bInUndoMode ) + { + std::unique_ptr<OTabFieldDelUndoAct> pUndoAction(new OTabFieldDelUndoAct( this )); + pUndoAction->SetTabFieldDescr(pDesc); + pUndoAction->SetColumnPosition(nPos); + rController.addUndoActionAndInvalidate( std::move(pUndoAction) ); + } + + RemoveColumn(nColumnId); + + invalidateUndoRedo(); +} + +void OSelectionBrowseBox::adjustSelectionMode( bool _bClickedOntoHeader, bool _bClickedOntoHandleCol ) +{ + // if a Header has been selected it should be shown otherwise not + if ( _bClickedOntoHeader ) + { + if (0 == GetSelectColumnCount() ) + // I am in the correct mode if a selected column exists + if ( BrowserMode::HIDESELECT == ( m_nMode & BrowserMode::HIDESELECT ) ) + { + m_nMode &= ~BrowserMode::HIDESELECT; + m_nMode |= BrowserMode::MULTISELECTION; + SetMode( m_nMode ); + } + } + else if ( BrowserMode::HIDESELECT != ( m_nMode & BrowserMode::HIDESELECT ) ) + { + if ( GetSelectColumnCount() != 0 ) + SetNoSelection(); + + if ( _bClickedOntoHandleCol ) + { + m_nMode |= BrowserMode::HIDESELECT; + m_nMode &= ~BrowserMode::MULTISELECTION; + SetMode( m_nMode ); + } + } +} + +void OSelectionBrowseBox::MouseButtonDown(const BrowserMouseEvent& rEvt) +{ + if( rEvt.IsLeft() ) + { + bool bOnHandle = HANDLE_ID == rEvt.GetColumnId(); + bool bOnHeader = ( rEvt.GetRow() < 0 ) && !bOnHandle; + adjustSelectionMode( bOnHeader, bOnHandle ); + } + EditBrowseBox::MouseButtonDown(rEvt); +} + +void OSelectionBrowseBox::MouseButtonUp(const BrowserMouseEvent& rEvt) +{ + EditBrowseBox::MouseButtonUp( rEvt ); + static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( ID_BROWSER_QUERY_EXECUTE ); +} + +void OSelectionBrowseBox::KeyInput( const KeyEvent& rEvt ) +{ + if (IsColumnSelected(GetCurColumnId())) + { + if (rEvt.GetKeyCode().GetCode() == KEY_DELETE && // Delete rows + !rEvt.GetKeyCode().IsShift() && + !rEvt.GetKeyCode().IsMod1()) + { + RemoveField(GetCurColumnId()); + return; + } + } + EditBrowseBox::KeyInput(rEvt); +} + +sal_Int8 OSelectionBrowseBox::AcceptDrop( const BrowserAcceptDropEvent& rEvt ) +{ + sal_Int8 nDropAction = DND_ACTION_NONE; + if ( rEvt.GetRow() >= -1 ) + { + if ( IsEditing() ) + { + // allow the asterisk again + m_bDisableErrorBox = true; + SaveModified(); + m_bDisableErrorBox = false; + DeactivateCell(); + } + // check if the format is already supported, if not deactivate the current cell and try again + if ( OJoinExchObj::isFormatAvailable(GetDataFlavors()) ) + nDropAction = DND_ACTION_LINK; + } + + return nDropAction; +} + +sal_Int8 OSelectionBrowseBox::ExecuteDrop( const BrowserExecuteDropEvent& _rEvt ) +{ + + TransferableDataHelper aDropped(_rEvt.maDropEvent.Transferable); + if (!OJoinExchObj::isFormatAvailable(aDropped.GetDataFlavorExVector())) + { + OSL_FAIL("OSelectionBrowseBox::ExecuteDrop: this should never have passed AcceptDrop!"); + return DND_ACTION_NONE; + } + + // insert the field at the selected position + OJoinExchangeData jxdSource = OJoinExchObj::GetSourceDescription(_rEvt.maDropEvent.Transferable); + InsertField(jxdSource); + + return DND_ACTION_LINK; +} + +OTableFieldDescRef const & OSelectionBrowseBox::AppendNewCol( sal_uInt16 nCnt) +{ + // one or more can be created, but the first one will is not returned + sal_uInt32 nCount = getFields().size(); + for (sal_uInt16 i=0 ; i<nCnt ; i++) + { + OTableFieldDescRef pEmptyEntry = new OTableFieldDesc(); + getFields().push_back(pEmptyEntry); + sal_uInt16 nColumnId = sal::static_int_cast< sal_uInt16 >(getFields().size()); + pEmptyEntry->SetColumnId( nColumnId ); + + InsertDataColumn( nColumnId , OUString(), DEFAULT_SIZE ); + } + + return getFields()[nCount]; +} + +void OSelectionBrowseBox::DeleteFields(const OUString& rAliasName) +{ + if (getFields().empty()) + return; + + sal_uInt16 nColId = GetCurColumnId(); + sal_uInt32 nRow = GetCurRow(); + + bool bWasEditing = IsEditing(); + if (bWasEditing) + DeactivateCell(); + + auto aIter = std::find_if(getFields().rbegin(), getFields().rend(), + [&rAliasName](const OTableFieldDescRef pEntry) { return pEntry->GetAlias() == rAliasName; }); + if (aIter != getFields().rend()) + { + sal_uInt16 nPos = sal::static_int_cast<sal_uInt16>(std::distance(aIter, getFields().rend())); + RemoveField( GetColumnId( nPos ) ); + } + + if (bWasEditing) + ActivateCell(nRow , nColId); +} + +void OSelectionBrowseBox::SetColWidth(sal_uInt16 nColId, tools::Long nNewWidth) +{ + bool bWasEditing = IsEditing(); + if (bWasEditing) + DeactivateCell(); + + // create the BaseClass + SetColumnWidth(nColId, nNewWidth); + + // tell it the FieldDescription + OTableFieldDescRef pEntry = getEntry(GetColumnPos(nColId) - 1); + if (pEntry.is()) + pEntry->SetColWidth(sal_uInt16(GetColumnWidth(nColId))); + + if (bWasEditing) + ActivateCell(GetCurRow(), GetCurColumnId()); +} + +tools::Rectangle OSelectionBrowseBox::GetInvalidRect( sal_uInt16 nColId ) +{ + // The rectangle is the full output area of the window + tools::Rectangle aInvalidRect( Point(0,0), GetOutputSizePixel() ); + + // now update the left side + tools::Rectangle aFieldRect(GetCellRect( 0, nColId )); // used instead of GetFieldRectPixel + aInvalidRect.SetLeft( aFieldRect.Left() ); + + return aInvalidRect; +} + +void OSelectionBrowseBox::InsertColumn(const OTableFieldDescRef& pEntry, sal_uInt16& _nColumnPosition) +{ + // the control should have exactly one more column: the HandleColumn + OSL_ENSURE(_nColumnPosition == BROWSER_INVALIDID || (_nColumnPosition <= static_cast<tools::Long>(getFields().size())), "OSelectionBrowseBox::InsertColumn : invalid parameter nColId."); + // -1 means at the end. Count means at the end, others denotes a correct position + + sal_uInt16 nCurCol = GetCurColumnId(); + sal_Int32 nCurrentRow = GetCurRow(); + + DeactivateCell(); + + // remember the column id of the current position + sal_uInt16 nColumnId = GetColumnId(_nColumnPosition); + // put at the end of the list if too small or too big, + if ((_nColumnPosition == BROWSER_INVALIDID) || (_nColumnPosition >= getFields().size())) // append the field + { + if (FindFirstFreeCol(_nColumnPosition) == nullptr) // no more free columns + { + AppendNewCol(); + _nColumnPosition = sal::static_int_cast< sal_uInt16 >( + getFields().size()); + } + else + ++_nColumnPosition; // within the list + nColumnId = GetColumnId(_nColumnPosition); + pEntry->SetColumnId( nColumnId ); + getFields()[ _nColumnPosition - 1] = pEntry; + } + + // check if the column ids are identical, if not we have to move + if ( pEntry->GetColumnId() != nColumnId ) + { + sal_uInt16 nOldPosition = GetColumnPos(pEntry->GetColumnId()); + OSL_ENSURE( nOldPosition != 0,"Old position was 0. Not possible!"); + SetColumnPos(pEntry->GetColumnId(),_nColumnPosition); + // we have to delete an empty field for the fields list, because the columns must have equal length + if ( nOldPosition > 0 && nOldPosition <= getFields().size() ) + getFields()[nOldPosition - 1] = pEntry; + + ColumnMoved(pEntry->GetColumnId(),false); + } + + if ( pEntry->GetFunctionType() & FKT_AGGREGATE ) + { + OUString sFunctionName = pEntry->GetFunction(); + if ( GetFunctionName(sal_uInt32(-1),sFunctionName) ) + pEntry->SetFunction(sFunctionName); + } + + nColumnId = pEntry->GetColumnId(); + + SetColWidth(nColumnId,getDesignView()->getColWidth(GetColumnPos(nColumnId)-1)); + // redraw + tools::Rectangle aInvalidRect = GetInvalidRect( nColumnId ); + Invalidate( aInvalidRect ); + + ActivateCell( nCurrentRow, nCurCol ); + static_cast<OQueryController&>(getDesignView()->getController()).setModified( true ); + + invalidateUndoRedo(); +} + +OTableFieldDescRef OSelectionBrowseBox::InsertField(const OJoinExchangeData& jxdSource) +{ + OQueryTableWindow* pSourceWin = static_cast<OQueryTableWindow*>(jxdSource.pListBox->GetTabWin()); + if (!pSourceWin) + return nullptr; + + // name and position of the selected field + weld::TreeView& rTreeView = jxdSource.pListBox->get_widget(); + OUString aFieldName = rTreeView.get_text(jxdSource.nEntry); + sal_uInt32 nFieldIndex = jxdSource.nEntry; + OTableFieldInfo* pInf = weld::fromId<OTableFieldInfo*>(rTreeView.get_id(jxdSource.nEntry)); + + // construct DragInfo, such that I use the other InsertField + OTableFieldDescRef aInfo = new OTableFieldDesc(pSourceWin->GetTableName(),aFieldName); + aInfo->SetTabWindow(pSourceWin); + aInfo->SetFieldIndex(nFieldIndex); + aInfo->SetFieldType(pInf->GetKeyType()); + aInfo->SetAlias(pSourceWin->GetAliasName()); + + aInfo->SetDataType(pInf->GetDataType()); + aInfo->SetVisible(); + + return InsertField(aInfo); +} + +OTableFieldDescRef OSelectionBrowseBox::InsertField(const OTableFieldDescRef& _rInfo, sal_uInt16 _nColumnPosition, bool bVis, bool bActivate) +{ + + if(m_nMaxColumns && m_nMaxColumns <= FieldsCount()) + return nullptr; + if (bActivate) + SaveModified(); + + // new column description + OTableFieldDescRef pEntry = _rInfo; + pEntry->SetVisible(bVis); + + // insert column + InsertColumn( pEntry, _nColumnPosition ); + + if ( !m_bInUndoMode ) + { + // trigger UndoAction + std::unique_ptr<OTabFieldCreateUndoAct> pUndoAction(new OTabFieldCreateUndoAct( this )); + pUndoAction->SetTabFieldDescr( pEntry ); + pUndoAction->SetColumnPosition(_nColumnPosition); + getDesignView()->getController().addUndoActionAndInvalidate( std::move(pUndoAction) ); + } + + return pEntry; +} + +sal_uInt16 OSelectionBrowseBox::FieldsCount() +{ + sal_uInt16 nCount = 0; + for (auto const& field : getFields()) + { + if (field.is() && !field->IsEmpty()) + ++nCount; + } + + return nCount; +} + +OTableFieldDescRef OSelectionBrowseBox::FindFirstFreeCol(sal_uInt16& _rColumnPosition ) +{ + + _rColumnPosition = BROWSER_INVALIDID; + + for (auto const& field : getFields()) + { + ++_rColumnPosition; + OTableFieldDescRef pEntry = field; + if ( pEntry.is() && pEntry->IsEmpty() ) + return pEntry; + } + + return nullptr; +} + +void OSelectionBrowseBox::CheckFreeColumns(sal_uInt16& _rColumnPosition) +{ + if (FindFirstFreeCol(_rColumnPosition) == nullptr) + { + // it is full, so append a pack of columns + AppendNewCol(DEFAULT_QUERY_COLS); + OSL_VERIFY(FindFirstFreeCol(_rColumnPosition).is()); + } +} + +void OSelectionBrowseBox::AddGroupBy( const OTableFieldDescRef& rInfo ) +{ + Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection(); + if(!xConnection.is()) + return; + OSL_ENSURE(!rInfo->IsEmpty(),"AddGroupBy:: OTableFieldDescRef should not be empty!"); + OTableFieldDescRef pEntry; + const Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData(); + const ::comphelper::UStringMixEqual bCase(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers()); + //sal_Bool bAppend = sal_False; + + bool bAllFieldsSearched = true; + for (auto const& field : getFields()) + { + pEntry = field; + OSL_ENSURE(pEntry.is(),"OTableFieldDescRef was null!"); + + const OUString aField = pEntry->GetField(); + const OUString aAlias = pEntry->GetAlias(); + + if (bCase(aField,rInfo->GetField()) && + bCase(aAlias,rInfo->GetAlias()) && + pEntry->GetFunctionType() == rInfo->GetFunctionType() && + pEntry->GetFunction() == rInfo->GetFunction()) + { + if ( pEntry->isNumericOrAggregateFunction() && rInfo->IsGroupBy() ) + { + pEntry->SetGroupBy(false); + // we do want to consider that bAllFieldsSearched still true here + // bAllFieldsSearched = false; + break; + } + else + { + if ( !pEntry->IsGroupBy() && !pEntry->HasCriteria() ) // here we have a where condition which is no having clause + { + pEntry->SetGroupBy(rInfo->IsGroupBy()); + if(!m_bGroupByUnRelated && pEntry->IsGroupBy()) + pEntry->SetVisible(); + bAllFieldsSearched = false; + break; + } + } + + } + } + + if (bAllFieldsSearched) + { + OTableFieldDescRef pTmp = InsertField(rInfo, BROWSER_INVALIDID, false, false ); + if ( pTmp->isNumericOrAggregateFunction() && rInfo->IsGroupBy() ) // the GroupBy is inherited from rInfo + pTmp->SetGroupBy(false); + } +} + +void OSelectionBrowseBox::DuplicateConditionLevel( const sal_uInt16 nLevel) +{ + const sal_uInt16 nNewLevel = nLevel +1; + for (auto const& field : getFields()) + { + const OTableFieldDescRef& pEntry = field; + OUString sValue = pEntry->GetCriteria(nLevel); + if ( !sValue.isEmpty() ) + { + pEntry->SetCriteria( nNewLevel, sValue); + if ( nNewLevel == (m_nVisibleCount-BROW_CRIT1_ROW-1) ) + { + RowInserted( GetRowCount()-1 ); + m_bVisibleRow.push_back(true); + ++m_nVisibleCount; + } + m_bVisibleRow[BROW_CRIT1_ROW + nNewLevel] = true; + } + } +} + +void OSelectionBrowseBox::AddCondition( const OTableFieldDescRef& rInfo, const OUString& rValue, const sal_uInt16 nLevel,bool _bAddOrOnOneLine ) +{ + Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection(); + if(!xConnection.is()) + return; + OSL_ENSURE(rInfo.is() && !rInfo->IsEmpty(),"AddCondition:: OTableFieldDescRef should not be Empty!"); + + OTableFieldDescRef pLastEntry; + Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData(); + ::comphelper::UStringMixEqual bCase(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers()); + + bool bAllFieldsSearched = true; + for (auto const& field : getFields()) + { + const OTableFieldDescRef& pEntry = field; + const OUString aField = pEntry->GetField(); + const OUString aAlias = pEntry->GetAlias(); + + if (bCase(aField,rInfo->GetField()) && + bCase(aAlias,rInfo->GetAlias()) && + pEntry->GetFunctionType() == rInfo->GetFunctionType() && + pEntry->GetFunction() == rInfo->GetFunction() && + pEntry->IsGroupBy() == rInfo->IsGroupBy() ) + { + if ( pEntry->isNumericOrAggregateFunction() && rInfo->IsGroupBy() ) + pEntry->SetGroupBy(false); + else + { + if(!m_bGroupByUnRelated && pEntry->IsGroupBy()) + pEntry->SetVisible(); + } + if (pEntry->GetCriteria(nLevel).isEmpty() ) + { + pEntry->SetCriteria( nLevel, rValue); + if(nLevel == (m_nVisibleCount-BROW_CRIT1_ROW-1)) + { + RowInserted( GetRowCount()-1 ); + m_bVisibleRow.push_back(true); + ++m_nVisibleCount; + } + m_bVisibleRow[BROW_CRIT1_ROW + nLevel] = true; + bAllFieldsSearched = false; + break; + } + if ( _bAddOrOnOneLine ) + { + pLastEntry = pEntry; + } + } + } + if ( pLastEntry.is() ) + { + OUString sCriteria = rValue; + OUString sOldCriteria = pLastEntry->GetCriteria( nLevel ); + if ( !sOldCriteria.isEmpty() ) + { + sCriteria = "( " + sOldCriteria + " OR " + rValue + " )"; + } + pLastEntry->SetCriteria( nLevel, sCriteria); + if(nLevel == (m_nVisibleCount-BROW_CRIT1_ROW-1)) + { + RowInserted( GetRowCount()-1 ); + m_bVisibleRow.push_back(true); + ++m_nVisibleCount; + } + m_bVisibleRow[BROW_CRIT1_ROW + nLevel] = true; + } + else if (bAllFieldsSearched) + { + OTableFieldDescRef pTmp = InsertField(rInfo, BROWSER_INVALIDID, false, false ); + if ( pTmp->isNumericOrAggregateFunction() && rInfo->IsGroupBy() ) // the GroupBy was inherited from rInfo + pTmp->SetGroupBy(false); + if ( pTmp.is() ) + { + pTmp->SetCriteria( nLevel, rValue); + if(nLevel == (m_nVisibleCount-BROW_CRIT1_ROW-1)) + { + RowInserted( GetRowCount()-1 ); + m_bVisibleRow.push_back(true); + ++m_nVisibleCount; + } + } + } +} + +void OSelectionBrowseBox::AddOrder( const OTableFieldDescRef& rInfo, const EOrderDir eDir, sal_uInt32 _nCurrentPos) +{ + if (_nCurrentPos == 0) + m_nLastSortColumn = SORT_COLUMN_NONE; + + Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection(); + if(!xConnection.is()) + return; + OSL_ENSURE(!rInfo->IsEmpty(),"AddOrder:: OTableFieldDescRef should not be Empty!"); + OTableFieldDescRef pEntry; + Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData(); + ::comphelper::UStringMixEqual bCase(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers()); + + bool bAppend = false; + sal_uInt32 nPos = 0; + bool bAllFieldsSearched = true; + for (auto const& field : getFields()) + { + pEntry = field; + OUString aField = pEntry->GetField(); + OUString aAlias = pEntry->GetAlias(); + + if (bCase(aField,rInfo->GetField()) && + bCase(aAlias,rInfo->GetAlias())) + { + bAppend = (m_nLastSortColumn != SORT_COLUMN_NONE) && (nPos <= m_nLastSortColumn); + if ( bAppend ) + { + // we do want to consider that bAllFieldsSearched still true here + // bAllFieldsSearched = false; + break; + } + else + { + if ( !m_bOrderByUnRelated ) + pEntry->SetVisible(); + pEntry->SetOrderDir( eDir ); + m_nLastSortColumn = nPos; + } + bAllFieldsSearched = false; + break; + } + ++nPos; + } + + if (bAllFieldsSearched) + { + OTableFieldDescRef pTmp = InsertField(rInfo, BROWSER_INVALIDID, false, false ); + if(pTmp.is()) + { + m_nLastSortColumn = pTmp->GetColumnId() - 1; + if ( !m_bOrderByUnRelated && !bAppend ) + pTmp->SetVisible(); + pTmp->SetOrderDir( eDir ); + } + } +} + +bool OSelectionBrowseBox::Save() +{ + bool bRet = true; + if (IsModified()) + bRet = SaveModified(); + return bRet; +} + +void OSelectionBrowseBox::CellModified() +{ + sal_Int32 nRow = GetRealRow(GetCurRow()); + switch (nRow) + { + case BROW_VIS_ROW: + { + OTableFieldDescRef pEntry = getEntry(GetColumnPos(GetCurColumnId()) - 1); + + weld::ComboBox& rComboBox = m_pOrderCell->get_widget(); + sal_Int32 nIdx = rComboBox.get_active(); + if(!m_bOrderByUnRelated && nIdx > 0 && + nIdx != -1 && + !pEntry->IsEmpty() && + pEntry->GetOrderDir() != ORDER_NONE) + { + m_pVisibleCell->GetBox().set_active(true); + pEntry->SetVisible(); + } + else + pEntry->SetVisible(m_pVisibleCell->GetBox().get_active()); + } + break; + } + static_cast<OQueryController&>(getDesignView()->getController()).setModified( true ); +} + +void OSelectionBrowseBox::Fill() +{ + OSL_ENSURE(ColCount() >= 1, "OSelectionBrowseBox::Fill : please call only after inserting the handle column !"); + + sal_uInt16 nColCount = ColCount() - 1; + if (nColCount < DEFAULT_QUERY_COLS) + AppendNewCol(DEFAULT_QUERY_COLS - nColCount); +} + +Size OSelectionBrowseBox::CalcOptimalSize( const Size& _rAvailable ) +{ + Size aReturn( _rAvailable.Width(), GetTitleHeight() ); + + aReturn.AdjustHeight(( m_nVisibleCount ? m_nVisibleCount : 15 ) * GetDataRowHeight() ); + aReturn.AdjustHeight(40 ); // just some space + + return aReturn; +} + +void OSelectionBrowseBox::Command(const CommandEvent& rEvt) +{ + switch (rEvt.GetCommand()) + { + case CommandEventId::ContextMenu: + { + Point aMenuPos( rEvt.GetMousePosPixel() ); + + if (!rEvt.IsMouseEvent()) + { + if ( 1 == GetSelectColumnCount() ) + { + sal_uInt16 nSelId = GetColumnId( + sal::static_int_cast< sal_uInt16 >( + FirstSelectedColumn() ) ); + ::tools::Rectangle aColRect( GetFieldRectPixel( 0, nSelId, false ) ); + + aMenuPos = aColRect.TopCenter(); + } + else + { + EditBrowseBox::Command(rEvt); + return; + } + } + + sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel( aMenuPos.X() )); + sal_Int32 nRow = GetRowAtYPosPixel( aMenuPos.Y() ); + + if (nRow < 0 && nColId > HANDLE_ID ) + { + if ( !IsColumnSelected( nColId ) ) + { + adjustSelectionMode( true /* clicked onto a header */ , false /* not onto the handle col */ ); + SelectColumnId( nColId ); + } + + if (!static_cast<OQueryController&>(getDesignView()->getController()).isReadOnly()) + { + ::tools::Rectangle aRect(aMenuPos, Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/querycolmenu.ui")); + std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu")); + OString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect); + if (sIdent == "delete") + RemoveField(nColId); + else if (sIdent == "width") + adjustBrowseBoxColumnWidth( this, nColId ); + } + } + else if(nRow >= 0 && nColId <= HANDLE_ID) + { + if (!static_cast<OQueryController&>(getDesignView()->getController()).isReadOnly()) + { + ::tools::Rectangle aRect(aMenuPos, Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/queryfuncmenu.ui")); + std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu")); + xContextMenu->set_active("functions", m_bVisibleRow[BROW_FUNCTION_ROW]); + xContextMenu->set_active("tablename", m_bVisibleRow[BROW_TABLE_ROW]); + xContextMenu->set_active("alias", m_bVisibleRow[BROW_COLUMNALIAS_ROW]); + xContextMenu->set_active("distinct", static_cast<OQueryController&>(getDesignView()->getController()).isDistinct()); + + OString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect); + if (sIdent == "functions") + { + SetRowVisible(BROW_FUNCTION_ROW, !IsRowVisible(BROW_FUNCTION_ROW)); + static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( SID_QUERY_VIEW_FUNCTIONS ); + } + else if (sIdent == "tablename") + { + SetRowVisible(BROW_TABLE_ROW, !IsRowVisible(BROW_TABLE_ROW)); + static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( SID_QUERY_VIEW_TABLES ); + } + else if (sIdent == "alias") + { + SetRowVisible(BROW_COLUMNALIAS_ROW, !IsRowVisible(BROW_COLUMNALIAS_ROW)); + static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( SID_QUERY_VIEW_ALIASES ); + } + else if (sIdent == "distinct") + { + static_cast<OQueryController&>(getDesignView()->getController()).setDistinct(!static_cast<OQueryController&>(getDesignView()->getController()).isDistinct()); + static_cast<OQueryController&>(getDesignView()->getController()).setModified( true ); + static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( SID_QUERY_DISTINCT_VALUES ); + } + + static_cast<OQueryController&>(getDesignView()->getController()).setModified( true ); + } + } + else + { + EditBrowseBox::Command(rEvt); + return; + } + + [[fallthrough]]; + } + default: + EditBrowseBox::Command(rEvt); + } +} + +bool OSelectionBrowseBox::IsRowVisible(sal_uInt16 _nWhich) const +{ + OSL_ENSURE(_nWhich<(m_bVisibleRow.size()), "OSelectionBrowseBox::IsRowVisible : invalid parameter !"); + return m_bVisibleRow[_nWhich]; +} + +void OSelectionBrowseBox::SetRowVisible(sal_uInt16 _nWhich, bool _bVis) +{ + OSL_ENSURE(_nWhich<m_bVisibleRow.size(), "OSelectionBrowseBox::SetRowVisible : invalid parameter !"); + + bool bWasEditing = IsEditing(); + if (bWasEditing) + DeactivateCell(); + + // do this before removing or inserting rows, as this triggers ActivateCell-calls, which rely on m_bVisibleRow + m_bVisibleRow[_nWhich] = !m_bVisibleRow[_nWhich]; + + tools::Long nId = GetBrowseRow(_nWhich); + if (_bVis) + { + RowInserted(nId); + ++m_nVisibleCount; + } + else + { + RowRemoved(nId); + --m_nVisibleCount; + } + + if (bWasEditing) + ActivateCell(); +} + +sal_Int32 OSelectionBrowseBox::GetBrowseRow(sal_Int32 nRowId) const +{ + sal_Int32 nCount(0); + for(sal_Int32 i = 0 ; i < nRowId ; ++i) + { + if ( m_bVisibleRow[i] ) + ++nCount; + } + return nCount; +} + +sal_Int32 OSelectionBrowseBox::GetRealRow(sal_Int32 nRowId) const +{ + sal_Int32 nErg=0,i; + const sal_Int32 nCount = m_bVisibleRow.size(); + for(i=0;i < nCount; ++i) + { + if(m_bVisibleRow[i] && nErg++ == nRowId) + break; + } + OSL_ENSURE(nErg <= tools::Long(m_bVisibleRow.size()),"nErg cannot be greater than BROW_ROW_CNT!"); + return i; +} + +const tools::Long nVisibleRowMask[] = + { + 0x0001, + 0x0002, + 0x0004, + 0x0008, + 0x0010, + 0x0020, + 0x0040, + 0x0080, + 0x0100, + 0x0200, + 0x0400, + 0x0800 + }; +sal_Int32 OSelectionBrowseBox::GetNoneVisibleRows() const +{ + sal_Int32 nErg(0); + // only the first 11 rows are interesting + sal_Int32 const nSize = SAL_N_ELEMENTS(nVisibleRowMask); + for(sal_Int32 i=0;i<nSize;i++) + { + if(!m_bVisibleRow[i]) + nErg |= nVisibleRowMask[i]; + } + return nErg; +} + +void OSelectionBrowseBox::SetNoneVisibleRow(sal_Int32 nRows) +{ + // only the first 11 rows are interesting + sal_Int32 const nSize = SAL_N_ELEMENTS(nVisibleRowMask); + for(sal_Int32 i=0;i< nSize;i++) + m_bVisibleRow[i] = !(nRows & nVisibleRowMask[i]); +} + +OUString OSelectionBrowseBox::GetCellText(sal_Int32 nRow, sal_uInt16 nColId) const +{ + + sal_uInt16 nPos = GetColumnPos(nColId); + if ( nPos == 0 || nPos == BROWSER_INVALIDID || nPos > getFields().size() ) + return OUString(); + + OTableFieldDescRef pEntry = getFields()[nPos-1]; + OSL_ENSURE(pEntry != nullptr, "OSelectionBrowseBox::GetCellText : invalid column id, prepare for GPF ... "); + if ( pEntry->IsEmpty() ) + return OUString(); + + OUString aText; + switch (nRow) + { + case BROW_TABLE_ROW: + aText = pEntry->GetAlias(); + break; + case BROW_FIELD_ROW: + { + OUString aField = pEntry->GetField(); + if (!aField.isEmpty() && aField[0] == '*') // * replace with alias.* + { + aField = pEntry->GetAlias(); + if(!aField.isEmpty()) + aField += "."; + aField += "*"; + } + aText = aField; + } break; + case BROW_ORDER_ROW: + if (pEntry->GetOrderDir() != ORDER_NONE) + aText = DBA_RES(STR_QUERY_SORTTEXT).getToken(sal::static_int_cast< sal_uInt16 >(pEntry->GetOrderDir()), ';'); + break; + case BROW_VIS_ROW: + break; + case BROW_COLUMNALIAS_ROW: + aText = pEntry->GetFieldAlias(); + break; + case BROW_FUNCTION_ROW: + // we always show the group function at first + if ( pEntry->IsGroupBy() ) + aText = m_aFunctionStrings.copy(m_aFunctionStrings.lastIndexOf(';')+1); + else if ( pEntry->isNumericOrAggregateFunction() ) + aText = pEntry->GetFunction(); + break; + default: + aText = pEntry->GetCriteria(sal_uInt16(nRow - BROW_CRIT1_ROW)); + } + return aText; +} + +bool OSelectionBrowseBox::GetFunctionName(sal_uInt32 _nFunctionTokenId, OUString& rFkt) +{ + weld::ComboBox& rComboBox = m_pFunctionCell->get_widget(); + switch(_nFunctionTokenId) + { + case SQL_TOKEN_COUNT: + rFkt = (rComboBox.get_count() < 3) ? rComboBox.get_text(1) : rComboBox.get_text(2); + break; + case SQL_TOKEN_AVG: + rFkt = rComboBox.get_text(1); + break; + case SQL_TOKEN_MAX: + rFkt = rComboBox.get_text(3); + break; + case SQL_TOKEN_MIN: + rFkt = rComboBox.get_text(4); + break; + case SQL_TOKEN_SUM: + rFkt = rComboBox.get_text(5); + break; + case SQL_TOKEN_EVERY: + rFkt = rComboBox.get_text(6); + break; + case SQL_TOKEN_ANY: + rFkt = rComboBox.get_text(7); + break; + case SQL_TOKEN_SOME: + rFkt = rComboBox.get_text(8); + break; + case SQL_TOKEN_STDDEV_POP: + rFkt = rComboBox.get_text(9); + break; + case SQL_TOKEN_STDDEV_SAMP: + rFkt = rComboBox.get_text(10); + break; + case SQL_TOKEN_VAR_SAMP: + rFkt = rComboBox.get_text(11); + break; + case SQL_TOKEN_VAR_POP: + rFkt = rComboBox.get_text(12); + break; + case SQL_TOKEN_COLLECT: + rFkt = rComboBox.get_text(13); + break; + case SQL_TOKEN_FUSION: + rFkt = rComboBox.get_text(14); + break; + case SQL_TOKEN_INTERSECTION: + rFkt = rComboBox.get_text(15); + break; + default: + { + const sal_Int32 nStopIdx = m_aFunctionStrings.lastIndexOf(';'); // grouping is not counted + for (sal_Int32 nIdx {0}; nIdx<nStopIdx;) + { + const OUString sFunc {m_aFunctionStrings.getToken(0, ';', nIdx)}; + if (rFkt.equalsIgnoreAsciiCase(sFunc)) + { + rFkt = sFunc; + return true; + } + } + return false; + } + } + + return true; +} + +OUString OSelectionBrowseBox::GetCellContents(sal_Int32 nCellIndex, sal_uInt16 nColId) +{ + if ( GetCurColumnId() == nColId && !m_bInUndoMode ) + SaveModified(); + + sal_uInt16 nPos = GetColumnPos(nColId); + OTableFieldDescRef pEntry = getFields()[nPos - 1]; + OSL_ENSURE(pEntry != nullptr, "OSelectionBrowseBox::GetCellContents : invalid column id, prepare for GPF ... "); + + switch (nCellIndex) + { + case BROW_VIS_ROW : + return OUString(pEntry->IsVisible() ? std::u16string_view(u"1") : std::u16string_view(u"0")); + case BROW_ORDER_ROW: + { + sal_Int32 nIdx = m_pOrderCell->get_widget().get_active(); + if (nIdx == -1) + nIdx = 0; + return OUString::number(nIdx); + } + default: + return GetCellText(nCellIndex, nColId); + } +} + +void OSelectionBrowseBox::SetCellContents(sal_Int32 nRow, sal_uInt16 nColId, const OUString& strNewText) +{ + bool bWasEditing = IsEditing() && (GetCurColumnId() == nColId) && IsRowVisible(static_cast<sal_uInt16>(nRow)) && (GetCurRow() == static_cast<sal_uInt16>(GetBrowseRow(nRow))); + if (bWasEditing) + DeactivateCell(); + + sal_uInt16 nPos = GetColumnPos(nColId); + OTableFieldDescRef pEntry = getEntry(nPos - 1); + OSL_ENSURE(pEntry != nullptr, "OSelectionBrowseBox::SetCellContents : invalid column id, prepare for GPF ... "); + + switch (nRow) + { + case BROW_VIS_ROW: + pEntry->SetVisible(strNewText == "1"); + break; + case BROW_FIELD_ROW: + pEntry->SetField(strNewText); + break; + case BROW_TABLE_ROW: + pEntry->SetAlias(strNewText); + break; + case BROW_ORDER_ROW: + { + sal_uInt16 nIdx = static_cast<sal_uInt16>(strNewText.toInt32()); + pEntry->SetOrderDir(EOrderDir(nIdx)); + } break; + case BROW_COLUMNALIAS_ROW: + pEntry->SetFieldAlias(strNewText); + break; + case BROW_FUNCTION_ROW: + { + std::u16string_view sGroupFunctionName = m_aFunctionStrings.subView(m_aFunctionStrings.lastIndexOf(';')+1); + pEntry->SetFunction(strNewText); + // first reset this two member + sal_Int32 nFunctionType = pEntry->GetFunctionType(); + nFunctionType &= ~FKT_AGGREGATE; + pEntry->SetFunctionType(nFunctionType); + if ( pEntry->IsGroupBy() && !o3tl::equalsIgnoreAsciiCase(sGroupFunctionName, strNewText) ) + pEntry->SetGroupBy(false); + + if ( o3tl::equalsIgnoreAsciiCase(sGroupFunctionName, strNewText) ) + pEntry->SetGroupBy(true); + else if ( !strNewText.isEmpty() ) + { + nFunctionType |= FKT_AGGREGATE; + pEntry->SetFunctionType(nFunctionType); + } + } break; + default: + pEntry->SetCriteria(sal_uInt16(nRow - BROW_CRIT1_ROW), strNewText); + } + + tools::Long nCellIndex = GetRealRow(nRow); + if(IsRowVisible(static_cast<sal_uInt16>(nRow))) + RowModified(nCellIndex, nColId); + + // the appropriate field-description is now empty -> set Visible to sal_False (now it is consistent to normal empty rows) + if (pEntry->IsEmpty()) + pEntry->SetVisible(false); + + if (bWasEditing) + ActivateCell(nCellIndex, nColId); + + static_cast<OQueryController&>(getDesignView()->getController()).setModified( true ); +} + +void OSelectionBrowseBox::ColumnResized(sal_uInt16 nColId) +{ + if (static_cast<OQueryController&>(getDesignView()->getController()).isReadOnly()) + return; + // The resizing of columns can't be suppressed (BrowseBox doesn't support that) so we have to do this + // fake. It's not _that_ bad : the user may change column widths while in read-only mode to see all details + // but the changes aren't permanent ... + + sal_uInt16 nPos = GetColumnPos(nColId); + OSL_ENSURE(nPos <= getFields().size(),"ColumnResized:: nColId should not be greater than List::count!"); + OTableFieldDescRef pEntry = getEntry(nPos-1); + OSL_ENSURE(pEntry.is(), "OSelectionBrowseBox::ColumnResized : invalid FieldDescription !"); + static_cast<OQueryController&>(getDesignView()->getController()).setModified( true ); + EditBrowseBox::ColumnResized(nColId); + + if ( pEntry.is()) + { + if ( !m_bInUndoMode ) + { + // create the undo action + std::unique_ptr<OTabFieldSizedUndoAct> pUndo(new OTabFieldSizedUndoAct(this)); + pUndo->SetColumnPosition( nPos ); + pUndo->SetOriginalWidth(pEntry->GetColWidth()); + getDesignView()->getController().addUndoActionAndInvalidate(std::move(pUndo)); + } + pEntry->SetColWidth(sal_uInt16(GetColumnWidth(nColId))); + } +} + +sal_uInt32 OSelectionBrowseBox::GetTotalCellWidth(sal_Int32 nRowId, sal_uInt16 nColId) +{ + sal_uInt16 nPos = GetColumnPos(nColId); + OSL_ENSURE((nPos == 0) || (nPos <= getFields().size()), "OSelectionBrowseBox::GetTotalCellWidth : invalid parameter nColId"); + + OTableFieldDescRef pEntry = getFields()[nPos-1]; + OSL_ENSURE(pEntry.is(), "OSelectionBrowseBox::GetTotalCellWidth : invalid FieldDescription !"); + + sal_Int32 nRow = GetRealRow(nRowId); + OUString strText(GetCellText(nRow, nColId)); + return GetDataWindow().LogicToPixel(Size(GetDataWindow().GetTextWidth(strText),0)).Width(); +} + +bool OSelectionBrowseBox::isCutAllowed() const +{ + bool bCutAllowed = false; + sal_Int32 nRow = GetRealRow(GetCurRow()); + switch (nRow) + { + case BROW_VIS_ROW: + case BROW_ORDER_ROW: + case BROW_TABLE_ROW: + case BROW_FUNCTION_ROW: + break; + case BROW_FIELD_ROW: + { + weld::ComboBox& rComboBox = m_pFieldCell->get_widget(); + int nStartPos, nEndPos; + bCutAllowed = rComboBox.get_entry_selection_bounds(nStartPos, nEndPos); + break; + } + default: + { + weld::Entry& rEntry = m_pTextCell->get_widget(); + int nStartPos, nEndPos; + bCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos); + break; + } + } + return bCutAllowed; +} + +void OSelectionBrowseBox::cut() +{ + sal_Int32 nRow = GetRealRow(GetCurRow()); + switch (nRow) + { + case BROW_FIELD_ROW: + { + weld::ComboBox& rComboBox = m_pFieldCell->get_widget(); + rComboBox.cut_entry_clipboard(); + break; + } + default: + { + weld::Entry& rEntry = m_pTextCell->get_widget(); + rEntry.cut_clipboard(); + } + } + SaveModified(); + RowModified(GetBrowseRow(nRow), GetCurColumnId()); + + invalidateUndoRedo(); +} + +void OSelectionBrowseBox::paste() +{ + sal_Int32 nRow = GetRealRow(GetCurRow()); + switch (nRow) + { + case BROW_FIELD_ROW: + { + weld::ComboBox& rComboBox = m_pFieldCell->get_widget(); + rComboBox.paste_entry_clipboard(); + break; + } + default: + { + weld::Entry& rEntry = m_pTextCell->get_widget(); + rEntry.paste_clipboard(); + break; + } + } + RowModified(GetBrowseRow(nRow), GetCurColumnId()); + invalidateUndoRedo(); +} + +bool OSelectionBrowseBox::isPasteAllowed() const +{ + bool bPasteAllowed = true; + sal_Int32 nRow = GetRealRow(GetCurRow()); + switch (nRow) + { + case BROW_VIS_ROW: + case BROW_ORDER_ROW: + case BROW_TABLE_ROW: + case BROW_FUNCTION_ROW: + bPasteAllowed = false; + break; + } + return bPasteAllowed; +} + +bool OSelectionBrowseBox::isCopyAllowed() const +{ + return isCutAllowed(); +} + +void OSelectionBrowseBox::copy() +{ + sal_Int32 nRow = GetRealRow(GetCurRow()); + switch (nRow) + { + case BROW_FIELD_ROW: + { + weld::ComboBox& rComboBox = m_pFieldCell->get_widget(); + rComboBox.copy_entry_clipboard(); + break; + } + default: + { + weld::Entry& rEntry = m_pTextCell->get_widget(); + rEntry.copy_clipboard(); + break; + } + } +} + +void OSelectionBrowseBox::appendUndoAction(const OUString& _rOldValue, std::u16string_view _rNewValue, sal_Int32 _nRow, bool& _bListAction) +{ + if ( !m_bInUndoMode && _rNewValue != _rOldValue ) + { + if ( !_bListAction ) + { + _bListAction = true; + static_cast<OQueryController&>(getDesignView()->getController()).GetUndoManager().EnterListAction(OUString(),OUString(),0,ViewShellId(-1)); + } + appendUndoAction(_rOldValue,_rNewValue,_nRow); + } +} + +void OSelectionBrowseBox::appendUndoAction(const OUString& _rOldValue,std::u16string_view _rNewValue,sal_Int32 _nRow) +{ + if ( !m_bInUndoMode && _rNewValue != _rOldValue ) + { + std::unique_ptr<OTabFieldCellModifiedUndoAct> pUndoAct(new OTabFieldCellModifiedUndoAct(this)); + pUndoAct->SetCellIndex(_nRow); + OSL_ENSURE(GetColumnPos(GetCurColumnId()) != BROWSER_INVALIDID,"Current position isn't valid!"); + pUndoAct->SetColumnPosition( GetColumnPos(GetCurColumnId()) ); + pUndoAct->SetCellContents(_rOldValue); + getDesignView()->getController().addUndoActionAndInvalidate(std::move(pUndoAct)); + } +} + +IMPL_LINK_NOARG(OSelectionBrowseBox, OnInvalidateTimer, Timer *, void) +{ + static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature(SID_CUT); + static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature(SID_COPY); + static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature(SID_PASTE); + if(!m_bStopTimer) + m_timerInvalidate.Start(); +} + +void OSelectionBrowseBox::stopTimer() +{ + m_bStopTimer = true; + if (m_timerInvalidate.IsActive()) + m_timerInvalidate.Stop(); +} + +void OSelectionBrowseBox::startTimer() +{ + m_bStopTimer = false; + if (!m_timerInvalidate.IsActive()) + m_timerInvalidate.Start(); +} + +OTableFields& OSelectionBrowseBox::getFields() const +{ + OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController()); + return rController.getTableFieldDesc(); +} + +void OSelectionBrowseBox::enableControl(const OTableFieldDescRef& _rEntry,Window* _pControl) +{ + bool bEnable = !_rEntry->isCondition(); + _pControl->Enable(bEnable); + _pControl->EnableInput(bEnable); +} + +void OSelectionBrowseBox::setTextCellContext(const OTableFieldDescRef& _rEntry,const OUString& _sText,const OString& _sHelpId) +{ + weld::Entry& rEntry = m_pTextCell->get_widget(); + rEntry.set_text(_sText); + rEntry.save_value(); + if (!m_pTextCell->HasFocus()) + m_pTextCell->GrabFocus(); + + enableControl(_rEntry,m_pTextCell); + + if (m_pTextCell->GetHelpId() != _sHelpId) + // as TextCell is used in various contexts I will delete the cached HelpText + m_pTextCell->SetHelpText(OUString()); + m_pTextCell->SetHelpId(_sHelpId); +} + +void OSelectionBrowseBox::invalidateUndoRedo() +{ + OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController()); + rController.InvalidateFeature( ID_BROWSER_UNDO ); + rController.InvalidateFeature( ID_BROWSER_REDO ); + rController.InvalidateFeature( ID_BROWSER_QUERY_EXECUTE ); +} + +OTableFieldDescRef OSelectionBrowseBox::getEntry(OTableFields::size_type _nPos) +{ + // we have to check if we need a new entry at this position + OTableFields& aFields = getFields(); + OSL_ENSURE(aFields.size() > _nPos,"ColID is to great!"); + + OTableFieldDescRef pEntry = aFields[_nPos]; + OSL_ENSURE(pEntry.is(),"Invalid entry!"); + if ( !pEntry.is() ) + { + pEntry = new OTableFieldDesc(); + pEntry->SetColumnId( + GetColumnId(sal::static_int_cast< sal_uInt16 >(_nPos+1))); + aFields[_nPos] = pEntry; + } + return pEntry; +} + +void OSelectionBrowseBox::GetFocus() +{ + if(!IsEditing() && !m_bWasEditing) + ActivateCell(); + EditBrowseBox::GetFocus(); +} + +void OSelectionBrowseBox::DeactivateCell(bool _bUpdate) +{ + m_bWasEditing = true; + EditBrowseBox::DeactivateCell(_bUpdate); + m_bWasEditing = false; +} + +OUString OSelectionBrowseBox::GetRowDescription( sal_Int32 _nRow ) const +{ + OUString aLabel(DBA_RES(STR_QUERY_HANDLETEXT)); + + // from BROW_CRIT2_ROW onwards all rows are shown as "or" + sal_Int32 nToken = (_nRow >= GetBrowseRow(BROW_CRIT2_ROW)) + ? BROW_CRIT2_ROW : GetRealRow(_nRow); + return aLabel.getToken(nToken, ';'); +} + +OUString OSelectionBrowseBox::GetAccessibleObjectName( AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition) const +{ + OUString sRetText; + switch( _eObjType ) + { + case AccessibleBrowseBoxObjType::RowHeaderCell: + sRetText = GetRowDescription(_nPosition); + break; + default: + sRetText = EditBrowseBox::GetAccessibleObjectDescription(_eObjType,_nPosition); + } + return sRetText; +} + +bool OSelectionBrowseBox::fillEntryTable(OTableFieldDescRef const & _pEntry,const OUString& _sTableName) +{ + bool bRet = false; + OJoinTableView::OTableWindowMap& rTabWinList = getDesignView()->getTableView()->GetTabWinMap(); + OJoinTableView::OTableWindowMap::const_iterator aIter = rTabWinList.find(_sTableName); + if(aIter != rTabWinList.end()) + { + OQueryTableWindow* pEntryTab = static_cast<OQueryTableWindow*>(aIter->second.get()); + if (pEntryTab) + { + _pEntry->SetTable(pEntryTab->GetTableName()); + _pEntry->SetTabWindow(pEntryTab); + bRet = true; + } + } + return bRet; +} + +void OSelectionBrowseBox::setFunctionCell(OTableFieldDescRef const & _pEntry) +{ + Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection(); + if ( !xConnection.is() ) + return; + + // Aggregate functions in general only available with Core SQL + if ( lcl_SupportsCoreSQLGrammar(xConnection) ) + { + sal_Int32 nIdx {0}; + // if we have an asterisk, no other function than count is allowed + weld::ComboBox& rComboBox = m_pFunctionCell->get_widget(); + rComboBox.clear(); + rComboBox.append_text(m_aFunctionStrings.getToken(0, ';', nIdx)); + if ( isFieldNameAsterisk(_pEntry->GetField()) ) + rComboBox.append_text(m_aFunctionStrings.getToken(1, ';', nIdx)); // 2nd token: COUNT + else + { + const bool bSkipLastToken {_pEntry->isNumeric()}; + while (nIdx>0) + { + const OUString sTok {m_aFunctionStrings.getToken(0, ';', nIdx)}; + if (bSkipLastToken && nIdx<0) + break; + rComboBox.append_text(sTok); + } + } + + if ( _pEntry->IsGroupBy() ) + { + OSL_ENSURE(!_pEntry->isNumeric(),"Not allowed to combine group by and numeric values!"); + rComboBox.set_active_text(rComboBox.get_text(rComboBox.get_count() - 1)); + } + else if (rComboBox.find_text(_pEntry->GetFunction()) != -1) + rComboBox.set_active_text(_pEntry->GetFunction()); + else + rComboBox.set_active(0); + + enableControl(_pEntry, m_pFunctionCell); + } + else + { + // only COUNT(*) and COUNT("table".*) allowed + bool bCountRemoved = !isFieldNameAsterisk(_pEntry->GetField()); + weld::ComboBox& rComboBox = m_pFunctionCell->get_widget(); + if ( bCountRemoved ) + rComboBox.remove(1); + + if ( !bCountRemoved && rComboBox.get_count() < 2) + rComboBox.append_text(m_aFunctionStrings.getToken(2, ';')); // 2 -> COUNT + + if (rComboBox.find_text(_pEntry->GetFunction()) != -1) + rComboBox.set_active_text(_pEntry->GetFunction()); + else + rComboBox.set_active(0); + } +} + +Reference< XAccessible > OSelectionBrowseBox::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos ) +{ + OTableFieldDescRef pEntry; + if ( _nColumnPos != 0 && _nColumnPos != BROWSER_INVALIDID && _nColumnPos <= getFields().size() ) + pEntry = getFields()[_nColumnPos - 1]; + + if ( _nRow == BROW_VIS_ROW && pEntry.is() ) + return EditBrowseBox::CreateAccessibleCheckBoxCell( _nRow, _nColumnPos,pEntry->IsVisible() ? TRISTATE_TRUE : TRISTATE_FALSE ); + + return EditBrowseBox::CreateAccessibleCell( _nRow, _nColumnPos ); +} + +bool OSelectionBrowseBox::HasFieldByAliasName(std::u16string_view rFieldName, OTableFieldDescRef const & rInfo) const +{ + for (auto const& field : getFields()) + { + if ( field->GetFieldAlias() == rFieldName ) + { + *rInfo = *field; + return true; + } + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/SelectionBrowseBox.hxx b/dbaccess/source/ui/querydesign/SelectionBrowseBox.hxx new file mode 100644 index 000000000..761870fb8 --- /dev/null +++ b/dbaccess/source/ui/querydesign/SelectionBrowseBox.hxx @@ -0,0 +1,324 @@ +/* -*- 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 <string_view> + +#include <svtools/editbrowsebox.hxx> +#include <TableFieldDescription.hxx> +#include <TableWindowListBox.hxx> +#include <QEnumTypes.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> + +namespace connectivity +{ + class OSQLParseNode; +} + +namespace dbaui +{ +#define BROW_FIELD_ROW 0 +#define BROW_COLUMNALIAS_ROW 1 +#define BROW_TABLE_ROW 2 +#define BROW_ORDER_ROW 3 +#define BROW_VIS_ROW 4 +#define BROW_FUNCTION_ROW 5 +#define BROW_CRIT1_ROW 6 +#define BROW_CRIT2_ROW 7 +#define BROW_CRIT3_ROW 8 +#define BROW_CRIT4_ROW 9 +#define BROW_CRIT5_ROW 10 +#define BROW_CRIT6_ROW 11 +#define BROW_ROW_CNT 12 + + class OQueryDesignView; + class OSelectionBrowseBox final : public ::svt::EditBrowseBox + { + friend class OQueryDesignView; + std::vector<bool> m_bVisibleRow; // at pos we find the RowId + Timer m_timerInvalidate; + + sal_Int32 m_nSeekRow; + BrowserMode m_nMode; // remember the BrowseModes + VclPtr< ::svt::EditControl> m_pTextCell; + VclPtr< ::svt::CheckBoxControl> m_pVisibleCell; + VclPtr< ::svt::ComboBoxControl> m_pFieldCell; + VclPtr< ::svt::ListBoxControl> m_pFunctionCell; + VclPtr< ::svt::ListBoxControl> m_pTableCell; + VclPtr< ::svt::ListBoxControl> m_pOrderCell; + + sal_Int32 m_nMaxColumns; // maximum number of columns in a Select-Statement + + OUString m_aFunctionStrings; + sal_uInt16 m_nVisibleCount; // maximum number of visible rows + sal_uInt32 m_nLastSortColumn; // index of last (highest) sort column + bool m_bOrderByUnRelated; + bool m_bGroupByUnRelated; + bool m_bStopTimer; + bool m_bWasEditing; + bool m_bDisableErrorBox; + bool m_bInUndoMode; + + DECL_LINK(OnInvalidateTimer, Timer*, void); + public: + explicit OSelectionBrowseBox( vcl::Window* pParent ); + virtual ~OSelectionBrowseBox() override; + virtual void dispose() override; + + void initialize(); + OTableFieldDescRef InsertField( const OJoinExchangeData& jxdSource ); + OTableFieldDescRef InsertField( const OTableFieldDescRef& rInfo, sal_uInt16 _nColumnPosition = BROWSER_INVALIDID, bool bVis=true, bool bActivate=true ); + void InsertColumn( const OTableFieldDescRef& pEntry, sal_uInt16& _nColumnPosition ); + void RemoveColumn( sal_uInt16 _nColumnId ); + void DeleteFields( const OUString& rAliasName ); + + bool HasFieldByAliasName(std::u16string_view rFieldName, OTableFieldDescRef const & rInfo) const; + + // AddGroupBy:: inserts a field with function == grouping. If the fields already exists and uses an aggregate function, + // the flag is not set + void AddGroupBy( const OTableFieldDescRef& rInfo ); + void AddCondition( const OTableFieldDescRef& rInfo, + const OUString& rValue, + const sal_uInt16 nLevel, + bool _bAddOrOnOneLine ); + void DuplicateConditionLevel( const sal_uInt16 nLevel); + void AddOrder(const OTableFieldDescRef& rInfo, const EOrderDir eDir, sal_uInt32 _nCurrentPos); + void ClearAll(); + OTableFieldDescRef const & AppendNewCol( sal_uInt16 nCnt=1 ); + bool Save(); + OQueryDesignView* getDesignView(); + OQueryDesignView* getDesignView() const; + sal_uInt16 FieldsCount(); + + void SetColWidth(sal_uInt16 nColId, tools::Long lNewWidth); + // unlike SetColumnWidth of the base class it checks an active cell in this column + + OUString GetCellContents(sal_Int32 nCellIndex, sal_uInt16 nColId); + void SetCellContents(sal_Int32 nCellIndex, sal_uInt16 nColId, const OUString& strNewText); + // cell content (formatted as string) set/return + sal_Int32 GetNoneVisibleRows() const; + void SetNoneVisibleRow(sal_Int32 nRows); + bool IsRowVisible(sal_uInt16 _nWhich) const; + void SetRowVisible(sal_uInt16 _nWhich, bool _bVis); + + void SetReadOnly(bool bRO); + // calculate an optimal size. Basically, this takes into account the number of visible rows. + Size CalcOptimalSize( const Size& _rAvailable ); + + // can the current content be cut + bool isPasteAllowed() const; + bool isCutAllowed() const; + bool isCopyAllowed() const; + void cut(); + void paste(); + void copy(); + + virtual void GetFocus() override; + virtual void DeactivateCell(bool bUpdate = true) override; + virtual void ColumnMoved( sal_uInt16 nColId ) override { ColumnMoved(nColId,true); } + void ColumnMoved( sal_uInt16 nColId, bool _bCreateUndo); + + void Fill(); + void PreFill(); + + /** Disables the generation of undo actions + */ + void EnterUndoMode() { m_bInUndoMode = true; } + /** Enables the generation of undo actions + */ + void LeaveUndoMode() { m_bInUndoMode = false; } + + /** GetCellText returns the text at the given position + @param _nRow + the number of the row + @param _nColId + the ID of the column + @return + the text out of the cell + */ + virtual OUString GetCellText(sal_Int32 _nRow, sal_uInt16 _nColId) const override; + + /** returns the description of the row. + @param _nRow + The row number. + @return + The header text of the specified row. + */ + virtual OUString GetRowDescription( sal_Int32 _nRow ) const override; + + /** return the name of the specified object. + @param eObjType + The type to ask for + @param _nPosition + The position of a tablecell (index position), header bar column/row cell + @return + The name of the specified object. + */ + virtual OUString GetAccessibleObjectName( AccessibleBrowseBoxObjType eObjType,sal_Int32 _nPosition = -1) const override; + + // IAccessibleTableProvider + /** Creates the accessible object of a data table cell. + @param nRow The row index of the cell. + @param nColumnId The column ID of the cell. + @return The XAccessible interface of the specified cell. */ + virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessibleCell( sal_Int32 nRow, sal_uInt16 nColumnId ) override; + + private: + virtual bool SeekRow( sal_Int32 nRow ) override; + + virtual void PaintStatusCell(OutputDevice& rDev, const tools::Rectangle& rRect) const override; + virtual void PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, + sal_uInt16 nColumnId ) const override; + + virtual sal_Int8 AcceptDrop( const BrowserAcceptDropEvent& rEvt ) override; + virtual sal_Int8 ExecuteDrop( const BrowserExecuteDropEvent& rEvt ) override; + virtual void MouseButtonDown( const BrowserMouseEvent& rEvt ) override; + virtual void MouseButtonUp( const BrowserMouseEvent& rEvt ) override; + virtual void KeyInput( const KeyEvent& rEvt ) override; + virtual void Command(const CommandEvent& rEvt) override; + + virtual ::svt::CellController* GetController(sal_Int32 nRow, sal_uInt16 nCol) override; + virtual void InitController(::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol) override; + virtual void CellModified() override; + virtual bool SaveModified() override; + virtual void Init() override; + virtual void ColumnResized( sal_uInt16 nColId ) override; + + virtual sal_uInt32 GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId) override; + + // if you want to have an own header ... + virtual VclPtr<BrowserHeader> imp_CreateHeaderBar(BrowseBox* pParent) override; + + void stopTimer(); + void startTimer(); + + OTableFieldDescRef FindFirstFreeCol(sal_uInt16& _rColumnPosition); + + // rCol contains the number (in pOTableFieldDescList) of the first column, which itself tells it is empty + // if there are none, rCol is undefined and the returnvalue NULL + void CheckFreeColumns(sal_uInt16& _rColumnPosition); + // checks if empty columns are available, if not, a new pack is appended + // rCol contains the number of the first empty column (in pOTableFieldDescList) + + void RemoveField( sal_uInt16 nId ); + tools::Rectangle GetInvalidRect( sal_uInt16 nColId ); + sal_Int32 GetRealRow(sal_Int32 nRow) const; + sal_Int32 GetBrowseRow(sal_Int32 nRowId) const; + bool GetFunctionName(sal_uInt32 _nFunctionTokenId, OUString& rFkt); + void appendUndoAction(const OUString& _rOldValue,std::u16string_view _rNewValue,sal_Int32 _nRow, bool& _bListAction); + void appendUndoAction(const OUString& _rOldValue,std::u16string_view _rNewValue,sal_Int32 _nRow); + OTableFields& getFields() const; + static void enableControl(const OTableFieldDescRef& _rEntry,Window* _pControl); + void setTextCellContext(const OTableFieldDescRef& _rEntry,const OUString& _sText,const OString& _sHelpId); + void invalidateUndoRedo(); + OTableFieldDescRef getEntry(OTableFields::size_type _nPos); + + void adjustSelectionMode( bool _bClickedOntoHeader, bool _bClickedOntoHandleCol ); + + /** save the field change in save modified + @param _sFieldName + The field name inserted by the user. + @param _pEntry + The entry which will contain the necessary entries. + @param _bListAction + Will be set to <TRUE/> when we are in a list action otherwise <FALSE/> + @return + <TRUE/> if an error occurred otherwise <FALSE/> + */ + bool saveField(OUString& _sFieldName, OTableFieldDescRef const & _pEntry, bool& _bListAction); + + /** sets the table window at the _pEntry + @param _pEntry + The entry where the window should be set. + @param _sTableName + The table name to search for. + @return + <TRUE/> if the table name was set otherwise <FALSE/> + */ + bool fillEntryTable(OTableFieldDescRef const & _pEntry,const OUString& _sTableName); + + /** uses the parse node to fill all information into the field + @param _pColumnRef + The parse node used to fill the info into the field. + @param _xMetaData + Use to parse the node to a string. + @param _pEntry + The entry which will contain the necessary entries. + @param _bListAction + Will be set to <TRUE/> when we are in a list action otherwise <FALSE/> + @return + <TRUE/> if an error occurred otherwise <FALSE/> + */ + bool fillColumnRef( const ::connectivity::OSQLParseNode* _pColumnRef, + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + OTableFieldDescRef const & _pEntry, + bool& _bListAction); + bool fillColumnRef( const OUString& _sColumnName, + std::u16string_view _sTableRange, + const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _xMetaData, + OTableFieldDescRef const & _pEntry, + bool& _bListAction); + + /** append an undo action for the table field + @param _sOldAlias + The old table alias. + @param _sAlias + The new alias name. + @param _bListAction + Will be set to <TRUE/> when we are in a list action otherwise <FALSE/> + */ + void notifyTableFieldChanged(const OUString& _sOldAlias,std::u16string_view _sAlias, bool& _bListAction,sal_uInt16 _nColumnId); + + /** append an undo action for the function field + @param _sOldFunctionName + The old value. + @param _sFunctionName + The new function name. + @param _bListAction + Will be set to <TRUE/> when we are in a list action otherwise <FALSE/> + */ + void notifyFunctionFieldChanged(const OUString& _sOldFunctionName,std::u16string_view _sFunctionName, bool& _bListAction,sal_uInt16 _nColumnId); + + /** clears the function fields of the submitted entry if it doesn't match the SQL standard and append an undo action. + E.q. AGGREGATE functions are only valid when the field name isn't an asterisk + @param _sFieldName + The field name. + @param _pEntry + The entry to be cleared + @param _bListAction + When <TRUE/> a list action will be created. + */ + void clearEntryFunctionField(const OUString& _sFieldName,OTableFieldDescRef const & _pEntry, bool& _bListAction,sal_uInt16 _nColumnId); + + /** remove or insert the necessary function types + @param _pEntry + The currently edited entry. + */ + void setFunctionCell(OTableFieldDescRef const & _pEntry); + + using ::svt::EditBrowseBox::AcceptDrop; + using ::svt::EditBrowseBox::ExecuteDrop; + using ::svt::EditBrowseBox::MouseButtonDown; + using ::svt::EditBrowseBox::MouseButtonUp; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableConnection.cxx b/dbaccess/source/ui/querydesign/TableConnection.cxx new file mode 100644 index 000000000..ada4b5990 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableConnection.cxx @@ -0,0 +1,190 @@ +/* -*- 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 <TableConnection.hxx> +#include <ConnectionLine.hxx> +#include <TableConnectionData.hxx> +#include <JoinTableView.hxx> + +using namespace dbaui; +using namespace comphelper; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::accessibility; + +namespace dbaui +{ + OTableConnection::OTableConnection( OJoinTableView* _pContainer,const TTableConnectionData::value_type& _pTabConnData ) + :Window(_pContainer) + ,m_pData( _pTabConnData ) + ,m_pParent( _pContainer ) + ,m_bSelected( false ) + { + Init(); + Show(); + } + + OTableConnection::OTableConnection( const OTableConnection& _rConn ) + : VclReferenceBase() + ,Window(_rConn.m_pParent.get()) + ,m_pData(_rConn.GetData()->NewInstance()) + ,m_pParent(nullptr) + { + *this = _rConn; + } + + void OTableConnection::Init() + { + // initialise linelist with defaults + OConnectionLineDataVec& rLineData = GetData()->GetConnLineDataList(); + m_vConnLine.reserve(rLineData.size()); + for (auto const& elem : rLineData) + m_vConnLine.emplace_back( new OConnectionLine(this, elem) ); + } + + void OTableConnection::clearLineData() + { + m_vConnLine.clear(); + } + void OTableConnection::UpdateLineList() + { + // delete linelist + clearLineData(); + + Init(); + } + + OTableConnection& OTableConnection::operator=( const OTableConnection& rConn ) + { + if( &rConn == this ) + return *this; + + // delete linelist + clearLineData(); + + // copy linelist + if(! rConn.GetConnLineList().empty() ) + { + const std::vector<std::unique_ptr<OConnectionLine>>& rLine = rConn.GetConnLineList(); + m_vConnLine.reserve(rLine.size()); + for (auto const& elem : rLine) + m_vConnLine.emplace_back( new OConnectionLine(*elem)); + } + + // as the data are not mine, I also do not delete the old + m_pData->CopyFrom(*rConn.GetData()); + // CopyFrom is virtual, therefore it is not a problem if m_pData is a derived type of OTableConnectionData + + m_bSelected = rConn.m_bSelected; + m_pParent = rConn.m_pParent; + + return *this; + } + + void OTableConnection::RecalcLines() + { + // call RecalcLines on each line + for( const auto& pLine : m_vConnLine ) + pLine->RecalcLine(); + } + OTableWindow* OTableConnection::GetSourceWin() const + { + TTableWindowData::value_type pRef = GetData()->getReferencingTable(); + OTableWindow* pRet = m_pParent->GetTabWindow( pRef->GetWinName() ); + if ( !pRet ) + { + pRet = m_pParent->GetTabWindow( pRef->GetComposedName() ); + } + return pRet; + } + OTableWindow* OTableConnection::GetDestWin() const + { + TTableWindowData::value_type pRef = GetData()->getReferencedTable(); + OTableWindow* pRet = m_pParent->GetTabWindow( pRef->GetWinName() ); + if ( !pRet ) + { + pRet = m_pParent->GetTabWindow( pRef->GetComposedName() ); + } + return pRet; + } + + void OTableConnection::Select() + { + m_bSelected = true; + m_pParent->Invalidate( GetBoundingRect(), InvalidateFlags::NoChildren); + } + + void OTableConnection::Deselect() + { + m_bSelected = false; + InvalidateConnection(); + } + + bool OTableConnection::CheckHit( const Point& rMousePos ) const + { + // check if the point hit our line + return std::any_of(m_vConnLine.begin(), + m_vConnLine.end(), + [&rMousePos] + ( const std::unique_ptr<OConnectionLine> & pLine ) + { return pLine->CheckHit( rMousePos ); } ); + } + + void OTableConnection::InvalidateConnection() + { + tools::Rectangle rcBounding = GetBoundingRect(); + rcBounding.AdjustBottom(1 ); + rcBounding.AdjustRight(1 ); + // I believe Invalidate and Draw(Rectangle) do not behave consistent: in any case it + // could explain, why without the fake here when deleting a connection a dash remains at the lower end: + // Invalidate records obviously one pixel line less as Draw. + // Or everything works differently... in any case it works... + m_pParent->Invalidate( rcBounding, InvalidateFlags::NoChildren ); + } + + tools::Rectangle OTableConnection::GetBoundingRect() const + { + // determine all lines of the surrounding rectangle + tools::Rectangle aBoundingRect( Point(0,0), Point(0,0) ); + tools::Rectangle aTempRect; + for (auto const& elem : m_vConnLine) + { + aTempRect = elem->GetBoundingRect(); + + // is the BoundingRect of this line valid? + if( (aTempRect.GetWidth()!=1) && (aTempRect.GetHeight()!=1) ) + { + if( (aBoundingRect.GetWidth()==1) && (aBoundingRect.GetHeight()==1) ) + aBoundingRect = aTempRect; + else + aBoundingRect.Union( aTempRect ); + } + } + + return aBoundingRect; + } + + void OTableConnection::Draw(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/) + { + // Draw line + for( const auto& pLine : m_vConnLine ) + pLine->Draw( &rRenderContext ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableConnectionData.cxx b/dbaccess/source/ui/querydesign/TableConnectionData.cxx new file mode 100644 index 000000000..107d8a9d1 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableConnectionData.cxx @@ -0,0 +1,147 @@ +/* -*- 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 <TableConnectionData.hxx> +#include <osl/diagnose.h> + +using namespace dbaui; + +OTableConnectionData::OTableConnectionData() +{ + Init(); +} + +OTableConnectionData::OTableConnectionData(const TTableWindowData::value_type& _pReferencingTable + ,const TTableWindowData::value_type& _pReferencedTable ) + :m_pReferencingTable(_pReferencingTable) + ,m_pReferencedTable(_pReferencedTable) +{ + Init(); +} + +void OTableConnectionData::Init() +{ + // initialise linedatalist with defaults + OSL_ENSURE(m_vConnLineData.empty(), "OTableConnectionData::Init() : call only with empty line list!"); + ResetConnLines(); + // this creates the defaults +} + +OTableConnectionData::OTableConnectionData( const OTableConnectionData& rConnData ) +{ + *this = rConnData; +} + +void OTableConnectionData::CopyFrom(const OTableConnectionData& rSource) +{ + *this = rSource; + // here I revert to the (non-virtual) operator =, which only copies my members +} + +OTableConnectionData::~OTableConnectionData() +{ + // delete LineDataList + OConnectionLineDataVec().swap(m_vConnLineData); +} + +OTableConnectionData& OTableConnectionData::operator=( const OTableConnectionData& rConnData ) +{ + if (&rConnData == this) + return *this; + + m_pReferencingTable = rConnData.m_pReferencingTable; + m_pReferencedTable = rConnData.m_pReferencedTable; + m_aConnName = rConnData.m_aConnName; + + // clear line list + ResetConnLines(); + + // and copy + for (auto const& elem : rConnData.GetConnLineDataList()) + m_vConnLineData.push_back(new OConnectionLineData(*elem)); + + return *this; +} + +void OTableConnectionData::SetConnLine( sal_uInt16 nIndex, const OUString& rSourceFieldName, const OUString& rDestFieldName ) +{ + if (sal_uInt16(m_vConnLineData.size()) < nIndex) + return; + + // == still allowed, this corresponds to an Append + + if (m_vConnLineData.size() == nIndex) + { + AppendConnLine(rSourceFieldName, rDestFieldName); + return; + } + + OConnectionLineDataRef pConnLineData = m_vConnLineData[nIndex]; + OSL_ENSURE(pConnLineData != nullptr, "OTableConnectionData::SetConnLine : have invalid LineData object"); + + pConnLineData->SetSourceFieldName( rSourceFieldName ); + pConnLineData->SetDestFieldName( rDestFieldName ); +} + +bool OTableConnectionData::AppendConnLine( const OUString& rSourceFieldName, const OUString& rDestFieldName ) +{ + for (auto const& elem : m_vConnLineData) + { + if(elem->GetDestFieldName() == rDestFieldName && elem->GetSourceFieldName() == rSourceFieldName) + return true; + } + OConnectionLineDataRef pNew = new OConnectionLineData(rSourceFieldName, rDestFieldName); + if (!pNew.is()) + return false; + + m_vConnLineData.push_back(pNew); + return true; +} + +void OTableConnectionData::ResetConnLines() +{ + OConnectionLineDataVec().swap(m_vConnLineData); +} + +std::shared_ptr<OTableConnectionData> OTableConnectionData::NewInstance() const +{ + return std::make_shared<OTableConnectionData>(); +} + +OConnectionLineDataVec::size_type OTableConnectionData::normalizeLines() +{ + // remove empty lines + OConnectionLineDataVec::size_type nCount = m_vConnLineData.size(); + OConnectionLineDataVec::size_type nRet = nCount; + for(OConnectionLineDataVec::size_type i = 0; i < nCount;) + { + if(m_vConnLineData[i]->GetSourceFieldName().isEmpty() && m_vConnLineData[i]->GetDestFieldName().isEmpty()) + { + m_vConnLineData.erase(m_vConnLineData.begin()+i); + --nCount; + if (i < nRet) + nRet=i; + } + else + ++i; + } + return nRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableFieldDescription.cxx b/dbaccess/source/ui/querydesign/TableFieldDescription.cxx new file mode 100644 index 000000000..1e8604181 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableFieldDescription.cxx @@ -0,0 +1,196 @@ +/* -*- 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 <TableFieldDescription.hxx> + +#include <osl/diagnose.h> +#include <com/sun/star/sdbc/DataType.hpp> +#include <comphelper/namedvaluecollection.hxx> + +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace comphelper; +using namespace dbaui; + +OTableFieldDesc::OTableFieldDesc() + :m_pTabWindow(nullptr) + ,m_eDataType(1000) + ,m_eFunctionType( FKT_NONE ) + ,m_eFieldType(TAB_NORMAL_FIELD) + ,m_eOrderDir( ORDER_NONE ) + ,m_nIndex(0) + ,m_nColWidth(0) + ,m_nColumnId(sal_uInt16(-1)) + ,m_bGroupBy(false) + ,m_bVisible(false) +{ +} + +OTableFieldDesc::OTableFieldDesc(const OTableFieldDesc& rRS) + : ::salhelper::SimpleReferenceObject() + , m_pTabWindow(nullptr) +{ + *this = rRS; +} + +OTableFieldDesc::OTableFieldDesc(const OUString& rT, const OUString& rF ) + :m_pTabWindow(nullptr) + ,m_eDataType(1000) + ,m_eFunctionType( FKT_NONE ) + ,m_eFieldType(TAB_NORMAL_FIELD) + ,m_eOrderDir( ORDER_NONE ) + ,m_nIndex(0) + ,m_nColWidth(0) + ,m_nColumnId(sal_uInt16(-1)) + ,m_bGroupBy(false) + ,m_bVisible(false) +{ + SetField( rF ); SetTable( rT ); +} + +OTableFieldDesc::~OTableFieldDesc() +{ +} + +OTableFieldDesc& OTableFieldDesc::operator=( const OTableFieldDesc& rRS ) +{ + if (&rRS == this) + return *this; + + m_aCriteria = rRS.GetCriteria(); + m_aTableName = rRS.GetTable(); + m_aAliasName = rRS.GetAlias(); // table range + m_aFieldName = rRS.GetField(); // column + m_aFieldAlias = rRS.GetFieldAlias(); // column alias + m_aFunctionName = rRS.GetFunction(); + m_pTabWindow = rRS.GetTabWindow(); + m_eDataType = rRS.GetDataType(); + m_eFunctionType = rRS.GetFunctionType(); + m_eFieldType = rRS.GetFieldType(); + m_eOrderDir = rRS.GetOrderDir(); + m_nIndex = rRS.GetFieldIndex(); + m_nColWidth = rRS.GetColWidth(); + m_nColumnId = rRS.m_nColumnId; + m_bGroupBy = rRS.IsGroupBy(); + m_bVisible = rRS.IsVisible(); + + return *this; +} + +void OTableFieldDesc::SetCriteria( sal_uInt16 nIdx, const OUString& rCrit) +{ + if (nIdx < m_aCriteria.size()) + m_aCriteria[nIdx] = rCrit; + else + { + m_aCriteria.insert(m_aCriteria.end(), nIdx - m_aCriteria.size(), OUString()); + m_aCriteria.push_back(rCrit); + } +} + +OUString OTableFieldDesc::GetCriteria( sal_uInt16 nIdx ) const +{ + OUString aRetStr; + if( nIdx < m_aCriteria.size()) + aRetStr = m_aCriteria[nIdx]; + + return aRetStr; +} + +namespace +{ + struct SelectPropertyValueAsString + { + OUString operator()( const PropertyValue& i_rPropValue ) const + { + OUString sValue; + OSL_VERIFY( i_rPropValue.Value >>= sValue ); + return sValue; + } + }; +} + +void OTableFieldDesc::Load( const css::beans::PropertyValue& i_rSettings, const bool i_bIncludingCriteria ) +{ + + ::comphelper::NamedValueCollection aFieldDesc( i_rSettings.Value ); + m_aAliasName = aFieldDesc.getOrDefault( "AliasName", m_aAliasName ); + m_aTableName = aFieldDesc.getOrDefault( "TableName", m_aTableName ); + m_aFieldName = aFieldDesc.getOrDefault( "FieldName", m_aFieldName ); + m_aFieldAlias = aFieldDesc.getOrDefault( "FieldAlias", m_aFieldAlias ); + m_aFunctionName = aFieldDesc.getOrDefault( "FunctionName", m_aFunctionName ); + m_eDataType = aFieldDesc.getOrDefault( "DataType", m_eDataType ); + m_eFunctionType = aFieldDesc.getOrDefault( "FunctionType", m_eFunctionType ); + m_nColWidth = aFieldDesc.getOrDefault( "ColWidth", m_nColWidth ); + m_bGroupBy = aFieldDesc.getOrDefault( "GroupBy", m_bGroupBy ); + m_bVisible = aFieldDesc.getOrDefault( "Visible", m_bVisible ); + + m_eFieldType = static_cast< ETableFieldType >( aFieldDesc.getOrDefault( "FieldType", static_cast< sal_Int32 >( m_eFieldType ) ) ); + m_eOrderDir = static_cast< EOrderDir >( aFieldDesc.getOrDefault( "OrderDir", static_cast< sal_Int32 >( m_eOrderDir ) ) ); + + if ( i_bIncludingCriteria ) + { + const Sequence< PropertyValue > aCriteria( aFieldDesc.getOrDefault( "Criteria", Sequence< PropertyValue >() ) ); + m_aCriteria.resize( aCriteria.getLength() ); + std::transform( + aCriteria.begin(), + aCriteria.end(), + m_aCriteria.begin(), + SelectPropertyValueAsString() + ); + } +} + +void OTableFieldDesc::Save( ::comphelper::NamedValueCollection& o_rSettings, const bool i_bIncludingCriteria ) +{ + + o_rSettings.put( "AliasName", m_aAliasName ); + o_rSettings.put( "TableName", m_aTableName ); + o_rSettings.put( "FieldName", m_aFieldName ); + o_rSettings.put( "FieldAlias", m_aFieldAlias ); + o_rSettings.put( "FunctionName", m_aFunctionName ); + o_rSettings.put( "DataType", m_eDataType ); + o_rSettings.put( "FunctionType", m_eFunctionType ); + o_rSettings.put( "FieldType", static_cast<sal_Int32>(m_eFieldType) ); + o_rSettings.put( "OrderDir", static_cast<sal_Int32>(m_eOrderDir) ); + o_rSettings.put( "ColWidth", m_nColWidth ); + o_rSettings.put( "GroupBy", m_bGroupBy ); + o_rSettings.put( "Visible", m_bVisible ); + + if ( !i_bIncludingCriteria ) + return; + + if ( m_aCriteria.empty() ) + return; + + sal_Int32 c = 0; + Sequence< PropertyValue > aCriteria( m_aCriteria.size() ); + auto pCriteria = aCriteria.getArray(); + for (auto const& criteria : m_aCriteria) + { + pCriteria[c].Name = "Criterion_" + OUString::number( c ); + pCriteria[c].Value <<= criteria; + ++c; + } + + o_rSettings.put( "Criteria", aCriteria ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableFieldInfo.cxx b/dbaccess/source/ui/querydesign/TableFieldInfo.cxx new file mode 100644 index 000000000..808862c11 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableFieldInfo.cxx @@ -0,0 +1,30 @@ +/* -*- 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 "TableFieldInfo.hxx" + +using namespace dbaui; + +OTableFieldInfo::OTableFieldInfo() + : m_eFieldType(TAB_NORMAL_FIELD) + , m_eDataType(1000) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableFieldInfo.hxx b/dbaccess/source/ui/querydesign/TableFieldInfo.hxx new file mode 100644 index 000000000..e7d2c9b72 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableFieldInfo.hxx @@ -0,0 +1,43 @@ +/* -*- 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 <QEnumTypes.hxx> +#include <sal/types.h> + +namespace dbaui +{ + class OTableFieldInfo + { + private: + ETableFieldType m_eFieldType; + sal_Int32 m_eDataType; + + public: + OTableFieldInfo(); + + ETableFieldType GetKeyType() const { return m_eFieldType; } + void SetKey(ETableFieldType bKey) { m_eFieldType = bKey; } + sal_Int32 GetDataType() const { return m_eDataType; } + void SetDataType(sal_Int32 eTyp) { m_eDataType = eTyp; } + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableWindow.cxx b/dbaccess/source/ui/querydesign/TableWindow.cxx new file mode 100644 index 000000000..b8afc951d --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableWindow.cxx @@ -0,0 +1,716 @@ +/* -*- 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 <TableWindow.hxx> +#include <TableWindowListBox.hxx> +#include <TableWindowData.hxx> +#include <imageprovider.hxx> +#include <JoinController.hxx> +#include <JoinTableView.hxx> +#include <JoinDesignView.hxx> +#include <osl/diagnose.h> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/ptrstyle.hxx> +#include <vcl/wall.hxx> +#include <vcl/weldutils.hxx> +#include <tools/diagnose_ex.h> + +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdb/application/DatabaseObject.hpp> +#include <bitmaps.hlst> +#include <TableWindowAccess.hxx> +#include <connectivity/dbtools.hxx> + +using namespace dbaui; +using namespace ::utl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::accessibility; + +namespace DatabaseObject = css::sdb::application::DatabaseObject; + +#define TABWIN_SIZING_AREA 4 +#define TABWIN_WIDTH_MIN 90 +#define TABWIN_HEIGHT_MIN 80 + +namespace { + +void Draw3DBorder(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + // Use the System Style-Settings for my colours + const StyleSettings& aSystemStyle = Application::GetSettings().GetStyleSettings(); + + // Black lines for bottom and right + rRenderContext.SetLineColor(aSystemStyle.GetDarkShadowColor()); + rRenderContext.DrawLine(rRect.BottomLeft(), rRect.BottomRight()); + rRenderContext.DrawLine(rRect.BottomRight(), rRect.TopRight()); + + // Dark grey lines over the black lines + rRenderContext.SetLineColor(aSystemStyle.GetShadowColor()); + Point aEHvector(1, 1); + rRenderContext.DrawLine(rRect.BottomLeft() + Point(1, -1), rRect.BottomRight() - aEHvector); + rRenderContext.DrawLine(rRect.BottomRight() - aEHvector, rRect.TopRight() + Point(-1, 1)); + + // Light grey lines for top and left + rRenderContext.SetLineColor(aSystemStyle.GetLightColor()); + rRenderContext.DrawLine(rRect.BottomLeft() + Point(1, -2), rRect.TopLeft() + aEHvector); + rRenderContext.DrawLine(rRect.TopLeft() + aEHvector, rRect.TopRight() + Point(-2, 1)); +} + +} + +OTableWindow::OTableWindow( vcl::Window* pParent, const TTableWindowData::value_type& pTabWinData ) + : ::comphelper::OContainerListener(m_aMutex) + , Window( pParent, WB_3DLOOK|WB_MOVEABLE ) + , m_xTitle( VclPtr<OTableWindowTitle>::Create(this) ) + , m_pData( pTabWinData ) + , m_nMoveCount(0) + , m_nMoveIncrement(1) + , m_nSizingFlags( SizingFlags::NONE ) +{ + // Set position and size + if( GetData()->HasPosition() ) + SetPosPixel( GetData()->GetPosition() ); + + if( GetData()->HasSize() ) + SetSizePixel( GetData()->GetSize() ); + + // Set background + const StyleSettings& aSystemStyle = Application::GetSettings().GetStyleSettings(); + SetBackground(Wallpaper(aSystemStyle.GetFaceColor())); + // Set the text colour even though there is no text, + // because derived classes might need it + SetTextColor(aSystemStyle.GetButtonTextColor()); + + EnableClipSiblings(); +} + +OTableWindow::~OTableWindow() +{ + disposeOnce(); +} + +void OTableWindow::dispose() +{ + if (m_xListBox) + { + OSL_ENSURE(m_xListBox->get_widget().n_children()==0,"Forgot to call EmptyListbox()!"); + } + m_xListBox.disposeAndClear(); + if ( m_pContainerListener.is() ) + m_pContainerListener->dispose(); + + m_xTitle.disposeAndClear(); + vcl::Window::dispose(); +} + +const OJoinTableView* OTableWindow::getTableView() const +{ + OSL_ENSURE(static_cast<OJoinTableView*>(GetParent()),"No OJoinTableView!"); + return static_cast<OJoinTableView*>(GetParent()); +} + +OJoinTableView* OTableWindow::getTableView() +{ + OSL_ENSURE(static_cast<OJoinTableView*>(GetParent()),"No OJoinTableView!"); + return static_cast<OJoinTableView*>(GetParent()); +} + +OJoinDesignView* OTableWindow::getDesignView() +{ + OSL_ENSURE(static_cast<OJoinDesignView*>(GetParent()->GetParent()->GetParent()),"No OJoinDesignView!"); + return static_cast<OJoinDesignView*>(GetParent()->GetParent()->GetParent()); +} + +void OTableWindow::SetPosPixel( const Point& rNewPos ) +{ + Point aNewPosData = rNewPos + getTableView()->GetScrollOffset(); + GetData()->SetPosition( aNewPosData ); + Window::SetPosPixel( rNewPos ); +} + +void OTableWindow::SetSizePixel( const Size& rNewSize ) +{ + Size aOutSize(rNewSize); + if( aOutSize.Width() < TABWIN_WIDTH_MIN ) + aOutSize.setWidth( TABWIN_WIDTH_MIN ); + if( aOutSize.Height() < TABWIN_HEIGHT_MIN ) + aOutSize.setHeight( TABWIN_HEIGHT_MIN ); + + GetData()->SetSize( aOutSize ); + Window::SetSizePixel( aOutSize ); +} + +void OTableWindow::SetPosSizePixel( const Point& rNewPos, const Size& rNewSize ) +{ + SetPosPixel( rNewPos ); + SetSizePixel( rNewSize ); +} + +void OTableWindow::FillListBox() +{ + clearListBox(); + weld::TreeView& rTreeView = m_xListBox->get_widget(); + assert(!rTreeView.n_children()); + + if ( !m_pContainerListener.is() ) + { + Reference< XContainer> xContainer(m_pData->getColumns(),UNO_QUERY); + if ( xContainer.is() ) + m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer); + } + + // mark all primary keys with special image + OUString aPrimKeyImage(BMP_PRIMARY_KEY); + + if (GetData()->IsShowAll()) + { + rTreeView.append(weld::toId(createUserData(nullptr,false)), OUString("*")); + } + + Reference<XNameAccess> xPKeyColumns; + try + { + xPKeyColumns = dbtools::getPrimaryKeyColumns_throw(m_pData->getTable()); + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION( "dbaccess", ""); + } + try + { + Reference< XNameAccess > xColumns = m_pData->getColumns(); + if( xColumns.is() ) + { + Sequence< OUString> aColumns = xColumns->getElementNames(); + const OUString* pIter = aColumns.getConstArray(); + const OUString* pEnd = pIter + aColumns.getLength(); + + for (; pIter != pEnd; ++pIter) + { + bool bPrimaryKeyColumn = xPKeyColumns.is() && xPKeyColumns->hasByName( *pIter ); + + OUString sId; + Reference<XPropertySet> xColumn(xColumns->getByName(*pIter),UNO_QUERY); + if (xColumn.is()) + sId = weld::toId(createUserData(xColumn, bPrimaryKeyColumn)); + + rTreeView.append(sId, *pIter); + + // is this column in the primary key + if ( bPrimaryKeyColumn ) + rTreeView.set_image(rTreeView.n_children() - 1, aPrimKeyImage); + } + + } + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION( "dbaccess", ""); + } +} + +void* OTableWindow::createUserData(const Reference< XPropertySet>& /*_xColumn*/,bool /*_bPrimaryKey*/) +{ + return nullptr; +} + +void OTableWindow::deleteUserData(void*& _pUserData) +{ + OSL_ENSURE(!_pUserData,"INVALID call. Need to delete the userclass!"); + _pUserData = nullptr; +} + +void OTableWindow::clearListBox() +{ + if ( !m_xListBox ) + return; + + weld::TreeView& rTreeView = m_xListBox->get_widget(); + rTreeView.all_foreach([this, &rTreeView](weld::TreeIter& rEntry){ + void* pUserData = weld::fromId<void*>(rTreeView.get_id(rEntry)); + deleteUserData(pUserData); + return false; + }); + + rTreeView.clear(); +} + +void OTableWindow::impl_updateImage() +{ + weld::Image& rImage = m_xTitle->GetImage(); + ImageProvider aImageProvider( getDesignView()->getController().getConnection() ); + rImage.set_from_icon_name(aImageProvider.getImageId(GetComposedName(), m_pData->isQuery() ? DatabaseObject::QUERY : DatabaseObject::TABLE)); + rImage.show(); +} + +bool OTableWindow::Init() +{ + // create list box if necessary + if ( !m_xListBox ) + { + m_xListBox = VclPtr<OTableWindowListBox>::Create(this); + assert(m_xListBox && "OTableWindow::Init() : CreateListBox returned NULL !"); + m_xListBox->get_widget().set_selection_mode(SelectionMode::Multiple); + } + + // Set the title + weld::Label& rLabel = m_xTitle->GetLabel(); + rLabel.set_label(m_pData->GetWinName()); + rLabel.set_tooltip_text(GetComposedName()); + m_xTitle->Show(); + + m_xListBox->Show(); + + // add the fields to the ListBox + FillListBox(); + m_xListBox->get_widget().unselect_all(); + + impl_updateImage(); + + return true; +} + +void OTableWindow::DataChanged(const DataChangedEvent& rDCEvt) +{ + if (rDCEvt.GetType() == DataChangedEventType::SETTINGS) + { + // In the worst-case the colours have changed so + // adapt myself to the new colours + const StyleSettings& aSystemStyle = Application::GetSettings().GetStyleSettings(); + SetBackground(Wallpaper(aSystemStyle.GetFaceColor())); + SetTextColor(aSystemStyle.GetButtonTextColor()); + } +} + +void OTableWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + tools::Rectangle aRect(Point(0,0), GetOutputSizePixel()); + Window::Paint(rRenderContext, rRect); + Draw3DBorder(rRenderContext, aRect); +} + +tools::Rectangle OTableWindow::getSizingRect(const Point& _rPos,const Size& _rOutputSize) const +{ + tools::Rectangle aSizingRect( GetPosPixel(), GetSizePixel() ); + + if( m_nSizingFlags & SizingFlags::Top ) + { + if( _rPos.Y() < 0 ) + aSizingRect.SetTop( 0 ); + else + aSizingRect.SetTop( _rPos.Y() ); + } + + if( m_nSizingFlags & SizingFlags::Bottom ) + { + if( _rPos.Y() > _rOutputSize.Height() ) + aSizingRect.SetBottom( _rOutputSize.Height() ); + else + aSizingRect.SetBottom( _rPos.Y() ); + } + + if( m_nSizingFlags & SizingFlags::Right ) + { + if( _rPos.X() > _rOutputSize.Width() ) + aSizingRect.SetRight( _rOutputSize.Width() ); + else + aSizingRect.SetRight( _rPos.X() ); + } + + if( m_nSizingFlags & SizingFlags::Left ) + { + if( _rPos.X() < 0 ) + aSizingRect.SetLeft( 0 ); + else + aSizingRect.SetLeft( _rPos.X() ); + } + return aSizingRect; +} + +void OTableWindow::setSizingFlag(const Point& _rPos) +{ + Size aOutSize = GetOutputSizePixel(); + // Set the flags when the mouse cursor is in the sizing area + m_nSizingFlags = SizingFlags::NONE; + + if( _rPos.X() < TABWIN_SIZING_AREA ) + m_nSizingFlags |= SizingFlags::Left; + + if( _rPos.Y() < TABWIN_SIZING_AREA ) + m_nSizingFlags |= SizingFlags::Top; + + if( _rPos.X() > aOutSize.Width()-TABWIN_SIZING_AREA ) + m_nSizingFlags |= SizingFlags::Right; + + if( _rPos.Y() > aOutSize.Height()-TABWIN_SIZING_AREA ) + m_nSizingFlags |= SizingFlags::Bottom; +} + +void OTableWindow::MouseMove( const MouseEvent& rEvt ) +{ + Window::MouseMove(rEvt); + + OJoinTableView* pCont = getTableView(); + if (pCont->getDesignView()->getController().isReadOnly()) + return; + + Point aPos = rEvt.GetPosPixel(); + setSizingFlag(aPos); + PointerStyle aPointer = PointerStyle::Arrow; + + // Set the mouse cursor when it is in the sizing area + if ( m_nSizingFlags == SizingFlags::Top || + m_nSizingFlags == SizingFlags::Bottom ) + aPointer = PointerStyle::SSize; + else if ( m_nSizingFlags == SizingFlags::Left || + m_nSizingFlags ==SizingFlags::Right ) + aPointer = PointerStyle::ESize; + else if ( m_nSizingFlags == (SizingFlags::Left | SizingFlags::Top) || + m_nSizingFlags == (SizingFlags::Right | SizingFlags::Bottom) ) + aPointer = PointerStyle::SESize; + else if ( m_nSizingFlags == (SizingFlags::Right | SizingFlags::Top) || + m_nSizingFlags == (SizingFlags::Left | SizingFlags::Bottom) ) + aPointer = PointerStyle::NESize; + + SetPointer( aPointer ); +} + +void OTableWindow::MouseButtonDown( const MouseEvent& rEvt ) +{ + // When resizing, the parent must be informed that + // the window size of its child has changed + if( m_nSizingFlags != SizingFlags::NONE ) + getTableView()->BeginChildSizing( this, GetPointer() ); + + Window::MouseButtonDown( rEvt ); +} + +void OTableWindow::Resize() +{ + // The window must not disappear so we enforce a minimum size + Size aOutSize = GetOutputSizePixel(); + aOutSize = Size(CalcZoom(aOutSize.Width()),CalcZoom(aOutSize.Height())); + + tools::Long nTitleHeight = CalcZoom( GetTextHeight() )+ CalcZoom( 4 ); + + // Set the title and ListBox + tools::Long n5Pos = CalcZoom(5); + tools::Long nPositionX = n5Pos; + tools::Long nPositionY = n5Pos; + + Size aPreferredSize = m_xTitle->get_preferred_size(); + if (nTitleHeight < aPreferredSize.Height()) + nTitleHeight = aPreferredSize.Height(); + + m_xTitle->SetPosSizePixel( Point( nPositionX, nPositionY ), Size( aOutSize.Width() - nPositionX - n5Pos, nTitleHeight ) ); + + tools::Long nTitleToList = CalcZoom( 3 ); + + m_xListBox->SetPosSizePixel( + Point( n5Pos, nPositionY + nTitleHeight + nTitleToList ), + Size( aOutSize.Width() - 2 * n5Pos, aOutSize.Height() - ( nPositionY + nTitleHeight + nTitleToList ) - n5Pos ) + ); + + Window::Invalidate(); +} + +void OTableWindow::SetBoldTitle( bool bBold ) +{ + weld::Label& rLabel = m_xTitle->GetLabel(); + vcl::Font aFont = rLabel.get_font(); + aFont.SetWeight(bBold ? WEIGHT_BOLD : WEIGHT_NORMAL); + rLabel.set_font(aFont); +} + +void OTableWindow::GetFocus() +{ + Window::GetFocus(); + // we have to forward the focus to our listbox to enable keystrokes + if(m_xListBox) + m_xListBox->GrabFocus(); +} + +void OTableWindow::setActive(bool _bActive) +{ + SetBoldTitle( _bActive ); + if (_bActive || !m_xListBox) + return; + + weld::TreeView& rTreeView = m_xListBox->get_widget(); + if (rTreeView.get_selected_index() != -1) + rTreeView.unselect_all(); +} + +void OTableWindow::Remove() +{ + // Delete the window + OJoinTableView* pTabWinCont = getTableView(); + VclPtr<OTableWindow> aHoldSelf(this); // keep ourselves alive during the RemoveTabWin process + pTabWinCont->RemoveTabWin( this ); + pTabWinCont->Invalidate(); +} + +bool OTableWindow::ExistsAConn() const +{ + return getTableView()->ExistsAConn(this); +} + +void OTableWindow::EnumValidFields(std::vector< OUString>& arrstrFields) +{ + arrstrFields.clear(); + weld::TreeView& rTreeView = m_xListBox->get_widget(); + + // This default implementation counts every item in the ListBox ... for any other behaviour it must be over-written + rTreeView.all_foreach([&rTreeView, &arrstrFields](weld::TreeIter& rEntry){ + arrstrFields.push_back(rTreeView.get_text(rEntry)); + return false; + }); +} + +void OTableWindow::StateChanged( StateChangedType nType ) +{ + Window::StateChanged( nType ); + + // FIXME RenderContext + + if ( nType != StateChangedType::Zoom ) + return; + + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + vcl::Font aFont = rStyleSettings.GetGroupFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetZoomedPointFont(*GetOutDev(), aFont); + + m_xTitle->SetZoom(GetZoom()); + m_xListBox->SetZoom(GetZoom()); + Resize(); + Invalidate(); +} + +Reference< XAccessible > OTableWindow::CreateAccessible() +{ + return new OTableWindowAccess(this); +} + +void OTableWindow::Command(const CommandEvent& rEvt) +{ + switch (rEvt.GetCommand()) + { + case CommandEventId::ContextMenu: + { + OJoinController& rController = getDesignView()->getController(); + if(!rController.isReadOnly() && rController.isConnected()) + { + Point ptWhere; + if ( rEvt.IsMouseEvent() ) + ptWhere = rEvt.GetMousePosPixel(); + else + { + weld::TreeView& rTreeView = m_xListBox->get_widget(); + std::unique_ptr<weld::TreeIter> xCurrent = rTreeView.make_iterator(); + if (rTreeView.get_cursor(xCurrent.get())) + ptWhere = rTreeView.get_row_area(*xCurrent).Center(); + else + ptWhere = m_xTitle->GetPosPixel(); + } + + ::tools::Rectangle aRect(ptWhere, Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/jointablemenu.ui")); + std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu")); + if (!xContextMenu->popup_at_rect(pPopupParent, aRect).isEmpty()) + Remove(); + } + break; + } + default: + Window::Command(rEvt); + } +} + +bool OTableWindow::PreNotify(NotifyEvent& rNEvt) +{ + bool bHandled = false; + switch (rNEvt.GetType()) + { + case MouseNotifyEvent::KEYINPUT: + { + if ( getDesignView()->getController().isReadOnly() ) + break; + + const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); + const vcl::KeyCode& rCode = pKeyEvent->GetKeyCode(); + if ( rCode.IsMod1() ) + { + Point aStartPoint = GetPosPixel(); + if ( rCode.IsShift() ) + { + aStartPoint.setX( GetSizePixel().Width() ); + aStartPoint.setY( GetSizePixel().Height() ); + } + + switch( rCode.GetCode() ) + { + case KEY_DOWN: + bHandled = true; + aStartPoint.AdjustY(m_nMoveIncrement ); + break; + case KEY_UP: + bHandled = true; + aStartPoint.AdjustY(-m_nMoveIncrement ); + break; + case KEY_LEFT: + bHandled = true; + aStartPoint.AdjustX(-m_nMoveIncrement ); + break; + case KEY_RIGHT: + bHandled = true; + aStartPoint.AdjustX(m_nMoveIncrement ); + break; + } + if ( bHandled ) + { + if ( rCode.IsShift() ) + { + OJoinTableView* pView = getTableView(); + Point ptOld = GetPosPixel(); + Size aSize = pView->getRealOutputSize(); + Size aNewSize(aStartPoint.X(),aStartPoint.Y()); + if ( ((ptOld.X() + aNewSize.Width()) <= aSize.Width()) + && ((ptOld.Y() + aNewSize.Height()) <= aSize.Height()) ) + { + if ( aNewSize.Width() < TABWIN_WIDTH_MIN ) + aNewSize.setWidth( TABWIN_WIDTH_MIN ); + if ( aNewSize.Height() < TABWIN_HEIGHT_MIN ) + aNewSize.setHeight( TABWIN_HEIGHT_MIN ); + + Size szOld = GetSizePixel(); + + aNewSize = Size(pView->CalcZoom(aNewSize.Width()),pView->CalcZoom(aNewSize.Height())); + SetPosSizePixel( ptOld, aNewSize ); + pView->TabWinSized(this, ptOld, szOld); + Invalidate( InvalidateFlags::NoChildren ); + } + } + else + { + // remember how often the user moved our window + ++m_nMoveCount; + if( m_nMoveCount == 5 ) + m_nMoveIncrement = 10; + else if( m_nMoveCount > 15 ) + m_nMoveCount = m_nMoveIncrement = 20; + + Point aOldDataPoint = GetData()->GetPosition(); + Point aNewDataPoint = aStartPoint + getTableView()->GetScrollOffset(); + if ( aNewDataPoint.X() > -1 && aNewDataPoint.Y() > -1 ) + { + OJoinTableView* pView = getTableView(); + if ( pView->isMovementAllowed(aNewDataPoint, GetData()->GetSize()) ) + { + SetPosPixel(aStartPoint); + + // aNewDataPoint can not be used here because SetPosPixel reset it + pView->EnsureVisible(GetData()->GetPosition(), GetData()->GetSize()); + pView->TabWinMoved(this,aOldDataPoint); + Invalidate(InvalidateFlags::NoChildren); + getDesignView()->getController().setModified( true ); + } + else + { + m_nMoveCount = 0; // reset our movement count + m_nMoveIncrement = 1; + } + } + else + { + m_nMoveCount = 0; // reset our movement count + m_nMoveIncrement = 1; + } + } + m_nSizingFlags = SizingFlags::NONE; + } + else + { + m_nMoveCount = 0; // reset our movement count + m_nMoveIncrement = 1; + } + } + else + { + m_nMoveCount = 0; // reset our movement count + m_nMoveIncrement = 1; + } + break; + } + case MouseNotifyEvent::KEYUP: + { + const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); + const vcl::KeyCode& rCode = pKeyEvent->GetKeyCode(); + sal_uInt16 nKeyCode = rCode.GetCode(); + if ( rCode.IsMod2() && nKeyCode != KEY_UP && nKeyCode != KEY_DOWN && nKeyCode != KEY_LEFT && nKeyCode != KEY_RIGHT ) + { + m_nMoveCount = 0; // reset our movement count + m_nMoveIncrement = 1; + } + break; + } + default: + break; + } + if (!bHandled) + return Window::PreNotify(rNEvt); + return true; +} + +OUString OTableWindow::getTitle() const +{ + return m_xTitle->GetLabel().get_label(); +} + +void OTableWindow::_elementInserted( const container::ContainerEvent& /*_rEvent*/ ) +{ + FillListBox(); +} + +void OTableWindow::_elementRemoved( const container::ContainerEvent& /*_rEvent*/ ) +{ + FillListBox(); +} + +void OTableWindow::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ ) +{ + FillListBox(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableWindowAccess.cxx b/dbaccess/source/ui/querydesign/TableWindowAccess.cxx new file mode 100644 index 000000000..787d257b5 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableWindowAccess.cxx @@ -0,0 +1,250 @@ +/* -*- 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 <TableWindowAccess.hxx> +#include <TableWindow.hxx> +#include <TableWindowListBox.hxx> +#include <JoinTableView.hxx> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <comphelper/sequence.hxx> +#include <vcl/vclevent.hxx> + +namespace dbaui +{ + using namespace ::com::sun::star::accessibility; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star; + + OTableWindowAccess::OTableWindowAccess(OTableWindow* _pTable) + :VCLXAccessibleComponent(_pTable->GetComponentInterface().is() ? _pTable->GetWindowPeer() : nullptr) + ,m_pTable(_pTable) + { + } + void SAL_CALL OTableWindowAccess::disposing() + { + m_pTable = nullptr; + VCLXAccessibleComponent::disposing(); + } + void OTableWindowAccess::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) + { + if ( rVclWindowEvent.GetId() == VclEventId::ObjectDying ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_pTable = nullptr; + } + + VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent ); + } + Any SAL_CALL OTableWindowAccess::queryInterface( const Type& aType ) + { + Any aRet(VCLXAccessibleComponent::queryInterface( aType )); + return aRet.hasValue() ? aRet : OTableWindowAccess_BASE::queryInterface( aType ); + } + Sequence< Type > SAL_CALL OTableWindowAccess::getTypes( ) + { + return ::comphelper::concatSequences(VCLXAccessibleComponent::getTypes(),OTableWindowAccess_BASE::getTypes()); + } + OUString SAL_CALL OTableWindowAccess::getImplementationName() + { + return "org.openoffice.comp.dbu.TableWindowAccessibility"; + } + Sequence< OUString > SAL_CALL OTableWindowAccess::getSupportedServiceNames() + { + return { "com.sun.star.accessibility.Accessible", + "com.sun.star.accessibility.AccessibleContext" }; + } + // XAccessibleContext + sal_Int32 SAL_CALL OTableWindowAccess::getAccessibleChildCount( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + sal_Int32 nCount = 0; + if(m_pTable) + { + ++nCount; + if(m_pTable->GetListBox()) + ++nCount; + } + return nCount; + } + Reference< XAccessible > SAL_CALL OTableWindowAccess::getAccessibleChild( sal_Int32 i ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XAccessible > aRet; + if (m_pTable && !m_pTable->isDisposed()) + { + switch(i) + { + case 0: + { + VclPtr<OTableWindowTitle> xCtrl(m_pTable->GetTitleCtrl()); + if (xCtrl) + aRet = xCtrl->GetAccessible(); + break; + } + case 1: + { + VclPtr<OTableWindowListBox> xCtrl(m_pTable->GetListBox()); + if (xCtrl) + aRet = xCtrl->GetAccessible(); + break; + } + default: + throw IndexOutOfBoundsException(); + } + } + return aRet; + } + sal_Int32 SAL_CALL OTableWindowAccess::getAccessibleIndexInParent( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + sal_Int32 nIndex = -1; + if( m_pTable ) + { + // search the position of our table window in the table window map + bool bFoundElem = false; + for (auto const& tabWin : m_pTable->getTableView()->GetTabWinMap()) + { + if (tabWin.second == m_pTable) + { + bFoundElem = true; + break; + } + ++nIndex; + } + nIndex = bFoundElem? nIndex : -1; + } + return nIndex; + } + sal_Int16 SAL_CALL OTableWindowAccess::getAccessibleRole( ) + { + return AccessibleRole::PANEL; // ? or may be an AccessibleRole::WINDOW + } + Reference< XAccessibleRelationSet > SAL_CALL OTableWindowAccess::getAccessibleRelationSet( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return this; + } + // XAccessibleComponent + Reference< XAccessible > SAL_CALL OTableWindowAccess::getAccessibleAtPoint( const awt::Point& _aPoint ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XAccessible > aRet; + if(m_pTable && !m_pTable->isDisposed()) + { + Point aPoint(_aPoint.X,_aPoint.Y); + tools::Rectangle aRect(m_pTable->GetDesktopRectPixel()); + if( aRect.Contains(aPoint) ) + aRet = this; + else if( m_pTable->GetListBox()->GetDesktopRectPixel().Contains(aPoint)) + aRet = m_pTable->GetListBox()->GetAccessible(); + } + return aRet; + } + Reference< XAccessible > OTableWindowAccess::getParentChild(sal_Int32 _nIndex) + { + Reference< XAccessible > xReturn; + Reference< XAccessible > xParent = getAccessibleParent(); + if ( xParent.is() ) + { + Reference< XAccessibleContext > xParentContext = xParent->getAccessibleContext(); + if ( xParentContext.is() ) + { + xReturn = xParentContext->getAccessibleChild(_nIndex); + } + } + return xReturn; + } + + sal_Int32 SAL_CALL OTableWindowAccess::getRelationCount( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return m_pTable ? m_pTable->getTableView()->getConnectionCount(m_pTable) : sal_Int32(0); + } + AccessibleRelation SAL_CALL OTableWindowAccess::getRelation( sal_Int32 nIndex ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if( nIndex < 0 || nIndex >= getRelationCount() ) + throw IndexOutOfBoundsException(); + + AccessibleRelation aRet; + if( m_pTable ) + { + OJoinTableView* pView = m_pTable->getTableView(); + auto aIter = pView->getTableConnections(m_pTable) + nIndex; + aRet.TargetSet = { getParentChild(aIter - pView->getTableConnections().begin()) }; + aRet.RelationType = AccessibleRelationType::CONTROLLER_FOR; + } + return aRet; + } + sal_Bool SAL_CALL OTableWindowAccess::containsRelation( sal_Int16 aRelationType ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return AccessibleRelationType::CONTROLLER_FOR == aRelationType + && m_pTable && m_pTable->getTableView()->ExistsAConn(m_pTable); + } + AccessibleRelation SAL_CALL OTableWindowAccess::getRelationByType( sal_Int16 aRelationType ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if( AccessibleRelationType::CONTROLLER_FOR == aRelationType && m_pTable) + { + OJoinTableView* pView = m_pTable->getTableView(); + const auto& rConnectionList = pView->getTableConnections(); + + auto aIter = pView->getTableConnections(m_pTable); + auto aEnd = rConnectionList.end(); + std::vector< Reference<XInterface> > aRelations; + aRelations.reserve(5); // just guessing + // TODO JNA aIter comes from pView->getTableConnections(m_pTable) + // and aEnd comes from pView->getTableConnections().end() + for (; aIter != aEnd ; ++aIter ) + { + uno::Reference<uno::XInterface> xInterface( + getParentChild(aIter - rConnectionList.begin())); + aRelations.push_back(xInterface); + } + + Sequence< Reference<XInterface> > aSeq(aRelations.data(), aRelations.size()); + return AccessibleRelation(AccessibleRelationType::CONTROLLER_FOR,aSeq); + } + return AccessibleRelation(); + } + OUString SAL_CALL OTableWindowAccess::getTitledBorderText( ) + { + return getAccessibleName( ); + } + OUString SAL_CALL OTableWindowAccess::getAccessibleName( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + OUString sAccessibleName; + if ( m_pTable ) + sAccessibleName = m_pTable->getTitle(); + return sAccessibleName; + } + Reference< XAccessibleContext > SAL_CALL OTableWindowAccess::getAccessibleContext( ) + { + return this; + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableWindowData.cxx b/dbaccess/source/ui/querydesign/TableWindowData.cxx new file mode 100644 index 000000000..d07c8214a --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableWindowData.cxx @@ -0,0 +1,135 @@ +/* -*- 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 <TableWindowData.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XKeysSupplier.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/lang/XComponent.hpp> + +using namespace dbaui; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +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; + +OTableWindowData::OTableWindowData( const Reference< XPropertySet>& _xTable + ,const OUString& _rComposedName + ,const OUString& rTableName + ,const OUString& rWinName ) + :m_xTable(_xTable) + ,m_aTableName( rTableName ) + ,m_aWinName( rWinName ) + ,m_sComposedName(_rComposedName) + ,m_aPosition( Point(-1,-1) ) + ,m_aSize( Size(-1,-1) ) + ,m_bShowAll( true ) + ,m_bIsQuery(false) + ,m_bIsValid(true) +{ + if( m_aWinName.isEmpty() ) + m_aWinName = m_aTableName; + + listen(); +} + +OTableWindowData::~OTableWindowData() +{ + Reference<XComponent> xComponent( m_xTable, UNO_QUERY ); + if ( xComponent.is() ) + stopComponentListening( xComponent ); +} + +bool OTableWindowData::HasPosition() const +{ + return ( (m_aPosition.X() != -1) && (m_aPosition.Y() != -1) ); +} + +bool OTableWindowData::HasSize() const +{ + return ( (m_aSize.Width() != -1) && (m_aSize.Height() !=-1) ); +} + +void OTableWindowData::_disposing( const css::lang::EventObject& /*_rSource*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + // it doesn't matter which one was disposed + m_xColumns.clear(); + m_xKeys.clear(); + m_xTable.clear(); +} + +bool OTableWindowData::init(const Reference< XConnection >& _xConnection,bool _bAllowQueries) +{ + OSL_ENSURE(!m_xTable.is(),"We are already connected to a table!"); + + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference< XQueriesSupplier > xSupQueries( _xConnection, UNO_QUERY_THROW ); + Reference< XNameAccess > xQueries( xSupQueries->getQueries(), UNO_SET_THROW ); + bool bIsKnownQuery = _bAllowQueries && xQueries->hasByName( m_sComposedName ); + + Reference< XTablesSupplier > xSupTables( _xConnection, UNO_QUERY_THROW ); + Reference< XNameAccess > xTables( xSupTables->getTables(), UNO_SET_THROW ); + bool bIsKnownTable = xTables->hasByName( m_sComposedName ); + + if ( bIsKnownQuery ) + m_xTable.set( xQueries->getByName( m_sComposedName ), UNO_QUERY ); + else if ( bIsKnownTable ) + m_xTable.set( xTables->getByName( m_sComposedName ), UNO_QUERY ); + else + m_bIsValid = false; + + // if we survived so far, we know whether it's a query + m_bIsQuery = bIsKnownQuery; + + listen(); + + Reference< XIndexAccess > xColumnsAsIndex( m_xColumns,UNO_QUERY ); + return xColumnsAsIndex.is() && ( xColumnsAsIndex->getCount() > 0 ); +} + +void OTableWindowData::listen() +{ + if ( !m_xTable.is() ) + return; + + // listen for the object being disposed + Reference<XComponent> xComponent( m_xTable, UNO_QUERY ); + if ( xComponent.is() ) + startComponentListening( xComponent ); + + // obtain the columns + Reference< XColumnsSupplier > xColumnsSups( m_xTable, UNO_QUERY); + if ( xColumnsSups.is() ) + m_xColumns = xColumnsSups->getColumns(); + + Reference<XKeysSupplier> xKeySup(m_xTable,UNO_QUERY); + if ( xKeySup.is() ) + m_xKeys = xKeySup->getKeys(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableWindowListBox.cxx b/dbaccess/source/ui/querydesign/TableWindowListBox.cxx new file mode 100644 index 000000000..3066f8429 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableWindowListBox.cxx @@ -0,0 +1,292 @@ +/* -*- 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 <TableWindowListBox.hxx> +#include <TableWindow.hxx> +#include <JoinController.hxx> +#include <JoinExchange.hxx> +#include <JoinTableView.hxx> +#include <JoinDesignView.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <vcl/svapp.hxx> +#include <vcl/commandevent.hxx> +#include <o3tl/string_view.hxx> + +using namespace dbaui; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::datatransfer; + +OJoinExchangeData::OJoinExchangeData(OTableWindowListBox* pBox) + : pListBox(pBox) + , nEntry(pBox->get_widget().get_selected_index()) +{ +} + +OTableWindowListBox::OTableWindowListBox(OTableWindow* pParent) + : InterimItemWindow(pParent, "dbaccess/ui/tablelistbox.ui", "TableListBox") + , m_xTreeView(m_xBuilder->weld_tree_view("treeview")) + , m_xDragDropTargetHelper(new TableWindowListBoxHelper(*this, m_xTreeView->get_drop_target())) + , m_pTabWin(pParent) + , m_nDropEvent(nullptr) + , m_nUiEvent(nullptr) +{ + m_xTreeView->connect_row_activated(LINK(this, OTableWindowListBox, OnDoubleClick)); + m_xTreeView->connect_visible_range_changed(LINK(this, OTableWindowListBox, ScrollHdl)); + m_xTreeView->connect_popup_menu(LINK(this, OTableWindowListBox, CommandHdl)); + + m_xHelper.set(new OJoinExchObj); + rtl::Reference<TransferDataContainer> xHelper(m_xHelper); + m_xTreeView->enable_drag_source(xHelper, DND_ACTION_LINK); + m_xTreeView->connect_drag_begin(LINK(this, OTableWindowListBox, DragBeginHdl)); +} + +IMPL_LINK(OTableWindowListBox, CommandHdl, const CommandEvent&, rCEvt, bool) +{ + if (rCEvt.GetCommand() != CommandEventId::ContextMenu) + return false; + m_pTabWin->Command(rCEvt); + return true; +} + +void OTableWindowListBox::dragFinished() +{ + // first show the error msg when existing + m_pTabWin->getDesignView()->getController().showError( + m_pTabWin->getDesignView()->getController().clearOccurredError()); + // second look for ui activities which should happen after d&d + if (m_nUiEvent) + Application::RemoveUserEvent(m_nUiEvent); + m_nUiEvent + = Application::PostUserEvent(LINK(this, OTableWindowListBox, LookForUiHdl), nullptr, true); +} + +OTableWindowListBox::~OTableWindowListBox() { disposeOnce(); } + +void OTableWindowListBox::dispose() +{ + if (m_nDropEvent) + Application::RemoveUserEvent(m_nDropEvent); + if (m_nUiEvent) + Application::RemoveUserEvent(m_nUiEvent); + m_pTabWin.clear(); + m_xDragDropTargetHelper.reset(); + m_xTreeView.reset(); + InterimItemWindow::dispose(); +} + +int OTableWindowListBox::GetEntryFromText(std::u16string_view rEntryText) +{ + // iterate through the list + OJoinDesignView* pView = m_pTabWin->getDesignView(); + OJoinController& rController = pView->getController(); + + try + { + bool bCase = false; + const Reference<XConnection>& xConnection = rController.getConnection(); + if (xConnection.is()) + { + Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData(); + if (xMeta.is()) + bCase = xMeta->supportsMixedCaseQuotedIdentifiers(); + } + for (int nEntry = 0, nCount = m_xTreeView->n_children(); nEntry < nCount; ++nEntry) + { + if (bCase ? rEntryText == m_xTreeView->get_text(nEntry) + : o3tl::equalsIgnoreAsciiCase(rEntryText, m_xTreeView->get_text(nEntry))) + return nEntry; + } + } + catch (SQLException&) + { + } + + return -1; +} + +IMPL_LINK_NOARG(OTableWindowListBox, ScrollHdl, weld::TreeView&, void) +{ + // connections of this table, if any, should be redrawn + m_pTabWin->getTableView()->Invalidate(InvalidateFlags::NoChildren); +} + +IMPL_LINK(OTableWindowListBox, DragBeginHdl, bool&, rUnsetDragIcon, bool) +{ + rUnsetDragIcon = false; + if (m_xTreeView->get_selected_index() == -1) + { + // no drag without a field + return true; + } + + OJoinTableView* pCont = m_pTabWin->getTableView(); + if (!pCont->getDesignView()->getController().isReadOnly() + && pCont->getDesignView()->getController().isConnected()) + { + // asterisk was not allowed to be copied to selection browsebox + bool bFirstNotAllowed = m_xTreeView->is_selected(0) && m_pTabWin->GetData()->IsShowAll(); + // create a description of the source + OJoinExchangeData jxdSource(this); + // update the exchange object + m_xHelper->setDescriptors(jxdSource, bFirstNotAllowed); + + return false; + } + + return true; +} + +sal_Int8 OTableWindowListBox::AcceptDrop(const AcceptDropEvent& _rEvt) +{ + // to enable the autoscroll when we're close to the edges + std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator()); + bool bHasDestRow = m_xTreeView->get_dest_row_at_pos(_rEvt.maPosPixel, xEntry.get(), true); + + sal_Int8 nDND_Action = DND_ACTION_NONE; + // check the format + if (!OJoinExchObj::isFormatAvailable( + m_xDragDropTargetHelper->GetDataFlavorExVector(), + SotClipboardFormatId::SBA_TABID) // this means that the first entry is to be dragged + && OJoinExchObj::isFormatAvailable(m_xDragDropTargetHelper->GetDataFlavorExVector())) + { // don't drop into the window if it's the drag source itself + + // remove the selection if the dragging operation is leaving the window + if (_rEvt.mbLeaving) + m_xTreeView->unselect_all(); + else + { + if (!bHasDestRow) + return DND_ACTION_NONE; + + // automatically select right entry when dragging + m_xTreeView->unselect_all(); + m_xTreeView->select(*xEntry); + + // one cannot drop on the first (*) entry + if (!(m_pTabWin->GetData()->IsShowAll() + && (m_xTreeView->get_iter_index_in_parent(*xEntry) == 0))) + nDND_Action = DND_ACTION_LINK; + } + } + return nDND_Action; +} + +IMPL_LINK_NOARG(OTableWindowListBox, LookForUiHdl, void*, void) +{ + m_nUiEvent = nullptr; + m_pTabWin->getTableView()->lookForUiActivities(); +} + +IMPL_LINK_NOARG(OTableWindowListBox, DropHdl, void*, void) +{ + // create the connection + m_nDropEvent = nullptr; + OSL_ENSURE(m_pTabWin, "No TableWindow!"); + try + { + OJoinTableView* pCont = m_pTabWin->getTableView(); + OSL_ENSURE(pCont, "No QueryTableView!"); + pCont->AddConnection(m_aDropInfo.aSource, m_aDropInfo.aDest); + } + catch (const SQLException& e) + { + // remember the exception so that we can show them later when d&d is finished + m_pTabWin->getDesignView()->getController().setErrorOccurred( + ::dbtools::SQLExceptionInfo(e)); + } +} + +sal_Int8 OTableWindowListBox::ExecuteDrop(const ExecuteDropEvent& _rEvt) +{ + TransferableDataHelper aDropped(_rEvt.maDropEvent.Transferable); + if (OJoinExchObj::isFormatAvailable(aDropped.GetDataFlavorExVector())) + { // don't drop into the window if it's the drag source itself + m_aDropInfo.aSource = OJoinExchangeData(this); + m_aDropInfo.aDest = OJoinExchObj::GetSourceDescription(_rEvt.maDropEvent.Transferable); + + if (m_nDropEvent) + Application::RemoveUserEvent(m_nDropEvent); + m_nDropEvent + = Application::PostUserEvent(LINK(this, OTableWindowListBox, DropHdl), nullptr, true); + + dragFinished(); + + return DND_ACTION_NONE; + } + return DND_ACTION_NONE; +} + +void OTableWindowListBox::LoseFocus() +{ + if (m_pTabWin) + m_pTabWin->setActive(false); + InterimItemWindow::LoseFocus(); +} + +void OTableWindowListBox::GetFocus() +{ + if (m_pTabWin) + m_pTabWin->setActive(); + + if (m_xTreeView) + { + std::unique_ptr<weld::TreeIter> xCurrent = m_xTreeView->make_iterator(); + if (m_xTreeView->get_cursor(xCurrent.get())) + { + m_xTreeView->unselect_all(); + m_xTreeView->select(*xCurrent); + } + } + + InterimItemWindow::GetFocus(); +} + +IMPL_LINK_NOARG(OTableWindowListBox, OnDoubleClick, weld::TreeView&, bool) +{ + // tell my parent + vcl::Window* pParent = Window::GetParent(); + OSL_ENSURE(pParent != nullptr, "OTableWindowListBox::OnDoubleClick : have no Parent !"); + + std::unique_ptr<weld::TreeIter> xCurrent = m_xTreeView->make_iterator(); + if (!m_xTreeView->get_cursor(xCurrent.get())) + return false; + + static_cast<OTableWindow*>(pParent)->OnEntryDoubleClicked(*xCurrent); + + return false; +} + +void OTableWindowListBox::Command(const CommandEvent& rEvt) +{ + switch (rEvt.GetCommand()) + { + case CommandEventId::ContextMenu: + { + static_cast<OTableWindow*>(Window::GetParent())->Command(rEvt); + break; + } + default: + InterimItemWindow::Command(rEvt); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableWindowTitle.cxx b/dbaccess/source/ui/querydesign/TableWindowTitle.cxx new file mode 100644 index 000000000..50eb19c28 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableWindowTitle.cxx @@ -0,0 +1,97 @@ +/* -*- 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 <TableWindowTitle.hxx> +#include <TableWindow.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <TableWindowListBox.hxx> +#include <TableConnection.hxx> +#include <JoinController.hxx> + +using namespace dbaui; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +OTableWindowTitle::OTableWindowTitle(OTableWindow* pParent) + : InterimItemWindow(pParent, "dbaccess/ui/tabletitle.ui", "TableTitle") + , m_pTabWin( pParent ) + , m_xLabel(m_xBuilder->weld_label("label")) + , m_xImage(m_xBuilder->weld_image("image")) +{ + m_xLabel->connect_mouse_press(LINK(this, OTableWindowTitle, MousePressHdl)); +} + +OTableWindowTitle::~OTableWindowTitle() +{ + disposeOnce(); +} + +void OTableWindowTitle::dispose() +{ + m_xImage.reset(); + m_xLabel.reset(); + m_pTabWin.clear(); + InterimItemWindow::dispose(); +} + +IMPL_LINK(OTableWindowTitle, MousePressHdl, const MouseEvent&, rEvt, bool) +{ + if (rEvt.IsLeft()) + { + if( rEvt.GetClicks() == 2) + { + Size aSize(GetTextWidth(GetText()) + 20, + m_pTabWin->GetSizePixel().Height() - m_pTabWin->GetListBox()->GetSizePixel().Height()); + + weld::TreeView& rTreeView = m_pTabWin->GetListBox()->get_widget(); + aSize.AdjustHeight(rTreeView.get_height_rows(rTreeView.n_children() + 2)); + if (m_pTabWin->GetSizePixel() != aSize) + { + m_pTabWin->SetSizePixel(aSize); + + OJoinTableView* pView = m_pTabWin->getTableView(); + OSL_ENSURE(pView,"No OJoinTableView!"); + for (auto& conn : pView->getTableConnections()) + conn->RecalcLines(); + + pView->InvalidateConnections(); + pView->getDesignView()->getController().setModified(true); + pView->Invalidate(InvalidateFlags::NoChildren); + } + } + else + { + Point aPos = rEvt.GetPosPixel(); + aPos = OutputToScreenPixel( aPos ); + OJoinTableView* pView = m_pTabWin->getTableView(); + OSL_ENSURE(pView,"No OJoinTableView!"); + pView->NotifyTitleClicked( static_cast<OTableWindow*>(GetParent()), aPos ); + } + } + else if (rEvt.IsRight()) + { + CommandEvent aCEvt(rEvt.GetPosPixel(), CommandEventId::ContextMenu, true); + // tdf#94709 - protect shutdown code-path. + VclPtr<OTableWindow> xTabWin(m_pTabWin); + xTabWin->Command(aCEvt); + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/class.jpg b/dbaccess/source/ui/querydesign/class.jpg Binary files differnew file mode 100644 index 000000000..b1a3b6d27 --- /dev/null +++ b/dbaccess/source/ui/querydesign/class.jpg diff --git a/dbaccess/source/ui/querydesign/limitboxcontroller.cxx b/dbaccess/source/ui/querydesign/limitboxcontroller.cxx new file mode 100644 index 000000000..8b6884338 --- /dev/null +++ b/dbaccess/source/ui/querydesign/limitboxcontroller.cxx @@ -0,0 +1,322 @@ +/* -*- 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/. + */ + +#include "limitboxcontroller.hxx" + +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> + +#include <comphelper/propertyvalue.hxx> +#include <vcl/InterimItemWindow.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/window.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include <core_resource.hxx> +#include <strings.hrc> + +using namespace ::com::sun::star; + +namespace +{ + +/// Default values +sal_Int64 const aDefLimitAry[] = +{ + 5, + 10, + 20, + 50 +}; + +} + +namespace dbaui +{ + +/** + * Input box to add limit to an SQL query (maximum number of result's rows) + * This box is reachable on the Query Design Toolbar + */ +class LimitBox final : public InterimItemWindow +{ +public: + LimitBox(vcl::Window* pParent, LimitBoxController* pCtrl) + : InterimItemWindow(pParent, "dbaccess/ui/limitbox.ui", "LimitBox") + , m_pControl( pCtrl ) + , m_xWidget(m_xBuilder->weld_combo_box("limit")) + { + InitControlBase(m_xWidget.get()); + + LoadDefaultLimits(); + + m_xWidget->connect_key_press(LINK(this, LimitBox, KeyInputHdl)); + m_xWidget->connect_entry_activate(LINK(this, LimitBox, ActivateHdl)); + m_xWidget->connect_changed(LINK(this, LimitBox, ChangeHdl)); + m_xWidget->connect_focus_out(LINK(this, LimitBox, FocusOutHdl)); + m_xWidget->set_entry_width_chars(6); + SetSizePixel(m_xContainer->get_preferred_size()); + } + + virtual void dispose() override + { + m_xWidget.reset(); + InterimItemWindow::dispose(); + } + + virtual ~LimitBox() override + { + disposeOnce(); + } + + void set_sensitive(bool bSensitive) + { + m_xWidget->set_sensitive(bSensitive); + } + + void set_value(int nLimit) + { + if (nLimit < 0) + m_xWidget->set_active(0); + else + m_xWidget->set_entry_text(OUString::number(nLimit)); + m_xWidget->save_value(); + } + +private: + LimitBoxController* m_pControl; + std::unique_ptr<weld::ComboBox> m_xWidget; + + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(ActivateHdl, weld::ComboBox&, bool); + DECL_LINK(ChangeHdl, weld::ComboBox&, void); + DECL_LINK(FocusOutHdl, weld::Widget&, void); + + void Apply() + { + if (!m_xWidget->get_value_changed_from_saved()) + return; + sal_Int64 nLimit; + OUString sActiveText = m_xWidget->get_active_text(); + if (sActiveText == DBA_RES(STR_QUERY_LIMIT_ALL)) + nLimit = -1; + else + { + nLimit = m_xWidget->get_active_text().toInt64(); + if (nLimit < 0) + nLimit = -1; + } + set_value(nLimit); + m_pControl->dispatchCommand({ comphelper::makePropertyValue("DBLimit.Value", nLimit) }); + } + + ///Initialize entries + void LoadDefaultLimits() + { + m_xWidget->freeze(); + m_xWidget->append_text(DBA_RES(STR_QUERY_LIMIT_ALL)); + for (auto nIndex : aDefLimitAry) + { + m_xWidget->append_text(OUString::number(nIndex)); + } + m_xWidget->thaw(); + } +}; + +IMPL_LINK(LimitBox, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + bool bHandled = false; + const sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + switch (nCode) + { + case KEY_ESCAPE: + m_xWidget->set_entry_text(m_xWidget->get_saved_value()); + bHandled = true; + break; + case KEY_RETURN: + { + bHandled = ActivateHdl(*m_xWidget); + break; + } + } + return bHandled || ChildKeyInput(rKEvt); +} + +IMPL_LINK_NOARG(LimitBox, FocusOutHdl, weld::Widget&, void) +{ + if (!m_xWidget || m_xWidget->has_focus()) // comboboxes can be comprised of multiple widgets, ensure all have lost focus + return; + Apply(); +} + +IMPL_LINK(LimitBox, ChangeHdl, weld::ComboBox&, rComboBox, void) +{ + if (rComboBox.changed_by_direct_pick()) + ActivateHdl(rComboBox); +} + +IMPL_LINK_NOARG(LimitBox, ActivateHdl, weld::ComboBox&, bool) +{ + GrabFocusToDocument(); + Apply(); + return true; +} + +LimitBoxController::LimitBoxController( + const uno::Reference< uno::XComponentContext >& rxContext ) : + svt::ToolboxController( rxContext, + uno::Reference< frame::XFrame >(), + ".uno:DBLimit" ), + m_xLimitBox( nullptr ) +{ +} + +LimitBoxController::~LimitBoxController() +{ +} + +/// XInterface +uno::Any SAL_CALL LimitBoxController::queryInterface( const uno::Type& aType ) +{ + uno::Any a = ToolboxController::queryInterface( aType ); + if ( a.hasValue() ) + return a; + + return ::cppu::queryInterface( aType, static_cast< lang::XServiceInfo* >( this )); +} + +void SAL_CALL LimitBoxController::acquire() noexcept +{ + ToolboxController::acquire(); +} + +void SAL_CALL LimitBoxController::release() noexcept +{ + ToolboxController::release(); +} + + +/// XServiceInfo +OUString SAL_CALL LimitBoxController::getImplementationName() +{ + return "org.libreoffice.comp.dbu.LimitBoxController"; +} + +sal_Bool SAL_CALL LimitBoxController::supportsService(const OUString& _rServiceName) + { + const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames()); + for (const OUString& s : aSupported) + if (s == _rServiceName) + return true; + + return false; + } + +css::uno::Sequence< OUString > SAL_CALL LimitBoxController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +/// XComponent +void SAL_CALL LimitBoxController::dispose() +{ + svt::ToolboxController::dispose(); + + SolarMutexGuard aSolarMutexGuard; + m_xLimitBox.disposeAndClear(); +} + +/// XStatusListener +void SAL_CALL LimitBoxController::statusChanged( + const frame::FeatureStateEvent& rEvent ) +{ + if ( !m_xLimitBox ) + return; + + SolarMutexGuard aSolarMutexGuard; + if ( rEvent.FeatureURL.Path == "DBLimit" ) + { + if ( rEvent.IsEnabled ) + { + m_xLimitBox->set_sensitive(true); + sal_Int64 nLimit = 0; + if (rEvent.State >>= nLimit) + m_xLimitBox->set_value(nLimit); + } + else + m_xLimitBox->set_sensitive(false); + } +} + +/// XToolbarController +void SAL_CALL LimitBoxController::execute( sal_Int16 /*KeyModifier*/ ) +{ +} + +void SAL_CALL LimitBoxController::click() +{ +} + +void SAL_CALL LimitBoxController::doubleClick() +{ +} + +uno::Reference< awt::XWindow > SAL_CALL LimitBoxController::createPopupWindow() +{ + return uno::Reference< awt::XWindow >(); +} + +uno::Reference< awt::XWindow > SAL_CALL LimitBoxController::createItemWindow( + const uno::Reference< awt::XWindow >& xParent ) +{ + uno::Reference< awt::XWindow > xItemWindow; + + VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent ); + if ( pParent ) + { + SolarMutexGuard aSolarMutexGuard; + m_xLimitBox = VclPtr<LimitBox>::Create(pParent, this); + xItemWindow = VCLUnoHelper::GetInterface(m_xLimitBox); + } + + return xItemWindow; +} + +void LimitBoxController::dispatchCommand( + const uno::Sequence< beans::PropertyValue >& rArgs ) +{ + uno::Reference< frame::XDispatchProvider > xDispatchProvider( m_xFrame, uno::UNO_QUERY ); + if ( xDispatchProvider.is() ) + { + util::URL aURL; + uno::Reference< frame::XDispatch > xDispatch; + uno::Reference< util::XURLTransformer > xURLTransformer = getURLTransformer(); + + aURL.Complete = ".uno:DBLimit"; + xURLTransformer->parseStrict( aURL ); + xDispatch = xDispatchProvider->queryDispatch( aURL, OUString(), 0 ); + if ( xDispatch.is() ) + xDispatch->dispatch( aURL, rArgs ); + } +} + +} // dbaui namespace + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_dbu_LimitBoxController_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::LimitBoxController(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/limitboxcontroller.hxx b/dbaccess/source/ui/querydesign/limitboxcontroller.hxx new file mode 100644 index 000000000..af1e5a666 --- /dev/null +++ b/dbaccess/source/ui/querydesign/limitboxcontroller.hxx @@ -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/. + */ + +#pragma once + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <connectivity/CommonTools.hxx> +#include <svtools/toolboxcontroller.hxx> +#include <vcl/vclptr.hxx> + +namespace dbaui +{ + +class LimitBox; + +/** + * A ToolboxController to paste LimitBox onto the Query Design Toolbar + * It is communicating with querycontroller and this channel make enable + * to set\get the value of limitbox when switching between views + */ +class LimitBoxController: public svt::ToolboxController, + public css::lang::XServiceInfo +{ + public: + explicit LimitBoxController( + const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + virtual ~LimitBoxController() override; + + /// XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire() noexcept override; + virtual void SAL_CALL release() noexcept override; + + /// XServiceInfo + DECLARE_SERVICE_INFO(); + + /// XComponent + virtual void SAL_CALL dispose() override; + + /// XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override; + + /// XToolbarController + virtual void SAL_CALL execute( sal_Int16 KeyModifier ) override; + virtual void SAL_CALL click() override; + virtual void SAL_CALL doubleClick() override; + virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createPopupWindow() override; + virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override; + + void dispatchCommand( const css::uno::Sequence< css::beans::PropertyValue >& rArgs ); + using svt::ToolboxController::dispatchCommand; + + private: + VclPtr<LimitBox> m_xLimitBox; +}; + +} ///dbaui namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/querycontainerwindow.cxx b/dbaccess/source/ui/querydesign/querycontainerwindow.cxx new file mode 100644 index 000000000..68b4c5c86 --- /dev/null +++ b/dbaccess/source/ui/querydesign/querycontainerwindow.cxx @@ -0,0 +1,222 @@ +/* -*- 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 <querycontainerwindow.hxx> +#include <QueryDesignView.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <JoinController.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <strings.hxx> +#include <sfx2/sfxsids.hrc> +#include <vcl/event.hxx> +#include <UITools.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/Frame.hpp> +#include <com/sun/star/util/XCloseable.hpp> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::beans; + + // OQueryContainerWindow + OQueryContainerWindow::OQueryContainerWindow(vcl::Window* pParent, OQueryController& _rController,const Reference< XComponentContext >& _rxContext) + :ODataView( pParent, _rController, _rxContext ) + ,m_pViewSwitch(nullptr) + ,m_pBeamer(nullptr) + { + m_pViewSwitch = new OQueryViewSwitch( this, _rController, _rxContext ); + + m_pSplitter = VclPtr<Splitter>::Create(this,WB_VSCROLL); + m_pSplitter->Hide(); + m_pSplitter->SetSplitHdl( LINK( this, OQueryContainerWindow, SplitHdl ) ); + m_pSplitter->SetBackground( Wallpaper( Application::GetSettings().GetStyleSettings().GetDialogColor() ) ); + } + OQueryContainerWindow::~OQueryContainerWindow() + { + disposeOnce(); + } + void OQueryContainerWindow::dispose() + { + { + OQueryViewSwitch* pTemp = m_pViewSwitch; + m_pViewSwitch = nullptr; + delete pTemp; + } + if ( m_pBeamer ) + ::dbaui::notifySystemWindow(this,m_pBeamer,::comphelper::mem_fun(&TaskPaneList::RemoveWindow)); + m_pBeamer.clear(); + if ( m_xBeamer.is() ) + { + Reference< css::util::XCloseable > xCloseable(m_xBeamer,UNO_QUERY); + m_xBeamer = nullptr; + if(xCloseable.is()) + xCloseable->close(false); // false - holds the ownership of this frame + } + + m_pSplitter.disposeAndClear(); + ODataView::dispose(); + } + bool OQueryContainerWindow::switchView( ::dbtools::SQLExceptionInfo* _pErrorInfo ) + { + return m_pViewSwitch->switchView( _pErrorInfo ); + } + + void OQueryContainerWindow::forceInitialView() + { + return m_pViewSwitch->forceInitialView(); + } + + void OQueryContainerWindow::resizeAll( const tools::Rectangle& _rPlayground ) + { + tools::Rectangle aPlayground( _rPlayground ); + + if ( m_pBeamer && m_pBeamer->IsVisible() ) + { + // calc pos and size of the splitter + Point aSplitPos = m_pSplitter->GetPosPixel(); + Size aSplitSize = m_pSplitter->GetOutputSizePixel(); + aSplitSize.setWidth( aPlayground.GetWidth() ); + + if ( aSplitPos.Y() <= aPlayground.Top() ) + aSplitPos.setY( aPlayground.Top() + sal_Int32( aPlayground.GetHeight() * 0.2 ) ); + + if ( aSplitPos.Y() + aSplitSize.Height() > aPlayground.GetHeight() ) + aSplitPos.setY( aPlayground.GetHeight() - aSplitSize.Height() ); + + // set pos and size of the splitter + m_pSplitter->SetPosSizePixel( aSplitPos, aSplitSize ); + m_pSplitter->SetDragRectPixel( aPlayground ); + + // set pos and size of the beamer + Size aBeamerSize( aPlayground.GetWidth(), aSplitPos.Y() ); + m_pBeamer->SetPosSizePixel( aPlayground.TopLeft(), aBeamerSize ); + + // shrink the playground by the size which is occupied by the beamer + aPlayground.SetTop( aSplitPos.Y() + aSplitSize.Height() ); + } + + ODataView::resizeAll( aPlayground ); + } + + void OQueryContainerWindow::resizeDocumentView( tools::Rectangle& _rPlayground ) + { + m_pViewSwitch->SetPosSizePixel( _rPlayground.TopLeft(), Size( _rPlayground.GetWidth(), _rPlayground.GetHeight() ) ); + + ODataView::resizeDocumentView( _rPlayground ); + } + + void OQueryContainerWindow::GetFocus() + { + ODataView::GetFocus(); + if(m_pViewSwitch) + m_pViewSwitch->GrabFocus(); + } + IMPL_LINK_NOARG( OQueryContainerWindow, SplitHdl, Splitter*, void ) + { + m_pSplitter->SetPosPixel( Point( m_pSplitter->GetPosPixel().X(),m_pSplitter->GetSplitPosPixel() ) ); + Resize(); + } + + void OQueryContainerWindow::Construct() + { + m_pViewSwitch->Construct(); + } + + void OQueryContainerWindow::disposingPreview() + { + if ( m_pBeamer ) + { + // here I know that we will be destroyed from the frame + ::dbaui::notifySystemWindow(this,m_pBeamer,::comphelper::mem_fun(&TaskPaneList::RemoveWindow)); + m_pBeamer = nullptr; + m_xBeamer = nullptr; + m_pSplitter->Hide(); + Resize(); + } + } + bool OQueryContainerWindow::PreNotify( NotifyEvent& rNEvt ) + { + if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS && m_pViewSwitch) + { + OJoinController& rController = m_pViewSwitch->getDesignView()->getController(); + rController.InvalidateFeature(SID_CUT); + rController.InvalidateFeature(SID_COPY); + rController.InvalidateFeature(SID_PASTE); + } + return ODataView::PreNotify(rNEvt); + } + void OQueryContainerWindow::showPreview(const Reference<XFrame>& _xFrame) + { + if(m_pBeamer) + return; + + m_pBeamer = VclPtr<OBeamer>::Create(this); + + ::dbaui::notifySystemWindow(this,m_pBeamer,::comphelper::mem_fun(&TaskPaneList::AddWindow)); + + m_xBeamer = Frame::create( m_pViewSwitch->getORB() ); + m_xBeamer->initialize( VCLUnoHelper::GetInterface ( m_pBeamer ) ); + + // notify layout manager to not create internal toolbars + try + { + Reference < XPropertySet > xLMPropSet(m_xBeamer->getLayoutManager(), UNO_QUERY); + if ( xLMPropSet.is() ) + { + xLMPropSet->setPropertyValue( "AutomaticToolbars", Any( false )); + } + } + catch( Exception& ) + { + } + + m_xBeamer->setName(FRAME_NAME_QUERY_PREVIEW); + + // append our frame + Reference < XFramesSupplier > xSup(_xFrame,UNO_QUERY); + Reference < XFrames > xFrames = xSup->getFrames(); + xFrames->append( Reference<XFrame>(m_xBeamer,UNO_QUERY_THROW) ); + + Size aSize = GetOutputSizePixel(); + Size aBeamer(aSize.Width(),sal_Int32(aSize.Height()*0.33)); + + const tools::Long nFrameHeight = LogicToPixel(Size(0, 3), MapMode(MapUnit::MapAppFont)).Height(); + Point aPos(0,aBeamer.Height()+nFrameHeight); + + m_pBeamer->SetPosSizePixel(Point(0,0),aBeamer); + m_pBeamer->Show(); + + m_pSplitter->SetPosSizePixel( Point(0,aBeamer.Height()), Size(aSize.Width(),nFrameHeight) ); + // a default pos for the splitter, so that the listbox is about 80 (logical) pixels wide + m_pSplitter->SetSplitPosPixel( aBeamer.Height() ); + m_pViewSwitch->SetPosSizePixel(aPos,Size(aBeamer.Width(),aSize.Height() - aBeamer.Height()-nFrameHeight)); + + m_pSplitter->Show(); + + Resize(); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/querycontroller.cxx b/dbaccess/source/ui/querydesign/querycontroller.cxx new file mode 100644 index 000000000..230cb7f6e --- /dev/null +++ b/dbaccess/source/ui/querydesign/querycontroller.cxx @@ -0,0 +1,1790 @@ +/* -*- 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 <browserids.hxx> +#include <core_resource.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <query.hrc> +#include <stringconstants.hxx> +#include <defaultobjectnamecheck.hxx> +#include <dlgsave.hxx> +#include <querycontainerwindow.hxx> +#include <querycontroller.hxx> +#include <QueryDesignView.hxx> +#include <QueryTableView.hxx> +#include <sqlmessage.hxx> +#include <TableConnectionData.hxx> +#include <TableFieldDescription.hxx> +#include <UITools.hxx> +#include <QueryPropertiesDialog.hxx> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp> +#include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XDrop.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/util/XCloseable.hpp> +#include <com/sun/star/util/VetoException.hpp> +#include <com/sun/star/ui/XUIElement.hpp> + +#include <comphelper/propertysequence.hxx> +#include <comphelper/property.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <svl/undo.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <vcl/stdtext.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <osl/mutex.hxx> +#include <o3tl/string_view.hxx> +#include <memory> +#include <vector> + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_OQueryDesign_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::OQueryController(context)); +} + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::lang; + + namespace { + + class OViewController : public OQueryController + { + virtual OUString SAL_CALL getImplementationName() override + { + return "org.openoffice.comp.dbu.OViewDesign"; + } + virtual Sequence< OUString> SAL_CALL getSupportedServiceNames() override + { + return { "com.sun.star.sdb.ViewDesign" }; + } + + public: + explicit OViewController(const Reference< XComponentContext >& _rM) : OQueryController(_rM){} + }; + + } +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_OViewDesign_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::OViewController(context)); +} + +namespace dbaui +{ + using namespace ::connectivity; + + namespace + { + OUString lcl_getObjectResourceString(TranslateId pResId, sal_Int32 _nCommandType) + { + OUString sMessageText = DBA_RES(pResId); + OUString sObjectType = DBA_RES(RSC_QUERY_OBJECT_TYPE[_nCommandType]); + sMessageText = sMessageText.replaceFirst( "$object$", sObjectType ); + return sMessageText; + } + } + +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::ui; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::awt; +using namespace ::dbtools; + +using namespace ::comphelper; + +namespace +{ + void ensureToolbars( OQueryController& _rController, bool _bDesign ) + { + Reference< css::frame::XLayoutManager > xLayoutManager = OGenericUnoController::getLayoutManager( _rController.getFrame() ); + if ( !xLayoutManager.is() ) + return; + + xLayoutManager->lock(); + static constexpr OUStringLiteral s_sDesignToolbar = u"private:resource/toolbar/designobjectbar"; + static constexpr OUStringLiteral s_sSqlToolbar = u"private:resource/toolbar/sqlobjectbar"; + if ( _bDesign ) + { + xLayoutManager->destroyElement( s_sSqlToolbar ); + xLayoutManager->createElement( s_sDesignToolbar ); + } + else + { + xLayoutManager->destroyElement( s_sDesignToolbar ); + xLayoutManager->createElement( s_sSqlToolbar ); + } + xLayoutManager->unlock(); + xLayoutManager->doLayout(); + } + + /** + * The value of m_nLimit is updated when LimitBox loses its focus + * So in those case when execution needs recent data, grab the focus + * (e.g. execute SQL statement, change views) + */ + void grabFocusFromLimitBox( OQueryController& _rController ) + { + Reference< XLayoutManager > xLayoutManager = OGenericUnoController::getLayoutManager( _rController.getFrame() ); + Reference< XUIElement > xUIElement = xLayoutManager->getElement("private:resource/toolbar/designobjectbar"); + if (xUIElement.is()) + { + Reference< XWindow > xWindow(xUIElement->getRealInterface(), css::uno::UNO_QUERY); + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); + if( pWindow && pWindow->HasChildPathFocus() ) + { + pWindow->GrabFocusToDocument(); + } + } + } +} + +OUString SAL_CALL OQueryController::getImplementationName() +{ + return "org.openoffice.comp.dbu.OQueryDesign"; +} + +Sequence< OUString> SAL_CALL OQueryController::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.QueryDesign" }; +} + +OQueryController::OQueryController(const Reference< XComponentContext >& _rM) + :OJoinController(_rM) + ,OQueryController_PBase( getBroadcastHelper() ) + ,m_pParseContext( new svxform::OSystemParseContext ) + ,m_aSqlParser( _rM, m_pParseContext.get() ) + ,m_nLimit(-1) + ,m_nVisibleRows(0x400) + ,m_nSplitPos(-1) + ,m_nCommandType( CommandType::QUERY ) + ,m_bGraphicalDesign(false) + ,m_bDistinct(false) + ,m_bEscapeProcessing(true) +{ + InvalidateAll(); + + registerProperty( PROPERTY_ACTIVECOMMAND, PROPERTY_ID_ACTIVECOMMAND, PropertyAttribute::READONLY | PropertyAttribute::BOUND, + &m_sStatement, cppu::UnoType<decltype(m_sStatement)>::get() ); + registerProperty( PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::READONLY | PropertyAttribute::BOUND, + &m_bEscapeProcessing, cppu::UnoType<decltype(m_bEscapeProcessing)>::get() ); +} + +OQueryController::~OQueryController() +{ + if ( !getBroadcastHelper().bDisposed && !getBroadcastHelper().bInDispose ) + { + OSL_FAIL("Please check who doesn't dispose this component!"); + // increment ref count to prevent double call of Dtor + osl_atomic_increment( &m_refCount ); + dispose(); + } +} + +IMPLEMENT_FORWARD_XINTERFACE2( OQueryController, OJoinController, OQueryController_PBase ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( OQueryController, OJoinController, OQueryController_PBase ) + +Reference< XPropertySetInfo > SAL_CALL OQueryController::getPropertySetInfo() +{ + Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +void SAL_CALL OQueryController::getFastPropertyValue( Any& o_rValue, sal_Int32 i_nHandle ) const +{ + switch ( i_nHandle ) + { + case PROPERTY_ID_CURRENT_QUERY_DESIGN: + { + ::comphelper::NamedValueCollection aCurrentDesign; + aCurrentDesign.put( "GraphicalDesign", isGraphicalDesign() ); + aCurrentDesign.put( PROPERTY_ESCAPE_PROCESSING, m_bEscapeProcessing ); + + if ( isGraphicalDesign() ) + { + getContainer()->SaveUIConfig(); + saveViewSettings( aCurrentDesign, true ); + aCurrentDesign.put( "Statement", m_sStatement ); + } + else + { + aCurrentDesign.put( "Statement", getContainer()->getStatement() ); + } + + o_rValue <<= aCurrentDesign.getPropertyValues(); + } + break; + + default: + OPropertyContainer::getFastPropertyValue( o_rValue, i_nHandle ); + break; + } +} + +::cppu::IPropertyArrayHelper& OQueryController::getInfoHelper() +{ + return *getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* OQueryController::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties( aProps ); + + // one additional property: + const sal_Int32 nLength = aProps.getLength(); + aProps.realloc( nLength + 1 ); + auto pProps = aProps.getArray(); + pProps[ nLength ] = Property( + "CurrentQueryDesign", + PROPERTY_ID_CURRENT_QUERY_DESIGN, + ::cppu::UnoType< Sequence< PropertyValue > >::get(), + PropertyAttribute::READONLY + ); + + std::sort( + pProps, + pProps + aProps.getLength(), + ::comphelper::PropertyCompareByName() + ); + + return new ::cppu::OPropertyArrayHelper(aProps); +} + +void OQueryController::deleteIterator() +{ + if(m_pSqlIterator) + { + delete m_pSqlIterator->getParseTree(); + m_pSqlIterator->dispose(); + m_pSqlIterator.reset(); + } +} + +void OQueryController::disposing() +{ + OQueryController_PBase::disposing(); + + deleteIterator(); + + m_pParseContext.reset(); + + clearFields(); + OTableFields().swap(m_vUnUsedFieldsDesc); + + ::comphelper::disposeComponent(m_xComposer); + OJoinController::disposing(); + OQueryController_PBase::disposing(); +} + +void OQueryController::clearFields() +{ + OTableFields().swap(m_vTableFieldDesc); +} + +FeatureState OQueryController::GetState(sal_uInt16 _nId) const +{ + FeatureState aReturn; + aReturn.bEnabled = true; + // (disabled automatically) + + switch (_nId) + { + case ID_BROWSER_EDITDOC: + if ( editingCommand() ) + aReturn.bEnabled = false; + else if ( editingView() && !m_xAlterView.is() ) + aReturn.bEnabled = false; + else + aReturn = OJoinController::GetState( _nId ); + break; + + case ID_BROWSER_ESCAPEPROCESSING: + aReturn.bChecked = !m_bEscapeProcessing; + aReturn.bEnabled = ( m_pSqlIterator != nullptr ) && !m_bGraphicalDesign; + break; + case SID_RELATION_ADD_RELATION: + aReturn.bEnabled = isEditable() && m_bGraphicalDesign && m_vTableData.size() > 1; + break; + case ID_BROWSER_SAVEASDOC: + aReturn.bEnabled = !editingCommand() && (!m_bGraphicalDesign || !(m_vTableFieldDesc.empty() || m_vTableData.empty())); + break; + case ID_BROWSER_SAVEDOC: + aReturn.bEnabled = isEditable() && (!m_bGraphicalDesign || !(m_vTableFieldDesc.empty() || m_vTableData.empty())); + break; + case SID_PRINTDOCDIRECT: + break; + case ID_BROWSER_CUT: + aReturn.bEnabled = isEditable() && getContainer() && getContainer()->isCutAllowed(); + break; + case ID_BROWSER_COPY: + aReturn.bEnabled = getContainer() && getContainer()->isCopyAllowed(); + break; + case ID_BROWSER_PASTE: + aReturn.bEnabled = isEditable() && getContainer() && getContainer()->isPasteAllowed(); + break; + case ID_BROWSER_SQL: + aReturn.bEnabled = m_bEscapeProcessing && m_pSqlIterator; + aReturn.bChecked = m_bGraphicalDesign; + break; + case SID_BROWSER_CLEAR_QUERY: + aReturn.bEnabled = isEditable() && (!m_sStatement.isEmpty() || !m_vTableData.empty()); + break; + case SID_QUERY_VIEW_FUNCTIONS: + case SID_QUERY_VIEW_TABLES: + case SID_QUERY_VIEW_ALIASES: + aReturn.bChecked = getContainer() && getContainer()->isSlotEnabled(_nId); + aReturn.bEnabled = m_bGraphicalDesign; + break; + case SID_QUERY_DISTINCT_VALUES: + aReturn.bEnabled = m_bGraphicalDesign && isEditable(); + aReturn.bChecked = m_bDistinct; + break; + case SID_QUERY_LIMIT: + aReturn.bEnabled = m_bGraphicalDesign; + if( aReturn.bEnabled ) + aReturn.aValue <<= m_nLimit; + break; + case SID_QUERY_PROP_DLG: + aReturn.bEnabled = m_bGraphicalDesign; + break; + case ID_BROWSER_QUERY_EXECUTE: + aReturn.bEnabled = true; + break; + case SID_DB_QUERY_PREVIEW: + aReturn.bEnabled = true; + aReturn.bChecked = getContainer() && getContainer()->getPreviewFrame().is(); + break; +#if OSL_DEBUG_LEVEL > 0 + case ID_EDIT_QUERY_SQL: + break; + case ID_EDIT_QUERY_DESIGN: + break; +#endif + case ID_BROWSER_ADDTABLE: + if ( !m_bGraphicalDesign ) + { + aReturn.bEnabled = false; + break; + } + [[fallthrough]]; + default: + aReturn = OJoinController::GetState(_nId); + break; + } + return aReturn; +} + +void OQueryController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs) +{ + switch(_nId) + { + case ID_BROWSER_ESCAPEPROCESSING: + setEscapeProcessing_fireEvent( !m_bEscapeProcessing ); + if ( !editingView() ) + setModified(true); + InvalidateFeature(ID_BROWSER_SQL); + break; + case ID_BROWSER_SAVEASDOC: + case ID_BROWSER_SAVEDOC: + grabFocusFromLimitBox(*this); + doSaveAsDoc(ID_BROWSER_SAVEASDOC == _nId); + break; + case SID_RELATION_ADD_RELATION: + { + OJoinDesignView* pView = getJoinView(); + if( pView ) + static_cast<OQueryTableView*>(pView->getTableView())->createNewConnection(); + } + break; + case SID_PRINTDOCDIRECT: + break; + case ID_BROWSER_CUT: + getContainer()->cut(); + break; + case ID_BROWSER_COPY: + getContainer()->copy(); + break; + case ID_BROWSER_PASTE: + getContainer()->paste(); + break; + case ID_BROWSER_SQL: + { + grabFocusFromLimitBox(*this); + if ( !getContainer()->checkStatement() ) + break; + SQLExceptionInfo aError; + try + { + setStatement_fireEvent( getContainer()->getStatement() ); + if(m_sStatement.isEmpty() && m_pSqlIterator) + { + // change the view of the data + delete m_pSqlIterator->getParseTree(); + m_pSqlIterator->setParseTree(nullptr); + m_bGraphicalDesign = !m_bGraphicalDesign; + impl_setViewMode( &aError ); + } + else + { + OUString aErrorMsg; + std::unique_ptr<::connectivity::OSQLParseNode> pNode = m_aSqlParser.parseTree(aErrorMsg,m_sStatement,m_bGraphicalDesign); + if ( pNode ) + { + delete m_pSqlIterator->getParseTree(); + m_pSqlIterator->setParseTree(pNode.release()); + m_pSqlIterator->traverseAll(); + + if ( m_pSqlIterator->hasErrors() ) + { + aError = m_pSqlIterator->getErrors(); + } + else + { + const OSQLTables& rTabs = m_pSqlIterator->getTables(); + if ( m_pSqlIterator->getStatementType() != OSQLStatementType::Select || rTabs.empty() ) + { + aError = SQLException( + DBA_RES(STR_QRY_NOSELECT), + nullptr, + "S1000", + 1000, + Any() + ); + } + else + { + // change the view of the data + m_bGraphicalDesign = !m_bGraphicalDesign; + OUString sNewStatement; + m_pSqlIterator->getParseTree()->parseNodeToStr( sNewStatement, getConnection() ); + setStatement_fireEvent( sNewStatement ); + getContainer()->SaveUIConfig(); + m_vTableConnectionData.clear(); + impl_setViewMode( &aError ); + } + } + } + else + { + aError = SQLException( + DBA_RES(STR_QRY_SYNTAX), + nullptr, + "S1000", + 1000, + Any() + ); + } + } + } + catch(const SQLException&) + { + aError = ::cppu::getCaughtException(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if ( aError.isValid() ) + showError( aError ); + + if(m_bGraphicalDesign) + { + InvalidateFeature(ID_BROWSER_ADDTABLE); + InvalidateFeature(SID_RELATION_ADD_RELATION); + } + } + break; + case SID_BROWSER_CLEAR_QUERY: + { + GetUndoManager().EnterListAction(DBA_RES(STR_QUERY_UNDO_TABWINDELETE), OUString(), 0, ViewShellId(-1) ); + getContainer()->clear(); + GetUndoManager().LeaveListAction(); + + setStatement_fireEvent( OUString() ); + if(m_bGraphicalDesign) + InvalidateFeature(ID_BROWSER_ADDTABLE); + } + break; + case SID_QUERY_VIEW_FUNCTIONS: + case SID_QUERY_VIEW_TABLES: + case SID_QUERY_VIEW_ALIASES: + getContainer()->setSlotEnabled(_nId,!getContainer()->isSlotEnabled(_nId)); + setModified(true); + break; + case SID_QUERY_DISTINCT_VALUES: + m_bDistinct = !m_bDistinct; + setModified(true); + break; + case SID_QUERY_LIMIT: + if ( aArgs.hasElements() && aArgs[0].Name == "DBLimit.Value" ) + { + aArgs[0].Value >>= m_nLimit; + setModified(true); + } + break; + case SID_QUERY_PROP_DLG: + grabFocusFromLimitBox(*this); + execute_QueryPropDlg(); + break; + case ID_BROWSER_QUERY_EXECUTE: + grabFocusFromLimitBox(*this); + if ( getContainer()->checkStatement() ) + executeQuery(); + break; + case SID_DB_QUERY_PREVIEW: + try + { + Reference< css::util::XCloseable > xCloseFrame( getContainer()->getPreviewFrame(), UNO_QUERY ); + if ( xCloseFrame.is() ) + { + try + { + xCloseFrame->close( true ); + } + catch(const Exception&) + { + OSL_FAIL( "OQueryController::Execute(SID_DB_QUERY_PREVIEW): *nobody* is expected to veto closing the preview frame!" ); + } + } + else + Execute(ID_BROWSER_QUERY_EXECUTE,Sequence< PropertyValue >()); + } + catch(const Exception&) + { + } + break; + default: + OJoinController::Execute(_nId,aArgs); + return; // else we would invalidate twice + } + InvalidateFeature(_nId); +} + +void OQueryController::impl_showAutoSQLViewError( const css::uno::Any& _rErrorDetails ) +{ + SQLContext aErrorContext; + aErrorContext.Message = lcl_getObjectResourceString( STR_ERROR_PARSING_STATEMENT, m_nCommandType ); + aErrorContext.Context = *this; + aErrorContext.Details = lcl_getObjectResourceString( STR_INFO_OPENING_IN_SQL_VIEW, m_nCommandType ); + aErrorContext.NextException = _rErrorDetails; + showError( aErrorContext ); +} + +void OQueryController::impl_setViewMode( ::dbtools::SQLExceptionInfo* _pErrorInfo ) +{ + OSL_PRECOND( getContainer(), "OQueryController::impl_setViewMode: illegal call!" ); + + bool wasModified = isModified(); + + SQLExceptionInfo aError; + bool bSuccess = getContainer()->switchView( &aError ); + if ( !bSuccess ) + { + m_bGraphicalDesign = !m_bGraphicalDesign; + // restore old state + getContainer()->switchView( nullptr ); + // don't pass &aError here, this would overwrite the error which the first switchView call + // returned in this location. + if ( _pErrorInfo ) + *_pErrorInfo = aError; + else + showError( aError ); + } + else + { + ensureToolbars( *this, m_bGraphicalDesign ); + } + + setModified( wasModified ); +} + +void OQueryController::impl_initialize() +{ + OJoinController::impl_initialize(); + + const NamedValueCollection& rArguments( getInitParams() ); + + OUString sCommand; + m_nCommandType = CommandType::QUERY; + + // reading parameters: + + // legacy parameters first (later overwritten by regular parameters) + OUString sIndependentSQLCommand; + if ( rArguments.get_ensureType( "IndependentSQLCommand", sIndependentSQLCommand ) ) + { + OSL_FAIL( "OQueryController::impl_initialize: IndependentSQLCommand is regognized for compatibility only!" ); + sCommand = sIndependentSQLCommand; + m_nCommandType = CommandType::COMMAND; + } + + OUString sCurrentQuery; + if ( rArguments.get_ensureType( "CurrentQuery", sCurrentQuery ) ) + { + OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" ); + sCommand = sCurrentQuery; + m_nCommandType = CommandType::QUERY; + } + + bool bCreateView( false ); + if ( rArguments.get_ensureType( "CreateView", bCreateView ) && bCreateView ) + { + OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" ); + m_nCommandType = CommandType::TABLE; + } + + // non-legacy parameters which overwrite the legacy parameters + rArguments.get_ensureType( PROPERTY_COMMAND, sCommand ); + rArguments.get_ensureType( PROPERTY_COMMAND_TYPE, m_nCommandType ); + + // translate Command/Type into proper members + // TODO/Later: all this (including those members) should be hidden behind some abstract interface, + // which is implemented for all the three commands + switch ( m_nCommandType ) + { + case CommandType::QUERY: + m_sName = sCommand; + break; + case CommandType::TABLE: + m_sName = sCommand; + break; + case CommandType::COMMAND: + setStatement_fireEvent( sCommand ); + m_sName.clear(); + break; + default: + OSL_FAIL( "OQueryController::impl_initialize: logic error in code!" ); + throw RuntimeException(); + } + + // more legacy parameters + bool bGraphicalDesign( true ); + if ( rArguments.get_ensureType( PROPERTY_QUERYDESIGNVIEW, bGraphicalDesign ) ) + { + OSL_FAIL( "OQueryController::impl_initialize: QueryDesignView is regognized for compatibility only!" ); + m_bGraphicalDesign = bGraphicalDesign; + } + + // more non-legacy + rArguments.get_ensureType( PROPERTY_GRAPHICAL_DESIGN, m_bGraphicalDesign ); + + bool bEscapeProcessing( true ); + if ( rArguments.get_ensureType( PROPERTY_ESCAPE_PROCESSING, bEscapeProcessing ) ) + { + setEscapeProcessing_fireEvent( bEscapeProcessing ); + + OSL_ENSURE( m_bEscapeProcessing || !m_bGraphicalDesign, "OQueryController::impl_initialize: can't do the graphical design without escape processing!" ); + if ( !m_bEscapeProcessing ) + m_bGraphicalDesign = false; + } + + // initial design + bool bForceInitialDesign = false; + Sequence< PropertyValue > aCurrentQueryDesignProps; + aCurrentQueryDesignProps = rArguments.getOrDefault( "CurrentQueryDesign", aCurrentQueryDesignProps ); + + if ( aCurrentQueryDesignProps.hasElements() ) + { + ::comphelper::NamedValueCollection aCurrentQueryDesign( aCurrentQueryDesignProps ); + if ( aCurrentQueryDesign.has( PROPERTY_GRAPHICAL_DESIGN ) ) + { + aCurrentQueryDesign.get_ensureType( PROPERTY_GRAPHICAL_DESIGN, m_bGraphicalDesign ); + } + if ( aCurrentQueryDesign.has( PROPERTY_ESCAPE_PROCESSING ) ) + { + aCurrentQueryDesign.get_ensureType( PROPERTY_ESCAPE_PROCESSING, m_bEscapeProcessing ); + } + if ( aCurrentQueryDesign.has( "Statement" ) ) + { + OUString sStatement; + aCurrentQueryDesign.get_ensureType( "Statement", sStatement ); + aCurrentQueryDesign.remove( "Statement" ); + setStatement_fireEvent( sStatement ); + } + + loadViewSettings( aCurrentQueryDesign ); + + bForceInitialDesign = true; + } + + if ( !ensureConnected() ) + { // we have no connection so what else should we do + m_bGraphicalDesign = false; + if ( editingView() ) + { + connectionLostMessage(); + throw SQLException(); + } + } + + // check the view capabilities + if ( isConnected() && editingView() ) + { + Reference< XViewsSupplier > xViewsSup( getConnection(), UNO_QUERY ); + Reference< XNameAccess > xViews; + if ( xViewsSup.is() ) + xViews = xViewsSup->getViews(); + + if ( !xViews.is() ) + { // we can't create views so we ask if the user wants to create a query instead + m_nCommandType = CommandType::QUERY; + bool bClose = false; + { + OUString aTitle(DBA_RES(STR_QUERYDESIGN_NO_VIEW_SUPPORT)); + OUString aMessage(DBA_RES(STR_QUERYDESIGN_NO_VIEW_ASK)); + OSQLMessageBox aDlg(getFrameWeld(), aTitle, aMessage, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes, MessageType::Query); + bClose = aDlg.run() == RET_NO; + } + if ( bClose ) + throw VetoException(); + } + + // now if we are to edit an existing view, check whether this is possible + if ( !m_sName.isEmpty() ) + { + Any aView( xViews->getByName( m_sName ) ); + // will throw if there is no such view + if ( !( aView >>= m_xAlterView ) ) + { + throw IllegalArgumentException( + DBA_RES(STR_NO_ALTER_VIEW_SUPPORT), + *this, + 1 + ); + } + } + } + + OSL_ENSURE(getDataSource().is(),"OQueryController::impl_initialize: need a datasource!"); + + try + { + getContainer()->initialize(); + impl_reset( bForceInitialDesign ); + + SQLExceptionInfo aError; + const bool bAttemptedGraphicalDesign = m_bGraphicalDesign; + + if ( bForceInitialDesign ) + { + getContainer()->forceInitialView(); + } + else + { + impl_setViewMode( &aError ); + } + + if ( aError.isValid() && bAttemptedGraphicalDesign && !m_bGraphicalDesign ) + { + // we tried initializing the graphical view, this failed, and we were automatically switched to SQL + // view => tell this to the user + if ( !editingView() ) + { + impl_showAutoSQLViewError( aError.get() ); + } + } + + ClearUndoManager(); + + if ( m_bGraphicalDesign + && ( ( m_sName.isEmpty() && !editingCommand() ) + || ( m_sStatement.isEmpty() && editingCommand() ) + ) + ) + { + Application::PostUserEvent( LINK( this, OQueryController, OnExecuteAddTable ) ); + } + + setModified(false); + } + catch(const SQLException& e) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + // we caught an exception so we switch to text only mode + { + m_bGraphicalDesign = false; + getContainer()->initialize(); + OSQLMessageBox aBox(getFrameWeld(), e); + aBox.run(); + } + throw; + } +} + +void OQueryController::onLoadedMenu(const Reference< css::frame::XLayoutManager >& /*_xLayoutManager*/) +{ + ensureToolbars( *this, m_bGraphicalDesign ); +} + +OUString OQueryController::getPrivateTitle( ) const +{ + if ( m_sName.isEmpty() ) + { + if ( !editingCommand() ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + OUString aDefaultName = DBA_RES(editingView() ? STR_VIEW_TITLE : STR_QRY_TITLE); + return o3tl::getToken(aDefaultName, 0, ' ') + OUString::number(getCurrentStartNumber()); + } + } + return m_sName; +} + +void OQueryController::setQueryComposer() +{ + if(!isConnected()) + return; + + Reference< XSQLQueryComposerFactory > xFactory(getConnection(), UNO_QUERY); + OSL_ENSURE(xFactory.is(),"Connection doesn't support a querycomposer"); + if ( !(xFactory.is() && getContainer()) ) + return; + + try + { + m_xComposer = xFactory->createQueryComposer(); + getContainer()->setStatement(m_sStatement); + } + catch(const Exception&) + { + m_xComposer = nullptr; + } + OSL_ENSURE(m_xComposer.is(),"No querycomposer available!"); + Reference<XTablesSupplier> xTablesSup(getConnection(), UNO_QUERY); + deleteIterator(); + m_pSqlIterator.reset(new ::connectivity::OSQLParseTreeIterator( getConnection(), xTablesSup->getTables(), m_aSqlParser )); +} + +bool OQueryController::Construct(vcl::Window* pParent) +{ + // TODO: we have to check if we should create the text view or the design view + + setView( VclPtr<OQueryContainerWindow>::Create( pParent, *this, getORB() ) ); + + return OJoinController::Construct(pParent); +} + +OJoinDesignView* OQueryController::getJoinView() +{ + return getContainer()->getDesignView(); +} + +void OQueryController::describeSupportedFeatures() +{ + OJoinController::describeSupportedFeatures(); + implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:SbaNativeSql", ID_BROWSER_ESCAPEPROCESSING,CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:DBViewFunctions", SID_QUERY_VIEW_FUNCTIONS, CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:DBViewTableNames", SID_QUERY_VIEW_TABLES, CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:DBViewAliases", SID_QUERY_VIEW_ALIASES, CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:DBDistinctValues", SID_QUERY_DISTINCT_VALUES, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:DBChangeDesignMode",ID_BROWSER_SQL, CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:DBClearQuery", SID_BROWSER_CLEAR_QUERY, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:SbaExecuteSql", ID_BROWSER_QUERY_EXECUTE, CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:DBAddRelation", SID_RELATION_ADD_RELATION, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:DBQueryPreview", SID_DB_QUERY_PREVIEW, CommandGroup::VIEW ); + implDescribeSupportedFeature( ".uno:DBLimit", SID_QUERY_LIMIT, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:DBQueryPropertiesDialog", SID_QUERY_PROP_DLG, CommandGroup::FORMAT ); + +#if OSL_DEBUG_LEVEL > 0 + implDescribeSupportedFeature( ".uno:DBShowParseTree", ID_EDIT_QUERY_SQL ); + implDescribeSupportedFeature( ".uno:DBMakeDisjunct", ID_EDIT_QUERY_DESIGN ); +#endif +} + +void OQueryController::impl_onModifyChanged() +{ + OJoinController::impl_onModifyChanged(); + InvalidateFeature(SID_BROWSER_CLEAR_QUERY); + InvalidateFeature(ID_BROWSER_SAVEASDOC); + InvalidateFeature(ID_BROWSER_QUERY_EXECUTE); +} + +void SAL_CALL OQueryController::disposing( const EventObject& Source ) +{ + SolarMutexGuard aGuard; + + if ( getContainer() && Source.Source.is() ) + { + if ( Source.Source == m_aCurrentFrame.getFrame() ) + { // our frame is being disposed -> close the preview window (if we have one) + Reference< XFrame2 > xPreviewFrame( getContainer()->getPreviewFrame() ); + ::comphelper::disposeComponent( xPreviewFrame ); + } + else if ( Source.Source == getContainer()->getPreviewFrame() ) + { + getContainer()->disposingPreview(); + } + } + + OJoinController_BASE::disposing(Source); +} + +void OQueryController::reconnect(bool _bUI) +{ + deleteIterator(); + ::comphelper::disposeComponent(m_xComposer); + + OJoinController::reconnect( _bUI ); + + if (isConnected()) + { + setQueryComposer(); + } + else + { + if(m_bGraphicalDesign) + { + m_bGraphicalDesign = false; + // don't call Execute(SQL) because this changes the sql statement + impl_setViewMode( nullptr ); + } + InvalidateAll(); + } +} + +void OQueryController::saveViewSettings( ::comphelper::NamedValueCollection& o_rViewSettings, const bool i_includingCriteria ) const +{ + saveTableWindows( o_rViewSettings ); + + ::comphelper::NamedValueCollection aAllFieldsData; + ::comphelper::NamedValueCollection aFieldData; + sal_Int32 i = 1; + for (auto const& fieldDesc : m_vTableFieldDesc) + { + if ( !fieldDesc->IsEmpty() ) + { + aFieldData.clear(); + fieldDesc->Save( aFieldData, i_includingCriteria ); + + const OUString sFieldSettingName = "Field" + OUString::number( i ); + aAllFieldsData.put( sFieldSettingName, aFieldData.getPropertyValues() ); + } + ++i; + } + + o_rViewSettings.put( "Fields", aAllFieldsData.getPropertyValues() ); + o_rViewSettings.put( "SplitterPosition", m_nSplitPos ); + o_rViewSettings.put( "VisibleRows", m_nVisibleRows ); +} + +void OQueryController::loadViewSettings( const ::comphelper::NamedValueCollection& o_rViewSettings ) +{ + loadTableWindows( o_rViewSettings ); + + m_nSplitPos = o_rViewSettings.getOrDefault( "SplitterPosition", m_nSplitPos ); + m_nVisibleRows = o_rViewSettings.getOrDefault( "VisibleRows", m_nVisibleRows ); + m_aFieldInformation = o_rViewSettings.getOrDefault( "Fields", m_aFieldInformation ); +} + +void OQueryController::execute_QueryPropDlg() +{ + QueryPropertiesDialog aQueryPropDlg(getContainer()->GetFrameWeld(), m_bDistinct, m_nLimit); + + if (aQueryPropDlg.run() == RET_OK) + { + m_bDistinct = aQueryPropDlg.getDistinct(); + m_nLimit = aQueryPropDlg.getLimit(); + InvalidateFeature( SID_QUERY_DISTINCT_VALUES ); + InvalidateFeature( SID_QUERY_LIMIT, nullptr, true ); + } +} + +sal_Int32 OQueryController::getColWidth(sal_uInt16 _nColPos) const +{ + if ( _nColPos < m_aFieldInformation.getLength() ) + { + rtl::Reference<OTableFieldDesc> pField( new OTableFieldDesc()); + pField->Load( m_aFieldInformation[ _nColPos ], false ); + return pField->GetColWidth(); + } + return 0; +} + +Reference<XNameAccess> OQueryController::getObjectContainer() const +{ + Reference< XNameAccess > xElements; + if ( editingView() ) + { + Reference< XViewsSupplier > xViewsSupp( getConnection(), UNO_QUERY ); + if ( xViewsSupp.is() ) + xElements = xViewsSupp->getViews(); + } + else + { + Reference< XQueriesSupplier > xQueriesSupp( getConnection(), UNO_QUERY ); + if ( xQueriesSupp.is() ) + xElements = xQueriesSupp->getQueries(); + else + { + Reference< XQueryDefinitionsSupplier > xQueryDefsSupp( getDataSource(), UNO_QUERY ); + if ( xQueryDefsSupp.is() ) + xElements = xQueryDefsSupp->getQueryDefinitions(); + } + } + + OSL_ENSURE( xElements.is(), "OQueryController::getObjectContainer: unable to obtain the container!" ); + return xElements; +} + +void OQueryController::executeQuery() +{ + // we don't need to check the connection here because we already check the composer + // which can't live without his connection + OUString sTranslatedStmt = translateStatement( false ); + + OUString sDataSourceName = getDataSourceName(); + if ( sDataSourceName.isEmpty() || sTranslatedStmt.isEmpty() ) + return; + + try + { + getContainer()->showPreview( getFrame() ); + InvalidateFeature(SID_DB_QUERY_PREVIEW); + + URL aWantToDispatch; + aWantToDispatch.Complete = ".component:DB/DataSourceBrowser"; + + OUString sFrameName( FRAME_NAME_QUERY_PREVIEW ); + sal_Int32 nSearchFlags = FrameSearchFlag::CHILDREN; + + Reference< XDispatch> xDisp; + Reference< XDispatchProvider> xProv( getFrame()->findFrame( sFrameName, nSearchFlags ), UNO_QUERY ); + if(!xProv.is()) + { + xProv.set( getFrame(), UNO_QUERY ); + if (xProv.is()) + xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, nSearchFlags); + } + else + { + xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, FrameSearchFlag::SELF); + } + if (xDisp.is()) + { + auto aProps(::comphelper::InitPropertySequence( + { + { PROPERTY_DATASOURCENAME, Any(sDataSourceName) }, + { PROPERTY_COMMAND_TYPE, Any(CommandType::COMMAND) }, + { PROPERTY_COMMAND, Any(sTranslatedStmt) }, + { PROPERTY_ENABLE_BROWSER, Any(false) }, + { PROPERTY_ACTIVE_CONNECTION, Any(getConnection()) }, + { PROPERTY_UPDATE_CATALOGNAME, Any(m_sUpdateCatalogName) }, + { PROPERTY_UPDATE_SCHEMANAME, Any(m_sUpdateSchemaName) }, + { PROPERTY_UPDATE_TABLENAME, Any(OUString()) }, + { PROPERTY_ESCAPE_PROCESSING, Any(m_bEscapeProcessing) } + })); + + xDisp->dispatch(aWantToDispatch, aProps); + // check the state of the beamer + // be notified when the beamer frame is closed + Reference< XComponent > xComponent = getFrame()->findFrame( sFrameName, nSearchFlags ); + if (xComponent.is()) + { + OSL_ENSURE(Reference< XFrame >(xComponent, UNO_QUERY).get() == getContainer()->getPreviewFrame().get(), + "OQueryController::executeQuery: oops ... which window do I have here?"); + Reference< XEventListener> xEvtL(static_cast<cppu::OWeakObject*>(this),UNO_QUERY); + xComponent->addEventListener(xEvtL); + } + } + else + { + OSL_FAIL("Couldn't create a beamer window!"); + } + } + catch(const Exception&) + { + OSL_FAIL("Couldn't create a beamer window!"); + } +} + +bool OQueryController::askForNewName(const Reference<XNameAccess>& _xElements, bool _bSaveAs) +{ + OSL_ENSURE( !editingCommand(), "OQueryController::askForNewName: not to be called when designing an independent statement!" ); + if ( editingCommand() ) + return false; + + OSL_PRECOND( _xElements.is(), "OQueryController::askForNewName: invalid container!" ); + if ( !_xElements.is() ) + return false; + + bool bRet = true; + bool bNew = _bSaveAs || !_xElements->hasByName( m_sName ); + if(bNew) + { + OUString aDefaultName; + if (!m_sName.isEmpty()) + aDefaultName = m_sName; + else + { + OUString sName = DBA_RES(editingView() ? STR_VIEW_TITLE : STR_QRY_TITLE); + aDefaultName = ::dbtools::createUniqueName(_xElements, sName.getToken(0, ' ')); + } + + DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::QUERY ); + OSaveAsDlg aDlg( + getFrameWeld(), + m_nCommandType, + getORB(), + getConnection(), + aDefaultName, + aNameChecker, + SADFlags::NONE ); + + bRet = ( aDlg.run() == RET_OK ); + if ( bRet ) + { + m_sName = aDlg.getName(); + if ( editingView() ) + { + m_sUpdateCatalogName = aDlg.getCatalog(); + m_sUpdateSchemaName = aDlg.getSchema(); + } + } + } + return bRet; +} + +bool OQueryController::doSaveAsDoc(bool _bSaveAs) +{ + OSL_ENSURE(isEditable(),"Slot ID_BROWSER_SAVEDOC should not be enabled!"); + if ( !editingCommand() && !haveDataSource() ) + { + OUString aMessage(DBA_RES(STR_DATASOURCE_DELETED)); + OSQLWarningBox aBox(getFrameWeld(), aMessage); + aBox.run(); + return false; + } + + Reference< XNameAccess > xElements = getObjectContainer(); + if ( !xElements.is() ) + return false; + + if ( !getContainer()->checkStatement() ) + return false; + + OUString sTranslatedStmt = translateStatement(); + if ( editingCommand() ) + { + setModified( false ); + // this is all we need to do here. translateStatement implicitly set our m_sStatement, and + // notified it, and that's all + return true; + } + + if ( sTranslatedStmt.isEmpty() ) + return false; + + // first we need a name for our query so ask the user + // did we get a name + OUString sOriginalName( m_sName ); + if ( !askForNewName( xElements, _bSaveAs ) || m_sName.isEmpty() ) + return false; + + SQLExceptionInfo aInfo; + bool bSuccess = false; + bool bNew = false; + try + { + bNew = _bSaveAs + || ( !xElements->hasByName( m_sName ) ); + + Reference<XPropertySet> xQuery; + if ( bNew ) // just to make sure the query already exists + { + // drop the query, in case it already exists + if ( xElements->hasByName( m_sName ) ) + { + Reference< XDrop > xNameCont( xElements, UNO_QUERY ); + if ( xNameCont.is() ) + xNameCont->dropByName( m_sName ); + else + { + Reference< XNameContainer > xCont( xElements, UNO_QUERY ); + if ( xCont.is() ) + xCont->removeByName( m_sName ); + } + } + + // create a new (empty, uninitialized) query resp. view + Reference< XDataDescriptorFactory > xFact( xElements, UNO_QUERY ); + if ( xFact.is() ) + { + xQuery = xFact->createDataDescriptor(); + // to set the name is only allowed when the query is new + xQuery->setPropertyValue( PROPERTY_NAME, Any( m_sName ) ); + } + else + { + Reference< XSingleServiceFactory > xSingleFac( xElements, UNO_QUERY ); + if ( xSingleFac.is() ) + xQuery.set(xSingleFac->createInstance(), css::uno::UNO_QUERY); + } + } + else + { + xElements->getByName( m_sName ) >>= xQuery; + } + if ( !xQuery.is() ) + throw RuntimeException(); + + // the new commands + if ( editingView() && !bNew ) + { + OSL_ENSURE( xQuery == m_xAlterView, "OQueryController::doSaveAsDoc: already have another alterable view ...!?" ); + m_xAlterView.set( xQuery, UNO_QUERY_THROW ); + m_xAlterView->alterCommand( sTranslatedStmt ); + } + else + { // we're creating a query, or a *new* view + xQuery->setPropertyValue( PROPERTY_COMMAND, Any( sTranslatedStmt ) ); + + if ( editingView() ) + { + xQuery->setPropertyValue( PROPERTY_CATALOGNAME, Any( m_sUpdateCatalogName ) ); + xQuery->setPropertyValue( PROPERTY_SCHEMANAME, Any( m_sUpdateSchemaName ) ); + } + + if ( editingQuery() ) + { + xQuery->setPropertyValue( PROPERTY_UPDATE_TABLENAME, Any( OUString() ) ); + xQuery->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, css::uno::Any( m_bEscapeProcessing ) ); + + xQuery->setPropertyValue( PROPERTY_LAYOUTINFORMATION, getViewData() ); + } + } + + if ( bNew ) + { + Reference< XAppend > xAppend( xElements, UNO_QUERY ); + if ( xAppend.is() ) + { + xAppend->appendByDescriptor( xQuery ); + } + else + { + Reference< XNameContainer > xCont( xElements, UNO_QUERY ); + if ( xCont.is() ) + xCont->insertByName( m_sName, Any( xQuery ) ); + } + + if ( editingView() ) + { + Reference< XPropertySet > xViewProps; + if ( xElements->hasByName( m_sName ) ) + xViewProps.set( xElements->getByName( m_sName ), UNO_QUERY ); + + if ( !xViewProps.is() ) // correct name and try again + m_sName = ::dbtools::composeTableName( getMetaData(), xQuery, ::dbtools::EComposeRule::InDataManipulation, false ); + + OSL_ENSURE( xElements->hasByName( m_sName ), "OQueryController::doSaveAsDoc: newly created view does not exist!" ); + + if ( xElements->hasByName( m_sName ) ) + m_xAlterView.set( xElements->getByName( m_sName ), UNO_QUERY ); + + // now check if our datasource has set a tablefilter and if so, append the new table name to it + ::dbaui::appendToFilter(getConnection(), m_sName, getORB(), getFrameWeld()); + } + Reference< XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY); + if ( xEventListener.is() ) + { + TitleChangedEvent aEvent; + xEventListener->titleChanged(aEvent); + } + releaseNumberForComponent(); + } + + setModified( false ); + bSuccess = true; + + } + catch(const SQLException&) + { + if ( !bNew ) + m_sName = sOriginalName; + aInfo = SQLExceptionInfo( ::cppu::getCaughtException() ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + if ( !bNew ) + m_sName = sOriginalName; + } + + showError( aInfo ); + + // if we successfully saved a view we were creating, then close the designer + if ( bSuccess && editingView() && !m_xAlterView.is() ) + { + closeTask(); + } + + if ( bSuccess && editingView() ) + InvalidateFeature( ID_BROWSER_EDITDOC ); + + return bSuccess; +} + +namespace { +struct CommentStrip +{ + OUString maComment; + bool mbLastOnLine; + CommentStrip( const OUString& rComment, bool bLastOnLine ) + : maComment( rComment), mbLastOnLine( bLastOnLine) {} +}; + +} + +/** Obtain all comments in a query. + + See also delComment() implementation for OSQLParser::parseTree(). + */ +static std::vector< CommentStrip > getComment( const OUString& rQuery ) +{ + std::vector< CommentStrip > aRet; + // First a quick search if there is any "--" or "//" or "/*", if not then + // the whole copying loop is pointless. + if (rQuery.indexOf( "--" ) < 0 && rQuery.indexOf( "//" ) < 0 && + rQuery.indexOf( "/*" ) < 0) + return aRet; + + const sal_Unicode* pCopy = rQuery.getStr(); + const sal_Int32 nQueryLen = rQuery.getLength(); + bool bIsText1 = false; // "text" + bool bIsText2 = false; // 'text' + bool bComment2 = false; // /* comment */ + bool bComment = false; // -- or // comment + OUStringBuffer aBuf; + for (sal_Int32 i=0; i < nQueryLen; ++i) + { + if (bComment2) + { + aBuf.append( &pCopy[i], 1); + if ((i+1) < nQueryLen) + { + if (pCopy[i]=='*' && pCopy[i+1]=='/') + { + bComment2 = false; + aBuf.append( &pCopy[++i], 1); + aRet.emplace_back( aBuf.makeStringAndClear(), false); + } + } + else + { + // comment can't close anymore, actually an error, but... + aRet.emplace_back( aBuf.makeStringAndClear(), false); + } + continue; + } + if (pCopy[i] == '\n' || i == nQueryLen-1) + { + if (bComment) + { + if (i == nQueryLen-1 && pCopy[i] != '\n') + aBuf.append( &pCopy[i], 1); + aRet.emplace_back( aBuf.makeStringAndClear(), true); + bComment = false; + } + else if (!aRet.empty()) + aRet.back().mbLastOnLine = true; + } + else if (!bComment) + { + if (pCopy[i] == '\"' && !bIsText2) + bIsText1 = !bIsText1; + else if (pCopy[i] == '\'' && !bIsText1) + bIsText2 = !bIsText2; + if (!bIsText1 && !bIsText2 && (i+1) < nQueryLen) + { + if ((pCopy[i]=='-' && pCopy[i+1]=='-') || (pCopy[i]=='/' && pCopy[i+1]=='/')) + bComment = true; + else if (pCopy[i]=='/' && pCopy[i+1]=='*') + bComment2 = true; + } + } + if (bComment || bComment2) + aBuf.append( &pCopy[i], 1); + } + return aRet; +} + +/** Concat/insert comments that were previously obtained with getComment(). + + NOTE: The current parser implementation does not preserve newlines, so all + comments are always appended to the entire query, also inline comments + that would need positioning anyway that can't be obtained after + recomposition. This is ugly but at least allows commented queries while + preserving the comments _somehow_. + */ +static OUString concatComment( const OUString& rQuery, const std::vector< CommentStrip >& rComments ) +{ + // No comments => return query. + if (rComments.empty()) + return rQuery; + + const sal_Unicode* pBeg = rQuery.getStr(); + const sal_Int32 nLen = rQuery.getLength(); + const size_t nComments = rComments.size(); + // Obtaining the needed size once should be faster than reallocating. + // Also add a blank or linefeed for each comment. + sal_Int32 nBufSize = nLen + nComments; + for (auto const& comment : rComments) + nBufSize += comment.maComment.getLength(); + OUStringBuffer aBuf( nBufSize ); + sal_Int32 nIndBeg = 0; + sal_Int32 nIndLF = rQuery.indexOf('\n'); + size_t i = 0; + while (nIndLF >= 0 && i < nComments) + { + aBuf.append( pBeg + nIndBeg, nIndLF - nIndBeg); + do + { + aBuf.append( rComments[i].maComment); + } while (!rComments[i++].mbLastOnLine && i < nComments); + aBuf.append( pBeg + nIndLF, 1); // the LF + nIndBeg = nIndLF + 1; + nIndLF = (nIndBeg < nLen ? rQuery.indexOf( '\n', nIndBeg) : -1); + } + // Append remainder of query. + if (nIndBeg < nLen) + aBuf.append( pBeg + nIndBeg, nLen - nIndBeg); + // Append all remaining comments, preserve lines. + bool bNewLine = false; + for ( ; i < nComments; ++i) + { + if (!bNewLine) + aBuf.append( ' '); + aBuf.append( rComments[i].maComment); + if (rComments[i].mbLastOnLine) + { + aBuf.append( '\n'); + bNewLine = true; + } + else + bNewLine = false; + } + return aBuf.makeStringAndClear(); +} + +OUString OQueryController::translateStatement( bool _bFireStatementChange ) +{ + // now set the properties + setStatement_fireEvent( getContainer()->getStatement(), _bFireStatementChange ); + OUString sTranslatedStmt; + if(!m_sStatement.isEmpty() && m_xComposer.is() && m_bEscapeProcessing) + { + try + { + OUString aErrorMsg; + + std::vector< CommentStrip > aComments = getComment( m_sStatement); + + std::unique_ptr<::connectivity::OSQLParseNode> pNode = m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign ); + if(pNode) + { + pNode->parseNodeToStr( sTranslatedStmt, getConnection() ); + } + + m_xComposer->setQuery(sTranslatedStmt); + sTranslatedStmt = m_xComposer->getComposedQuery(); + sTranslatedStmt = concatComment( sTranslatedStmt, aComments); + } + catch(const SQLException& e) + { + ::dbtools::SQLExceptionInfo aInfo(e); + showError(aInfo); + // an error occurred so we clear the statement + sTranslatedStmt.clear(); + } + } + else if(m_sStatement.isEmpty()) + { + showError(SQLException(DBA_RES(STR_QRY_NOSELECT), nullptr, "S1000", 1000, Any())); + } + else + sTranslatedStmt = m_sStatement; + + return sTranslatedStmt; +} + +short OQueryController::saveModified() +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + short nRet = RET_YES; + if ( !isConnected() || !isModified() ) + return nRet; + + if ( !m_bGraphicalDesign + || ( !m_vTableFieldDesc.empty() + && !m_vTableData.empty() + ) + ) + { + OUString sMessageText( lcl_getObjectResourceString( STR_QUERY_SAVEMODIFIED, m_nCommandType ) ); + + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(getFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + sMessageText)); + xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL); + xQueryBox->set_default_response(RET_YES); + + nRet = xQueryBox->run(); + if ( ( nRet == RET_YES ) + && !doSaveAsDoc( false ) + ) + { + nRet = RET_CANCEL; + } + } + return nRet; +} + +void OQueryController::impl_reset( const bool i_bForceCurrentControllerSettings ) +{ + bool bValid = false; + + Sequence< PropertyValue > aLayoutInformation; + // get command from the query if a query name was supplied + if ( !i_bForceCurrentControllerSettings && !editingCommand() ) + { + if ( !m_sName.isEmpty() ) + { + Reference< XNameAccess > xQueries = getObjectContainer(); + if ( xQueries.is() ) + { + Reference< XPropertySet > xProp; + if( xQueries->hasByName( m_sName ) && ( xQueries->getByName( m_sName ) >>= xProp ) && xProp.is() ) + { + OUString sNewStatement; + xProp->getPropertyValue( PROPERTY_COMMAND ) >>= sNewStatement; + setStatement_fireEvent( sNewStatement ); + + if ( editingQuery() ) + { + bool bNewEscapeProcessing( true ); + xProp->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bNewEscapeProcessing; + setEscapeProcessing_fireEvent( bNewEscapeProcessing ); + } + + m_bGraphicalDesign = m_bGraphicalDesign && m_bEscapeProcessing; + bValid = true; + + try + { + if ( editingQuery() ) + xProp->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) >>= aLayoutInformation; + } + catch( const Exception& ) + { + OSL_FAIL( "OQueryController::impl_reset: could not retrieve the layout information from the query!" ); + } + } + } + } + } + else + { + bValid = true; + // assume that we got all necessary information during initialization + } + + if ( bValid ) + { + // load the layoutInformation + if ( aLayoutInformation.hasElements() ) + { + try + { + loadViewSettings( aLayoutInformation ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + if ( !m_sStatement.isEmpty() ) + { + setQueryComposer(); + + bool bError( false ); + + if ( !m_pSqlIterator ) + { + bError = true; + } + else if ( m_bEscapeProcessing ) + { + OUString aErrorMsg; + std::unique_ptr< ::connectivity::OSQLParseNode > pNode( + m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign ) ); + + if (pNode) + { + delete m_pSqlIterator->getParseTree(); + m_pSqlIterator->setParseTree( pNode.release() ); + m_pSqlIterator->traverseAll(); + if ( m_pSqlIterator->hasErrors() ) + { + if ( !i_bForceCurrentControllerSettings && m_bGraphicalDesign && !editingView() ) + { + impl_showAutoSQLViewError( Any( m_pSqlIterator->getErrors() ) ); + } + bError = true; + } + } + else + { + if ( !i_bForceCurrentControllerSettings && !editingView() ) + { + OUString aTitle(DBA_RES(STR_SVT_SQL_SYNTAX_ERROR)); + OSQLMessageBox aDlg(getFrameWeld(), aTitle, aErrorMsg); + aDlg.run(); + } + bError = true; + } + } + + if ( bError ) + { + m_bGraphicalDesign = false; + if ( editingView() ) + // if we're editing a view whose statement could not be parsed, default to "no escape processing" + setEscapeProcessing_fireEvent( false ); + } + } + } + + if(!m_pSqlIterator) + setQueryComposer(); + OSL_ENSURE(m_pSqlIterator,"No SQLIterator set!"); + + getContainer()->setNoneVisibleRow(m_nVisibleRows); +} + +void OQueryController::reset() +{ + impl_reset(); + getContainer()->reset(); + ClearUndoManager(); +} + +void OQueryController::setStatement_fireEvent( const OUString& _rNewStatement, bool _bFireStatementChange ) +{ + Any aOldValue( m_sStatement ); + m_sStatement = _rNewStatement; + Any aNewValue( m_sStatement ); + + sal_Int32 nHandle = PROPERTY_ID_ACTIVECOMMAND; + if ( _bFireStatementChange ) + fire( &nHandle, &aNewValue, &aOldValue, 1, false ); +} + +void OQueryController::setEscapeProcessing_fireEvent( const bool _bEscapeProcessing ) +{ + if ( _bEscapeProcessing == m_bEscapeProcessing ) + return; + + Any aOldValue( m_bEscapeProcessing ); + m_bEscapeProcessing = _bEscapeProcessing; + Any aNewValue( m_bEscapeProcessing ); + + sal_Int32 nHandle = PROPERTY_ID_ESCAPE_PROCESSING; + fire( &nHandle, &aNewValue, &aOldValue, 1, false ); +} + +IMPL_LINK_NOARG( OQueryController, OnExecuteAddTable, void*, void ) +{ + Execute( ID_BROWSER_ADDTABLE,Sequence<PropertyValue>() ); +} + +bool OQueryController::allowViews() const +{ + return true; +} + +bool OQueryController::allowQueries() const +{ + OSL_ENSURE( getSdbMetaData().isConnected(), "OQueryController::allowQueries: illegal call!" ); + if ( !getSdbMetaData().supportsSubqueriesInFrom() ) + return false; + + const NamedValueCollection& rArguments( getInitParams() ); + sal_Int32 nCommandType = rArguments.getOrDefault( PROPERTY_COMMAND_TYPE, sal_Int32(CommandType::QUERY) ); + bool bCreatingView = ( nCommandType == CommandType::TABLE ); + return !bCreatingView; +} + +Any SAL_CALL OQueryController::getViewData() +{ + ::osl::MutexGuard aGuard( getMutex() ); + + getContainer()->SaveUIConfig(); + + ::comphelper::NamedValueCollection aViewSettings; + saveViewSettings( aViewSettings, false ); + + return Any( aViewSettings.getPropertyValues() ); +} + +void SAL_CALL OQueryController::restoreViewData(const Any& /*Data*/) +{ + // TODO +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/querydlg.cxx b/dbaccess/source/ui/querydesign/querydlg.cxx new file mode 100644 index 000000000..5a21998d9 --- /dev/null +++ b/dbaccess/source/ui/querydesign/querydlg.cxx @@ -0,0 +1,313 @@ +/* -*- 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 "querydlg.hxx" +#include <JoinController.hxx> +#include <JoinDesignView.hxx> +#include <strings.hrc> +#include <tools/diagnose_ex.h> +#include "QTableConnectionData.hxx" +#include <core_resource.hxx> +#include <QueryTableView.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <RelationControl.hxx> + +#define ID_INNER_JOIN 1 +#define ID_LEFT_JOIN 2 +#define ID_RIGHT_JOIN 3 +#define ID_FULL_JOIN 4 +#define ID_CROSS_JOIN 5 + +using namespace dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbc; + +DlgQryJoin::DlgQryJoin(const OQueryTableView* pParent, + const TTableConnectionData::value_type& _pData, + const OJoinTableView::OTableWindowMap* _pTableMap, + const Reference< XConnection >& _xConnection, + bool _bAllowTableSelect) + : GenericDialogController(pParent->GetFrameWeld(), "dbaccess/ui/joindialog.ui", "JoinDialog") + , eJoinType(static_cast<OQueryTableConnectionData*>(_pData.get())->GetJoinType()) + , m_pOrigConnData(_pData) + , m_xConnection(_xConnection) + , m_xML_HelpText(m_xBuilder->weld_label("helptext")) + , m_xPB_OK(m_xBuilder->weld_button("ok")) + , m_xLB_JoinType(m_xBuilder->weld_combo_box("type")) + , m_xCBNatural(m_xBuilder->weld_check_button("natural")) +{ + Size aSize(m_xML_HelpText->get_approximate_digit_width() * 44, + m_xML_HelpText->get_text_height() * 6); + //alternatively loop through the STR_QUERY_* strings with their STR_JOIN_TYPE_HINT + //suffix to find the longest entry at runtime + m_xML_HelpText->set_size_request(aSize.Width(), aSize.Height()); + + // Copy connection + m_pConnData = _pData->NewInstance(); + m_pConnData->CopyFrom(*_pData); + + m_xTableControl.reset(new OTableListBoxControl(m_xBuilder.get(), _pTableMap, this)); + + m_xCBNatural->set_active(static_cast<OQueryTableConnectionData*>(m_pConnData.get())->isNatural()); + + if( _bAllowTableSelect ) + { + m_xTableControl->Init( m_pConnData ); + m_xTableControl->fillListBoxes(); + } + else + { + m_xTableControl->fillAndDisable(m_pConnData); + m_xTableControl->Init( m_pConnData ); + } + + m_xTableControl->lateUIInit(); + + bool bSupportFullJoin = false; + Reference<XDatabaseMetaData> xMeta; + try + { + xMeta = m_xConnection->getMetaData(); + if ( xMeta.is() ) + bSupportFullJoin = xMeta->supportsFullOuterJoins(); + } + catch(SQLException&) + { + } + bool bSupportOuterJoin = false; + try + { + if ( xMeta.is() ) + bSupportOuterJoin= xMeta->supportsOuterJoins(); + } + catch(SQLException&) + { + } + + setJoinType(eJoinType); + + m_xPB_OK->connect_clicked(LINK(this, DlgQryJoin, OKClickHdl)); + + m_xLB_JoinType->connect_changed(LINK(this,DlgQryJoin,LBChangeHdl)); + m_xCBNatural->connect_toggled(LINK(this,DlgQryJoin,NaturalToggleHdl)); + + if ( pParent->getDesignView()->getController().isReadOnly() ) + { + m_xLB_JoinType->set_sensitive(false); + m_xCBNatural->set_sensitive(false); + m_xTableControl->Disable(); + } + else + { + for (sal_Int32 i = 0; i < m_xLB_JoinType->get_count();) + { + const sal_Int32 nJoinTyp = m_xLB_JoinType->get_id(i).toInt32(); + if ( !bSupportFullJoin && nJoinTyp == ID_FULL_JOIN ) + m_xLB_JoinType->remove(i); + else if ( !bSupportOuterJoin && (nJoinTyp == ID_LEFT_JOIN || nJoinTyp == ID_RIGHT_JOIN) ) + m_xLB_JoinType->remove(i); + else + ++i; + } + + m_xTableControl->NotifyCellChange(); + m_xTableControl->enableRelation(!static_cast<OQueryTableConnectionData*>(m_pConnData.get())->isNatural() && eJoinType != CROSS_JOIN ); + } +} + +DlgQryJoin::~DlgQryJoin() +{ +} + +IMPL_LINK_NOARG( DlgQryJoin, LBChangeHdl, weld::ComboBox&, void ) +{ + if (!m_xLB_JoinType->get_value_changed_from_saved()) + return; + + m_xLB_JoinType->save_value(); + m_xML_HelpText->set_label(OUString()); + + m_xTableControl->enableRelation(true); + + OUString sFirstWinName = m_pConnData->getReferencingTable()->GetWinName(); + OUString sSecondWinName = m_pConnData->getReferencedTable()->GetWinName(); + const EJoinType eOldJoinType = eJoinType; + TranslateId pResId; + const sal_Int32 nPos = m_xLB_JoinType->get_active(); + const sal_Int32 nJoinType = m_xLB_JoinType->get_id(nPos).toInt32(); + bool bAddHint = true; + switch ( nJoinType ) + { + default: + case ID_INNER_JOIN: + pResId = STR_QUERY_INNER_JOIN; + bAddHint = false; + eJoinType = INNER_JOIN; + break; + case ID_LEFT_JOIN: + pResId = STR_QUERY_LEFTRIGHT_JOIN; + eJoinType = LEFT_JOIN; + break; + case ID_RIGHT_JOIN: + { + pResId = STR_QUERY_LEFTRIGHT_JOIN; + eJoinType = RIGHT_JOIN; + OUString sTemp = sFirstWinName; + sFirstWinName = sSecondWinName; + sSecondWinName = sTemp; + } + break; + case ID_FULL_JOIN: + pResId = STR_QUERY_FULL_JOIN; + eJoinType = FULL_JOIN; + break; + case ID_CROSS_JOIN: + { + pResId = STR_QUERY_CROSS_JOIN; + eJoinType = CROSS_JOIN; + + m_pConnData->ResetConnLines(); + m_xTableControl->lateInit(); + m_xCBNatural->set_active(false); + m_xTableControl->enableRelation(false); + m_pConnData->AppendConnLine("",""); + m_xPB_OK->set_sensitive(true); + } + break; + } + + m_xCBNatural->set_sensitive(eJoinType != CROSS_JOIN); + + if ( eJoinType != eOldJoinType && eOldJoinType == CROSS_JOIN ) + { + m_pConnData->ResetConnLines(); + } + if ( eJoinType != CROSS_JOIN ) + { + m_xTableControl->NotifyCellChange(); + NaturalToggleHdl(*m_xCBNatural); + } + + m_xTableControl->Invalidate(); + + OUString sHelpText = DBA_RES(pResId); + if( nPos ) + { + sHelpText = sHelpText.replaceFirst( "%1", sFirstWinName ); + sHelpText = sHelpText.replaceFirst( "%2", sSecondWinName ); + } + if ( bAddHint ) + { + sHelpText += "\n" + DBA_RES( STR_JOIN_TYPE_HINT ); + } + + m_xML_HelpText->set_label( sHelpText ); +} + +IMPL_LINK_NOARG(DlgQryJoin, OKClickHdl, weld::Button&, void) +{ + m_pConnData->Update(); + m_pOrigConnData->CopyFrom( *m_pConnData ); + + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(DlgQryJoin, NaturalToggleHdl, weld::Toggleable&, void) +{ + bool bChecked = m_xCBNatural->get_active(); + static_cast<OQueryTableConnectionData*>(m_pConnData.get())->setNatural(bChecked); + m_xTableControl->enableRelation(!bChecked); + if ( !bChecked ) + return; + + m_pConnData->ResetConnLines(); + try + { + Reference<XNameAccess> xReferencedTableColumns(m_pConnData->getReferencedTable()->getColumns()); + Sequence< OUString> aSeq = m_pConnData->getReferencingTable()->getColumns()->getElementNames(); + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + for(;pIter != pEnd;++pIter) + { + if ( xReferencedTableColumns->hasByName(*pIter) ) + m_pConnData->AppendConnLine(*pIter,*pIter); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + m_xTableControl->NotifyCellChange(); + m_xTableControl->Invalidate(); +} + +void DlgQryJoin::setValid(bool _bValid) +{ + m_xPB_OK->set_sensitive(_bValid || eJoinType == CROSS_JOIN ); +} + +void DlgQryJoin::notifyConnectionChange( ) +{ + setJoinType( static_cast<OQueryTableConnectionData*>(m_pConnData.get())->GetJoinType() ); + m_xCBNatural->set_active(static_cast<OQueryTableConnectionData*>(m_pConnData.get())->isNatural()); + NaturalToggleHdl(*m_xCBNatural); +} + +void DlgQryJoin::setJoinType(EJoinType _eNewJoinType) +{ + eJoinType = _eNewJoinType; + m_xCBNatural->set_sensitive(eJoinType != CROSS_JOIN); + + sal_Int32 nJoinType = 0; + switch ( eJoinType ) + { + default: + case INNER_JOIN: + nJoinType = ID_INNER_JOIN; + break; + case LEFT_JOIN: + nJoinType = ID_LEFT_JOIN; + break; + case RIGHT_JOIN: + nJoinType = ID_RIGHT_JOIN; + break; + case FULL_JOIN: + nJoinType = ID_FULL_JOIN; + break; + case CROSS_JOIN: + nJoinType = ID_CROSS_JOIN; + break; + } + + const sal_Int32 nCount = m_xLB_JoinType->get_count(); + for (sal_Int32 i = 0; i < nCount; ++i) + { + if (nJoinType == m_xLB_JoinType->get_id(i).toInt32()) + { + m_xLB_JoinType->set_active(i); + break; + } + } + + LBChangeHdl(*m_xLB_JoinType); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/querydlg.hxx b/dbaccess/source/ui/querydesign/querydlg.hxx new file mode 100644 index 000000000..3da416c6e --- /dev/null +++ b/dbaccess/source/ui/querydesign/querydlg.hxx @@ -0,0 +1,77 @@ +/* -*- 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 <vcl/weld.hxx> + +#include <QEnumTypes.hxx> + +#include <RelControliFace.hxx> +#include <JoinTableView.hxx> + + +namespace dbaui +{ + class OTableListBoxControl; + class OQueryTableView; + class DlgQryJoin final : public weld::GenericDialogController + , public IRelationControlInterface + { + EJoinType eJoinType; + TTableConnectionData::value_type m_pConnData; // contains left and right table + TTableConnectionData::value_type m_pOrigConnData; + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + + std::unique_ptr<weld::Label> m_xML_HelpText; + std::unique_ptr<weld::Button> m_xPB_OK; + std::unique_ptr<weld::ComboBox> m_xLB_JoinType; + std::unique_ptr<weld::CheckButton> m_xCBNatural; + std::unique_ptr<OTableListBoxControl> m_xTableControl; + + DECL_LINK(OKClickHdl, weld::Button&, void); + DECL_LINK(LBChangeHdl, weld::ComboBox&, void); + DECL_LINK(NaturalToggleHdl, weld::Toggleable&, void); + + /** setJoinType enables and set the new join type + @param _eNewJoinType the new jointype + */ + void setJoinType(EJoinType _eNewJoinType); + public: + DlgQryJoin( const OQueryTableView * pParent, + const TTableConnectionData::value_type& pData, + const OJoinTableView::OTableWindowMap* _pTableMap, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + bool _bAllowTableSelect); + virtual ~DlgQryJoin() override; + EJoinType GetJoinType() const { return eJoinType; }; + + /** setValid set the valid inside, can be used for OK buttons + @param _bValid true when the using control allows an update + */ + virtual void setValid(bool _bValid) override; + + /** notifyConnectionChange is callback which is called when the table selection has changed and a new connection exists + @param _pConnectionData the connection which exists between the new tables + */ + virtual void notifyConnectionChange() override; + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/relationdesign/RTableConnection.cxx b/dbaccess/source/ui/relationdesign/RTableConnection.cxx new file mode 100644 index 000000000..ba60ae546 --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RTableConnection.cxx @@ -0,0 +1,117 @@ +/* -*- 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 "RTableConnection.hxx" +#include <RTableConnectionData.hxx> +#include <RelationTableView.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <ConnectionLine.hxx> + +using namespace dbaui; +ORelationTableConnection::ORelationTableConnection( ORelationTableView* pContainer, + const TTableConnectionData::value_type& pTabConnData ) + :OTableConnection( pContainer, pTabConnData ) +{ +} + +ORelationTableConnection::ORelationTableConnection( const ORelationTableConnection& rConn ) + : VclReferenceBase(), OTableConnection( rConn ) +{ + // no own members, thus the base class functionality is enough +} + +ORelationTableConnection& ORelationTableConnection::operator=( const ORelationTableConnection& rConn ) +{ + // this doesn't change anything, since the base class tests this, too and I don't have my own members to copy + if (&rConn == this) + return *this; + + OTableConnection::operator=( rConn ); + return *this; +} + +void ORelationTableConnection::Draw(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) +{ + OTableConnection::Draw(rRenderContext, rRect); + ORelationTableConnectionData* pData = static_cast< ORelationTableConnectionData* >(GetData().get()); + if (pData && (pData->GetCardinality() == Cardinality::Undefined)) + return; + + // search lines for top line + tools::Rectangle aBoundingRect; + tools::Long nTop = GetBoundingRect().Bottom(); + tools::Long nTemp; + + const OConnectionLine* pTopLine = nullptr; + const std::vector<std::unique_ptr<OConnectionLine>>& rConnLineList = GetConnLineList(); + + for (auto const& elem : rConnLineList) + { + if( elem->IsValid() ) + { + aBoundingRect = elem->GetBoundingRect(); + nTemp = aBoundingRect.Top(); + if(nTemp < nTop) + { + nTop = nTemp; + pTopLine = elem.get(); + } + } + } + + // cardinality + if (!pTopLine) + return; + + tools::Rectangle aSourcePos = pTopLine->GetSourceTextPos(); + tools::Rectangle aDestPos = pTopLine->GetDestTextPos(); + + OUString aSourceText; + OUString aDestText; + + switch (pData->GetCardinality()) + { + case Cardinality::OneMany: + aSourceText = "1"; + aDestText = "n"; + break; + + case Cardinality::ManyOne: + aSourceText = "n"; + aDestText = "1"; + break; + + case Cardinality::OneOne: + aSourceText = "1"; + aDestText = "1"; + break; + default: break; + } + + if (IsSelected()) + rRenderContext.SetTextColor(Application::GetSettings().GetStyleSettings().GetHighlightColor()); + else + rRenderContext.SetTextColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor()); + + rRenderContext.DrawText(aSourcePos, aSourceText, DrawTextFlags::Clip | DrawTextFlags::Center | DrawTextFlags::Bottom); + rRenderContext.DrawText(aDestPos, aDestText, DrawTextFlags::Clip | DrawTextFlags::Center | DrawTextFlags::Bottom); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/relationdesign/RTableConnection.hxx b/dbaccess/source/ui/relationdesign/RTableConnection.hxx new file mode 100644 index 000000000..0448d494f --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RTableConnection.hxx @@ -0,0 +1,40 @@ +/* -*- 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 <TableConnection.hxx> + +namespace dbaui +{ + class ORelationTableView; + class ORelationTableConnection : public OTableConnection + { + public: + ORelationTableConnection( ORelationTableView* pContainer, const TTableConnectionData::value_type& pTabConnData ); + ORelationTableConnection( const ORelationTableConnection& rConn ); + // important comment to the CopyConstructor see OTableConnection(const OTableConnection&) + + ORelationTableConnection& operator=( const ORelationTableConnection& rConn ); + + virtual void Draw(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + using OTableConnection::Draw; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/relationdesign/RTableConnectionData.cxx b/dbaccess/source/ui/relationdesign/RTableConnectionData.cxx new file mode 100644 index 000000000..26b39b69c --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RTableConnectionData.cxx @@ -0,0 +1,398 @@ +/* -*- 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 <RTableConnectionData.hxx> +#include <com/sun/star/sdbc/KeyRule.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbcx/XDrop.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <strings.hrc> +#include <strings.hxx> +#include <core_resource.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <osl/diagnose.h> + +using namespace dbaui; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +ORelationTableConnectionData::ORelationTableConnectionData() + :m_nUpdateRules(KeyRule::NO_ACTION) + ,m_nDeleteRules(KeyRule::NO_ACTION) + ,m_nCardinality(Cardinality::Undefined) +{ +} + +ORelationTableConnectionData::ORelationTableConnectionData( const TTableWindowData::value_type& _pReferencingTable, + const TTableWindowData::value_type& _pReferencedTable, + const OUString& rConnName ) + :OTableConnectionData( _pReferencingTable, _pReferencedTable ) + ,m_nUpdateRules(KeyRule::NO_ACTION) + ,m_nDeleteRules(KeyRule::NO_ACTION) + ,m_nCardinality(Cardinality::Undefined) +{ + m_aConnName = rConnName; + + if ( !m_aConnName.isEmpty() ) + SetCardinality(); +} + +ORelationTableConnectionData::ORelationTableConnectionData( const ORelationTableConnectionData& rConnData ) + :OTableConnectionData( rConnData ) +{ + *this = rConnData; +} + +ORelationTableConnectionData::~ORelationTableConnectionData() +{ +} + +void ORelationTableConnectionData::DropRelation() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + // delete relation + Reference< XIndexAccess> xKeys = getReferencingTable()->getKeys(); + if( m_aConnName.isEmpty() || !xKeys.is() ) + return; + + const sal_Int32 nCount = xKeys->getCount(); + for(sal_Int32 i = 0;i < nCount;++i) + { + Reference< XPropertySet> xKey(xKeys->getByIndex(i),UNO_QUERY); + OSL_ENSURE(xKey.is(),"Key is not valid!"); + if(xKey.is()) + { + OUString sName; + xKey->getPropertyValue(PROPERTY_NAME) >>= sName; + if(sName == m_aConnName) + { + Reference< XDrop> xDrop(xKeys,UNO_QUERY); + OSL_ENSURE(xDrop.is(),"can't drop key because we haven't a drop interface!"); + if(xDrop.is()) + xDrop->dropByIndex(i); + break; + } + } + } +} + +void ORelationTableConnectionData::ChangeOrientation() +{ + // exchange Source- and DestFieldName of the lines + OUString sTempString; + for (auto const& elem : m_vConnLineData) + { + sTempString = elem->GetSourceFieldName(); + elem->SetSourceFieldName( elem->GetDestFieldName() ); + elem->SetDestFieldName( sTempString ); + } + + // adapt member + TTableWindowData::value_type pTemp = m_pReferencingTable; + m_pReferencingTable = m_pReferencedTable; + m_pReferencedTable = pTemp; +} + +void ORelationTableConnectionData::SetCardinality() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + m_nCardinality = Cardinality::Undefined; + + if( IsSourcePrimKey() ) + { + if( IsDestPrimKey() ) + m_nCardinality = Cardinality::OneOne; + else + m_nCardinality = Cardinality::OneMany; + } + + if( IsDestPrimKey() ) + { + if( !IsSourcePrimKey() ) + m_nCardinality = Cardinality::ManyOne; + } + +} + +bool ORelationTableConnectionData::checkPrimaryKey(const Reference< XPropertySet>& i_xTable,EConnectionSide _eEConnectionSide) const +{ + // check if Table has the primary key column depending on _eEConnectionSide + sal_uInt16 nPrimKeysCount = 0, + nValidLinesCount = 0; + const Reference< XNameAccess> xKeyColumns = dbtools::getPrimaryKeyColumns_throw(i_xTable); + if ( xKeyColumns.is() ) + { + Sequence< OUString> aKeyColumns = xKeyColumns->getElementNames(); + const OUString* pKeyIter = aKeyColumns.getConstArray(); + const OUString* pKeyEnd = pKeyIter + aKeyColumns.getLength(); + + for(;pKeyIter != pKeyEnd;++pKeyIter) + { + for (auto const& elem : m_vConnLineData) + { + ++nValidLinesCount; + if ( elem->GetFieldName(_eEConnectionSide) == *pKeyIter ) + { + ++nPrimKeysCount; + break; + } + } + } + if ( nPrimKeysCount != aKeyColumns.getLength() ) + return false; + } + return nPrimKeysCount && nPrimKeysCount == nValidLinesCount; +} + +void ORelationTableConnectionData::IsConnectionPossible() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + // if the SourceFields are a PrimKey, it's only the orientation which is wrong + if ( IsSourcePrimKey() && !IsDestPrimKey() ) + ChangeOrientation(); +} + +void ORelationTableConnectionData::CopyFrom(const OTableConnectionData& rSource) +{ + // retract to the (non-virtual) operator= like in the base class + *this = *static_cast<const ORelationTableConnectionData*>(&rSource); +} + +ORelationTableConnectionData& ORelationTableConnectionData::operator=( const ORelationTableConnectionData& rConnData ) +{ + if (&rConnData == this) + return *this; + + OTableConnectionData::operator=( rConnData ); + m_nUpdateRules = rConnData.GetUpdateRules(); + m_nDeleteRules = rConnData.GetDeleteRules(); + m_nCardinality = rConnData.GetCardinality(); + + return *this; +} + +namespace dbaui +{ +bool operator==(const ORelationTableConnectionData& lhs, const ORelationTableConnectionData& rhs) +{ + bool bEqual = (lhs.m_nUpdateRules == rhs.m_nUpdateRules) + && (lhs.m_nDeleteRules == rhs.m_nDeleteRules) + && (lhs.m_nCardinality == rhs.m_nCardinality) + && (lhs.getReferencingTable() == rhs.getReferencingTable()) + && (lhs.getReferencedTable() == rhs.getReferencedTable()) + && (lhs.m_aConnName == rhs.m_aConnName) + && (lhs.m_vConnLineData.size() == rhs.m_vConnLineData.size()); + + if ( bEqual ) + { + sal_Int32 i = 0; + for (auto const& elem : lhs.m_vConnLineData) + { + if ( *(rhs.m_vConnLineData[i]) != *elem ) + { + bEqual = false; + break; + } + ++i; + } + } + return bEqual; +} + +} + +bool ORelationTableConnectionData::Update() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + // delete old relation + { + DropRelation(); + IsConnectionPossible(); + } + + // reassign the keys because the orientation could be changed + Reference<XPropertySet> xTableProp(getReferencingTable()->getTable()); + Reference< XIndexAccess> xKeys ( getReferencingTable()->getKeys()); + + if ( !xKeys.is() ) + return false; + // create new relation + Reference<XDataDescriptorFactory> xKeyFactory(xKeys,UNO_QUERY); + OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!"); + Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor(); + OSL_ENSURE(xKey.is(),"Key is null!"); + if ( xKey.is() && xTableProp.is() ) + { + // build a foreign key name + OUString sSourceName; + xTableProp->getPropertyValue(PROPERTY_NAME) >>= sSourceName; + OUString sKeyName = sSourceName + getReferencedTable()->GetTableName(); + + xKey->setPropertyValue(PROPERTY_NAME,Any(sKeyName)); + xKey->setPropertyValue(PROPERTY_TYPE,Any(KeyType::FOREIGN)); + xKey->setPropertyValue(PROPERTY_REFERENCEDTABLE,Any(getReferencedTable()->GetTableName())); + xKey->setPropertyValue(PROPERTY_UPDATERULE, Any(GetUpdateRules())); + xKey->setPropertyValue(PROPERTY_DELETERULE, Any(GetDeleteRules())); + } + + Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY); + if ( xColSup.is() ) + { + Reference<XNameAccess> xColumns = xColSup->getColumns(); + Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); + Reference<XAppend> xColumnAppend(xColumns,UNO_QUERY); + if ( xColumnFactory.is() ) + { + for (auto const& elem : m_vConnLineData) + { + if(!(elem->GetSourceFieldName().isEmpty() || elem->GetDestFieldName().isEmpty())) + { + Reference<XPropertySet> xColumn = xColumnFactory->createDataDescriptor(); + if ( xColumn.is() ) + { + xColumn->setPropertyValue(PROPERTY_NAME,Any(elem->GetSourceFieldName())); + xColumn->setPropertyValue(PROPERTY_RELATEDCOLUMN,Any(elem->GetDestFieldName())); + xColumnAppend->appendByDescriptor(xColumn); + } + } + } + + if ( xColumns->hasElements() ) + xAppend->appendByDescriptor(xKey); + } + // to get the key we have to reget it because after append it is no longer valid + } + + // get the name of foreign key; search for columns + m_aConnName.clear(); + xKey.clear(); + bool bDropRelation = false; + for(sal_Int32 i=0;i<xKeys->getCount();++i) + { + xKeys->getByIndex(i) >>= xKey; + OSL_ENSURE(xKey.is(),"Key is not valid!"); + if ( xKey.is() ) + { + OUString sReferencedTable; + xKey->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= sReferencedTable; + if ( sReferencedTable == getReferencedTable()->GetTableName() ) + { + xColSup.set(xKey,UNO_QUERY_THROW); + try + { + Reference<XNameAccess> xColumns = xColSup->getColumns(); + Sequence< OUString> aNames = xColumns->getElementNames(); + const OUString* pIter = aNames.getConstArray(); + const OUString* pEnd = pIter + aNames.getLength(); + + Reference<XPropertySet> xColumn; + OUString sName,sRelatedColumn; + for ( ; pIter != pEnd ; ++pIter ) + { + xColumn.set(xColumns->getByName(*pIter),UNO_QUERY_THROW); + xColumn->getPropertyValue(PROPERTY_NAME) >>= sName; + xColumn->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedColumn; + + bool bFoundElem = false; + for (auto const& elem : m_vConnLineData) + { + if( elem->GetSourceFieldName() == sName + && elem->GetDestFieldName() == sRelatedColumn ) + { + bFoundElem = true; + break; + } + } + if (!bFoundElem) + break; + } + if ( pIter == pEnd ) + { + xKey->getPropertyValue(PROPERTY_NAME) >>= sName; + m_aConnName = sName; + bDropRelation = !aNames.hasElements(); // the key contains no column, so it isn't valid and we have to drop it + //here we already know our column structure so we don't have to recreate the table connection data + xColSup.clear(); + break; + } + } + catch(Exception&) + { + } + } + } + xKey.clear(); + } + if ( bDropRelation ) + { + DropRelation(); + OUString sError(DBA_RES(STR_QUERY_REL_COULD_NOT_CREATE)); + ::dbtools::throwGenericSQLException(sError,nullptr); + } + + // The fields the relation marks may not be the same as our LineDatas mark after the relation has been updated + if ( xColSup.is() ) + { + OConnectionLineDataVec().swap(m_vConnLineData); + Reference<XNameAccess> xColumns = xColSup->getColumns(); + Sequence< OUString> aNames = xColumns->getElementNames(); + const OUString* pIter = aNames.getConstArray(); + const OUString* pEnd = pIter + aNames.getLength(); + + m_vConnLineData.reserve( aNames.getLength() ); + Reference<XPropertySet> xColumn; + OUString sName,sRelatedColumn; + + for(;pIter != pEnd;++pIter) + { + xColumns->getByName(*pIter) >>= xColumn; + if ( xColumn.is() ) + { + OConnectionLineDataRef pNewData = new OConnectionLineData(); + + xColumn->getPropertyValue(PROPERTY_NAME) >>= sName; + xColumn->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedColumn; + + pNewData->SetSourceFieldName(sName); + pNewData->SetDestFieldName(sRelatedColumn); + m_vConnLineData.push_back(pNewData); + } + } + } + // NOTE : the caller is responsible for updating any other objects referencing the old LineDatas (for instance a ConnLine) + + // determine cardinality + SetCardinality(); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/relationdesign/RTableWindow.hxx b/dbaccess/source/ui/relationdesign/RTableWindow.hxx new file mode 100644 index 000000000..25b8d05a1 --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RTableWindow.hxx @@ -0,0 +1,40 @@ +/* -*- 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 <TableWindow.hxx> + +namespace dbaui +{ + class ORelationTableWindow : public OTableWindow + { + public: + ORelationTableWindow( vcl::Window* pParent,const TTableWindowData::value_type& pTabWinData) + : OTableWindow(pParent, pTabWinData) {} + + /** returns the name which should be used when displaying join or relations + @return + The composed name or the window name. + */ + virtual OUString GetName() const override { return GetComposedName(); } + }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/relationdesign/RelationController.cxx b/dbaccess/source/ui/relationdesign/RelationController.cxx new file mode 100644 index 000000000..e35eebe96 --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RelationController.cxx @@ -0,0 +1,548 @@ +/* -*- 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 <map> + +#include <strings.hrc> +#include <strings.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <browserids.hxx> +#include <comphelper/types.hxx> +#include <core_resource.hxx> +#include <connectivity/dbtools.hxx> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <com/sun/star/sdbcx/XKeysSupplier.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbmetadata.hxx> +#include <sqlmessage.hxx> +#include <RelationController.hxx> +#include <TableWindowData.hxx> +#include <UITools.hxx> +#include <RTableConnectionData.hxx> +#include <RelationTableView.hxx> +#include <RelationDesignView.hxx> +#include <tools/diagnose_ex.h> +#include <osl/thread.hxx> +#include <osl/mutex.hxx> + +#define MAX_THREADS 10 + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_ORelationDesign_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::ORelationController(context)); +} + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::util; +using namespace ::dbtools; +using namespace ::dbaui; +using namespace ::comphelper; +using namespace ::osl; + +OUString SAL_CALL ORelationController::getImplementationName() +{ + return "org.openoffice.comp.dbu.ORelationDesign"; +} + +Sequence< OUString> SAL_CALL ORelationController::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.RelationDesign" }; +} + +ORelationController::ORelationController(const Reference< XComponentContext >& _rM) + : OJoinController(_rM) + ,m_nThreadEvent(0) + ,m_bRelationsPossible(true) +{ + InvalidateAll(); +} + +ORelationController::~ORelationController() +{ +} + +FeatureState ORelationController::GetState(sal_uInt16 _nId) const +{ + FeatureState aReturn; + aReturn.bEnabled = m_bRelationsPossible; + switch (_nId) + { + case SID_RELATION_ADD_RELATION: + aReturn.bEnabled = !m_vTableData.empty() && isConnected() && isEditable(); + aReturn.bChecked = false; + break; + case ID_BROWSER_SAVEDOC: + aReturn.bEnabled = haveDataSource() && impl_isModified(); + break; + default: + aReturn = OJoinController::GetState(_nId); + break; + } + return aReturn; +} + +void ORelationController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs) +{ + switch(_nId) + { + case ID_BROWSER_SAVEDOC: + { + OSL_ENSURE(isEditable(),"Slot ID_BROWSER_SAVEDOC should not be enabled!"); + if(!::dbaui::checkDataSourceAvailable(::comphelper::getString(getDataSource()->getPropertyValue(PROPERTY_NAME)), getORB())) + { + OUString aMessage(DBA_RES(STR_DATASOURCE_DELETED)); + OSQLWarningBox aWarning(getFrameWeld(), aMessage); + aWarning.run(); + } + else + { + // now we save the layout information + // create the output stream + try + { + if ( haveDataSource() && getDataSource()->getPropertySetInfo()->hasPropertyByName(PROPERTY_LAYOUTINFORMATION) ) + { + ::comphelper::NamedValueCollection aWindowsData; + saveTableWindows( aWindowsData ); + getDataSource()->setPropertyValue( PROPERTY_LAYOUTINFORMATION, Any( aWindowsData.getPropertyValues() ) ); + setModified(false); + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + break; + case SID_RELATION_ADD_RELATION: + static_cast<ORelationTableView*>(static_cast<ORelationDesignView*>( getView() )->getTableView())->AddNewRelation(); + break; + default: + OJoinController::Execute(_nId,aArgs); + return; + } + InvalidateFeature(_nId); +} + +void ORelationController::impl_initialize() +{ + OJoinController::impl_initialize(); + + if( !getSdbMetaData().supportsRelations() ) + {// check if this database supports relations + + setEditable(false); + m_bRelationsPossible = false; + { + OUString sTitle(DBA_RES(STR_RELATIONDESIGN)); + sTitle = sTitle.copy(3); + OSQLMessageBox aDlg(getFrameWeld(), sTitle, DBA_RES(STR_RELATIONDESIGN_NOT_AVAILABLE)); + aDlg.run(); + } + disconnect(); + throw SQLException(); + } + + if(!m_bRelationsPossible) + InvalidateAll(); + + // we need a datasource + OSL_ENSURE(haveDataSource(),"ORelationController::initialize: need a datasource!"); + + Reference<XTablesSupplier> xSup(getConnection(),UNO_QUERY); + OSL_ENSURE(xSup.is(),"Connection isn't a XTablesSupplier!"); + if(xSup.is()) + m_xTables = xSup->getTables(); + // load the layoutInformation + loadLayoutInformation(); + try + { + loadData(); + if ( !m_nThreadEvent ) + Application::PostUserEvent(LINK(this, ORelationController, OnThreadFinished)); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + +} + +OUString ORelationController::getPrivateTitle( ) const +{ + OUString sName = getDataSourceName(); + return ::dbaui::getStrippedDatabaseName(getDataSource(),sName); +} + +bool ORelationController::Construct(vcl::Window* pParent) +{ + setView( VclPtr<ORelationDesignView>::Create( pParent, *this, getORB() ) ); + OJoinController::Construct(pParent); + return true; +} + +short ORelationController::saveModified() +{ + short nSaved = RET_YES; + if(haveDataSource() && isModified()) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/designsavemodifieddialog.ui")); + std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("DesignSaveModifiedDialog")); + nSaved = xQuery->run(); + if(nSaved == RET_YES) + Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>()); + } + return nSaved; +} + +void ORelationController::describeSupportedFeatures() +{ + OJoinController::describeSupportedFeatures(); + implDescribeSupportedFeature( ".uno:DBAddRelation", SID_RELATION_ADD_RELATION, CommandGroup::EDIT ); +} + +namespace +{ + class RelationLoader : public ::osl::Thread + { + typedef std::map<OUString, std::shared_ptr<OTableWindowData>, ::comphelper::UStringMixLess> TTableDataHelper; + TTableDataHelper m_aTableData; + TTableConnectionData m_vTableConnectionData; + const Sequence< OUString> m_aTableList; + ORelationController* m_pParent; + const Reference< XDatabaseMetaData> m_xMetaData; + const Reference< XNameAccess > m_xTables; + const sal_Int32 m_nStartIndex; + const sal_Int32 m_nEndIndex; + + public: + RelationLoader(ORelationController* _pParent + ,const Reference< XDatabaseMetaData>& _xMetaData + ,const Reference< XNameAccess >& _xTables + ,const Sequence< OUString>& _aTableList + ,const sal_Int32 _nStartIndex + ,const sal_Int32 _nEndIndex) + :m_aTableData(_xMetaData.is() && _xMetaData->supportsMixedCaseQuotedIdentifiers()) + ,m_aTableList(_aTableList) + ,m_pParent(_pParent) + ,m_xMetaData(_xMetaData) + ,m_xTables(_xTables) + ,m_nStartIndex(_nStartIndex) + ,m_nEndIndex(_nEndIndex) + { + } + + /// Working method which should be overridden. + virtual void SAL_CALL run() override; + virtual void SAL_CALL onTerminated() override; + protected: + virtual ~RelationLoader() override {} + + void loadTableData(const Any& _aTable); + }; + + void SAL_CALL RelationLoader::run() + { + osl_setThreadName("RelationLoader"); + + for(sal_Int32 i = m_nStartIndex; i < m_nEndIndex; ++i) + { + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, + m_aTableList[i], + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + Any aCatalog; + if ( !sCatalog.isEmpty() ) + aCatalog <<= sCatalog; + + try + { + Reference< XResultSet > xResult = m_xMetaData->getImportedKeys(aCatalog, sSchema,sTable); + if ( xResult.is() && xResult->next() ) + { + ::comphelper::disposeComponent(xResult); + loadTableData(m_xTables->getByName(m_aTableList[i])); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + void SAL_CALL RelationLoader::onTerminated() + { + m_pParent->mergeData(m_vTableConnectionData); + delete this; + } + + void RelationLoader::loadTableData(const Any& _aTable) + { + Reference<XPropertySet> xTableProp(_aTable,UNO_QUERY); + const OUString sSourceName = ::dbtools::composeTableName( m_xMetaData, xTableProp, ::dbtools::EComposeRule::InTableDefinitions, false ); + TTableDataHelper::const_iterator aFind = m_aTableData.find(sSourceName); + if ( aFind == m_aTableData.end() ) + { + aFind = m_aTableData.emplace(sSourceName,std::make_shared<OTableWindowData>(xTableProp,sSourceName, sSourceName, OUString())).first; + aFind->second->ShowAll(false); + } + TTableWindowData::value_type pReferencingTable = aFind->second; + Reference<XIndexAccess> xKeys = pReferencingTable->getKeys(); + const Reference<XKeysSupplier> xKeySup(xTableProp,UNO_QUERY); + + if ( !xKeys.is() && xKeySup.is() ) + { + xKeys = xKeySup->getKeys(); + } + + if ( !xKeys.is() ) + return; + + Reference<XPropertySet> xKey; + const sal_Int32 nCount = xKeys->getCount(); + for(sal_Int32 i = 0 ; i < nCount ; ++i) + { + xKeys->getByIndex(i) >>= xKey; + sal_Int32 nKeyType = 0; + xKey->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; + if ( KeyType::FOREIGN == nKeyType ) + { + OUString sReferencedTable; + xKey->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= sReferencedTable; + + // insert windows + TTableDataHelper::const_iterator aRefFind = m_aTableData.find(sReferencedTable); + if ( aRefFind == m_aTableData.end() ) + { + if ( m_xTables->hasByName(sReferencedTable) ) + { + Reference<XPropertySet> xReferencedTable(m_xTables->getByName(sReferencedTable),UNO_QUERY); + aRefFind = m_aTableData.emplace(sReferencedTable,std::make_shared<OTableWindowData>(xReferencedTable,sReferencedTable, sReferencedTable, OUString())).first; + aRefFind->second->ShowAll(false); + } + else + continue; // table name could not be found so we do not show this table relation + } + TTableWindowData::value_type pReferencedTable = aRefFind->second; + + OUString sKeyName; + xKey->getPropertyValue(PROPERTY_NAME) >>= sKeyName; + // insert connection + auto xTabConnData = std::make_shared<ORelationTableConnectionData>( pReferencingTable, pReferencedTable, sKeyName ); + m_vTableConnectionData.push_back(xTabConnData); + // insert columns + const Reference<XColumnsSupplier> xColsSup(xKey,UNO_QUERY); + OSL_ENSURE(xColsSup.is(),"Key is no XColumnsSupplier!"); + const Reference<XNameAccess> xColumns = xColsSup->getColumns(); + const Sequence< OUString> aNames = xColumns->getElementNames(); + OUString sColumnName,sRelatedName; + for(sal_Int32 j=0;j<aNames.getLength();++j) + { + const Reference<XPropertySet> xPropSet(xColumns->getByName(aNames[j]),UNO_QUERY); + OSL_ENSURE(xPropSet.is(),"Invalid column found in KeyColumns!"); + if ( xPropSet.is() ) + { + xPropSet->getPropertyValue(PROPERTY_NAME) >>= sColumnName; + xPropSet->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedName; + } + xTabConnData->SetConnLine( j, sColumnName, sRelatedName ); + } + // set update/del flags + sal_Int32 nUpdateRule = 0; + sal_Int32 nDeleteRule = 0; + xKey->getPropertyValue(PROPERTY_UPDATERULE) >>= nUpdateRule; + xKey->getPropertyValue(PROPERTY_DELETERULE) >>= nDeleteRule; + + xTabConnData->SetUpdateRules( nUpdateRule ); + xTabConnData->SetDeleteRules( nDeleteRule ); + + // set cardinality + xTabConnData->SetCardinality(); + } + } + } +} + +void ORelationController::mergeData(const TTableConnectionData& _aConnectionData) +{ + ::osl::MutexGuard aGuard( getMutex() ); + + m_vTableConnectionData.insert( m_vTableConnectionData.end(), _aConnectionData.begin(), _aConnectionData.end() ); + // here we are finished, so we can collect the table from connection data + for (auto const& elem : m_vTableConnectionData) + { + if ( !existsTable(elem->getReferencingTable()->GetComposedName()) ) + { + m_vTableData.push_back(elem->getReferencingTable()); + } + if ( !existsTable(elem->getReferencedTable()->GetComposedName()) ) + { + m_vTableData.push_back(elem->getReferencedTable()); + } + } + if ( m_nThreadEvent ) + { + --m_nThreadEvent; + if ( !m_nThreadEvent ) + Application::PostUserEvent(LINK(this, ORelationController, OnThreadFinished)); + } +} + +IMPL_LINK_NOARG( ORelationController, OnThreadFinished, void*, void ) +{ + ::SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + try + { + getView()->initialize(); // show the windows and fill with our information + getView()->Invalidate(InvalidateFlags::NoErase); + ClearUndoManager(); + setModified(false); // and we are not modified yet + + if(m_vTableData.empty()) + Execute(ID_BROWSER_ADDTABLE,Sequence<PropertyValue>()); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + m_xWaitObject.reset(); +} + +void ORelationController::loadData() +{ + m_xWaitObject.reset(new weld::WaitObject(getFrameWeld())); + try + { + if ( !m_xTables.is() ) + return; + DatabaseMetaData aMeta(getConnection()); + // this may take some time + const Reference< XDatabaseMetaData> xMetaData = getConnection()->getMetaData(); + const Sequence< OUString> aNames = m_xTables->getElementNames(); + const sal_Int32 nCount = aNames.getLength(); + if ( aMeta.supportsThreads() ) + { + const sal_Int32 nMaxElements = (nCount / MAX_THREADS) +1; + sal_Int32 nStart = 0,nEnd = std::min(nMaxElements,nCount); + while(nStart != nEnd) + { + ++m_nThreadEvent; + RelationLoader* pThread = new RelationLoader(this,xMetaData,m_xTables,aNames,nStart,nEnd); + pThread->createSuspended(); + pThread->setPriority(osl_Thread_PriorityBelowNormal); + pThread->resume(); + nStart = nEnd; + nEnd += nMaxElements; + nEnd = std::min(nEnd,nCount); + } + } + else + { + RelationLoader* pThread = new RelationLoader(this,xMetaData,m_xTables,aNames,0,nCount); + pThread->run(); + pThread->onTerminated(); + } + } + catch(SQLException& e) + { + showError(SQLExceptionInfo(e)); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +TTableWindowData::value_type ORelationController::existsTable(std::u16string_view _rComposedTableName) const +{ + ::comphelper::UStringMixEqual bCase(true); + for (auto const& elem : m_vTableData) + { + if(bCase(elem->GetComposedName(),_rComposedTableName)) + return elem; + } + return TTableWindowData::value_type(); +} + +void ORelationController::loadLayoutInformation() +{ + try + { + OSL_ENSURE(haveDataSource(),"We need a datasource from our connection!"); + if ( haveDataSource() ) + { + if ( getDataSource()->getPropertySetInfo()->hasPropertyByName(PROPERTY_LAYOUTINFORMATION) ) + { + Sequence<PropertyValue> aWindows; + getDataSource()->getPropertyValue(PROPERTY_LAYOUTINFORMATION) >>= aWindows; + loadTableWindows(aWindows); + } + } + } + catch(Exception&) + { + } +} + +void ORelationController::reset() +{ + loadLayoutInformation(); + ODataView* pView = getView(); + OSL_ENSURE(pView,"No current view!"); + if(pView) + { + pView->initialize(); + pView->Invalidate(InvalidateFlags::NoErase); + } +} + +bool ORelationController::allowViews() const +{ + return false; +} + +bool ORelationController::allowQueries() const +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/relationdesign/RelationDesignView.cxx b/dbaccess/source/ui/relationdesign/RelationDesignView.cxx new file mode 100644 index 000000000..014579cf7 --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RelationDesignView.cxx @@ -0,0 +1,74 @@ +/* -*- 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 <RelationDesignView.hxx> +#include <RelationTableView.hxx> +#include <RelationController.hxx> +#include <vcl/event.hxx> + +using namespace ::dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; + +ORelationDesignView::ORelationDesignView(vcl::Window* _pParent, ORelationController& _rController,const Reference< XComponentContext >& _rxContext) + :OJoinDesignView( _pParent, _rController, _rxContext ) +{ +} + +void ORelationDesignView::Construct() +{ + m_pTableView = VclPtr<ORelationTableView>::Create(m_pScrollWindow,this); + OJoinDesignView::Construct(); +} + +void ORelationDesignView::initialize() +{ + m_pTableView->clearLayoutInformation(); + m_pTableView->ReSync(); + + OJoinDesignView::initialize(); +} + +bool ORelationDesignView::PreNotify( NotifyEvent& rNEvt ) +{ + bool bDone = false; + if(rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + { + if(m_pTableView && !m_pTableView->HasChildPathFocus()) + { + m_pTableView->GrabTabWinFocus(); + bDone = true; + } + } + if(!bDone) + bDone = OJoinDesignView::PreNotify(rNEvt); + return bDone; +} + +void ORelationDesignView::GetFocus() +{ + OJoinDesignView::GetFocus(); + if ( m_pTableView && m_pTableView->IsVisible() && !m_pTableView->GetTabWinMap().empty() ) + m_pTableView->GrabTabWinFocus(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/relationdesign/RelationTableView.cxx b/dbaccess/source/ui/relationdesign/RelationTableView.cxx new file mode 100644 index 000000000..ea7b83146 --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RelationTableView.cxx @@ -0,0 +1,410 @@ +/* -*- 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 <RelationTableView.hxx> +#include <core_resource.hxx> +#include <browserids.hxx> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <connectivity/dbtools.hxx> +#include <tools/diagnose_ex.h> +#include <helpids.h> +#include <RelationDesignView.hxx> +#include <JoinController.hxx> +#include <TableWindow.hxx> +#include <TableWindowData.hxx> +#include "RTableConnection.hxx" +#include <RTableConnectionData.hxx> +#include <RelationDlg.hxx> +#include <sqlmessage.hxx> +#include <strings.hrc> +#include <connectivity/dbexception.hxx> +#include "RTableWindow.hxx" +#include <JAccess.hxx> +#include <vcl/stdtext.hxx> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> + +using namespace dbaui; +using namespace ::dbtools; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +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::accessibility; + +ORelationTableView::ORelationTableView( vcl::Window* pParent, ORelationDesignView* pView ) + :OJoinTableView( pParent, pView ) + , ::comphelper::OContainerListener(m_aMutex) + ,m_pExistingConnection(nullptr) + ,m_bInRemove(false) + +{ + SetHelpId(HID_CTL_RELATIONTAB); +} + +ORelationTableView::~ORelationTableView() +{ + disposeOnce(); +} + +void ORelationTableView::dispose() +{ + if ( m_pContainerListener.is() ) + m_pContainerListener->dispose(); + m_pExistingConnection.clear(); + OJoinTableView::dispose(); +} + +void ORelationTableView::ReSync() +{ + if ( !m_pContainerListener.is() ) + { + Reference< XConnection> xConnection = m_pView->getController().getConnection(); + Reference< XTablesSupplier > xTableSupp( xConnection, UNO_QUERY_THROW ); + Reference< XNameAccess > xTables = xTableSupp->getTables(); + Reference< XContainer> xContainer(xTables,uno::UNO_QUERY); + if ( xContainer.is() ) + m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer); + } + // Tables could have been hidden in the database, which are part of a relation. Or a table was in layout + // (quite often without a relation) and does not exist anymore. In both cases creation of TabWins will fail + // and all TabWinDatas and related ConnDates should be deleted. + std::vector< OUString> arrInvalidTables; + + // create and insert windows + TTableWindowData& rTabWinDataList = m_pView->getController().getTableWindowData(); + TTableWindowData::const_reverse_iterator aIter = rTabWinDataList.rbegin(); + for(;aIter != rTabWinDataList.rend();++aIter) + { + TTableWindowData::value_type pData = *aIter; + VclPtr<OTableWindow> pTabWin = createWindow(pData); + + if (!pTabWin->Init()) + { + // initialisation failed, which means this TabWin is not available, therefore, + // it should be cleaned up, including its data in the document + pTabWin->clearListBox(); + pTabWin.disposeAndClear(); + arrInvalidTables.push_back(pData->GetTableName()); + + rTabWinDataList.erase( std::remove(rTabWinDataList.begin(), rTabWinDataList.end(), *aIter), rTabWinDataList.end()); + continue; + } + + GetTabWinMap()[pData->GetComposedName()] = pTabWin; // insert at the beginning, as the Datalist is walked through backward + // if there's no position or size contained in the data -> Default + if (!pData->HasPosition() && !pData->HasSize()) + SetDefaultTabWinPosSize(pTabWin); + + pTabWin->Show(); + } + + // insert connection + TTableConnectionData& rTabConnDataList = m_pView->getController().getTableConnectionData(); + TTableConnectionData::const_reverse_iterator aConIter = rTabConnDataList.rbegin(); + + for(;aConIter != rTabConnDataList.rend();++aConIter) + { + ORelationTableConnectionData* pTabConnData = static_cast<ORelationTableConnectionData*>(aConIter->get()); + if ( !arrInvalidTables.empty() ) + { + // do the tables to the connection exist? + OUString strTabExistenceTest = pTabConnData->getReferencingTable()->GetTableName(); + bool bInvalid = std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end(); + strTabExistenceTest = pTabConnData->getReferencedTable()->GetTableName(); + bInvalid = bInvalid || std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end(); + + if (bInvalid) + { + // no -> bad luck, the connection is gone + rTabConnDataList.erase( std::remove(rTabConnDataList.begin(), rTabConnDataList.end(), *aConIter), rTabConnDataList.end() ); + continue; + } + } + + addConnection( VclPtr<ORelationTableConnection>::Create(this, *aConIter), false ); + } + + if ( !GetTabWinMap().empty() ) + GetTabWinMap().begin()->second->GrabFocus(); +} + +bool ORelationTableView::IsAddAllowed() +{ + + return !m_pView->getController().isReadOnly(); +} + +void ORelationTableView::AddConnection(const OJoinExchangeData& jxdSource, const OJoinExchangeData& jxdDest) +{ + // Set LineDataObject based on selected fieldname + // check if relation already exists + OTableWindow* pSourceWin = jxdSource.pListBox->GetTabWin(); + OTableWindow* pDestWin = jxdDest.pListBox->GetTabWin(); + + for(VclPtr<OTableConnection> const & pFirst : getTableConnections()) + { + if((pFirst->GetSourceWin() == pSourceWin && pFirst->GetDestWin() == pDestWin) || + (pFirst->GetSourceWin() == pDestWin && pFirst->GetDestWin() == pSourceWin)) + { + m_pExistingConnection = pFirst; + break; + } + } + // insert table connection into view + TTableConnectionData::value_type pTabConnData = std::make_shared<ORelationTableConnectionData>(pSourceWin->GetData(), + pDestWin->GetData()); + + // the names of the affected fields + weld::TreeView& rSourceTreeView = jxdSource.pListBox->get_widget(); + OUString sSourceFieldName = rSourceTreeView.get_text(jxdSource.nEntry); + weld::TreeView& rDestTreeView = jxdDest.pListBox->get_widget(); + OUString sDestFieldName = rDestTreeView.get_text(jxdDest.nEntry); + + // the number of PKey-Fields in the source + const Reference< XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(pSourceWin->GetData()->getTable()); + bool bAskUser = xPrimaryKeyColumns.is() && Reference< XIndexAccess>(xPrimaryKeyColumns,UNO_QUERY_THROW)->getCount() > 1; + + pTabConnData->SetConnLine( 0, sSourceFieldName, sDestFieldName ); + + if ( bAskUser || m_pExistingConnection ) + m_pCurrentlyTabConnData = pTabConnData; // this implies that we ask the user what to do + else + { + try + { + // hand over data to the database + if( pTabConnData->Update() ) + { + // enter UI-object into ConnList + addConnection( VclPtr<ORelationTableConnection>::Create( this, pTabConnData ) ); + } + } + catch(const SQLException&) + { + throw; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "dbaccess", "ORelationTableView::AddConnection"); + } + } +} + +void ORelationTableView::ConnDoubleClicked(VclPtr<OTableConnection>& rConnection) +{ + ORelationDialog aRelDlg(this, rConnection->GetData()); + switch (aRelDlg.run()) + { + case RET_OK: + // successfully updated + rConnection->UpdateLineList(); + // The connection references 1 ConnData and n ConnLines, each ConnData references n LineDatas, each Line exactly 1 LineData + // As the Dialog and the ConnData->Update may have changed the LineDatas we have to restore the consistent state + break; + + case RET_NO: + // tried at least one update, but did not succeed -> the original connection is lost + RemoveConnection(rConnection ,true); + break; + + case RET_CANCEL: + // no break, as nothing happened and we don't need the code below + return; + + } + + Invalidate(InvalidateFlags::NoChildren); +} + +void ORelationTableView::AddNewRelation() +{ + + TTableConnectionData::value_type pNewConnData = std::make_shared<ORelationTableConnectionData>(); + ORelationDialog aRelDlg(this, pNewConnData, true); + + bool bSuccess = (aRelDlg.run() == RET_OK); + if (bSuccess) + { + // already updated by the dialog + // announce it to the document + addConnection( VclPtr<ORelationTableConnection>::Create(this, pNewConnData) ); + } +} + +bool ORelationTableView::RemoveConnection(VclPtr<OTableConnection>& rConn, bool /*_bDelete*/) +{ + ORelationTableConnectionData* pTabConnData = static_cast<ORelationTableConnectionData*>(rConn->GetData().get()); + try + { + if (!m_bInRemove) + pTabConnData->DropRelation(); + return OJoinTableView::RemoveConnection(rConn, true); + } + catch(SQLException& e) + { + getDesignView()->getController().showError(SQLExceptionInfo(e)); + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION( "dbaccess", "ORelationTableView::RemoveConnection: Something other than SQLException occurred!"); + } + return false; +} + +void ORelationTableView::AddTabWin(const OUString& _rComposedName, const OUString& rWinName, bool /*bNewTable*/) +{ + OSL_ENSURE(!_rComposedName.isEmpty(),"There must be a table name supplied!"); + OJoinTableView::OTableWindowMap::const_iterator aIter = GetTabWinMap().find(_rComposedName); + + if(aIter != GetTabWinMap().end()) + { + aIter->second->SetZOrder(nullptr, ZOrderFlags::First); + aIter->second->GrabFocus(); + EnsureVisible(aIter->second); + // no new one + return; + } + + // enter the new data structure into DocShell + TTableWindowData::value_type pNewTabWinData(createTableWindowData( _rComposedName, rWinName,rWinName )); + pNewTabWinData->ShowAll(false); + + // link new window into the window list + VclPtr<OTableWindow> pNewTabWin = createWindow( pNewTabWinData ); + if(pNewTabWin->Init()) + { + m_pView->getController().getTableWindowData().push_back( pNewTabWinData); + // when we already have a table with this name insert the full qualified one instead + GetTabWinMap()[_rComposedName] = pNewTabWin; + + SetDefaultTabWinPosSize( pNewTabWin ); + pNewTabWin->Show(); + + modified(); + + if ( m_pAccessible ) + m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD, + Any(), + Any(pNewTabWin->GetAccessible())); + } + else + { + pNewTabWin->clearListBox(); + pNewTabWin.disposeAndClear(); + } +} + +void ORelationTableView::RemoveTabWin( OTableWindow* pTabWin ) +{ + OSQLWarningBox aDlg(GetFrameWeld(), DBA_RES(STR_QUERY_REL_DELETE_WINDOW), MessBoxStyle::YesNo | MessBoxStyle::DefaultYes); + if (m_bInRemove || aDlg.run() == RET_YES) + { + m_pView->getController().ClearUndoManager(); + OJoinTableView::RemoveTabWin( pTabWin ); + + m_pView->getController().InvalidateFeature(SID_RELATION_ADD_RELATION); + m_pView->getController().InvalidateFeature(ID_BROWSER_UNDO); + m_pView->getController().InvalidateFeature(ID_BROWSER_REDO); + } +} + +void ORelationTableView::lookForUiActivities() +{ + if(m_pExistingConnection) + { + OUString sTitle(DBA_RES(STR_RELATIONDESIGN)); + sTitle = sTitle.copy(3); + OSQLMessageBox aDlg(GetFrameWeld(), DBA_RES(STR_QUERY_REL_EDIT_RELATION), OUString(), MessBoxStyle::NONE); + aDlg.set_title(sTitle); + aDlg.add_button(DBA_RES(STR_QUERY_REL_EDIT), RET_OK); + aDlg.set_default_response(RET_OK); + aDlg.add_button(DBA_RES(STR_QUERY_REL_CREATE), RET_YES); + aDlg.add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL); + sal_uInt16 nRet = aDlg.run(); + if (nRet == RET_CANCEL) + { + m_pCurrentlyTabConnData.reset(); + } + else if ( nRet == RET_OK ) // EDIT + { + ConnDoubleClicked(m_pExistingConnection); + m_pCurrentlyTabConnData.reset(); + } + m_pExistingConnection = nullptr; + } + if(m_pCurrentlyTabConnData) + { + ORelationDialog aRelDlg(this, m_pCurrentlyTabConnData); + if (aRelDlg.run() == RET_OK) + { + // already updated by the dialog + addConnection( VclPtr<ORelationTableConnection>::Create( this, m_pCurrentlyTabConnData ) ); + } + m_pCurrentlyTabConnData.reset(); + } +} + +VclPtr<OTableWindow> ORelationTableView::createWindow(const TTableWindowData::value_type& _pData) +{ + return VclPtr<ORelationTableWindow>::Create(this,_pData); +} + +bool ORelationTableView::allowQueries() const +{ + return false; +} + +void ORelationTableView::_elementInserted( const container::ContainerEvent& /*_rEvent*/ ) +{ + +} + +void ORelationTableView::_elementRemoved( const container::ContainerEvent& _rEvent ) +{ + m_bInRemove = true; + OUString sName; + if ( _rEvent.Accessor >>= sName ) + { + OTableWindow* pTableWindow = GetTabWindow(sName); + if ( pTableWindow ) + { + m_pView->getController().ClearUndoManager(); + OJoinTableView::RemoveTabWin( pTableWindow ); + + m_pView->getController().InvalidateFeature(SID_RELATION_ADD_RELATION); + m_pView->getController().InvalidateFeature(ID_BROWSER_UNDO); + m_pView->getController().InvalidateFeature(ID_BROWSER_REDO); + } + } + m_bInRemove = false; +} + +void ORelationTableView::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx b/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx new file mode 100644 index 000000000..d8dce84a0 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx @@ -0,0 +1,639 @@ +/* -*- 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 <FieldDescriptions.hxx> +#include <tools/diagnose_ex.h> +#include <strings.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <comphelper/types.hxx> +#include <comphelper/extract.hxx> +#include <UITools.hxx> +#include <com/sun/star/util/NumberFormat.hpp> + +#define DEFAULT_VARCHAR_PRECISION 100 +#define DEFAULT_OTHER_PRECISION 16 +#define DEFAULT_NUMERIC_PRECISION 5 +#define DEFAULT_NUMERIC_SCALE 0 + +using namespace dbaui; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; + +OFieldDescription::OFieldDescription() + :m_nType(DataType::VARCHAR) + ,m_nPrecision(0) + ,m_nScale(0) + ,m_nIsNullable(ColumnValue::NULLABLE) + ,m_nFormatKey(0) + ,m_eHorJustify(SvxCellHorJustify::Standard) + ,m_bIsAutoIncrement(false) + ,m_bIsPrimaryKey(false) + ,m_bIsCurrency(false) + ,m_bHidden(false) +{ +} + +OFieldDescription::OFieldDescription( const OFieldDescription& rDescr ) + :m_aControlDefault(rDescr.m_aControlDefault) + ,m_aWidth(rDescr.m_aWidth) + ,m_aRelativePosition(rDescr.m_aRelativePosition) + ,m_pType(rDescr.m_pType) + ,m_xDest(rDescr.m_xDest) + ,m_xDestInfo(rDescr.m_xDestInfo) + ,m_sName(rDescr.m_sName) + ,m_sTypeName(rDescr.m_sTypeName) + ,m_sDescription(rDescr.m_sDescription) + ,m_sAutoIncrementValue(rDescr.m_sAutoIncrementValue) + ,m_nType(rDescr.m_nType) + ,m_nPrecision(rDescr.m_nPrecision) + ,m_nScale(rDescr.m_nScale) + ,m_nIsNullable(rDescr.m_nIsNullable) + ,m_nFormatKey(rDescr.m_nFormatKey) + ,m_eHorJustify(rDescr.m_eHorJustify) + ,m_bIsAutoIncrement(rDescr.m_bIsAutoIncrement) + ,m_bIsPrimaryKey(rDescr.m_bIsPrimaryKey) + ,m_bIsCurrency(rDescr.m_bIsCurrency) + ,m_bHidden(rDescr.m_bHidden) +{ +} + +OFieldDescription::~OFieldDescription() +{ +} + +OFieldDescription::OFieldDescription(const Reference< XPropertySet >& xAffectedCol,bool _bUseAsDest) + :m_nType(DataType::VARCHAR) + ,m_nPrecision(0) + ,m_nScale(0) + ,m_nIsNullable(ColumnValue::NULLABLE) + ,m_nFormatKey(0) + ,m_eHorJustify(SvxCellHorJustify::Standard) + ,m_bIsAutoIncrement(false) + ,m_bIsPrimaryKey(false) + ,m_bIsCurrency(false) + ,m_bHidden(false) +{ + OSL_ENSURE(xAffectedCol.is(),"PropertySet can not be null!"); + if ( !xAffectedCol.is() ) + return; + + if ( _bUseAsDest ) + { + m_xDest = xAffectedCol; + m_xDestInfo = xAffectedCol->getPropertySetInfo(); + } + else + { + try + { + Reference<XPropertySetInfo> xPropSetInfo = xAffectedCol->getPropertySetInfo(); + if(xPropSetInfo->hasPropertyByName(PROPERTY_NAME)) + SetName(::comphelper::getString(xAffectedCol->getPropertyValue(PROPERTY_NAME))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_DESCRIPTION)) + SetDescription(::comphelper::getString(xAffectedCol->getPropertyValue(PROPERTY_DESCRIPTION))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_HELPTEXT)) + { + OUString sHelpText; + xAffectedCol->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText; + SetHelpText(sHelpText); + } + if(xPropSetInfo->hasPropertyByName(PROPERTY_DEFAULTVALUE)) + SetDefaultValue( xAffectedCol->getPropertyValue(PROPERTY_DEFAULTVALUE) ); + + if(xPropSetInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT)) + SetControlDefault( xAffectedCol->getPropertyValue(PROPERTY_CONTROLDEFAULT) ); + + if(xPropSetInfo->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION)) + SetAutoIncrementValue(::comphelper::getString(xAffectedCol->getPropertyValue(PROPERTY_AUTOINCREMENTCREATION))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_TYPE)) + SetTypeValue(::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_TYPE))); + if (xPropSetInfo->hasPropertyByName(PROPERTY_TYPENAME)) + SetTypeName(::comphelper::getString(xAffectedCol->getPropertyValue(PROPERTY_TYPENAME))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_PRECISION)) + SetPrecision(::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_PRECISION))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_SCALE)) + SetScale(::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_SCALE))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_ISNULLABLE)) + SetIsNullable(::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_ISNULLABLE))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_FORMATKEY)) + { + const Any aValue = xAffectedCol->getPropertyValue(PROPERTY_FORMATKEY); + if ( aValue.hasValue() ) + SetFormatKey(::comphelper::getINT32(aValue)); + } + if(xPropSetInfo->hasPropertyByName(PROPERTY_RELATIVEPOSITION)) + m_aRelativePosition = xAffectedCol->getPropertyValue(PROPERTY_RELATIVEPOSITION); + if(xPropSetInfo->hasPropertyByName(PROPERTY_WIDTH)) + m_aWidth = xAffectedCol->getPropertyValue(PROPERTY_WIDTH); + if(xPropSetInfo->hasPropertyByName(PROPERTY_HIDDEN)) + xAffectedCol->getPropertyValue(PROPERTY_HIDDEN) >>= m_bHidden; + if(xPropSetInfo->hasPropertyByName(PROPERTY_ALIGN)) + { + const Any aValue = xAffectedCol->getPropertyValue(PROPERTY_ALIGN); + if ( aValue.hasValue() ) + SetHorJustify( ::dbaui::mapTextJustify(::comphelper::getINT32(aValue))); + } + if(xPropSetInfo->hasPropertyByName(PROPERTY_ISAUTOINCREMENT)) + SetAutoIncrement(::cppu::any2bool(xAffectedCol->getPropertyValue(PROPERTY_ISAUTOINCREMENT))); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } +} + +void OFieldDescription::FillFromTypeInfo(const TOTypeInfoSP& _pType,bool _bForce,bool _bReset) +{ + TOTypeInfoSP pOldType = getTypeInfo(); + if ( _pType == pOldType ) + return; + + // reset type depending information + if ( _bReset ) + { + SetFormatKey(0); + SetControlDefault(Any()); + } + + bool bForce = _bForce || !pOldType || pOldType->nType != _pType->nType; + switch ( _pType->nType ) + { + case DataType::CHAR: + case DataType::VARCHAR: + if ( bForce ) + { + sal_Int32 nPrec = DEFAULT_VARCHAR_PRECISION; + if ( GetPrecision() ) + nPrec = GetPrecision(); + SetPrecision(std::min<sal_Int32>(nPrec,_pType->nPrecision)); + } + break; + case DataType::TIMESTAMP: + if ( bForce && _pType->nMaximumScale) + { + SetScale(std::min<sal_Int32>(GetScale() ? GetScale() : DEFAULT_NUMERIC_SCALE,_pType->nMaximumScale)); + } + break; + default: + if ( bForce ) + { + sal_Int32 nPrec = DEFAULT_OTHER_PRECISION; + switch ( _pType->nType ) + { + case DataType::BIT: + case DataType::BLOB: + case DataType::CLOB: + nPrec = _pType->nPrecision; + break; + default: + if ( GetPrecision() ) + nPrec = GetPrecision(); + break; + } + + if ( _pType->nPrecision ) + SetPrecision(std::min<sal_Int32>(nPrec ? nPrec : DEFAULT_NUMERIC_PRECISION,_pType->nPrecision)); + if ( _pType->nMaximumScale ) + SetScale(std::min<sal_Int32>(GetScale() ? GetScale() : DEFAULT_NUMERIC_SCALE,_pType->nMaximumScale)); + } + } + if ( _pType->aCreateParams.isEmpty() ) + { + SetPrecision(_pType->nPrecision); + SetScale(_pType->nMinimumScale); + } + if ( !_pType->bNullable && IsNullable() ) + SetIsNullable(ColumnValue::NO_NULLS); + if ( !_pType->bAutoIncrement && IsAutoIncrement() ) + SetAutoIncrement(false); + SetCurrency( _pType->bCurrency ); + SetType(_pType); + SetTypeName(_pType->aTypeName); +} + +void OFieldDescription::SetName(const OUString& _rName) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_NAME) ) + m_xDest->setPropertyValue(PROPERTY_NAME,Any(_rName)); + else + m_sName = _rName; + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetHelpText(const OUString& _sHelpText) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_HELPTEXT) ) + m_xDest->setPropertyValue(PROPERTY_HELPTEXT,Any(_sHelpText)); + else + m_sHelpText = _sHelpText; + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetDescription(const OUString& _rDescription) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_DESCRIPTION) ) + m_xDest->setPropertyValue(PROPERTY_DESCRIPTION,Any(_rDescription)); + else + m_sDescription = _rDescription; + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetDefaultValue(const Any& _rDefaultValue) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_DEFAULTVALUE) ) + m_xDest->setPropertyValue(PROPERTY_DEFAULTVALUE, _rDefaultValue); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetControlDefault(const Any& _rControlDefault) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT) ) + m_xDest->setPropertyValue(PROPERTY_CONTROLDEFAULT, _rControlDefault); + else + m_aControlDefault = _rControlDefault; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetAutoIncrementValue(const OUString& _sAutoIncValue) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION) ) + m_xDest->setPropertyValue(PROPERTY_AUTOINCREMENTCREATION,Any(_sAutoIncValue)); + else + m_sAutoIncrementValue = _sAutoIncValue; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetType(const TOTypeInfoSP& _pType) +{ + m_pType = _pType; + if ( !m_pType ) + return; + + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPE) ) + m_xDest->setPropertyValue(PROPERTY_TYPE,Any(m_pType->nType)); + else + m_nType = m_pType->nType; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetTypeValue(sal_Int32 _nType) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPE) ) + m_xDest->setPropertyValue(PROPERTY_TYPE,Any(_nType)); + else + { + m_nType = _nType; + OSL_ENSURE(!m_pType,"Invalid call here!"); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetPrecision(sal_Int32 _rPrecision) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_PRECISION) ) + m_xDest->setPropertyValue(PROPERTY_PRECISION,Any(_rPrecision)); + else + m_nPrecision = _rPrecision; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetScale(sal_Int32 _rScale) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_SCALE) ) + m_xDest->setPropertyValue(PROPERTY_SCALE,Any(_rScale)); + else + m_nScale = _rScale; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetIsNullable(sal_Int32 _rIsNullable) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISNULLABLE) ) + m_xDest->setPropertyValue(PROPERTY_ISNULLABLE,Any(_rIsNullable)); + else + m_nIsNullable = _rIsNullable; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetFormatKey(sal_Int32 _rFormatKey) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_FORMATKEY) ) + m_xDest->setPropertyValue(PROPERTY_FORMATKEY,Any(_rFormatKey)); + else + m_nFormatKey = _rFormatKey; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetHorJustify(const SvxCellHorJustify& _rHorJustify) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ALIGN) ) + m_xDest->setPropertyValue(PROPERTY_ALIGN,Any( dbaui::mapTextAlign(_rHorJustify))); + else + m_eHorJustify = _rHorJustify; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetAutoIncrement(bool _bAuto) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISAUTOINCREMENT) ) + m_xDest->setPropertyValue(PROPERTY_ISAUTOINCREMENT,Any(_bAuto)); + else + m_bIsAutoIncrement = _bAuto; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetPrimaryKey(bool _bPKey) +{ + m_bIsPrimaryKey = _bPKey; + if ( _bPKey ) + SetIsNullable(css::sdbc::ColumnValue::NO_NULLS); +} + +void OFieldDescription::SetCurrency(bool _bIsCurrency) +{ + m_bIsCurrency = _bIsCurrency; +} + +OUString OFieldDescription::GetName() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_NAME) ) + return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_NAME)); + else + return m_sName; +} + +OUString OFieldDescription::GetDescription() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_DESCRIPTION) ) + return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_DESCRIPTION)); + else + return m_sDescription; +} + +OUString OFieldDescription::GetHelpText() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_HELPTEXT) ) + return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_HELPTEXT)); + else + return m_sHelpText; +} + +css::uno::Any OFieldDescription::GetControlDefault() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT) ) + return m_xDest->getPropertyValue(PROPERTY_CONTROLDEFAULT); + else + return m_aControlDefault; +} + +OUString OFieldDescription::GetAutoIncrementValue() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION) ) + return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_AUTOINCREMENTCREATION)); + else + return m_sAutoIncrementValue; +} + +sal_Int32 OFieldDescription::GetType() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPE) ) + return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_TYPE)); + else + return m_pType ? m_pType->nType : m_nType; +} + +OUString OFieldDescription::GetTypeName() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPENAME) ) + return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_TYPENAME)); + else + return m_pType ? m_pType->aTypeName : m_sTypeName; +} + +sal_Int32 OFieldDescription::GetPrecision() const +{ + sal_Int32 nPrec = m_nPrecision; + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_PRECISION) ) + nPrec = ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_PRECISION)); + + TOTypeInfoSP pTypeInfo = getTypeInfo(); + if ( pTypeInfo ) + { + switch ( pTypeInfo->nType ) + { + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::BIGINT: + if ( !nPrec ) + nPrec = pTypeInfo->nPrecision; + break; + } + } + + return nPrec; +} + +sal_Int32 OFieldDescription::GetScale() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_SCALE) ) + return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_SCALE)); + else + return m_nScale; +} + +sal_Int32 OFieldDescription::GetIsNullable() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISNULLABLE) ) + return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_ISNULLABLE)); + else + return m_nIsNullable; +} + +sal_Int32 OFieldDescription::GetFormatKey() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_FORMATKEY) ) + return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_FORMATKEY)); + else + return m_nFormatKey; +} + +SvxCellHorJustify OFieldDescription::GetHorJustify() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ALIGN) ) + return ::dbaui::mapTextJustify(::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_ALIGN))); + else + return m_eHorJustify; +} + + +TOTypeInfoSP OFieldDescription::getSpecialTypeInfo() const +{ + TOTypeInfoSP pSpecialType = std::make_shared<OTypeInfo>(); + *pSpecialType = *m_pType; + pSpecialType->nPrecision = GetPrecision(); + pSpecialType->nMaximumScale = static_cast<sal_Int16>(GetScale()); + pSpecialType->bAutoIncrement = IsAutoIncrement(); // http://dba.openoffice.org/issues/show_bug.cgi?id=115398 fixed by ludob + return pSpecialType; +} + +bool OFieldDescription::IsAutoIncrement() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISAUTOINCREMENT) ) + return ::cppu::any2bool(m_xDest->getPropertyValue(PROPERTY_ISAUTOINCREMENT)); + else + return m_bIsAutoIncrement; +} + + +bool OFieldDescription::IsNullable() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISNULLABLE) ) + return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_ISNULLABLE)) == css::sdbc::ColumnValue::NULLABLE; + else + return m_nIsNullable == css::sdbc::ColumnValue::NULLABLE; +} + +void OFieldDescription::SetTypeName(const OUString& _sTypeName) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPENAME) ) + m_xDest->setPropertyValue(PROPERTY_TYPENAME,Any(_sTypeName)); + else + m_sTypeName = _sTypeName; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::copyColumnSettingsTo(const Reference< XPropertySet >& _rxColumn) +{ + if ( !_rxColumn.is() ) + return; + + Reference<XPropertySetInfo> xInfo = _rxColumn->getPropertySetInfo(); + + if ( GetFormatKey() != NumberFormat::ALL && xInfo->hasPropertyByName(PROPERTY_FORMATKEY) ) + _rxColumn->setPropertyValue(PROPERTY_FORMATKEY,Any(GetFormatKey())); + if ( GetHorJustify() != SvxCellHorJustify::Standard && xInfo->hasPropertyByName(PROPERTY_ALIGN) ) + _rxColumn->setPropertyValue(PROPERTY_ALIGN,Any(dbaui::mapTextAlign(GetHorJustify()))); + if ( !GetHelpText().isEmpty() && xInfo->hasPropertyByName(PROPERTY_HELPTEXT) ) + _rxColumn->setPropertyValue(PROPERTY_HELPTEXT,Any(GetHelpText())); + if ( GetControlDefault().hasValue() && xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT) ) + _rxColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,GetControlDefault()); + + if(xInfo->hasPropertyByName(PROPERTY_RELATIVEPOSITION)) + _rxColumn->setPropertyValue(PROPERTY_RELATIVEPOSITION,m_aRelativePosition); + if(xInfo->hasPropertyByName(PROPERTY_WIDTH)) + _rxColumn->setPropertyValue(PROPERTY_WIDTH,m_aWidth); + if(xInfo->hasPropertyByName(PROPERTY_HIDDEN)) + _rxColumn->setPropertyValue(PROPERTY_HIDDEN,Any(m_bHidden)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TEditControl.cxx b/dbaccess/source/ui/tabledesign/TEditControl.cxx new file mode 100644 index 000000000..5f7809882 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TEditControl.cxx @@ -0,0 +1,1679 @@ +/* -*- 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 "TEditControl.hxx" +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <core_resource.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <helpids.h> +#include <comphelper/types.hxx> +#include <FieldDescControl.hxx> +#include <FieldDescriptions.hxx> +#include "TableUndo.hxx" +#include <TableController.hxx> +#include <connectivity/dbmetadata.hxx> +#include <connectivity/dbtools.hxx> +#include <SqlNameEdit.hxx> +#include <TableRowExchange.hxx> +#include <o3tl/safeint.hxx> +#include <sot/storage.hxx> +#include <svx/svxids.hrc> +#include <UITools.hxx> +#include "TableFieldControl.hxx" +#include <dsntypes.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/svapp.hxx> + +using namespace ::dbaui; +using namespace ::comphelper; +using namespace ::svt; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdb; + + +#define HANDLE_ID 0 + +// default field widths +#define FIELDNAME_WIDTH 100 +#define FIELDTYPE_WIDTH 150 +#define FIELDDESCR_WIDTH 300 + +// Maximum length in description field +#define MAX_DESCR_LEN 256 + +OTableEditorCtrl::ClipboardInvalidator::ClipboardInvalidator(OTableEditorCtrl* _pOwner) +: m_aInvalidateTimer("dbaccess ClipboardInvalidator") +, m_pOwner(_pOwner) +{ + + m_aInvalidateTimer.SetTimeout(500); + m_aInvalidateTimer.SetInvokeHandler(LINK(this, OTableEditorCtrl::ClipboardInvalidator, OnInvalidate)); + m_aInvalidateTimer.Start(); +} + +OTableEditorCtrl::ClipboardInvalidator::~ClipboardInvalidator() +{ + m_aInvalidateTimer.Stop(); +} + +void OTableEditorCtrl::ClipboardInvalidator::Stop() +{ + m_aInvalidateTimer.Stop(); +} + +IMPL_LINK_NOARG(OTableEditorCtrl::ClipboardInvalidator, OnInvalidate, Timer *, void) +{ + m_pOwner->GetView()->getController().InvalidateFeature(SID_CUT); + m_pOwner->GetView()->getController().InvalidateFeature(SID_COPY); + m_pOwner->GetView()->getController().InvalidateFeature(SID_PASTE); +} + +void OTableEditorCtrl::Init() +{ + OTableRowView::Init(); + + // Should it be opened ReadOnly? + bool bRead(GetView()->getController().isReadOnly()); + + SetReadOnly( bRead ); + + // Insert the columns + InsertDataColumn( FIELD_NAME, DBA_RES(STR_TAB_FIELD_COLUMN_NAME), FIELDNAME_WIDTH ); + + InsertDataColumn( FIELD_TYPE, DBA_RES(STR_TAB_FIELD_COLUMN_DATATYPE), FIELDTYPE_WIDTH ); + + ::dbaccess::ODsnTypeCollection aDsnTypes(GetView()->getController().getORB()); + bool bShowColumnDescription = aDsnTypes.supportsColumnDescription(::comphelper::getString(GetView()->getController().getDataSource()->getPropertyValue(PROPERTY_URL))); + InsertDataColumn( HELP_TEXT, DBA_RES(STR_TAB_HELP_TEXT), bShowColumnDescription ? FIELDTYPE_WIDTH : FIELDDESCR_WIDTH ); + + if ( bShowColumnDescription ) + { + InsertDataColumn( COLUMN_DESCRIPTION, DBA_RES(STR_COLUMN_DESCRIPTION), FIELDTYPE_WIDTH ); + } + + InitCellController(); + + // Insert the rows + RowInserted(0, m_pRowList->size()); +} + +OTableEditorCtrl::OTableEditorCtrl(vcl::Window* pWindow, OTableDesignView* pView) + :OTableRowView(pWindow) + ,m_pView(pView) + ,pNameCell(nullptr) + ,pTypeCell(nullptr) + ,pHelpTextCell(nullptr) + ,pDescrCell(nullptr) + ,pDescrWin(nullptr) + ,nCutEvent(nullptr) + ,nPasteEvent(nullptr) + ,nDeleteEvent(nullptr) + ,nInsNewRowsEvent(nullptr) + ,nInvalidateTypeEvent(nullptr) + ,m_eChildFocus(NONE) + ,nOldDataPos(-1) + ,bReadOnly(true) + ,m_aInvalidate(this) +{ + SetHelpId(HID_TABDESIGN_BACKGROUND); + GetDataWindow().SetHelpId(HID_CTL_TABLEEDIT); + + m_pRowList = &GetView()->getController().getRows(); + m_nDataPos = 0; +} + +SfxUndoManager& OTableEditorCtrl::GetUndoManager() const +{ + return GetView()->getController().GetUndoManager(); +} + + +void OTableEditorCtrl::SetReadOnly( bool bRead ) +{ + // nothing to do? + if (bRead == IsReadOnly()) + // This check is important, as the underlying Def may be unnecessarily locked or unlocked + // or worse, this action may not be reversed afterwards + return; + + bReadOnly = bRead; + + // Disable active cells + sal_Int32 nRow(GetCurRow()); + sal_uInt16 nCol(GetCurColumnId()); + DeactivateCell(); + + // Select the correct Browsers cursor + BrowserMode nMode(BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION | BrowserMode::KEEPHIGHLIGHT | + BrowserMode::HLINES | BrowserMode::VLINES|BrowserMode::AUTOSIZE_LASTCOL); + if( !bReadOnly ) + nMode |= BrowserMode::HIDECURSOR; + SetMode(nMode); + + if( !bReadOnly ) + ActivateCell( nRow, nCol ); +} + +void OTableEditorCtrl::InitCellController() +{ + // Cell Field name + sal_Int32 nMaxTextLen = 0; + OUString sExtraNameChars; + Reference<XConnection> xCon; + try + { + xCon = GetView()->getController().getConnection(); + Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>(); + + // length 0 is treated by Entry::set_max_length as unlimited + nMaxTextLen = xMetaData.is() ? xMetaData->getMaxColumnNameLength() : 0; + + sExtraNameChars = xMetaData.is() ? xMetaData->getExtraNameCharacters() : OUString(); + + } + catch(SQLException&) + { + OSL_FAIL("getMaxColumnNameLength"); + } + + pNameCell = VclPtr<OSQLNameEditControl>::Create(&GetDataWindow(), sExtraNameChars); + pNameCell->get_widget().set_max_length(nMaxTextLen); + pNameCell->setCheck( isSQL92CheckEnabled(xCon) ); + + // Cell type + pTypeCell = VclPtr<ListBoxControl>::Create( &GetDataWindow() ); + + // Cell description + pDescrCell = VclPtr<EditControl>::Create(&GetDataWindow()); + pDescrCell->get_widget().set_max_length(MAX_DESCR_LEN); + + pHelpTextCell = VclPtr<EditControl>::Create(&GetDataWindow()); + pHelpTextCell->get_widget().set_max_length(MAX_DESCR_LEN); + + pNameCell->SetHelpId(HID_TABDESIGN_NAMECELL); + pTypeCell->SetHelpId(HID_TABDESIGN_TYPECELL); + pDescrCell->SetHelpId(HID_TABDESIGN_COMMENTCELL); + pHelpTextCell->SetHelpId(HID_TABDESIGN_HELPTEXT); + + Size aHeight; + const Control* pControls[] = { pTypeCell,pDescrCell,pNameCell,pHelpTextCell}; + for(const Control* pControl : pControls) + { + const Size aTemp(pControl->GetOptimalSize()); + if ( aTemp.Height() > aHeight.Height() ) + aHeight.setHeight( aTemp.Height() ); + } + SetDataRowHeight(aHeight.Height()); + + ClearModified(); +} + +void OTableEditorCtrl::ClearModified() +{ + pNameCell->get_widget().save_value(); + pDescrCell->get_widget().save_value(); + pHelpTextCell->get_widget().save_value(); + pTypeCell->get_widget().save_value(); +} + +OTableEditorCtrl::~OTableEditorCtrl() +{ + disposeOnce(); +} + +void OTableEditorCtrl::dispose() +{ + // Reset the Undo-Manager + GetUndoManager().Clear(); + + m_aInvalidate.Stop(); + + // Take possible Events from the queue + if( nCutEvent ) + Application::RemoveUserEvent( nCutEvent ); + if( nPasteEvent ) + Application::RemoveUserEvent( nPasteEvent ); + if( nDeleteEvent ) + Application::RemoveUserEvent( nDeleteEvent ); + if( nInsNewRowsEvent ) + Application::RemoveUserEvent( nInsNewRowsEvent ); + if( nInvalidateTypeEvent ) + Application::RemoveUserEvent( nInvalidateTypeEvent ); + + // Delete the control types + pNameCell.disposeAndClear(); + pTypeCell.disposeAndClear(); + pDescrCell.disposeAndClear(); + pHelpTextCell.disposeAndClear(); + pDescrWin = nullptr; + m_pView.clear(); + OTableRowView::dispose(); +} + +bool OTableEditorCtrl::SetDataPtr( sal_Int32 nRow ) +{ + if(nRow == -1) + return false; + + OSL_ENSURE(nRow < static_cast<tools::Long>(m_pRowList->size()),"Row is greater than size!"); + if(nRow >= static_cast<tools::Long>(m_pRowList->size())) + return false; + pActRow = (*m_pRowList)[nRow]; + return pActRow != nullptr; +} + +bool OTableEditorCtrl::SeekRow(sal_Int32 _nRow) +{ + // Call the Base class to remember which row must be repainted + EditBrowseBox::SeekRow(_nRow); + + m_nCurrentPos = _nRow; + return SetDataPtr(_nRow); +} + +void OTableEditorCtrl::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, + sal_uInt16 nColumnId ) const +{ + const OUString aText( GetCellText( m_nCurrentPos, nColumnId )); + + rDev.Push( vcl::PushFlags::CLIPREGION ); + rDev.SetClipRegion(vcl::Region(rRect)); + rDev.DrawText( rRect, aText, DrawTextFlags::Left | DrawTextFlags::VCenter ); + rDev.Pop(); +} + +CellController* OTableEditorCtrl::GetController(sal_Int32 nRow, sal_uInt16 nColumnId) +{ + // If EditorCtrl is ReadOnly, editing is forbidden + Reference<XPropertySet> xTable = GetView()->getController().getTable(); + if (IsReadOnly() || ( xTable.is() && + xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_TYPE) && + ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW")) + return nullptr; + + // If the row is ReadOnly, editing is forbidden + SetDataPtr( nRow ); + if( pActRow->IsReadOnly() ) + return nullptr; + + OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr(); + switch (nColumnId) + { + case FIELD_NAME: + return new EditCellController( pNameCell ); + case FIELD_TYPE: + if (pActFieldDescr && !pActFieldDescr->GetName().isEmpty()) + return new ListBoxCellController( pTypeCell ); + else return nullptr; + case HELP_TEXT: + if (pActFieldDescr && !pActFieldDescr->GetName().isEmpty()) + return new EditCellController( pHelpTextCell ); + else + return nullptr; + case COLUMN_DESCRIPTION: + if (pActFieldDescr && !pActFieldDescr->GetName().isEmpty()) + return new EditCellController( pDescrCell ); + else + return nullptr; + default: + return nullptr; + } +} + +void OTableEditorCtrl::InitController(CellControllerRef&, sal_Int32 nRow, sal_uInt16 nColumnId) +{ + SeekRow( nRow == -1 ? GetCurRow() : nRow); + OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr(); + OUString aInitString; + + switch (nColumnId) + { + case FIELD_NAME: + { + if( pActFieldDescr ) + aInitString = pActFieldDescr->GetName(); + + weld::Entry& rEntry = pNameCell->get_widget(); + rEntry.set_text(aInitString); + rEntry.save_value(); + break; + } + case FIELD_TYPE: + { + if ( pActFieldDescr && pActFieldDescr->getTypeInfo() ) + aInitString = pActFieldDescr->getTypeInfo()->aUIName; + + // Set the ComboBox contents + weld::ComboBox& rTypeList = pTypeCell->get_widget(); + rTypeList.clear(); + if( !pActFieldDescr ) + break; + + const OTypeInfoMap& rTypeInfo = GetView()->getController().getTypeInfo(); + for (auto const& elem : rTypeInfo) + rTypeList.append_text(elem.second->aUIName); + rTypeList.set_active_text(aInitString); + } + + break; + case HELP_TEXT: + { + if( pActFieldDescr ) + aInitString = pActFieldDescr->GetHelpText(); + weld::Entry& rEntry = pHelpTextCell->get_widget(); + rEntry.set_text(aInitString); + rEntry.save_value(); + break; + } + case COLUMN_DESCRIPTION: + { + if( pActFieldDescr ) + aInitString = pActFieldDescr->GetDescription(); + weld::Entry& rEntry = pDescrCell->get_widget(); + rEntry.set_text(aInitString); + rEntry.save_value(); + break; + } + } +} + +EditBrowseBox::RowStatus OTableEditorCtrl::GetRowStatus(sal_Int32 nRow) const +{ + const_cast<OTableEditorCtrl*>(this)->SetDataPtr( nRow ); + if( !pActRow ) + return EditBrowseBox::CLEAN; + if (nRow >= 0 && nRow == m_nDataPos) + { + if( pActRow->IsPrimaryKey() ) + return EditBrowseBox::CURRENT_PRIMARYKEY; + return EditBrowseBox::CURRENT; + } + else + { + if( pActRow->IsPrimaryKey() ) + return EditBrowseBox::PRIMARYKEY; + return EditBrowseBox::CLEAN; + } +} + +void OTableEditorCtrl::SaveCurRow() +{ + if (GetFieldDescr(GetCurRow()) == nullptr) + // there is no data in the current row + return; + if (!SaveModified()) + return; + + SetDataPtr(GetCurRow()); + pDescrWin->SaveData( pActRow->GetActFieldDescr() ); +} + +void OTableEditorCtrl::DisplayData(sal_Int32 nRow) +{ + // go to the correct cell + SetDataPtr(nRow); + + // Disable Edit-Mode temporarily + bool bWasEditing = IsEditing(); + if (bWasEditing) + DeactivateCell(); + + CellControllerRef aTemp; + InitController(aTemp, nRow, FIELD_NAME); + InitController(aTemp, nRow, FIELD_TYPE); + InitController(aTemp, nRow, COLUMN_DESCRIPTION); + InitController(aTemp, nRow, HELP_TEXT); + + GoToRow(nRow); + // Update the Description-Window + GetView()->GetDescWin()->DisplayData(GetFieldDescr(nRow)); + // redraw the row + RowModified(nRow); + + // and re-enable edit mode + ActivateCell(nRow, GetCurColumnId()); +} + +void OTableEditorCtrl::CursorMoved() +{ + // New line? + m_nDataPos = GetCurRow(); + if( m_nDataPos != nOldDataPos && m_nDataPos != -1) + { + CellControllerRef aTemp; + InitController(aTemp,m_nDataPos,FIELD_NAME); + InitController(aTemp,m_nDataPos,FIELD_TYPE); + InitController(aTemp,m_nDataPos,COLUMN_DESCRIPTION); + InitController(aTemp,m_nDataPos,HELP_TEXT); + } + + OTableRowView::CursorMoved(); +} + +sal_Int32 OTableEditorCtrl::HasFieldName( std::u16string_view rFieldName ) +{ + + Reference<XConnection> xCon = GetView()->getController().getConnection(); + Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>(); + + ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers()); + + sal_Int32 nCount(0); + for (auto const& row : *m_pRowList) + { + OFieldDescription* pFieldDescr = row->GetActFieldDescr(); + if( pFieldDescr && bCase(rFieldName,pFieldDescr->GetName())) + nCount++; + } + return nCount; +} + +void OTableEditorCtrl::SaveData(sal_Int32 nRow, sal_uInt16 nColId) +{ + // Store the cell content + SetDataPtr( nRow == -1 ? GetCurRow() : nRow); + OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr(); + + switch( nColId) + { + // Store NameCell + case FIELD_NAME: + { + // If there is no name, do nothing + weld::Entry& rEntry = pNameCell->get_widget(); + const OUString aName(rEntry.get_text()); + + if( aName.isEmpty() ) + { + // If FieldDescr exists, the field is deleted and the old content restored + if (pActFieldDescr) + { + GetUndoManager().AddUndoAction(std::make_unique<OTableEditorTypeSelUndoAct>(this, nRow, FIELD_TYPE, pActFieldDescr->getTypeInfo())); + SwitchType(TOTypeInfoSP()); + pActFieldDescr = pActRow->GetActFieldDescr(); + } + else + return; + } + if(pActFieldDescr) + pActFieldDescr->SetName( aName ); + rEntry.save_value(); + + break; + } + + // Store the field type + case FIELD_TYPE: + break; + + // Store DescrCell + case HELP_TEXT: + { + // if the current field description is NULL, set Default + weld::Entry& rEntry = pHelpTextCell->get_widget(); + if( !pActFieldDescr ) + { + rEntry.set_text(OUString()); + rEntry.save_value(); + } + else + pActFieldDescr->SetHelpText(rEntry.get_text()); + break; + } + case COLUMN_DESCRIPTION: + { + // Set the default if the field description is null + weld::Entry& rEntry = pDescrCell->get_widget(); + if( !pActFieldDescr ) + { + rEntry.set_text(OUString()); + rEntry.save_value(); + } + else + pActFieldDescr->SetDescription(rEntry.get_text()); + break; + } + case FIELD_PROPERTY_DEFAULT: + case FIELD_PROPERTY_REQUIRED: + case FIELD_PROPERTY_TEXTLEN: + case FIELD_PROPERTY_NUMTYPE: + case FIELD_PROPERTY_AUTOINC: + case FIELD_PROPERTY_LENGTH: + case FIELD_PROPERTY_SCALE: + case FIELD_PROPERTY_BOOL_DEFAULT: + pDescrWin->SaveData(pActFieldDescr); + + if ( FIELD_PROPERTY_AUTOINC == nColId && pActFieldDescr->IsAutoIncrement() ) + { + OTableController& rController = GetView()->getController(); + if ( rController.isAutoIncrementPrimaryKey() ) + { + pActFieldDescr->SetPrimaryKey( true ); + InvalidateHandleColumn(); + Invalidate(); + } + } + break; + } +} + +bool OTableEditorCtrl::SaveModified() +{ + sal_uInt16 nColId = GetCurColumnId(); + + switch( nColId ) + { + // Field type + case FIELD_TYPE: + { + // Reset the type + resetType(); + } break; + } + + return true; +} + +bool OTableEditorCtrl::CursorMoving(sal_Int32 nNewRow, sal_uInt16 nNewCol) +{ + + if (!EditBrowseBox::CursorMoving(nNewRow, nNewCol)) + return false; + + // Called after SaveModified(), current row is still the old one + m_nDataPos = nNewRow; + nOldDataPos = GetCurRow(); + + // Reset the markers + InvalidateStatusCell( nOldDataPos ); + InvalidateStatusCell( m_nDataPos ); + + // Store the data from the Property window + if( SetDataPtr(nOldDataPos) && pDescrWin) + pDescrWin->SaveData( pActRow->GetActFieldDescr() ); + + // Show new data in the Property window + if( SetDataPtr(m_nDataPos) && pDescrWin) + pDescrWin->DisplayData( pActRow->GetActFieldDescr() ); + + return true; +} + +IMPL_LINK_NOARG( OTableEditorCtrl, InvalidateFieldType, void*, void ) +{ + nInvalidateTypeEvent = nullptr; + Invalidate( GetFieldRectPixel(nOldDataPos, FIELD_TYPE) ); +} + +void OTableEditorCtrl::CellModified( sal_Int32 nRow, sal_uInt16 nColId ) +{ + + // If the description is null, use the default + if(nRow == -1) + nRow = GetCurRow(); + SetDataPtr( nRow ); + OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr(); + + OUString sActionDescription; + switch ( nColId ) + { + case FIELD_NAME: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_NAME ); break; + case FIELD_TYPE: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_TYPE ); break; + case HELP_TEXT: + case COLUMN_DESCRIPTION: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_DESCRIPTION ); break; + default: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_ATTRIBUTE ); break; + } + + GetUndoManager().EnterListAction( sActionDescription, OUString(), 0, ViewShellId(-1) ); + if (!pActFieldDescr) + { + const OTypeInfoMap& rTypeInfoMap = GetView()->getController().getTypeInfo(); + if ( !rTypeInfoMap.empty() ) + { + OTypeInfoMap::const_iterator aTypeIter = rTypeInfoMap.find(DataType::VARCHAR); + if ( aTypeIter == rTypeInfoMap.end() ) + aTypeIter = rTypeInfoMap.begin(); + pActRow->SetFieldType( aTypeIter->second ); + } + else + pActRow->SetFieldType( GetView()->getController().getTypeInfoFallBack() ); + + nInvalidateTypeEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, InvalidateFieldType), nullptr, true ); + pActFieldDescr = pActRow->GetActFieldDescr(); + pDescrWin->DisplayData( pActFieldDescr ); + GetUndoManager().AddUndoAction( std::make_unique<OTableEditorTypeSelUndoAct>(this, nRow, nColId+1, TOTypeInfoSP()) ); + } + + if( nColId != FIELD_TYPE ) + GetUndoManager().AddUndoAction( std::make_unique<OTableDesignCellUndoAct>(this, nRow, nColId) ); + else + { + GetUndoManager().AddUndoAction(std::make_unique<OTableEditorTypeSelUndoAct>(this, GetCurRow(), nColId, GetFieldDescr(GetCurRow())->getTypeInfo())); + resetType(); + } + + SaveData(nRow,nColId); + // SaveData could create an undo action as well + GetUndoManager().LeaveListAction(); + RowModified(nRow); + + // Set the Modify flag + GetView()->getController().setModified( true ); + InvalidateFeatures(); +} + +void OTableEditorCtrl::resetType() +{ + sal_Int32 nPos = pTypeCell->get_widget().get_active(); + if(nPos != -1) + SwitchType( GetView()->getController().getTypeInfo(nPos) ); + else + SwitchType(TOTypeInfoSP()); +} + +void OTableEditorCtrl::CellModified() +{ + CellModified( GetCurRow(), GetCurColumnId() ); +} + +void OTableEditorCtrl::InvalidateFeatures() +{ + GetView()->getController().InvalidateFeature(SID_UNDO); + GetView()->getController().InvalidateFeature(SID_REDO); + GetView()->getController().InvalidateFeature(SID_SAVEDOC); +} + +void OTableEditorCtrl::CopyRows() +{ + // set to the right row and save it + if( SetDataPtr(m_nDataPos) ) + pDescrWin->SaveData( pActRow->GetActFieldDescr() ); + + // Copy selected rows to the ClipboardList + std::shared_ptr<OTableRow> pClipboardRow; + std::shared_ptr<OTableRow> pRow; + std::vector< std::shared_ptr<OTableRow> > vClipboardList; + vClipboardList.reserve(GetSelectRowCount()); + + for( tools::Long nIndex=FirstSelectedRow(); nIndex != SFX_ENDOFSELECTION; nIndex=NextSelectedRow() ) + { + pRow = (*m_pRowList)[nIndex]; + OSL_ENSURE(pRow,"OTableEditorCtrl::CopyRows: Row is NULL!"); + if ( pRow && pRow->GetActFieldDescr() ) + { + pClipboardRow = std::make_shared<OTableRow>( *pRow ); + vClipboardList.push_back( pClipboardRow); + } + } + if(!vClipboardList.empty()) + { + rtl::Reference<OTableRowExchange> pData = new OTableRowExchange(std::move(vClipboardList)); + pData->CopyToClipboard(GetParent()); + } +} + +OUString OTableEditorCtrl::GenerateName( const OUString& rName ) +{ + // Create a base name for appending numbers to + OUString aBaseName; + Reference<XConnection> xCon = GetView()->getController().getConnection(); + Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>(); + + sal_Int32 nMaxTextLen(xMetaData.is() ? xMetaData->getMaxColumnNameLength() : 0); + + if( (rName.getLength()+2) >nMaxTextLen ) + aBaseName = rName.copy( 0, nMaxTextLen-2 ); + else + aBaseName = rName; + + // append a sequential number to the base name (up to 99) + OUString aFieldName( rName); + sal_Int32 i=1; + while( HasFieldName(aFieldName) ) + { + aFieldName = aBaseName + OUString::number(i); + i++; + } + + return aFieldName; +} + +void OTableEditorCtrl::InsertRows( sal_Int32 nRow ) +{ + + std::vector< std::shared_ptr<OTableRow> > vInsertedUndoRedoRows; // need for undo/redo handling + // get rows from clipboard + TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent())); + if(aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED)) + { + ::tools::SvRef<SotTempStream> aStreamRef; + bool bOk = aTransferData.GetSotStorageStream(SotClipboardFormatId::SBA_TABED,aStreamRef); + if (bOk && aStreamRef.is()) + { + aStreamRef->Seek(STREAM_SEEK_TO_BEGIN); + aStreamRef->ResetError(); + sal_Int32 nInsertRow = nRow; + std::shared_ptr<OTableRow> pRow; + sal_Int32 nSize = 0; + (*aStreamRef).ReadInt32( nSize ); + vInsertedUndoRedoRows.reserve(nSize); + for(sal_Int32 i=0;i < nSize;++i) + { + pRow = std::make_shared<OTableRow>(); + ReadOTableRow( *aStreamRef, *pRow ); + pRow->SetReadOnly( false ); + sal_Int32 nType = pRow->GetActFieldDescr()->GetType(); + if ( pRow->GetActFieldDescr() ) + pRow->GetActFieldDescr()->SetType(GetView()->getController().getTypeInfoByType(nType)); + // Adjust the field names + pRow->GetActFieldDescr()->SetName( GenerateName( pRow->GetActFieldDescr()->GetName() ) ); + pRow->SetPos(nInsertRow); + m_pRowList->insert( m_pRowList->begin()+nInsertRow,pRow ); + vInsertedUndoRedoRows.push_back(std::make_shared<OTableRow>(*pRow)); + nInsertRow++; + } + } + } + // RowInserted calls CursorMoved. + // The UI data should not be stored here. + RowInserted( nRow,vInsertedUndoRedoRows.size() ); + + // Create the Undo-Action + GetUndoManager().AddUndoAction( std::make_unique<OTableEditorInsUndoAct>(this, nRow, std::move(vInsertedUndoRedoRows)) ); + GetView()->getController().setModified( true ); + InvalidateFeatures(); +} + +void OTableEditorCtrl::DeleteRows() +{ + OSL_ENSURE(GetView()->getController().isDropAllowed(),"Call of DeleteRows not valid here. Please check isDropAllowed!"); + // Create the Undo-Action + GetUndoManager().AddUndoAction( std::make_unique<OTableEditorDelUndoAct>(this) ); + + // Delete all marked rows + tools::Long nIndex = FirstSelectedRow(); + nOldDataPos = nIndex; + + while( nIndex != SFX_ENDOFSELECTION ) + { + // Remove rows + m_pRowList->erase( m_pRowList->begin()+nIndex ); + RowRemoved( nIndex ); + + // Insert the empty row at the end + m_pRowList->push_back( std::make_shared<OTableRow>()); + RowInserted( GetRowCount()-1 ); + + nIndex = FirstSelectedRow(); + } + + // Force the current record to be displayed + m_nDataPos = GetCurRow(); + InvalidateStatusCell( nOldDataPos ); + InvalidateStatusCell( m_nDataPos ); + SetDataPtr( m_nDataPos ); + ActivateCell(); + pDescrWin->DisplayData( pActRow->GetActFieldDescr() ); + GetView()->getController().setModified( true ); + InvalidateFeatures(); +} + +void OTableEditorCtrl::InsertNewRows( sal_Int32 nRow ) +{ + OSL_ENSURE(GetView()->getController().isAddAllowed(),"Call of InsertNewRows not valid here. Please check isAppendAllowed!"); + // Create Undo-Action + sal_Int32 nInsertRows = GetSelectRowCount(); + if( !nInsertRows ) + nInsertRows = 1; + GetUndoManager().AddUndoAction( std::make_unique<OTableEditorInsNewUndoAct>(this, nRow, nInsertRows) ); + // Insert the number of selected rows + for( tools::Long i=nRow; i<(nRow+nInsertRows); i++ ) + m_pRowList->insert( m_pRowList->begin()+i ,std::make_shared<OTableRow>()); + RowInserted( nRow, nInsertRows ); + + GetView()->getController().setModified( true ); + InvalidateFeatures(); +} + +void OTableEditorCtrl::SetControlText( sal_Int32 nRow, sal_uInt16 nColId, const OUString& rText ) +{ + // Set the Browser Controls + if( nColId < FIELD_FIRST_VIRTUAL_COLUMN ) + { + GoToRow( nRow ); + GoToColumnId( nColId ); + CellControllerRef xController = Controller(); + if(xController.is()) + xController->GetWindow().SetText( rText ); + else + RowModified(nRow,nColId); + } + + // Set the Tabpage controls + else + { + pDescrWin->SetControlText( nColId, rText ); + } +} + +void OTableEditorCtrl::SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const TOTypeInfoSP& _pTypeInfo ) +{ + // Relocate the current pointer + if( nRow == -1 ) + nRow = GetCurRow(); + OFieldDescription* pFieldDescr = GetFieldDescr( nRow ); + if( !pFieldDescr && nColId != FIELD_TYPE) + return; + + // Set individual fields + switch( nColId ) + { + case FIELD_TYPE: + SwitchType( _pTypeInfo ); + break; + default: + OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!"); + } + SetControlText(nRow,nColId,_pTypeInfo ? _pTypeInfo->aUIName : OUString()); +} + +void OTableEditorCtrl::SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const css::uno::Any& _rNewData ) +{ + // Relocate the current pointer + if( nRow == -1 ) + nRow = GetCurRow(); + OFieldDescription* pFieldDescr = GetFieldDescr( nRow ); + if( !pFieldDescr && nColId != FIELD_TYPE) + return; + + OUString sValue; + // Set individual fields + switch( nColId ) + { + case FIELD_NAME: + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetName( sValue ); + break; + + case FIELD_TYPE: + OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!"); + break; + + case COLUMN_DESCRIPTION: + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetDescription( sValue ); + break; + + case FIELD_PROPERTY_DEFAULT: + pFieldDescr->SetControlDefault( _rNewData ); + sValue = GetView()->GetDescWin()->getGenPage()->getControlDefault(pFieldDescr); + break; + + case FIELD_PROPERTY_REQUIRED: + { + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetIsNullable( sValue.toInt32() ); + } + break; + + case FIELD_PROPERTY_TEXTLEN: + case FIELD_PROPERTY_LENGTH: + { + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetPrecision( sValue.toInt32() ); + } + break; + + case FIELD_PROPERTY_NUMTYPE: + OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!"); + break; + + case FIELD_PROPERTY_AUTOINC: + { + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetAutoIncrement(sValue == DBA_RES(STR_VALUE_YES)); + } + break; + case FIELD_PROPERTY_SCALE: + { + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetScale(sValue.toInt32()); + } + break; + + case FIELD_PROPERTY_BOOL_DEFAULT: + sValue = GetView()->GetDescWin()->BoolStringPersistent(::comphelper::getString(_rNewData)); + pFieldDescr->SetControlDefault(Any(sValue)); + break; + + case FIELD_PROPERTY_FORMAT: + { + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetFormatKey(sValue.toInt32()); + } + break; + } + + SetControlText(nRow,nColId,sValue); +} + +Any OTableEditorCtrl::GetCellData( sal_Int32 nRow, sal_uInt16 nColId ) +{ + OFieldDescription* pFieldDescr = GetFieldDescr( nRow ); + if( !pFieldDescr ) + return Any(); + + // Relocate the current pointer + if( nRow==-1 ) + nRow = GetCurRow(); + SetDataPtr( nRow ); + + static const OUString strYes(DBA_RES(STR_VALUE_YES)); + static const OUString strNo(DBA_RES(STR_VALUE_NO)); + OUString sValue; + // Read out the fields + switch( nColId ) + { + case FIELD_NAME: + sValue = pFieldDescr->GetName(); + break; + + case FIELD_TYPE: + if ( pFieldDescr->getTypeInfo() ) + sValue = pFieldDescr->getTypeInfo()->aUIName; + break; + + case COLUMN_DESCRIPTION: + sValue = pFieldDescr->GetDescription(); + break; + case HELP_TEXT: + sValue = pFieldDescr->GetHelpText(); + break; + + case FIELD_PROPERTY_DEFAULT: + return pFieldDescr->GetControlDefault(); + + case FIELD_PROPERTY_REQUIRED: + sValue = pFieldDescr->GetIsNullable() == ColumnValue::NULLABLE ? strYes : strNo; + break; + + case FIELD_PROPERTY_TEXTLEN: + case FIELD_PROPERTY_LENGTH: + sValue = OUString::number(pFieldDescr->GetPrecision()); + break; + + case FIELD_PROPERTY_NUMTYPE: + OSL_FAIL("OTableEditorCtrl::GetCellData: invalid column!"); + break; + + case FIELD_PROPERTY_AUTOINC: + sValue = pFieldDescr->IsAutoIncrement() ? strYes : strNo; + break; + + case FIELD_PROPERTY_SCALE: + sValue = OUString::number(pFieldDescr->GetScale()); + break; + + case FIELD_PROPERTY_BOOL_DEFAULT: + sValue = GetView()->GetDescWin()->BoolStringUI(::comphelper::getString(pFieldDescr->GetControlDefault())); + break; + + case FIELD_PROPERTY_FORMAT: + sValue = OUString::number(pFieldDescr->GetFormatKey()); + break; + } + + return Any(sValue); +} + +OUString OTableEditorCtrl::GetCellText( sal_Int32 nRow, sal_uInt16 nColId ) const +{ + OUString sCellText; + const_cast< OTableEditorCtrl* >( this )->GetCellData( nRow, nColId ) >>= sCellText; + return sCellText; +} + +sal_uInt32 OTableEditorCtrl::GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId) +{ + return GetTextWidth(GetCellText(nRow, nColId)) + 2 * GetTextWidth("0"); +} + +OFieldDescription* OTableEditorCtrl::GetFieldDescr( sal_Int32 nRow ) +{ + std::vector< std::shared_ptr<OTableRow> >::size_type nListCount( + m_pRowList->size()); + if( (nRow<0) || (sal::static_int_cast< unsigned long >(nRow)>=nListCount) ) + { + OSL_FAIL("(nRow<0) || (nRow>=nListCount)"); + return nullptr; + } + std::shared_ptr<OTableRow> pRow = (*m_pRowList)[ nRow ]; + if( !pRow ) + return nullptr; + return pRow->GetActFieldDescr(); +} + +bool OTableEditorCtrl::IsCutAllowed() +{ + bool bIsCutAllowed = (GetView()->getController().isAddAllowed() && GetView()->getController().isDropAllowed()) || + GetView()->getController().isAlterAllowed(); + + if (bIsCutAllowed) + { + int nStartPos, nEndPos; + switch(m_eChildFocus) + { + case DESCRIPTION: + { + weld::Entry& rEntry = pDescrCell->get_widget(); + bIsCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos); + break; + } + case HELPTEXT: + { + weld::Entry& rEntry = pHelpTextCell->get_widget(); + bIsCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos); + break; + } + case NAME: + { + weld::Entry& rEntry = pNameCell->get_widget(); + bIsCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos); + break; + } + case ROW: + bIsCutAllowed = IsCopyAllowed(); + break; + default: + bIsCutAllowed = false; + break; + } + } + + return bIsCutAllowed; +} + +bool OTableEditorCtrl::IsCopyAllowed() +{ + bool bIsCopyAllowed = false; + int nStartPos, nEndPos; + if (m_eChildFocus == DESCRIPTION ) + { + weld::Entry& rEntry = pDescrCell->get_widget(); + bIsCopyAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos); + } + else if(HELPTEXT == m_eChildFocus ) + { + weld::Entry& rEntry = pHelpTextCell->get_widget(); + bIsCopyAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos); + } + else if(m_eChildFocus == NAME) + { + weld::Entry& rEntry = pNameCell->get_widget(); + bIsCopyAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos); + } + else if(m_eChildFocus == ROW) + { + Reference<XPropertySet> xTable = GetView()->getController().getTable(); + if( !GetSelectRowCount() || (xTable.is() && ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW")) + return false; + + // If one of the selected rows is empty, Copy is not possible + std::shared_ptr<OTableRow> pRow; + tools::Long nIndex = FirstSelectedRow(); + while( nIndex != SFX_ENDOFSELECTION ) + { + pRow = (*m_pRowList)[nIndex]; + if( !pRow->GetActFieldDescr() ) + return false; + + nIndex = NextSelectedRow(); + } + + bIsCopyAllowed = true; + } + + return bIsCopyAllowed; +} + +bool OTableEditorCtrl::IsPasteAllowed() const +{ + bool bAllowed = GetView()->getController().isAddAllowed(); + if ( bAllowed ) + { + TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent())); + bool bRowFormat = aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED); + if ( m_eChildFocus == ROW ) + bAllowed = bRowFormat; + else + bAllowed = !bRowFormat && aTransferData.HasFormat(SotClipboardFormatId::STRING); + } + + return bAllowed; +} + +void OTableEditorCtrl::cut() +{ + if(m_eChildFocus == NAME) + { + if(GetView()->getController().isAlterAllowed()) + { + SaveData(-1,FIELD_NAME); + pNameCell->get_widget().cut_clipboard(); + CellModified(-1,FIELD_NAME); + } + } + else if(m_eChildFocus == DESCRIPTION) + { + if(GetView()->getController().isAlterAllowed()) + { + SaveData(-1,COLUMN_DESCRIPTION); + pDescrCell->get_widget().cut_clipboard(); + CellModified(-1,COLUMN_DESCRIPTION); + } + } + else if(HELPTEXT == m_eChildFocus ) + { + if(GetView()->getController().isAlterAllowed()) + { + SaveData(-1,HELP_TEXT); + pHelpTextCell->get_widget().cut_clipboard(); + CellModified(-1,HELP_TEXT); + } + } + else if(m_eChildFocus == ROW) + { + if (nCutEvent) + Application::RemoveUserEvent(nCutEvent); + nCutEvent = Application::PostUserEvent(LINK(this, OTableEditorCtrl, DelayedCut), nullptr, true); + } +} + +void OTableEditorCtrl::copy() +{ + if (GetSelectRowCount()) + OTableRowView::copy(); + else if(m_eChildFocus == NAME) + { + weld::Entry& rEntry = pNameCell->get_widget(); + rEntry.copy_clipboard(); + } + else if(HELPTEXT == m_eChildFocus ) + { + weld::Entry& rEntry = pHelpTextCell->get_widget(); + rEntry.copy_clipboard(); + } + else if(m_eChildFocus == DESCRIPTION ) + { + weld::Entry& rEntry = pDescrCell->get_widget(); + rEntry.copy_clipboard(); + } +} + +void OTableEditorCtrl::paste() +{ + TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent())); + if(aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED)) + { + if( nPasteEvent ) + Application::RemoveUserEvent( nPasteEvent ); + nPasteEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, DelayedPaste), nullptr, true ); + } + else if(m_eChildFocus == NAME) + { + if(GetView()->getController().isAlterAllowed()) + { + pNameCell->get_widget().paste_clipboard(); + CellModified(); + } + } + else if(HELPTEXT == m_eChildFocus ) + { + if(GetView()->getController().isAlterAllowed()) + { + pHelpTextCell->get_widget().paste_clipboard(); + CellModified(); + } + } + else if(m_eChildFocus == DESCRIPTION) + { + if(GetView()->getController().isAlterAllowed()) + { + pDescrCell->get_widget().paste_clipboard(); + CellModified(); + } + } +} + +bool OTableEditorCtrl::IsDeleteAllowed() +{ + + return GetSelectRowCount() != 0 && GetView()->getController().isDropAllowed(); +} + +bool OTableEditorCtrl::IsInsertNewAllowed( sal_Int32 nRow ) +{ + + bool bInsertNewAllowed = GetView()->getController().isAddAllowed(); + // If fields can be added, Paste in the new fields + if (bInsertNewAllowed && !GetView()->getController().isDropAllowed()) + { + SetDataPtr(nRow); + if( GetActRow()->IsReadOnly() ) + return false; + } + + return bInsertNewAllowed; +} + +bool OTableEditorCtrl::IsPrimaryKeyAllowed() +{ + if( !GetSelectRowCount() ) + return false; + + OTableController& rController = GetView()->getController(); + if ( !rController.getSdbMetaData().supportsPrimaryKeys() ) + return false; + + Reference<XPropertySet> xTable = rController.getTable(); + // Key must not be changed + // This applies only if the table is not new and not a css::sdbcx::View. Otherwise no DROP is executed + + if(xTable.is() && ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW") + return false; + // If there is an empty field, no primary key + // The entry is only permitted if + // - there are no empty entries in the selection + // - No Memo or Image entries + // - DROP is not permitted (see above) and the column is not Required (not null flag is not set). + tools::Long nIndex = FirstSelectedRow(); + std::shared_ptr<OTableRow> pRow; + while( nIndex != SFX_ENDOFSELECTION ) + { + pRow = (*m_pRowList)[nIndex]; + OFieldDescription* pFieldDescr = pRow->GetActFieldDescr(); + if(!pFieldDescr) + return false; + else + { + // Memo and Image fields cannot be primary keys + // or if the column cannot be dropped and the Required flag is not set + // or if a css::sdbcx::View is available and the Required flag is not set + const TOTypeInfoSP& pTypeInfo = pFieldDescr->getTypeInfo(); + if( pTypeInfo->nSearchType == ColumnSearch::NONE + || (pFieldDescr->IsNullable() && pRow->IsReadOnly()) + ) + return false; + } + + nIndex = NextSelectedRow(); + } + + return true; +} + +void OTableEditorCtrl::Command(const CommandEvent& rEvt) +{ + switch (rEvt.GetCommand()) + { + case CommandEventId::ContextMenu: + { + Point aMenuPos( rEvt.GetMousePosPixel() ); + if (!rEvt.IsMouseEvent()) + { + if ( 1 == GetSelectColumnCount() ) + { + sal_uInt16 nSelId = GetColumnId( + sal::static_int_cast< sal_uInt16 >( + FirstSelectedColumn() ) ); + ::tools::Rectangle aColRect( GetFieldRectPixel( 0, nSelId, false ) ); + + aMenuPos = aColRect.TopCenter(); + } + else if ( GetSelectRowCount() > 0 ) + { + ::tools::Rectangle aColRect( GetFieldRectPixel( FirstSelectedRow(), HANDLE_ID ) ); + + aMenuPos = aColRect.TopCenter(); + } + else + { + OTableRowView::Command(rEvt); + return; + } + } + + // Show the Context menu + if( !IsReadOnly() ) + { + sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(aMenuPos.X())); + sal_Int32 nRow = GetRowAtYPosPixel(aMenuPos.Y()); + + if ( HANDLE_ID != nColId ) + { + if ( nRow < 0 && nColId != BROWSER_INVALIDID ) + { // hit the header + if ( 3 != nColId ) + { // 3 would mean the last column, and this last column is auto-sized + if ( !IsColumnSelected( nColId ) ) + SelectColumnId( nColId ); + + ::tools::Rectangle aRect(aMenuPos, Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/querycolmenu.ui")); + std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu")); + xContextMenu->remove("delete"); + xContextMenu->remove("separator"); + if (xContextMenu->popup_at_rect(pPopupParent, aRect) == "width") + adjustBrowseBoxColumnWidth( this, nColId ); + } + } + } + else + { + ::tools::Rectangle aRect(aMenuPos, Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/tabledesignrowmenu.ui")); + std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu")); + + if (!IsCutAllowed()) + xContextMenu->remove("cut"); + if (!IsCopyAllowed()) + xContextMenu->remove("copy"); + if (!IsPasteAllowed()) + xContextMenu->remove("paste"); + if (!IsDeleteAllowed()) + xContextMenu->remove("delete"); + if (!IsPrimaryKeyAllowed()) + xContextMenu->remove("primarykey"); + if (!IsInsertNewAllowed(nRow)) + xContextMenu->remove("insert"); + xContextMenu->set_active("primarykey", IsRowSelected(GetCurRow()) && IsPrimaryKey()); + + if( SetDataPtr(m_nDataPos) ) + pDescrWin->SaveData( pActRow->GetActFieldDescr() ); + + // All actions which change the number of rows must be run asynchronously + // otherwise there may be problems between the Context menu and the Browser + m_nDataPos = GetCurRow(); + OString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect); + if (sIdent == "cut") + cut(); + else if (sIdent == "copy") + copy(); + else if (sIdent == "paste") + paste(); + else if (sIdent == "delete") + { + if( nDeleteEvent ) + Application::RemoveUserEvent( nDeleteEvent ); + nDeleteEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, DelayedDelete), nullptr, true ); + } + else if (sIdent == "insert") + { + if( nInsNewRowsEvent ) + Application::RemoveUserEvent( nInsNewRowsEvent ); + nInsNewRowsEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, DelayedInsNewRows), nullptr, true ); + } + else if (sIdent == "primarykey") + { + SetPrimaryKey( !IsPrimaryKey() ); + } + } + } + } + break; + default: + OTableRowView::Command(rEvt); + } + +} + +IMPL_LINK_NOARG( OTableEditorCtrl, DelayedCut, void*, void ) +{ + nCutEvent = nullptr; + OTableRowView::cut(); +} + +IMPL_LINK_NOARG( OTableEditorCtrl, DelayedPaste, void*, void ) +{ + nPasteEvent = nullptr; + + sal_Int32 nPastePosition = GetView()->getController().getFirstEmptyRowPosition(); + if ( !GetView()->getController().getTable().is() ) + nPastePosition = GetSelectRowCount() ? FirstSelectedRow() : GetCurRow(); + + if (!IsInsertNewAllowed(nPastePosition)) + { // Insertion is not allowed, only appending, so test if there are full cells after the PastePosition + + auto aIter = std::find_if(m_pRowList->rbegin(), m_pRowList->rend(), [](const std::shared_ptr<OTableRow>& rxRow) { + return rxRow && rxRow->GetActFieldDescr() && !rxRow->GetActFieldDescr()->GetName().isEmpty(); }); + auto nFreeFromPos = static_cast<sal_Int32>(std::distance(aIter, m_pRowList->rend())); // from here on there are only empty rows + if (nPastePosition < nFreeFromPos) // if at least one PastePosition is full, go right to the end + nPastePosition = nFreeFromPos; + } + + OTableRowView::Paste( nPastePosition ); + SetNoSelection(); + GoToRow( nPastePosition ); +} + +IMPL_LINK_NOARG( OTableEditorCtrl, DelayedDelete, void*, void ) +{ + nDeleteEvent = nullptr; + DeleteRows(); +} + +IMPL_LINK_NOARG( OTableEditorCtrl, DelayedInsNewRows, void*, void ) +{ + nInsNewRowsEvent = nullptr; + sal_Int32 nPastePosition = GetView()->getController().getFirstEmptyRowPosition(); + if ( !GetView()->getController().getTable().is() ) + nPastePosition = GetSelectRowCount() ? FirstSelectedRow() : m_nDataPos; + + InsertNewRows( nPastePosition ); + SetNoSelection(); + GoToRow( nPastePosition ); +} + +void OTableEditorCtrl::AdjustFieldDescription(OFieldDescription* _pFieldDesc, + MultiSelection& _rMultiSel, + sal_Int32 _nPos, + bool _bSet, + bool _bPrimaryKey) +{ + _pFieldDesc->SetPrimaryKey( _bPrimaryKey ); + if(!_bSet && _pFieldDesc->getTypeInfo()->bNullable) + { + _pFieldDesc->SetIsNullable(ColumnValue::NO_NULLS); + _pFieldDesc->SetControlDefault(Any()); + } + if ( _pFieldDesc->IsAutoIncrement() && !_bPrimaryKey ) + { + OTableController& rController = GetView()->getController(); + if ( rController.isAutoIncrementPrimaryKey() ) + { + _pFieldDesc->SetAutoIncrement(false); + } + } + // update field description + pDescrWin->DisplayData(_pFieldDesc); + + _rMultiSel.Insert( _nPos ); + _rMultiSel.Select( _nPos ); +} + +void OTableEditorCtrl::SetPrimaryKey( bool bSet ) +{ + // Delete any existing Primary Keys + MultiSelection aDeletedPrimKeys; + aDeletedPrimKeys.SetTotalRange( Range(0,GetRowCount()) ); + + sal_Int32 nRow = 0; + for (auto const& row : *m_pRowList) + { + OFieldDescription* pFieldDescr = row->GetActFieldDescr(); + if( pFieldDescr && row->IsPrimaryKey() && (!bSet || !IsRowSelected(nRow)) ) + { + AdjustFieldDescription(pFieldDescr,aDeletedPrimKeys,nRow,bSet,false); + } + ++nRow; + } + + // Set the primary keys of the marked rows + MultiSelection aInsertedPrimKeys; + aInsertedPrimKeys.SetTotalRange( Range(0,GetRowCount()) ); + if( bSet ) + { + tools::Long nIndex = FirstSelectedRow(); + while( nIndex != SFX_ENDOFSELECTION ) + { + // Set the key + std::shared_ptr<OTableRow> pRow = (*m_pRowList)[nIndex]; + OFieldDescription* pFieldDescr = pRow->GetActFieldDescr(); + if(pFieldDescr) + AdjustFieldDescription(pFieldDescr,aInsertedPrimKeys,nIndex,false,true); + + nIndex = NextSelectedRow(); + } + } + + GetUndoManager().AddUndoAction( std::make_unique<OPrimKeyUndoAct>(this, aDeletedPrimKeys, aInsertedPrimKeys) ); + + // Invalidate the handle-columns + InvalidateHandleColumn(); + + // Set the TableDocSh's ModifyFlag + GetView()->getController().setModified( true ); + InvalidateFeatures(); +} + +bool OTableEditorCtrl::IsPrimaryKey() +{ + // Are all marked fields part of the Primary Key ? + tools::Long nPrimaryKeys = 0; + sal_Int32 nRow=0; + for (auto const& row : *m_pRowList) + { + if( IsRowSelected(nRow) && !row->IsPrimaryKey() ) + return false; + if( row->IsPrimaryKey() ) + ++nPrimaryKeys; + ++nRow; + } + + // Are there any unselected fields that are part of the Key ? + return GetSelectRowCount() == nPrimaryKeys; +} + +void OTableEditorCtrl::SwitchType( const TOTypeInfoSP& _pType ) +{ + // if there is no assigned field name + sal_Int32 nRow(GetCurRow()); + OFieldDescription* pActFieldDescr = GetFieldDescr( nRow ); + if( pActFieldDescr ) + // Store the old description + pDescrWin->SaveData( pActFieldDescr ); + + if ( nRow < 0 || o3tl::make_unsigned(nRow) > m_pRowList->size() ) + return; + // Show the new description + std::shared_ptr<OTableRow> pRow = (*m_pRowList)[nRow]; + pRow->SetFieldType( _pType, true ); + if ( _pType ) + { + weld::ComboBox& rTypeList = pTypeCell->get_widget(); + const sal_Int32 nCurrentlySelected = rTypeList.get_active(); + + if ( ( nCurrentlySelected == -1 ) + || ( GetView()->getController().getTypeInfo( nCurrentlySelected ) != _pType ) + ) + { + sal_Int32 nEntryPos = 0; + const OTypeInfoMap& rTypeInfo = GetView()->getController().getTypeInfo(); + for (auto const& elem : rTypeInfo) + { + if(elem.second == _pType) + break; + ++nEntryPos; + } + if (nEntryPos < rTypeList.get_count()) + rTypeList.set_active(nEntryPos); + } + } + + pActFieldDescr = pRow->GetActFieldDescr(); + if (pActFieldDescr != nullptr && !pActFieldDescr->GetFormatKey()) + { + sal_Int32 nFormatKey = ::dbtools::getDefaultNumberFormat( pActFieldDescr->GetType(), + pActFieldDescr->GetScale(), + pActFieldDescr->IsCurrency(), + Reference< XNumberFormatTypes>(GetView()->getController().getNumberFormatter()->getNumberFormatsSupplier()->getNumberFormats(),UNO_QUERY), + GetView()->getLocale()); + + pActFieldDescr->SetFormatKey(nFormatKey); + } + + pDescrWin->DisplayData( pActFieldDescr ); +} + +OTableDesignView* OTableEditorCtrl::GetView() const +{ + return m_pView; +} + +void OTableEditorCtrl::DeactivateCell(bool bUpdate) +{ + OTableRowView::DeactivateCell(bUpdate); + // now we have to deactivate the field description + sal_Int32 nRow(GetCurRow()); + if (pDescrWin) + pDescrWin->SetReadOnly(bReadOnly || !SetDataPtr(nRow) || GetActRow()->IsReadOnly()); +} + +bool OTableEditorCtrl::PreNotify( NotifyEvent& rNEvt ) +{ + if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + { + if( pHelpTextCell && pHelpTextCell->HasChildPathFocus() ) + m_eChildFocus = HELPTEXT; + else if( pDescrCell && pDescrCell->HasChildPathFocus() ) + m_eChildFocus = DESCRIPTION; + else if(pNameCell && pNameCell->HasChildPathFocus() ) + m_eChildFocus = NAME; + else + m_eChildFocus = ROW; + } + + return OTableRowView::PreNotify(rNEvt); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TEditControl.hxx b/dbaccess/source/ui/tabledesign/TEditControl.hxx new file mode 100644 index 000000000..7b1d46781 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TEditControl.hxx @@ -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 . + */ +#pragma once + +#include <TableDesignControl.hxx> +#include <TableDesignView.hxx> +#include "TableFieldDescWin.hxx" +#include <TableRow.hxx> +#include <TypeInfo.hxx> + +class Edit; +class SfxUndoManager; +namespace dbaui +{ + class OSQLNameEditControl; + + class OTableEditorCtrl : public OTableRowView + { + enum ChildFocusState + { + HELPTEXT, + DESCRIPTION, + NAME, + ROW, + NONE + }; + + std::vector< std::shared_ptr<OTableRow> >* m_pRowList; + + VclPtr<OTableDesignView> m_pView; + VclPtr<OSQLNameEditControl> pNameCell; + VclPtr<::svt::ListBoxControl> pTypeCell; + VclPtr<::svt::EditControl> pHelpTextCell; + VclPtr<::svt::EditControl> pDescrCell; + OTableFieldDescWin* pDescrWin; // properties of one column + + std::shared_ptr<OTableRow> pActRow; + + ImplSVEvent * nCutEvent; + ImplSVEvent * nPasteEvent; + ImplSVEvent * nDeleteEvent; + ImplSVEvent * nInsNewRowsEvent; + ImplSVEvent * nInvalidateTypeEvent; + ChildFocusState m_eChildFocus; + + tools::Long nOldDataPos; + + bool bReadOnly; + + // helper class + class ClipboardInvalidator final + { + private: + AutoTimer m_aInvalidateTimer; + VclPtr<OTableEditorCtrl> m_pOwner; + + public: + explicit ClipboardInvalidator(OTableEditorCtrl*); + ~ClipboardInvalidator(); + void Stop(); + + private: + DECL_LINK(OnInvalidate, Timer*, void); + }; + + friend class OTableEditorCtrl::ClipboardInvalidator; + + ClipboardInvalidator m_aInvalidate; + + protected: + virtual void Command( const CommandEvent& rEvt ) override; + virtual bool SeekRow(sal_Int32 nRow) override; + virtual void PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, + sal_uInt16 nColumnId ) const override; + + virtual void CursorMoved() override; + virtual RowStatus GetRowStatus(sal_Int32 nRow) const override; + + virtual ::svt::CellController* GetController(sal_Int32 nRow, sal_uInt16 nCol) override; + virtual void InitController(::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol) override; + + virtual void CellModified() override; + virtual bool SaveModified() override; // is called before changing a cell (false prevents change) + + virtual OUString GetCellText(sal_Int32 nRow, sal_uInt16 nColId) const override; + virtual sal_uInt32 GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId) override; + + virtual void CopyRows() override; + virtual void InsertRows( sal_Int32 nRow ) override; + virtual void DeleteRows() override; + virtual void InsertNewRows( sal_Int32 nRow ) override; + + virtual bool IsPrimaryKeyAllowed() override; + virtual bool IsInsertNewAllowed( sal_Int32 nRow ) override; + virtual bool IsDeleteAllowed() override; + + void ClearModified(); + + void SetPrimaryKey( bool bSet ); + bool IsPrimaryKey(); + + public: + explicit OTableEditorCtrl(vcl::Window* pParentWin, OTableDesignView* pView); + virtual ~OTableEditorCtrl() override; + virtual void dispose() override; + virtual bool CursorMoving(sal_Int32 nNewRow, sal_uInt16 nNewCol) override; + SfxUndoManager& GetUndoManager() const; + + void SetDescrWin( OTableFieldDescWin* pWin ) + { + pDescrWin = pWin; + if (pDescrWin && pActRow) + pDescrWin->DisplayData(pActRow->GetActFieldDescr()); + } + void SaveCurRow(); + void SwitchType( const TOTypeInfoSP& _pType ); + + /// force displaying of the given row + void DisplayData( sal_Int32 nRow ); + + virtual void SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const TOTypeInfoSP& _pTypeInfo ) override; + virtual void SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const css::uno::Any& _rSaveData ) override; + virtual css::uno::Any GetCellData( sal_Int32 nRow, sal_uInt16 nColId ) override; + virtual void SetControlText( sal_Int32 nRow, sal_uInt16 nColId, const OUString& rText ) override; + + virtual OTableDesignView* GetView() const override; + + std::vector< std::shared_ptr<OTableRow> >* GetRowList(){ return m_pRowList; } + + const std::shared_ptr<OTableRow>& GetActRow() const { return pActRow; } + void CellModified( sal_Int32 nRow, sal_uInt16 nColId ); + void SetReadOnly( bool bRead ); + + virtual void Init() override; + virtual void DeactivateCell(bool bUpdate = true) override; + + bool IsCutAllowed(); + bool IsCopyAllowed(); + bool IsPasteAllowed() const; + bool IsReadOnly() const { return bReadOnly;} + OFieldDescription* GetFieldDescr( sal_Int32 nRow ); + + // Window overrides + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + + // IClipboardTest + virtual bool isCutAllowed() override { return IsCutAllowed(); } + virtual bool isCopyAllowed() override { return IsCopyAllowed(); } + virtual bool isPasteAllowed() override { return IsPasteAllowed(); } + + virtual void cut() override; + virtual void copy() override; + virtual void paste() override; + + private: + DECL_LINK( DelayedCut, void*, void ); + DECL_LINK( DelayedPaste, void*, void ); + DECL_LINK( DelayedDelete, void*, void ); + DECL_LINK( DelayedInsNewRows, void*, void ); + DECL_LINK( InvalidateFieldType, void*, void ); + + void InitCellController(); + sal_Int32 HasFieldName( std::u16string_view rFieldName ); + OUString GenerateName( const OUString& rName ); + bool SetDataPtr( sal_Int32 nRow ); + + void SaveData(sal_Int32 nRow, sal_uInt16 nColumnId); + /** AdjustFieldDescription set the needed values for the description + @param _pFieldDesc the field description where to set the values + @param _rMultiSel contains the positions which changed for undo/redo + @param _nPos the current position + @param _bSet should a key be set + @param _bPrimaryKey which value should the pkey have + */ + void AdjustFieldDescription( OFieldDescription* _pFieldDesc, + MultiSelection& _rMultiSel, + sal_Int32 _nPos, + bool _bSet, + bool _bPrimaryKey); + /** InvalidateFeatures invalidates the slots SID_UNDO | SID_REDO | SID_SAVEDOC + */ + void InvalidateFeatures(); + + void resetType(); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableController.cxx b/dbaccess/source/ui/tabledesign/TableController.cxx new file mode 100644 index 000000000..07fe30a91 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableController.cxx @@ -0,0 +1,1495 @@ +/* -*- 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 <FieldDescriptions.hxx> +#include "TEditControl.hxx" +#include <TableController.hxx> +#include <TableDesignView.hxx> +#include <TableRow.hxx> +#include <TypeInfo.hxx> +#include <UITools.hxx> +#include <browserids.hxx> +#include <core_resource.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <defaultobjectnamecheck.hxx> +#include <dlgsave.hxx> +#include <indexdialog.hxx> +#include <sqlmessage.hxx> + +#include <com/sun/star/frame/XTitleChangeListener.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <com/sun/star/sdbcx/XAlterTable.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XDrop.hpp> +#include <com/sun/star/sdbcx/XIndexesSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> + +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbmetadata.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <o3tl/string_view.hxx> + +#include <algorithm> +#include <functional> +#include <set> + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_OTableDesign_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::OTableController(context)); +} + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::ui; +using namespace ::com::sun::star::util; +using namespace ::dbtools; +using namespace ::dbaui; +using namespace ::comphelper; + +// number of columns when creating it from scratch +#define NEWCOLS 128 + +namespace +{ + void dropTable(const Reference<XNameAccess>& _rxTable,const OUString& _sTableName) + { + if ( _rxTable->hasByName(_sTableName) ) + { + Reference<XDrop> xNameCont(_rxTable,UNO_QUERY); + OSL_ENSURE(xNameCont.is(),"No drop interface for tables!"); + if ( xNameCont.is() ) + xNameCont->dropByName(_sTableName); + } + } +} + +OUString SAL_CALL OTableController::getImplementationName() +{ + return "org.openoffice.comp.dbu.OTableDesign"; +} + +Sequence< OUString> OTableController::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.TableDesign" }; +} + +OTableController::OTableController(const Reference< XComponentContext >& _rM) : OTableController_BASE(_rM) + ,m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES)) + ,m_bAllowAutoIncrementValue(false) + ,m_bNew(true) +{ + + InvalidateAll(); + m_pTypeInfo = std::make_shared<OTypeInfo>(); + m_pTypeInfo->aUIName = m_sTypeNames.getToken(TYPE_OTHER, ';'); +} + +OTableController::~OTableController() +{ + m_aTypeInfoIndex.clear(); + m_aTypeInfo.clear(); + +} + +void OTableController::startTableListening() +{ + Reference< XComponent > xComponent(m_xTable, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(static_cast<XModifyListener*>(this)); +} + +void OTableController::stopTableListening() +{ + Reference< XComponent > xComponent(m_xTable, UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener(static_cast<XModifyListener*>(this)); +} + +void OTableController::disposing() +{ + OTableController_BASE::disposing(); + clearView(); + + m_vRowList.clear(); +} + +FeatureState OTableController::GetState(sal_uInt16 _nId) const +{ + FeatureState aReturn; + // disabled automatically + + switch (_nId) + { + case ID_BROWSER_CLOSE: + aReturn.bEnabled = true; + break; + case ID_BROWSER_EDITDOC: + aReturn.bChecked = isEditable(); + aReturn.bEnabled = true; + break; + case ID_BROWSER_SAVEDOC: + aReturn.bEnabled = isEditable() && std::any_of(m_vRowList.begin(),m_vRowList.end(),std::mem_fn(&OTableRow::isValid)); + break; + case ID_BROWSER_SAVEASDOC: + aReturn.bEnabled = isConnected() && isEditable(); + if ( aReturn.bEnabled ) + { + aReturn.bEnabled = std::any_of(m_vRowList.begin(),m_vRowList.end(), + std::mem_fn(&OTableRow::isValid)); + } + break; + + case ID_BROWSER_CUT: + aReturn.bEnabled = isEditable() && getView() && static_cast<OTableDesignView*>(getView())->isCutAllowed(); + break; + case ID_BROWSER_COPY: + aReturn.bEnabled = getView() && static_cast<OTableDesignView*>(getView())->isCopyAllowed(); + break; + case ID_BROWSER_PASTE: + aReturn.bEnabled = isEditable() && getView() && static_cast<OTableDesignView*>(getView())->isPasteAllowed(); + break; + case SID_INDEXDESIGN: + aReturn.bEnabled = + ( ( ((!m_bNew && impl_isModified()) || impl_isModified()) + || Reference< XIndexesSupplier >(m_xTable, UNO_QUERY).is() + ) + && isConnected() + ); + if ( aReturn.bEnabled ) + { + aReturn.bEnabled = std::any_of(m_vRowList.begin(),m_vRowList.end(), + std::mem_fn(&OTableRow::isValid)); + } + break; + default: + aReturn = OTableController_BASE::GetState(_nId); + } + return aReturn; +} + +void OTableController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs) +{ + switch(_nId) + { + case ID_BROWSER_EDITDOC: + setEditable(!isEditable()); + static_cast<OTableDesignView*>(getView())->setReadOnly(!isEditable()); + InvalidateFeature(ID_BROWSER_SAVEDOC); + InvalidateFeature(ID_BROWSER_PASTE); + InvalidateFeature(SID_BROWSER_CLEAR_QUERY); + break; + case ID_BROWSER_SAVEASDOC: + doSaveDoc(true); + break; + case ID_BROWSER_SAVEDOC: + static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->SaveCurRow(); + doSaveDoc(false); + break; + case ID_BROWSER_CUT: + static_cast<OTableDesignView*>(getView())->cut(); + break; + case ID_BROWSER_COPY: + static_cast<OTableDesignView*>(getView())->copy(); + break; + case ID_BROWSER_PASTE: + static_cast<OTableDesignView*>(getView())->paste(); + break; + case SID_INDEXDESIGN: + doEditIndexes(); + break; + default: + OTableController_BASE::Execute(_nId,aArgs); + } + InvalidateFeature(_nId); +} + +bool OTableController::doSaveDoc(bool _bSaveAs) +{ + if (!isConnected()) + reconnect(true); // ask the user for a new connection + Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY); + + if (!xTablesSup.is()) + { + OUString aMessage(DBA_RES(STR_TABLEDESIGN_CONNECTION_MISSING)); + OSQLWarningBox aWarning(getFrameWeld(), aMessage); + aWarning.run(); + return false; + } + + // check if a column exists + // TODO + + Reference<XNameAccess> xTables; + OUString sCatalog, sSchema; + + bool bNew = m_sName.isEmpty(); + bNew = bNew || m_bNew || _bSaveAs; + + try + { + xTables = xTablesSup->getTables(); + OSL_ENSURE(xTables.is(),"The tables can't be null!"); + bNew = bNew || (xTables.is() && !xTables->hasByName(m_sName)); + + // first we need a name for our query so ask the user + if(bNew) + { + OUString aName = DBA_RES(STR_TBL_TITLE); + OUString aDefaultName = aName.getToken(0,' '); + aDefaultName = ::dbtools::createUniqueName(xTables,aDefaultName); + + DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::TABLE ); + OSaveAsDlg aDlg(getFrameWeld(), CommandType::TABLE, getORB(), getConnection(), aDefaultName, aNameChecker, SADFlags::NONE); + if (aDlg.run() != RET_OK) + return false; + + m_sName = aDlg.getName(); + sCatalog = aDlg.getCatalog(); + sSchema = aDlg.getSchema(); + } + + // did we get a name + if(m_sName.isEmpty()) + return false; + } + catch(Exception&) + { + OSL_FAIL("OTableController::doSaveDoc: nothing is expected to happen here!"); + } + + bool bAlter = false; + bool bError = false; + SQLExceptionInfo aInfo; + try + { + // check the columns for double names + if(!checkColumns(bNew || !xTables->hasByName(m_sName))) + { + return false; + } + + Reference<XPropertySet> xTable; + if(bNew || !xTables->hasByName(m_sName)) // just to make sure the table already exists + { + dropTable(xTables,m_sName); + + Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY); + OSL_ENSURE(xFact.is(),"OTableController::doSaveDoc: No XDataDescriptorFactory available!"); + xTable = xFact->createDataDescriptor(); + OSL_ENSURE(xTable.is(),"OTableController::doSaveDoc: Create query failed!"); + // to set the name is only allowed when the query is new + xTable->setPropertyValue(PROPERTY_CATALOGNAME,Any(sCatalog)); + xTable->setPropertyValue(PROPERTY_SCHEMANAME,Any(sSchema)); + xTable->setPropertyValue(PROPERTY_NAME,Any(m_sName)); + + // now append the columns + Reference<XColumnsSupplier> xColSup(xTable,UNO_QUERY); + appendColumns(xColSup,bNew); + // now append the primary key + Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY); + appendPrimaryKey(xKeySup,bNew); + } + // now set the properties + if(bNew) + { + Reference<XAppend> xAppend(xTables,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"OTableController::doSaveDoc: No XAppend Interface!"); + xAppend->appendByDescriptor(xTable); + + assignTable(); + if(!m_xTable.is()) // correct name and try again + { + // it can be that someone inserted new data for us + m_sName = ::dbtools::composeTableName( getConnection()->getMetaData(), xTable, ::dbtools::EComposeRule::InDataManipulation, false ); + assignTable(); + } + // now check if our datasource has set a tablefilter and if append the new table name to it + ::dbaui::appendToFilter(getConnection(), m_sName, getORB(), getFrameWeld()); // we are not interested in the return value + Reference< frame::XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY); + if ( xEventListener.is() ) + { + frame::TitleChangedEvent aEvent; + xEventListener->titleChanged(aEvent); + } + releaseNumberForComponent(); + } + else if(m_xTable.is()) + { + bAlter = true; + alterColumns(); + } + reSyncRows(); + } + catch(const SQLContext& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const SQLWarning& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const SQLException& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const ElementExistException& ) + { + OUString sText( DBA_RES( STR_NAME_ALREADY_EXISTS ) ); + sText = sText.replaceFirst( "#" , m_sName); + OSQLMessageBox aDlg(getFrameWeld(), DBA_RES( STR_ERROR_DURING_CREATION ), sText, MessBoxStyle::Ok, MessageType::Error); + aDlg.run(); + bError = true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + bError = true; + } + + if ( aInfo.isValid() ) + aInfo.prepend( DBA_RES( STR_TABLEDESIGN_SAVE_ERROR ) ); + showError(aInfo); + + if (aInfo.isValid() || bError) + { + if(!bAlter || bNew) + { + m_sName.clear(); + stopTableListening(); + m_xTable = nullptr; + } + } + return ! (aInfo.isValid() || bError); +} + +void OTableController::doEditIndexes() +{ + // table needs to be saved before editing indexes + if (m_bNew || isModified()) + { + std::unique_ptr<weld::MessageDialog> xAsk(Application::CreateMessageDialog(getFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + DBA_RES(STR_QUERY_SAVE_TABLE_EDIT_INDEXES))); + if (RET_YES != xAsk->run()) + return; + + if (!doSaveDoc(false)) + return; + + OSL_ENSURE(!m_bNew && !isModified(), "OTableController::doEditIndexes: what the hell did doSaveDoc do?"); + } + + Reference< XNameAccess > xIndexes; // will be the keys of the table + Sequence< OUString > aFieldNames; // will be the column names of the table + try + { + // get the keys + Reference< XIndexesSupplier > xIndexesSupp(m_xTable, UNO_QUERY); + if (xIndexesSupp.is()) + { + xIndexes = xIndexesSupp->getIndexes(); + OSL_ENSURE(xIndexes.is(), "OTableController::doEditIndexes: no keys got from the indexes supplier!"); + } + else + OSL_FAIL("OTableController::doEditIndexes: should never have reached this (no indexes supplier)!"); + + // get the field names + Reference< XColumnsSupplier > xColSupp(m_xTable, UNO_QUERY); + OSL_ENSURE(xColSupp.is(), "OTableController::doEditIndexes: no columns supplier!"); + if (xColSupp.is()) + { + Reference< XNameAccess > xCols = xColSupp->getColumns(); + OSL_ENSURE(xCols.is(), "OTableController::doEditIndexes: no columns!"); + if (xCols.is()) + aFieldNames = xCols->getElementNames(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if (!xIndexes.is()) + return; + + DbaIndexDialog aDialog(getFrameWeld(), aFieldNames, xIndexes, getConnection(), getORB()); + if (RET_OK != aDialog.run()) + return; + +} + +void OTableController::impl_initialize() +{ + try + { + OTableController_BASE::impl_initialize(); + + const NamedValueCollection& rArguments( getInitParams() ); + + rArguments.get_ensureType( PROPERTY_CURRENTTABLE, m_sName ); + + // read autoincrement value set in the datasource + ::dbaui::fillAutoIncrementValue(getDataSource(),m_bAllowAutoIncrementValue,m_sAutoIncrementValue); + + assignTable(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + try + { + ::dbaui::fillTypeInfo(getConnection(),m_sTypeNames,m_aTypeInfo,m_aTypeInfoIndex); // fill the needed type information + } + catch(const SQLException&) + { + OSQLWarningBox aWarning(getFrameWeld(), DBA_RES( STR_NO_TYPE_INFO_AVAILABLE)); + aWarning.run(); + throw; + } + try + { + loadData(); // fill the column information from the table + getView()->initialize(); // show the windows and fill with our information + ClearUndoManager(); + setModified(false); // and we are not modified yet + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +bool OTableController::Construct(vcl::Window* pParent) +{ + setView( VclPtr<OTableDesignView>::Create( pParent, getORB(), *this ) ); + OTableController_BASE::Construct(pParent); + return true; +} + +sal_Bool SAL_CALL OTableController::suspend(sal_Bool /*_bSuspend*/) +{ + if ( getBroadcastHelper().bInDispose || getBroadcastHelper().bDisposed ) + return true; + + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + if ( getView() && getView()->IsInModalMode() ) + return false; + if ( getView() ) + static_cast<OTableDesignView*>(getView())->GrabFocus(); + bool bCheck = true; + if ( isModified() ) + { + if ( std::any_of(m_vRowList.begin(),m_vRowList.end(), + std::mem_fn(&OTableRow::isValid)) ) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/tabledesignsavemodifieddialog.ui")); + std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("TableDesignSaveModifiedDialog")); + switch (xQuery->run()) + { + case RET_YES: + Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>()); + if ( isModified() ) + bCheck = false; // when we save the table this must be false else some press cancel + break; + case RET_CANCEL: + bCheck = false; + break; + default: + break; + } + } + else if ( !m_bNew ) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/deleteallrowsdialog.ui")); + std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("DeleteAllRowsDialog")); + switch (xQuery->run()) + { + case RET_YES: + { + try + { + Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY); + Reference<XNameAccess> xTables = xTablesSup->getTables(); + dropTable(xTables,m_sName); + } + catch(const Exception&) + { + OSL_FAIL("OTableController::suspend: nothing is expected to happen here!"); + } + + } + break; + case RET_CANCEL: + bCheck = false; + break; + default: + break; + } + } + } + + return bCheck; +} + +void OTableController::describeSupportedFeatures() +{ + OSingleDocumentController::describeSupportedFeatures(); + + implDescribeSupportedFeature( ".uno:Redo", ID_BROWSER_REDO, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVEDOC, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Undo", ID_BROWSER_UNDO, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:NewDoc", SID_NEWDOC, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:DBIndexDesign", SID_INDEXDESIGN, CommandGroup::APPLICATION ); + implDescribeSupportedFeature( ".uno:EditDoc", ID_BROWSER_EDITDOC, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:GetUndoStrings", SID_GETUNDOSTRINGS ); + implDescribeSupportedFeature( ".uno:GetRedoStrings", SID_GETREDOSTRINGS ); +} + +void OTableController::impl_onModifyChanged() +{ + OSingleDocumentController::impl_onModifyChanged(); + InvalidateFeature( SID_INDEXDESIGN ); +} + +void SAL_CALL OTableController::disposing( const EventObject& _rSource ) +{ + if ( _rSource.Source == m_xTable ) + { // some deleted our table so we have a new one + stopTableListening(); + m_xTable = nullptr; + m_bNew = true; + setModified(true); + } + else + OTableController_BASE::disposing( _rSource ); +} + +void OTableController::losingConnection( ) +{ + // let the base class do its reconnect + OTableController_BASE::losingConnection( ); + + // remove from the table + Reference< XComponent > xComponent(m_xTable, UNO_QUERY); + if (xComponent.is()) + { + Reference<XEventListener> xEvtL( static_cast< ::cppu::OWeakObject*>(this), UNO_QUERY); + xComponent->removeEventListener(xEvtL); + } + stopTableListening(); + m_xTable = nullptr; + assignTable(); + if(!m_xTable.is()) + { + m_bNew = true; + setModified(true); + } + InvalidateAll(); +} + +TOTypeInfoSP OTableController::getTypeInfoByType(sal_Int32 _nDataType) const +{ + return queryTypeInfoByType(_nDataType,m_aTypeInfo); +} + +void OTableController::appendColumns(Reference<XColumnsSupplier> const & _rxColSup, bool _bNew, bool _bKeyColumns) +{ + try + { + // now append the columns + OSL_ENSURE(_rxColSup.is(),"No columns supplier"); + if(!_rxColSup.is()) + return; + Reference<XNameAccess> xColumns = _rxColSup->getColumns(); + OSL_ENSURE(xColumns.is(),"No columns"); + Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); + + Reference<XAppend> xAppend(xColumns,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + for (auto const& row : m_vRowList) + { + OSL_ENSURE(row,"OTableRow is null!"); + OFieldDescription* pField = row->GetActFieldDescr(); + if ( !pField || (!_bNew && row->IsReadOnly() && !_bKeyColumns) ) + continue; + + Reference<XPropertySet> xColumn; + if(pField->IsPrimaryKey() || !_bKeyColumns) + xColumn = xColumnFactory->createDataDescriptor(); + if(xColumn.is()) + { + if(!_bKeyColumns) + ::dbaui::setColumnProperties(xColumn,pField); + else + xColumn->setPropertyValue(PROPERTY_NAME,Any(pField->GetName())); + + xAppend->appendByDescriptor(xColumn); + xColumn = nullptr; + // now only the settings are missing + if(xColumns->hasByName(pField->GetName())) + { + xColumns->getByName(pField->GetName()) >>= xColumn; + if(xColumn.is()) + pField->copyColumnSettingsTo(xColumn); + } + else + { + OSL_FAIL("OTableController::appendColumns: invalid field name!"); + } + + } + } + } + catch(const SQLException& ) + { + showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OTableController::appendPrimaryKey(Reference<XKeysSupplier> const & _rxSup, bool _bNew) +{ + if(!_rxSup.is()) + return; // the database doesn't support keys + + OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!"); + Reference<XIndexAccess> xKeys = _rxSup->getKeys(); + Reference<XPropertySet> xProp; + if (!xKeys.is()) + return; + const sal_Int32 nCount = xKeys->getCount(); + for(sal_Int32 i=0;i< nCount ;++i) + { + xKeys->getByIndex(i) >>= xProp; + sal_Int32 nKeyType = 0; + xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; + if(KeyType::PRIMARY == nKeyType) + { + return; // primary key already exists after appending a column + } + } + Reference<XDataDescriptorFactory> xKeyFactory(xKeys,UNO_QUERY); + OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!"); + if ( !xKeyFactory.is() ) + return; + Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor(); + OSL_ENSURE(xKey.is(),"Key is null!"); + xKey->setPropertyValue(PROPERTY_TYPE,Any(KeyType::PRIMARY)); + + Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY); + if(xColSup.is()) + { + appendColumns(xColSup,_bNew,true); + Reference<XNameAccess> xColumns = xColSup->getColumns(); + if(xColumns->hasElements()) + xAppend->appendByDescriptor(xKey); + } +} + +void OTableController::loadData() +{ + // if the data structure already exists, empty it + m_vRowList.clear(); + + std::shared_ptr<OTableRow> pTabEdRow; + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + // fill data structure with data from DataDefinitionObject + if(m_xTable.is() && xMetaData.is()) + { + Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY); + OSL_ENSURE(xColSup.is(),"No XColumnsSupplier!"); + Reference<XNameAccess> xColumns = xColSup->getColumns(); + // ReadOnly-Flag + // For Drop no row may be editable + // For Add only the empty rows may be editable + // For Add and Drop all rows can be edited + // sal_Bool bReadOldRow = xMetaData->supportsAlterTableWithAddColumn() && xMetaData->supportsAlterTableWithDropColumn(); + bool bIsAlterAllowed = isAlterAllowed(); + + const Sequence<OUString> aColNames = xColumns->getElementNames(); + for(const OUString& rColumn : aColNames) + { + Reference<XPropertySet> xColumn; + xColumns->getByName(rColumn) >>= xColumn; + sal_Int32 nType = 0; + sal_Int32 nScale = 0; + sal_Int32 nPrecision = 0; + sal_Int32 nNullable = 0; + sal_Int32 nFormatKey = 0; + sal_Int32 nAlign = 0; + + bool bIsAutoIncrement = false, bIsCurrency = false; + OUString sName,sDescription,sTypeName,sHelpText; + Any aControlDefault; + + // get the properties from the column + xColumn->getPropertyValue(PROPERTY_NAME) >>= sName; + xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; + xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable; + xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bIsAutoIncrement; + xColumn->getPropertyValue(PROPERTY_ISCURRENCY) >>= bIsCurrency; + xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType; + xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale; + xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision; + xColumn->getPropertyValue(PROPERTY_DESCRIPTION) >>= sDescription; + + if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_HELPTEXT)) + xColumn->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText; + + if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_CONTROLDEFAULT)) + aControlDefault = xColumn->getPropertyValue(PROPERTY_CONTROLDEFAULT); + if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_FORMATKEY)) + xColumn->getPropertyValue(PROPERTY_FORMATKEY) >>= nFormatKey; + if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ALIGN)) + xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign; + + pTabEdRow = std::make_shared<OTableRow>(); + pTabEdRow->SetReadOnly(!bIsAlterAllowed); + // search for type + bool bForce; + TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,"x",nPrecision,nScale,bIsAutoIncrement,bForce); + if ( !pTypeInfo ) + pTypeInfo = m_pTypeInfo; + pTabEdRow->SetFieldType( pTypeInfo, bForce ); + + OFieldDescription* pActFieldDescr = pTabEdRow->GetActFieldDescr(); + OSL_ENSURE(pActFieldDescr, "OTableController::loadData: invalid field description generated by the table row!"); + if ( pActFieldDescr ) + { + pActFieldDescr->SetName(sName); + pActFieldDescr->SetFormatKey(nFormatKey); + pActFieldDescr->SetDescription(sDescription); + pActFieldDescr->SetHelpText(sHelpText); + pActFieldDescr->SetAutoIncrement(bIsAutoIncrement); + pActFieldDescr->SetHorJustify(dbaui::mapTextJustify(nAlign)); + pActFieldDescr->SetCurrency(bIsCurrency); + + // special data + pActFieldDescr->SetIsNullable(nNullable); + pActFieldDescr->SetControlDefault(aControlDefault); + pActFieldDescr->SetPrecision(nPrecision); + pActFieldDescr->SetScale(nScale); + } + m_vRowList.push_back( pTabEdRow); + } + // fill the primary key information + Reference<XNameAccess> xKeyColumns = getKeyColumns(); + if(xKeyColumns.is()) + { + const Sequence<OUString> aKeyColumnNames = xKeyColumns->getElementNames(); + for(const OUString& rKeyColumn : aKeyColumnNames) + { + for(std::shared_ptr<OTableRow> const& pRow : m_vRowList) + { + if(pRow->GetActFieldDescr()->GetName() == rKeyColumn) + { + pRow->SetPrimaryKey(true); + break; + } + } + } + } + } + + // fill empty rows + + OTypeInfoMap::const_iterator aTypeIter = m_aTypeInfo.find(DataType::VARCHAR); + if(aTypeIter == m_aTypeInfo.end()) + aTypeIter = m_aTypeInfo.begin(); + + OSL_ENSURE(aTypeIter != m_aTypeInfo.end(),"We have no type information!"); + + bool bReadRow = !isAddAllowed(); + for(sal_Int32 i=m_vRowList.size(); i < NEWCOLS; i++ ) + { + pTabEdRow = std::make_shared<OTableRow>(); + pTabEdRow->SetReadOnly(bReadRow); + m_vRowList.push_back( pTabEdRow); + } +} + +Reference<XNameAccess> OTableController::getKeyColumns() const +{ + return getPrimaryKeyColumns_throw(m_xTable); +} + +bool OTableController::checkColumns(bool _bNew) +{ + bool bOk = true; + bool bFoundPKey = false; + Reference< XDatabaseMetaData > xMetaData = getMetaData( ); + DatabaseMetaData aMetaData( getConnection() ); + + ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers()); + std::vector< std::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin(); + std::vector< std::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end(); + for(;aIter != aEnd;++aIter) + { + OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr(); + if (pFieldDesc && !pFieldDesc->GetName().isEmpty()) + { + bFoundPKey |= (*aIter)->IsPrimaryKey(); + // first check for duplicate names + bool bDuplicateNameFound = std::any_of(aIter+1, aEnd, + [&bCase, &pFieldDesc](const std::shared_ptr<OTableRow>& rxRow) { + OFieldDescription* pCompareDesc = rxRow->GetActFieldDescr(); + return pCompareDesc && bCase(pCompareDesc->GetName(),pFieldDesc->GetName()); + }); + if (bDuplicateNameFound) + { + OUString strMessage = DBA_RES(STR_TABLEDESIGN_DUPLICATE_NAME); + strMessage = strMessage.replaceFirst("$column$", pFieldDesc->GetName()); + OSQLWarningBox aWarning(getFrameWeld(), strMessage); + aWarning.run(); + return false; + } + } + } + if ( _bNew && !bFoundPKey && aMetaData.supportsPrimaryKeys() ) + { + OUString sTitle(DBA_RES(STR_TABLEDESIGN_NO_PRIM_KEY_HEAD)); + OUString sMsg(DBA_RES(STR_TABLEDESIGN_NO_PRIM_KEY)); + OSQLMessageBox aBox(getFrameWeld(), sTitle,sMsg, MessBoxStyle::YesNoCancel | MessBoxStyle::DefaultYes); + + switch (aBox.run()) + { + case RET_YES: + { + auto pNewRow = std::make_shared<OTableRow>(); + TOTypeInfoSP pTypeInfo = ::dbaui::queryPrimaryKeyType(m_aTypeInfo); + if ( !pTypeInfo ) + break; + + pNewRow->SetFieldType( pTypeInfo ); + OFieldDescription* pActFieldDescr = pNewRow->GetActFieldDescr(); + + pActFieldDescr->SetAutoIncrement(false); + pActFieldDescr->SetIsNullable(ColumnValue::NO_NULLS); + + pActFieldDescr->SetName( createUniqueName("ID" )); + pActFieldDescr->SetPrimaryKey( true ); + m_vRowList.insert(m_vRowList.begin(),pNewRow); + + static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->Invalidate(); + static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->RowInserted(0); + } + break; + case RET_CANCEL: + bOk = false; + break; + } + } + return bOk; +} + +void OTableController::alterColumns() +{ + Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY_THROW); + + Reference<XNameAccess> xColumns = xColSup->getColumns(); + Reference<XIndexAccess> xIdxColumns(xColumns,UNO_QUERY_THROW); + OSL_ENSURE(xColumns.is(),"No columns"); + if ( !xColumns.is() ) + return; + Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY); // can be null + + sal_Int32 nColumnCount = xIdxColumns->getCount(); + Reference<XDrop> xDrop(xColumns,UNO_QUERY); // can be null + Reference<XAppend> xAppend(xColumns,UNO_QUERY); // can be null + Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); // can be null + + bool bReload = false; // refresh the data + + // contains all columns names which are already handled those which are not in the list will be deleted + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + + std::set<OUString, comphelper::UStringMixLess> aColumns( + comphelper::UStringMixLess( + !xMetaData.is() + || xMetaData->supportsMixedCaseQuotedIdentifiers())); + std::vector< std::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin(); + std::vector< std::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end(); + // first look for columns where something other than the name changed + for(sal_Int32 nPos = 0;aIter != aEnd;++aIter,++nPos) + { + OSL_ENSURE(*aIter,"OTableRow is null!"); + OFieldDescription* pField = (*aIter)->GetActFieldDescr(); + if ( !pField ) + continue; + if ( (*aIter)->IsReadOnly() ) + { + aColumns.insert(pField->GetName()); + continue; + } + + Reference<XPropertySet> xColumn; + if ( xColumns->hasByName(pField->GetName()) ) + { + aColumns.insert(pField->GetName()); + xColumns->getByName(pField->GetName()) >>= xColumn; + OSL_ENSURE(xColumn.is(),"Column is null!"); + + sal_Int32 nType=0,nPrecision=0,nScale=0,nNullable=0; + bool bAutoIncrement = false; + OUString sTypeName,sDescription; + + xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType; + xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision; + xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale; + xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable; + xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bAutoIncrement; + xColumn->getPropertyValue(PROPERTY_DESCRIPTION) >>= sDescription; + + try { xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; } + catch( const Exception& ) + { + OSL_FAIL( "no TypeName property?!" ); + // since this is a last minute fix for #i41785#, I want to be on the safe side, + // and catch errors here as early as possible (instead of the whole process of altering + // the columns failing) + // Normally, sdbcx::Column objects are expected to have a TypeName property + } + + // check if something changed + if((nType != pField->GetType() || + sTypeName != pField->GetTypeName() || + (nPrecision != pField->GetPrecision() && nPrecision ) || + nScale != pField->GetScale() || + nNullable != pField->GetIsNullable() || + sDescription != pField->GetDescription() || + bAutoIncrement != pField->IsAutoIncrement())&& + xColumnFactory.is()) + { + Reference<XPropertySet> xNewColumn = xColumnFactory->createDataDescriptor(); + ::dbaui::setColumnProperties(xNewColumn,pField); + // first try to alter the column + bool bNotOk = false; + try + { + // first try if we can alter the column + if(xAlter.is()) + xAlter->alterColumnByName(pField->GetName(),xNewColumn); + } + catch(const SQLException&) + { + if(xDrop.is() && xAppend.is()) + { + OUString aMessage( DBA_RES( STR_TABLEDESIGN_ALTER_ERROR ) ); + aMessage = aMessage.replaceFirst( "$column$", pField->GetName() ); + + SQLExceptionInfo aError( ::cppu::getCaughtException() ); + OSQLWarningBox aMsg(getFrameWeld(), aMessage, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes , &aError); + bNotOk = aMsg.run() == RET_YES; + } + else + throw; + } + // if something went wrong or we can't alter columns + // drop and append a new one + if((!xAlter.is() || bNotOk) && xDrop.is() && xAppend.is()) + { + xDrop->dropByName(pField->GetName()); + try + { + xAppend->appendByDescriptor(xNewColumn); + } + catch(const SQLException&) + { // an error occurred so we try to reactivate the old one + xAppend->appendByDescriptor(xColumn); + throw; + } + } + // exceptions are caught outside + xNewColumn = nullptr; + if(xColumns->hasByName(pField->GetName())) + xColumns->getByName(pField->GetName()) >>= xColumn; + bReload = true; + } + + } + else if(xColumnFactory.is() && xAlter.is() && nPos < nColumnCount) + { // we can't find the column so we could try it with the index before we drop and append a new column + try + { + Reference<XPropertySet> xNewColumn = xColumnFactory->createDataDescriptor(); + ::dbaui::setColumnProperties(xNewColumn,pField); + xAlter->alterColumnByIndex(nPos,xNewColumn); + if(xColumns->hasByName(pField->GetName())) + { // ask for the append by name + aColumns.insert(pField->GetName()); + xColumns->getByName(pField->GetName()) >>= xColumn; + if(xColumn.is()) + pField->copyColumnSettingsTo(xColumn); + } + else + { + OSL_FAIL("OTableController::alterColumns: invalid column (2)!"); + } + } + catch(const SQLException&) + { // we couldn't alter the column so we have to add new columns + SQLExceptionInfo aError( ::cppu::getCaughtException() ); + bReload = true; + if(xDrop.is() && xAppend.is()) + { + OUString aMessage(DBA_RES(STR_TABLEDESIGN_ALTER_ERROR)); + aMessage = aMessage.replaceFirst("$column$",pField->GetName()); + OSQLWarningBox aMsg(getFrameWeld(), aMessage, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes, &aError); + if (aMsg.run() != RET_YES) + { + Reference<XPropertySet> xNewColumn(xIdxColumns->getByIndex(nPos),UNO_QUERY_THROW); + OUString sName; + xNewColumn->getPropertyValue(PROPERTY_NAME) >>= sName; + aColumns.insert(sName); + aColumns.insert(pField->GetName()); + continue; + } + } + else + throw; + } + } + else + bReload = true; + } + // alter column settings + + // first look for columns where something other than the name changed + for (auto const& row : m_vRowList) + { + OSL_ENSURE(row,"OTableRow is null!"); + OFieldDescription* pField = row->GetActFieldDescr(); + if ( !pField ) + continue; + if ( row->IsReadOnly() ) + { + aColumns.insert(pField->GetName()); + continue; + } + + Reference<XPropertySet> xColumn; + if ( xColumns->hasByName(pField->GetName()) ) + { + xColumns->getByName(pField->GetName()) >>= xColumn; + Reference<XPropertySetInfo> xInfo = xColumn->getPropertySetInfo(); + if ( xInfo->hasPropertyByName(PROPERTY_HELPTEXT) ) + xColumn->setPropertyValue(PROPERTY_HELPTEXT,Any(pField->GetHelpText())); + + if(xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT)) + xColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,pField->GetControlDefault()); + if(xInfo->hasPropertyByName(PROPERTY_FORMATKEY)) + xColumn->setPropertyValue(PROPERTY_FORMATKEY,Any(pField->GetFormatKey())); + if(xInfo->hasPropertyByName(PROPERTY_ALIGN)) + xColumn->setPropertyValue(PROPERTY_ALIGN,Any(dbaui::mapTextAlign(pField->GetHorJustify()))); + } + } + // second drop all columns which could be found by name + Reference<XNameAccess> xKeyColumns = getKeyColumns(); + // now we have to look for the columns who could be deleted + if ( xDrop.is() ) + { + const Sequence<OUString> aColNames = xColumns->getElementNames(); + for(const OUString& rColumnName : aColNames) + { + if(aColumns.find(rColumnName) == aColumns.end()) // found a column to delete + { + if(xKeyColumns.is() && xKeyColumns->hasByName(rColumnName)) // check if this column is a member of the primary key + { + OUString aMsgT(DBA_RES(STR_TBL_COLUMN_IS_KEYCOLUMN)); + aMsgT = aMsgT.replaceFirst("$column$",rColumnName); + OUString aTitle(DBA_RES(STR_TBL_COLUMN_IS_KEYCOLUMN_TITLE)); + OSQLMessageBox aMsg(getFrameWeld(), aTitle, aMsgT, MessBoxStyle::YesNo| MessBoxStyle::DefaultYes); + if (aMsg.run() == RET_YES) + { + xKeyColumns = nullptr; + dropPrimaryKey(); + } + else + { + bReload = true; + continue; + } + } + try + { + xDrop->dropByName(rColumnName); + } + catch (const SQLException&) + { + OUString sError( DBA_RES( STR_TABLEDESIGN_COULD_NOT_DROP_COL ) ); + sError = sError.replaceFirst( "$column$", rColumnName ); + + SQLException aNewException; + aNewException.Message = sError; + aNewException.SQLState = "S1000"; + aNewException.NextException = ::cppu::getCaughtException(); + + throw aNewException; + } + } + } + } + + // third append the new columns + for(const auto& rxRow : m_vRowList) + { + OSL_ENSURE(rxRow,"OTableRow is null!"); + OFieldDescription* pField = rxRow->GetActFieldDescr(); + if ( !pField || rxRow->IsReadOnly() || aColumns.find(pField->GetName()) != aColumns.end() ) + continue; + + Reference<XPropertySet> xColumn; + if(!xColumns->hasByName(pField->GetName())) + { + if(xColumnFactory.is() && xAppend.is()) + {// column not found by its name so we assume it is new + // Column is new + xColumn = xColumnFactory->createDataDescriptor(); + ::dbaui::setColumnProperties(xColumn,pField); + xAppend->appendByDescriptor(xColumn); + if(xColumns->hasByName(pField->GetName())) + { // ask for the append by name + aColumns.insert(pField->GetName()); + xColumns->getByName(pField->GetName()) >>= xColumn; + if(xColumn.is()) + pField->copyColumnSettingsTo(xColumn); + } + else + { + OSL_FAIL("OTableController::alterColumns: invalid column!"); + } + } + } + } + + // check if we have to do something with the primary key + bool bNeedDropKey = false; + bool bNeedAppendKey = false; + if ( xKeyColumns.is() ) + { + for(const auto& rxRow : m_vRowList) + { + OSL_ENSURE(rxRow,"OTableRow is null!"); + OFieldDescription* pField = rxRow->GetActFieldDescr(); + if ( !pField ) + continue; + + if ( pField->IsPrimaryKey() + && !xKeyColumns->hasByName( pField->GetName() ) + ) + { // new primary key column inserted which isn't already in the columns selection + bNeedDropKey = bNeedAppendKey = true; + break; + } + else if ( !pField->IsPrimaryKey() + && xKeyColumns->hasByName( pField->GetName() ) + ) + { // found a column which currently is in the primary key, but is marked not to be anymore + bNeedDropKey = bNeedAppendKey = true; + break; + } + } + } + else + { // no primary key available so we check if we should create one + bNeedAppendKey = true; + } + + if ( bNeedDropKey && xKeyColumns.is() && xKeyColumns->getElementNames().hasElements() ) + dropPrimaryKey(); + + if ( bNeedAppendKey ) + { + Reference< XKeysSupplier > xKeySup( m_xTable, UNO_QUERY ); + appendPrimaryKey( xKeySup ,false); + } + + reSyncRows(); + + if ( bReload ) + reload(); +} + +void OTableController::dropPrimaryKey() +{ + SQLExceptionInfo aInfo; + try + { + Reference<XKeysSupplier> xKeySup(m_xTable,UNO_QUERY); + Reference<XIndexAccess> xKeys; + if(xKeySup.is()) + xKeys = xKeySup->getKeys(); + + if(xKeys.is()) + { + Reference<XPropertySet> xProp; + for(sal_Int32 i=0;i< xKeys->getCount();++i) + { + xProp.set(xKeys->getByIndex(i),UNO_QUERY); + sal_Int32 nKeyType = 0; + xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; + if(KeyType::PRIMARY == nKeyType) + { + Reference<XDrop> xDrop(xKeys,UNO_QUERY); + xDrop->dropByIndex(i); // delete the key + break; + } + } + } + } + catch(const SQLContext& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const SQLWarning& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const SQLException& e) + { + aInfo = SQLExceptionInfo(e); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + showError(aInfo); +} + +void OTableController::assignTable() +{ + // get the table + if(m_sName.isEmpty()) + return; + + Reference<XNameAccess> xNameAccess; + Reference<XTablesSupplier> xSup(getConnection(),UNO_QUERY); + if(!xSup.is()) + return; + + xNameAccess = xSup->getTables(); + OSL_ENSURE(xNameAccess.is(),"no nameaccess for the queries!"); + + if(!xNameAccess->hasByName(m_sName)) + return; + + Reference<XPropertySet> xProp(xNameAccess->getByName(m_sName), css::uno::UNO_QUERY); + if (!xProp.is()) + return; + + m_xTable = xProp; + startTableListening(); + + // check if we set the table editable + Reference<XDatabaseMetaData> xMeta = getConnection()->getMetaData(); + setEditable( xMeta.is() && !xMeta->isReadOnly() && (isAlterAllowed() || isDropAllowed() || isAddAllowed()) ); + if(!isEditable()) + { + for( const auto& rTableRow : m_vRowList ) + { + rTableRow->SetReadOnly(); + } + } + m_bNew = false; + // be notified when the table is in disposing + InvalidateAll(); +} + +bool OTableController::isAddAllowed() const +{ + Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY); + bool bAddAllowed = !m_xTable.is(); + if(xColsSup.is()) + bAddAllowed = Reference<XAppend>(xColsSup->getColumns(),UNO_QUERY).is(); + + try + { + Reference< XDatabaseMetaData > xMetaData = getMetaData( ); + bAddAllowed = bAddAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithAddColumn()); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + bAddAllowed = false; + } + + return bAddAllowed; +} + +bool OTableController::isDropAllowed() const +{ + Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY); + bool bDropAllowed = !m_xTable.is(); + if(xColsSup.is()) + { + Reference<XNameAccess> xNameAccess = xColsSup->getColumns(); + bDropAllowed = Reference<XDrop>(xNameAccess,UNO_QUERY).is() && xNameAccess->hasElements(); + } + + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + bDropAllowed = bDropAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithDropColumn()); + + return bDropAllowed; +} + +bool OTableController::isAlterAllowed() const +{ + bool bAllowed(!m_xTable.is() || Reference<XAlterTable>(m_xTable,UNO_QUERY).is()); + return bAllowed; +} + +void OTableController::reSyncRows() +{ + bool bAlterAllowed = isAlterAllowed(); + bool bAddAllowed = isAddAllowed(); + for (auto const& row : m_vRowList) + { + OSL_ENSURE(row,"OTableRow is null!"); + OFieldDescription* pField = row->GetActFieldDescr(); + if ( pField ) + row->SetReadOnly(!bAlterAllowed); + else + row->SetReadOnly(!bAddAllowed); + + } + static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our information + + ClearUndoManager(); + setModified(false); // and we are not modified yet +} + +OUString OTableController::createUniqueName(const OUString& _rName) +{ + OUString sName = _rName; + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + + ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers()); + + auto lHasName = [&bCase, &sName](const std::shared_ptr<OTableRow>& rxRow) { + OFieldDescription* pFieldDesc = rxRow->GetActFieldDescr(); + return pFieldDesc && !pFieldDesc->GetName().isEmpty() && bCase(sName, pFieldDesc->GetName()); + }; + + sal_Int32 i = 0; + while(std::any_of(m_vRowList.begin(), m_vRowList.end(), lHasName)) + { + // found a second name of _rName so we need another + sName = _rName + OUString::number(++i); + } + return sName; +} + +OUString OTableController::getPrivateTitle() const +{ + OUString sTitle; + try + { + // get the table + if ( !m_sName.isEmpty() && getConnection().is() ) + { + if ( m_xTable.is() ) + sTitle = ::dbtools::composeTableName( getConnection()->getMetaData(), m_xTable, ::dbtools::EComposeRule::InDataManipulation, false ); + else + sTitle = m_sName; + } + if ( sTitle.isEmpty() ) + { + OUString aName = DBA_RES(STR_TBL_TITLE); + sTitle = o3tl::getToken(aName,0,' ') + OUString::number(getCurrentStartNumber()); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return sTitle; +} + +void OTableController::reload() +{ + loadData(); // fill the column information from the table + static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our information + ClearUndoManager(); + setModified(false); // and we are not modified yet + static_cast<OTableDesignView*>(getView())->Invalidate(); +} + +sal_Int32 OTableController::getFirstEmptyRowPosition() +{ + sal_Int32 nRet = 0; + bool bFoundElem = false; + for (auto const& row : m_vRowList) + { + if ( !row || !row->GetActFieldDescr() || row->GetActFieldDescr()->GetName().isEmpty() ) + { + bFoundElem = true; + break; + } + ++nRet; + } + if (!bFoundElem) + { + bool bReadRow = !isAddAllowed(); + auto pTabEdRow = std::make_shared<OTableRow>(); + pTabEdRow->SetReadOnly(bReadRow); + nRet = m_vRowList.size(); + m_vRowList.push_back( pTabEdRow); + } + return nRet; +} + +bool OTableController::isAutoIncrementPrimaryKey() const +{ + return getSdbMetaData().isAutoIncrementPrimaryKey(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableDesignControl.cxx b/dbaccess/source/ui/tabledesign/TableDesignControl.cxx new file mode 100644 index 000000000..1526682ed --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableDesignControl.cxx @@ -0,0 +1,172 @@ +/* -*- 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 <TableDesignControl.hxx> +#include <TableDesignView.hxx> +#include <TableController.hxx> +#include <com/sun/star/util/URL.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <vcl/commandevent.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weldutils.hxx> +#include <helpids.h> + +using namespace ::dbaui; +using namespace ::svt; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +// Defines +#define HANDLE_ID 0 + +OTableRowView::OTableRowView(vcl::Window* pParent) + : EditBrowseBox(pParent, EditBrowseBoxFlags::NONE, WB_TABSTOP|WB_HIDE|WB_3DLOOK, + BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION | + BrowserMode::AUTOSIZE_LASTCOL | BrowserMode::KEEPHIGHLIGHT | + BrowserMode::HLINES | BrowserMode::VLINES) + , m_nDataPos(-1) + , m_nCurrentPos(-1) + , m_nCurUndoActId(0) +{ + SetHelpId(HID_TABDESIGN_BACKGROUND); + SetSizePixel(LogicToPixel(Size(40, 12), MapMode(MapUnit::MapAppFont))); +} + +void OTableRowView::Init() +{ + EditBrowseBox::Init(); + + vcl::Font aFont( GetDataWindow().GetFont() ); + aFont.SetWeight( WEIGHT_NORMAL ); + GetDataWindow().SetFont( aFont ); + + // set font for the headings to light + aFont = GetFont(); + aFont.SetWeight( WEIGHT_LIGHT ); + SetFont(aFont); + + // set up HandleColumn for at maximum 5 digits + InsertHandleColumn(static_cast<sal_uInt16>(GetTextWidth(OUString('0')) * 4)/*, sal_True */); + + BrowserMode const nMode = BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION | BrowserMode::KEEPHIGHLIGHT | + BrowserMode::HLINES | BrowserMode::VLINES | BrowserMode::AUTOSIZE_LASTCOL; + + SetMode(nMode); +} + +void OTableRowView::KeyInput( const KeyEvent& rEvt ) +{ + if (IsDeleteAllowed()) + { + if (rEvt.GetKeyCode().GetCode() == KEY_DELETE && // Delete rows + !rEvt.GetKeyCode().IsShift() && + !rEvt.GetKeyCode().IsMod1()) + { + DeleteRows(); + return; + } + if( rEvt.GetKeyCode().GetCode() == KEY_F2 ) + { + css::util::URL aUrl; + aUrl.Complete = ".uno:DSBEditDoc"; + GetView()->getController().dispatch( aUrl,Sequence< PropertyValue >() ); + } + } + EditBrowseBox::KeyInput(rEvt); +} + +void OTableRowView::Command(const CommandEvent& rEvt) +{ + + switch (rEvt.GetCommand()) + { + case CommandEventId::ContextMenu: + { + if (!rEvt.IsMouseEvent()) + { + EditBrowseBox::Command(rEvt); + return; + } + + sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X())); + sal_Int32 nRow = GetRowAtYPosPixel(rEvt.GetMousePosPixel().Y()); + + if ( nColId == HANDLE_ID ) + { + ::tools::Rectangle aRect(rEvt.GetMousePosPixel(), Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/tabledesignrowmenu.ui")); + std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu")); + sal_Int32 nSelectRowCount = GetSelectRowCount(); + xContextMenu->set_sensitive("cut", nSelectRowCount != 0); + xContextMenu->set_sensitive("copy", nSelectRowCount != 0); + OString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect); + if (sIdent == "cut") + cut(); + else if (sIdent == "copy") + copy(); + else if (sIdent == "insert") + { + InsertNewRows( nRow ); + SetNoSelection(); + GoToRow( nRow ); + SeekRow( nRow ); + } + + return; + } + + [[fallthrough]]; + } + default: + EditBrowseBox::Command(rEvt); + } + +} + +void OTableRowView::cut() +{ + CopyRows(); + DeleteRows(); +} + +void OTableRowView::copy() +{ + CopyRows(); +} + +void OTableRowView::paste() +{ + OSL_FAIL("OTableRowView::Paste : (pseudo-) abstract method called !"); +} + +void OTableRowView::Paste( sal_Int32 nRow ) +{ + InsertRows( nRow ); +} + +EditBrowseBox::RowStatus OTableRowView::GetRowStatus(sal_Int32 nRow) const +{ + if (nRow >= 0 && m_nDataPos == nRow) + return CURRENT; + else + return CLEAN; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx b/dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx new file mode 100644 index 000000000..f81123e55 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableDesignHelpBar.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 <TableDesignHelpBar.hxx> +#include <helpids.h> + +using namespace dbaui; + +#define DETAILS_MIN_HELP_WIDTH 200 + +OTableDesignHelpBar::OTableDesignHelpBar(std::unique_ptr<weld::TextView> xTextWin) + : m_xTextWin(std::move(xTextWin)) +{ + m_xTextWin->set_size_request(DETAILS_MIN_HELP_WIDTH, -1); + m_xTextWin->set_help_id(HID_TAB_DESIGN_HELP_TEXT_FRAME); +} + +void OTableDesignHelpBar::SetHelpText(const OUString& rText) +{ + if (!m_xTextWin) + return; + m_xTextWin->set_text(rText); +} + +bool OTableDesignHelpBar::isCopyAllowed() +{ + int mStartPos, nEndPos; + return m_xTextWin && m_xTextWin->get_selection_bounds(mStartPos, nEndPos); +} + +bool OTableDesignHelpBar::isCutAllowed() { return false; } + +bool OTableDesignHelpBar::isPasteAllowed() { return false; } + +void OTableDesignHelpBar::cut() {} + +void OTableDesignHelpBar::copy() +{ + if (!m_xTextWin) + return; + m_xTextWin->copy_clipboard(); +} + +void OTableDesignHelpBar::paste() {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableDesignView.cxx b/dbaccess/source/ui/tabledesign/TableDesignView.cxx new file mode 100644 index 000000000..f0570ddba --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableDesignView.cxx @@ -0,0 +1,260 @@ +/* -*- 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 <TableDesignView.hxx> +#include <TableController.hxx> +#include <helpids.h> +#include <FieldDescriptions.hxx> +#include "TEditControl.hxx" +#include "TableFieldDescWin.hxx" +#include <TableRow.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <unotools/syslocale.hxx> +#include <memory> + +using namespace ::dbaui; +using namespace ::utl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::datatransfer::clipboard; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +OTableBorderWindow::OTableBorderWindow(OTableDesignView* pParent) + : InterimItemWindow(pParent, "dbaccess/ui/tableborderwindow.ui", "TableBorderWindow", false) + , m_xHorzSplitter(m_xBuilder->weld_paned("splitter")) + , m_xEditorParent(m_xBuilder->weld_container("editor")) + , m_xEditorParentWin(m_xEditorParent->CreateChildFrame()) + , m_xEditorCtrl(VclPtr<OTableEditorCtrl>::Create(VCLUnoHelper::GetWindow(m_xEditorParentWin), pParent)) + , m_xFieldDescParent(m_xBuilder->weld_container("fielddesc")) + , m_xFieldDescWin(new OTableFieldDescWin(m_xFieldDescParent.get(), pParent)) +{ + SetStyle(GetStyle() | WB_DIALOGCONTROL); + + m_xFieldDescWin->SetHelpId(HID_TAB_DESIGN_DESCWIN); + + // set depending windows and controls + m_xEditorCtrl->SetDescrWin(m_xFieldDescWin.get()); +} + +OTableBorderWindow::~OTableBorderWindow() +{ + disposeOnce(); +} + +void OTableBorderWindow::dispose() +{ + // destroy children + m_xEditorCtrl.disposeAndClear(); + m_xEditorParentWin->dispose(); + m_xEditorParentWin.clear(); + m_xEditorParent.reset(); + m_xFieldDescWin.reset(); + m_xFieldDescParent.reset(); + m_xHorzSplitter.reset(); + InterimItemWindow::dispose(); +} + +void OTableBorderWindow::Layout() +{ + // dimensions of parent window + auto nOutputHeight = GetSizePixel().Height(); + auto nOldSplitPos = m_xHorzSplitter->get_position(); + auto nSplitPos = nOldSplitPos; + + // shift range of the splitter is the middle third of the output + auto nDragPosY = nOutputHeight/3; + auto nDragSizeHeight = nOutputHeight/3; + if (nSplitPos < nDragPosY || nSplitPos > nDragPosY + nDragSizeHeight) + nSplitPos = nDragPosY + nDragSizeHeight; + + // set splitter + m_xHorzSplitter->set_position(nSplitPos); + + InterimItemWindow::Layout(); + + if (nOldSplitPos != nSplitPos) + m_xHorzSplitter->set_position(nSplitPos); +} + +void OTableBorderWindow::GetFocus() +{ + InterimItemWindow::GetFocus(); + + // forward the focus to the current cell of the editor control + if (m_xEditorCtrl) + m_xEditorCtrl->GrabFocus(); +} + +OTableDesignView::OTableDesignView( vcl::Window* pParent, + const Reference< XComponentContext >& _rxOrb, + OTableController& _rController + ) : + ODataView( pParent, _rController,_rxOrb ) + ,m_rController( _rController ) + ,m_eChildFocus(NONE) +{ + + try + { + m_aLocale = SvtSysLocale().GetLanguageTag().getLocale(); + } + catch(Exception&) + { + } + + m_pWin = VclPtr<OTableBorderWindow>::Create(this); + + m_pWin->GetDescWin()->connect_focus_in(LINK(this, OTableDesignView, FieldDescFocusIn)); + + m_pWin->Show(); +} + +OTableDesignView::~OTableDesignView() +{ + disposeOnce(); +} + +void OTableDesignView::dispose() +{ + m_pWin->Hide(); + m_pWin.disposeAndClear(); + ODataView::dispose(); +} + +void OTableDesignView::initialize() +{ + GetEditorCtrl()->Init(); + GetDescWin()->Init(); + // first call after the editctrl has been set + + GetEditorCtrl()->Show(); + GetDescWin()->Show(); + + GetEditorCtrl()->DisplayData(0); +} + +void OTableDesignView::resizeDocumentView(tools::Rectangle& _rPlayground) +{ + m_pWin->SetPosSizePixel( _rPlayground.TopLeft(), _rPlayground.GetSize() ); + + // just for completeness: there is no space left, we occupied it all ... + _rPlayground.SetPos( _rPlayground.BottomRight() ); + _rPlayground.SetSize( Size( 0, 0 ) ); +} + +IMPL_LINK_NOARG(OTableDesignView, FieldDescFocusIn, weld::Widget&, void) +{ + m_eChildFocus = DESCRIPTION; +} + +bool OTableDesignView::PreNotify( NotifyEvent& rNEvt ) +{ + if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + { + if( GetDescWin() && GetDescWin()->HasChildPathFocus() ) + m_eChildFocus = DESCRIPTION; + else if ( GetEditorCtrl() && GetEditorCtrl()->HasChildPathFocus() ) + m_eChildFocus = EDITOR; + else + m_eChildFocus = NONE; + } + + return ODataView::PreNotify(rNEvt); +} + +IClipboardTest* OTableDesignView::getActiveChild() const +{ + IClipboardTest* pTest = nullptr; + switch(m_eChildFocus) + { + case DESCRIPTION: + pTest = GetDescWin(); + break; + case EDITOR: + pTest = GetEditorCtrl(); + break; + case NONE: + break; + } + return pTest; +} + +bool OTableDesignView::isCopyAllowed() +{ + IClipboardTest* pTest = getActiveChild(); + return pTest && pTest->isCopyAllowed(); +} + +bool OTableDesignView::isCutAllowed() +{ + IClipboardTest* pTest = getActiveChild(); + return pTest && pTest->isCutAllowed(); +} + +bool OTableDesignView::isPasteAllowed() +{ + IClipboardTest* pTest = getActiveChild(); + return pTest && pTest->isPasteAllowed(); +} + +void OTableDesignView::copy() +{ + IClipboardTest* pTest = getActiveChild(); + if ( pTest ) + pTest->copy(); +} + +void OTableDesignView::cut() +{ + IClipboardTest* pTest = getActiveChild(); + if ( pTest ) + pTest->cut(); +} + +void OTableDesignView::paste() +{ + IClipboardTest* pTest = getActiveChild(); + if ( pTest ) + pTest->paste(); +} + +// set the view readonly or not +void OTableDesignView::setReadOnly(bool _bReadOnly) +{ + GetDescWin()->SetReadOnly(_bReadOnly); + GetEditorCtrl()->SetReadOnly(_bReadOnly); +} + +void OTableDesignView::reSync() +{ + GetEditorCtrl()->DeactivateCell(); + std::shared_ptr<OTableRow> pRow = (*GetEditorCtrl()->GetRowList())[GetEditorCtrl()->GetCurRow()]; + OFieldDescription* pFieldDescr = pRow ? pRow->GetActFieldDescr() : nullptr; + if ( pFieldDescr ) + GetDescWin()->DisplayData(pFieldDescr); +} + +void OTableDesignView::GetFocus() +{ + if ( GetEditorCtrl() ) + GetEditorCtrl()->GrabFocus(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableFieldControl.cxx b/dbaccess/source/ui/tabledesign/TableFieldControl.cxx new file mode 100644 index 000000000..aa04b914a --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldControl.cxx @@ -0,0 +1,154 @@ +/* -*- 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 "TableFieldControl.hxx" +#include <TableController.hxx> +#include <TableDesignView.hxx> +#include "TEditControl.hxx" +#include <strings.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <comphelper/types.hxx> +#include <TypeInfo.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace dbaui; + +OTableFieldControl::OTableFieldControl(weld::Container* pParent, OTableDesignHelpBar* pHelpBar, OTableDesignView* pView) + : OFieldDescControl(pParent, pHelpBar) + , m_xView(pView) +{ +} + +void OTableFieldControl::dispose() +{ + m_xView.clear(); +} + +OTableFieldControl::~OTableFieldControl() +{ + dispose(); +} + +void OTableFieldControl::CellModified(sal_Int32 nRow, sal_uInt16 nColId ) +{ + GetCtrl()->CellModified(nRow,nColId); +} + +OTableEditorCtrl* OTableFieldControl::GetCtrl() const +{ + assert(m_xView && "no view!"); + return m_xView->GetEditorCtrl(); +} + +bool OTableFieldControl::IsReadOnly() +{ + bool bRead(GetCtrl()->IsReadOnly()); + if( !bRead ) + { + // The columns of a css::sdbcx::View could not be locked + Reference<XPropertySet> xTable = GetCtrl()->GetView()->getController().getTable(); + if(xTable.is() && ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW") + bRead = true; + else + { + std::shared_ptr<OTableRow> pCurRow = GetCtrl()->GetActRow(); + if( pCurRow ) + bRead = pCurRow->IsReadOnly(); + } + } + return bRead; +} + +void OTableFieldControl::ActivateAggregate( EControlType eType ) +{ + switch(eType) + { + case tpColumnName: + case tpType: + break; + default: + OFieldDescControl::ActivateAggregate(eType); + } +} + +void OTableFieldControl::DeactivateAggregate( EControlType eType ) +{ + switch(eType) + { + case tpColumnName: + case tpType: + break; + default: + OFieldDescControl::DeactivateAggregate(eType); + } +} + +void OTableFieldControl::SetModified(bool bModified) +{ + GetCtrl()->GetView()->getController().setModified(bModified); +} + +css::uno::Reference< css::sdbc::XConnection> OTableFieldControl::getConnection() +{ + return GetCtrl()->GetView()->getController().getConnection(); +} + +css::uno::Reference< css::sdbc::XDatabaseMetaData> OTableFieldControl::getMetaData() +{ + Reference<XConnection> xCon = GetCtrl()->GetView()->getController().getConnection(); + if(!xCon.is()) + return nullptr; + return xCon->getMetaData(); +} + +Reference< XNumberFormatter > OTableFieldControl::GetFormatter() const +{ + return GetCtrl()->GetView()->getController().getNumberFormatter(); +} + +TOTypeInfoSP OTableFieldControl::getTypeInfo(sal_Int32 _nPos) +{ + return GetCtrl()->GetView()->getController().getTypeInfo(_nPos); +} + +const OTypeInfoMap* OTableFieldControl::getTypeInfo() const +{ + return &GetCtrl()->GetView()->getController().getTypeInfo(); +} + +Locale OTableFieldControl::GetLocale() const +{ + return GetCtrl()->GetView()->getLocale(); +} + +bool OTableFieldControl::isAutoIncrementValueEnabled() const +{ + return GetCtrl()->GetView()->getController().isAutoIncrementValueEnabled(); +} + +OUString OTableFieldControl::getAutoIncrementValue() const +{ + return GetCtrl()->GetView()->getController().getAutoIncrementValue(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableFieldControl.hxx b/dbaccess/source/ui/tabledesign/TableFieldControl.hxx new file mode 100644 index 000000000..4a232f86c --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldControl.hxx @@ -0,0 +1,66 @@ +/* -*- 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 <FieldDescControl.hxx> + +namespace dbaui +{ + class OTableEditorCtrl; + class OTableDesignHelpBar; + class OTableDesignView; + + // OTableFieldControl + class OTableFieldControl : public OFieldDescControl + { + VclPtr<OTableDesignView> m_xView; + + OTableEditorCtrl* GetCtrl() const; + + void dispose(); + + protected: + virtual void ActivateAggregate( EControlType eType ) override; + virtual void DeactivateAggregate( EControlType eType ) override; + // are to be implemented by the derived classes + virtual void CellModified(sal_Int32 nRow, sal_uInt16 nColId ) override; + virtual bool IsReadOnly() override; + virtual void SetModified(bool bModified) override; + virtual css::uno::Reference< css::util::XNumberFormatter > GetFormatter() const override; + + virtual css::lang::Locale GetLocale() const override; + + virtual TOTypeInfoSP getTypeInfo(sal_Int32 _nPos) override; + virtual const OTypeInfoMap* getTypeInfo() const override; + virtual bool isAutoIncrementValueEnabled() const override; + virtual OUString getAutoIncrementValue() const override; + + public: + OTableFieldControl(weld::Container* pParent, OTableDesignHelpBar* pHelpBar, OTableDesignView* pView); + virtual ~OTableFieldControl() override; + + using OFieldDescControl::BoolStringPersistent; + using OFieldDescControl::BoolStringUI; + + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() override; + virtual css::uno::Reference< css::sdbc::XConnection> getConnection() override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx b/dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx new file mode 100644 index 000000000..7e6c4f111 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx @@ -0,0 +1,140 @@ +/* -*- 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 "TableFieldDescWin.hxx" +#include <FieldDescriptions.hxx> +#include <strings.hrc> +#include <TableDesignHelpBar.hxx> +#include <helpids.h> +#include <core_resource.hxx> + +using namespace dbaui; + +OTableFieldDescWin::OTableFieldDescWin(weld::Container* pParent, OTableDesignView* pView) + : OChildWindow(pParent, "dbaccess/ui/fielddescpanel.ui", "FieldDescPanel") + , m_xHelpBar(new OTableDesignHelpBar(m_xBuilder->weld_text_view("textview"))) + , m_xBox(m_xBuilder->weld_container("box")) + , m_xFieldControl(new OTableFieldControl(m_xBox.get(), m_xHelpBar.get(), pView)) + , m_xHeader(m_xBuilder->weld_label("header")) + , m_eChildFocus(NONE) +{ + // Header + m_xHeader->set_label(DBA_RES(STR_TAB_PROPERTIES)); + + m_xFieldControl->SetHelpId(HID_TAB_DESIGN_FIELDCONTROL); + + m_xHelpBar->connect_focus_in(LINK(this, OTableFieldDescWin, HelpFocusIn)); + m_xFieldControl->connect_focus_in(LINK(this, OTableFieldDescWin, FieldFocusIn)); +} + +bool OTableFieldDescWin::HasChildPathFocus() const +{ + return m_xFieldControl->HasChildPathFocus() || m_xHelpBar->HasFocus(); +} + +OTableFieldDescWin::~OTableFieldDescWin() +{ +} + +void OTableFieldDescWin::Init() +{ + m_xFieldControl->Init(); +} + +void OTableFieldDescWin::SetReadOnly( bool bRead ) +{ + m_xFieldControl->SetReadOnly( bRead ); +} + +void OTableFieldDescWin::DisplayData( OFieldDescription* pFieldDescr ) +{ + m_xFieldControl->DisplayData( pFieldDescr ); +} + +void OTableFieldDescWin::SaveData( OFieldDescription* pFieldDescr ) +{ + m_xFieldControl->SaveData( pFieldDescr ); +} + +IClipboardTest* OTableFieldDescWin::getActiveChild() const +{ + IClipboardTest* pTest = nullptr; + switch(m_eChildFocus) + { + case DESCRIPTION: + pTest = m_xFieldControl.get(); + break; + default: + pTest = m_xHelpBar.get(); + break; + } + return pTest; +} + +bool OTableFieldDescWin::isCopyAllowed() +{ + return getActiveChild() && getActiveChild()->isCopyAllowed(); +} + +bool OTableFieldDescWin::isCutAllowed() +{ + return getActiveChild() && getActiveChild()->isCutAllowed(); +} + +bool OTableFieldDescWin::isPasteAllowed() +{ + return getActiveChild() && getActiveChild()->isPasteAllowed(); +} + +void OTableFieldDescWin::cut() +{ + if (getActiveChild()) + getActiveChild()->cut(); +} + +void OTableFieldDescWin::copy() +{ + if ( getActiveChild() ) + getActiveChild()->copy(); +} + +void OTableFieldDescWin::paste() +{ + if (getActiveChild()) + getActiveChild()->paste(); +} + +void OTableFieldDescWin::GrabFocus() +{ + m_xFieldControl->GrabFocus(); +} + +IMPL_LINK(OTableFieldDescWin, HelpFocusIn, weld::Widget&, rWidget, void) +{ + m_eChildFocus = HELP; + m_aFocusInHdl.Call(rWidget); +} + +IMPL_LINK(OTableFieldDescWin, FieldFocusIn, weld::Widget&, rWidget, void) +{ + m_eChildFocus = DESCRIPTION; + m_aFocusInHdl.Call(rWidget); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx b/dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx new file mode 100644 index 000000000..9f15c1e1b --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx @@ -0,0 +1,91 @@ +/* -*- 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 <IClipBoardTest.hxx> +#include <ChildWindow.hxx> +#include "TableFieldControl.hxx" + +namespace dbaui +{ + class OTableDesignHelpBar; + class OTableDesignView; + class OFieldDescription; + + class OTableFieldDescWin final : public OChildWindow + , public IClipboardTest + { + enum ChildFocusState + { + DESCRIPTION, + HELP, + NONE + }; + private: + std::unique_ptr<OTableDesignHelpBar> m_xHelpBar; + std::unique_ptr<weld::Container> m_xBox; + std::unique_ptr<OTableFieldControl> m_xFieldControl; + std::unique_ptr<weld::Label> m_xHeader; + Link<weld::Widget&, void> m_aFocusInHdl; + + ChildFocusState m_eChildFocus; + + IClipboardTest* getActiveChild() const; + + DECL_LINK(HelpFocusIn, weld::Widget&, void); + DECL_LINK(FieldFocusIn, weld::Widget&, void); + + public: + explicit OTableFieldDescWin(weld::Container* pParent, OTableDesignView* pView); + virtual ~OTableFieldDescWin() override; + + void Init(); + + void DisplayData( OFieldDescription* pFieldDescr ); + void SaveData( OFieldDescription* pFieldDescr ); + void SetReadOnly( bool bReadOnly ); + + void SetControlText( sal_uInt16 nControlId, const OUString& rText ) + { m_xFieldControl->SetControlText(nControlId,rText); } + + OUString BoolStringPersistent(std::u16string_view rUIString) const { return m_xFieldControl->BoolStringPersistent(rUIString); } + OUString BoolStringUI(const OUString& rPersistentString) const { return m_xFieldControl->BoolStringUI(rPersistentString); } + + virtual bool HasChildPathFocus() const override; + virtual void GrabFocus() override; + + // IClipboardTest + virtual bool isCutAllowed() override; + virtual bool isCopyAllowed() override; + virtual bool isPasteAllowed() override; + + virtual void copy() override; + virtual void cut() override; + virtual void paste() override; + + void connect_focus_in(const Link<weld::Widget&, void>& rLink) + { + m_aFocusInHdl = rLink; + } + + OTableFieldControl* getGenPage() const { return m_xFieldControl.get(); } + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableRow.cxx b/dbaccess/source/ui/tabledesign/TableRow.cxx new file mode 100644 index 000000000..8f13193e1 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableRow.cxx @@ -0,0 +1,183 @@ +/* -*- 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 <TableRow.hxx> +#include <tools/stream.hxx> +#include <FieldDescriptions.hxx> +#include <comphelper/types.hxx> + +using namespace dbaui; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +OTableRow::OTableRow() + :m_pActFieldDescr( nullptr ) + ,m_nPos( -1 ) + ,m_bReadOnly( false ) + ,m_bOwnsDescriptions(false) +{ +} + +OTableRow::OTableRow( const OTableRow& rRow, tools::Long nPosition ) + :m_pActFieldDescr(nullptr) + ,m_nPos( nPosition ) + ,m_bReadOnly(rRow.IsReadOnly()) + ,m_bOwnsDescriptions(false) +{ + + OFieldDescription* pSrcField = rRow.GetActFieldDescr(); + if(pSrcField) + { + m_pActFieldDescr = new OFieldDescription(*pSrcField); + m_bOwnsDescriptions = true; + } +} + +OTableRow::~OTableRow() +{ + if(m_bOwnsDescriptions) + delete m_pActFieldDescr; +} + +void OTableRow::SetPrimaryKey( bool bSet ) +{ + if(m_pActFieldDescr) + m_pActFieldDescr->SetPrimaryKey(bSet); +} + +bool OTableRow::IsPrimaryKey() const +{ + return m_pActFieldDescr && m_pActFieldDescr->IsPrimaryKey(); +} + +void OTableRow::SetFieldType( const TOTypeInfoSP& _pType, bool _bForce ) +{ + if ( _pType ) + { + if( !m_pActFieldDescr ) + { + m_pActFieldDescr = new OFieldDescription(); + m_bOwnsDescriptions = true; + } + m_pActFieldDescr->FillFromTypeInfo(_pType,_bForce,true); + } + else + { + delete m_pActFieldDescr; + m_pActFieldDescr = nullptr; + } +} + +namespace dbaui +{ + SvStream& WriteOTableRow( SvStream& _rStr, const OTableRow& _rRow ) + { + _rStr.WriteInt32( _rRow.m_nPos ); + OFieldDescription* pFieldDesc = _rRow.GetActFieldDescr(); + if(pFieldDesc) + { + _rStr.WriteInt32( 1 ); + _rStr.WriteUniOrByteString(pFieldDesc->GetName(), _rStr.GetStreamCharSet()); + _rStr.WriteUniOrByteString(pFieldDesc->GetDescription(), _rStr.GetStreamCharSet()); + _rStr.WriteUniOrByteString(pFieldDesc->GetHelpText(), _rStr.GetStreamCharSet()); + double nValue = 0.0; + Any aValue = pFieldDesc->GetControlDefault(); + if ( aValue >>= nValue ) + { + _rStr.WriteInt32( 1 ); + _rStr.WriteDouble( nValue ); + } + else + { + _rStr.WriteInt32( 2 ); + _rStr.WriteUniOrByteString(::comphelper::getString(aValue), _rStr.GetStreamCharSet()); + } + + _rStr.WriteInt32( pFieldDesc->GetType() ); + + _rStr.WriteInt32( pFieldDesc->GetPrecision() ); + _rStr.WriteInt32( pFieldDesc->GetScale() ); + _rStr.WriteInt32( pFieldDesc->GetIsNullable() ); + _rStr.WriteInt32( pFieldDesc->GetFormatKey() ); + _rStr.WriteInt32( static_cast<sal_Int32>(pFieldDesc->GetHorJustify()) ); + _rStr.WriteInt32( pFieldDesc->IsAutoIncrement() ? 1 : 0 ); + _rStr.WriteInt32( pFieldDesc->IsPrimaryKey() ? 1 : 0 ); + _rStr.WriteInt32( pFieldDesc->IsCurrency() ? 1 : 0 ); + } + else + _rStr.WriteInt32( 0 ); + return _rStr; + } + SvStream& ReadOTableRow( SvStream& _rStr, OTableRow& _rRow ) + { + _rStr.ReadInt32( _rRow.m_nPos ); + sal_Int32 nValue = 0; + _rStr.ReadInt32( nValue ); + if ( !nValue ) + return _rStr; + OFieldDescription* pFieldDesc = new OFieldDescription(); + _rRow.m_pActFieldDescr = pFieldDesc; + pFieldDesc->SetName(_rStr.ReadUniOrByteString(_rStr.GetStreamCharSet())); + pFieldDesc->SetDescription(_rStr.ReadUniOrByteString(_rStr.GetStreamCharSet())); + pFieldDesc->SetHelpText(_rStr.ReadUniOrByteString(_rStr.GetStreamCharSet())); + + _rStr.ReadInt32( nValue ); + Any aControlDefault; + switch ( nValue ) + { + case 1: + { + double nControlDefault; + _rStr.ReadDouble( nControlDefault ); + aControlDefault <<= nControlDefault; + break; + } + case 2: + aControlDefault <<= _rStr.ReadUniOrByteString(_rStr.GetStreamCharSet()); + break; + } + + pFieldDesc->SetControlDefault(aControlDefault); + + _rStr.ReadInt32( nValue ); + pFieldDesc->SetTypeValue(nValue); + + _rStr.ReadInt32( nValue ); + pFieldDesc->SetPrecision(nValue); + _rStr.ReadInt32( nValue ); + pFieldDesc->SetScale(nValue); + _rStr.ReadInt32( nValue ); + pFieldDesc->SetIsNullable(nValue); + _rStr.ReadInt32( nValue ); + pFieldDesc->SetFormatKey(nValue); + _rStr.ReadInt32( nValue ); + pFieldDesc->SetHorJustify(static_cast<SvxCellHorJustify>(nValue)); + + _rStr.ReadInt32( nValue ); + pFieldDesc->SetAutoIncrement(nValue != 0); + _rStr.ReadInt32( nValue ); + pFieldDesc->SetPrimaryKey(nValue != 0); + _rStr.ReadInt32( nValue ); + pFieldDesc->SetCurrency(nValue != 0); + return _rStr; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableRowExchange.cxx b/dbaccess/source/ui/tabledesign/TableRowExchange.cxx new file mode 100644 index 000000000..c56450ac1 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableRowExchange.cxx @@ -0,0 +1,67 @@ +/* -*- 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 <TableRowExchange.hxx> +#include <sot/formats.hxx> +#include <sot/storage.hxx> +#include <TableRow.hxx> + +namespace dbaui +{ + constexpr sal_uInt32 FORMAT_OBJECT_ID_SBA_TABED = 1; + + using namespace ::com::sun::star::uno; + OTableRowExchange::OTableRowExchange(std::vector< std::shared_ptr<OTableRow> >&& _rvTableRow) + : m_vTableRow(std::move(_rvTableRow)) + { + } + bool OTableRowExchange::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor& /*rFlavor*/ ) + { + if(nUserObjectId == FORMAT_OBJECT_ID_SBA_TABED) + { + std::vector< std::shared_ptr<OTableRow> >* pRows = static_cast< std::vector< std::shared_ptr<OTableRow> >* >(pUserObject); + if(pRows) + { + (*rxOStm).WriteInt32( pRows->size() ); // first stream the size + for (auto const& row : *pRows) + WriteOTableRow(*rxOStm, *row); + return true; + } + } + return false; + } + void OTableRowExchange::AddSupportedFormats() + { + if ( !m_vTableRow.empty() ) + AddFormat(SotClipboardFormatId::SBA_TABED); + } + bool OTableRowExchange::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ ) + { + SotClipboardFormatId nFormat = SotExchange::GetFormat(rFlavor); + if(nFormat == SotClipboardFormatId::SBA_TABED) + return SetObject(&m_vTableRow,FORMAT_OBJECT_ID_SBA_TABED,rFlavor); + return false; + } + void OTableRowExchange::ObjectReleased() + { + m_vTableRow.clear(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableUndo.cxx b/dbaccess/source/ui/tabledesign/TableUndo.cxx new file mode 100644 index 000000000..d60756a2e --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableUndo.cxx @@ -0,0 +1,352 @@ +/* -*- 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 "TableUndo.hxx" +#include <strings.hrc> +#include "TEditControl.hxx" +#include <TableRow.hxx> +#include <TableController.hxx> +#include <TableDesignView.hxx> +#include <FieldDescriptions.hxx> +#include <svx/svxids.hrc> + +using namespace dbaui; +using namespace ::svt; + + +OTableDesignUndoAct::OTableDesignUndoAct(OTableRowView* pOwner, TranslateId pCommentID) + : OCommentUndoAction(pCommentID) + , m_pTabDgnCtrl(pOwner) +{ + m_pTabDgnCtrl->m_nCurUndoActId++; +} + +OTableDesignUndoAct::~OTableDesignUndoAct() +{ +} + +void OTableDesignUndoAct::Undo() +{ + m_pTabDgnCtrl->m_nCurUndoActId--; + + // doc has not been modified if first undo was reverted + if( m_pTabDgnCtrl->m_nCurUndoActId == 0 ) + { + m_pTabDgnCtrl->GetView()->getController().setModified(false); + m_pTabDgnCtrl->GetView()->getController().InvalidateFeature(SID_SAVEDOC); + } +} + +void OTableDesignUndoAct::Redo() +{ + m_pTabDgnCtrl->m_nCurUndoActId++; + + // restore Modified-flag after Redo of first Undo-action + if( m_pTabDgnCtrl->m_nCurUndoActId > 0 ) + { + m_pTabDgnCtrl->GetView()->getController().setModified(true); + m_pTabDgnCtrl->GetView()->getController().InvalidateFeature(SID_SAVEDOC); + } +} + +OTableDesignCellUndoAct::OTableDesignCellUndoAct( OTableRowView* pOwner, sal_Int32 nRowID, sal_uInt16 nColumn ) : + OTableDesignUndoAct( pOwner ,STR_TABED_UNDO_CELLMODIFIED) + ,m_nCol( nColumn ) + ,m_nRow( nRowID ) +{ + // read text at position (m_nRow, m_nCol) + m_sOldText = m_pTabDgnCtrl->GetCellData( m_nRow, m_nCol ); +} + +OTableDesignCellUndoAct::~OTableDesignCellUndoAct() +{ +} + +void OTableDesignCellUndoAct::Undo() +{ + // store text at old line and restore the old one + m_pTabDgnCtrl->ActivateCell( m_nRow, m_nCol ); + m_sNewText = m_pTabDgnCtrl->GetCellData( m_nRow, m_nCol ); + m_pTabDgnCtrl->SetCellData( m_nRow, m_nCol, m_sOldText ); + // line has not been modified if the first Undo was reverted + if (m_pTabDgnCtrl->GetCurUndoActId() == 1) + { + CellControllerRef xController = m_pTabDgnCtrl->Controller(); + if ( xController.is() ) + xController->SaveValue(); + m_pTabDgnCtrl->GetView()->getController().setModified(false); + + } + + OTableDesignUndoAct::Undo(); +} + +void OTableDesignCellUndoAct::Redo() +{ + // restore new text + m_pTabDgnCtrl->ActivateCell( m_nRow, m_nCol ); + m_pTabDgnCtrl->SetCellData( m_nRow, m_nCol, m_sNewText ); + + OTableDesignUndoAct::Redo(); +} + +OTableEditorUndoAct::OTableEditorUndoAct(OTableEditorCtrl* pOwner, TranslateId pCommentID) + : OTableDesignUndoAct(pOwner, pCommentID) + , pTabEdCtrl(pOwner) +{ +} + +OTableEditorUndoAct::~OTableEditorUndoAct() +{ +} + +OTableEditorTypeSelUndoAct::OTableEditorTypeSelUndoAct( OTableEditorCtrl* pOwner, sal_Int32 nRowID, sal_uInt16 nColumn, const TOTypeInfoSP& _pOldType ) + :OTableEditorUndoAct( pOwner ,STR_TABED_UNDO_TYPE_CHANGED) + ,m_nCol( nColumn ) + ,m_nRow( nRowID ) + ,m_pOldType( _pOldType ) +{ +} + +OTableEditorTypeSelUndoAct::~OTableEditorTypeSelUndoAct() +{ +} + +void OTableEditorTypeSelUndoAct::Undo() +{ + // restore type + OFieldDescription* pFieldDesc = pTabEdCtrl->GetFieldDescr(m_nRow); + if(pFieldDesc) + m_pNewType = pFieldDesc->getTypeInfo(); + else + m_pNewType = TOTypeInfoSP(); + pTabEdCtrl->SetCellData(m_nRow,m_nCol,m_pOldType); + pTabEdCtrl->SwitchType( m_pOldType ); + + OTableEditorUndoAct::Undo(); +} + +void OTableEditorTypeSelUndoAct::Redo() +{ + // new type + pTabEdCtrl->GoToRowColumnId( m_nRow ,m_nCol); + pTabEdCtrl->SetCellData(m_nRow,m_nCol,m_pNewType); + + OTableEditorUndoAct::Redo(); +} + +OTableEditorDelUndoAct::OTableEditorDelUndoAct( OTableEditorCtrl* pOwner) : + OTableEditorUndoAct( pOwner ,STR_TABED_UNDO_ROWDELETED) +{ + // fill DeletedRowList + std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pOwner->GetRowList(); + sal_Int32 nIndex = pOwner->FirstSelectedRow(); + std::shared_ptr<OTableRow> pOriginalRow; + std::shared_ptr<OTableRow> pNewRow; + + while( nIndex != SFX_ENDOFSELECTION ) + { + pOriginalRow = (*pOriginalRows)[nIndex]; + pNewRow = std::make_shared<OTableRow>( *pOriginalRow, nIndex ); + m_aDeletedRows.push_back( pNewRow); + + nIndex = pOwner->NextSelectedRow(); + } +} + +OTableEditorDelUndoAct::~OTableEditorDelUndoAct() +{ + m_aDeletedRows.clear(); +} + +void OTableEditorDelUndoAct::Undo() +{ + // Insert the deleted line + sal_uLong nPos; + + std::shared_ptr<OTableRow> pNewOrigRow; + std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pTabEdCtrl->GetRowList(); + + for (auto const& deletedRow : m_aDeletedRows) + { + pNewOrigRow = std::make_shared<OTableRow>( *deletedRow ); + nPos = deletedRow->GetPos(); + pOriginalRows->insert( pOriginalRows->begin()+nPos,pNewOrigRow); + } + + pTabEdCtrl->DisplayData(pTabEdCtrl->GetCurRow()); + pTabEdCtrl->Invalidate(); + OTableEditorUndoAct::Undo(); +} + +void OTableEditorDelUndoAct::Redo() +{ + // delete line again + std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pTabEdCtrl->GetRowList(); + + for (auto const& deletedRow : m_aDeletedRows) + { + auto it = pOriginalRows->begin() + deletedRow->GetPos(); + pOriginalRows->erase(it); + } + + pTabEdCtrl->DisplayData(pTabEdCtrl->GetCurRow()); + pTabEdCtrl->Invalidate(); + OTableEditorUndoAct::Redo(); +} + +OTableEditorInsUndoAct::OTableEditorInsUndoAct( OTableEditorCtrl* pOwner, + tools::Long nInsertPosition , + std::vector< std::shared_ptr<OTableRow> >&& _vInsertedRows) + :OTableEditorUndoAct( pOwner,STR_TABED_UNDO_ROWINSERTED ) + ,m_vInsertedRows(std::move(_vInsertedRows)) + ,m_nInsPos( nInsertPosition ) +{ +} + +OTableEditorInsUndoAct::~OTableEditorInsUndoAct() +{ + m_vInsertedRows.clear(); +} + +void OTableEditorInsUndoAct::Undo() +{ + // delete lines again + std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pTabEdCtrl->GetRowList(); + pOriginalRows->erase(pOriginalRows->begin() + m_nInsPos, pOriginalRows->begin() + m_nInsPos + m_vInsertedRows.size()); + + pTabEdCtrl->RowRemoved( m_nInsPos, m_vInsertedRows.size() ); + pTabEdCtrl->InvalidateHandleColumn(); + + OTableEditorUndoAct::Undo(); +} + +void OTableEditorInsUndoAct::Redo() +{ + // insert lines again + sal_Int32 nInsertRow = m_nInsPos; + std::shared_ptr<OTableRow> pRow; + std::vector< std::shared_ptr<OTableRow> >* pRowList = pTabEdCtrl->GetRowList(); + for (auto const& insertedRow : m_vInsertedRows) + { + pRow = std::make_shared<OTableRow>( *insertedRow ); + pRowList->insert( pRowList->begin()+nInsertRow ,pRow ); + nInsertRow++; + } + + pTabEdCtrl->RowInserted( m_nInsPos, m_vInsertedRows.size() ); + pTabEdCtrl->InvalidateHandleColumn(); + + OTableEditorUndoAct::Redo(); +} + +OTableEditorInsNewUndoAct::OTableEditorInsNewUndoAct( OTableEditorCtrl* pOwner, sal_Int32 nInsertPosition, sal_Int32 nInsertedRows ) : + OTableEditorUndoAct( pOwner ,STR_TABED_UNDO_NEWROWINSERTED) + ,m_nInsPos( nInsertPosition ) + ,m_nInsRows( nInsertedRows ) +{ +} + +OTableEditorInsNewUndoAct::~OTableEditorInsNewUndoAct() +{ +} + +void OTableEditorInsNewUndoAct::Undo() +{ + // delete inserted lines + std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pTabEdCtrl->GetRowList(); + + pOriginalRows->erase(pOriginalRows->begin() + m_nInsPos, pOriginalRows->begin() + m_nInsPos + m_nInsRows); + + pTabEdCtrl->RowRemoved( m_nInsPos, m_nInsRows ); + pTabEdCtrl->InvalidateHandleColumn(); + + OTableEditorUndoAct::Undo(); +} + +void OTableEditorInsNewUndoAct::Redo() +{ + // insert lines again + std::vector< std::shared_ptr<OTableRow> >* pRowList = pTabEdCtrl->GetRowList(); + + for( tools::Long i=m_nInsPos; i<(m_nInsPos+m_nInsRows); i++ ) + pRowList->insert( pRowList->begin()+i,std::make_shared<OTableRow>() ); + + pTabEdCtrl->RowInserted( m_nInsPos, m_nInsRows ); + pTabEdCtrl->InvalidateHandleColumn(); + + OTableEditorUndoAct::Redo(); +} + +OPrimKeyUndoAct::OPrimKeyUndoAct( OTableEditorCtrl* pOwner, const MultiSelection& aDeletedKeys, const MultiSelection& aInsertedKeys) : + OTableEditorUndoAct( pOwner ,STR_TABLEDESIGN_UNDO_PRIMKEY) + ,m_aDelKeys( aDeletedKeys ) + ,m_aInsKeys( aInsertedKeys ) + ,m_pEditorCtrl( pOwner ) +{ +} + +OPrimKeyUndoAct::~OPrimKeyUndoAct() +{ +} + +void OPrimKeyUndoAct::Undo() +{ + std::vector< std::shared_ptr<OTableRow> >* pRowList = pTabEdCtrl->GetRowList(); + std::shared_ptr<OTableRow> pRow; + tools::Long nIndex; + + // delete inserted keys + for( nIndex = m_aInsKeys.FirstSelected(); nIndex != tools::Long(SFX_ENDOFSELECTION); nIndex=m_aInsKeys.NextSelected() ) + { + OSL_ENSURE(nIndex <= static_cast<tools::Long>(pRowList->size()),"Index for undo isn't valid!"); + pRow = (*pRowList)[nIndex]; + pRow->SetPrimaryKey( false ); + } + + // restore deleted keys + for( nIndex = m_aDelKeys.FirstSelected(); nIndex != tools::Long(SFX_ENDOFSELECTION); nIndex=m_aDelKeys.NextSelected() ) + { + OSL_ENSURE(nIndex <= static_cast<tools::Long>(pRowList->size()),"Index for undo isn't valid!"); + pRow = (*pRowList)[nIndex]; + pRow->SetPrimaryKey( true ); + } + + m_pEditorCtrl->InvalidateHandleColumn(); + OTableEditorUndoAct::Undo(); +} + +void OPrimKeyUndoAct::Redo() +{ + std::vector< std::shared_ptr<OTableRow> >* pRowList = pTabEdCtrl->GetRowList(); + tools::Long nIndex; + + // delete the deleted keys + for( nIndex = m_aDelKeys.FirstSelected(); nIndex != tools::Long(SFX_ENDOFSELECTION); nIndex=m_aDelKeys.NextSelected() ) + (*pRowList)[nIndex]->SetPrimaryKey( false ); + + // restore the inserted keys + for( nIndex = m_aInsKeys.FirstSelected(); nIndex != tools::Long(SFX_ENDOFSELECTION); nIndex=m_aInsKeys.NextSelected() ) + (*pRowList)[nIndex]->SetPrimaryKey( true ); + + m_pEditorCtrl->InvalidateHandleColumn(); + OTableEditorUndoAct::Redo(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableUndo.hxx b/dbaccess/source/ui/tabledesign/TableUndo.hxx new file mode 100644 index 000000000..5ad23b84f --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableUndo.hxx @@ -0,0 +1,136 @@ +/* -*- 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 <GeneralUndo.hxx> +#include <tools/multisel.hxx> + +#include <vector> + +#include <com/sun/star/uno/Any.h> +#include <TypeInfo.hxx> +#include <vcl/vclptr.hxx> + +namespace dbaui +{ + class OTableRowView; + class OTableRow; + class OTableDesignUndoAct : public OCommentUndoAction + { + protected: + VclPtr<OTableRowView> m_pTabDgnCtrl; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableDesignUndoAct(OTableRowView* pOwner, TranslateId pCommentID); + virtual ~OTableDesignUndoAct() override; + }; + + class OTableEditorCtrl; + class OTableEditorUndoAct : public OTableDesignUndoAct + { + protected: + VclPtr<OTableEditorCtrl> pTabEdCtrl; + + public: + OTableEditorUndoAct(OTableEditorCtrl* pOwner, TranslateId pCommentID); + virtual ~OTableEditorUndoAct() override; + }; + + class OTableDesignCellUndoAct final : public OTableDesignUndoAct + { + sal_uInt16 m_nCol; + sal_Int32 m_nRow; + css::uno::Any m_sOldText; + css::uno::Any m_sNewText; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableDesignCellUndoAct( OTableRowView* pOwner, sal_Int32 nRowID, sal_uInt16 nColumn ); + virtual ~OTableDesignCellUndoAct() override; + }; + + class OTableEditorTypeSelUndoAct final : public OTableEditorUndoAct + { + sal_uInt16 m_nCol; + sal_Int32 m_nRow; + TOTypeInfoSP m_pOldType; + TOTypeInfoSP m_pNewType; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableEditorTypeSelUndoAct( OTableEditorCtrl* pOwner, sal_Int32 nRowID, sal_uInt16 nColumn, const TOTypeInfoSP& _pOldType ); + virtual ~OTableEditorTypeSelUndoAct() override; + }; + + class OTableEditorDelUndoAct final : public OTableEditorUndoAct + { + std::vector< std::shared_ptr<OTableRow> > m_aDeletedRows; + + virtual void Undo() override; + virtual void Redo() override; + public: + explicit OTableEditorDelUndoAct( OTableEditorCtrl* pOwner ); + virtual ~OTableEditorDelUndoAct() override; + }; + + class OTableEditorInsUndoAct final : public OTableEditorUndoAct + { + std::vector< std::shared_ptr<OTableRow> > m_vInsertedRows; + tools::Long m_nInsPos; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableEditorInsUndoAct( OTableEditorCtrl* pOwner, + tools::Long nInsertPosition, + std::vector< std::shared_ptr<OTableRow> >&& _vInsertedRows); + virtual ~OTableEditorInsUndoAct() override; + }; + + class OTableEditorInsNewUndoAct final : public OTableEditorUndoAct + { + sal_Int32 m_nInsPos; + sal_Int32 m_nInsRows; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableEditorInsNewUndoAct( OTableEditorCtrl* pOwner, sal_Int32 nInsertPosition, sal_Int32 nInsertedRows ); + virtual ~OTableEditorInsNewUndoAct() override; + }; + + class OPrimKeyUndoAct final : public OTableEditorUndoAct + { + MultiSelection m_aDelKeys, + m_aInsKeys; + VclPtr<OTableEditorCtrl> m_pEditorCtrl; + + virtual void Undo() override; + virtual void Redo() override; + public: + OPrimKeyUndoAct( OTableEditorCtrl* pOwner, const MultiSelection& aDeletedKeys, const MultiSelection& aInsertedKeys ); + virtual ~OPrimKeyUndoAct() override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/AdvancedSettingsDlg.cxx b/dbaccess/source/ui/uno/AdvancedSettingsDlg.cxx new file mode 100644 index 000000000..3d24cfc24 --- /dev/null +++ b/dbaccess/source/ui/uno/AdvancedSettingsDlg.cxx @@ -0,0 +1,117 @@ +/* -*- 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 <unoadmin.hxx> +#include <advancedsettingsdlg.hxx> +#include <comphelper/proparrhlp.hxx> +#include <vcl/svapp.hxx> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + + namespace { + + // OAdvancedSettingsDialog + class OAdvancedSettingsDialog + :public ODatabaseAdministrationDialog + ,public ::comphelper::OPropertyArrayUsageHelper< OAdvancedSettingsDialog > + { + + public: + explicit OAdvancedSettingsDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + + // XTypeProvider + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + protected: + // OGenericUnoDialog overridables + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; + }; + + } + + OAdvancedSettingsDialog::OAdvancedSettingsDialog(const Reference< XComponentContext >& _rxORB) + :ODatabaseAdministrationDialog(_rxORB) + { + } + Sequence<sal_Int8> SAL_CALL OAdvancedSettingsDialog::getImplementationId( ) + { + return css::uno::Sequence<sal_Int8>(); + } + + OUString SAL_CALL OAdvancedSettingsDialog::getImplementationName() + { + return "org.openoffice.comp.dbu.OAdvancedSettingsDialog"; + } + + css::uno::Sequence<OUString> SAL_CALL OAdvancedSettingsDialog::getSupportedServiceNames() + { + return { "com.sun.star.sdb.AdvancedDatabaseSettingsDialog" }; + } + + Reference<XPropertySetInfo> SAL_CALL OAdvancedSettingsDialog::getPropertySetInfo() + { + Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + ::cppu::IPropertyArrayHelper& OAdvancedSettingsDialog::getInfoHelper() + { + return *getArrayHelper(); + } + + ::cppu::IPropertyArrayHelper* OAdvancedSettingsDialog::createArrayHelper( ) const + { + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); + } + + std::unique_ptr<weld::DialogController> OAdvancedSettingsDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) + { + return std::make_unique<AdvancedSettingsDialog>(Application::GetFrameWeld(rParent), m_pDatasourceItems.get(), + m_aContext, m_aInitialSelection); + } + +} // namespace dbaui + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_OAdvancedSettingsDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::OAdvancedSettingsDialog(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/ColumnControl.cxx b/dbaccess/source/ui/uno/ColumnControl.cxx new file mode 100644 index 000000000..9295b9954 --- /dev/null +++ b/dbaccess/source/ui/uno/ColumnControl.cxx @@ -0,0 +1,146 @@ +/* -*- 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 "ColumnControl.hxx" +#include "ColumnPeer.hxx" +#include <strings.hxx> +#include <vcl/window.hxx> +#include <com/sun/star/awt/PosSize.hpp> + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_dbu_OColumnControl_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::OColumnControl(context)); +} + +namespace dbaui +{ +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; + +OColumnControl::OColumnControl(const Reference<XComponentContext>& rxContext) + : m_xContext(rxContext) +{ +} + +OUString SAL_CALL OColumnControl::getImplementationName() +{ + return SERVICE_CONTROLDEFAULT; +} +sal_Bool SAL_CALL OColumnControl::supportsService(const OUString& _rServiceName) + { + const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames()); + for (const OUString& s : aSupported) + if (s == _rServiceName) + return true; + + return false; + } +css::uno::Sequence< OUString > SAL_CALL OColumnControl::getSupportedServiceNames() +{ + return { "com.sun.star.awt.UnoControl","com.sun.star.sdb.ColumnDescriptorControl" }; +} + +OUString OColumnControl::GetComponentServiceName() const +{ + return "com.sun.star.sdb.ColumnDescriptorControl"; +} + +void SAL_CALL OColumnControl::createPeer(const Reference< XToolkit >& /*rToolkit*/, const Reference< XWindowPeer >& rParentPeer) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + if ( getPeer().is() ) + return; + + mbCreatingPeer = true; + + vcl::Window* pParentWin = nullptr; + if (rParentPeer.is()) + { + VCLXWindow* pParent = comphelper::getFromUnoTunnel<VCLXWindow>(rParentPeer); + if (pParent) + pParentWin = pParent->GetWindow(); + } + + rtl::Reference<OColumnPeer> pPeer = new OColumnPeer( pParentWin, m_xContext ); + OSL_ENSURE(pPeer != nullptr, "FmXGridControl::createPeer : imp_CreatePeer didn't return a peer !"); + setPeer( pPeer ); + + UnoControlComponentInfos aComponentInfos(maComponentInfos); + Reference< XGraphics > xGraphics( mxGraphics ); + Reference< XView > xV(getPeer(), UNO_QUERY); + Reference< XWindow > xW(getPeer(), UNO_QUERY); + + aGuard.clear(); + + updateFromModel(); + + xV->setZoom( aComponentInfos.nZoomX, aComponentInfos.nZoomY ); + setPosSize( aComponentInfos.nX, aComponentInfos.nY, aComponentInfos.nWidth, aComponentInfos.nHeight, css::awt::PosSize::POSSIZE ); + + Reference<XPropertySet> xProp(getModel(), UNO_QUERY); + if ( xProp.is() ) + { + Reference<XConnection> xCon(xProp->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY); + pPeer->setConnection(xCon); + Reference<XPropertySet> xColumn(xProp->getPropertyValue(PROPERTY_COLUMN),UNO_QUERY); + pPeer->setColumn(xColumn); + sal_Int32 nWidth = 50; + xProp->getPropertyValue(PROPERTY_EDIT_WIDTH) >>= nWidth; + pPeer->setEditWidth(nWidth); + } + + if (aComponentInfos.bVisible) + xW->setVisible(true); + + if (!aComponentInfos.bEnable) + xW->setEnable(false); + + if (maWindowListeners.getLength()) + xW->addWindowListener( &maWindowListeners ); + + if (maFocusListeners.getLength()) + xW->addFocusListener( &maFocusListeners ); + + if (maKeyListeners.getLength()) + xW->addKeyListener( &maKeyListeners ); + + if (maMouseListeners.getLength()) + xW->addMouseListener( &maMouseListeners ); + + if (maMouseMotionListeners.getLength()) + xW->addMouseMotionListener( &maMouseMotionListeners ); + + if (maPaintListeners.getLength()) + xW->addPaintListener( &maPaintListeners ); + + Reference< css::awt::XView > xPeerView(getPeer(), UNO_QUERY); + xPeerView->setZoom( maComponentInfos.nZoomX, maComponentInfos.nZoomY ); + xPeerView->setGraphics( xGraphics ); + + mbCreatingPeer = false; +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/ColumnControl.hxx b/dbaccess/source/ui/uno/ColumnControl.hxx new file mode 100644 index 000000000..63f066512 --- /dev/null +++ b/dbaccess/source/ui/uno/ColumnControl.hxx @@ -0,0 +1,46 @@ +/* -*- 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 <connectivity/CommonTools.hxx> +#include <toolkit/controls/unocontrol.hxx> + +namespace com::sun::star::uno { class XComponentContext; } + +namespace dbaui +{ + class OColumnControl : public UnoControl + { + private: + css::uno::Reference< css::uno::XComponentContext> m_xContext; + public: + explicit OColumnControl(const css::uno::Reference< css::uno::XComponentContext>& rxContext); + + // UnoControl + virtual OUString GetComponentServiceName() const override; + + // XServiceInfo + DECLARE_SERVICE_INFO(); + + // css::awt::XControl + virtual void SAL_CALL createPeer(const css::uno::Reference< css::awt::XToolkit >& _rToolkit, const css::uno::Reference< css::awt::XWindowPeer >& Parent) override; + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/ColumnModel.cxx b/dbaccess/source/ui/uno/ColumnModel.cxx new file mode 100644 index 000000000..de83b6176 --- /dev/null +++ b/dbaccess/source/ui/uno/ColumnModel.cxx @@ -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 . + */ + +#include "ColumnModel.hxx" +#include <com/sun/star/beans/PropertyAttribute.hpp> + +#include <stringconstants.hxx> +#include <strings.hxx> + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_dbu_OColumnControlModel_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::OColumnControlModel()); +} + +namespace dbaui +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; + +OColumnControlModel::OColumnControlModel() + :OPropertyContainer(m_aBHelper) + ,OColumnControlModel_BASE(m_aMutex) + ,m_sDefaultControl(SERVICE_CONTROLDEFAULT) + ,m_bEnable(true) + ,m_nBorder(0) + ,m_nWidth(50) +{ + registerProperties(); +} + +OColumnControlModel::OColumnControlModel(const OColumnControlModel* _pSource) + :OPropertyContainer(m_aBHelper) + ,OColumnControlModel_BASE(m_aMutex) + ,m_sDefaultControl(_pSource->m_sDefaultControl) + ,m_aTabStop(_pSource->m_aTabStop) + ,m_bEnable(_pSource->m_bEnable) + ,m_nBorder(_pSource->m_nBorder) + ,m_nWidth(50) +{ + registerProperties(); +} + +OColumnControlModel::~OColumnControlModel() +{ + if ( !OColumnControlModel_BASE::rBHelper.bDisposed && !OColumnControlModel_BASE::rBHelper.bInDispose ) + { + acquire(); + dispose(); + } +} + +void OColumnControlModel::registerProperties() +{ + registerProperty( PROPERTY_ACTIVE_CONNECTION, PROPERTY_ID_ACTIVE_CONNECTION, PropertyAttribute::TRANSIENT | PropertyAttribute::BOUND, + &m_xConnection, cppu::UnoType<decltype(m_xConnection)>::get() ); + Any a; + a <<= m_xColumn; + registerProperty( PROPERTY_COLUMN, PROPERTY_ID_COLUMN, PropertyAttribute::TRANSIENT | PropertyAttribute::BOUND, + &m_xColumn, cppu::UnoType<decltype(m_xColumn)>::get() ); + + registerMayBeVoidProperty( PROPERTY_TABSTOP, PROPERTY_ID_TABSTOP, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID, + &m_aTabStop, ::cppu::UnoType<sal_Int16>::get() ); + registerProperty( PROPERTY_DEFAULTCONTROL, PROPERTY_ID_DEFAULTCONTROL, PropertyAttribute::BOUND, + &m_sDefaultControl, cppu::UnoType<decltype(m_sDefaultControl)>::get() ); + registerProperty( PROPERTY_ENABLED, PROPERTY_ID_ENABLED, PropertyAttribute::BOUND, + &m_bEnable, cppu::UnoType<decltype(m_bEnable)>::get() ); + registerProperty( PROPERTY_BORDER, PROPERTY_ID_BORDER, PropertyAttribute::BOUND, + &m_nBorder, cppu::UnoType<decltype(m_nBorder)>::get() ); + registerProperty( PROPERTY_EDIT_WIDTH, PROPERTY_ID_EDIT_WIDTH, PropertyAttribute::BOUND, + &m_nWidth, cppu::UnoType<decltype(m_nWidth)>::get() ); +} + +// XCloneable +Reference< XCloneable > SAL_CALL OColumnControlModel::createClone( ) +{ + return new OColumnControlModel( this ); +} + +css::uno::Sequence<sal_Int8> OColumnControlModel::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +css::uno::Sequence< css::uno::Type > OColumnControlModel::getTypes() +{ + return ::comphelper::concatSequences( + OColumnControlModel_BASE::getTypes( ), + OPropertyContainer::getTypes( ) + ); +} +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OColumnControlModel::getPropertySetInfo() +{ + Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} +::cppu::IPropertyArrayHelper& OColumnControlModel::getInfoHelper() +{ + return *OColumnControlModel::getArrayHelper(); +} +::cppu::IPropertyArrayHelper* OColumnControlModel::createArrayHelper( ) const +{ + css::uno::Sequence< css::beans::Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +OUString SAL_CALL OColumnControlModel::getImplementationName() +{ + return "com.sun.star.comp.dbu.OColumnControlModel"; +} +sal_Bool SAL_CALL OColumnControlModel::supportsService(const OUString& _rServiceName) + { + const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames()); + for (const OUString& s : aSupported) + if (s == _rServiceName) + return true; + + return false; + } +css::uno::Sequence< OUString > SAL_CALL OColumnControlModel::getSupportedServiceNames() +{ + return { "com.sun.star.awt.UnoControlModel","com.sun.star.sdb.ColumnDescriptorControlModel" }; +} +IMPLEMENT_FORWARD_REFCOUNT( OColumnControlModel, OColumnControlModel_BASE ) +Any SAL_CALL OColumnControlModel::queryInterface( const Type& _rType ) +{ + return OColumnControlModel_BASE::queryInterface( _rType ); +} + +// css::XAggregation +Any SAL_CALL OColumnControlModel::queryAggregation( const Type& rType ) +{ + Any aRet(OColumnControlModel_BASE::queryAggregation(rType)); + if (!aRet.hasValue()) + aRet = comphelper::OPropertyContainer::queryInterface(rType); + return aRet; +} + +OUString SAL_CALL OColumnControlModel::getServiceName() +{ + return OUString(); +} + +void OColumnControlModel::write(const Reference<XObjectOutputStream>& /*_rxOutStream*/) +{ + // TODO +} + +void OColumnControlModel::read(const Reference<XObjectInputStream>& /*_rxInStream*/) +{ + // TODO +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/ColumnModel.hxx b/dbaccess/source/ui/uno/ColumnModel.hxx new file mode 100644 index 000000000..400d03652 --- /dev/null +++ b/dbaccess/source/ui/uno/ColumnModel.hxx @@ -0,0 +1,97 @@ +/* -*- 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/awt/XControlModel.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/util/XCloneable.hpp> +#include <com/sun/star/io/XPersistObject.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <comphelper/proparrhlp.hxx> +#include <comphelper/propertycontainer.hxx> +#include <comphelper/broadcasthelper.hxx> +#include <comphelper/uno3.hxx> +#include <cppuhelper/compbase4.hxx> +#include <connectivity/CommonTools.hxx> + +namespace dbaui +{ + +// OColumnControlModel +typedef ::cppu::WeakAggComponentImplHelper4 < css::awt::XControlModel + , css::lang::XServiceInfo + , css::util::XCloneable + , css::io::XPersistObject + > OColumnControlModel_BASE; + +class OColumnControlModel; + +class OColumnControlModel : public ::comphelper::OMutexAndBroadcastHelper + ,public ::comphelper::OPropertyContainer + ,public ::comphelper::OPropertyArrayUsageHelper< OColumnControlModel > + ,public OColumnControlModel_BASE +{ + +// [properties] + css::uno::Reference< css::sdbc::XConnection> m_xConnection; + css::uno::Reference< css::beans::XPropertySet > m_xColumn; + OUString m_sDefaultControl; + css::uno::Any m_aTabStop; + bool m_bEnable; + sal_Int16 m_nBorder; + sal_Int32 m_nWidth; +// [properties] + + void registerProperties(); +protected: + + virtual ~OColumnControlModel() override; + OColumnControlModel(const OColumnControlModel* _pSource); +public: + explicit OColumnControlModel(); + +// UNO binding + DECLARE_XINTERFACE( ) + +// css::lang::XServiceInfo + DECLARE_SERVICE_INFO(); + + virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override; + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override; + +// css::uno::XAggregation + virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& aType ) override; + +// css::io::XPersistObject + virtual OUString SAL_CALL getServiceName() override; + virtual void SAL_CALL write(const css::uno::Reference< css::io::XObjectOutputStream>& _rxOutStream) override; + virtual void SAL_CALL read(const css::uno::Reference< css::io::XObjectInputStream>& _rxInStream) override; + +// OPropertyArrayUsageHelper + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + + + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) override; +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/ColumnPeer.cxx b/dbaccess/source/ui/uno/ColumnPeer.cxx new file mode 100644 index 000000000..48f5fbce5 --- /dev/null +++ b/dbaccess/source/ui/uno/ColumnPeer.cxx @@ -0,0 +1,148 @@ +/* -*- 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 "ColumnPeer.hxx" +#include <ColumnControlWindow.hxx> +#include <vcl/svapp.hxx> +#include <strings.hxx> +#include <FieldDescriptions.hxx> + +namespace dbaui +{ +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; + +OColumnPeer::OColumnPeer(vcl::Window* _pParent,const Reference<XComponentContext>& _rxContext) + :m_pActFieldDescr(nullptr) +{ + osl_atomic_increment( &m_refCount ); + { + VclPtrInstance<OColumnControlTopLevel> pFieldControl(_pParent, _rxContext); + pFieldControl->SetComponentInterface(this); + pFieldControl->Show(); + } + osl_atomic_decrement( &m_refCount ); +} + +void OColumnPeer::setEditWidth(sal_Int32 _nWidth) +{ + SolarMutexGuard aGuard; + VclPtr<OColumnControlTopLevel> pFieldControl = GetAs<OColumnControlTopLevel>(); + if ( pFieldControl ) + pFieldControl->GetControl().setEditWidth(_nWidth); +} + +void OColumnPeer::setColumn(const Reference< XPropertySet>& _xColumn) +{ + SolarMutexGuard aGuard; + + VclPtr<OColumnControlTopLevel> pFieldControl = GetAs<OColumnControlTopLevel>(); + if ( !pFieldControl ) + return; + + OColumnControlWindow& rControl = pFieldControl->GetControl(); + + if ( m_pActFieldDescr ) + { + delete m_pActFieldDescr; + m_pActFieldDescr = nullptr; + } + if ( _xColumn.is() ) + { + sal_Int32 nType = 0; + sal_Int32 nScale = 0; + sal_Int32 nPrecision = 0; + bool bAutoIncrement = false; + OUString sTypeName; + + try + { + // get the properties from the column + _xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; + _xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType; + _xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale; + _xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision; + _xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bAutoIncrement; + } + catch(const Exception&) + { + } + + m_pActFieldDescr = new OFieldDescription(_xColumn,true); + // search for type + bool bForce; + TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(*rControl.getTypeInfo(),nType,sTypeName,"x",nPrecision,nScale,bAutoIncrement,bForce); + if ( !pTypeInfo ) + pTypeInfo = rControl.getDefaultTyp(); + + m_pActFieldDescr->FillFromTypeInfo(pTypeInfo,true,false); + m_xColumn = _xColumn; + } + rControl.DisplayData(m_pActFieldDescr); +} + +void OColumnPeer::setConnection(const Reference< XConnection>& _xCon) +{ + SolarMutexGuard aGuard; + VclPtr<OColumnControlTopLevel> pFieldControl = GetAs<OColumnControlTopLevel>(); + if ( pFieldControl ) + pFieldControl->GetControl().setConnection(_xCon); +} + +void OColumnPeer::setProperty( const OUString& _rPropertyName, const Any& Value) +{ + SolarMutexGuard aGuard; + + if (_rPropertyName == PROPERTY_COLUMN) + { + Reference<XPropertySet> xProp(Value,UNO_QUERY); + setColumn(xProp); + } + else if (_rPropertyName == PROPERTY_ACTIVE_CONNECTION) + { + Reference<XConnection> xCon(Value,UNO_QUERY); + setConnection(xCon); + } + else + VCLXWindow::setProperty(_rPropertyName,Value); +} + +Any OColumnPeer::getProperty( const OUString& _rPropertyName ) +{ + Any aProp; + VclPtr<OColumnControlTopLevel> pFieldControl = GetAs<OColumnControlTopLevel>(); + if (pFieldControl && _rPropertyName == PROPERTY_COLUMN) + { + aProp <<= m_xColumn; + } + else if (pFieldControl && _rPropertyName == PROPERTY_ACTIVE_CONNECTION) + { + aProp <<= pFieldControl->GetControl().getConnection(); + } + else + aProp = VCLXWindow::getProperty(_rPropertyName); + return aProp; +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/ColumnPeer.hxx b/dbaccess/source/ui/uno/ColumnPeer.hxx new file mode 100644 index 000000000..8a92a40cd --- /dev/null +++ b/dbaccess/source/ui/uno/ColumnPeer.hxx @@ -0,0 +1,47 @@ +/* -*- 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 <toolkit/awt/vclxwindow.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +namespace dbaui +{ + class OFieldDescription; + class OColumnPeer : public VCLXWindow + { + OFieldDescription* m_pActFieldDescr; + css::uno::Reference< css::beans::XPropertySet> m_xColumn; + public: + + OColumnPeer(vcl::Window* _pParent + ,const css::uno::Reference< css::uno::XComponentContext>& _rxContext); + + void setColumn(const css::uno::Reference< css::beans::XPropertySet>& _xColumn); + void setConnection(const css::uno::Reference< css::sdbc::XConnection>& _xCon); + void setEditWidth(sal_Int32 _nWidth); + // VCLXWindow + virtual void SAL_CALL setProperty( const OUString& PropertyName, const css::uno::Any& Value ) override; + virtual css::uno::Any SAL_CALL getProperty( const OUString& PropertyName ) override; + }; +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/DBTypeWizDlg.cxx b/dbaccess/source/ui/uno/DBTypeWizDlg.cxx new file mode 100644 index 000000000..8c9d16596 --- /dev/null +++ b/dbaccess/source/ui/uno/DBTypeWizDlg.cxx @@ -0,0 +1,85 @@ +/* -*- 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 "DBTypeWizDlg.hxx" +#include <dbwiz.hxx> +#include <vcl/svapp.hxx> + +using namespace dbaui; + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_ODBTypeWizDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ODBTypeWizDialog(context)); +} + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + +ODBTypeWizDialog::ODBTypeWizDialog(const Reference< XComponentContext >& _rxORB) + :ODatabaseAdministrationDialog(_rxORB) +{ +} + +Sequence<sal_Int8> SAL_CALL ODBTypeWizDialog::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +OUString SAL_CALL ODBTypeWizDialog::getImplementationName() +{ + return "org.openoffice.comp.dbu.ODBTypeWizDialog"; +} + +css::uno::Sequence<OUString> SAL_CALL ODBTypeWizDialog::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.DataSourceTypeChangeDialog" }; +} + +Reference<XPropertySetInfo> SAL_CALL ODBTypeWizDialog::getPropertySetInfo() +{ + Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +::cppu::IPropertyArrayHelper& ODBTypeWizDialog::getInfoHelper() +{ + return *getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* ODBTypeWizDialog::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +std::unique_ptr<weld::DialogController> ODBTypeWizDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) +{ + return std::make_unique<ODbTypeWizDialog>(Application::GetFrameWeld(rParent), m_pDatasourceItems.get(), m_aContext, m_aInitialSelection); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/DBTypeWizDlg.hxx b/dbaccess/source/ui/uno/DBTypeWizDlg.hxx new file mode 100644 index 000000000..093981a0e --- /dev/null +++ b/dbaccess/source/ui/uno/DBTypeWizDlg.hxx @@ -0,0 +1,56 @@ +/* -*- 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 <unoadmin.hxx> + +#include <comphelper/proparrhlp.hxx> + +namespace dbaui +{ +class ODBTypeWizDialog final + :public ODatabaseAdministrationDialog + ,public ::comphelper::OPropertyArrayUsageHelper< ODBTypeWizDialog > +{ +public: + + explicit ODBTypeWizDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + + // XTypeProvider + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; +private: + // OGenericUnoDialog overridables + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx b/dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx new file mode 100644 index 000000000..63c3d6304 --- /dev/null +++ b/dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx @@ -0,0 +1,104 @@ +/* -*- 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 "DBTypeWizDlgSetup.hxx" +#include <dbwizsetup.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> +#include <vcl/svapp.hxx> + +using namespace dbaui; + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_ODBTypeWizDialogSetup_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ODBTypeWizDialogSetup(context)); +} + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::sdbc; + +ODBTypeWizDialogSetup::ODBTypeWizDialogSetup(const Reference< XComponentContext >& _rxORB) + :ODatabaseAdministrationDialog(_rxORB) + ,m_bOpenDatabase(true) + ,m_bStartTableWizard(false) +{ + registerProperty("OpenDatabase", 3, PropertyAttribute::TRANSIENT, + &m_bOpenDatabase, cppu::UnoType<bool>::get()); + + registerProperty("StartTableWizard", 4, PropertyAttribute::TRANSIENT, + &m_bStartTableWizard, cppu::UnoType<bool>::get()); +} + +Sequence<sal_Int8> SAL_CALL ODBTypeWizDialogSetup::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +OUString SAL_CALL ODBTypeWizDialogSetup::getImplementationName() +{ + return "org.openoffice.comp.dbu.ODBTypeWizDialogSetup"; +} + +css::uno::Sequence<OUString> SAL_CALL ODBTypeWizDialogSetup::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.DatabaseWizardDialog" }; +} + +Reference<XPropertySetInfo> SAL_CALL ODBTypeWizDialogSetup::getPropertySetInfo() +{ + return createPropertySetInfo( getInfoHelper() ); +} + +::cppu::IPropertyArrayHelper& ODBTypeWizDialogSetup::getInfoHelper() +{ + return *getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* ODBTypeWizDialogSetup::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +std::unique_ptr<weld::DialogController> ODBTypeWizDialogSetup::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) +{ + return std::make_unique<ODbTypeWizDialogSetup>(Application::GetFrameWeld(rParent), m_pDatasourceItems.get(), m_aContext, m_aInitialSelection); +} + +void ODBTypeWizDialogSetup::executedDialog(sal_Int16 nExecutionResult) +{ + if (nExecutionResult == css::ui::dialogs::ExecutableDialogResults::OK) + { + const ODbTypeWizDialogSetup* pDialog = static_cast<ODbTypeWizDialogSetup*>(m_xDialog.get()); + m_bOpenDatabase = pDialog->IsDatabaseDocumentToBeOpened(); + m_bStartTableWizard = pDialog->IsTableWizardToBeStarted(); + } +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/DBTypeWizDlgSetup.hxx b/dbaccess/source/ui/uno/DBTypeWizDlgSetup.hxx new file mode 100644 index 000000000..56bd9a08a --- /dev/null +++ b/dbaccess/source/ui/uno/DBTypeWizDlgSetup.hxx @@ -0,0 +1,59 @@ +/* -*- 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 <unoadmin.hxx> + +#include <comphelper/proparrhlp.hxx> + +namespace dbaui +{ +class ODBTypeWizDialogSetup final + :public ODatabaseAdministrationDialog + ,public ::comphelper::OPropertyArrayUsageHelper< ODBTypeWizDialogSetup > +{ + bool m_bOpenDatabase; + bool m_bStartTableWizard; + +public: + explicit ODBTypeWizDialogSetup(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + + // XTypeProvider + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; +private: + // OGenericUnoDialog overridables + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; + virtual void executedDialog(sal_Int16 _nExecutionResult) override; +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/TableFilterDlg.cxx b/dbaccess/source/ui/uno/TableFilterDlg.cxx new file mode 100644 index 000000000..cd01f2587 --- /dev/null +++ b/dbaccess/source/ui/uno/TableFilterDlg.cxx @@ -0,0 +1,85 @@ +/* -*- 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 "TableFilterDlg.hxx" +#include <TablesSingleDlg.hxx> +#include <vcl/svapp.hxx> + +using namespace dbaui; + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_OTableFilterDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new OTableFilterDialog(context)); +} + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + +OTableFilterDialog::OTableFilterDialog(const Reference< XComponentContext >& _rxORB) + :ODatabaseAdministrationDialog(_rxORB) +{ +} + +Sequence<sal_Int8> SAL_CALL OTableFilterDialog::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +OUString SAL_CALL OTableFilterDialog::getImplementationName() +{ + return "org.openoffice.comp.dbu.OTableFilterDialog"; +} + +css::uno::Sequence<OUString> SAL_CALL OTableFilterDialog::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.TableFilterDialog" }; +} + +Reference<XPropertySetInfo> SAL_CALL OTableFilterDialog::getPropertySetInfo() +{ + Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +::cppu::IPropertyArrayHelper& OTableFilterDialog::getInfoHelper() +{ + return *getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* OTableFilterDialog::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +std::unique_ptr<weld::DialogController> OTableFilterDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) +{ + return std::make_unique<OTableSubscriptionDialog>(Application::GetFrameWeld(rParent), m_pDatasourceItems.get(), m_aContext, m_aInitialSelection); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/TableFilterDlg.hxx b/dbaccess/source/ui/uno/TableFilterDlg.hxx new file mode 100644 index 000000000..7c16a7f26 --- /dev/null +++ b/dbaccess/source/ui/uno/TableFilterDlg.hxx @@ -0,0 +1,57 @@ +/* -*- 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 <unoadmin.hxx> + +#include <comphelper/proparrhlp.hxx> + +namespace dbaui +{ + +class OTableFilterDialog final + :public ODatabaseAdministrationDialog + ,public ::comphelper::OPropertyArrayUsageHelper< OTableFilterDialog > +{ + +public: + explicit OTableFilterDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + + // XTypeProvider + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; +private: + // OGenericUnoDialog overridables + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/UserSettingsDlg.cxx b/dbaccess/source/ui/uno/UserSettingsDlg.cxx new file mode 100644 index 000000000..7039c7396 --- /dev/null +++ b/dbaccess/source/ui/uno/UserSettingsDlg.cxx @@ -0,0 +1,85 @@ +/* -*- 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 "UserSettingsDlg.hxx" +#include <UserAdminDlg.hxx> +#include <vcl/svapp.hxx> + +using namespace dbaui; + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_OUserSettingsDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new OUserSettingsDialog(context)); +} + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + +OUserSettingsDialog::OUserSettingsDialog(const Reference< XComponentContext >& _rxORB) + :ODatabaseAdministrationDialog(_rxORB) +{ +} + +Sequence<sal_Int8> SAL_CALL OUserSettingsDialog::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +OUString SAL_CALL OUserSettingsDialog::getImplementationName() +{ + return "org.openoffice.comp.dbu.OUserSettingsDialog"; +} + +css::uno::Sequence<OUString> SAL_CALL OUserSettingsDialog::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.UserAdministrationDialog" }; +} + +Reference<XPropertySetInfo> SAL_CALL OUserSettingsDialog::getPropertySetInfo() +{ + Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +::cppu::IPropertyArrayHelper& OUserSettingsDialog::getInfoHelper() +{ + return *getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* OUserSettingsDialog::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +std::unique_ptr<weld::DialogController> OUserSettingsDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) +{ + return std::make_unique<OUserAdminDlg>(Application::GetFrameWeld(rParent), m_pDatasourceItems.get(), m_aContext, m_aInitialSelection, m_xActiveConnection); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/UserSettingsDlg.hxx b/dbaccess/source/ui/uno/UserSettingsDlg.hxx new file mode 100644 index 000000000..7e0780ea2 --- /dev/null +++ b/dbaccess/source/ui/uno/UserSettingsDlg.hxx @@ -0,0 +1,57 @@ +/* -*- 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 <unoadmin.hxx> + +#include <comphelper/proparrhlp.hxx> + +namespace dbaui +{ +// OUserSettingsDialog +class OUserSettingsDialog final + :public ODatabaseAdministrationDialog + ,public ::comphelper::OPropertyArrayUsageHelper< OUserSettingsDialog > +{ + +public: + explicit OUserSettingsDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + + // XTypeProvider + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; +private: + // OGenericUnoDialog overridables + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/admindlg.cxx b/dbaccess/source/ui/uno/admindlg.cxx new file mode 100644 index 000000000..3e524372e --- /dev/null +++ b/dbaccess/source/ui/uno/admindlg.cxx @@ -0,0 +1,92 @@ +/* -*- 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 "admindlg.hxx" +#include <dbadmin.hxx> +#include <vcl/svapp.hxx> + +using namespace dbaui; + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_ODatasourceAdministrationDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new ODataSourcePropertyDialog(context)); +} + +namespace dbaui +{ +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +ODataSourcePropertyDialog::ODataSourcePropertyDialog(const Reference<XComponentContext>& _rxORB) + : ODatabaseAdministrationDialog(_rxORB) +{ +} + +Sequence<sal_Int8> SAL_CALL ODataSourcePropertyDialog::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +OUString SAL_CALL ODataSourcePropertyDialog::getImplementationName() +{ + return "org.openoffice.comp.dbu.ODatasourceAdministrationDialog"; +} + +css::uno::Sequence<OUString> SAL_CALL ODataSourcePropertyDialog::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.DatasourceAdministrationDialog" }; +} + +Reference<XPropertySetInfo> SAL_CALL ODataSourcePropertyDialog::getPropertySetInfo() +{ + Reference<XPropertySetInfo> xInfo(createPropertySetInfo(getInfoHelper())); + return xInfo; +} + +::cppu::IPropertyArrayHelper& ODataSourcePropertyDialog::getInfoHelper() +{ + return *getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* ODataSourcePropertyDialog::createArrayHelper() const +{ + Sequence<Property> aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +std::unique_ptr<weld::DialogController> +ODataSourcePropertyDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) +{ + std::unique_ptr<ODbAdminDialog> xDialog(new ODbAdminDialog( + Application::GetFrameWeld(rParent), m_pDatasourceItems.get(), m_aContext)); + + // the initial selection + if (m_aInitialSelection.hasValue()) + xDialog->selectDataSource(m_aInitialSelection); + + return xDialog; +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/admindlg.hxx b/dbaccess/source/ui/uno/admindlg.hxx new file mode 100644 index 000000000..62faabf64 --- /dev/null +++ b/dbaccess/source/ui/uno/admindlg.hxx @@ -0,0 +1,56 @@ +/* -*- 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 <unoadmin.hxx> + +#include <comphelper/proparrhlp.hxx> + +namespace dbaui +{ +class ODataSourcePropertyDialog final + :public ODatabaseAdministrationDialog + ,public ::comphelper::OPropertyArrayUsageHelper< ODataSourcePropertyDialog > +{ +public: + + explicit ODataSourcePropertyDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + + // XTypeProvider + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; +private: + // OGenericUnoDialog overridables + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; +}; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/composerdialogs.cxx b/dbaccess/source/ui/uno/composerdialogs.cxx new file mode 100644 index 000000000..f4b8fe24a --- /dev/null +++ b/dbaccess/source/ui/uno/composerdialogs.cxx @@ -0,0 +1,270 @@ +/* -*- 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 "composerdialogs.hxx" + +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <queryfilter.hxx> +#include <queryorder.hxx> +#include <strings.hxx> +#include <connectivity/dbtools.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <vcl/svapp.hxx> + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_uno_comp_sdb_RowsetOrderDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::RowsetOrderDialog(context)); +} +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_uno_comp_sdb_RowsetFilterDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::RowsetFilterDialog(context)); +} + +namespace dbaui +{ + +#define PROPERTY_ID_QUERYCOMPOSER 100 +#define PROPERTY_ID_ROWSET 101 + +constexpr OUStringLiteral PROPERTY_QUERYCOMPOSER = u"QueryComposer"; +constexpr OUStringLiteral PROPERTY_ROWSET = u"RowSet"; + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::sdbcx; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::sdb; + + // ComposerDialog + ComposerDialog::ComposerDialog(const Reference< XComponentContext >& _rxORB) + :OGenericUnoDialog( _rxORB ) + { + + registerProperty( PROPERTY_QUERYCOMPOSER, PROPERTY_ID_QUERYCOMPOSER, PropertyAttribute::TRANSIENT, + &m_xComposer, cppu::UnoType<decltype(m_xComposer)>::get() ); + registerProperty( PROPERTY_ROWSET, PROPERTY_ID_ROWSET, PropertyAttribute::TRANSIENT, + &m_xRowSet, cppu::UnoType<decltype(m_xRowSet)>::get() ); + } + + ComposerDialog::~ComposerDialog() + { + + } + + css::uno::Sequence<sal_Int8> ComposerDialog::getImplementationId() + { + return css::uno::Sequence<sal_Int8>(); + } + + css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL ComposerDialog::getPropertySetInfo() + { + Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + ::cppu::IPropertyArrayHelper& ComposerDialog::getInfoHelper() + { + return *ComposerDialog::getArrayHelper(); + } + ::cppu::IPropertyArrayHelper* ComposerDialog::createArrayHelper( ) const + { + css::uno::Sequence< css::beans::Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); + } + + std::unique_ptr<weld::DialogController> ComposerDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) + { + // obtain all the objects needed for the dialog + Reference< XConnection > xConnection; + Reference< XNameAccess > xColumns; + try + { + // the connection the row set is working with + if ( !::dbtools::isEmbeddedInDatabase( m_xRowSet, xConnection ) ) + { + Reference< XPropertySet > xRowsetProps( m_xRowSet, UNO_QUERY ); + if ( xRowsetProps.is() ) + xRowsetProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection; + } + + // fallback: if there is a connection and thus a row set, but no composer, create one + if ( xConnection.is() && !m_xComposer.is() ) + m_xComposer = ::dbtools::getCurrentSettingsComposer( Reference< XPropertySet >( m_xRowSet, UNO_QUERY ), m_aContext, rParent ); + + // the columns of the row set + Reference< XColumnsSupplier > xSuppColumns( m_xRowSet, UNO_QUERY ); + if ( xSuppColumns.is() ) + xColumns = xSuppColumns->getColumns(); + + if ( !xColumns.is() || !xColumns->hasElements() ) + { // perhaps the composer can supply us with columns? This is necessary for cases + // where the dialog is invoked for a rowset which is not yet loaded + // #i22878# + xSuppColumns.set(m_xComposer, css::uno::UNO_QUERY); + if ( xSuppColumns.is() ) + xColumns = xSuppColumns->getColumns(); + } + + OSL_ENSURE( xColumns.is() && xColumns->hasElements(), "ComposerDialog::createDialog: not much fun without any columns!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if ( !xConnection.is() || !xColumns.is() || !m_xComposer.is() ) + { + // can't create the dialog if I have improper settings + return nullptr; + } + + return createComposerDialog(Application::GetFrameWeld(rParent), xConnection, xColumns); + } + + // RowsetFilterDialog + RowsetFilterDialog::RowsetFilterDialog( const Reference< XComponentContext >& _rxORB ) + :ComposerDialog( _rxORB ) + { + } + + OUString SAL_CALL RowsetFilterDialog::getImplementationName() + { + return "com.sun.star.uno.comp.sdb.RowsetFilterDialog"; + } + sal_Bool SAL_CALL RowsetFilterDialog::supportsService(const OUString& _rServiceName) + { + const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames()); + for (const OUString& s : aSupported) + if (s == _rServiceName) + return true; + + return false; + } + css::uno::Sequence< OUString > SAL_CALL RowsetFilterDialog::getSupportedServiceNames() + { + return { "com.sun.star.sdb.FilterDialog" }; + } + + std::unique_ptr<weld::GenericDialogController> RowsetFilterDialog::createComposerDialog(weld::Window* _pParent, const Reference< XConnection >& _rxConnection, const Reference< XNameAccess >& _rxColumns ) + { + return std::make_unique<DlgFilterCrit>(_pParent, m_aContext, _rxConnection, m_xComposer, _rxColumns); + } + + void SAL_CALL RowsetFilterDialog::initialize( const Sequence< Any >& aArguments ) + { + if( aArguments.getLength() == 3 ) + { + // this is the FilterDialog::createWithQuery method + Reference<css::sdb::XSingleSelectQueryComposer> xQueryComposer; + aArguments[0] >>= xQueryComposer; + Reference<css::sdbc::XRowSet> xRowSet; + aArguments[1] >>= xRowSet; + Reference<css::awt::XWindow> xParentWindow; + aArguments[2] >>= xParentWindow; + setPropertyValue( "QueryComposer", Any( xQueryComposer ) ); + setPropertyValue( "RowSet", Any( xRowSet ) ); + setPropertyValue( "ParentWindow", Any( xParentWindow ) ); + } + else + ComposerDialog::initialize(aArguments); + } + + void RowsetFilterDialog::executedDialog( sal_Int16 _nExecutionResult ) + { + ComposerDialog::executedDialog( _nExecutionResult ); + + if ( _nExecutionResult && m_xDialog ) + static_cast<DlgFilterCrit*>(m_xDialog.get())->BuildWherePart(); + } + + // RowsetOrderDialog + RowsetOrderDialog::RowsetOrderDialog( const Reference< XComponentContext >& _rxORB ) + :ComposerDialog( _rxORB ) + { + } + + OUString SAL_CALL RowsetOrderDialog::getImplementationName() + { + return "com.sun.star.uno.comp.sdb.RowsetOrderDialog"; + } + sal_Bool SAL_CALL RowsetOrderDialog::supportsService(const OUString& _rServiceName) + { + const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames()); + for (const OUString& s : aSupported) + if (s == _rServiceName) + return true; + + return false; + } + css::uno::Sequence< OUString > SAL_CALL RowsetOrderDialog::getSupportedServiceNames() + { + return { "com.sun.star.sdb.OrderDialog" }; + } + + std::unique_ptr<weld::GenericDialogController> RowsetOrderDialog::createComposerDialog(weld::Window* pParent, const Reference< XConnection >& rxConnection, const Reference< XNameAccess >& rxColumns) + { + return std::make_unique<DlgOrderCrit>(pParent, rxConnection, m_xComposer, rxColumns); + } + + void SAL_CALL RowsetOrderDialog::initialize( const Sequence< Any >& aArguments ) + { + if (aArguments.getLength() == 2 || aArguments.getLength() == 3) + { + Reference<css::sdb::XSingleSelectQueryComposer> xQueryComposer; + aArguments[0] >>= xQueryComposer; + Reference<css::beans::XPropertySet> xRowSet; + aArguments[1] >>= xRowSet; + setPropertyValue( "QueryComposer", Any( xQueryComposer ) ); + setPropertyValue( "RowSet", Any( xRowSet ) ); + if (aArguments.getLength() == 3) + { + Reference<css::awt::XWindow> xParentWindow; + aArguments[2] >>= xParentWindow; + setPropertyValue("ParentWindow", Any(xParentWindow)); + } + } + else + ComposerDialog::initialize(aArguments); + } + + void RowsetOrderDialog::executedDialog( sal_Int16 _nExecutionResult ) + { + ComposerDialog::executedDialog( _nExecutionResult ); + + if ( !m_xDialog ) + return; + + if ( _nExecutionResult ) + static_cast<DlgOrderCrit*>(m_xDialog.get())->BuildOrderPart(); + else if ( m_xComposer.is() ) + m_xComposer->setOrder(static_cast<DlgOrderCrit*>(m_xDialog.get())->GetOriginalOrder()); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/composerdialogs.hxx b/dbaccess/source/ui/uno/composerdialogs.hxx new file mode 100644 index 000000000..4e71b1c64 --- /dev/null +++ b/dbaccess/source/ui/uno/composerdialogs.hxx @@ -0,0 +1,123 @@ +/* -*- 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> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> +#include <com/sun/star/sdbc/XRowSet.hpp> + +#include <comphelper/proparrhlp.hxx> +#include <connectivity/CommonTools.hxx> +#include <svtools/genericunodialog.hxx> + +namespace dbaui +{ + + // ComposerDialog + class ComposerDialog; + typedef ::comphelper::OPropertyArrayUsageHelper< ComposerDialog > ComposerDialog_PBASE; + + class ComposerDialog + :public svt::OGenericUnoDialog + ,public ComposerDialog_PBASE + { + protected: + // <properties> + css::uno::Reference< css::sdb::XSingleSelectQueryComposer > + m_xComposer; + css::uno::Reference< css::sdbc::XRowSet > + m_xRowSet; + // </properties> + + protected: + explicit ComposerDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + virtual ~ComposerDialog() override; + + public: + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override; + + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + + protected: + // own overridables + virtual std::unique_ptr<weld::GenericDialogController> createComposerDialog( + weld::Window* _pParent, + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + const css::uno::Reference< css::container::XNameAccess >& _rxColumns + ) = 0; + + private: + // OGenericUnoDialog overridables + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; + }; + + // RowsetFilterDialog + class RowsetFilterDialog : public ComposerDialog + { + public: + explicit RowsetFilterDialog( + const css::uno::Reference< css::uno::XComponentContext >& _rxORB + ); + + DECLARE_SERVICE_INFO(); + + protected: + // own overridables + virtual std::unique_ptr<weld::GenericDialogController> createComposerDialog( + weld::Window* _pParent, + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + const css::uno::Reference< css::container::XNameAccess >& _rxColumns + ) override; + + // OGenericUnoDialog overridables + virtual void executedDialog( sal_Int16 _nExecutionResult ) override; + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + }; + + // RowsetOrderDialog + class RowsetOrderDialog : public ComposerDialog + { + public: + explicit RowsetOrderDialog( + const css::uno::Reference< css::uno::XComponentContext >& _rxORB + ); + + DECLARE_SERVICE_INFO(); + + protected: + // own overridables + virtual std::unique_ptr<weld::GenericDialogController> createComposerDialog( + weld::Window* _pParent, + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + const css::uno::Reference< css::container::XNameAccess >& _rxColumns + ) override; + + // OGenericUnoDialog overridables + virtual void executedDialog( sal_Int16 _nExecutionResult ) override; + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/copytablewizard.cxx b/dbaccess/source/ui/uno/copytablewizard.cxx new file mode 100644 index 000000000..09ec99415 --- /dev/null +++ b/dbaccess/source/ui/uno/copytablewizard.cxx @@ -0,0 +1,1579 @@ +/* -*- 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 <memory> +#include <strings.hrc> +#include <strings.hxx> +#include <core_resource.hxx> +#include <WCopyTable.hxx> + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sdb/application/XCopyTableWizard.hpp> +#include <com/sun/star/sdb/application/CopyTableContinuation.hpp> +#include <com/sun/star/sdb/application/CopyTableOperation.hpp> +#include <com/sun/star/ucb/AlreadyInitializedException.hpp> +#include <com/sun/star/lang/NotInitializedException.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <com/sun/star/sdb/XDocumentDataSource.hpp> +#include <com/sun/star/sdb/XCompletedConnection.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdbc/DriverManager.hpp> +#include <com/sun/star/sdbc/ConnectionPool.hpp> + +#include <comphelper/processfactory.hxx> +#include <comphelper/interaction.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/proparrhlp.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/implbase.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <o3tl/safeint.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <svtools/genericunodialog.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/diagnose_ex.h> +#include <unotools/sharedunocomponent.hxx> +#include <vcl/svapp.hxx> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::beans::XPropertySetInfo; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::beans::Property; + using ::com::sun::star::sdb::application::XCopyTableWizard; + using ::com::sun::star::sdb::application::XCopyTableListener; + using ::com::sun::star::sdb::application::CopyTableRowEvent; + using ::com::sun::star::beans::Optional; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::ucb::AlreadyInitializedException; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::lang::NotInitializedException; + using ::com::sun::star::lang::XServiceInfo; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::sdbc::XDataSource; + using ::com::sun::star::container::XNameAccess; + using ::com::sun::star::container::XChild; + using ::com::sun::star::task::InteractionHandler; + using ::com::sun::star::task::XInteractionHandler; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::sdb::DatabaseContext; + using ::com::sun::star::sdb::XDatabaseContext; + using ::com::sun::star::sdb::XDocumentDataSource; + using ::com::sun::star::sdb::XCompletedConnection; + using ::com::sun::star::lang::WrappedTargetException; + using ::com::sun::star::sdbcx::XTablesSupplier; + using ::com::sun::star::sdb::XQueriesSupplier; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::sdbc::XPreparedStatement; + using ::com::sun::star::sdb::XSingleSelectQueryComposer; + using ::com::sun::star::sdbc::XDatabaseMetaData; + using ::com::sun::star::sdbcx::XColumnsSupplier; + using ::com::sun::star::sdbc::XParameters; + using ::com::sun::star::sdbc::XResultSet; + using ::com::sun::star::sdbc::XRow; + using ::com::sun::star::sdbcx::XRowLocate; + using ::com::sun::star::sdbc::XResultSetMetaDataSupplier; + using ::com::sun::star::sdbc::XResultSetMetaData; + using ::com::sun::star::sdbc::SQLException; + using ::com::sun::star::sdb::SQLContext; + using ::com::sun::star::sdbc::ConnectionPool; + using ::com::sun::star::sdbc::XDriverManager; + using ::com::sun::star::sdbc::DriverManager; + using ::com::sun::star::beans::PropertyValue; + + namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation; + namespace CopyTableContinuation = ::com::sun::star::sdb::application::CopyTableContinuation; + namespace CommandType = ::com::sun::star::sdb::CommandType; + namespace DataType = ::com::sun::star::sdbc::DataType; + + typedef ::utl::SharedUNOComponent< XConnection > SharedConnection; + + // CopyTableWizard + typedef ::svt::OGenericUnoDialog CopyTableWizard_DialogBase; + typedef ::cppu::ImplInheritanceHelper< CopyTableWizard_DialogBase + , XCopyTableWizard + > CopyTableWizard_Base; + + namespace { + + class CopyTableWizard + :public CopyTableWizard_Base + ,public ::comphelper::OPropertyArrayUsageHelper< CopyTableWizard > + { + public: + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XCopyTableWizard + virtual ::sal_Int16 SAL_CALL getOperation() override; + virtual void SAL_CALL setOperation( ::sal_Int16 _operation ) override; + virtual OUString SAL_CALL getDestinationTableName() override; + virtual void SAL_CALL setDestinationTableName( const OUString& _destinationTableName ) override; + virtual Optional< OUString > SAL_CALL getCreatePrimaryKey() override; + virtual void SAL_CALL setCreatePrimaryKey( const Optional< OUString >& _newPrimaryKey ) override; + virtual sal_Bool SAL_CALL getUseHeaderLineAsColumnNames() override; + virtual void SAL_CALL setUseHeaderLineAsColumnNames( sal_Bool _bUseHeaderLineAsColumnNames ) override; + virtual void SAL_CALL addCopyTableListener( const Reference< XCopyTableListener >& Listener ) override; + virtual void SAL_CALL removeCopyTableListener( const Reference< XCopyTableListener >& Listener ) override; + + // XCopyTableWizard::XExecutableDialog + virtual void SAL_CALL setTitle( const OUString& aTitle ) override; + virtual ::sal_Int16 SAL_CALL execute( ) override; + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override; + + // XPropertySet + virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + public: + ::osl::Mutex& getMutex() { return m_aMutex; } + bool isInitialized() const { return m_xSourceConnection.is() && m_pSourceObject && m_xDestConnection.is(); } + + explicit CopyTableWizard( const Reference< XComponentContext >& _rxORB ); + virtual ~CopyTableWizard() override; + + protected: + // OGenericUnoDialog overridables + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; + virtual void executedDialog( sal_Int16 _nExecutionResult ) override; + + private: + /// ensures our current attribute values are reflected in the dialog + void impl_attributesToDialog_nothrow( OCopyTableWizard& _rDialog ) const; + + /// ensures the current dialog settings are reflected in our attributes + void impl_dialogToAttributes_nothrow( const OCopyTableWizard& _rDialog ); + + /** returns our typed dialog + + @throws css::uno::RuntimeException + if we don't have a dialog at the moment the method is called + */ + OCopyTableWizard& + impl_getDialog_throw(); + + /** ensures the given argument sequence contains a valid data access descriptor at the given position + @param _rAllArgs + the arguments as passed to ->initialize + @param _nArgPos + the position within ->_rAllArgs which contains the data access descriptor + @param _out_rxConnection + will, upon successful return, contain the connection for the data source + @param _out_rxDocInteractionHandler + will, upon successful return, contain the interaction handler which could + be deduced from database document described by the descriptor, if any. + (It is possible that the descriptor does not allow to deduce a database document, + in which case <code>_out_rxDocInteractionHandler</code> will be <NULL/>.) + @return the data access descriptor + */ + Reference< XPropertySet > + impl_ensureDataAccessDescriptor_throw( + const Sequence< Any >& _rAllArgs, + const sal_Int16 _nArgPos, + SharedConnection& _out_rxConnection, + Reference< XInteractionHandler >& _out_rxDocInteractionHandler + ) const; + + /** extracts the source object (table or query) described by the given descriptor, + relative to m_xSourceConnection + */ + std::unique_ptr< ICopyTableSourceObject > + impl_extractSourceObject_throw( + const Reference< XPropertySet >& _rxDescriptor, + sal_Int32& _out_rCommandType + ) const; + + /** extracts the result set to copy records from, and the selection-related aspects, if any. + + Effectively, this method extracts m_xSourceResultSet, m_aSourceSelection, and m_bSourceSelectionBookmarks. + + If an inconsistent/insufficient sub set of those properties is present in the descriptor, and exception + is thrown. + */ + void impl_extractSourceResultSet_throw( + const Reference< XPropertySet >& i_rDescriptor + ); + + /** checks whether the given copy source descriptor contains settings which are not + supported (yet) + + Throws an IllegalArgumentException if the descriptor contains a valid setting, which is + not yet supported. + */ + void impl_checkForUnsupportedSettings_throw( + const Reference< XPropertySet >& _rxSourceDescriptor ) const; + + /** obtains the connection described by the given data access descriptor + + If needed and possible, the method will ask the user, using the interaction + handler associated with the database described by the descriptor. + + All errors are handled with the InteractionHandler associated with the data source, + if there is one. Else, they will be silenced (but asserted in non-product builds). + + @param _rxDataSourceDescriptor + the data access descriptor describing the data source whose connection + should be obtained. Must not be <NULL/>. + @param _out_rxDocInteractionHandler + the interaction handler which could be deduced from the descriptor + + @throws RuntimeException + if anything goes seriously wrong. + */ + SharedConnection + impl_extractConnection_throw( + const Reference< XPropertySet >& _rxDataSourceDescriptor, + Reference< XInteractionHandler >& _out_rxDocInteractionHandler + ) const; + + /** actually copies the table + + This method is called after the dialog has been successfully executed. + */ + void impl_doCopy_nothrow(); + + /** creates the INSERT INTO statement + @param _xTable The destination table. + */ + OUString impl_getServerSideCopyStatement_throw( const Reference< XPropertySet >& _xTable ); + + /** creates the statement which, when executed, will produce the source data to copy + + If the source object refers to a query which contains parameters, those parameters + are filled in, using an interaction handler. + */ + ::utl::SharedUNOComponent< XPreparedStatement > + impl_createSourceStatement_throw() const; + + /** copies the data rows from the given source result set to the given destination table + */ + void impl_copyRows_throw( + const Reference< XResultSet >& _rxSourceResultSet, + const Reference< XPropertySet >& _rxDestTable + ); + + /** processes an error which occurred during copying + + First, all listeners are ask. If a listener tells to cancel or continue copying, this is reported to the + method's caller. If a listener tells to ask the user, this is done, and the user's decision is + reported to the method's caller. + + @return + <TRUE/> if and only if copying should be continued. + */ + bool impl_processCopyError_nothrow( + const CopyTableRowEvent& _rEvent ); + +private: + Reference<XComponentContext> m_xContext; + + // attributes + sal_Int16 m_nOperation; + OUString m_sDestinationTable; + Optional< OUString > m_aPrimaryKeyName; + bool m_bUseHeaderLineAsColumnNames; + + // source + SharedConnection m_xSourceConnection; + sal_Int32 m_nCommandType; + std::unique_ptr< ICopyTableSourceObject > + m_pSourceObject; + Reference< XResultSet > m_xSourceResultSet; + Sequence< Any > m_aSourceSelection; + bool m_bSourceSelectionBookmarks; + + // destination + SharedConnection m_xDestConnection; + + // other + Reference< XInteractionHandler > m_xInteractionHandler; + ::comphelper::OInterfaceContainerHelper3<XCopyTableListener> + m_aCopyTableListeners; + sal_Int16 m_nOverrideExecutionResult; + }; + +// MethodGuard +class CopyTableAccessGuard +{ +public: + explicit CopyTableAccessGuard( CopyTableWizard& _rWizard ) + :m_rWizard( _rWizard ) + { + m_rWizard.getMutex().acquire(); + if ( !m_rWizard.isInitialized() ) + throw NotInitializedException(); + } + + ~CopyTableAccessGuard() + { + m_rWizard.getMutex().release(); + } + +private: + CopyTableWizard& m_rWizard; +}; + +} + +CopyTableWizard::CopyTableWizard( const Reference< XComponentContext >& _rxORB ) + :CopyTableWizard_Base( _rxORB ) + ,m_xContext( _rxORB ) + ,m_nOperation( CopyTableOperation::CopyDefinitionAndData ) + ,m_aPrimaryKeyName( false, "ID" ) + ,m_bUseHeaderLineAsColumnNames( true ) + ,m_nCommandType( CommandType::COMMAND ) + ,m_bSourceSelectionBookmarks( true ) + ,m_aCopyTableListeners( m_aMutex ) + ,m_nOverrideExecutionResult( -1 ) +{ +} + +CopyTableWizard::~CopyTableWizard() +{ + acquire(); + + // protect some members whose dtor might potentially throw + try { m_xSourceConnection.clear(); } + catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); } + try { m_xDestConnection.clear(); } + catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); } + + // TODO: shouldn't we have explicit disposal support? If a listener is registered + // at our instance, and perhaps holds this our instance by a hard ref, then we'll never + // be destroyed. + // However, adding XComponent support to the GenericUNODialog probably requires + // some thinking - would it break existing clients which do not call a dispose, then? +} + +OUString SAL_CALL CopyTableWizard::getImplementationName() +{ + return "org.openoffice.comp.dbu.CopyTableWizard"; +} + +css::uno::Sequence<OUString> SAL_CALL CopyTableWizard::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.application.CopyTableWizard" }; +} + +Reference< XPropertySetInfo > SAL_CALL CopyTableWizard::getPropertySetInfo() +{ + Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +::sal_Int16 SAL_CALL CopyTableWizard::getOperation() +{ + CopyTableAccessGuard aGuard( *this ); + return m_nOperation; +} + +void SAL_CALL CopyTableWizard::setOperation( ::sal_Int16 _operation ) +{ + CopyTableAccessGuard aGuard( *this ); + + if ( ( _operation != CopyTableOperation::CopyDefinitionAndData ) + && ( _operation != CopyTableOperation::CopyDefinitionOnly ) + && ( _operation != CopyTableOperation::CreateAsView ) + && ( _operation != CopyTableOperation::AppendData ) + ) + throw IllegalArgumentException( OUString(), *this, 1 ); + + if ( ( _operation == CopyTableOperation::CreateAsView ) + && !OCopyTableWizard::supportsViews( m_xDestConnection ) + ) + throw IllegalArgumentException( + DBA_RES( STR_CTW_NO_VIEWS_SUPPORT ), + *this, + 1 + ); + + m_nOperation = _operation; +} + +OUString SAL_CALL CopyTableWizard::getDestinationTableName() +{ + CopyTableAccessGuard aGuard( *this ); + return m_sDestinationTable; +} + +void SAL_CALL CopyTableWizard::setDestinationTableName( const OUString& _destinationTableName ) +{ + CopyTableAccessGuard aGuard( *this ); + m_sDestinationTable = _destinationTableName; +} + +Optional< OUString > SAL_CALL CopyTableWizard::getCreatePrimaryKey() +{ + CopyTableAccessGuard aGuard( *this ); + return m_aPrimaryKeyName; +} + +void SAL_CALL CopyTableWizard::setCreatePrimaryKey( const Optional< OUString >& _newPrimaryKey ) +{ + CopyTableAccessGuard aGuard( *this ); + + if ( _newPrimaryKey.IsPresent && !OCopyTableWizard::supportsPrimaryKey( m_xDestConnection ) ) + throw IllegalArgumentException( + DBA_RES( STR_CTW_NO_PRIMARY_KEY_SUPPORT ), + *this, + 1 + ); + + m_aPrimaryKeyName = _newPrimaryKey; +} + +sal_Bool SAL_CALL CopyTableWizard::getUseHeaderLineAsColumnNames() +{ + CopyTableAccessGuard aGuard( *this ); + return m_bUseHeaderLineAsColumnNames; +} + +void SAL_CALL CopyTableWizard::setUseHeaderLineAsColumnNames( sal_Bool _bUseHeaderLineAsColumnNames ) +{ + CopyTableAccessGuard aGuard( *this ); + m_bUseHeaderLineAsColumnNames = _bUseHeaderLineAsColumnNames; +} + +void SAL_CALL CopyTableWizard::addCopyTableListener( const Reference< XCopyTableListener >& _rxListener ) +{ + CopyTableAccessGuard aGuard( *this ); + if ( _rxListener.is() ) + m_aCopyTableListeners.addInterface( _rxListener ); +} + +void SAL_CALL CopyTableWizard::removeCopyTableListener( const Reference< XCopyTableListener >& _rxListener ) +{ + CopyTableAccessGuard aGuard( *this ); + if ( _rxListener.is() ) + m_aCopyTableListeners.removeInterface( _rxListener ); +} + +void SAL_CALL CopyTableWizard::setTitle( const OUString& _rTitle ) +{ + CopyTableAccessGuard aGuard( *this ); + CopyTableWizard_DialogBase::setTitle( _rTitle ); +} + +::sal_Int16 SAL_CALL CopyTableWizard::execute( ) +{ + CopyTableAccessGuard aGuard( *this ); + + m_nOverrideExecutionResult = -1; + sal_Int16 nExecutionResult = CopyTableWizard_DialogBase::execute(); + if ( m_nOverrideExecutionResult ) + nExecutionResult = m_nOverrideExecutionResult; + + return nExecutionResult; +} + +OCopyTableWizard& CopyTableWizard::impl_getDialog_throw() +{ + OCopyTableWizard* pWizard = dynamic_cast<OCopyTableWizard*>(m_xDialog.get()); + if ( !pWizard ) + throw DisposedException( OUString(), *this ); + return *pWizard; +} + +void CopyTableWizard::impl_attributesToDialog_nothrow( OCopyTableWizard& _rDialog ) const +{ + // primary key column + _rDialog.setCreatePrimaryKey( m_aPrimaryKeyName.IsPresent, m_aPrimaryKeyName.Value ); + _rDialog.setUseHeaderLine(m_bUseHeaderLineAsColumnNames); + + // everything else was passed at construction time already +} + +void CopyTableWizard::impl_dialogToAttributes_nothrow( const OCopyTableWizard& _rDialog ) +{ + m_aPrimaryKeyName.IsPresent = _rDialog.shouldCreatePrimaryKey(); + if ( m_aPrimaryKeyName.IsPresent ) + m_aPrimaryKeyName.Value = _rDialog.getPrimaryKeyName(); + else + m_aPrimaryKeyName.Value.clear(); + + m_sDestinationTable = _rDialog.getName(); + + m_nOperation = _rDialog.getOperation(); + m_bUseHeaderLineAsColumnNames = _rDialog.UseHeaderLine(); +} + +namespace +{ + /** tries to obtain the InteractionHandler associated with a given data source + + If the data source is a sdb-level data source, it will have a DatabaseDocument associated + with it. This document may have an InteractionHandler used while loading it. + + @throws RuntimeException + if it occurs during invoking any of the data source's methods, or if any of the involved + components violates its contract by not providing the required interfaces + */ + Reference< XInteractionHandler > lcl_getInteractionHandler_throw( const Reference< XDataSource >& _rxDataSource, const Reference< XInteractionHandler >& _rFallback ) + { + Reference< XInteractionHandler > xHandler( _rFallback ); + + // try to obtain the document model + Reference< XModel > xDocumentModel; + Reference< XDocumentDataSource > xDocDataSource( _rxDataSource, UNO_QUERY ); + if ( xDocDataSource.is() ) + xDocumentModel.set( xDocDataSource->getDatabaseDocument(), UNO_QUERY_THROW ); + + // see whether the document model can provide a handler + if ( xDocumentModel.is() ) + { + xHandler = ::comphelper::NamedValueCollection::getOrDefault( xDocumentModel->getArgs(), u"InteractionHandler", xHandler ); + } + + return xHandler; + } + /** tries to obtain the InteractionHandler associated with a given connection + + If the connection belongs to a sdb-level data source, then this data source + is examined for an interaction handler. Else, <NULL/> is returned. + + @throws RuntimeException + if it occurs during invoking any of the data source's methods, or if any of the involved + components violates its contract by not providing the required interfaces + */ + Reference< XInteractionHandler > lcl_getInteractionHandler_throw( const Reference< XConnection >& _rxConnection, const Reference< XInteractionHandler >& _rFallback ) + { + // try whether there is a data source which the connection belongs to + Reference< XDataSource > xDataSource; + Reference< XChild > xAsChild( _rxConnection, UNO_QUERY ); + if ( xAsChild.is() ) + xDataSource.set(xAsChild->getParent(), css::uno::UNO_QUERY); + + if ( xDataSource.is() ) + return lcl_getInteractionHandler_throw( xDataSource, _rFallback ); + + return _rFallback; + } +} + +Reference< XPropertySet > CopyTableWizard::impl_ensureDataAccessDescriptor_throw( + const Sequence< Any >& _rAllArgs, const sal_Int16 _nArgPos, SharedConnection& _out_rxConnection, + Reference< XInteractionHandler >& _out_rxDocInteractionHandler ) const +{ + Reference< XPropertySet > xDescriptor; + _rAllArgs[ _nArgPos ] >>= xDescriptor; + + // the descriptor must be non-NULL, of course + bool bIsValid = xDescriptor.is(); + + // it must support the proper service + if ( bIsValid ) + { + Reference< XServiceInfo > xSI( xDescriptor, UNO_QUERY ); + bIsValid = ( xSI.is() + && xSI->supportsService( "com.sun.star.sdb.DataAccessDescriptor" ) ); + } + + // it must be able to provide a connection + if ( bIsValid ) + { + _out_rxConnection = impl_extractConnection_throw( xDescriptor, _out_rxDocInteractionHandler ); + bIsValid = _out_rxConnection.is(); + } + + if ( !bIsValid ) + { + throw IllegalArgumentException( + DBA_RES( STR_CTW_INVALID_DATA_ACCESS_DESCRIPTOR ), + *const_cast< CopyTableWizard* >( this ), + _nArgPos + 1 + ); + } + + return xDescriptor; +} + +namespace +{ + bool lcl_hasNonEmptyStringValue_throw( const Reference< XPropertySet >& _rxDescriptor, + const Reference< XPropertySetInfo >& rxPSI, const OUString& _rPropertyName ) + { + OUString sValue; + if ( rxPSI->hasPropertyByName( _rPropertyName ) ) + { + OSL_VERIFY( _rxDescriptor->getPropertyValue( _rPropertyName ) >>= sValue ); + } + return !sValue.isEmpty(); + } +} + +void CopyTableWizard::impl_checkForUnsupportedSettings_throw( const Reference< XPropertySet >& _rxSourceDescriptor ) const +{ + OSL_PRECOND( _rxSourceDescriptor.is(), "CopyTableWizard::impl_checkForUnsupportedSettings_throw: illegal argument!" ); + Reference< XPropertySetInfo > xPSI( _rxSourceDescriptor->getPropertySetInfo(), UNO_SET_THROW ); + OUString sUnsupportedSetting; + + const OUString aSettings[] = { + OUString(PROPERTY_FILTER), OUString(PROPERTY_ORDER), OUString(PROPERTY_HAVING_CLAUSE), OUString(PROPERTY_GROUP_BY) + }; + for (const auto & aSetting : aSettings) + { + if ( lcl_hasNonEmptyStringValue_throw( _rxSourceDescriptor, xPSI, aSetting ) ) + { + sUnsupportedSetting = aSetting; + break; + } + } + + if ( !sUnsupportedSetting.isEmpty() ) + { + OUString sMessage( + DBA_RES(STR_CTW_ERROR_UNSUPPORTED_SETTING). + replaceFirst("$name$", sUnsupportedSetting)); + throw IllegalArgumentException( + sMessage, + *const_cast< CopyTableWizard* >( this ), + 1 + ); + } + +} + +std::unique_ptr< ICopyTableSourceObject > CopyTableWizard::impl_extractSourceObject_throw( const Reference< XPropertySet >& _rxDescriptor, sal_Int32& _out_rCommandType ) const +{ + OSL_PRECOND( _rxDescriptor.is() && m_xSourceConnection.is(), "CopyTableWizard::impl_extractSourceObject_throw: illegal arguments!" ); + + Reference< XPropertySetInfo > xPSI( _rxDescriptor->getPropertySetInfo(), UNO_SET_THROW ); + if ( !xPSI->hasPropertyByName( PROPERTY_COMMAND ) + || !xPSI->hasPropertyByName( PROPERTY_COMMAND_TYPE ) + ) + throw IllegalArgumentException("Expecting a table or query specification.", + // TODO: resource + *const_cast< CopyTableWizard* >( this ), 1); + + OUString sCommand; + _out_rCommandType = CommandType::COMMAND; + OSL_VERIFY( _rxDescriptor->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand ); + OSL_VERIFY( _rxDescriptor->getPropertyValue( PROPERTY_COMMAND_TYPE ) >>= _out_rCommandType ); + + std::unique_ptr< ICopyTableSourceObject > pSourceObject; + Reference< XNameAccess > xContainer; + switch ( _out_rCommandType ) + { + case CommandType::TABLE: + { + Reference< XTablesSupplier > xSuppTables( m_xSourceConnection.getTyped(), UNO_QUERY ); + if ( xSuppTables.is() ) + xContainer.set( xSuppTables->getTables(), UNO_SET_THROW ); + } + break; + case CommandType::QUERY: + { + Reference< XQueriesSupplier > xSuppQueries( m_xSourceConnection.getTyped(), UNO_QUERY ); + if ( xSuppQueries.is() ) + xContainer.set( xSuppQueries->getQueries(), UNO_SET_THROW ); + } + break; + default: + throw IllegalArgumentException( + DBA_RES( STR_CTW_ONLY_TABLES_AND_QUERIES_SUPPORT ), + *const_cast< CopyTableWizard* >( this ), + 1 + ); + } + + if ( xContainer.is() ) + { + pSourceObject.reset( new ObjectCopySource( m_xSourceConnection, + Reference< XPropertySet >( xContainer->getByName( sCommand ), UNO_QUERY_THROW ) ) ); + } + else + { + // our source connection is an SDBC level connection only, not a SDBCX level one + // Which means it cannot provide the to-be-copied object as component. + + if ( _out_rCommandType == CommandType::QUERY ) + // we cannot copy a query if the connection cannot provide it ... + throw IllegalArgumentException( + DBA_RES( STR_CTW_ERROR_NO_QUERY ), + *const_cast< CopyTableWizard* >( this ), + 1 + ); + pSourceObject.reset( new NamedTableCopySource( m_xSourceConnection, sCommand ) ); + } + + return pSourceObject; +} + +void CopyTableWizard::impl_extractSourceResultSet_throw( const Reference< XPropertySet >& i_rDescriptor ) +{ + Reference< XPropertySetInfo > xPSI( i_rDescriptor->getPropertySetInfo(), UNO_SET_THROW ); + + // extract relevant settings + if ( xPSI->hasPropertyByName( PROPERTY_RESULT_SET ) ) + m_xSourceResultSet.set( i_rDescriptor->getPropertyValue( PROPERTY_RESULT_SET ), UNO_QUERY ); + + if ( xPSI->hasPropertyByName( PROPERTY_SELECTION ) ) + OSL_VERIFY( i_rDescriptor->getPropertyValue( PROPERTY_SELECTION ) >>= m_aSourceSelection ); + + if ( xPSI->hasPropertyByName( PROPERTY_BOOKMARK_SELECTION ) ) + OSL_VERIFY( i_rDescriptor->getPropertyValue( PROPERTY_BOOKMARK_SELECTION ) >>= m_bSourceSelectionBookmarks ); + + // sanity checks + const bool bHasResultSet = m_xSourceResultSet.is(); + const bool bHasSelection = m_aSourceSelection.hasElements(); + if ( bHasSelection && !bHasResultSet ) + throw IllegalArgumentException("A result set is needed when specifying a selection to copy.", + // TODO: resource + *this, 1); + + if ( bHasSelection && m_bSourceSelectionBookmarks ) + { + Reference< XRowLocate > xRowLocate( m_xSourceResultSet, UNO_QUERY ); + if ( !xRowLocate.is() ) + { + ::dbtools::throwGenericSQLException( + DBA_RES(STR_CTW_COPY_SOURCE_NEEDS_BOOKMARKS), + *this + ); + } + } +} + +SharedConnection CopyTableWizard::impl_extractConnection_throw( const Reference< XPropertySet >& _rxDataSourceDescriptor, + Reference< XInteractionHandler >& _out_rxDocInteractionHandler ) const +{ + SharedConnection xConnection; + + OSL_PRECOND( _rxDataSourceDescriptor.is(), "CopyTableWizard::impl_extractConnection_throw: no descriptor!" ); + if ( !_rxDataSourceDescriptor.is() ) + return xConnection; + + Reference< XInteractionHandler > xInteractionHandler; + + do + { + Reference< XPropertySetInfo > xPSI( _rxDataSourceDescriptor->getPropertySetInfo(), UNO_SET_THROW ); + + // if there's an ActiveConnection, use it + if ( xPSI->hasPropertyByName( PROPERTY_ACTIVE_CONNECTION ) ) + { + Reference< XConnection > xPure; + OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xPure ); + xConnection.reset( xPure, SharedConnection::NoTakeOwnership ); + } + if ( xConnection.is() ) + { + xInteractionHandler = lcl_getInteractionHandler_throw( xConnection.getTyped(), m_xInteractionHandler ); + SAL_WARN_IF( !xInteractionHandler.is(), "dbaccess.ui", "CopyTableWizard::impl_extractConnection_throw: lcl_getInteractionHandler_throw returned nonsense!" ); + break; + } + + // there could be a DataSourceName or a DatabaseLocation, describing the css.sdb.DataSource + OUString sDataSource, sDatabaseLocation; + if ( xPSI->hasPropertyByName( PROPERTY_DATASOURCENAME ) ) + OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_DATASOURCENAME ) >>= sDataSource ); + if ( xPSI->hasPropertyByName( PROPERTY_DATABASE_LOCATION ) ) + OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_DATABASE_LOCATION ) >>= sDatabaseLocation ); + + // need a DatabaseContext for loading the data source + Reference< XDatabaseContext > xDatabaseContext = DatabaseContext::create( m_xContext ); + Reference< XDataSource > xDataSource; + if ( !sDataSource.isEmpty() ) + xDataSource.set( xDatabaseContext->getByName( sDataSource ), UNO_QUERY_THROW ); + if ( !xDataSource.is() && !sDatabaseLocation.isEmpty() ) + xDataSource.set( xDatabaseContext->getByName( sDatabaseLocation ), UNO_QUERY_THROW ); + + if ( xDataSource.is() ) + { + // first, try connecting with completion + xInteractionHandler = lcl_getInteractionHandler_throw( xDataSource, m_xInteractionHandler ); + SAL_WARN_IF( !xInteractionHandler.is(), "dbaccess.ui", "CopyTableWizard::impl_extractConnection_throw: lcl_getInteractionHandler_throw returned nonsense!" ); + if ( xInteractionHandler.is() ) + { + Reference< XCompletedConnection > xInteractiveConnection( xDataSource, UNO_QUERY ); + if ( xInteractiveConnection.is() ) + xConnection.reset( xInteractiveConnection->connectWithCompletion( xInteractionHandler ), SharedConnection::TakeOwnership ); + } + + // interactively connecting was not successful or possible -> connect without interaction + if ( !xConnection.is() ) + { + xConnection.reset( xDataSource->getConnection( OUString(), OUString() ), SharedConnection::TakeOwnership ); + } + } + + if ( xConnection.is() ) + break; + + // finally, there could be a ConnectionResource/ConnectionInfo + OUString sConnectionResource; + Sequence< PropertyValue > aConnectionInfo; + if ( xPSI->hasPropertyByName( PROPERTY_CONNECTION_RESOURCE ) ) + OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_CONNECTION_RESOURCE ) >>= sConnectionResource ); + if ( xPSI->hasPropertyByName( PROPERTY_CONNECTION_INFO ) ) + OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_CONNECTION_INFO ) >>= aConnectionInfo ); + + Reference< XDriverManager > xDriverManager; + try { + xDriverManager.set( ConnectionPool::create( m_xContext ), UNO_QUERY_THROW ); + } catch( const Exception& ) { } + if ( !xDriverManager.is() ) + // no connection pool installed + xDriverManager.set( DriverManager::create( m_xContext ), UNO_QUERY_THROW ); + + if ( aConnectionInfo.hasElements() ) + xConnection.set( xDriverManager->getConnectionWithInfo( sConnectionResource, aConnectionInfo ), UNO_SET_THROW ); + else + xConnection.set( xDriverManager->getConnection( sConnectionResource ), UNO_SET_THROW ); + } + while ( false ); + + if ( xInteractionHandler != m_xInteractionHandler ) + _out_rxDocInteractionHandler = xInteractionHandler; + + return xConnection; +} + +::utl::SharedUNOComponent< XPreparedStatement > CopyTableWizard::impl_createSourceStatement_throw() const +{ + OSL_PRECOND( m_xSourceConnection.is(), "CopyTableWizard::impl_createSourceStatement_throw: illegal call!" ); + if ( !m_xSourceConnection.is() ) + throw RuntimeException( "CopyTableWizard::impl_createSourceStatement_throw: illegal call!", *const_cast< CopyTableWizard* >( this )); + + ::utl::SharedUNOComponent< XPreparedStatement > xStatement; + switch ( m_nCommandType ) + { + case CommandType::TABLE: + xStatement.set( m_pSourceObject->getPreparedSelectStatement(), UNO_SET_THROW ); + break; + + case CommandType::QUERY: + { + OUString sQueryCommand( m_pSourceObject->getSelectStatement() ); + xStatement.set( m_pSourceObject->getPreparedSelectStatement(), UNO_SET_THROW ); + + // check whether we have to fill in parameter values + // create and fill a composer + + Reference< XMultiServiceFactory > xFactory( m_xSourceConnection, UNO_QUERY ); + ::utl::SharedUNOComponent< XSingleSelectQueryComposer > xComposer; + if ( xFactory.is() ) + // note: connections below the sdb-level are allowed to not support the XMultiServiceFactory interface + xComposer.set( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY ); + + if ( xComposer.is() ) + { + xComposer->setQuery( sQueryCommand ); + + Reference< XParameters > xStatementParams( xStatement, UNO_QUERY ); + OSL_ENSURE( xStatementParams.is(), "CopyTableWizard::impl_createSourceStatement_throw: no access to the statement's parameters!" ); + // the statement should be a css.sdbc.PreparedStatement (this is what + // we created), and a prepared statement is required to support XParameters + if ( xStatementParams.is() ) + { + OSL_ENSURE( m_xInteractionHandler.is(), + "CopyTableWizard::impl_createSourceStatement_throw: no interaction handler for the parameters request!" ); + // we should always have an interaction handler - as last fallback, we create an own one in ::initialize + + if ( m_xInteractionHandler.is() ) + ::dbtools::askForParameters( xComposer, xStatementParams, m_xSourceConnection, m_xInteractionHandler ); + } + } + } + break; + + default: + // this should not have survived initialization phase + throw RuntimeException("No case matched, this should not have survived the initialization phase", *const_cast< CopyTableWizard* >( this )); + } + + return xStatement; +} + +namespace +{ + class ValueTransfer + { + public: + ValueTransfer( std::vector< sal_Int32 > _rColTypes, + const Reference< XRow >& _rxSource, const Reference< XParameters >& _rxDest ) + :m_ColTypes( std::move(_rColTypes) ) + ,m_xSource( _rxSource ) + ,m_xDest( _rxDest ) + { + } + + template< typename VALUE_TYPE > + void transferValue( sal_Int32 _nSourcePos, sal_Int32 _nDestPos, + VALUE_TYPE ( SAL_CALL XRow::*_pGetter )( sal_Int32 ), + void (SAL_CALL XParameters::*_pSetter)( sal_Int32, VALUE_TYPE ) ) + { + VALUE_TYPE value( (m_xSource.get()->*_pGetter)( _nSourcePos ) ); + if ( m_xSource->wasNull() ) + m_xDest->setNull( _nDestPos, m_ColTypes[ _nSourcePos ] ); + else + (m_xDest.get()->*_pSetter)( _nDestPos, value ); + } + + template< typename VALUE_TYPE > + void transferComplexValue( sal_Int32 _nSourcePos, sal_Int32 _nDestPos, + VALUE_TYPE ( SAL_CALL XRow::*_pGetter )( sal_Int32 ), + void (SAL_CALL XParameters::*_pSetter)( sal_Int32, const VALUE_TYPE& ) ) + { + const VALUE_TYPE value( (m_xSource.get()->*_pGetter)( _nSourcePos ) ); + if ( m_xSource->wasNull() ) + m_xDest->setNull( _nDestPos, m_ColTypes[ _nSourcePos ] ); + else + (m_xDest.get()->*_pSetter)( _nDestPos, value ); + } + private: + const std::vector< sal_Int32 > m_ColTypes; + const Reference< XRow > m_xSource; + const Reference< XParameters > m_xDest; + }; +} + +bool CopyTableWizard::impl_processCopyError_nothrow( const CopyTableRowEvent& _rEvent ) +{ + try + { + ::comphelper::OInterfaceIteratorHelper3 aIter( m_aCopyTableListeners ); + while ( aIter.hasMoreElements() ) + { + Reference< XCopyTableListener > xListener( aIter.next() ); + sal_Int16 nListenerChoice = xListener->copyRowError( _rEvent ); + switch ( nListenerChoice ) + { + case CopyTableContinuation::Proceed: return true; // continue copying + case CopyTableContinuation::CallNextHandler: continue; // continue the loop, ask next listener + case CopyTableContinuation::Cancel: return false; // cancel copying + case CopyTableContinuation::AskUser: break; // stop asking the listeners, ask the user + + default: + SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_processCopyError_nothrow: invalid listener response!" ); + // ask next listener + continue; + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + // no listener felt responsible for the error, or a listener told to ask the user + + try + { + SQLContext aError; + aError.Context = *this; + aError.Message = DBA_RES(STR_ERROR_OCCURRED_WHILE_COPYING); + + ::dbtools::SQLExceptionInfo aInfo( _rEvent.Error ); + if ( aInfo.isValid() ) + aError.NextException = _rEvent.Error; + else + { + // a non-SQL exception happened + Exception aException; + OSL_VERIFY( _rEvent.Error >>= aException ); + SQLContext aContext; + aContext.Context = aException.Context; + aContext.Message = aException.Message; + aContext.Details = _rEvent.Error.getValueTypeName(); + aError.NextException <<= aContext; + } + + ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( Any( aError ) ) ); + + ::rtl::Reference< ::comphelper::OInteractionApprove > xYes = new ::comphelper::OInteractionApprove; + xRequest->addContinuation( xYes ); + xRequest->addContinuation( new ::comphelper::OInteractionDisapprove ); + + OSL_ENSURE( m_xInteractionHandler.is(), + "CopyTableWizard::impl_processCopyError_nothrow: we always should have an interaction handler!" ); + if ( m_xInteractionHandler.is() ) + m_xInteractionHandler->handle( xRequest ); + + if ( xYes->wasSelected() ) + // continue copying + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + // cancel copying + return false; +} + +void CopyTableWizard::impl_copyRows_throw( const Reference< XResultSet >& _rxSourceResultSet, + const Reference< XPropertySet >& _rxDestTable ) +{ + OSL_PRECOND( m_xDestConnection.is(), "CopyTableWizard::impl_copyRows_throw: illegal call!" ); + if ( !m_xDestConnection.is() ) + throw RuntimeException( "m_xDestConnection is set to null, CopyTableWizard::impl_copyRows_throw: illegal call!", *this ); + + Reference< XDatabaseMetaData > xDestMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW ); + + const OCopyTableWizard& rWizard = impl_getDialog_throw(); + ODatabaseExport::TPositions aColumnPositions = rWizard.GetColumnPositions(); + const bool bShouldCreatePrimaryKey = rWizard.shouldCreatePrimaryKey(); + + Reference< XRow > xRow ( _rxSourceResultSet, UNO_QUERY_THROW ); + Reference< XRowLocate > xRowLocate ( _rxSourceResultSet, UNO_QUERY_THROW ); + + Reference< XResultSetMetaDataSupplier > xSuppResMeta( _rxSourceResultSet, UNO_QUERY_THROW ); + Reference< XResultSetMetaData> xMeta( xSuppResMeta->getMetaData() ); + + // we need a vector which all types + sal_Int32 nCount = xMeta->getColumnCount(); + std::vector< sal_Int32 > aSourceColTypes; + aSourceColTypes.reserve( nCount + 1 ); + aSourceColTypes.push_back( -1 ); // just to avoid an every time i-1 call + + std::vector< sal_Int32 > aSourcePrec; + aSourcePrec.reserve( nCount + 1 ); + aSourcePrec.push_back( -1 ); // just to avoid an every time i-1 call + + for ( sal_Int32 k=1; k <= nCount; ++k ) + { + aSourceColTypes.push_back( xMeta->getColumnType( k ) ); + aSourcePrec.push_back( xMeta->getPrecision( k ) ); + } + + // now create, fill and execute the prepared statement + Reference< XPreparedStatement > xStatement( ODatabaseExport::createPreparedStatment( xDestMetaData, _rxDestTable, aColumnPositions ), UNO_SET_THROW ); + Reference< XParameters > xStatementParams( xStatement, UNO_QUERY_THROW ); + + const bool bSelectedRecordsOnly = m_aSourceSelection.hasElements(); + const Any* pSelectedRow = m_aSourceSelection.getConstArray(); + const Any* pSelEnd = pSelectedRow + m_aSourceSelection.getLength(); + + sal_Int32 nRowCount = 0; + bool bContinue = false; + + CopyTableRowEvent aCopyEvent; + aCopyEvent.Source = *this; + aCopyEvent.SourceData = _rxSourceResultSet; + + do // loop as long as there are more rows or the selection ends + { + bContinue = false; + if ( bSelectedRecordsOnly ) + { + if ( pSelectedRow != pSelEnd ) + { + if ( m_bSourceSelectionBookmarks ) + { + bContinue = xRowLocate->moveToBookmark( *pSelectedRow ); + } + else + { + sal_Int32 nPos = 0; + OSL_VERIFY( *pSelectedRow >>= nPos ); + bContinue = _rxSourceResultSet->absolute( nPos ); + } + ++pSelectedRow; + } + } + else + bContinue = _rxSourceResultSet->next(); + + if ( !bContinue ) + { + break; + } + + ++nRowCount; + + aCopyEvent.Error.clear(); + try + { + bool bInsertedPrimaryKey = false; + // notify listeners + m_aCopyTableListeners.notifyEach( &XCopyTableListener::copyingRow, aCopyEvent ); + + sal_Int32 nSourceColumn( 1 ); + ValueTransfer aTransfer( aSourceColTypes, xRow, xStatementParams ); + + for ( auto const& rColumnPos : aColumnPositions ) + { + sal_Int32 nDestColumn = rColumnPos.first; + if ( nDestColumn == COLUMN_POSITION_NOT_FOUND ) + { + ++nSourceColumn; + // otherwise we don't get the correct value when only the 2nd source column was selected + continue; + } + + if ( bShouldCreatePrimaryKey && !bInsertedPrimaryKey ) + { + xStatementParams->setInt( 1, nRowCount ); + ++nSourceColumn; + bInsertedPrimaryKey = true; + continue; + } + + if ( ( nSourceColumn < 1 ) || ( o3tl::make_unsigned(nSourceColumn) >= aSourceColTypes.size() ) ) + { // ( we have to check here against 1 because the parameters are 1 based) + ::dbtools::throwSQLException("Internal error: invalid column type index.", + ::dbtools::StandardSQLState::INVALID_DESCRIPTOR_INDEX, *this); + } + + switch ( aSourceColTypes[ nSourceColumn ] ) + { + case DataType::DOUBLE: + case DataType::REAL: + aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getDouble, &XParameters::setDouble ); + break; + + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getString, &XParameters::setString ); + break; + + case DataType::BIGINT: + aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getLong, &XParameters::setLong ); + break; + + case DataType::FLOAT: + aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getFloat, &XParameters::setFloat ); + break; + + case DataType::LONGVARBINARY: + case DataType::BINARY: + case DataType::VARBINARY: + aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getBytes, &XParameters::setBytes ); + break; + + case DataType::DATE: + aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getDate, &XParameters::setDate ); + break; + + case DataType::TIME: + aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getTime, &XParameters::setTime ); + break; + + case DataType::TIMESTAMP: + aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getTimestamp, &XParameters::setTimestamp ); + break; + + case DataType::BIT: + if ( aSourcePrec[nSourceColumn] > 1 ) + { + aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getBytes, &XParameters::setBytes ); + break; + } + [[fallthrough]]; + case DataType::BOOLEAN: + aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getBoolean, &XParameters::setBoolean ); + break; + + case DataType::TINYINT: + aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getByte, &XParameters::setByte ); + break; + + case DataType::SMALLINT: + aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getShort, &XParameters::setShort ); + break; + + case DataType::INTEGER: + aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getInt, &XParameters::setInt ); + break; + + case DataType::BLOB: + aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getBlob, &XParameters::setBlob ); + break; + + case DataType::CLOB: + aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getClob, &XParameters::setClob ); + break; + + default: + { + OUString aMessage( DBA_RES( STR_CTW_UNSUPPORTED_COLUMN_TYPE ) ); + + aMessage = aMessage.replaceFirst( "$type$", OUString::number( aSourceColTypes[ nSourceColumn ] ) ); + aMessage = aMessage.replaceFirst( "$pos$", OUString::number( nSourceColumn ) ); + + ::dbtools::throwSQLException( + aMessage, + ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE, + *this + ); + } + } + ++nSourceColumn; + } + xStatement->executeUpdate(); + + // notify listeners + m_aCopyTableListeners.notifyEach( &XCopyTableListener::copiedRow, aCopyEvent ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("dbaccess", ""); + aCopyEvent.Error = ::cppu::getCaughtException(); + } + + if ( aCopyEvent.Error.hasValue() ) + bContinue = impl_processCopyError_nothrow( aCopyEvent ); + } + while( bContinue ); +} + +void CopyTableWizard::impl_doCopy_nothrow() +{ + Any aError; + + try + { + OCopyTableWizard& rWizard( impl_getDialog_throw() ); + + weld::WaitObject aWO(rWizard.getDialog()); + Reference< XPropertySet > xTable; + + switch ( rWizard.getOperation() ) + { + case CopyTableOperation::CopyDefinitionOnly: + case CopyTableOperation::CopyDefinitionAndData: + { + xTable = rWizard.createTable(); + + if( !xTable.is() ) + { + SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: createTable should throw here, shouldn't it?" ); + break; + } + + if( CopyTableOperation::CopyDefinitionOnly == rWizard.getOperation() ) + break; + + [[fallthrough]]; + } + + case CopyTableOperation::AppendData: + { + // note that the CopyDefinitionAndData case falls through to here. + assert((rWizard.getOperation() == CopyTableOperation::CopyDefinitionAndData) || + (rWizard.getOperation() == CopyTableOperation::AppendData)); + assert((rWizard.getOperation() == CopyTableOperation::CopyDefinitionAndData) == xTable.is()); + if ( !xTable.is() ) + { + assert(rWizard.getOperation() == CopyTableOperation::AppendData); + xTable = rWizard.getTable(); + if ( !xTable.is() ) + { + SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: getTable should throw here, shouldn't it?" ); + break; + } + } + + ::utl::SharedUNOComponent< XPreparedStatement > xSourceStatement; + ::utl::SharedUNOComponent< XResultSet > xSourceResultSet; + + if ( m_xSourceResultSet.is() ) + { + xSourceResultSet.reset( m_xSourceResultSet, ::utl::SharedUNOComponent< XResultSet >::NoTakeOwnership ); + } + else + { + const bool bIsSameConnection = ( m_xSourceConnection.getTyped() == m_xDestConnection.getTyped() ); + const bool bIsTable = ( CommandType::TABLE == m_nCommandType ); + bool bDone = false; + if ( bIsSameConnection && bIsTable ) + { + // try whether the server supports copying via SQL + try + { + m_xDestConnection->createStatement()->executeUpdate( impl_getServerSideCopyStatement_throw(xTable) ); + bDone = true; + } + catch( const Exception& ) + { + // this is allowed. + } + } + + if ( !bDone ) + { + xSourceStatement.set( impl_createSourceStatement_throw(), UNO_SET_THROW ); + xSourceResultSet.set( xSourceStatement->executeQuery(), UNO_SET_THROW ); + } + } + + if ( xSourceResultSet.is() ) + impl_copyRows_throw( xSourceResultSet, xTable ); + + // tdf#119962 + const Reference< XDatabaseMetaData > xDestMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW ); + OUString sDatabaseDest = xDestMetaData->getDatabaseProductName().toAsciiLowerCase(); + // If we created a new primary key, then it won't necessarily be an IDENTITY column + const bool bShouldCreatePrimaryKey = rWizard.shouldCreatePrimaryKey(); + if ( !bShouldCreatePrimaryKey && ((sDatabaseDest.indexOf("hsql") != -1) || (sDatabaseDest.indexOf("firebird") != -1)) ) + { + const OUString sComposedTableName = ::dbtools::composeTableName( xDestMetaData, xTable, ::dbtools::EComposeRule::InDataManipulation, true ); + + OUString aSchema,aTable; + xTable->getPropertyValue("SchemaName") >>= aSchema; + xTable->getPropertyValue("Name") >>= aTable; + Any aCatalog = xTable->getPropertyValue("CatalogName"); + + const Reference< XResultSet > xResultPKCL(xDestMetaData->getPrimaryKeys(aCatalog,aSchema,aTable)); + Reference< XRow > xRowPKCL(xResultPKCL, UNO_QUERY_THROW); + OUString sPKCL; + if ( xRowPKCL.is() ) + { + if (xResultPKCL->next()) + { + sPKCL = xRowPKCL->getString(4); + } + } + + if (!sPKCL.isEmpty()) + { + OUString strSql = "SELECT MAX(\"" + sPKCL + "\") FROM " + sComposedTableName; + + Reference< XResultSet > xResultMAXNUM(m_xDestConnection->createStatement()->executeQuery(strSql)); + Reference< XRow > xRow(xResultMAXNUM, UNO_QUERY_THROW); + + sal_Int64 maxVal = -1L; + if (xResultMAXNUM->next()) + { + maxVal = xRow->getLong(1); + } + + if (maxVal > 0L) + { + strSql = "ALTER TABLE " + sComposedTableName + " ALTER \"" + sPKCL + "\" RESTART WITH " + OUString::number(maxVal + 1); + + m_xDestConnection->createStatement()->execute(strSql); + } + } + } + } + break; + + case CopyTableOperation::CreateAsView: + rWizard.createView(); + break; + + default: + SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: What operation, please?" ); + break; + } + } + catch( const Exception& ) + { + aError = ::cppu::getCaughtException(); + + // silence the error of the user cancelling the parameter's dialog + SQLException aSQLError; + if ( ( aError >>= aSQLError ) && ( aSQLError.ErrorCode == ::dbtools::ParameterInteractionCancelled ) ) + { + aError.clear(); + m_nOverrideExecutionResult = RET_CANCEL; + } + } + + if ( aError.hasValue() && m_xInteractionHandler.is() ) + { + try + { + ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( aError ) ); + m_xInteractionHandler->handle( xRequest ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } +} + +OUString CopyTableWizard::impl_getServerSideCopyStatement_throw(const Reference< XPropertySet >& _xTable) +{ + const Reference<XColumnsSupplier> xDestColsSup(_xTable,UNO_QUERY_THROW); + const Sequence< OUString> aDestColumnNames = xDestColsSup->getColumns()->getElementNames(); + const Reference< XDatabaseMetaData > xDestMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW ); + const OUString sQuote = xDestMetaData->getIdentifierQuoteString(); + OUStringBuffer sColumns; + // 1st check if the columns matching + for ( auto const & rColumnPositionPair : impl_getDialog_throw().GetColumnPositions() ) + { + if ( COLUMN_POSITION_NOT_FOUND != rColumnPositionPair.second ) + { + if ( !sColumns.isEmpty() ) + sColumns.append(","); + sColumns.append(sQuote + aDestColumnNames[rColumnPositionPair.second - 1] + sQuote); + } + } + const OUString sComposedTableName = ::dbtools::composeTableName( xDestMetaData, _xTable, ::dbtools::EComposeRule::InDataManipulation, true ); + OUString sSql("INSERT INTO " + sComposedTableName + " ( " + sColumns + " ) " + m_pSourceObject->getSelectStatement()); + + return sSql; +} + +void SAL_CALL CopyTableWizard::initialize( const Sequence< Any >& _rArguments ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( isInitialized() ) + throw AlreadyInitializedException( OUString(), *this ); + + sal_Int32 nArgCount( _rArguments.getLength() ); + if ( ( nArgCount != 2 ) && ( nArgCount != 3 ) ) + throw IllegalArgumentException( + DBA_RES( STR_CTW_ILLEGAL_PARAMETER_COUNT ), + *this, + 1 + ); + + try + { + if ( nArgCount == 3 ) + { // ->createWithInteractionHandler + if ( !( _rArguments[2] >>= m_xInteractionHandler ) ) + throw IllegalArgumentException( + DBA_RES( STR_CTW_ERROR_INVALID_INTERACTIONHANDLER ), + *this, + 3 + ); + } + if ( !m_xInteractionHandler.is() ) + m_xInteractionHandler = InteractionHandler::createWithParent(m_xContext, nullptr); + + Reference< XInteractionHandler > xSourceDocHandler; + Reference< XPropertySet > xSourceDescriptor( impl_ensureDataAccessDescriptor_throw( _rArguments, 0, m_xSourceConnection, xSourceDocHandler ) ); + impl_checkForUnsupportedSettings_throw( xSourceDescriptor ); + m_pSourceObject = impl_extractSourceObject_throw( xSourceDescriptor, m_nCommandType ); + impl_extractSourceResultSet_throw( xSourceDescriptor ); + + Reference< XInteractionHandler > xDestDocHandler; + impl_ensureDataAccessDescriptor_throw( _rArguments, 1, m_xDestConnection, xDestDocHandler ); + + if ( xDestDocHandler.is() && !m_xInteractionHandler.is() ) + m_xInteractionHandler = xDestDocHandler; + + Reference< XPropertySet > xInteractionHandler(m_xInteractionHandler, UNO_QUERY); + if (xInteractionHandler.is()) + { + Any aParentWindow(xInteractionHandler->getPropertyValue("ParentWindow")); + aParentWindow >>= m_xParent; + } + } + catch( const RuntimeException& ) { throw; } + catch( const SQLException& ) { throw; } + catch( const Exception& ) + { + throw WrappedTargetException( + DBA_RES( STR_CTW_ERROR_DURING_INITIALIZATION ), + *this, + ::cppu::getCaughtException() + ); + } +} + +::cppu::IPropertyArrayHelper& CopyTableWizard::getInfoHelper() +{ + return *getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* CopyTableWizard::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties( aProps ); + return new ::cppu::OPropertyArrayHelper( aProps ); +} + +std::unique_ptr<weld::DialogController> CopyTableWizard::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) +{ + OSL_PRECOND( isInitialized(), "CopyTableWizard::createDialog: not initialized!" ); + // this should have been prevented in ::execute already + + auto xWizard = std::make_unique<OCopyTableWizard>( + Application::GetFrameWeld(rParent), + m_sDestinationTable, + m_nOperation, + *m_pSourceObject, + m_xSourceConnection.getTyped(), + m_xDestConnection.getTyped(), + m_xContext, + m_xInteractionHandler); + + impl_attributesToDialog_nothrow(*xWizard); + + return xWizard; +} + +void CopyTableWizard::executedDialog( sal_Int16 _nExecutionResult ) +{ + CopyTableWizard_DialogBase::executedDialog( _nExecutionResult ); + + if ( _nExecutionResult == RET_OK ) + impl_doCopy_nothrow(); + + // do this after impl_doCopy_nothrow: The attributes may change during copying, for instance + // if the user entered an unqualified table name + impl_dialogToAttributes_nothrow( impl_getDialog_throw() ); +} + +} // namespace dbaui + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_CopyTableWizard_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::CopyTableWizard(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/dbinteraction.cxx b/dbaccess/source/ui/uno/dbinteraction.cxx new file mode 100644 index 000000000..ad7480c1a --- /dev/null +++ b/dbaccess/source/ui/uno/dbinteraction.cxx @@ -0,0 +1,387 @@ +/* -*- 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 "dbinteraction.hxx" +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <connectivity/dbexception.hxx> +#include <sqlmessage.hxx> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/task/XInteractionApprove.hpp> +#include <com/sun/star/task/XInteractionDisapprove.hpp> +#include <com/sun/star/task/XInteractionRetry.hpp> +#include <com/sun/star/task/XInteractionAbort.hpp> +#include <com/sun/star/sdb/XInteractionSupplyParameters.hpp> +#include <com/sun/star/sdb/XInteractionDocumentSave.hpp> +#include <sfx2/QuerySaveDocument.hxx> +#include <paramdialog.hxx> +#include <vcl/svapp.hxx> +#include <CollectionView.hxx> +#include <comphelper/sequenceashashmap.hxx> + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_dbaccess_DatabaseInteractionHandler_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::SQLExceptionInteractionHandler(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_dbaccess_LegacyInteractionHandler_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::LegacyInteractionHandler(context)); +} + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::ucb; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::task; + using namespace ::com::sun::star::beans; + using namespace ::dbtools; + + // BasicInteractionHandler + BasicInteractionHandler::BasicInteractionHandler( const Reference< XComponentContext >& rxContext, const bool i_bFallbackToGeneric ) + :m_xContext( rxContext ) + ,m_bFallbackToGeneric( i_bFallbackToGeneric ) + { + OSL_ENSURE( !m_bFallbackToGeneric, + "BasicInteractionHandler::BasicInteractionHandler: enabling legacy behavior, there should be no clients of this anymore!" ); + } + + void SAL_CALL BasicInteractionHandler::initialize(const Sequence<Any>& rArgs) + { + comphelper::SequenceAsHashMap aMap(rArgs); + m_xParentWindow.set(aMap.getValue("Parent"), UNO_QUERY); + } + + sal_Bool SAL_CALL BasicInteractionHandler::handleInteractionRequest( const Reference< XInteractionRequest >& i_rRequest ) + { + return impl_handle_throw( i_rRequest ); + } + + void SAL_CALL BasicInteractionHandler::handle( const Reference< XInteractionRequest >& i_rRequest ) + { + impl_handle_throw( i_rRequest ); + } + + bool BasicInteractionHandler::impl_handle_throw( const Reference< XInteractionRequest >& i_Request ) + { + Any aRequest( i_Request->getRequest() ); + OSL_ENSURE(aRequest.hasValue(), "BasicInteractionHandler::handle: invalid request!"); + if ( !aRequest.hasValue() ) + // no request -> no handling + return false; + + Sequence< Reference< XInteractionContinuation > > aContinuations( i_Request->getContinuations() ); + + // try to extract an SQLException (or one of its derived members + SQLExceptionInfo aInfo( aRequest ); + if ( aInfo.isValid() ) + { + implHandle( aInfo, aContinuations ); + return true; + } + + ParametersRequest aParamRequest; + if ( aRequest >>= aParamRequest ) + { + implHandle( aParamRequest, aContinuations ); + return true; + } + + DocumentSaveRequest aDocuRequest; + if ( aRequest >>= aDocuRequest ) + { + implHandle( aDocuRequest, aContinuations ); + return true; + } + + if ( m_bFallbackToGeneric ) + return implHandleUnknown( i_Request ); + + return false; + } + + void BasicInteractionHandler::implHandle(const ParametersRequest& _rParamRequest, const Sequence< Reference< XInteractionContinuation > >& _rContinuations) + { + SolarMutexGuard aGuard; + // want to open a dialog... + + sal_Int32 nAbortPos = getContinuation(ABORT, _rContinuations); + sal_Int32 nParamPos = getContinuation(SUPPLY_PARAMETERS, _rContinuations); + + Reference< XInteractionSupplyParameters > xParamCallback; + if (-1 != nParamPos) + xParamCallback.set(_rContinuations[nParamPos], UNO_QUERY); + OSL_ENSURE(xParamCallback.is(), "BasicInteractionHandler::implHandle(ParametersRequest): can't set the parameters without an appropriate interaction handler!s"); + + OParameterDialog aDlg(Application::GetFrameWeld(m_xParentWindow), _rParamRequest.Parameters, _rParamRequest.Connection, m_xContext); + sal_Int16 nResult = aDlg.run(); + try + { + switch (nResult) + { + case RET_OK: + if (xParamCallback.is()) + { + xParamCallback->setParameters(aDlg.getValues()); + xParamCallback->select(); + } + break; + default: + if (-1 != nAbortPos) + _rContinuations[nAbortPos]->select(); + break; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void BasicInteractionHandler::implHandle(const SQLExceptionInfo& _rSqlInfo, const Sequence< Reference< XInteractionContinuation > >& _rContinuations) + { + SolarMutexGuard aGuard; + // want to open a dialog... + + sal_Int32 nApprovePos = getContinuation(APPROVE, _rContinuations); + sal_Int32 nDisapprovePos = getContinuation(DISAPPROVE, _rContinuations); + sal_Int32 nAbortPos = getContinuation(ABORT, _rContinuations); + sal_Int32 nRetryPos = getContinuation(RETRY, _rContinuations); + + // determine the style of the dialog, dependent on the present continuation types + MessBoxStyle nDialogStyle = MessBoxStyle::NONE; + bool bHaveCancel = nAbortPos != -1; + // "approve" means "Yes", "disapprove" means "No" + // VCL only supports having both (which makes sense ...) + if ( ( nApprovePos != -1 ) || ( nDisapprovePos != -1 ) ) + nDialogStyle = ( bHaveCancel ? MessBoxStyle::YesNoCancel : MessBoxStyle::YesNo ) | MessBoxStyle::DefaultYes; + else + { + // if there's no yes/no, then use a default OK button + nDialogStyle = ( bHaveCancel ? MessBoxStyle::OkCancel : MessBoxStyle::Ok ) | MessBoxStyle::DefaultOk; + } + + // If there's a "Retry" continuation, have a "Retry" button + if ( nRetryPos != -1 ) + { + nDialogStyle = MessBoxStyle::RetryCancel | MessBoxStyle::DefaultRetry; + } + + // execute the dialog + OSQLMessageBox aDialog(nullptr, _rSqlInfo, nDialogStyle); + // TODO: need a way to specify the parent window + sal_Int16 nResult = aDialog.run(); + try + { + switch (nResult) + { + case RET_YES: + case RET_OK: + if ( nApprovePos != -1 ) + _rContinuations[ nApprovePos ]->select(); + else + OSL_ENSURE( nResult != RET_YES, "BasicInteractionHandler::implHandle: no handler for YES!" ); + break; + + case RET_NO: + if ( nDisapprovePos != -1 ) + _rContinuations[ nDisapprovePos ]->select(); + else + OSL_FAIL( "BasicInteractionHandler::implHandle: no handler for NO!" ); + break; + + case RET_CANCEL: + if ( nAbortPos != -1 ) + _rContinuations[ nAbortPos ]->select(); + else if ( nDisapprovePos != -1 ) + _rContinuations[ nDisapprovePos ]->select(); + else + OSL_FAIL( "BasicInteractionHandler::implHandle: no handler for CANCEL!" ); + break; + case RET_RETRY: + if ( nRetryPos != -1 ) + _rContinuations[ nRetryPos ]->select(); + else + OSL_FAIL( "BasicInteractionHandler::implHandle: where does the RETRY come from?" ); + break; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + void BasicInteractionHandler::implHandle(const DocumentSaveRequest& _rDocuRequest, const Sequence< Reference< XInteractionContinuation > >& _rContinuations) + { + SolarMutexGuard aGuard; + // want to open a dialog... + + sal_Int32 nApprovePos = getContinuation(APPROVE, _rContinuations); + sal_Int32 nDisApprovePos = getContinuation(DISAPPROVE, _rContinuations); + sal_Int32 nAbortPos = getContinuation(ABORT, _rContinuations); + + short nRet = RET_YES; + if ( -1 != nApprovePos ) + { + // ask whether it should be saved + nRet = ExecuteQuerySaveDocument(Application::GetFrameWeld(m_xParentWindow), _rDocuRequest.Name); + } + + if ( RET_CANCEL == nRet ) + { + if (-1 != nAbortPos) + _rContinuations[nAbortPos]->select(); + return; + } + else if ( RET_YES == nRet ) + { + sal_Int32 nDocuPos = getContinuation(SUPPLY_DOCUMENTSAVE, _rContinuations); + + if (-1 != nDocuPos) + { + Reference< XInteractionDocumentSave > xCallback(_rContinuations[nDocuPos], UNO_QUERY); + OSL_ENSURE(xCallback.is(), "BasicInteractionHandler::implHandle(DocumentSaveRequest): can't save document without an appropriate interaction handler!s"); + + OCollectionView aDlg(Application::GetFrameWeld(m_xParentWindow), _rDocuRequest.Content, _rDocuRequest.Name, m_xContext); + sal_Int16 nResult = aDlg.run(); + try + { + switch (nResult) + { + case RET_OK: + if (xCallback.is()) + { + xCallback->setName(aDlg.getName(), aDlg.getSelectedFolder()); + xCallback->select(); + } + break; + default: + if (-1 != nAbortPos) + _rContinuations[nAbortPos]->select(); + break; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + else if ( -1 != nApprovePos ) + _rContinuations[nApprovePos]->select(); + } + else if ( -1 != nDisApprovePos ) + _rContinuations[nDisApprovePos]->select(); + } + + bool BasicInteractionHandler::implHandleUnknown( const Reference< XInteractionRequest >& _rxRequest ) + { + if ( m_xContext.is() ) + { + Reference< XInteractionHandler2 > xFallbackHandler( + InteractionHandler::createWithParent(m_xContext, nullptr) ); + xFallbackHandler->handle( _rxRequest ); + return true; + } + return false; + } + + sal_Int32 BasicInteractionHandler::getContinuation(Continuation _eCont, const Sequence< Reference< XInteractionContinuation > >& _rContinuations) + { + const Reference< XInteractionContinuation >* pContinuations = _rContinuations.getConstArray(); + for (sal_Int32 i=0; i<_rContinuations.getLength(); ++i, ++pContinuations) + { + switch (_eCont) + { + case APPROVE: + if (Reference< XInteractionApprove >(*pContinuations, UNO_QUERY).is()) + return i; + break; + case DISAPPROVE: + if (Reference< XInteractionDisapprove >(*pContinuations, UNO_QUERY).is()) + return i; + break; + case RETRY: + if (Reference< XInteractionRetry >(*pContinuations, UNO_QUERY).is()) + return i; + break; + case ABORT: + if (Reference< XInteractionAbort >(*pContinuations, UNO_QUERY).is()) + return i; + break; + case SUPPLY_PARAMETERS: + if (Reference< XInteractionSupplyParameters >(*pContinuations, UNO_QUERY).is()) + return i; + break; + case SUPPLY_DOCUMENTSAVE: + if (Reference< XInteractionDocumentSave >(*pContinuations, UNO_QUERY).is()) + return i; + break; + } + } + + return -1; + } + + // SQLExceptionInteractionHandler + OUString SAL_CALL SQLExceptionInteractionHandler::getImplementationName() + { + return "com.sun.star.comp.dbaccess.DatabaseInteractionHandler"; + } + sal_Bool SAL_CALL SQLExceptionInteractionHandler::supportsService(const OUString& _rServiceName) + { + const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames()); + for (const OUString& s : aSupported) + if (s == _rServiceName) + return true; + + return false; + } + css::uno::Sequence< OUString > SAL_CALL SQLExceptionInteractionHandler::getSupportedServiceNames() + { + return { "com.sun.star.sdb.DatabaseInteractionHandler" }; + } + + // LegacyInteractionHandler + OUString SAL_CALL LegacyInteractionHandler::getImplementationName() + { + return "com.sun.star.comp.dbaccess.LegacyInteractionHandler"; + } + sal_Bool SAL_CALL LegacyInteractionHandler::supportsService(const OUString& _rServiceName) + { + const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames()); + for (const OUString& s : aSupported) + if (s == _rServiceName) + return true; + + return false; + } + css::uno::Sequence< OUString > SAL_CALL LegacyInteractionHandler::getSupportedServiceNames() + { + return { "com.sun.star.sdb.InteractionHandler" }; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/dbinteraction.hxx b/dbaccess/source/ui/uno/dbinteraction.hxx new file mode 100644 index 000000000..fdb0dbd2c --- /dev/null +++ b/dbaccess/source/ui/uno/dbinteraction.hxx @@ -0,0 +1,168 @@ +/* -*- 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 <cppuhelper/implbase.hxx> +#include <connectivity/CommonTools.hxx> + +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/task/XInteractionHandler2.hpp> +#include <com/sun/star/sdb/ParametersRequest.hpp> +#include <com/sun/star/sdb/DocumentSaveRequest.hpp> + +namespace com::sun::star::uno { class XComponentContext; } + +namespace dbtools +{ + class SQLExceptionInfo; +} + +namespace dbaui +{ + + // BasicInteractionHandler + typedef ::cppu::WeakImplHelper< css::lang::XServiceInfo + , css::lang::XInitialization + , css::task::XInteractionHandler2 + > BasicInteractionHandler_Base; + /** implements an <type scope="com.sun.star.task">XInteractionHandler</type> for + database related interaction requests. + <p/> + Supported interaction requests by now (specified by an exception: The appropriate exception + has to be returned by the getRequest method of the object implementing the + <type scope="com.sun.star.task">XInteractionRequest</type> interface. + <ul> + <li><b><type scope="com.sun.star.sdbc">SQLException</type></b>: requests to display a + standard error dialog for the (maybe chained) exception given</li> + </ul> + */ + class BasicInteractionHandler + :public BasicInteractionHandler_Base + { + css::uno::Reference< css::awt::XWindow > m_xParentWindow; + const css::uno::Reference< css::uno::XComponentContext > + m_xContext; + const bool m_bFallbackToGeneric; + + public: + BasicInteractionHandler( + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const bool i_bFallbackToGeneric + ); + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& rArgs ) override; + + // XInteractionHandler2 + virtual sal_Bool SAL_CALL handleInteractionRequest( const css::uno::Reference< css::task::XInteractionRequest >& Request ) override; + + // XInteractionHandler + virtual void SAL_CALL handle( const css::uno::Reference< css::task::XInteractionRequest >& Request ) override; + + protected: + bool + impl_handle_throw( const css::uno::Reference< css::task::XInteractionRequest >& i_Request ); + + /// handle SQLExceptions (and derived classes) + static void implHandle( + const ::dbtools::SQLExceptionInfo& _rSqlInfo, + const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > >& _rContinuations); + + /// handle parameter requests + void implHandle( + const css::sdb::ParametersRequest& _rParamRequest, + const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > >& _rContinuations); + + /// handle document save requests + void implHandle( + const css::sdb::DocumentSaveRequest& _rParamRequest, + const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > >& _rContinuations); + + /// handles requests which are not SDB-specific + bool implHandleUnknown( + const css::uno::Reference< css::task::XInteractionRequest >& _rxRequest ); + + /// known continuation types + enum Continuation + { + APPROVE, + DISAPPROVE, + RETRY, + ABORT, + SUPPLY_PARAMETERS, + SUPPLY_DOCUMENTSAVE + }; + /** check if a given continuation sequence contains a given continuation type<p/> + @return the index within <arg>_rContinuations</arg> of the first occurrence of a continuation + of the requested type, -1 of no such continuation exists + */ + static sal_Int32 getContinuation( + Continuation _eCont, + const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > >& _rContinuations); + }; + + // SQLExceptionInteractionHandler + class SQLExceptionInteractionHandler : public BasicInteractionHandler + { + public: + explicit SQLExceptionInteractionHandler( + const css::uno::Reference< css::uno::XComponentContext >& rxContext + ) + :BasicInteractionHandler( rxContext, false ) + { + } + + // XServiceInfo + DECLARE_SERVICE_INFO(); + }; + + // SQLExceptionInteractionHandler + /** an implementation for the legacy css.sdb.InteractionHandler + + css.sdb.InteractionHandler is deprecated, as it does not only handle database related interactions, + but also delegates all kind of unknown requests to a css.task.InteractionHandler. + + In today's architecture, there's only one central css.task.InteractionHandler, which is to be used + for all requests. Depending on configuration information, it decides which handler implementation + to delegate a request to. + + SQLExceptionInteractionHandler is the delegatee which handles only database related interactions. + LegacyInteractionHandler is the version which first checks for a database related interaction, and + forwards everything else to the css.task.InteractionHandler. + */ + class LegacyInteractionHandler : public BasicInteractionHandler + { + public: + explicit LegacyInteractionHandler( + const css::uno::Reference< css::uno::XComponentContext >& rxContext + ) + :BasicInteractionHandler( rxContext, true ) + { + } + + // XServiceInfo + DECLARE_SERVICE_INFO(); + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/textconnectionsettings_uno.cxx b/dbaccess/source/ui/uno/textconnectionsettings_uno.cxx new file mode 100644 index 000000000..5b1636f90 --- /dev/null +++ b/dbaccess/source/ui/uno/textconnectionsettings_uno.cxx @@ -0,0 +1,268 @@ +/* -*- 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 <textconnectionsettings.hxx> +#include <unoadmin.hxx> +#include <stringconstants.hxx> +#include <propertystorage.hxx> + +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdb/XTextConnectionSettings.hpp> + +#include <comphelper/proparrhlp.hxx> +#include <connectivity/CommonTools.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/svapp.hxx> +#include <cppuhelper/implbase.hxx> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::beans::XPropertySetInfo; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::beans::Property; + + namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute; + + // OTextConnectionSettingsDialog + + namespace { + + class OTextConnectionSettingsDialog; + + } + + typedef ::cppu::ImplInheritanceHelper< ODatabaseAdministrationDialog + , css::sdb::XTextConnectionSettings + > OTextConnectionSettingsDialog_BASE; + typedef ::comphelper::OPropertyArrayUsageHelper< OTextConnectionSettingsDialog > OTextConnectionSettingsDialog_PBASE; + + namespace { + + class OTextConnectionSettingsDialog + :public OTextConnectionSettingsDialog_BASE + ,public OTextConnectionSettingsDialog_PBASE + { + PropertyValues m_aPropertyValues; + + public: + explicit OTextConnectionSettingsDialog( const Reference<XComponentContext>& _rContext ); + + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override; + + DECLARE_SERVICE_INFO(); + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) override; + virtual sal_Bool SAL_CALL convertFastPropertyValue( Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue) override; + virtual void SAL_CALL getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const override; + + // Overrides to resolve inheritance ambiguity + virtual void SAL_CALL setPropertyValue(const OUString& p1, const css::uno::Any& p2) override + { ODatabaseAdministrationDialog::setPropertyValue(p1, p2); } + virtual css::uno::Any SAL_CALL getPropertyValue(const OUString& p1) override + { return ODatabaseAdministrationDialog::getPropertyValue(p1); } + virtual void SAL_CALL addPropertyChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XPropertyChangeListener>& p2) override + { ODatabaseAdministrationDialog::addPropertyChangeListener(p1, p2); } + virtual void SAL_CALL removePropertyChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XPropertyChangeListener>& p2) override + { ODatabaseAdministrationDialog::removePropertyChangeListener(p1, p2); } + virtual void SAL_CALL addVetoableChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XVetoableChangeListener>& p2) override + { ODatabaseAdministrationDialog::addVetoableChangeListener(p1, p2); } + virtual void SAL_CALL removeVetoableChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XVetoableChangeListener>& p2) override + { ODatabaseAdministrationDialog::removeVetoableChangeListener(p1, p2); } + virtual void SAL_CALL setTitle(const OUString& p1) override + { ODatabaseAdministrationDialog::setTitle(p1); } + virtual sal_Int16 SAL_CALL execute() override + { return ODatabaseAdministrationDialog::execute(); } + + protected: + // OGenericUnoDialog overridables + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; + using OTextConnectionSettingsDialog_BASE::getFastPropertyValue; + }; + + } + + // OTextConnectionSettingsDialog + OTextConnectionSettingsDialog::OTextConnectionSettingsDialog( const Reference<XComponentContext>& _rContext ) + :OTextConnectionSettingsDialog_BASE( _rContext ) + { + TextConnectionSettingsDialog::bindItemStorages( *m_pDatasourceItems, m_aPropertyValues ); + } + + css::uno::Sequence<sal_Int8> + OTextConnectionSettingsDialog::getImplementationId() + { + return css::uno::Sequence<sal_Int8>(); + } + + OUString SAL_CALL OTextConnectionSettingsDialog::getImplementationName() + { + return "com.sun.star.comp.dbaccess.OTextConnectionSettingsDialog"; + } + sal_Bool SAL_CALL OTextConnectionSettingsDialog::supportsService(const OUString& _rServiceName) + { + const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames()); + for (const OUString& s : aSupported) + if (s == _rServiceName) + return true; + + return false; + } + css::uno::Sequence< OUString > SAL_CALL OTextConnectionSettingsDialog::getSupportedServiceNames() + { + return { "com.sun.star.sdb.TextConnectionSettings" }; + } + + Reference< XPropertySetInfo > SAL_CALL OTextConnectionSettingsDialog::getPropertySetInfo() + { + return createPropertySetInfo( getInfoHelper() ); + } + + ::cppu::IPropertyArrayHelper& OTextConnectionSettingsDialog::getInfoHelper() + { + return *getArrayHelper(); + } + + ::cppu::IPropertyArrayHelper* OTextConnectionSettingsDialog::createArrayHelper( ) const + { + Sequence< Property > aProps; + describeProperties( aProps ); + + // in addition to the properties registered by the base class, we have + // more properties which are not even handled by the PropertyContainer implementation, + // but whose values are stored in our item set + sal_Int32 nProp = aProps.getLength(); + aProps.realloc( nProp + 6 ); + auto pProps = aProps.getArray(); + + pProps[ nProp++ ] = Property( + "HeaderLine", + PROPERTY_ID_HEADER_LINE, + ::cppu::UnoType< sal_Bool >::get(), + PropertyAttribute::TRANSIENT + ); + + pProps[ nProp++ ] = Property( + "FieldDelimiter", + PROPERTY_ID_FIELD_DELIMITER, + ::cppu::UnoType< OUString >::get(), + PropertyAttribute::TRANSIENT + ); + + pProps[ nProp++ ] = Property( + "StringDelimiter", + PROPERTY_ID_STRING_DELIMITER, + ::cppu::UnoType< OUString >::get(), + PropertyAttribute::TRANSIENT + ); + + pProps[ nProp++ ] = Property( + "DecimalDelimiter", + PROPERTY_ID_DECIMAL_DELIMITER, + ::cppu::UnoType< OUString >::get(), + PropertyAttribute::TRANSIENT + ); + + pProps[ nProp++ ] = Property( + "ThousandDelimiter", + PROPERTY_ID_THOUSAND_DELIMITER, + ::cppu::UnoType< OUString >::get(), + PropertyAttribute::TRANSIENT + ); + + pProps[ nProp++ ] = Property( + "CharSet", + PROPERTY_ID_ENCODING, + ::cppu::UnoType< OUString >::get(), + PropertyAttribute::TRANSIENT + ); + + return new ::cppu::OPropertyArrayHelper( aProps ); + } + + std::unique_ptr<weld::DialogController> OTextConnectionSettingsDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) + { + return std::make_unique<TextConnectionSettingsDialog>(Application::GetFrameWeld(rParent), *m_pDatasourceItems); + } + + void SAL_CALL OTextConnectionSettingsDialog::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) + { + PropertyValues::const_iterator pos = m_aPropertyValues.find( _nHandle ); + if ( pos != m_aPropertyValues.end() ) + { + pos->second->setPropertyValue( _rValue ); + } + else + { + OTextConnectionSettingsDialog::setFastPropertyValue_NoBroadcast( _nHandle, _rValue ); + } + } + + sal_Bool SAL_CALL OTextConnectionSettingsDialog::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue) + { + bool bModified = false; + + PropertyValues::const_iterator pos = m_aPropertyValues.find( _nHandle ); + if ( pos != m_aPropertyValues.end() ) + { + // we're lazy here ... + _rConvertedValue = _rValue; + pos->second->getPropertyValue( _rOldValue ); + bModified = true; + } + else + { + bModified = OTextConnectionSettingsDialog::convertFastPropertyValue( _rConvertedValue, _rOldValue, _nHandle, _rValue ); + } + + return bModified; + } + + void SAL_CALL OTextConnectionSettingsDialog::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const + { + PropertyValues::const_iterator pos = m_aPropertyValues.find( _nHandle ); + if ( pos != m_aPropertyValues.end() ) + { + pos->second->getPropertyValue( _rValue ); + } + else + { + OTextConnectionSettingsDialog::getFastPropertyValue( _rValue, _nHandle ); + } + } + +} // namespace dbaui + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_dbaccess_OTextConnectionSettingsDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(static_cast<dbaui::ODatabaseAdministrationDialog*>(new ::dbaui::OTextConnectionSettingsDialog(context))); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/unoDirectSql.cxx b/dbaccess/source/ui/uno/unoDirectSql.cxx new file mode 100644 index 000000000..7b3a4cc6c --- /dev/null +++ b/dbaccess/source/ui/uno/unoDirectSql.cxx @@ -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 . + */ + +#include <sal/config.h> + +#include "unoDirectSql.hxx" +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/connection/XConnection.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <directsql.hxx> +#include <datasourceconnector.hxx> +#include <strings.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_sdb_DirectSQLDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::ODirectSQLDialog(context)); +} + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::sdbcx; + using namespace ::com::sun::star::sdbc; + + // ODirectSQLDialog + ODirectSQLDialog::ODirectSQLDialog(const Reference< XComponentContext >& _rxORB) + :ODirectSQLDialog_BASE( _rxORB ) + { + + } + + ODirectSQLDialog::~ODirectSQLDialog() + { + + } + + css::uno::Sequence<sal_Int8> ODirectSQLDialog::getImplementationId() + { + return css::uno::Sequence<sal_Int8>(); + } + + OUString SAL_CALL ODirectSQLDialog::getImplementationName() + { + return "com.sun.star.comp.sdb.DirectSQLDialog"; + } + sal_Bool SAL_CALL ODirectSQLDialog::supportsService(const OUString& _rServiceName) + { + const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames()); + for (const OUString& s : aSupported) + if (s == _rServiceName) + return true; + + return false; + } + css::uno::Sequence< OUString > SAL_CALL ODirectSQLDialog::getSupportedServiceNames( ) + { + return { SERVICE_SDB_DIRECTSQLDIALOG }; + } + + css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL ODirectSQLDialog::getPropertySetInfo() + { + Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + ::cppu::IPropertyArrayHelper& ODirectSQLDialog::getInfoHelper() + { + return *ODirectSQLDialog::getArrayHelper(); + } + ::cppu::IPropertyArrayHelper* ODirectSQLDialog::createArrayHelper( ) const + { + css::uno::Sequence< css::beans::Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); + } + + + std::unique_ptr<weld::DialogController> ODirectSQLDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) + { + // obtain all the objects needed for the dialog + Reference< XConnection > xConnection = m_xActiveConnection; + weld::Window* pParent = Application::GetFrameWeld(rParent); + if ( !xConnection.is() ) + { + try + { + // the connection the row set is working with + ODatasourceConnector aDSConnector(m_aContext, pParent); + xConnection = aDSConnector.connect( m_sInitialSelection, nullptr ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + if (!xConnection.is()) + { + // can't create the dialog if I have improper settings + return nullptr; + } + + return std::make_unique<DirectSQLDialog>(pParent, xConnection); + } + + void ODirectSQLDialog::implInitialize(const Any& _rValue) + { + PropertyValue aProperty; + if (_rValue >>= aProperty) + { + if (aProperty.Name == "InitialSelection") + { + OSL_VERIFY( aProperty.Value >>= m_sInitialSelection ); + return; + } + else if (aProperty.Name == "ActiveConnection") + { + m_xActiveConnection.set( aProperty.Value, UNO_QUERY ); + OSL_ENSURE( m_xActiveConnection.is(), "ODirectSQLDialog::implInitialize: invalid connection!" ); + return; + } + } + ODirectSQLDialog_BASE::implInitialize(_rValue); + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/unoDirectSql.hxx b/dbaccess/source/ui/uno/unoDirectSql.hxx new file mode 100644 index 000000000..c83f975d6 --- /dev/null +++ b/dbaccess/source/ui/uno/unoDirectSql.hxx @@ -0,0 +1,61 @@ +/* -*- 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 <com/sun/star/sdbc/XConnection.hpp> +#include <comphelper/proparrhlp.hxx> +#include <connectivity/CommonTools.hxx> + +namespace dbaui +{ + + // ODirectSQLDialog + class ODirectSQLDialog; + typedef ::svt::OGenericUnoDialog ODirectSQLDialog_BASE; + typedef ::comphelper::OPropertyArrayUsageHelper< ODirectSQLDialog > ODirectSQLDialog_PBASE; + + class ODirectSQLDialog + :public ODirectSQLDialog_BASE + ,public ODirectSQLDialog_PBASE + { + OUString m_sInitialSelection; + css::uno::Reference< css::sdbc::XConnection > m_xActiveConnection; + public: + explicit ODirectSQLDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + virtual ~ODirectSQLDialog() override; + + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override; + + DECLARE_SERVICE_INFO(); + + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + + protected: + // OGenericUnoDialog overridables + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; + virtual void implInitialize(const css::uno::Any& _rValue) override; + }; + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/unoadmin.cxx b/dbaccess/source/ui/uno/unoadmin.cxx new file mode 100644 index 000000000..3d863b92e --- /dev/null +++ b/dbaccess/source/ui/uno/unoadmin.cxx @@ -0,0 +1,71 @@ +/* -*- 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 <unoadmin.hxx> +#include <dbadmin.hxx> + +#include <osl/mutex.hxx> + + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + +ODatabaseAdministrationDialog::ODatabaseAdministrationDialog(const Reference< XComponentContext >& _rxORB) + :ODatabaseAdministrationDialogBase(_rxORB) + ,m_pItemPoolDefaults(nullptr) +{ + m_pCollection.reset( new ::dbaccess::ODsnTypeCollection(_rxORB) ); + ODbAdminDialog::createItemSet(m_pDatasourceItems, m_pItemPool, m_pItemPoolDefaults, m_pCollection.get()); +} + +ODatabaseAdministrationDialog::~ODatabaseAdministrationDialog() +{ + ::osl::MutexGuard aGuard(m_aMutex); + if (m_xDialog) + destroyDialog(); + ODbAdminDialog::destroyItemSet(m_pDatasourceItems, m_pItemPool, m_pItemPoolDefaults); +} + +void ODatabaseAdministrationDialog::implInitialize(const Any& _rValue) +{ + PropertyValue aProperty; + if (_rValue >>= aProperty) + { + if (aProperty.Name == "InitialSelection") + { + m_aInitialSelection = aProperty.Value; + } + else if (aProperty.Name == "ActiveConnection") + { + m_xActiveConnection.set(aProperty.Value,UNO_QUERY); + } + else + ODatabaseAdministrationDialogBase::implInitialize(_rValue); + } + else + ODatabaseAdministrationDialogBase::implInitialize(_rValue); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/unosqlmessage.cxx b/dbaccess/source/ui/uno/unosqlmessage.cxx new file mode 100644 index 000000000..39364ba25 --- /dev/null +++ b/dbaccess/source/ui/uno/unosqlmessage.cxx @@ -0,0 +1,144 @@ +/* -*- 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 <sqlmessage.hxx> +#include <unosqlmessage.hxx> +#include <stringconstants.hxx> +#include <strings.hxx> +#include <comphelper/propertysequence.hxx> +#include <connectivity/dbexception.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +using namespace dbaui; +using namespace dbtools; + +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_OSQLMessageDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new OSQLMessageDialog(context)); +} + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + +OSQLMessageDialog::OSQLMessageDialog(const Reference< XComponentContext >& _rxORB) + :OSQLMessageDialogBase(_rxORB) +{ + registerMayBeVoidProperty(PROPERTY_SQLEXCEPTION, PROPERTY_ID_SQLEXCEPTION, PropertyAttribute::TRANSIENT | PropertyAttribute::MAYBEVOID, + &m_aException, ::cppu::UnoType<SQLException>::get()); + registerProperty( PROPERTY_HELP_URL, PROPERTY_ID_HELP_URL, PropertyAttribute::TRANSIENT, + &m_sHelpURL, cppu::UnoType<decltype(m_sHelpURL)>::get() ); +} + +Sequence<sal_Int8> SAL_CALL OSQLMessageDialog::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +OUString SAL_CALL OSQLMessageDialog::getImplementationName() +{ + return "org.openoffice.comp.dbu.OSQLMessageDialog"; +} + +css::uno::Sequence<OUString> SAL_CALL OSQLMessageDialog::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.ErrorMessageDialog" }; +} + +void OSQLMessageDialog::initialize(Sequence<Any> const & args) +{ + OUString title; + Reference< css::awt::XWindow > parentWindow; + + if ((args.getLength() == 3) && (args[0] >>= title) && (args[1] >>= parentWindow)) { + Sequence<Any> s(comphelper::InitAnyPropertySequence( + { + {"Title", Any(title)}, + {"ParentWindow", Any(parentWindow)}, + {"SQLException", args[2]} + })); + OGenericUnoDialog::initialize(s); + } else { + OGenericUnoDialog::initialize(args); + } +} + +sal_Bool SAL_CALL OSQLMessageDialog::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue) +{ + switch (_nHandle) + { + case PROPERTY_ID_SQLEXCEPTION: + { + SQLExceptionInfo aInfo(_rValue); + if (!aInfo.isValid()) + throw IllegalArgumentException(); + + _rOldValue = m_aException; + _rConvertedValue = aInfo.get(); + + return true; + // always assume "modified", don't bother with comparing the two values + } + default: + return OSQLMessageDialogBase::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue); + } +} + +Reference<XPropertySetInfo> SAL_CALL OSQLMessageDialog::getPropertySetInfo() +{ + Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +::cppu::IPropertyArrayHelper& OSQLMessageDialog::getInfoHelper() +{ + return *getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* OSQLMessageDialog::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +std::unique_ptr<weld::DialogController> OSQLMessageDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) +{ + weld::Window* pParent = Application::GetFrameWeld(rParent); + if ( m_aException.hasValue() ) + return std::make_unique<OSQLMessageBox>(pParent, SQLExceptionInfo(m_aException), MessBoxStyle::Ok | MessBoxStyle::DefaultOk, m_sHelpURL); + + OSL_FAIL("OSQLMessageDialog::createDialog : You should use the SQLException property to specify the error to display!"); + return std::make_unique<OSQLMessageBox>(pParent, SQLException()); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |