1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <browserids.hxx>
21 #include <core_resource.hxx>
22 #include <strings.hrc>
23 #include <strings.hxx>
25 #include <stringconstants.hxx>
26 #include <defaultobjectnamecheck.hxx>
27 #include <dlgsave.hxx>
28 #include <querycontainerwindow.hxx>
29 #include <querycontroller.hxx>
30 #include <QueryDesignView.hxx>
31 #include <QueryTableView.hxx>
32 #include <sqlmessage.hxx>
33 #include <TableConnectionData.hxx>
34 #include <TableFieldDescription.hxx>
35 #include <UITools.hxx>
36 #include <QueryPropertiesDialog.hxx>
38 #include <com/sun/star/beans/PropertyAttribute.hpp>
39 #include <com/sun/star/container/XNameContainer.hpp>
40 #include <com/sun/star/frame/FrameSearchFlag.hpp>
41 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
42 #include <com/sun/star/sdb/CommandType.hpp>
43 #include <com/sun/star/sdb/SQLContext.hpp>
44 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
45 #include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
46 #include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
47 #include <com/sun/star/sdbcx/XAppend.hpp>
48 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
49 #include <com/sun/star/sdbcx/XDrop.hpp>
50 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
51 #include <com/sun/star/sdbcx/XViewsSupplier.hpp>
52 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
53 #include <com/sun/star/util/XCloseable.hpp>
54 #include <com/sun/star/util/VetoException.hpp>
55 #include <com/sun/star/ui/XUIElement.hpp>
57 #include <comphelper/propertysequence.hxx>
58 #include <comphelper/property.hxx>
59 #include <comphelper/types.hxx>
60 #include <connectivity/dbexception.hxx>
61 #include <connectivity/dbtools.hxx>
62 #include <cppuhelper/exc_hlp.hxx>
63 #include <svl/undo.hxx>
64 #include <toolkit/helper/vclunohelper.hxx>
65 #include <comphelper/diagnose_ex.hxx>
66 #include <osl/diagnose.h>
68 #include <vcl/stdtext.hxx>
69 #include <vcl/svapp.hxx>
70 #include <vcl/weld.hxx>
71 #include <osl/mutex.hxx>
72 #include <o3tl/string_view.hxx>
76 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
77 org_openoffice_comp_dbu_OQueryDesign_get_implementation(
78 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const& )
80 return cppu::acquire(new ::dbaui::OQueryController(context
));
85 using namespace ::com::sun::star::uno
;
86 using namespace ::com::sun::star::beans
;
87 using namespace ::com::sun::star::frame
;
88 using namespace ::com::sun::star::util
;
89 using namespace ::com::sun::star::lang
;
93 class OViewController
: public OQueryController
95 virtual OUString SAL_CALL
getImplementationName() override
97 return "org.openoffice.comp.dbu.OViewDesign";
99 virtual Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
101 return { "com.sun.star.sdb.ViewDesign" };
105 explicit OViewController(const Reference
< XComponentContext
>& _rM
) : OQueryController(_rM
){}
111 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
112 org_openoffice_comp_dbu_OViewDesign_get_implementation(
113 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const& )
115 return cppu::acquire(new ::dbaui::OViewController(context
));
120 using namespace ::connectivity
;
124 OUString
lcl_getObjectResourceString(TranslateId pResId
, sal_Int32 _nCommandType
)
126 OUString sMessageText
= DBA_RES(pResId
);
127 OUString sObjectType
= DBA_RES(RSC_QUERY_OBJECT_TYPE
[_nCommandType
]);
128 sMessageText
= sMessageText
.replaceFirst( "$object$", sObjectType
);
133 using namespace ::com::sun::star::io
;
134 using namespace ::com::sun::star::container
;
135 using namespace ::com::sun::star::sdbcx
;
136 using namespace ::com::sun::star::sdbc
;
137 using namespace ::com::sun::star::sdb
;
138 using namespace ::com::sun::star::ui
;
139 using namespace ::com::sun::star::ui::dialogs
;
140 using namespace ::com::sun::star::awt
;
141 using namespace ::dbtools
;
143 using namespace ::comphelper
;
147 void ensureToolbars( OQueryController
& _rController
, bool _bDesign
)
149 Reference
< css::frame::XLayoutManager
> xLayoutManager
= OGenericUnoController::getLayoutManager( _rController
.getFrame() );
150 if ( !xLayoutManager
.is() )
153 xLayoutManager
->lock();
154 static constexpr OUStringLiteral s_sDesignToolbar
= u
"private:resource/toolbar/designobjectbar";
155 static constexpr OUStringLiteral s_sSqlToolbar
= u
"private:resource/toolbar/sqlobjectbar";
158 xLayoutManager
->destroyElement( s_sSqlToolbar
);
159 xLayoutManager
->createElement( s_sDesignToolbar
);
163 xLayoutManager
->destroyElement( s_sDesignToolbar
);
164 xLayoutManager
->createElement( s_sSqlToolbar
);
166 xLayoutManager
->unlock();
167 xLayoutManager
->doLayout();
171 * The value of m_nLimit is updated when LimitBox loses its focus
172 * So in those case when execution needs recent data, grab the focus
173 * (e.g. execute SQL statement, change views)
175 void grabFocusFromLimitBox( OQueryController
& _rController
)
177 Reference
< XLayoutManager
> xLayoutManager
= OGenericUnoController::getLayoutManager( _rController
.getFrame() );
178 Reference
< XUIElement
> xUIElement
= xLayoutManager
->getElement("private:resource/toolbar/designobjectbar");
181 Reference
< XWindow
> xWindow(xUIElement
->getRealInterface(), css::uno::UNO_QUERY
);
182 VclPtr
<vcl::Window
> pWindow
= VCLUnoHelper::GetWindow( xWindow
);
183 if( pWindow
&& pWindow
->HasChildPathFocus() )
185 pWindow
->GrabFocusToDocument();
191 OUString SAL_CALL
OQueryController::getImplementationName()
193 return "org.openoffice.comp.dbu.OQueryDesign";
196 Sequence
< OUString
> SAL_CALL
OQueryController::getSupportedServiceNames()
198 return { "com.sun.star.sdb.QueryDesign" };
201 OQueryController::OQueryController(const Reference
< XComponentContext
>& _rM
)
202 :OJoinController(_rM
)
203 ,OQueryController_PBase( getBroadcastHelper() )
204 ,m_pParseContext( new svxform::OSystemParseContext
)
205 ,m_aSqlParser( _rM
, m_pParseContext
.get() )
207 ,m_nVisibleRows(0x400)
209 ,m_nCommandType( CommandType::QUERY
)
210 ,m_bGraphicalDesign(false)
212 ,m_bEscapeProcessing(true)
216 registerProperty( PROPERTY_ACTIVECOMMAND
, PROPERTY_ID_ACTIVECOMMAND
, PropertyAttribute::READONLY
| PropertyAttribute::BOUND
,
217 &m_sStatement
, cppu::UnoType
<decltype(m_sStatement
)>::get() );
218 registerProperty( PROPERTY_ESCAPE_PROCESSING
, PROPERTY_ID_ESCAPE_PROCESSING
, PropertyAttribute::READONLY
| PropertyAttribute::BOUND
,
219 &m_bEscapeProcessing
, cppu::UnoType
<decltype(m_bEscapeProcessing
)>::get() );
222 OQueryController::~OQueryController()
224 if ( !getBroadcastHelper().bDisposed
&& !getBroadcastHelper().bInDispose
)
226 OSL_FAIL("Please check who doesn't dispose this component!");
227 // increment ref count to prevent double call of Dtor
228 osl_atomic_increment( &m_refCount
);
233 IMPLEMENT_FORWARD_XINTERFACE2( OQueryController
, OJoinController
, OQueryController_PBase
)
234 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OQueryController
, OJoinController
, OQueryController_PBase
)
236 Reference
< XPropertySetInfo
> SAL_CALL
OQueryController::getPropertySetInfo()
238 Reference
< XPropertySetInfo
> xInfo( createPropertySetInfo( getInfoHelper() ) );
242 void SAL_CALL
OQueryController::getFastPropertyValue( Any
& o_rValue
, sal_Int32 i_nHandle
) const
246 case PROPERTY_ID_CURRENT_QUERY_DESIGN
:
248 ::comphelper::NamedValueCollection aCurrentDesign
;
249 aCurrentDesign
.put( "GraphicalDesign", isGraphicalDesign() );
250 aCurrentDesign
.put( PROPERTY_ESCAPE_PROCESSING
, m_bEscapeProcessing
);
252 if ( isGraphicalDesign() )
254 getContainer()->SaveUIConfig();
255 saveViewSettings( aCurrentDesign
, true );
256 aCurrentDesign
.put( "Statement", m_sStatement
);
260 aCurrentDesign
.put( "Statement", getContainer()->getStatement() );
263 o_rValue
<<= aCurrentDesign
.getPropertyValues();
268 OPropertyContainer::getFastPropertyValue( o_rValue
, i_nHandle
);
273 ::cppu::IPropertyArrayHelper
& OQueryController::getInfoHelper()
275 return *getArrayHelper();
278 ::cppu::IPropertyArrayHelper
* OQueryController::createArrayHelper( ) const
280 Sequence
< Property
> aProps
;
281 describeProperties( aProps
);
283 // one additional property:
284 const sal_Int32 nLength
= aProps
.getLength();
285 aProps
.realloc( nLength
+ 1 );
286 auto pProps
= aProps
.getArray();
287 pProps
[ nLength
] = Property(
288 "CurrentQueryDesign",
289 PROPERTY_ID_CURRENT_QUERY_DESIGN
,
290 ::cppu::UnoType
< Sequence
< PropertyValue
> >::get(),
291 PropertyAttribute::READONLY
296 pProps
+ aProps
.getLength(),
297 ::comphelper::PropertyCompareByName()
300 return new ::cppu::OPropertyArrayHelper(aProps
);
303 void OQueryController::deleteIterator()
307 delete m_pSqlIterator
->getParseTree();
308 m_pSqlIterator
->dispose();
309 m_pSqlIterator
.reset();
313 void OQueryController::disposing()
315 OQueryController_PBase::disposing();
319 m_pParseContext
.reset();
322 OTableFields().swap(m_vUnUsedFieldsDesc
);
324 ::comphelper::disposeComponent(m_xComposer
);
325 OJoinController::disposing();
326 OQueryController_PBase::disposing();
329 void OQueryController::clearFields()
331 OTableFields().swap(m_vTableFieldDesc
);
334 FeatureState
OQueryController::GetState(sal_uInt16 _nId
) const
336 FeatureState aReturn
;
337 aReturn
.bEnabled
= true;
338 // (disabled automatically)
342 case ID_BROWSER_EDITDOC
:
343 if ( editingCommand() )
344 aReturn
.bEnabled
= false;
345 else if ( editingView() && !m_xAlterView
.is() )
346 aReturn
.bEnabled
= false;
348 aReturn
= OJoinController::GetState( _nId
);
351 case ID_BROWSER_ESCAPEPROCESSING
:
352 aReturn
.bChecked
= !m_bEscapeProcessing
;
353 aReturn
.bEnabled
= ( m_pSqlIterator
!= nullptr ) && !m_bGraphicalDesign
;
355 case SID_RELATION_ADD_RELATION
:
356 aReturn
.bEnabled
= isEditable() && m_bGraphicalDesign
&& m_vTableData
.size() > 1;
358 case ID_BROWSER_SAVEASDOC
:
359 aReturn
.bEnabled
= !editingCommand() && (!m_bGraphicalDesign
|| !(m_vTableFieldDesc
.empty() || m_vTableData
.empty()));
361 case ID_BROWSER_SAVEDOC
:
362 aReturn
.bEnabled
= isEditable() && (!m_bGraphicalDesign
|| !(m_vTableFieldDesc
.empty() || m_vTableData
.empty()));
364 case SID_PRINTDOCDIRECT
:
367 aReturn
.bEnabled
= isEditable() && getContainer() && getContainer()->isCutAllowed();
369 case ID_BROWSER_COPY
:
370 aReturn
.bEnabled
= getContainer() && getContainer()->isCopyAllowed();
372 case ID_BROWSER_PASTE
:
373 aReturn
.bEnabled
= isEditable() && getContainer() && getContainer()->isPasteAllowed();
376 aReturn
.bEnabled
= m_bEscapeProcessing
&& m_pSqlIterator
;
377 aReturn
.bChecked
= m_bGraphicalDesign
;
379 case SID_BROWSER_CLEAR_QUERY
:
380 aReturn
.bEnabled
= isEditable() && (!m_sStatement
.isEmpty() || !m_vTableData
.empty());
382 case SID_QUERY_VIEW_FUNCTIONS
:
383 case SID_QUERY_VIEW_TABLES
:
384 case SID_QUERY_VIEW_ALIASES
:
385 aReturn
.bChecked
= getContainer() && getContainer()->isSlotEnabled(_nId
);
386 aReturn
.bEnabled
= m_bGraphicalDesign
;
388 case SID_QUERY_DISTINCT_VALUES
:
389 aReturn
.bEnabled
= m_bGraphicalDesign
&& isEditable();
390 aReturn
.bChecked
= m_bDistinct
;
392 case SID_QUERY_LIMIT
:
393 aReturn
.bEnabled
= m_bGraphicalDesign
;
394 if( aReturn
.bEnabled
)
395 aReturn
.aValue
<<= m_nLimit
;
397 case SID_QUERY_PROP_DLG
:
398 aReturn
.bEnabled
= m_bGraphicalDesign
;
400 case ID_BROWSER_QUERY_EXECUTE
:
401 aReturn
.bEnabled
= true;
403 case SID_DB_QUERY_PREVIEW
:
404 aReturn
.bEnabled
= true;
405 aReturn
.bChecked
= getContainer() && getContainer()->getPreviewFrame().is();
407 #if OSL_DEBUG_LEVEL > 0
408 case ID_EDIT_QUERY_SQL
:
410 case ID_EDIT_QUERY_DESIGN
:
413 case ID_BROWSER_ADDTABLE
:
414 if ( !m_bGraphicalDesign
)
416 aReturn
.bEnabled
= false;
421 aReturn
= OJoinController::GetState(_nId
);
427 void OQueryController::Execute(sal_uInt16 _nId
, const Sequence
< PropertyValue
>& aArgs
)
431 case ID_BROWSER_ESCAPEPROCESSING
:
432 setEscapeProcessing_fireEvent( !m_bEscapeProcessing
);
433 if ( !editingView() )
435 InvalidateFeature(ID_BROWSER_SQL
);
437 case ID_BROWSER_SAVEASDOC
:
438 case ID_BROWSER_SAVEDOC
:
439 grabFocusFromLimitBox(*this);
440 doSaveAsDoc(ID_BROWSER_SAVEASDOC
== _nId
);
442 case SID_RELATION_ADD_RELATION
:
444 OJoinDesignView
* pView
= getJoinView();
446 static_cast<OQueryTableView
*>(pView
->getTableView())->createNewConnection();
449 case SID_PRINTDOCDIRECT
:
452 getContainer()->cut();
454 case ID_BROWSER_COPY
:
455 getContainer()->copy();
457 case ID_BROWSER_PASTE
:
458 getContainer()->paste();
462 grabFocusFromLimitBox(*this);
463 if ( !getContainer()->checkStatement() )
465 SQLExceptionInfo aError
;
468 setStatement_fireEvent( getContainer()->getStatement() );
469 if(m_sStatement
.isEmpty() && m_pSqlIterator
)
471 // change the view of the data
472 delete m_pSqlIterator
->getParseTree();
473 m_pSqlIterator
->setParseTree(nullptr);
474 m_bGraphicalDesign
= !m_bGraphicalDesign
;
475 impl_setViewMode( &aError
);
480 std::unique_ptr
<::connectivity::OSQLParseNode
> pNode
= m_aSqlParser
.parseTree(aErrorMsg
,m_sStatement
,m_bGraphicalDesign
);
483 assert(m_pSqlIterator
&& "SqlIterator must exist");
484 delete m_pSqlIterator
->getParseTree();
485 m_pSqlIterator
->setParseTree(pNode
.release());
486 m_pSqlIterator
->traverseAll();
488 if ( m_pSqlIterator
->hasErrors() )
490 aError
= m_pSqlIterator
->getErrors();
494 const OSQLTables
& rTabs
= m_pSqlIterator
->getTables();
495 if ( m_pSqlIterator
->getStatementType() != OSQLStatementType::Select
|| rTabs
.empty() )
497 aError
= SQLException(
498 DBA_RES(STR_QRY_NOSELECT
),
507 // change the view of the data
508 m_bGraphicalDesign
= !m_bGraphicalDesign
;
509 OUString sNewStatement
;
510 m_pSqlIterator
->getParseTree()->parseNodeToStr( sNewStatement
, getConnection() );
511 setStatement_fireEvent( sNewStatement
);
512 getContainer()->SaveUIConfig();
513 m_vTableConnectionData
.clear();
514 impl_setViewMode( &aError
);
520 aError
= SQLException(
521 DBA_RES(STR_QRY_SYNTAX
),
530 catch(const SQLException
&)
532 aError
= ::cppu::getCaughtException();
534 catch(const Exception
&)
536 DBG_UNHANDLED_EXCEPTION("dbaccess");
539 if ( aError
.isValid() )
542 if(m_bGraphicalDesign
)
544 InvalidateFeature(ID_BROWSER_ADDTABLE
);
545 InvalidateFeature(SID_RELATION_ADD_RELATION
);
549 case SID_BROWSER_CLEAR_QUERY
:
551 GetUndoManager().EnterListAction(DBA_RES(STR_QUERY_UNDO_TABWINDELETE
), OUString(), 0, ViewShellId(-1) );
552 getContainer()->clear();
553 GetUndoManager().LeaveListAction();
555 setStatement_fireEvent( OUString() );
556 if(m_bGraphicalDesign
)
557 InvalidateFeature(ID_BROWSER_ADDTABLE
);
560 case SID_QUERY_VIEW_FUNCTIONS
:
561 case SID_QUERY_VIEW_TABLES
:
562 case SID_QUERY_VIEW_ALIASES
:
563 getContainer()->setSlotEnabled(_nId
,!getContainer()->isSlotEnabled(_nId
));
566 case SID_QUERY_DISTINCT_VALUES
:
567 m_bDistinct
= !m_bDistinct
;
570 case SID_QUERY_LIMIT
:
571 if ( aArgs
.hasElements() && aArgs
[0].Name
== "DBLimit.Value" )
573 aArgs
[0].Value
>>= m_nLimit
;
577 case SID_QUERY_PROP_DLG
:
578 grabFocusFromLimitBox(*this);
579 execute_QueryPropDlg();
581 case ID_BROWSER_QUERY_EXECUTE
:
582 grabFocusFromLimitBox(*this);
583 if ( getContainer()->checkStatement() )
586 case SID_DB_QUERY_PREVIEW
:
589 Reference
< css::util::XCloseable
> xCloseFrame( getContainer()->getPreviewFrame(), UNO_QUERY
);
590 if ( xCloseFrame
.is() )
594 xCloseFrame
->close( true );
596 catch(const Exception
&)
598 OSL_FAIL( "OQueryController::Execute(SID_DB_QUERY_PREVIEW): *nobody* is expected to veto closing the preview frame!" );
602 Execute(ID_BROWSER_QUERY_EXECUTE
,Sequence
< PropertyValue
>());
604 catch(const Exception
&)
609 OJoinController::Execute(_nId
,aArgs
);
610 return; // else we would invalidate twice
612 InvalidateFeature(_nId
);
615 void OQueryController::impl_showAutoSQLViewError( const css::uno::Any
& _rErrorDetails
)
617 SQLContext aErrorContext
;
618 aErrorContext
.Message
= lcl_getObjectResourceString( STR_ERROR_PARSING_STATEMENT
, m_nCommandType
);
619 aErrorContext
.Context
= *this;
620 aErrorContext
.Details
= lcl_getObjectResourceString( STR_INFO_OPENING_IN_SQL_VIEW
, m_nCommandType
);
621 aErrorContext
.NextException
= _rErrorDetails
;
622 showError( aErrorContext
);
625 void OQueryController::impl_setViewMode( ::dbtools::SQLExceptionInfo
* _pErrorInfo
)
627 OSL_PRECOND( getContainer(), "OQueryController::impl_setViewMode: illegal call!" );
629 bool wasModified
= isModified();
631 SQLExceptionInfo aError
;
632 bool bSuccess
= getContainer()->switchView( &aError
);
635 m_bGraphicalDesign
= !m_bGraphicalDesign
;
637 getContainer()->switchView( nullptr );
638 // don't pass &aError here, this would overwrite the error which the first switchView call
639 // returned in this location.
641 *_pErrorInfo
= aError
;
647 ensureToolbars( *this, m_bGraphicalDesign
);
650 setModified( wasModified
);
653 void OQueryController::impl_initialize()
655 OJoinController::impl_initialize();
657 const NamedValueCollection
& rArguments( getInitParams() );
660 m_nCommandType
= CommandType::QUERY
;
662 // reading parameters:
664 // legacy parameters first (later overwritten by regular parameters)
665 OUString sIndependentSQLCommand
;
666 if ( rArguments
.get_ensureType( "IndependentSQLCommand", sIndependentSQLCommand
) )
668 OSL_FAIL( "OQueryController::impl_initialize: IndependentSQLCommand is regognized for compatibility only!" );
669 sCommand
= sIndependentSQLCommand
;
670 m_nCommandType
= CommandType::COMMAND
;
673 OUString sCurrentQuery
;
674 if ( rArguments
.get_ensureType( "CurrentQuery", sCurrentQuery
) )
676 OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" );
677 sCommand
= sCurrentQuery
;
678 m_nCommandType
= CommandType::QUERY
;
681 bool bCreateView( false );
682 if ( rArguments
.get_ensureType( "CreateView", bCreateView
) && bCreateView
)
684 OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" );
685 m_nCommandType
= CommandType::TABLE
;
688 // non-legacy parameters which overwrite the legacy parameters
689 rArguments
.get_ensureType( PROPERTY_COMMAND
, sCommand
);
690 rArguments
.get_ensureType( PROPERTY_COMMAND_TYPE
, m_nCommandType
);
692 // translate Command/Type into proper members
693 // TODO/Later: all this (including those members) should be hidden behind some abstract interface,
694 // which is implemented for all the three commands
695 switch ( m_nCommandType
)
697 case CommandType::QUERY
:
700 case CommandType::TABLE
:
703 case CommandType::COMMAND
:
704 setStatement_fireEvent( sCommand
);
708 OSL_FAIL( "OQueryController::impl_initialize: logic error in code!" );
709 throw RuntimeException();
712 // more legacy parameters
713 bool bGraphicalDesign( true );
714 if ( rArguments
.get_ensureType( PROPERTY_QUERYDESIGNVIEW
, bGraphicalDesign
) )
716 OSL_FAIL( "OQueryController::impl_initialize: QueryDesignView is regognized for compatibility only!" );
717 m_bGraphicalDesign
= bGraphicalDesign
;
721 rArguments
.get_ensureType( PROPERTY_GRAPHICAL_DESIGN
, m_bGraphicalDesign
);
723 bool bEscapeProcessing( true );
724 if ( rArguments
.get_ensureType( PROPERTY_ESCAPE_PROCESSING
, bEscapeProcessing
) )
726 setEscapeProcessing_fireEvent( bEscapeProcessing
);
728 OSL_ENSURE( m_bEscapeProcessing
|| !m_bGraphicalDesign
, "OQueryController::impl_initialize: can't do the graphical design without escape processing!" );
729 if ( !m_bEscapeProcessing
)
730 m_bGraphicalDesign
= false;
734 bool bForceInitialDesign
= false;
735 Sequence
< PropertyValue
> aCurrentQueryDesignProps
;
736 aCurrentQueryDesignProps
= rArguments
.getOrDefault( "CurrentQueryDesign", aCurrentQueryDesignProps
);
738 if ( aCurrentQueryDesignProps
.hasElements() )
740 ::comphelper::NamedValueCollection
aCurrentQueryDesign( aCurrentQueryDesignProps
);
741 if ( aCurrentQueryDesign
.has( PROPERTY_GRAPHICAL_DESIGN
) )
743 aCurrentQueryDesign
.get_ensureType( PROPERTY_GRAPHICAL_DESIGN
, m_bGraphicalDesign
);
745 if ( aCurrentQueryDesign
.has( PROPERTY_ESCAPE_PROCESSING
) )
747 aCurrentQueryDesign
.get_ensureType( PROPERTY_ESCAPE_PROCESSING
, m_bEscapeProcessing
);
749 if ( aCurrentQueryDesign
.has( "Statement" ) )
752 aCurrentQueryDesign
.get_ensureType( "Statement", sStatement
);
753 aCurrentQueryDesign
.remove( "Statement" );
754 setStatement_fireEvent( sStatement
);
757 loadViewSettings( aCurrentQueryDesign
);
759 bForceInitialDesign
= true;
762 if ( !ensureConnected() )
763 { // we have no connection so what else should we do
764 m_bGraphicalDesign
= false;
767 connectionLostMessage();
768 throw SQLException();
772 // check the view capabilities
773 if ( isConnected() && editingView() )
775 Reference
< XViewsSupplier
> xViewsSup( getConnection(), UNO_QUERY
);
776 Reference
< XNameAccess
> xViews
;
777 if ( xViewsSup
.is() )
778 xViews
= xViewsSup
->getViews();
781 { // we can't create views so we ask if the user wants to create a query instead
782 m_nCommandType
= CommandType::QUERY
;
785 OUString
aTitle(DBA_RES(STR_QUERYDESIGN_NO_VIEW_SUPPORT
));
786 OUString
aMessage(DBA_RES(STR_QUERYDESIGN_NO_VIEW_ASK
));
787 OSQLMessageBox
aDlg(getFrameWeld(), aTitle
, aMessage
, MessBoxStyle::YesNo
| MessBoxStyle::DefaultYes
, MessageType::Query
);
788 bClose
= aDlg
.run() == RET_NO
;
791 throw VetoException();
794 // now if we are to edit an existing view, check whether this is possible
795 if ( !m_sName
.isEmpty() )
797 Any
aView( xViews
->getByName( m_sName
) );
798 // will throw if there is no such view
799 if ( !( aView
>>= m_xAlterView
) )
801 throw IllegalArgumentException(
802 DBA_RES(STR_NO_ALTER_VIEW_SUPPORT
),
810 OSL_ENSURE(getDataSource().is(),"OQueryController::impl_initialize: need a datasource!");
814 getContainer()->initialize();
815 impl_reset( bForceInitialDesign
);
817 SQLExceptionInfo aError
;
818 const bool bAttemptedGraphicalDesign
= m_bGraphicalDesign
;
820 if ( bForceInitialDesign
)
822 getContainer()->forceInitialView();
826 impl_setViewMode( &aError
);
829 if ( aError
.isValid() && bAttemptedGraphicalDesign
&& !m_bGraphicalDesign
)
831 // we tried initializing the graphical view, this failed, and we were automatically switched to SQL
832 // view => tell this to the user
833 if ( !editingView() )
835 impl_showAutoSQLViewError( aError
.get() );
841 if ( m_bGraphicalDesign
842 && ( ( m_sName
.isEmpty() && !editingCommand() )
843 || ( m_sStatement
.isEmpty() && editingCommand() )
847 Application::PostUserEvent( LINK( this, OQueryController
, OnExecuteAddTable
) );
852 catch(const SQLException
& e
)
854 DBG_UNHANDLED_EXCEPTION("dbaccess");
855 // we caught an exception so we switch to text only mode
857 m_bGraphicalDesign
= false;
858 getContainer()->initialize();
859 OSQLMessageBox
aBox(getFrameWeld(), e
);
866 void OQueryController::onLoadedMenu(const Reference
< css::frame::XLayoutManager
>& /*_xLayoutManager*/)
868 ensureToolbars( *this, m_bGraphicalDesign
);
871 OUString
OQueryController::getPrivateTitle( ) const
873 if ( m_sName
.isEmpty() )
875 if ( !editingCommand() )
877 SolarMutexGuard aSolarGuard
;
878 ::osl::MutexGuard
aGuard( getMutex() );
879 OUString aDefaultName
= DBA_RES(editingView() ? STR_VIEW_TITLE
: STR_QRY_TITLE
);
880 return o3tl::getToken(aDefaultName
, 0, ' ') + OUString::number(getCurrentStartNumber());
886 void OQueryController::setQueryComposer()
891 Reference
< XSQLQueryComposerFactory
> xFactory(getConnection(), UNO_QUERY
);
892 OSL_ENSURE(xFactory
.is(),"Connection doesn't support a querycomposer");
893 if ( !(xFactory
.is() && getContainer()) )
898 m_xComposer
= xFactory
->createQueryComposer();
899 getContainer()->setStatement(m_sStatement
);
901 catch(const Exception
&)
903 m_xComposer
= nullptr;
905 OSL_ENSURE(m_xComposer
.is(),"No querycomposer available!");
906 Reference
<XTablesSupplier
> xTablesSup(getConnection(), UNO_QUERY
);
908 m_pSqlIterator
.reset(new ::connectivity::OSQLParseTreeIterator( getConnection(), xTablesSup
->getTables(), m_aSqlParser
));
911 bool OQueryController::Construct(vcl::Window
* pParent
)
913 // TODO: we have to check if we should create the text view or the design view
915 setView( VclPtr
<OQueryContainerWindow
>::Create( pParent
, *this, getORB() ) );
917 return OJoinController::Construct(pParent
);
920 OJoinDesignView
* OQueryController::getJoinView()
922 return getContainer()->getDesignView();
925 void OQueryController::describeSupportedFeatures()
927 OJoinController::describeSupportedFeatures();
928 implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC
, CommandGroup::DOCUMENT
);
929 implDescribeSupportedFeature( ".uno:SbaNativeSql", ID_BROWSER_ESCAPEPROCESSING
,CommandGroup::FORMAT
);
930 implDescribeSupportedFeature( ".uno:DBViewFunctions", SID_QUERY_VIEW_FUNCTIONS
, CommandGroup::VIEW
);
931 implDescribeSupportedFeature( ".uno:DBViewTableNames", SID_QUERY_VIEW_TABLES
, CommandGroup::VIEW
);
932 implDescribeSupportedFeature( ".uno:DBViewAliases", SID_QUERY_VIEW_ALIASES
, CommandGroup::VIEW
);
933 implDescribeSupportedFeature( ".uno:DBDistinctValues", SID_QUERY_DISTINCT_VALUES
, CommandGroup::FORMAT
);
934 implDescribeSupportedFeature( ".uno:DBChangeDesignMode",ID_BROWSER_SQL
, CommandGroup::VIEW
);
935 implDescribeSupportedFeature( ".uno:DBClearQuery", SID_BROWSER_CLEAR_QUERY
, CommandGroup::EDIT
);
936 implDescribeSupportedFeature( ".uno:SbaExecuteSql", ID_BROWSER_QUERY_EXECUTE
, CommandGroup::VIEW
);
937 implDescribeSupportedFeature( ".uno:DBAddRelation", SID_RELATION_ADD_RELATION
, CommandGroup::EDIT
);
938 implDescribeSupportedFeature( ".uno:DBQueryPreview", SID_DB_QUERY_PREVIEW
, CommandGroup::VIEW
);
939 implDescribeSupportedFeature( ".uno:DBLimit", SID_QUERY_LIMIT
, CommandGroup::FORMAT
);
940 implDescribeSupportedFeature( ".uno:DBQueryPropertiesDialog", SID_QUERY_PROP_DLG
, CommandGroup::FORMAT
);
942 #if OSL_DEBUG_LEVEL > 0
943 implDescribeSupportedFeature( ".uno:DBShowParseTree", ID_EDIT_QUERY_SQL
);
944 implDescribeSupportedFeature( ".uno:DBMakeDisjunct", ID_EDIT_QUERY_DESIGN
);
948 void OQueryController::impl_onModifyChanged()
950 OJoinController::impl_onModifyChanged();
951 InvalidateFeature(SID_BROWSER_CLEAR_QUERY
);
952 InvalidateFeature(ID_BROWSER_SAVEASDOC
);
953 InvalidateFeature(ID_BROWSER_QUERY_EXECUTE
);
956 void SAL_CALL
OQueryController::disposing( const EventObject
& Source
)
958 SolarMutexGuard aGuard
;
960 if ( getContainer() && Source
.Source
.is() )
962 if ( Source
.Source
== m_aCurrentFrame
.getFrame() )
963 { // our frame is being disposed -> close the preview window (if we have one)
964 Reference
< XFrame2
> xPreviewFrame( getContainer()->getPreviewFrame() );
965 ::comphelper::disposeComponent( xPreviewFrame
);
967 else if ( Source
.Source
== getContainer()->getPreviewFrame() )
969 getContainer()->disposingPreview();
973 OJoinController_BASE::disposing(Source
);
976 void OQueryController::reconnect(bool _bUI
)
979 ::comphelper::disposeComponent(m_xComposer
);
981 OJoinController::reconnect( _bUI
);
989 if(m_bGraphicalDesign
)
991 m_bGraphicalDesign
= false;
992 // don't call Execute(SQL) because this changes the sql statement
993 impl_setViewMode( nullptr );
999 void OQueryController::saveViewSettings( ::comphelper::NamedValueCollection
& o_rViewSettings
, const bool i_includingCriteria
) const
1001 saveTableWindows( o_rViewSettings
);
1003 ::comphelper::NamedValueCollection aAllFieldsData
;
1004 ::comphelper::NamedValueCollection aFieldData
;
1006 for (auto const& fieldDesc
: m_vTableFieldDesc
)
1008 if ( !fieldDesc
->IsEmpty() )
1011 fieldDesc
->Save( aFieldData
, i_includingCriteria
);
1013 const OUString sFieldSettingName
= "Field" + OUString::number( i
);
1014 aAllFieldsData
.put( sFieldSettingName
, aFieldData
.getPropertyValues() );
1019 o_rViewSettings
.put( "Fields", aAllFieldsData
.getPropertyValues() );
1020 o_rViewSettings
.put( "SplitterPosition", m_nSplitPos
);
1021 o_rViewSettings
.put( "VisibleRows", m_nVisibleRows
);
1024 void OQueryController::loadViewSettings( const ::comphelper::NamedValueCollection
& o_rViewSettings
)
1026 loadTableWindows( o_rViewSettings
);
1028 m_nSplitPos
= o_rViewSettings
.getOrDefault( "SplitterPosition", m_nSplitPos
);
1029 m_nVisibleRows
= o_rViewSettings
.getOrDefault( "VisibleRows", m_nVisibleRows
);
1030 m_aFieldInformation
= o_rViewSettings
.getOrDefault( "Fields", m_aFieldInformation
);
1033 void OQueryController::execute_QueryPropDlg()
1035 QueryPropertiesDialog
aQueryPropDlg(getContainer()->GetFrameWeld(), m_bDistinct
, m_nLimit
);
1037 if (aQueryPropDlg
.run() == RET_OK
)
1039 m_bDistinct
= aQueryPropDlg
.getDistinct();
1040 m_nLimit
= aQueryPropDlg
.getLimit();
1041 InvalidateFeature( SID_QUERY_DISTINCT_VALUES
);
1042 InvalidateFeature( SID_QUERY_LIMIT
, nullptr, true );
1046 sal_Int32
OQueryController::getColWidth(sal_uInt16 _nColPos
) const
1048 if ( _nColPos
< m_aFieldInformation
.getLength() )
1050 rtl::Reference
<OTableFieldDesc
> pField( new OTableFieldDesc());
1051 pField
->Load( m_aFieldInformation
[ _nColPos
], false );
1052 return pField
->GetColWidth();
1057 Reference
<XNameAccess
> OQueryController::getObjectContainer() const
1059 Reference
< XNameAccess
> xElements
;
1060 if ( editingView() )
1062 Reference
< XViewsSupplier
> xViewsSupp( getConnection(), UNO_QUERY
);
1063 if ( xViewsSupp
.is() )
1064 xElements
= xViewsSupp
->getViews();
1068 Reference
< XQueriesSupplier
> xQueriesSupp( getConnection(), UNO_QUERY
);
1069 if ( xQueriesSupp
.is() )
1070 xElements
= xQueriesSupp
->getQueries();
1073 Reference
< XQueryDefinitionsSupplier
> xQueryDefsSupp( getDataSource(), UNO_QUERY
);
1074 if ( xQueryDefsSupp
.is() )
1075 xElements
= xQueryDefsSupp
->getQueryDefinitions();
1079 OSL_ENSURE( xElements
.is(), "OQueryController::getObjectContainer: unable to obtain the container!" );
1083 void OQueryController::executeQuery()
1085 // we don't need to check the connection here because we already check the composer
1086 // which can't live without his connection
1087 OUString sTranslatedStmt
= translateStatement( false );
1089 OUString sDataSourceName
= getDataSourceName();
1090 if ( sDataSourceName
.isEmpty() || sTranslatedStmt
.isEmpty() )
1095 getContainer()->showPreview( getFrame() );
1096 InvalidateFeature(SID_DB_QUERY_PREVIEW
);
1098 URL aWantToDispatch
;
1099 aWantToDispatch
.Complete
= ".component:DB/DataSourceBrowser";
1101 OUString
sFrameName( FRAME_NAME_QUERY_PREVIEW
);
1102 sal_Int32 nSearchFlags
= FrameSearchFlag::CHILDREN
;
1104 Reference
< XDispatch
> xDisp
;
1105 Reference
< XDispatchProvider
> xProv( getFrame()->findFrame( sFrameName
, nSearchFlags
), UNO_QUERY
);
1108 xProv
.set( getFrame(), UNO_QUERY
);
1110 xDisp
= xProv
->queryDispatch(aWantToDispatch
, sFrameName
, nSearchFlags
);
1114 xDisp
= xProv
->queryDispatch(aWantToDispatch
, sFrameName
, FrameSearchFlag::SELF
);
1118 auto aProps(::comphelper::InitPropertySequence(
1120 { PROPERTY_DATASOURCENAME
, Any(sDataSourceName
) },
1121 { PROPERTY_COMMAND_TYPE
, Any(CommandType::COMMAND
) },
1122 { PROPERTY_COMMAND
, Any(sTranslatedStmt
) },
1123 { PROPERTY_ENABLE_BROWSER
, Any(false) },
1124 { PROPERTY_ACTIVE_CONNECTION
, Any(getConnection()) },
1125 { PROPERTY_UPDATE_CATALOGNAME
, Any(m_sUpdateCatalogName
) },
1126 { PROPERTY_UPDATE_SCHEMANAME
, Any(m_sUpdateSchemaName
) },
1127 { PROPERTY_UPDATE_TABLENAME
, Any(OUString()) },
1128 { PROPERTY_ESCAPE_PROCESSING
, Any(m_bEscapeProcessing
) }
1131 xDisp
->dispatch(aWantToDispatch
, aProps
);
1132 // check the state of the beamer
1133 // be notified when the beamer frame is closed
1134 Reference
< XComponent
> xComponent
= getFrame()->findFrame( sFrameName
, nSearchFlags
);
1135 if (xComponent
.is())
1137 OSL_ENSURE(Reference
< XFrame
>(xComponent
, UNO_QUERY
).get() == getContainer()->getPreviewFrame().get(),
1138 "OQueryController::executeQuery: oops ... which window do I have here?");
1139 Reference
< XEventListener
> xEvtL(static_cast<cppu::OWeakObject
*>(this),UNO_QUERY
);
1140 xComponent
->addEventListener(xEvtL
);
1145 OSL_FAIL("Couldn't create a beamer window!");
1148 catch(const Exception
&)
1150 OSL_FAIL("Couldn't create a beamer window!");
1154 bool OQueryController::askForNewName(const Reference
<XNameAccess
>& _xElements
, bool _bSaveAs
)
1156 OSL_ENSURE( !editingCommand(), "OQueryController::askForNewName: not to be called when designing an independent statement!" );
1157 if ( editingCommand() )
1160 OSL_PRECOND( _xElements
.is(), "OQueryController::askForNewName: invalid container!" );
1161 if ( !_xElements
.is() )
1165 bool bNew
= _bSaveAs
|| !_xElements
->hasByName( m_sName
);
1168 OUString aDefaultName
;
1169 if (!m_sName
.isEmpty())
1170 aDefaultName
= m_sName
;
1173 OUString sName
= DBA_RES(editingView() ? STR_VIEW_TITLE
: STR_QRY_TITLE
);
1174 aDefaultName
= ::dbtools::createUniqueName(_xElements
, sName
.getToken(0, ' '));
1177 DynamicTableOrQueryNameCheck
aNameChecker( getConnection(), CommandType::QUERY
);
1187 bRet
= ( aDlg
.run() == RET_OK
);
1190 m_sName
= aDlg
.getName();
1191 if ( editingView() )
1193 m_sUpdateCatalogName
= aDlg
.getCatalog();
1194 m_sUpdateSchemaName
= aDlg
.getSchema();
1201 bool OQueryController::doSaveAsDoc(bool _bSaveAs
)
1203 OSL_ENSURE(isEditable(),"Slot ID_BROWSER_SAVEDOC should not be enabled!");
1204 if ( !editingCommand() && !haveDataSource() )
1206 OUString
aMessage(DBA_RES(STR_DATASOURCE_DELETED
));
1207 OSQLWarningBox
aBox(getFrameWeld(), aMessage
);
1212 Reference
< XNameAccess
> xElements
= getObjectContainer();
1213 if ( !xElements
.is() )
1216 if ( !getContainer()->checkStatement() )
1219 OUString sTranslatedStmt
= translateStatement();
1220 if ( editingCommand() )
1222 setModified( false );
1223 // this is all we need to do here. translateStatement implicitly set our m_sStatement, and
1224 // notified it, and that's all
1228 if ( sTranslatedStmt
.isEmpty() )
1231 // first we need a name for our query so ask the user
1232 // did we get a name
1233 OUString
sOriginalName( m_sName
);
1234 if ( !askForNewName( xElements
, _bSaveAs
) || m_sName
.isEmpty() )
1237 SQLExceptionInfo aInfo
;
1238 bool bSuccess
= false;
1243 || ( !xElements
->hasByName( m_sName
) );
1245 Reference
<XPropertySet
> xQuery
;
1246 if ( bNew
) // just to make sure the query already exists
1248 // drop the query, in case it already exists
1249 if ( xElements
->hasByName( m_sName
) )
1251 Reference
< XDrop
> xNameCont( xElements
, UNO_QUERY
);
1252 if ( xNameCont
.is() )
1253 xNameCont
->dropByName( m_sName
);
1256 Reference
< XNameContainer
> xCont( xElements
, UNO_QUERY
);
1258 xCont
->removeByName( m_sName
);
1262 // create a new (empty, uninitialized) query resp. view
1263 Reference
< XDataDescriptorFactory
> xFact( xElements
, UNO_QUERY
);
1266 xQuery
= xFact
->createDataDescriptor();
1267 // to set the name is only allowed when the query is new
1268 xQuery
->setPropertyValue( PROPERTY_NAME
, Any( m_sName
) );
1272 Reference
< XSingleServiceFactory
> xSingleFac( xElements
, UNO_QUERY
);
1273 if ( xSingleFac
.is() )
1274 xQuery
.set(xSingleFac
->createInstance(), css::uno::UNO_QUERY
);
1279 xElements
->getByName( m_sName
) >>= xQuery
;
1282 throw RuntimeException();
1285 if ( editingView() && !bNew
)
1287 OSL_ENSURE( xQuery
== m_xAlterView
, "OQueryController::doSaveAsDoc: already have another alterable view ...!?" );
1288 m_xAlterView
.set( xQuery
, UNO_QUERY_THROW
);
1289 m_xAlterView
->alterCommand( sTranslatedStmt
);
1292 { // we're creating a query, or a *new* view
1293 xQuery
->setPropertyValue( PROPERTY_COMMAND
, Any( sTranslatedStmt
) );
1295 if ( editingView() )
1297 xQuery
->setPropertyValue( PROPERTY_CATALOGNAME
, Any( m_sUpdateCatalogName
) );
1298 xQuery
->setPropertyValue( PROPERTY_SCHEMANAME
, Any( m_sUpdateSchemaName
) );
1301 if ( editingQuery() )
1303 xQuery
->setPropertyValue( PROPERTY_UPDATE_TABLENAME
, Any( OUString() ) );
1304 xQuery
->setPropertyValue( PROPERTY_ESCAPE_PROCESSING
, css::uno::Any( m_bEscapeProcessing
) );
1306 xQuery
->setPropertyValue( PROPERTY_LAYOUTINFORMATION
, getViewData() );
1312 Reference
< XAppend
> xAppend( xElements
, UNO_QUERY
);
1315 xAppend
->appendByDescriptor( xQuery
);
1319 Reference
< XNameContainer
> xCont( xElements
, UNO_QUERY
);
1321 xCont
->insertByName( m_sName
, Any( xQuery
) );
1324 if ( editingView() )
1326 Reference
< XPropertySet
> xViewProps
;
1327 if ( xElements
->hasByName( m_sName
) )
1328 xViewProps
.set( xElements
->getByName( m_sName
), UNO_QUERY
);
1330 if ( !xViewProps
.is() ) // correct name and try again
1331 m_sName
= ::dbtools::composeTableName( getMetaData(), xQuery
, ::dbtools::EComposeRule::InDataManipulation
, false );
1333 OSL_ENSURE( xElements
->hasByName( m_sName
), "OQueryController::doSaveAsDoc: newly created view does not exist!" );
1335 if ( xElements
->hasByName( m_sName
) )
1336 m_xAlterView
.set( xElements
->getByName( m_sName
), UNO_QUERY
);
1338 // now check if our datasource has set a tablefilter and if so, append the new table name to it
1339 ::dbaui::appendToFilter(getConnection(), m_sName
, getORB(), getFrameWeld());
1341 Reference
< XTitleChangeListener
> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY
);
1342 if ( xEventListener
.is() )
1344 TitleChangedEvent aEvent
;
1345 xEventListener
->titleChanged(aEvent
);
1347 releaseNumberForComponent();
1350 setModified( false );
1354 catch(const SQLException
&)
1357 m_sName
= sOriginalName
;
1358 aInfo
= SQLExceptionInfo( ::cppu::getCaughtException() );
1360 catch(const Exception
&)
1362 DBG_UNHANDLED_EXCEPTION("dbaccess");
1364 m_sName
= sOriginalName
;
1369 // if we successfully saved a view we were creating, then close the designer
1370 if ( bSuccess
&& editingView() && !m_xAlterView
.is() )
1375 if ( bSuccess
&& editingView() )
1376 InvalidateFeature( ID_BROWSER_EDITDOC
);
1386 CommentStrip( OUString sComment
, bool bLastOnLine
)
1387 : maComment(std::move( sComment
)), mbLastOnLine( bLastOnLine
) {}
1392 /** Obtain all comments in a query.
1394 See also delComment() implementation for OSQLParser::parseTree().
1396 static std::vector
< CommentStrip
> getComment( const OUString
& rQuery
)
1398 std::vector
< CommentStrip
> aRet
;
1399 // First a quick search if there is any "--" or "//" or "/*", if not then
1400 // the whole copying loop is pointless.
1401 if (rQuery
.indexOf( "--" ) < 0 && rQuery
.indexOf( "//" ) < 0 &&
1402 rQuery
.indexOf( "/*" ) < 0)
1405 const sal_Unicode
* pCopy
= rQuery
.getStr();
1406 const sal_Int32 nQueryLen
= rQuery
.getLength();
1407 bool bIsText1
= false; // "text"
1408 bool bIsText2
= false; // 'text'
1409 bool bComment2
= false; // /* comment */
1410 bool bComment
= false; // -- or // comment
1411 OUStringBuffer aBuf
;
1412 for (sal_Int32 i
=0; i
< nQueryLen
; ++i
)
1416 aBuf
.append( &pCopy
[i
], 1);
1417 if ((i
+1) < nQueryLen
)
1419 if (pCopy
[i
]=='*' && pCopy
[i
+1]=='/')
1422 aBuf
.append( &pCopy
[++i
], 1);
1423 aRet
.emplace_back( aBuf
.makeStringAndClear(), false);
1428 // comment can't close anymore, actually an error, but...
1429 aRet
.emplace_back( aBuf
.makeStringAndClear(), false);
1433 if (pCopy
[i
] == '\n' || i
== nQueryLen
-1)
1437 if (i
== nQueryLen
-1 && pCopy
[i
] != '\n')
1438 aBuf
.append( &pCopy
[i
], 1);
1439 aRet
.emplace_back( aBuf
.makeStringAndClear(), true);
1442 else if (!aRet
.empty())
1443 aRet
.back().mbLastOnLine
= true;
1447 if (pCopy
[i
] == '\"' && !bIsText2
)
1448 bIsText1
= !bIsText1
;
1449 else if (pCopy
[i
] == '\'' && !bIsText1
)
1450 bIsText2
= !bIsText2
;
1451 if (!bIsText1
&& !bIsText2
&& (i
+1) < nQueryLen
)
1453 if ((pCopy
[i
]=='-' && pCopy
[i
+1]=='-') || (pCopy
[i
]=='/' && pCopy
[i
+1]=='/'))
1455 else if (pCopy
[i
]=='/' && pCopy
[i
+1]=='*')
1459 if (bComment
|| bComment2
)
1460 aBuf
.append( &pCopy
[i
], 1);
1465 /** Concat/insert comments that were previously obtained with getComment().
1467 NOTE: The current parser implementation does not preserve newlines, so all
1468 comments are always appended to the entire query, also inline comments
1469 that would need positioning anyway that can't be obtained after
1470 recomposition. This is ugly but at least allows commented queries while
1471 preserving the comments _somehow_.
1473 static OUString
concatComment( const OUString
& rQuery
, const std::vector
< CommentStrip
>& rComments
)
1475 // No comments => return query.
1476 if (rComments
.empty())
1479 const sal_Unicode
* pBeg
= rQuery
.getStr();
1480 const sal_Int32 nLen
= rQuery
.getLength();
1481 const size_t nComments
= rComments
.size();
1482 // Obtaining the needed size once should be faster than reallocating.
1483 // Also add a blank or linefeed for each comment.
1484 sal_Int32 nBufSize
= nLen
+ nComments
;
1485 for (auto const& comment
: rComments
)
1486 nBufSize
+= comment
.maComment
.getLength();
1487 OUStringBuffer
aBuf( nBufSize
);
1488 sal_Int32 nIndBeg
= 0;
1489 sal_Int32 nIndLF
= rQuery
.indexOf('\n');
1491 while (nIndLF
>= 0 && i
< nComments
)
1493 aBuf
.append( pBeg
+ nIndBeg
, nIndLF
- nIndBeg
);
1496 aBuf
.append( rComments
[i
].maComment
);
1497 } while (!rComments
[i
++].mbLastOnLine
&& i
< nComments
);
1498 aBuf
.append( pBeg
+ nIndLF
, 1); // the LF
1499 nIndBeg
= nIndLF
+ 1;
1500 nIndLF
= (nIndBeg
< nLen
? rQuery
.indexOf( '\n', nIndBeg
) : -1);
1502 // Append remainder of query.
1504 aBuf
.append( pBeg
+ nIndBeg
, nLen
- nIndBeg
);
1505 // Append all remaining comments, preserve lines.
1506 bool bNewLine
= false;
1507 for ( ; i
< nComments
; ++i
)
1511 aBuf
.append( rComments
[i
].maComment
);
1512 if (rComments
[i
].mbLastOnLine
)
1520 return aBuf
.makeStringAndClear();
1523 OUString
OQueryController::translateStatement( bool _bFireStatementChange
)
1525 // now set the properties
1526 setStatement_fireEvent( getContainer()->getStatement(), _bFireStatementChange
);
1527 OUString sTranslatedStmt
;
1528 if(!m_sStatement
.isEmpty() && m_xComposer
.is() && m_bEscapeProcessing
)
1534 std::vector
< CommentStrip
> aComments
= getComment( m_sStatement
);
1536 std::unique_ptr
<::connectivity::OSQLParseNode
> pNode
= m_aSqlParser
.parseTree( aErrorMsg
, m_sStatement
, m_bGraphicalDesign
);
1539 pNode
->parseNodeToStr( sTranslatedStmt
, getConnection() );
1542 m_xComposer
->setQuery(sTranslatedStmt
);
1543 sTranslatedStmt
= m_xComposer
->getComposedQuery();
1544 sTranslatedStmt
= concatComment( sTranslatedStmt
, aComments
);
1546 catch(const SQLException
& e
)
1548 ::dbtools::SQLExceptionInfo
aInfo(e
);
1550 // an error occurred so we clear the statement
1551 sTranslatedStmt
.clear();
1554 else if(m_sStatement
.isEmpty())
1556 showError(SQLException(DBA_RES(STR_QRY_NOSELECT
), nullptr, "S1000", 1000, Any()));
1559 sTranslatedStmt
= m_sStatement
;
1561 return sTranslatedStmt
;
1564 short OQueryController::saveModified()
1566 SolarMutexGuard aSolarGuard
;
1567 ::osl::MutexGuard
aGuard( getMutex() );
1568 short nRet
= RET_YES
;
1569 if ( !isConnected() || !isModified() )
1572 if ( !m_bGraphicalDesign
1573 || ( !m_vTableFieldDesc
.empty()
1574 && !m_vTableData
.empty()
1578 OUString
sMessageText( lcl_getObjectResourceString( STR_QUERY_SAVEMODIFIED
, m_nCommandType
) );
1580 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(getFrameWeld(),
1581 VclMessageType::Question
, VclButtonsType::YesNo
,
1583 xQueryBox
->add_button(GetStandardText(StandardButtonType::Cancel
), RET_CANCEL
);
1584 xQueryBox
->set_default_response(RET_YES
);
1586 nRet
= xQueryBox
->run();
1587 if ( ( nRet
== RET_YES
)
1588 && !doSaveAsDoc( false )
1597 void OQueryController::impl_reset( const bool i_bForceCurrentControllerSettings
)
1599 bool bValid
= false;
1601 Sequence
< PropertyValue
> aLayoutInformation
;
1602 // get command from the query if a query name was supplied
1603 if ( !i_bForceCurrentControllerSettings
&& !editingCommand() )
1605 if ( !m_sName
.isEmpty() )
1607 Reference
< XNameAccess
> xQueries
= getObjectContainer();
1608 if ( xQueries
.is() )
1610 Reference
< XPropertySet
> xProp
;
1611 if( xQueries
->hasByName( m_sName
) && ( xQueries
->getByName( m_sName
) >>= xProp
) && xProp
.is() )
1613 OUString sNewStatement
;
1614 xProp
->getPropertyValue( PROPERTY_COMMAND
) >>= sNewStatement
;
1615 setStatement_fireEvent( sNewStatement
);
1617 if ( editingQuery() )
1619 bool bNewEscapeProcessing( true );
1620 xProp
->getPropertyValue( PROPERTY_ESCAPE_PROCESSING
) >>= bNewEscapeProcessing
;
1621 setEscapeProcessing_fireEvent( bNewEscapeProcessing
);
1624 m_bGraphicalDesign
= m_bGraphicalDesign
&& m_bEscapeProcessing
;
1629 if ( editingQuery() )
1630 xProp
->getPropertyValue( PROPERTY_LAYOUTINFORMATION
) >>= aLayoutInformation
;
1632 catch( const Exception
& )
1634 OSL_FAIL( "OQueryController::impl_reset: could not retrieve the layout information from the query!" );
1643 // assume that we got all necessary information during initialization
1648 // load the layoutInformation
1649 if ( aLayoutInformation
.hasElements() )
1653 loadViewSettings( aLayoutInformation
);
1655 catch( const Exception
& )
1657 DBG_UNHANDLED_EXCEPTION("dbaccess");
1661 if ( !m_sStatement
.isEmpty() )
1665 bool bError( false );
1667 if ( !m_pSqlIterator
)
1671 else if ( m_bEscapeProcessing
)
1674 std::unique_ptr
< ::connectivity::OSQLParseNode
> pNode(
1675 m_aSqlParser
.parseTree( aErrorMsg
, m_sStatement
, m_bGraphicalDesign
) );
1679 delete m_pSqlIterator
->getParseTree();
1680 m_pSqlIterator
->setParseTree( pNode
.release() );
1681 m_pSqlIterator
->traverseAll();
1682 if ( m_pSqlIterator
->hasErrors() )
1684 if ( !i_bForceCurrentControllerSettings
&& m_bGraphicalDesign
&& !editingView() )
1686 impl_showAutoSQLViewError( Any( m_pSqlIterator
->getErrors() ) );
1693 if ( !i_bForceCurrentControllerSettings
&& !editingView() )
1695 OUString
aTitle(DBA_RES(STR_SVT_SQL_SYNTAX_ERROR
));
1696 OSQLMessageBox
aDlg(getFrameWeld(), aTitle
, aErrorMsg
);
1705 m_bGraphicalDesign
= false;
1706 if ( editingView() )
1707 // if we're editing a view whose statement could not be parsed, default to "no escape processing"
1708 setEscapeProcessing_fireEvent( false );
1715 OSL_ENSURE(m_pSqlIterator
,"No SQLIterator set!");
1717 getContainer()->setNoneVisibleRow(m_nVisibleRows
);
1720 void OQueryController::reset()
1723 getContainer()->reset();
1727 void OQueryController::setStatement_fireEvent( const OUString
& _rNewStatement
, bool _bFireStatementChange
)
1729 Any
aOldValue( m_sStatement
);
1730 m_sStatement
= _rNewStatement
;
1731 Any
aNewValue( m_sStatement
);
1733 sal_Int32 nHandle
= PROPERTY_ID_ACTIVECOMMAND
;
1734 if ( _bFireStatementChange
)
1735 fire( &nHandle
, &aNewValue
, &aOldValue
, 1, false );
1738 void OQueryController::setEscapeProcessing_fireEvent( const bool _bEscapeProcessing
)
1740 if ( _bEscapeProcessing
== m_bEscapeProcessing
)
1743 Any
aOldValue( m_bEscapeProcessing
);
1744 m_bEscapeProcessing
= _bEscapeProcessing
;
1745 Any
aNewValue( m_bEscapeProcessing
);
1747 sal_Int32 nHandle
= PROPERTY_ID_ESCAPE_PROCESSING
;
1748 fire( &nHandle
, &aNewValue
, &aOldValue
, 1, false );
1751 IMPL_LINK_NOARG( OQueryController
, OnExecuteAddTable
, void*, void )
1753 Execute( ID_BROWSER_ADDTABLE
,Sequence
<PropertyValue
>() );
1756 bool OQueryController::allowViews() const
1761 bool OQueryController::allowQueries() const
1763 OSL_ENSURE( getSdbMetaData().isConnected(), "OQueryController::allowQueries: illegal call!" );
1764 if ( !getSdbMetaData().supportsSubqueriesInFrom() )
1767 const NamedValueCollection
& rArguments( getInitParams() );
1768 sal_Int32 nCommandType
= rArguments
.getOrDefault( PROPERTY_COMMAND_TYPE
, sal_Int32(CommandType::QUERY
) );
1769 bool bCreatingView
= ( nCommandType
== CommandType::TABLE
);
1770 return !bCreatingView
;
1773 Any SAL_CALL
OQueryController::getViewData()
1775 ::osl::MutexGuard
aGuard( getMutex() );
1777 getContainer()->SaveUIConfig();
1779 ::comphelper::NamedValueCollection aViewSettings
;
1780 saveViewSettings( aViewSettings
, false );
1782 return Any( aViewSettings
.getPropertyValues() );
1785 void SAL_CALL
OQueryController::restoreViewData(const Any
& /*Data*/)
1790 } // namespace dbaui
1792 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */