/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* org_openoffice_comp_dbu_OQueryDesign_get_implementation( css::uno::XComponentContext* context, css::uno::Sequence 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 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 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::get() ); registerProperty( PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::READONLY | PropertyAttribute::BOUND, &m_bEscapeProcessing, cppu::UnoType::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(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 ) { assert(m_pSqlIterator && "SqlIterator must exist"); 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 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::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 pField( new OTableFieldDesc()); pField->Load( m_aFieldInformation[ _nColPos ], false ); return pField->GetColWidth(); } return 0; } Reference 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(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& _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 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( OUString sComment, bool bLastOnLine ) : maComment(std::move( sComment)), 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 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() ); } 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: */