android: Update app icon to new startcenter icon
[LibreOffice.git] / dbaccess / source / ui / querydesign / querycontroller.cxx
blob38caed31a79fe11e1ed2685aeb1b46c911161ced
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <browserids.hxx>
21 #include <core_resource.hxx>
22 #include <strings.hrc>
23 #include <strings.hxx>
24 #include <query.hrc>
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>
67 #include <utility>
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>
73 #include <memory>
74 #include <vector>
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));
83 namespace dbaui
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;
91 namespace {
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" };
104 public:
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));
118 namespace dbaui
120 using namespace ::connectivity;
122 namespace
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 );
129 return sMessageText;
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;
145 namespace
147 void ensureToolbars( OQueryController& _rController, bool _bDesign )
149 Reference< css::frame::XLayoutManager > xLayoutManager = OGenericUnoController::getLayoutManager( _rController.getFrame() );
150 if ( !xLayoutManager.is() )
151 return;
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";
156 if ( _bDesign )
158 xLayoutManager->destroyElement( s_sSqlToolbar );
159 xLayoutManager->createElement( s_sDesignToolbar );
161 else
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");
179 if (xUIElement.is())
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() )
206 ,m_nLimit(-1)
207 ,m_nVisibleRows(0x400)
208 ,m_nSplitPos(-1)
209 ,m_nCommandType( CommandType::QUERY )
210 ,m_bGraphicalDesign(false)
211 ,m_bDistinct(false)
212 ,m_bEscapeProcessing(true)
214 InvalidateAll();
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 );
229 dispose();
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() ) );
239 return xInfo;
242 void SAL_CALL OQueryController::getFastPropertyValue( Any& o_rValue, sal_Int32 i_nHandle ) const
244 switch ( i_nHandle )
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 );
258 else
260 aCurrentDesign.put( "Statement", getContainer()->getStatement() );
263 o_rValue <<= aCurrentDesign.getPropertyValues();
265 break;
267 default:
268 OPropertyContainer::getFastPropertyValue( o_rValue, i_nHandle );
269 break;
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
294 std::sort(
295 pProps,
296 pProps + aProps.getLength(),
297 ::comphelper::PropertyCompareByName()
300 return new ::cppu::OPropertyArrayHelper(aProps);
303 void OQueryController::deleteIterator()
305 if(m_pSqlIterator)
307 delete m_pSqlIterator->getParseTree();
308 m_pSqlIterator->dispose();
309 m_pSqlIterator.reset();
313 void OQueryController::disposing()
315 OQueryController_PBase::disposing();
317 deleteIterator();
319 m_pParseContext.reset();
321 clearFields();
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)
340 switch (_nId)
342 case ID_BROWSER_EDITDOC:
343 if ( editingCommand() )
344 aReturn.bEnabled = false;
345 else if ( editingView() && !m_xAlterView.is() )
346 aReturn.bEnabled = false;
347 else
348 aReturn = OJoinController::GetState( _nId );
349 break;
351 case ID_BROWSER_ESCAPEPROCESSING:
352 aReturn.bChecked = !m_bEscapeProcessing;
353 aReturn.bEnabled = ( m_pSqlIterator != nullptr ) && !m_bGraphicalDesign;
354 break;
355 case SID_RELATION_ADD_RELATION:
356 aReturn.bEnabled = isEditable() && m_bGraphicalDesign && m_vTableData.size() > 1;
357 break;
358 case ID_BROWSER_SAVEASDOC:
359 aReturn.bEnabled = !editingCommand() && (!m_bGraphicalDesign || !(m_vTableFieldDesc.empty() || m_vTableData.empty()));
360 break;
361 case ID_BROWSER_SAVEDOC:
362 aReturn.bEnabled = isEditable() && (!m_bGraphicalDesign || !(m_vTableFieldDesc.empty() || m_vTableData.empty()));
363 break;
364 case SID_PRINTDOCDIRECT:
365 break;
366 case ID_BROWSER_CUT:
367 aReturn.bEnabled = isEditable() && getContainer() && getContainer()->isCutAllowed();
368 break;
369 case ID_BROWSER_COPY:
370 aReturn.bEnabled = getContainer() && getContainer()->isCopyAllowed();
371 break;
372 case ID_BROWSER_PASTE:
373 aReturn.bEnabled = isEditable() && getContainer() && getContainer()->isPasteAllowed();
374 break;
375 case ID_BROWSER_SQL:
376 aReturn.bEnabled = m_bEscapeProcessing && m_pSqlIterator;
377 aReturn.bChecked = m_bGraphicalDesign;
378 break;
379 case SID_BROWSER_CLEAR_QUERY:
380 aReturn.bEnabled = isEditable() && (!m_sStatement.isEmpty() || !m_vTableData.empty());
381 break;
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;
387 break;
388 case SID_QUERY_DISTINCT_VALUES:
389 aReturn.bEnabled = m_bGraphicalDesign && isEditable();
390 aReturn.bChecked = m_bDistinct;
391 break;
392 case SID_QUERY_LIMIT:
393 aReturn.bEnabled = m_bGraphicalDesign;
394 if( aReturn.bEnabled )
395 aReturn.aValue <<= m_nLimit;
396 break;
397 case SID_QUERY_PROP_DLG:
398 aReturn.bEnabled = m_bGraphicalDesign;
399 break;
400 case ID_BROWSER_QUERY_EXECUTE:
401 aReturn.bEnabled = true;
402 break;
403 case SID_DB_QUERY_PREVIEW:
404 aReturn.bEnabled = true;
405 aReturn.bChecked = getContainer() && getContainer()->getPreviewFrame().is();
406 break;
407 #if OSL_DEBUG_LEVEL > 0
408 case ID_EDIT_QUERY_SQL:
409 break;
410 case ID_EDIT_QUERY_DESIGN:
411 break;
412 #endif
413 case ID_BROWSER_ADDTABLE:
414 if ( !m_bGraphicalDesign )
416 aReturn.bEnabled = false;
417 break;
419 [[fallthrough]];
420 default:
421 aReturn = OJoinController::GetState(_nId);
422 break;
424 return aReturn;
427 void OQueryController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
429 switch(_nId)
431 case ID_BROWSER_ESCAPEPROCESSING:
432 setEscapeProcessing_fireEvent( !m_bEscapeProcessing );
433 if ( !editingView() )
434 setModified(true);
435 InvalidateFeature(ID_BROWSER_SQL);
436 break;
437 case ID_BROWSER_SAVEASDOC:
438 case ID_BROWSER_SAVEDOC:
439 grabFocusFromLimitBox(*this);
440 doSaveAsDoc(ID_BROWSER_SAVEASDOC == _nId);
441 break;
442 case SID_RELATION_ADD_RELATION:
444 OJoinDesignView* pView = getJoinView();
445 if( pView )
446 static_cast<OQueryTableView*>(pView->getTableView())->createNewConnection();
448 break;
449 case SID_PRINTDOCDIRECT:
450 break;
451 case ID_BROWSER_CUT:
452 getContainer()->cut();
453 break;
454 case ID_BROWSER_COPY:
455 getContainer()->copy();
456 break;
457 case ID_BROWSER_PASTE:
458 getContainer()->paste();
459 break;
460 case ID_BROWSER_SQL:
462 grabFocusFromLimitBox(*this);
463 if ( !getContainer()->checkStatement() )
464 break;
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 );
477 else
479 OUString aErrorMsg;
480 std::unique_ptr<::connectivity::OSQLParseNode> pNode = m_aSqlParser.parseTree(aErrorMsg,m_sStatement,m_bGraphicalDesign);
481 if ( pNode )
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();
492 else
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),
499 nullptr,
500 "S1000",
501 1000,
502 Any()
505 else
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 );
518 else
520 aError = SQLException(
521 DBA_RES(STR_QRY_SYNTAX),
522 nullptr,
523 "S1000",
524 1000,
525 Any()
530 catch(const SQLException&)
532 aError = ::cppu::getCaughtException();
534 catch(const Exception&)
536 DBG_UNHANDLED_EXCEPTION("dbaccess");
539 if ( aError.isValid() )
540 showError( aError );
542 if(m_bGraphicalDesign)
544 InvalidateFeature(ID_BROWSER_ADDTABLE);
545 InvalidateFeature(SID_RELATION_ADD_RELATION);
548 break;
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);
559 break;
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));
564 setModified(true);
565 break;
566 case SID_QUERY_DISTINCT_VALUES:
567 m_bDistinct = !m_bDistinct;
568 setModified(true);
569 break;
570 case SID_QUERY_LIMIT:
571 if ( aArgs.hasElements() && aArgs[0].Name == "DBLimit.Value" )
573 aArgs[0].Value >>= m_nLimit;
574 setModified(true);
576 break;
577 case SID_QUERY_PROP_DLG:
578 grabFocusFromLimitBox(*this);
579 execute_QueryPropDlg();
580 break;
581 case ID_BROWSER_QUERY_EXECUTE:
582 grabFocusFromLimitBox(*this);
583 if ( getContainer()->checkStatement() )
584 executeQuery();
585 break;
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!" );
601 else
602 Execute(ID_BROWSER_QUERY_EXECUTE,Sequence< PropertyValue >());
604 catch(const Exception&)
607 break;
608 default:
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 );
633 if ( !bSuccess )
635 m_bGraphicalDesign = !m_bGraphicalDesign;
636 // restore old state
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.
640 if ( _pErrorInfo )
641 *_pErrorInfo = aError;
642 else
643 showError( aError );
645 else
647 ensureToolbars( *this, m_bGraphicalDesign );
650 setModified( wasModified );
653 void OQueryController::impl_initialize()
655 OJoinController::impl_initialize();
657 const NamedValueCollection& rArguments( getInitParams() );
659 OUString sCommand;
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:
698 m_sName = sCommand;
699 break;
700 case CommandType::TABLE:
701 m_sName = sCommand;
702 break;
703 case CommandType::COMMAND:
704 setStatement_fireEvent( sCommand );
705 m_sName.clear();
706 break;
707 default:
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;
720 // more non-legacy
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;
733 // initial design
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" ) )
751 OUString sStatement;
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;
765 if ( editingView() )
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();
780 if ( !xViews.is() )
781 { // we can't create views so we ask if the user wants to create a query instead
782 m_nCommandType = CommandType::QUERY;
783 bool bClose = false;
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;
790 if ( bClose )
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),
803 *this,
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();
824 else
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() );
839 ClearUndoManager();
841 if ( m_bGraphicalDesign
842 && ( ( m_sName.isEmpty() && !editingCommand() )
843 || ( m_sStatement.isEmpty() && editingCommand() )
847 Application::PostUserEvent( LINK( this, OQueryController, OnExecuteAddTable ) );
850 setModified(false);
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);
860 aBox.run();
862 throw;
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());
883 return m_sName;
886 void OQueryController::setQueryComposer()
888 if(!isConnected())
889 return;
891 Reference< XSQLQueryComposerFactory > xFactory(getConnection(), UNO_QUERY);
892 OSL_ENSURE(xFactory.is(),"Connection doesn't support a querycomposer");
893 if ( !(xFactory.is() && getContainer()) )
894 return;
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);
907 deleteIterator();
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 );
945 #endif
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)
978 deleteIterator();
979 ::comphelper::disposeComponent(m_xComposer);
981 OJoinController::reconnect( _bUI );
983 if (isConnected())
985 setQueryComposer();
987 else
989 if(m_bGraphicalDesign)
991 m_bGraphicalDesign = false;
992 // don't call Execute(SQL) because this changes the sql statement
993 impl_setViewMode( nullptr );
995 InvalidateAll();
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;
1005 sal_Int32 i = 1;
1006 for (auto const& fieldDesc : m_vTableFieldDesc)
1008 if ( !fieldDesc->IsEmpty() )
1010 aFieldData.clear();
1011 fieldDesc->Save( aFieldData, i_includingCriteria );
1013 const OUString sFieldSettingName = "Field" + OUString::number( i );
1014 aAllFieldsData.put( sFieldSettingName, aFieldData.getPropertyValues() );
1016 ++i;
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();
1054 return 0;
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();
1066 else
1068 Reference< XQueriesSupplier > xQueriesSupp( getConnection(), UNO_QUERY );
1069 if ( xQueriesSupp.is() )
1070 xElements = xQueriesSupp->getQueries();
1071 else
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!" );
1080 return xElements;
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() )
1091 return;
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 );
1106 if(!xProv.is())
1108 xProv.set( getFrame(), UNO_QUERY );
1109 if (xProv.is())
1110 xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, nSearchFlags);
1112 else
1114 xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, FrameSearchFlag::SELF);
1116 if (xDisp.is())
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) }
1129 }));
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);
1143 else
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() )
1158 return false;
1160 OSL_PRECOND( _xElements.is(), "OQueryController::askForNewName: invalid container!" );
1161 if ( !_xElements.is() )
1162 return false;
1164 bool bRet = true;
1165 bool bNew = _bSaveAs || !_xElements->hasByName( m_sName );
1166 if(bNew)
1168 OUString aDefaultName;
1169 if (!m_sName.isEmpty())
1170 aDefaultName = m_sName;
1171 else
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 );
1178 OSaveAsDlg aDlg(
1179 getFrameWeld(),
1180 m_nCommandType,
1181 getORB(),
1182 getConnection(),
1183 aDefaultName,
1184 aNameChecker,
1185 SADFlags::NONE );
1187 bRet = ( aDlg.run() == RET_OK );
1188 if ( bRet )
1190 m_sName = aDlg.getName();
1191 if ( editingView() )
1193 m_sUpdateCatalogName = aDlg.getCatalog();
1194 m_sUpdateSchemaName = aDlg.getSchema();
1198 return bRet;
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);
1208 aBox.run();
1209 return false;
1212 Reference< XNameAccess > xElements = getObjectContainer();
1213 if ( !xElements.is() )
1214 return false;
1216 if ( !getContainer()->checkStatement() )
1217 return false;
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
1225 return true;
1228 if ( sTranslatedStmt.isEmpty() )
1229 return false;
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() )
1235 return false;
1237 SQLExceptionInfo aInfo;
1238 bool bSuccess = false;
1239 bool bNew = false;
1242 bNew = _bSaveAs
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 );
1254 else
1256 Reference< XNameContainer > xCont( xElements, UNO_QUERY );
1257 if ( xCont.is() )
1258 xCont->removeByName( m_sName );
1262 // create a new (empty, uninitialized) query resp. view
1263 Reference< XDataDescriptorFactory > xFact( xElements, UNO_QUERY );
1264 if ( xFact.is() )
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 ) );
1270 else
1272 Reference< XSingleServiceFactory > xSingleFac( xElements, UNO_QUERY );
1273 if ( xSingleFac.is() )
1274 xQuery.set(xSingleFac->createInstance(), css::uno::UNO_QUERY);
1277 else
1279 xElements->getByName( m_sName ) >>= xQuery;
1281 if ( !xQuery.is() )
1282 throw RuntimeException();
1284 // the new commands
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 );
1291 else
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() );
1310 if ( bNew )
1312 Reference< XAppend > xAppend( xElements, UNO_QUERY );
1313 if ( xAppend.is() )
1315 xAppend->appendByDescriptor( xQuery );
1317 else
1319 Reference< XNameContainer > xCont( xElements, UNO_QUERY );
1320 if ( xCont.is() )
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 );
1351 bSuccess = true;
1354 catch(const SQLException&)
1356 if ( !bNew )
1357 m_sName = sOriginalName;
1358 aInfo = SQLExceptionInfo( ::cppu::getCaughtException() );
1360 catch(const Exception&)
1362 DBG_UNHANDLED_EXCEPTION("dbaccess");
1363 if ( !bNew )
1364 m_sName = sOriginalName;
1367 showError( aInfo );
1369 // if we successfully saved a view we were creating, then close the designer
1370 if ( bSuccess && editingView() && !m_xAlterView.is() )
1372 closeTask();
1375 if ( bSuccess && editingView() )
1376 InvalidateFeature( ID_BROWSER_EDITDOC );
1378 return bSuccess;
1381 namespace {
1382 struct CommentStrip
1384 OUString maComment;
1385 bool mbLastOnLine;
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)
1403 return aRet;
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)
1414 if (bComment2)
1416 aBuf.append( &pCopy[i], 1);
1417 if ((i+1) < nQueryLen)
1419 if (pCopy[i]=='*' && pCopy[i+1]=='/')
1421 bComment2 = false;
1422 aBuf.append( &pCopy[++i], 1);
1423 aRet.emplace_back( aBuf.makeStringAndClear(), false);
1426 else
1428 // comment can't close anymore, actually an error, but...
1429 aRet.emplace_back( aBuf.makeStringAndClear(), false);
1431 continue;
1433 if (pCopy[i] == '\n' || i == nQueryLen-1)
1435 if (bComment)
1437 if (i == nQueryLen-1 && pCopy[i] != '\n')
1438 aBuf.append( &pCopy[i], 1);
1439 aRet.emplace_back( aBuf.makeStringAndClear(), true);
1440 bComment = false;
1442 else if (!aRet.empty())
1443 aRet.back().mbLastOnLine = true;
1445 else if (!bComment)
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]=='/'))
1454 bComment = true;
1455 else if (pCopy[i]=='/' && pCopy[i+1]=='*')
1456 bComment2 = true;
1459 if (bComment || bComment2)
1460 aBuf.append( &pCopy[i], 1);
1462 return aRet;
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())
1477 return rQuery;
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');
1490 size_t i = 0;
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.
1503 if (nIndBeg < nLen)
1504 aBuf.append( pBeg + nIndBeg, nLen - nIndBeg);
1505 // Append all remaining comments, preserve lines.
1506 bool bNewLine = false;
1507 for ( ; i < nComments; ++i)
1509 if (!bNewLine)
1510 aBuf.append( ' ');
1511 aBuf.append( rComments[i].maComment);
1512 if (rComments[i].mbLastOnLine)
1514 aBuf.append( '\n');
1515 bNewLine = true;
1517 else
1518 bNewLine = false;
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)
1532 OUString aErrorMsg;
1534 std::vector< CommentStrip > aComments = getComment( m_sStatement);
1536 std::unique_ptr<::connectivity::OSQLParseNode> pNode = m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign );
1537 if(pNode)
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);
1549 showError(aInfo);
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()));
1558 else
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() )
1570 return nRet;
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,
1582 sMessageText));
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 )
1591 nRet = RET_CANCEL;
1594 return nRet;
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;
1625 bValid = true;
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!" );
1640 else
1642 bValid = true;
1643 // assume that we got all necessary information during initialization
1646 if ( bValid )
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() )
1663 setQueryComposer();
1665 bool bError( false );
1667 if ( !m_pSqlIterator )
1669 bError = true;
1671 else if ( m_bEscapeProcessing )
1673 OUString aErrorMsg;
1674 std::unique_ptr< ::connectivity::OSQLParseNode > pNode(
1675 m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign ) );
1677 if (pNode)
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() ) );
1688 bError = true;
1691 else
1693 if ( !i_bForceCurrentControllerSettings && !editingView() )
1695 OUString aTitle(DBA_RES(STR_SVT_SQL_SYNTAX_ERROR));
1696 OSQLMessageBox aDlg(getFrameWeld(), aTitle, aErrorMsg);
1697 aDlg.run();
1699 bError = true;
1703 if ( bError )
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 );
1713 if(!m_pSqlIterator)
1714 setQueryComposer();
1715 OSL_ENSURE(m_pSqlIterator,"No SQLIterator set!");
1717 getContainer()->setNoneVisibleRow(m_nVisibleRows);
1720 void OQueryController::reset()
1722 impl_reset();
1723 getContainer()->reset();
1724 ClearUndoManager();
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 )
1741 return;
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
1758 return true;
1761 bool OQueryController::allowQueries() const
1763 OSL_ENSURE( getSdbMetaData().isConnected(), "OQueryController::allowQueries: illegal call!" );
1764 if ( !getSdbMetaData().supportsSubqueriesInFrom() )
1765 return false;
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*/)
1787 // TODO
1790 } // namespace dbaui
1792 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */