LibreOffice Module dbaccess (master) 1
querycontroller.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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>
27#include <dlgsave.hxx>
29#include <querycontroller.hxx>
30#include <QueryDesignView.hxx>
31#include <QueryTableView.hxx>
32#include <sqlmessage.hxx>
35#include <UITools.hxx>
37
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>
56
59#include <comphelper/types.hxx>
63#include <svl/undo.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>
75
76extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
78 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
79{
80 return cppu::acquire(new ::dbaui::OQueryController(context));
81}
82
83namespace dbaui
84{
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;
90
91 namespace {
92
93 class OViewController : public OQueryController
94 {
95 virtual OUString SAL_CALL getImplementationName() override
96 {
97 return "org.openoffice.comp.dbu.OViewDesign";
98 }
99 virtual Sequence< OUString> SAL_CALL getSupportedServiceNames() override
100 {
101 return { "com.sun.star.sdb.ViewDesign" };
102 }
103
104 public:
105 explicit OViewController(const Reference< XComponentContext >& _rM) : OQueryController(_rM){}
106 };
107
108 }
109}
110
111extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
113 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
114{
115 return cppu::acquire(new ::dbaui::OViewController(context));
116}
117
118namespace dbaui
119{
120 using namespace ::connectivity;
121
122 namespace
123 {
124 OUString lcl_getObjectResourceString(TranslateId pResId, sal_Int32 _nCommandType)
125 {
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;
130 }
131 }
132
133using namespace ::com::sun::star::io;
134using namespace ::com::sun::star::container;
135using namespace ::com::sun::star::sdbcx;
136using namespace ::com::sun::star::sdbc;
137using namespace ::com::sun::star::sdb;
138using namespace ::com::sun::star::ui;
139using namespace ::com::sun::star::ui::dialogs;
140using namespace ::com::sun::star::awt;
141using namespace ::dbtools;
142
143using namespace ::comphelper;
144
145namespace
146{
147 void ensureToolbars( OQueryController& _rController, bool _bDesign )
148 {
149 Reference< css::frame::XLayoutManager > xLayoutManager = OGenericUnoController::getLayoutManager( _rController.getFrame() );
150 if ( !xLayoutManager.is() )
151 return;
152
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 )
157 {
158 xLayoutManager->destroyElement( s_sSqlToolbar );
159 xLayoutManager->createElement( s_sDesignToolbar );
160 }
161 else
162 {
163 xLayoutManager->destroyElement( s_sDesignToolbar );
164 xLayoutManager->createElement( s_sSqlToolbar );
165 }
166 xLayoutManager->unlock();
167 xLayoutManager->doLayout();
168 }
169
175 void grabFocusFromLimitBox( OQueryController& _rController )
176 {
177 Reference< XLayoutManager > xLayoutManager = OGenericUnoController::getLayoutManager( _rController.getFrame() );
178 Reference< XUIElement > xUIElement = xLayoutManager->getElement("private:resource/toolbar/designobjectbar");
179 if (xUIElement.is())
180 {
181 Reference< XWindow > xWindow(xUIElement->getRealInterface(), css::uno::UNO_QUERY);
182 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
183 if( pWindow && pWindow->HasChildPathFocus() )
184 {
185 pWindow->GrabFocusToDocument();
186 }
187 }
188 }
189}
190
192{
193 return "org.openoffice.comp.dbu.OQueryDesign";
194}
195
197{
198 return { "com.sun.star.sdb.QueryDesign" };
199}
200
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)
210 ,m_bGraphicalDesign(false)
211 ,m_bDistinct(false)
212 ,m_bEscapeProcessing(true)
213{
214 InvalidateAll();
215
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,
220}
221
223{
224 if ( !getBroadcastHelper().bDisposed && !getBroadcastHelper().bInDispose )
225 {
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();
230 }
231}
232
235
236Reference< XPropertySetInfo > SAL_CALL OQueryController::getPropertySetInfo()
237{
238 Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
239 return xInfo;
240}
241
242void SAL_CALL OQueryController::getFastPropertyValue( Any& o_rValue, sal_Int32 i_nHandle ) const
243{
244 switch ( i_nHandle )
245 {
247 {
249 aCurrentDesign.put( "GraphicalDesign", isGraphicalDesign() );
251
252 if ( isGraphicalDesign() )
253 {
255 saveViewSettings( aCurrentDesign, true );
256 aCurrentDesign.put( "Statement", m_sStatement );
257 }
258 else
259 {
260 aCurrentDesign.put( "Statement", getContainer()->getStatement() );
261 }
262
263 o_rValue <<= aCurrentDesign.getPropertyValues();
264 }
265 break;
266
267 default:
268 OPropertyContainer::getFastPropertyValue( o_rValue, i_nHandle );
269 break;
270 }
271}
272
274{
275 return *getArrayHelper();
276}
277
279{
281 describeProperties( aProps );
282
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",
291 PropertyAttribute::READONLY
292 );
293
294 std::sort(
295 pProps,
296 pProps + aProps.getLength(),
298 );
299
300 return new ::cppu::OPropertyArrayHelper(aProps);
301}
302
304{
306 {
307 delete m_pSqlIterator->getParseTree();
308 m_pSqlIterator->dispose();
309 m_pSqlIterator.reset();
310 }
311}
312
314{
315 OQueryController_PBase::disposing();
316
318
319 m_pParseContext.reset();
320
321 clearFields();
323
324 ::comphelper::disposeComponent(m_xComposer);
326 OQueryController_PBase::disposing();
327}
328
330{
332}
333
335{
336 FeatureState aReturn;
337 aReturn.bEnabled = true;
338 // (disabled automatically)
339
340 switch (_nId)
341 {
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;
350
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;
359 aReturn.bEnabled = !editingCommand() && (!m_bGraphicalDesign || !(m_vTableFieldDesc.empty() || m_vTableData.empty()));
360 break;
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:
371 break;
372 case ID_BROWSER_PASTE:
373 aReturn.bEnabled = isEditable() && getContainer() && getContainer()->isPasteAllowed();
374 break;
375 case ID_BROWSER_SQL:
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);
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:
394 if( aReturn.bEnabled )
395 aReturn.aValue <<= m_nLimit;
396 break;
397 case SID_QUERY_PROP_DLG:
399 break;
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
409 break;
411 break;
412#endif
414 if ( !m_bGraphicalDesign )
415 {
416 aReturn.bEnabled = false;
417 break;
418 }
419 [[fallthrough]];
420 default:
421 aReturn = OJoinController::GetState(_nId);
422 break;
423 }
424 return aReturn;
425}
426
427void OQueryController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
428{
429 switch(_nId)
430 {
433 if ( !editingView() )
434 setModified(true);
435 InvalidateFeature(ID_BROWSER_SQL);
436 break;
439 grabFocusFromLimitBox(*this);
441 break;
442 case SID_RELATION_ADD_RELATION:
443 {
444 OJoinDesignView* pView = getJoinView();
445 if( pView )
446 static_cast<OQueryTableView*>(pView->getTableView())->createNewConnection();
447 }
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:
461 {
462 grabFocusFromLimitBox(*this);
463 if ( !getContainer()->checkStatement() )
464 break;
465 SQLExceptionInfo aError;
466 try
467 {
469 if(m_sStatement.isEmpty() && m_pSqlIterator)
470 {
471 // change the view of the data
472 delete m_pSqlIterator->getParseTree();
473 m_pSqlIterator->setParseTree(nullptr);
475 impl_setViewMode( &aError );
476 }
477 else
478 {
479 OUString aErrorMsg;
480 std::unique_ptr<::connectivity::OSQLParseNode> pNode = m_aSqlParser.parseTree(aErrorMsg,m_sStatement,m_bGraphicalDesign);
481 if ( pNode )
482 {
483 assert(m_pSqlIterator && "SqlIterator must exist");
484 delete m_pSqlIterator->getParseTree();
485 m_pSqlIterator->setParseTree(pNode.release());
486 m_pSqlIterator->traverseAll();
487
488 if ( m_pSqlIterator->hasErrors() )
489 {
490 aError = m_pSqlIterator->getErrors();
491 }
492 else
493 {
494 const OSQLTables& rTabs = m_pSqlIterator->getTables();
495 if ( m_pSqlIterator->getStatementType() != OSQLStatementType::Select || rTabs.empty() )
496 {
497 aError = SQLException(
498 DBA_RES(STR_QRY_NOSELECT),
499 nullptr,
500 "S1000",
501 1000,
502 Any()
503 );
504 }
505 else
506 {
507 // change the view of the data
509 OUString sNewStatement;
510 m_pSqlIterator->getParseTree()->parseNodeToStr( sNewStatement, getConnection() );
511 setStatement_fireEvent( sNewStatement );
514 impl_setViewMode( &aError );
515 }
516 }
517 }
518 else
519 {
520 aError = SQLException(
521 DBA_RES(STR_QRY_SYNTAX),
522 nullptr,
523 "S1000",
524 1000,
525 Any()
526 );
527 }
528 }
529 }
530 catch(const SQLException&)
531 {
532 aError = ::cppu::getCaughtException();
533 }
534 catch(const Exception&)
535 {
536 DBG_UNHANDLED_EXCEPTION("dbaccess");
537 }
538
539 if ( aError.isValid() )
540 showError( aError );
541
543 {
544 InvalidateFeature(ID_BROWSER_ADDTABLE);
545 InvalidateFeature(SID_RELATION_ADD_RELATION);
546 }
547 }
548 break;
549 case SID_BROWSER_CLEAR_QUERY:
550 {
551 GetUndoManager().EnterListAction(DBA_RES(STR_QUERY_UNDO_TABWINDELETE), OUString(), 0, ViewShellId(-1) );
552 getContainer()->clear();
554
555 setStatement_fireEvent( OUString() );
557 InvalidateFeature(ID_BROWSER_ADDTABLE);
558 }
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:
568 setModified(true);
569 break;
570 case SID_QUERY_LIMIT:
571 if ( aArgs.hasElements() && aArgs[0].Name == "DBLimit.Value" )
572 {
573 aArgs[0].Value >>= m_nLimit;
574 setModified(true);
575 }
576 break;
577 case SID_QUERY_PROP_DLG:
578 grabFocusFromLimitBox(*this);
580 break;
582 grabFocusFromLimitBox(*this);
583 if ( getContainer()->checkStatement() )
584 executeQuery();
585 break;
586 case SID_DB_QUERY_PREVIEW:
587 try
588 {
589 Reference< css::util::XCloseable > xCloseFrame( getContainer()->getPreviewFrame(), UNO_QUERY );
590 if ( xCloseFrame.is() )
591 {
592 try
593 {
594 xCloseFrame->close( true );
595 }
596 catch(const Exception&)
597 {
598 OSL_FAIL( "OQueryController::Execute(SID_DB_QUERY_PREVIEW): *nobody* is expected to veto closing the preview frame!" );
599 }
600 }
601 else
603 }
604 catch(const Exception&)
605 {
606 }
607 break;
608 default:
609 OJoinController::Execute(_nId,aArgs);
610 return; // else we would invalidate twice
611 }
612 InvalidateFeature(_nId);
613}
614
615void OQueryController::impl_showAutoSQLViewError( const css::uno::Any& _rErrorDetails )
616{
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 );
623}
624
626{
627 OSL_PRECOND( getContainer(), "OQueryController::impl_setViewMode: illegal call!" );
628
629 bool wasModified = isModified();
630
631 SQLExceptionInfo aError;
632 bool bSuccess = getContainer()->switchView( &aError );
633 if ( !bSuccess )
634 {
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 );
644 }
645 else
646 {
647 ensureToolbars( *this, m_bGraphicalDesign );
648 }
649
650 setModified( wasModified );
651}
652
654{
655 OJoinController::impl_initialize();
656
657 const NamedValueCollection& rArguments( getInitParams() );
658
659 OUString sCommand;
661
662 // reading parameters:
663
664 // legacy parameters first (later overwritten by regular parameters)
665 OUString sIndependentSQLCommand;
666 if ( rArguments.get_ensureType( "IndependentSQLCommand", sIndependentSQLCommand ) )
667 {
668 OSL_FAIL( "OQueryController::impl_initialize: IndependentSQLCommand is regognized for compatibility only!" );
669 sCommand = sIndependentSQLCommand;
670 m_nCommandType = CommandType::COMMAND;
671 }
672
673 OUString sCurrentQuery;
674 if ( rArguments.get_ensureType( "CurrentQuery", sCurrentQuery ) )
675 {
676 OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" );
677 sCommand = sCurrentQuery;
679 }
680
681 bool bCreateView( false );
682 if ( rArguments.get_ensureType( "CreateView", bCreateView ) && bCreateView )
683 {
684 OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" );
686 }
687
688 // non-legacy parameters which overwrite the legacy parameters
689 rArguments.get_ensureType( PROPERTY_COMMAND, sCommand );
691
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 )
696 {
698 m_sName = sCommand;
699 break;
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();
710 }
711
712 // more legacy parameters
713 bool bGraphicalDesign( true );
714 if ( rArguments.get_ensureType( PROPERTY_QUERYDESIGNVIEW, bGraphicalDesign ) )
715 {
716 OSL_FAIL( "OQueryController::impl_initialize: QueryDesignView is regognized for compatibility only!" );
717 m_bGraphicalDesign = bGraphicalDesign;
718 }
719
720 // more non-legacy
722
723 bool bEscapeProcessing( true );
724 if ( rArguments.get_ensureType( PROPERTY_ESCAPE_PROCESSING, bEscapeProcessing ) )
725 {
726 setEscapeProcessing_fireEvent( bEscapeProcessing );
727
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;
731 }
732
733 // initial design
734 bool bForceInitialDesign = false;
735 Sequence< PropertyValue > aCurrentQueryDesignProps;
736 aCurrentQueryDesignProps = rArguments.getOrDefault( "CurrentQueryDesign", aCurrentQueryDesignProps );
737
738 if ( aCurrentQueryDesignProps.hasElements() )
739 {
740 ::comphelper::NamedValueCollection aCurrentQueryDesign( aCurrentQueryDesignProps );
741 if ( aCurrentQueryDesign.has( PROPERTY_GRAPHICAL_DESIGN ) )
742 {
744 }
745 if ( aCurrentQueryDesign.has( PROPERTY_ESCAPE_PROCESSING ) )
746 {
748 }
749 if ( aCurrentQueryDesign.has( "Statement" ) )
750 {
751 OUString sStatement;
752 aCurrentQueryDesign.get_ensureType( "Statement", sStatement );
753 aCurrentQueryDesign.remove( "Statement" );
754 setStatement_fireEvent( sStatement );
755 }
756
757 loadViewSettings( aCurrentQueryDesign );
758
759 bForceInitialDesign = true;
760 }
761
762 if ( !ensureConnected() )
763 { // we have no connection so what else should we do
764 m_bGraphicalDesign = false;
765 if ( editingView() )
766 {
767 connectionLostMessage();
768 throw SQLException();
769 }
770 }
771
772 // check the view capabilities
773 if ( isConnected() && editingView() )
774 {
775 Reference< XViewsSupplier > xViewsSup( getConnection(), UNO_QUERY );
777 if ( xViewsSup.is() )
778 xViews = xViewsSup->getViews();
779
780 if ( !xViews.is() )
781 { // we can't create views so we ask if the user wants to create a query instead
783 bool bClose = false;
784 {
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;
789 }
790 if ( bClose )
791 throw VetoException();
792 }
793
794 // now if we are to edit an existing view, check whether this is possible
795 if ( !m_sName.isEmpty() )
796 {
797 Any aView( xViews->getByName( m_sName ) );
798 // will throw if there is no such view
799 if ( !( aView >>= m_xAlterView ) )
800 {
801 throw IllegalArgumentException(
802 DBA_RES(STR_NO_ALTER_VIEW_SUPPORT),
803 *this,
804 1
805 );
806 }
807 }
808 }
809
810 OSL_ENSURE(getDataSource().is(),"OQueryController::impl_initialize: need a datasource!");
811
812 try
813 {
815 impl_reset( bForceInitialDesign );
816
817 SQLExceptionInfo aError;
818 const bool bAttemptedGraphicalDesign = m_bGraphicalDesign;
819
820 if ( bForceInitialDesign )
821 {
823 }
824 else
825 {
826 impl_setViewMode( &aError );
827 }
828
829 if ( aError.isValid() && bAttemptedGraphicalDesign && !m_bGraphicalDesign )
830 {
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() )
834 {
835 impl_showAutoSQLViewError( aError.get() );
836 }
837 }
838
840
842 && ( ( m_sName.isEmpty() && !editingCommand() )
843 || ( m_sStatement.isEmpty() && editingCommand() )
844 )
845 )
846 {
847 Application::PostUserEvent( LINK( this, OQueryController, OnExecuteAddTable ) );
848 }
849
850 setModified(false);
851 }
852 catch(const SQLException& e)
853 {
854 DBG_UNHANDLED_EXCEPTION("dbaccess");
855 // we caught an exception so we switch to text only mode
856 {
857 m_bGraphicalDesign = false;
859 OSQLMessageBox aBox(getFrameWeld(), e);
860 aBox.run();
861 }
862 throw;
863 }
864}
865
867{
868 ensureToolbars( *this, m_bGraphicalDesign );
869}
870
872{
873 if ( m_sName.isEmpty() )
874 {
875 if ( !editingCommand() )
876 {
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());
881 }
882 }
883 return m_sName;
884}
885
887{
888 if(!isConnected())
889 return;
890
892 OSL_ENSURE(xFactory.is(),"Connection doesn't support a querycomposer");
893 if ( !(xFactory.is() && getContainer()) )
894 return;
895
896 try
897 {
898 m_xComposer = xFactory->createQueryComposer();
900 }
901 catch(const Exception&)
902 {
903 m_xComposer = nullptr;
904 }
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 ));
909}
910
912{
913 // TODO: we have to check if we should create the text view or the design view
914
915 setView( VclPtr<OQueryContainerWindow>::Create( pParent, *this, getORB() ) );
916
917 return OJoinController::Construct(pParent);
918}
919
921{
922 return getContainer()->getDesignView();
923}
924
926{
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 );
941
942#if OSL_DEBUG_LEVEL > 0
943 implDescribeSupportedFeature( ".uno:DBShowParseTree", ID_EDIT_QUERY_SQL );
944 implDescribeSupportedFeature( ".uno:DBMakeDisjunct", ID_EDIT_QUERY_DESIGN );
945#endif
946}
947
949{
951 InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
952 InvalidateFeature(ID_BROWSER_SAVEASDOC);
953 InvalidateFeature(ID_BROWSER_QUERY_EXECUTE);
954}
955
956void SAL_CALL OQueryController::disposing( const EventObject& Source )
957{
958 SolarMutexGuard aGuard;
959
960 if ( getContainer() && Source.Source.is() )
961 {
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 );
966 }
967 else if ( Source.Source == getContainer()->getPreviewFrame() )
968 {
970 }
971 }
972
974}
975
977{
979 ::comphelper::disposeComponent(m_xComposer);
980
982
983 if (isConnected())
984 {
986 }
987 else
988 {
990 {
991 m_bGraphicalDesign = false;
992 // don't call Execute(SQL) because this changes the sql statement
993 impl_setViewMode( nullptr );
994 }
995 InvalidateAll();
996 }
997}
998
999void OQueryController::saveViewSettings( ::comphelper::NamedValueCollection& o_rViewSettings, const bool i_includingCriteria ) const
1000{
1001 saveTableWindows( o_rViewSettings );
1002
1005 sal_Int32 i = 1;
1006 for (auto const& fieldDesc : m_vTableFieldDesc)
1007 {
1008 if ( !fieldDesc->IsEmpty() )
1009 {
1010 aFieldData.clear();
1011 fieldDesc->Save( aFieldData, i_includingCriteria );
1012
1013 const OUString sFieldSettingName = "Field" + OUString::number( i );
1014 aAllFieldsData.put( sFieldSettingName, aFieldData.getPropertyValues() );
1015 }
1016 ++i;
1017 }
1018
1019 o_rViewSettings.put( "Fields", aAllFieldsData.getPropertyValues() );
1020 o_rViewSettings.put( "SplitterPosition", m_nSplitPos );
1021 o_rViewSettings.put( "VisibleRows", m_nVisibleRows );
1022}
1023
1024void OQueryController::loadViewSettings( const ::comphelper::NamedValueCollection& o_rViewSettings )
1025{
1026 loadTableWindows( o_rViewSettings );
1027
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 );
1031}
1032
1034{
1036
1037 if (aQueryPropDlg.run() == RET_OK)
1038 {
1039 m_bDistinct = aQueryPropDlg.getDistinct();
1040 m_nLimit = aQueryPropDlg.getLimit();
1041 InvalidateFeature( SID_QUERY_DISTINCT_VALUES );
1042 InvalidateFeature( SID_QUERY_LIMIT, nullptr, true );
1043 }
1044}
1045
1046sal_Int32 OQueryController::getColWidth(sal_uInt16 _nColPos) const
1047{
1048 if ( _nColPos < m_aFieldInformation.getLength() )
1049 {
1051 pField->Load( m_aFieldInformation[ _nColPos ], false );
1052 return pField->GetColWidth();
1053 }
1054 return 0;
1055}
1056
1058{
1059 Reference< XNameAccess > xElements;
1060 if ( editingView() )
1061 {
1062 Reference< XViewsSupplier > xViewsSupp( getConnection(), UNO_QUERY );
1063 if ( xViewsSupp.is() )
1064 xElements = xViewsSupp->getViews();
1065 }
1066 else
1067 {
1068 Reference< XQueriesSupplier > xQueriesSupp( getConnection(), UNO_QUERY );
1069 if ( xQueriesSupp.is() )
1070 xElements = xQueriesSupp->getQueries();
1071 else
1072 {
1073 Reference< XQueryDefinitionsSupplier > xQueryDefsSupp( getDataSource(), UNO_QUERY );
1074 if ( xQueryDefsSupp.is() )
1075 xElements = xQueryDefsSupp->getQueryDefinitions();
1076 }
1077 }
1078
1079 OSL_ENSURE( xElements.is(), "OQueryController::getObjectContainer: unable to obtain the container!" );
1080 return xElements;
1081}
1082
1084{
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 );
1088
1089 OUString sDataSourceName = getDataSourceName();
1090 if ( sDataSourceName.isEmpty() || sTranslatedStmt.isEmpty() )
1091 return;
1092
1093 try
1094 {
1095 getContainer()->showPreview( getFrame() );
1096 InvalidateFeature(SID_DB_QUERY_PREVIEW);
1097
1098 URL aWantToDispatch;
1099 aWantToDispatch.Complete = ".component:DB/DataSourceBrowser";
1100
1102 sal_Int32 nSearchFlags = FrameSearchFlag::CHILDREN;
1103
1105 Reference< XDispatchProvider> xProv( getFrame()->findFrame( sFrameName, nSearchFlags ), UNO_QUERY );
1106 if(!xProv.is())
1107 {
1108 xProv.set( getFrame(), UNO_QUERY );
1109 if (xProv.is())
1110 xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, nSearchFlags);
1111 }
1112 else
1113 {
1114 xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, FrameSearchFlag::SELF);
1115 }
1116 if (xDisp.is())
1117 {
1118 auto aProps(::comphelper::InitPropertySequence(
1119 {
1120 { PROPERTY_DATASOURCENAME, Any(sDataSourceName) },
1121 { PROPERTY_COMMAND_TYPE, Any(CommandType::COMMAND) },
1122 { PROPERTY_COMMAND, Any(sTranslatedStmt) },
1123 { PROPERTY_ENABLE_BROWSER, Any(false) },
1127 { PROPERTY_UPDATE_TABLENAME, Any(OUString()) },
1129 }));
1130
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())
1136 {
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);
1141 }
1142 }
1143 else
1144 {
1145 OSL_FAIL("Couldn't create a beamer window!");
1146 }
1147 }
1148 catch(const Exception&)
1149 {
1150 OSL_FAIL("Couldn't create a beamer window!");
1151 }
1152}
1153
1154bool OQueryController::askForNewName(const Reference<XNameAccess>& _xElements, bool _bSaveAs)
1155{
1156 OSL_ENSURE( !editingCommand(), "OQueryController::askForNewName: not to be called when designing an independent statement!" );
1157 if ( editingCommand() )
1158 return false;
1159
1160 OSL_PRECOND( _xElements.is(), "OQueryController::askForNewName: invalid container!" );
1161 if ( !_xElements.is() )
1162 return false;
1163
1164 bool bRet = true;
1165 bool bNew = _bSaveAs || !_xElements->hasByName( m_sName );
1166 if(bNew)
1167 {
1168 OUString aDefaultName;
1169 if (!m_sName.isEmpty())
1170 aDefaultName = m_sName;
1171 else
1172 {
1173 OUString sName = DBA_RES(editingView() ? STR_VIEW_TITLE : STR_QRY_TITLE);
1174 aDefaultName = ::dbtools::createUniqueName(_xElements, sName.getToken(0, ' '));
1175 }
1176
1178 OSaveAsDlg aDlg(
1179 getFrameWeld(),
1181 getORB(),
1182 getConnection(),
1183 aDefaultName,
1184 aNameChecker,
1186
1187 bRet = ( aDlg.run() == RET_OK );
1188 if ( bRet )
1189 {
1190 m_sName = aDlg.getName();
1191 if ( editingView() )
1192 {
1195 }
1196 }
1197 }
1198 return bRet;
1199}
1200
1202{
1203 OSL_ENSURE(isEditable(),"Slot ID_BROWSER_SAVEDOC should not be enabled!");
1204 if ( !editingCommand() && !haveDataSource() )
1205 {
1206 OUString aMessage(DBA_RES(STR_DATASOURCE_DELETED));
1207 OSQLWarningBox aBox(getFrameWeld(), aMessage);
1208 aBox.run();
1209 return false;
1210 }
1211
1213 if ( !xElements.is() )
1214 return false;
1215
1216 if ( !getContainer()->checkStatement() )
1217 return false;
1218
1219 OUString sTranslatedStmt = translateStatement();
1220 if ( editingCommand() )
1221 {
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;
1226 }
1227
1228 if ( sTranslatedStmt.isEmpty() )
1229 return false;
1230
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;
1236
1237 SQLExceptionInfo aInfo;
1238 bool bSuccess = false;
1239 bool bNew = false;
1240 try
1241 {
1242 bNew = _bSaveAs
1243 || ( !xElements->hasByName( m_sName ) );
1244
1246 if ( bNew ) // just to make sure the query already exists
1247 {
1248 // drop the query, in case it already exists
1249 if ( xElements->hasByName( m_sName ) )
1250 {
1251 Reference< XDrop > xNameCont( xElements, UNO_QUERY );
1252 if ( xNameCont.is() )
1253 xNameCont->dropByName( m_sName );
1254 else
1255 {
1256 Reference< XNameContainer > xCont( xElements, UNO_QUERY );
1257 if ( xCont.is() )
1258 xCont->removeByName( m_sName );
1259 }
1260 }
1261
1262 // create a new (empty, uninitialized) query resp. view
1263 Reference< XDataDescriptorFactory > xFact( xElements, UNO_QUERY );
1264 if ( xFact.is() )
1265 {
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 ) );
1269 }
1270 else
1271 {
1272 Reference< XSingleServiceFactory > xSingleFac( xElements, UNO_QUERY );
1273 if ( xSingleFac.is() )
1274 xQuery.set(xSingleFac->createInstance(), css::uno::UNO_QUERY);
1275 }
1276 }
1277 else
1278 {
1279 xElements->getByName( m_sName ) >>= xQuery;
1280 }
1281 if ( !xQuery.is() )
1282 throw RuntimeException();
1283
1284 // the new commands
1285 if ( editingView() && !bNew )
1286 {
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 );
1290 }
1291 else
1292 { // we're creating a query, or a *new* view
1293 xQuery->setPropertyValue( PROPERTY_COMMAND, Any( sTranslatedStmt ) );
1294
1295 if ( editingView() )
1296 {
1297 xQuery->setPropertyValue( PROPERTY_CATALOGNAME, Any( m_sUpdateCatalogName ) );
1298 xQuery->setPropertyValue( PROPERTY_SCHEMANAME, Any( m_sUpdateSchemaName ) );
1299 }
1300
1301 if ( editingQuery() )
1302 {
1303 xQuery->setPropertyValue( PROPERTY_UPDATE_TABLENAME, Any( OUString() ) );
1304 xQuery->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, css::uno::Any( m_bEscapeProcessing ) );
1305
1306 xQuery->setPropertyValue( PROPERTY_LAYOUTINFORMATION, getViewData() );
1307 }
1308 }
1309
1310 if ( bNew )
1311 {
1312 Reference< XAppend > xAppend( xElements, UNO_QUERY );
1313 if ( xAppend.is() )
1314 {
1315 xAppend->appendByDescriptor( xQuery );
1316 }
1317 else
1318 {
1319 Reference< XNameContainer > xCont( xElements, UNO_QUERY );
1320 if ( xCont.is() )
1321 xCont->insertByName( m_sName, Any( xQuery ) );
1322 }
1323
1324 if ( editingView() )
1325 {
1326 Reference< XPropertySet > xViewProps;
1327 if ( xElements->hasByName( m_sName ) )
1328 xViewProps.set( xElements->getByName( m_sName ), UNO_QUERY );
1329
1330 if ( !xViewProps.is() ) // correct name and try again
1331 m_sName = ::dbtools::composeTableName( getMetaData(), xQuery, ::dbtools::EComposeRule::InDataManipulation, false );
1332
1333 OSL_ENSURE( xElements->hasByName( m_sName ), "OQueryController::doSaveAsDoc: newly created view does not exist!" );
1334
1335 if ( xElements->hasByName( m_sName ) )
1336 m_xAlterView.set( xElements->getByName( m_sName ), UNO_QUERY );
1337
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());
1340 }
1341 Reference< XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY);
1342 if ( xEventListener.is() )
1343 {
1344 TitleChangedEvent aEvent;
1345 xEventListener->titleChanged(aEvent);
1346 }
1347 releaseNumberForComponent();
1348 }
1349
1350 setModified( false );
1351 bSuccess = true;
1352
1353 }
1354 catch(const SQLException&)
1355 {
1356 if ( !bNew )
1357 m_sName = sOriginalName;
1358 aInfo = SQLExceptionInfo( ::cppu::getCaughtException() );
1359 }
1360 catch(const Exception&)
1361 {
1362 DBG_UNHANDLED_EXCEPTION("dbaccess");
1363 if ( !bNew )
1364 m_sName = sOriginalName;
1365 }
1366
1367 showError( aInfo );
1368
1369 // if we successfully saved a view we were creating, then close the designer
1370 if ( bSuccess && editingView() && !m_xAlterView.is() )
1371 {
1372 closeTask();
1373 }
1374
1375 if ( bSuccess && editingView() )
1376 InvalidateFeature( ID_BROWSER_EDITDOC );
1377
1378 return bSuccess;
1379}
1380
1381namespace {
1382struct CommentStrip
1383{
1384 OUString maComment;
1386 CommentStrip( OUString sComment, bool bLastOnLine )
1387 : maComment(std::move( sComment)), mbLastOnLine( bLastOnLine) {}
1388};
1389
1390}
1391
1396static std::vector< CommentStrip > getComment( const OUString& rQuery )
1397{
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;
1404
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)
1413 {
1414 if (bComment2)
1415 {
1416 aBuf.append( &pCopy[i], 1);
1417 if ((i+1) < nQueryLen)
1418 {
1419 if (pCopy[i]=='*' && pCopy[i+1]=='/')
1420 {
1421 bComment2 = false;
1422 aBuf.append( &pCopy[++i], 1);
1423 aRet.emplace_back( aBuf.makeStringAndClear(), false);
1424 }
1425 }
1426 else
1427 {
1428 // comment can't close anymore, actually an error, but...
1429 aRet.emplace_back( aBuf.makeStringAndClear(), false);
1430 }
1431 continue;
1432 }
1433 if (pCopy[i] == '\n' || i == nQueryLen-1)
1434 {
1435 if (bComment)
1436 {
1437 if (i == nQueryLen-1 && pCopy[i] != '\n')
1438 aBuf.append( &pCopy[i], 1);
1439 aRet.emplace_back( aBuf.makeStringAndClear(), true);
1440 bComment = false;
1441 }
1442 else if (!aRet.empty())
1443 aRet.back().mbLastOnLine = true;
1444 }
1445 else if (!bComment)
1446 {
1447 if (pCopy[i] == '\"' && !bIsText2)
1448 bIsText1 = !bIsText1;
1449 else if (pCopy[i] == '\'' && !bIsText1)
1450 bIsText2 = !bIsText2;
1451 if (!bIsText1 && !bIsText2 && (i+1) < nQueryLen)
1452 {
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;
1457 }
1458 }
1459 if (bComment || bComment2)
1460 aBuf.append( &pCopy[i], 1);
1461 }
1462 return aRet;
1463}
1464
1473static OUString concatComment( const OUString& rQuery, const std::vector< CommentStrip >& rComments )
1474{
1475 // No comments => return query.
1476 if (rComments.empty())
1477 return rQuery;
1478
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)
1492 {
1493 aBuf.append( pBeg + nIndBeg, nIndLF - nIndBeg);
1494 do
1495 {
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);
1501 }
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)
1508 {
1509 if (!bNewLine)
1510 aBuf.append( ' ');
1511 aBuf.append( rComments[i].maComment);
1512 if (rComments[i].mbLastOnLine)
1513 {
1514 aBuf.append( '\n');
1515 bNewLine = true;
1516 }
1517 else
1518 bNewLine = false;
1519 }
1520 return aBuf.makeStringAndClear();
1521}
1522
1523OUString OQueryController::translateStatement( bool _bFireStatementChange )
1524{
1525 // now set the properties
1526 setStatement_fireEvent( getContainer()->getStatement(), _bFireStatementChange );
1527 OUString sTranslatedStmt;
1528 if(!m_sStatement.isEmpty() && m_xComposer.is() && m_bEscapeProcessing)
1529 {
1530 try
1531 {
1532 OUString aErrorMsg;
1533
1534 std::vector< CommentStrip > aComments = getComment( m_sStatement);
1535
1536 std::unique_ptr<::connectivity::OSQLParseNode> pNode = m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign );
1537 if(pNode)
1538 {
1539 pNode->parseNodeToStr( sTranslatedStmt, getConnection() );
1540 }
1541
1542 m_xComposer->setQuery(sTranslatedStmt);
1543 sTranslatedStmt = m_xComposer->getComposedQuery();
1544 sTranslatedStmt = concatComment( sTranslatedStmt, aComments);
1545 }
1546 catch(const SQLException& e)
1547 {
1549 showError(aInfo);
1550 // an error occurred so we clear the statement
1551 sTranslatedStmt.clear();
1552 }
1553 }
1554 else if(m_sStatement.isEmpty())
1555 {
1556 showError(SQLException(DBA_RES(STR_QRY_NOSELECT), nullptr, "S1000", 1000, Any()));
1557 }
1558 else
1559 sTranslatedStmt = m_sStatement;
1560
1561 return sTranslatedStmt;
1562}
1563
1565{
1566 SolarMutexGuard aSolarGuard;
1567 ::osl::MutexGuard aGuard( getMutex() );
1568 short nRet = RET_YES;
1569 if ( !isConnected() || !isModified() )
1570 return nRet;
1571
1572 if ( !m_bGraphicalDesign
1573 || ( !m_vTableFieldDesc.empty()
1574 && !m_vTableData.empty()
1575 )
1576 )
1577 {
1578 OUString sMessageText( lcl_getObjectResourceString( STR_QUERY_SAVEMODIFIED, m_nCommandType ) );
1579
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);
1585
1586 nRet = xQueryBox->run();
1587 if ( ( nRet == RET_YES )
1588 && !doSaveAsDoc( false )
1589 )
1590 {
1591 nRet = RET_CANCEL;
1592 }
1593 }
1594 return nRet;
1595}
1596
1597void OQueryController::impl_reset( const bool i_bForceCurrentControllerSettings )
1598{
1599 bool bValid = false;
1600
1601 Sequence< PropertyValue > aLayoutInformation;
1602 // get command from the query if a query name was supplied
1603 if ( !i_bForceCurrentControllerSettings && !editingCommand() )
1604 {
1605 if ( !m_sName.isEmpty() )
1606 {
1608 if ( xQueries.is() )
1609 {
1611 if( xQueries->hasByName( m_sName ) && ( xQueries->getByName( m_sName ) >>= xProp ) && xProp.is() )
1612 {
1613 OUString sNewStatement;
1614 xProp->getPropertyValue( PROPERTY_COMMAND ) >>= sNewStatement;
1615 setStatement_fireEvent( sNewStatement );
1616
1617 if ( editingQuery() )
1618 {
1619 bool bNewEscapeProcessing( true );
1620 xProp->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bNewEscapeProcessing;
1621 setEscapeProcessing_fireEvent( bNewEscapeProcessing );
1622 }
1623
1625 bValid = true;
1626
1627 try
1628 {
1629 if ( editingQuery() )
1630 xProp->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) >>= aLayoutInformation;
1631 }
1632 catch( const Exception& )
1633 {
1634 OSL_FAIL( "OQueryController::impl_reset: could not retrieve the layout information from the query!" );
1635 }
1636 }
1637 }
1638 }
1639 }
1640 else
1641 {
1642 bValid = true;
1643 // assume that we got all necessary information during initialization
1644 }
1645
1646 if ( bValid )
1647 {
1648 // load the layoutInformation
1649 if ( aLayoutInformation.hasElements() )
1650 {
1651 try
1652 {
1653 loadViewSettings( aLayoutInformation );
1654 }
1655 catch( const Exception& )
1656 {
1657 DBG_UNHANDLED_EXCEPTION("dbaccess");
1658 }
1659 }
1660
1661 if ( !m_sStatement.isEmpty() )
1662 {
1664
1665 bool bError( false );
1666
1667 if ( !m_pSqlIterator )
1668 {
1669 bError = true;
1670 }
1671 else if ( m_bEscapeProcessing )
1672 {
1673 OUString aErrorMsg;
1674 std::unique_ptr< ::connectivity::OSQLParseNode > pNode(
1676
1677 if (pNode)
1678 {
1679 delete m_pSqlIterator->getParseTree();
1680 m_pSqlIterator->setParseTree( pNode.release() );
1681 m_pSqlIterator->traverseAll();
1682 if ( m_pSqlIterator->hasErrors() )
1683 {
1684 if ( !i_bForceCurrentControllerSettings && m_bGraphicalDesign && !editingView() )
1685 {
1686 impl_showAutoSQLViewError( Any( m_pSqlIterator->getErrors() ) );
1687 }
1688 bError = true;
1689 }
1690 }
1691 else
1692 {
1693 if ( !i_bForceCurrentControllerSettings && !editingView() )
1694 {
1695 OUString aTitle(DBA_RES(STR_SVT_SQL_SYNTAX_ERROR));
1696 OSQLMessageBox aDlg(getFrameWeld(), aTitle, aErrorMsg);
1697 aDlg.run();
1698 }
1699 bError = true;
1700 }
1701 }
1702
1703 if ( bError )
1704 {
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"
1709 }
1710 }
1711 }
1712
1713 if(!m_pSqlIterator)
1715 OSL_ENSURE(m_pSqlIterator,"No SQLIterator set!");
1716
1718}
1719
1721{
1722 impl_reset();
1723 getContainer()->reset();
1725}
1726
1727void OQueryController::setStatement_fireEvent( const OUString& _rNewStatement, bool _bFireStatementChange )
1728{
1729 Any aOldValue( m_sStatement );
1730 m_sStatement = _rNewStatement;
1731 Any aNewValue( m_sStatement );
1732
1734 if ( _bFireStatementChange )
1735 fire( &nHandle, &aNewValue, &aOldValue, 1, false );
1736}
1737
1738void OQueryController::setEscapeProcessing_fireEvent( const bool _bEscapeProcessing )
1739{
1740 if ( _bEscapeProcessing == m_bEscapeProcessing )
1741 return;
1742
1743 Any aOldValue( m_bEscapeProcessing );
1744 m_bEscapeProcessing = _bEscapeProcessing;
1745 Any aNewValue( m_bEscapeProcessing );
1746
1748 fire( &nHandle, &aNewValue, &aOldValue, 1, false );
1749}
1750
1751IMPL_LINK_NOARG( OQueryController, OnExecuteAddTable, void*, void )
1752{
1754}
1755
1757{
1758 return true;
1759}
1760
1762{
1763 OSL_ENSURE( getSdbMetaData().isConnected(), "OQueryController::allowQueries: illegal call!" );
1764 if ( !getSdbMetaData().supportsSubqueriesInFrom() )
1765 return false;
1766
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;
1771}
1772
1774{
1775 ::osl::MutexGuard aGuard( getMutex() );
1776
1778
1780 saveViewSettings( aViewSettings, false );
1781
1782 return Any( aViewSettings.getPropertyValues() );
1783}
1784
1785void SAL_CALL OQueryController::restoreViewData(const Any& /*Data*/)
1786{
1787 // TODO
1788}
1789
1790} // namespace dbaui
1791
1792/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sName
constexpr OUStringLiteral sFrameName
AnyEventRef aEvent
#define ID_BROWSER_EDITDOC
Definition: browserids.hxx:26
#define ID_BROWSER_ADDTABLE
Definition: browserids.hxx:53
#define ID_BROWSER_SAVEDOC
Definition: browserids.hxx:32
#define ID_EDIT_QUERY_DESIGN
Definition: browserids.hxx:69
#define ID_BROWSER_SQL
Definition: browserids.hxx:82
#define ID_BROWSER_ESCAPEPROCESSING
Definition: browserids.hxx:93
#define ID_BROWSER_PASTE
Definition: browserids.hxx:29
#define ID_BROWSER_CUT
Definition: browserids.hxx:25
#define ID_BROWSER_SAVEASDOC
Definition: browserids.hxx:33
#define ID_EDIT_QUERY_SQL
Definition: browserids.hxx:71
#define ID_BROWSER_COPY
Definition: browserids.hxx:24
#define ID_BROWSER_QUERY_EXECUTE
Definition: browserids.hxx:90
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, const ILibreOfficeKitNotifier *pNotifier=nullptr)
size_t LeaveListAction()
virtual void EnterListAction(const OUString &rComment, const OUString &rRepeatComment, sal_uInt16 nId, ViewShellId nViewShellId)
static vcl::Window * GetWindow(const css::uno::Reference< css::awt::XWindow > &rxWindow)
bool has(const OUString &_rValueName) const
bool get_ensureType(const OUString &_rValueName, VALUE_TYPE &_out_rValue) const
bool remove(const OUString &_rValueName)
bool put(const OUString &_rValueName, const VALUE_TYPE &_rValue)
css::uno::Sequence< css::beans::PropertyValue > getPropertyValues() const
VALUE_TYPE getOrDefault(const OUString &_rValueName, const VALUE_TYPE &_rDefault) const
::cppu::IPropertyArrayHelper * getArrayHelper()
void describeProperties(css::uno::Sequence< css::beans::Property > &_rProps) const
void registerProperty(const OUString &_rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, void *_pPointerToMember, const css::uno::Type &_rMemberType)
virtual void SAL_CALL getFastPropertyValue(css::uno::Any &rValue, sal_Int32 nHandle) const override
std::unique_ptr< OSQLParseNode > parseTree(OUString &rErrorMessage, const OUString &rStatement, bool bInternational=false)
class implementing the IObjectNameCheck interface, and checking a given name for being valid as eithe...
static css::uno::Reference< css::frame::XLayoutManager > getLayoutManager(const css::uno::Reference< css::frame::XFrame > &_xFrame)
get the layout manager
void loadTableWindows(const ::comphelper::NamedValueCollection &i_rViewSettings)
loads the information for the windows.
virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue > &aArgs) override
void saveTableWindows(::comphelper::NamedValueCollection &o_rViewSettings) const
saves the TableWindows structure in a sequence of property values
virtual void reconnect(bool _bUI) override
virtual FeatureState GetState(sal_uInt16 nId) const override
virtual void impl_onModifyChanged() override
virtual void describeSupportedFeatures() override
virtual void SAL_CALL disposing() override
TTableConnectionData m_vTableConnectionData
TTableWindowData m_vTableData
OJoinTableView * getTableView() const
void setStatement(const OUString &_rsStatement)
void showPreview(const css::uno::Reference< css::frame::XFrame > &_xFrame)
void setSlotEnabled(sal_Int32 _nSlotId, bool _bEnable)
bool isSlotEnabled(sal_Int32 _nSlotId)
void setNoneVisibleRow(sal_Int32 _nRows)
const css::uno::Reference< css::frame::XFrame2 > & getPreviewFrame() const
bool switchView(::dbtools::SQLExceptionInfo *_pErrorInfo)
css::uno::Reference< css::container::XNameAccess > getObjectContainer() const
returns the container of queries, views, or command definitions, depending on what object type we des...
virtual OUString getPrivateTitle() const override
virtual FeatureState GetState(sal_uInt16 nId) const override
virtual bool allowQueries() const override
determines whether or not it's allowed for queries to participate in the game
virtual void SAL_CALL restoreViewData(const css::uno::Any &Data) override
OUString translateStatement(bool _bFireStatementChange=true)
virtual bool allowViews() const override
determines whether or not it's allowed for database views to participate in the game
virtual void onLoadedMenu(const css::uno::Reference< css::frame::XLayoutManager > &_xLayoutManager) override
void impl_setViewMode(::dbtools::SQLExceptionInfo *_pErrorInfo)
switches to the graphical or SQL view mode, as determined by m_bGraphicalDesign
::connectivity::OSQLParser m_aSqlParser
virtual short saveModified() override
virtual void impl_initialize() override
css::uno::Sequence< css::beans::PropertyValue > m_aFieldInformation
virtual bool Construct(vcl::Window *pParent) override
virtual OUString SAL_CALL getImplementationName() override
std::unique_ptr<::svxform::OSystemParseContext > m_pParseContext
void setEscapeProcessing_fireEvent(const bool _bEscapeProcessing)
sets the m_bEscapeProcessing member, and notifies our respective property change listeners
const OUString & getStatement() const
bool askForNewName(const css::uno::Reference< css::container::XNameAccess > &_xElements, bool _bSaveAs)
OQueryContainerWindow * getContainer() const
virtual ~OQueryController() override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
void saveViewSettings(::comphelper::NamedValueCollection &o_rViewSettings, const bool i_includingCriteria) const
void impl_reset(const bool i_bIgnoreQuerySettings=false)
std::unique_ptr<::connectivity::OSQLParseTreeIterator > m_pSqlIterator
virtual OJoinDesignView * getJoinView() override
provides access to the OJoinDesignView belonging to the controller, which might or might not be the d...
void loadViewSettings(const ::comphelper::NamedValueCollection &o_rViewSettings)
css::uno::Reference< css::sdb::XSQLQueryComposer > m_xComposer
virtual void impl_onModifyChanged() override
bool doSaveAsDoc(bool _bSaveAs)
virtual void describeSupportedFeatures() override
virtual css::uno::Any SAL_CALL getViewData() override
virtual void SAL_CALL getFastPropertyValue(css::uno::Any &rValue, sal_Int32 nHandle) const override
sal_Int32 getColWidth(sal_uInt16 _nColPos) const
virtual void reset() override
OTableFields m_vUnUsedFieldsDesc
void impl_showAutoSQLViewError(const css::uno::Any &_rErrorDetails)
tells the user that we needed to switch to SQL view automatically
virtual ::cppu::IPropertyArrayHelper * createArrayHelper() const override
virtual void reconnect(bool _bUI) override
virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue > &aArgs) override
OQueryController(const css::uno::Reference< css::uno::XComponentContext > &_rM)
css::uno::Reference< css::sdbcx::XAlterView > m_xAlterView
if we're editing an existing view, this is non-NULL
void setStatement_fireEvent(const OUString &_rNewStatement, bool _bFireStatementChange=true)
sets m_sStatement, and notifies our respective property change listeners
virtual void SAL_CALL disposing() override
virtual ::cppu::IPropertyArrayHelper &SAL_CALL getInfoHelper() override
const OUString & getName() const
Definition: dlgsave.cxx:276
OUString getSchema() const
Definition: dlgsave.cxx:284
OUString getCatalog() const
Definition: dlgsave.cxx:280
virtual void SAL_CALL disposing() override
SfxUndoManager & GetUndoManager() const
need for undo's and redo's
void ClearUndoManager()
complete clears the Undo/Redo stacks
Dialog to set such properties of a query as distinct values and limit It can be opened from Edit menu...
const css::uno::Any & get() const
virtual short run()
sal_Int32 m_nCommandType
#define DBA_RES(id)
#define DBG_UNHANDLED_EXCEPTION(...)
weld::Window * GetFrameWeld(const SfxFrame *pFrame)
ULONG m_refCount
float u
Reference< XSingleServiceFactory > xFactory
aBuf
@ Exception
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
std::map< OUString, OSQLTable, comphelper::UStringMixLess > OSQLTables
css::uno::Reference< css::uno::XInterface > getDataSource(const css::uno::Reference< css::uno::XInterface > &_rxDependentObject)
IMPL_LINK_NOARG(OApplicationController, OnClipboardChanged, TransferableDataHelper *, void)
static OUString concatComment(const OUString &rQuery, const std::vector< CommentStrip > &rComments)
Concat/insert comments that were previously obtained with getComment().
std::vector< OTableFieldDescRef > OTableFields
bool appendToFilter(const css::uno::Reference< css::sdbc::XConnection > &xConnection, const OUString &rName, const css::uno::Reference< css::uno::XComponentContext > &rxContext, weld::Window *pParent)
append a name to tablefilter of a datasource
static std::vector< CommentStrip > getComment(const OUString &rQuery)
Obtain all comments in a query.
Reference< XConnection > getConnection(const Reference< XRowSet > &_rxRowSet)
void showError(const SQLExceptionInfo &_rInfo, const Reference< XWindow > &_xParent, const Reference< XComponentContext > &_rxContext)
::osl::Mutex & getMutex()
int i
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
const ::avmedia::MediaItem * Execute(const SdrMarkView *pSdrView, SfxRequest const &rReq)
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
void dispose()
OUString maComment
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * org_openoffice_comp_dbu_OViewDesign_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * org_openoffice_comp_dbu_OQueryDesign_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
bool mbLastOnLine
sal_Int32 nHandle
IMPLEMENT_FORWARD_XTYPEPROVIDER2(OStatement, OStatementBase, OStatement_IFACE)
IMPLEMENT_FORWARD_XINTERFACE2(OStatement, OStatementBase, OStatement_IFACE)
OUString VCL_DLLPUBLIC GetStandardText(StandardButtonType eButton)
#define PROPERTY_ID_ESCAPE_PROCESSING
#define PROPERTY_ID_ACTIVECOMMAND
#define PROPERTY_ID_CURRENT_QUERY_DESIGN
constexpr OUStringLiteral PROPERTY_COMMAND(u"Command")
constexpr OUStringLiteral PROPERTY_UPDATE_TABLENAME(u"UpdateTableName")
constexpr OUStringLiteral FRAME_NAME_QUERY_PREVIEW
Definition: strings.hxx:256
constexpr OUStringLiteral PROPERTY_QUERYDESIGNVIEW(u"QueryDesignView")
constexpr OUStringLiteral PROPERTY_UPDATE_SCHEMANAME(u"UpdateSchemaName")
constexpr OUStringLiteral PROPERTY_SCHEMANAME(u"SchemaName")
constexpr OUStringLiteral PROPERTY_ACTIVE_CONNECTION(u"ActiveConnection")
constexpr OUStringLiteral PROPERTY_ESCAPE_PROCESSING(u"EscapeProcessing")
constexpr OUStringLiteral PROPERTY_CATALOGNAME(u"CatalogName")
constexpr OUStringLiteral PROPERTY_ENABLE_BROWSER(u"EnableBrowser")
constexpr OUStringLiteral PROPERTY_NAME(u"Name")
constexpr OUStringLiteral PROPERTY_UPDATE_CATALOGNAME(u"UpdateCatalogName")
constexpr OUStringLiteral PROPERTY_LAYOUTINFORMATION(u"LayoutInformation")
constexpr OUStringLiteral PROPERTY_DATASOURCENAME(u"DataSourceName")
constexpr OUStringLiteral PROPERTY_ACTIVECOMMAND(u"ActiveCommand")
constexpr OUStringLiteral PROPERTY_GRAPHICAL_DESIGN(u"GraphicalDesign")
constexpr OUStringLiteral PROPERTY_COMMAND_TYPE(u"CommandType")
describes the state of a feature
std::optional< bool > bChecked
sal_uInt16 sal_Unicode
RET_OK
RET_CANCEL
RET_NO
RET_YES
QUERY
sal_Int32 nLength