Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / dbaccess / source / ui / querydesign / querycontroller.cxx
blobdfa1db928d8dfeab357631346320c8fe67c0c4e4
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 "adtabdlg.hxx"
21 #include "browserids.hxx"
22 #include "dbu_qry.hrc"
23 #include "dbu_reghelper.hxx"
24 #include "dbustrings.hrc"
25 #include "defaultobjectnamecheck.hxx"
26 #include "dlgsave.hxx"
27 #include "localresaccess.hxx"
28 #include "uiservices.hxx"
29 #include "QTableWindow.hxx"
30 #include "QTableWindowData.hxx"
31 #include "querycontainerwindow.hxx"
32 #include "querycontroller.hxx"
33 #include "QueryDesignView.hxx"
34 #include "QueryTableView.hxx"
35 #include "QueryTextView.hxx"
36 #include "queryview.hxx"
37 #include "QueryViewSwitch.hxx"
38 #include "sqlmessage.hxx"
39 #include "TableConnectionData.hxx"
40 #include "TableFieldDescription.hxx"
41 #include "UITools.hxx"
42 #include "QueryPropertiesDialog.hxx"
44 #include <com/sun/star/beans/PropertyAttribute.hpp>
45 #include <com/sun/star/container/XChild.hpp>
46 #include <com/sun/star/container/XNameContainer.hpp>
47 #include <com/sun/star/frame/FrameSearchFlag.hpp>
48 #include <com/sun/star/frame/XLoadEventListener.hpp>
49 #include <com/sun/star/io/XActiveDataSink.hpp>
50 #include <com/sun/star/io/XActiveDataSource.hpp>
51 #include <com/sun/star/sdb/CommandType.hpp>
52 #include <com/sun/star/sdb/SQLContext.hpp>
53 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
54 #include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
55 #include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
56 #include <com/sun/star/sdbc/SQLWarning.hpp>
57 #include <com/sun/star/sdbc/XRow.hpp>
58 #include <com/sun/star/sdbcx/XAppend.hpp>
59 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
60 #include <com/sun/star/sdbcx/XDrop.hpp>
61 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
62 #include <com/sun/star/sdbcx/XViewsSupplier.hpp>
63 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
64 #include <com/sun/star/util/XCloseable.hpp>
65 #include <com/sun/star/util/VetoException.hpp>
66 #include <com/sun/star/frame/XUntitledNumbers.hpp>
67 #include <com/sun/star/ui/XUIElement.hpp>
69 #include <comphelper/propertysequence.hxx>
70 #include <comphelper/processfactory.hxx>
71 #include <comphelper/property.hxx>
72 #include <comphelper/seqstream.hxx>
73 #include <comphelper/streamsection.hxx>
74 #include <comphelper/types.hxx>
75 #include <connectivity/dbexception.hxx>
76 #include <connectivity/dbtools.hxx>
77 #include <cppuhelper/exc_hlp.hxx>
78 #include <sfx2/sfxsids.hrc>
79 #include <svtools/localresaccess.hxx>
80 #include <toolkit/helper/vclunohelper.hxx>
81 #include <tools/diagnose_ex.h>
82 #include <osl/diagnose.h>
83 #include <vcl/msgbox.hxx>
84 #include <vcl/svapp.hxx>
85 #include <osl/mutex.hxx>
86 #include <rtl/strbuf.hxx>
87 #include <vector>
89 extern "C" void SAL_CALL createRegistryInfo_OQueryControl()
91 static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OQueryController > aAutoRegistration;
94 namespace dbaui
96 using namespace ::com::sun::star::uno;
97 using namespace ::com::sun::star::beans;
98 using namespace ::com::sun::star::frame;
99 using namespace ::com::sun::star::util;
100 using namespace ::com::sun::star::lang;
102 class OViewController : public OQueryController
104 virtual OUString SAL_CALL getImplementationName() throw( RuntimeException, std::exception ) override
106 return getImplementationName_Static();
108 virtual Sequence< OUString> SAL_CALL getSupportedServiceNames() throw(RuntimeException, std::exception) override
110 return getSupportedServiceNames_Static();
113 public:
114 explicit OViewController(const Reference< XComponentContext >& _rM) : OQueryController(_rM){}
116 // need by registration
117 static OUString getImplementationName_Static() throw( RuntimeException )
119 return OUString("org.openoffice.comp.dbu.OViewDesign");
121 static Sequence< OUString > getSupportedServiceNames_Static() throw( RuntimeException )
123 Sequence<OUString> aSupported { "com.sun.star.sdb.ViewDesign" };
124 return aSupported;
126 static Reference< XInterface > SAL_CALL Create(const Reference< XMultiServiceFactory >& _rM)
128 return *(new OViewController(comphelper::getComponentContext(_rM)));
133 extern "C" void SAL_CALL createRegistryInfo_OViewControl()
135 static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OViewController > aAutoRegistration;
138 namespace dbaui
140 using namespace ::connectivity;
141 #if OSL_DEBUG_LEVEL > 0
142 namespace
144 void insertParseTree(SvTreeListBox* _pBox,::connectivity::OSQLParseNode* _pNode,SvTreeListEntry* _pParent = nullptr)
146 OUString rString;
147 if (!_pNode->isToken())
149 // rule name as rule: ...
150 rString = "RULE_ID: " + OUString::number( (sal_Int32)_pNode->getRuleID() ) +
151 "(" + OSQLParser::RuleIDToStr(_pNode->getRuleID()) + ")";
153 _pParent = _pBox->InsertEntry(rString,_pParent);
155 // determine how much subtrees this node has
156 sal_uInt32 nStop = _pNode->count();
157 // fetch first subtree
158 for(sal_uInt32 i=0;i<nStop;++i)
159 insertParseTree(_pBox,_pNode->getChild(i),_pParent);
161 else
163 // token found
164 // tabs to insert according to nLevel
166 switch (_pNode->getNodeType())
169 case SQLNodeType::Keyword:
171 rString += "SQL_KEYWORD:";
172 OString sT = OSQLParser::TokenIDToStr(_pNode->getTokenID());
173 rString += OStringToOUString(sT, RTL_TEXTENCODING_UTF8);
174 break;}
176 case SQLNodeType::Comparison:
178 rString += "SQL_COMPARISON:" + _pNode->getTokenValue(); // append Nodevalue
179 // and start new line
180 break;}
182 case SQLNodeType::Name:
184 rString += "SQL_NAME:\"" + _pNode->getTokenValue() + "\"";
185 break;}
187 case SQLNodeType::String:
189 rString += "SQL_STRING:'" + _pNode->getTokenValue();
190 break;}
192 case SQLNodeType::IntNum:
194 rString += "SQL_INTNUM:" + _pNode->getTokenValue();
195 break;}
197 case SQLNodeType::ApproxNum:
199 rString += "SQL_APPROXNUM:" + _pNode->getTokenValue();
200 break;}
202 case SQLNodeType::Punctuation:
204 rString += "SQL_PUNCTUATION:" + _pNode->getTokenValue(); // append Nodevalue
205 break;}
207 case SQLNodeType::AMMSC:
209 rString += "SQL_AMMSC:" + _pNode->getTokenValue(); // append Nodevalue
210 break;}
212 default:
213 OSL_FAIL("OSQLParser::ShowParseTree: unzulaessiger NodeType");
214 rString += _pNode->getTokenValue();
216 _pBox->InsertEntry(rString,_pParent);
220 #endif // OSL_DEBUG_LEVEL
222 namespace
224 OUString lcl_getObjectResourceString( sal_uInt16 _nResId, sal_Int32 _nCommandType )
226 OUString sMessageText = ModuleRes( _nResId );
227 OUString sObjectType;
229 LocalResourceAccess aLocalRes( RSC_QUERY_OBJECT_TYPE, RSC_RESOURCE );
230 sObjectType = ModuleRes( (sal_uInt16)( _nCommandType + 1 ) );
232 sMessageText = sMessageText.replaceFirst( "$object$", sObjectType );
233 return sMessageText;
237 using namespace ::com::sun::star::uno;
238 using namespace ::com::sun::star::io;
239 using namespace ::com::sun::star::beans;
240 using namespace ::com::sun::star::frame;
241 using namespace ::com::sun::star::util;
242 using namespace ::com::sun::star::lang;
243 using namespace ::com::sun::star::container;
244 using namespace ::com::sun::star::sdbcx;
245 using namespace ::com::sun::star::sdbc;
246 using namespace ::com::sun::star::sdb;
247 using namespace ::com::sun::star::ui;
248 using namespace ::com::sun::star::ui::dialogs;
249 using namespace ::com::sun::star::awt;
250 using namespace ::dbtools;
252 using namespace ::comphelper;
254 namespace
256 void ensureToolbars( OQueryController& _rController, bool _bDesign )
258 Reference< css::frame::XLayoutManager > xLayoutManager = OGenericUnoController::getLayoutManager( _rController.getFrame() );
259 if ( xLayoutManager.is() )
261 xLayoutManager->lock();
262 static const char s_sDesignToolbar[] = "private:resource/toolbar/designobjectbar";
263 static const char s_sSqlToolbar[] = "private:resource/toolbar/sqlobjectbar";
264 if ( _bDesign )
266 xLayoutManager->destroyElement( s_sSqlToolbar );
267 xLayoutManager->createElement( s_sDesignToolbar );
269 else
271 xLayoutManager->destroyElement( s_sDesignToolbar );
272 xLayoutManager->createElement( s_sSqlToolbar );
274 xLayoutManager->unlock();
275 xLayoutManager->doLayout();
280 * The value of m_nLimit is updated when LimitBox loses its focus
281 * So in those case when execution needs recent data, grab the focus
282 * (e.g. execute SQL statement, change views)
284 void grabFocusFromLimitBox( OQueryController& _rController )
286 static const char sResourceURL[] = "private:resource/toolbar/designobjectbar";
287 Reference< XLayoutManager > xLayoutManager = OGenericUnoController::getLayoutManager( _rController.getFrame() );
288 Reference< XUIElement > xUIElement = xLayoutManager->getElement(sResourceURL);
289 if (xUIElement.is())
291 Reference< XWindow > xWindow(xUIElement->getRealInterface(), css::uno::UNO_QUERY);
292 vcl::Window* pWindow = VCLUnoHelper::GetWindow( xWindow );
293 if( pWindow && pWindow->HasChildPathFocus() )
295 pWindow->GrabFocusToDocument();
301 OUString SAL_CALL OQueryController::getImplementationName() throw( RuntimeException, std::exception )
303 return getImplementationName_Static();
306 OUString OQueryController::getImplementationName_Static() throw( RuntimeException )
308 return OUString("org.openoffice.comp.dbu.OQueryDesign");
311 Sequence< OUString> OQueryController::getSupportedServiceNames_Static() throw( RuntimeException )
313 Sequence<OUString> aSupported { "com.sun.star.sdb.QueryDesign" };
314 return aSupported;
317 Sequence< OUString> SAL_CALL OQueryController::getSupportedServiceNames() throw(RuntimeException, std::exception)
319 return getSupportedServiceNames_Static();
322 Reference< XInterface > SAL_CALL OQueryController::Create(const Reference<XMultiServiceFactory >& _rxFactory)
324 return *(new OQueryController(comphelper::getComponentContext(_rxFactory)));
327 OQueryController::OQueryController(const Reference< XComponentContext >& _rM)
328 :OJoinController(_rM)
329 ,OQueryController_PBase( getBroadcastHelper() )
330 ,m_pParseContext( new svxform::OSystemParseContext )
331 ,m_aSqlParser( _rM, m_pParseContext )
332 ,m_pSqlIterator(nullptr)
333 ,m_nLimit(-1)
334 ,m_nVisibleRows(0x400)
335 ,m_nSplitPos(-1)
336 ,m_nCommandType( CommandType::QUERY )
337 ,m_bGraphicalDesign(false)
338 ,m_bDistinct(false)
339 ,m_bEscapeProcessing(true)
341 InvalidateAll();
343 registerProperty( PROPERTY_ACTIVECOMMAND, PROPERTY_ID_ACTIVECOMMAND, PropertyAttribute::READONLY | PropertyAttribute::BOUND,
344 &m_sStatement, cppu::UnoType<decltype(m_sStatement)>::get() );
345 registerProperty( PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::READONLY | PropertyAttribute::BOUND,
346 &m_bEscapeProcessing, cppu::UnoType<decltype(m_bEscapeProcessing)>::get() );
349 OQueryController::~OQueryController()
351 if ( !getBroadcastHelper().bDisposed && !getBroadcastHelper().bInDispose )
353 OSL_FAIL("Please check who doesn't dispose this component!");
354 // increment ref count to prevent double call of Dtor
355 osl_atomic_increment( &m_refCount );
356 dispose();
360 IMPLEMENT_FORWARD_XINTERFACE2( OQueryController, OJoinController, OQueryController_PBase )
361 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OQueryController, OJoinController, OQueryController_PBase )
363 Reference< XPropertySetInfo > SAL_CALL OQueryController::getPropertySetInfo() throw(RuntimeException, std::exception)
365 Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
366 return xInfo;
369 sal_Bool SAL_CALL OQueryController::convertFastPropertyValue( Any& o_rConvertedValue, Any& o_rOldValue, sal_Int32 i_nHandle, const Any& i_rValue ) throw (IllegalArgumentException)
371 return OPropertyContainer::convertFastPropertyValue( o_rConvertedValue, o_rOldValue, i_nHandle, i_rValue );
374 void SAL_CALL OQueryController::setFastPropertyValue_NoBroadcast( sal_Int32 i_nHandle, const Any& i_rValue ) throw ( Exception, std::exception )
376 OPropertyContainer::setFastPropertyValue_NoBroadcast( i_nHandle, i_rValue );
379 void SAL_CALL OQueryController::getFastPropertyValue( Any& o_rValue, sal_Int32 i_nHandle ) const
381 switch ( i_nHandle )
383 case PROPERTY_ID_CURRENT_QUERY_DESIGN:
385 ::comphelper::NamedValueCollection aCurrentDesign;
386 aCurrentDesign.put( "GraphicalDesign", isGraphicalDesign() );
387 aCurrentDesign.put( OUString(PROPERTY_ESCAPE_PROCESSING), m_bEscapeProcessing );
389 if ( isGraphicalDesign() )
391 getContainer()->SaveUIConfig();
392 saveViewSettings( aCurrentDesign, true );
393 aCurrentDesign.put( "Statement", m_sStatement );
395 else
397 aCurrentDesign.put( "Statement", getContainer()->getStatement() );
400 o_rValue <<= aCurrentDesign.getPropertyValues();
402 break;
404 default:
405 OPropertyContainer::getFastPropertyValue( o_rValue, i_nHandle );
406 break;
410 ::cppu::IPropertyArrayHelper& OQueryController::getInfoHelper()
412 return *getArrayHelper();
415 ::cppu::IPropertyArrayHelper* OQueryController::createArrayHelper( ) const
417 Sequence< Property > aProps;
418 describeProperties( aProps );
420 // one additional property:
421 const sal_Int32 nLength = aProps.getLength();
422 aProps.realloc( nLength + 1 );
423 aProps[ nLength ] = Property(
424 "CurrentQueryDesign",
425 PROPERTY_ID_CURRENT_QUERY_DESIGN,
426 ::cppu::UnoType< Sequence< PropertyValue > >::get(),
427 PropertyAttribute::READONLY
430 ::std::sort(
431 aProps.getArray(),
432 aProps.getArray() + aProps.getLength(),
433 ::comphelper::PropertyCompareByName()
436 return new ::cppu::OPropertyArrayHelper(aProps);
439 void OQueryController::deleteIterator()
441 if(m_pSqlIterator)
443 delete m_pSqlIterator->getParseTree();
444 m_pSqlIterator->dispose();
445 delete m_pSqlIterator;
446 m_pSqlIterator = nullptr;
450 void OQueryController::disposing()
452 OQueryController_PBase::disposing();
454 deleteIterator();
456 delete m_pParseContext;
458 clearFields();
459 OTableFields().swap(m_vUnUsedFieldsDesc);
461 ::comphelper::disposeComponent(m_xComposer);
462 OJoinController::disposing();
463 OQueryController_PBase::disposing();
466 void OQueryController::clearFields()
468 OTableFields().swap(m_vTableFieldDesc);
471 FeatureState OQueryController::GetState(sal_uInt16 _nId) const
473 FeatureState aReturn;
474 aReturn.bEnabled = true;
475 // (disabled automatically)
477 switch (_nId)
479 case ID_BROWSER_EDITDOC:
480 if ( editingCommand() )
481 aReturn.bEnabled = false;
482 else if ( editingView() && !m_xAlterView.is() )
483 aReturn.bEnabled = false;
484 else
485 aReturn = OJoinController::GetState( _nId );
486 break;
488 case ID_BROWSER_ESCAPEPROCESSING:
489 aReturn.bChecked = !m_bEscapeProcessing;
490 aReturn.bEnabled = ( m_pSqlIterator != nullptr ) && !m_bGraphicalDesign;
491 break;
492 case SID_RELATION_ADD_RELATION:
493 aReturn.bEnabled = isEditable() && m_bGraphicalDesign && m_vTableData.size() > 1;
494 break;
495 case ID_BROWSER_SAVEASDOC:
496 aReturn.bEnabled = !editingCommand() && !editingView() && (!m_bGraphicalDesign || !(m_vTableFieldDesc.empty() || m_vTableData.empty()));
497 break;
498 case ID_BROWSER_SAVEDOC:
499 aReturn.bEnabled = isEditable() && (!m_bGraphicalDesign || !(m_vTableFieldDesc.empty() || m_vTableData.empty()));
500 break;
501 case SID_PRINTDOCDIRECT:
502 break;
503 case ID_BROWSER_CUT:
504 aReturn.bEnabled = isEditable() && getContainer() && getContainer()->isCutAllowed();
505 break;
506 case ID_BROWSER_COPY:
507 aReturn.bEnabled = getContainer() && getContainer()->isCopyAllowed();
508 break;
509 case ID_BROWSER_PASTE:
510 aReturn.bEnabled = isEditable() && getContainer() && getContainer()->isPasteAllowed();
511 break;
512 case ID_BROWSER_SQL:
513 aReturn.bEnabled = m_bEscapeProcessing && m_pSqlIterator;
514 aReturn.bChecked = m_bGraphicalDesign;
515 break;
516 case SID_BROWSER_CLEAR_QUERY:
517 aReturn.bEnabled = isEditable() && (!m_sStatement.isEmpty() || !m_vTableData.empty());
518 break;
519 case SID_QUERY_VIEW_FUNCTIONS:
520 case SID_QUERY_VIEW_TABLES:
521 case SID_QUERY_VIEW_ALIASES:
522 aReturn.bChecked = getContainer() && getContainer()->isSlotEnabled(_nId);
523 aReturn.bEnabled = m_bGraphicalDesign;
524 break;
525 case SID_QUERY_DISTINCT_VALUES:
526 aReturn.bEnabled = m_bGraphicalDesign && isEditable();
527 aReturn.bChecked = m_bDistinct;
528 break;
529 case SID_QUERY_LIMIT:
530 aReturn.bEnabled = m_bGraphicalDesign;
531 if( aReturn.bEnabled )
532 aReturn.aValue = makeAny( m_nLimit );
533 break;
534 case SID_QUERY_PROP_DLG:
535 aReturn.bEnabled = m_bGraphicalDesign;
536 break;
537 case ID_BROWSER_QUERY_EXECUTE:
538 aReturn.bEnabled = true;
539 break;
540 case SID_DB_QUERY_PREVIEW:
541 aReturn.bEnabled = true;
542 aReturn.bChecked = getContainer() && getContainer()->getPreviewFrame().is();
543 break;
544 #if OSL_DEBUG_LEVEL > 0
545 case ID_EDIT_QUERY_SQL:
546 break;
547 case ID_EDIT_QUERY_DESIGN:
548 break;
549 #endif
550 case ID_BROWSER_ADDTABLE:
551 if ( !m_bGraphicalDesign )
553 aReturn.bEnabled = false;
554 break;
556 SAL_FALLTHROUGH;
557 default:
558 aReturn = OJoinController::GetState(_nId);
559 break;
561 return aReturn;
564 void OQueryController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
566 switch(_nId)
568 case ID_BROWSER_ESCAPEPROCESSING:
569 setEscapeProcessing_fireEvent( !m_bEscapeProcessing );
570 if ( !editingView() )
571 setModified(true);
572 InvalidateFeature(ID_BROWSER_SQL);
573 break;
574 case ID_BROWSER_SAVEASDOC:
575 case ID_BROWSER_SAVEDOC:
576 grabFocusFromLimitBox(*this);
577 doSaveAsDoc(ID_BROWSER_SAVEASDOC == _nId);
578 break;
579 case SID_RELATION_ADD_RELATION:
581 OJoinDesignView* pView = getJoinView();
582 if( pView )
583 static_cast<OQueryTableView*>(pView->getTableView())->createNewConnection();
585 break;
586 case SID_PRINTDOCDIRECT:
587 break;
588 case ID_BROWSER_CUT:
589 getContainer()->cut();
590 break;
591 case ID_BROWSER_COPY:
592 getContainer()->copy();
593 break;
594 case ID_BROWSER_PASTE:
595 getContainer()->paste();
596 break;
597 case ID_BROWSER_SQL:
599 grabFocusFromLimitBox(*this);
600 if ( !getContainer()->checkStatement() )
601 break;
602 SQLExceptionInfo aError;
605 OUString aErrorMsg;
606 setStatement_fireEvent( getContainer()->getStatement() );
607 if(m_sStatement.isEmpty() && m_pSqlIterator)
609 // change the view of the data
610 delete m_pSqlIterator->getParseTree();
611 m_pSqlIterator->setParseTree(nullptr);
612 m_bGraphicalDesign = !m_bGraphicalDesign;
613 impl_setViewMode( &aError );
615 else
617 ::connectivity::OSQLParseNode* pNode = m_aSqlParser.parseTree(aErrorMsg,m_sStatement,m_bGraphicalDesign);
618 if ( pNode )
620 delete m_pSqlIterator->getParseTree();
621 m_pSqlIterator->setParseTree(pNode);
622 m_pSqlIterator->traverseAll();
624 if ( m_pSqlIterator->hasErrors() )
626 aError = m_pSqlIterator->getErrors();
628 else
630 const OSQLTables& rTabs = m_pSqlIterator->getTables();
631 if ( m_pSqlIterator->getStatementType() != OSQLStatementType::Select || rTabs.begin() == rTabs.end() )
633 aError = SQLException(
634 OUString( ModuleRes( STR_QRY_NOSELECT ) ),
635 nullptr,
636 "S1000",
637 1000,
638 Any()
641 else
643 // change the view of the data
644 m_bGraphicalDesign = !m_bGraphicalDesign;
645 OUString sNewStatement;
646 pNode->parseNodeToStr( sNewStatement, getConnection() );
647 setStatement_fireEvent( sNewStatement );
648 getContainer()->SaveUIConfig();
649 m_vTableConnectionData.clear();
650 impl_setViewMode( &aError );
654 else
656 aError = SQLException(
657 OUString( ModuleRes( STR_QRY_SYNTAX ) ),
658 nullptr,
659 "S1000",
660 1000,
661 Any()
666 catch(const SQLException&)
668 aError = ::cppu::getCaughtException();
670 catch(const Exception&)
672 DBG_UNHANDLED_EXCEPTION();
675 if ( aError.isValid() )
676 showError( aError );
678 if(m_bGraphicalDesign)
680 InvalidateFeature(ID_BROWSER_ADDTABLE);
681 InvalidateFeature(SID_RELATION_ADD_RELATION);
684 break;
685 case SID_BROWSER_CLEAR_QUERY:
687 GetUndoManager().EnterListAction( OUString( ModuleRes(STR_QUERY_UNDO_TABWINDELETE) ), OUString() );
688 getContainer()->clear();
689 GetUndoManager().LeaveListAction();
691 setStatement_fireEvent( OUString() );
692 if(m_bGraphicalDesign)
693 InvalidateFeature(ID_BROWSER_ADDTABLE);
695 break;
696 case SID_QUERY_VIEW_FUNCTIONS:
697 case SID_QUERY_VIEW_TABLES:
698 case SID_QUERY_VIEW_ALIASES:
699 getContainer()->setSlotEnabled(_nId,!getContainer()->isSlotEnabled(_nId));
700 setModified(true);
701 break;
702 case SID_QUERY_DISTINCT_VALUES:
703 m_bDistinct = !m_bDistinct;
704 setModified(true);
705 break;
706 case SID_QUERY_LIMIT:
707 if ( aArgs.getLength() >= 1 && aArgs[0].Name == "DBLimit.Value" )
709 aArgs[0].Value >>= m_nLimit;
710 setModified(true);
712 break;
713 case SID_QUERY_PROP_DLG:
714 grabFocusFromLimitBox(*this);
715 execute_QueryPropDlg();
716 break;
717 case ID_BROWSER_QUERY_EXECUTE:
718 grabFocusFromLimitBox(*this);
719 if ( getContainer()->checkStatement() )
720 executeQuery();
721 break;
722 case SID_DB_QUERY_PREVIEW:
725 Reference< css::util::XCloseable > xCloseFrame( getContainer()->getPreviewFrame(), UNO_QUERY );
726 if ( xCloseFrame.is() )
730 xCloseFrame->close( true );
732 catch(const Exception&)
734 OSL_FAIL( "OQueryController::Execute(SID_DB_QUERY_PREVIEW): *nobody* is expected to veto closing the preview frame!" );
737 else
738 Execute(ID_BROWSER_QUERY_EXECUTE,Sequence< PropertyValue >());
740 catch(const Exception&)
743 break;
744 case ID_QUERY_ZOOM_IN:
747 break;
748 case ID_QUERY_ZOOM_OUT:
751 break;
752 #if OSL_DEBUG_LEVEL > 0
753 case ID_EDIT_QUERY_DESIGN:
754 case ID_EDIT_QUERY_SQL:
756 OUString aErrorMsg;
757 setStatement_fireEvent( getContainer()->getStatement() );
758 ::connectivity::OSQLParseNode* pNode = m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign );
759 if ( pNode )
761 vcl::Window* pView = getView();
762 ScopedVclPtrInstance<ModalDialog> pWindow( pView, WB_STDMODAL | WB_SIZEMOVE | WB_CENTER );
763 pWindow->SetSizePixel( ::Size( pView->GetSizePixel().Width() / 2, pView->GetSizePixel().Height() / 2 ) );
764 ScopedVclPtrInstance<SvTreeListBox> pTreeBox( pWindow, WB_BORDER | WB_HASLINES | WB_HASBUTTONS | WB_HASBUTTONSATROOT | WB_HASLINESATROOT | WB_VSCROLL );
765 pTreeBox->SetPosSizePixel( ::Point( 6, 6 ), ::Size( pWindow->GetSizePixel().Width() - 12, pWindow->GetSizePixel().Height() - 12 ));
766 pTreeBox->SetNodeDefaultImages();
768 if ( _nId == ID_EDIT_QUERY_DESIGN )
770 ::connectivity::OSQLParseNode* pTemp = pNode ? pNode->getChild(3)->getChild(1) : nullptr;
771 // no where clause found
772 if ( pTemp && !pTemp->isLeaf() )
774 ::connectivity::OSQLParseNode * pCondition = pTemp->getChild(1);
775 if ( pCondition ) // no where clause
777 ::connectivity::OSQLParseNode::negateSearchCondition(pCondition);
778 ::connectivity::OSQLParseNode *pNodeTmp = pTemp->getChild(1);
780 ::connectivity::OSQLParseNode::disjunctiveNormalForm(pNodeTmp);
781 pNodeTmp = pTemp->getChild(1);
782 ::connectivity::OSQLParseNode::absorptions(pNodeTmp);
783 pNodeTmp = pTemp->getChild(1);
784 OSQLParseNode::compress(pNodeTmp);
786 OUString sTemp;
787 pNode->parseNodeToStr(sTemp,getConnection());
788 getContainer()->setStatement(sTemp);
792 insertParseTree(pTreeBox,pNode);
794 pTreeBox->Show();
795 pWindow->Execute();
797 delete pNode;
799 break;
801 #endif
802 default:
803 OJoinController::Execute(_nId,aArgs);
804 return; // else we would invalidate twice
806 InvalidateFeature(_nId);
809 void OQueryController::impl_showAutoSQLViewError( const css::uno::Any& _rErrorDetails )
811 SQLContext aErrorContext;
812 aErrorContext.Message = lcl_getObjectResourceString( STR_ERROR_PARSING_STATEMENT, m_nCommandType );
813 aErrorContext.Context = *this;
814 aErrorContext.Details = lcl_getObjectResourceString( STR_INFO_OPENING_IN_SQL_VIEW, m_nCommandType );
815 aErrorContext.NextException = _rErrorDetails;
816 showError( aErrorContext );
819 void OQueryController::impl_setViewMode( ::dbtools::SQLExceptionInfo* _pErrorInfo )
821 OSL_PRECOND( getContainer(), "OQueryController::impl_setViewMode: illegal call!" );
823 bool wasModified = isModified();
825 SQLExceptionInfo aError;
826 bool bSuccess = getContainer()->switchView( &aError );
827 if ( !bSuccess )
829 m_bGraphicalDesign = !m_bGraphicalDesign;
830 // restore old state
831 getContainer()->switchView( nullptr );
832 // don't pass &aError here, this would overwrite the error which the first switchView call
833 // returned in this location.
834 if ( _pErrorInfo )
835 *_pErrorInfo = aError;
836 else
837 showError( aError );
839 else
841 ensureToolbars( *this, m_bGraphicalDesign );
844 setModified( wasModified );
847 void OQueryController::impl_initialize()
849 OJoinController::impl_initialize();
851 const NamedValueCollection& rArguments( getInitParams() );
853 OUString sCommand;
854 m_nCommandType = CommandType::QUERY;
856 // reading parameters:
858 // legacy parameters first (later overwritten by regular parameters)
859 OUString sIndependentSQLCommand;
860 if ( rArguments.get_ensureType( "IndependentSQLCommand", sIndependentSQLCommand ) )
862 OSL_FAIL( "OQueryController::impl_initialize: IndependentSQLCommand is regognized for compatibility only!" );
863 sCommand = sIndependentSQLCommand;
864 m_nCommandType = CommandType::COMMAND;
867 OUString sCurrentQuery;
868 if ( rArguments.get_ensureType( "CurrentQuery", sCurrentQuery ) )
870 OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" );
871 sCommand = sCurrentQuery;
872 m_nCommandType = CommandType::QUERY;
875 bool bCreateView( false );
876 if ( rArguments.get_ensureType( "CreateView", bCreateView ) && bCreateView )
878 OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" );
879 m_nCommandType = CommandType::TABLE;
882 // non-legacy parameters which overwrite the legacy parameters
883 rArguments.get_ensureType( PROPERTY_COMMAND, sCommand );
884 rArguments.get_ensureType( PROPERTY_COMMAND_TYPE, m_nCommandType );
886 // translate Command/Type into proper members
887 // TODO/Later: all this (including those members) should be hidden behind some abstract interface,
888 // which is implemented for all the three commands
889 switch ( m_nCommandType )
891 case CommandType::QUERY:
892 m_sName = sCommand;
893 break;
894 case CommandType::TABLE:
895 m_sName = sCommand;
896 break;
897 case CommandType::COMMAND:
898 setStatement_fireEvent( sCommand );
899 m_sName.clear();
900 break;
901 default:
902 OSL_FAIL( "OQueryController::impl_initialize: logic error in code!" );
903 throw RuntimeException();
906 // more legacy parameters
907 bool bGraphicalDesign( true );
908 if ( rArguments.get_ensureType( PROPERTY_QUERYDESIGNVIEW, bGraphicalDesign ) )
910 OSL_FAIL( "OQueryController::impl_initialize: QueryDesignView is regognized for compatibility only!" );
911 m_bGraphicalDesign = bGraphicalDesign;
914 // more non-legacy
915 rArguments.get_ensureType( PROPERTY_GRAPHICAL_DESIGN, m_bGraphicalDesign );
917 bool bEscapeProcessing( true );
918 if ( rArguments.get_ensureType( PROPERTY_ESCAPE_PROCESSING, bEscapeProcessing ) )
920 setEscapeProcessing_fireEvent( bEscapeProcessing );
922 OSL_ENSURE( m_bEscapeProcessing || !m_bGraphicalDesign, "OQueryController::impl_initialize: can't do the graphical design without escape processing!" );
923 if ( !m_bEscapeProcessing )
924 m_bGraphicalDesign = false;
927 // initial design
928 bool bForceInitialDesign = false;
929 Sequence< PropertyValue > aCurrentQueryDesignProps;
930 aCurrentQueryDesignProps = rArguments.getOrDefault( "CurrentQueryDesign", aCurrentQueryDesignProps );
932 if ( aCurrentQueryDesignProps.getLength() )
934 ::comphelper::NamedValueCollection aCurrentQueryDesign( aCurrentQueryDesignProps );
935 if ( aCurrentQueryDesign.has( OUString(PROPERTY_GRAPHICAL_DESIGN) ) )
937 aCurrentQueryDesign.get_ensureType( PROPERTY_GRAPHICAL_DESIGN, m_bGraphicalDesign );
939 if ( aCurrentQueryDesign.has( OUString(PROPERTY_ESCAPE_PROCESSING) ) )
941 aCurrentQueryDesign.get_ensureType( PROPERTY_ESCAPE_PROCESSING, m_bEscapeProcessing );
943 if ( aCurrentQueryDesign.has( "Statement" ) )
945 OUString sStatement;
946 aCurrentQueryDesign.get_ensureType( "Statement", sStatement );
947 aCurrentQueryDesign.remove( "Statement" );
948 setStatement_fireEvent( sStatement );
951 loadViewSettings( aCurrentQueryDesign );
953 bForceInitialDesign = true;
956 if ( !ensureConnected() )
957 { // we have no connection so what else should we do
958 m_bGraphicalDesign = false;
959 if ( editingView() )
961 connectionLostMessage();
962 throw SQLException();
966 // check the view capabilities
967 if ( isConnected() && editingView() )
969 Reference< XViewsSupplier > xViewsSup( getConnection(), UNO_QUERY );
970 Reference< XNameAccess > xViews;
971 if ( xViewsSup.is() )
972 xViews = xViewsSup->getViews();
974 if ( !xViews.is() )
975 { // we can't create views so we ask if the user wants to create a query instead
976 m_nCommandType = CommandType::QUERY;
977 bool bClose = false;
979 OUString aTitle( ModuleRes( STR_QUERYDESIGN_NO_VIEW_SUPPORT ) );
980 OUString aMessage( ModuleRes( STR_QUERYDESIGN_NO_VIEW_ASK ) );
981 ODataView* pWindow = getView();
982 ScopedVclPtrInstance< OSQLMessageBox > aDlg( pWindow, aTitle, aMessage, WB_YES_NO | WB_DEF_YES, OSQLMessageBox::Query );
983 bClose = aDlg->Execute() == RET_NO;
985 if ( bClose )
986 throw VetoException();
989 // now if we are to edit an existing view, check whether this is possible
990 if ( !m_sName.isEmpty() )
992 Any aView( xViews->getByName( m_sName ) );
993 // will throw if there is no such view
994 if ( !( aView >>= m_xAlterView ) )
996 throw IllegalArgumentException(
997 OUString( ModuleRes( STR_NO_ALTER_VIEW_SUPPORT ) ),
998 *this,
1005 OSL_ENSURE(getDataSource().is(),"OQueryController::impl_initialize: need a datasource!");
1009 getContainer()->initialize();
1010 impl_reset( bForceInitialDesign );
1012 SQLExceptionInfo aError;
1013 const bool bAttemptedGraphicalDesign = m_bGraphicalDesign;
1015 if ( bForceInitialDesign )
1017 getContainer()->forceInitialView();
1019 else
1021 impl_setViewMode( &aError );
1024 if ( aError.isValid() && bAttemptedGraphicalDesign && !m_bGraphicalDesign )
1026 // we tried initializing the graphical view, this failed, and we were automatically switched to SQL
1027 // view => tell this to the user
1028 if ( !editingView() )
1030 impl_showAutoSQLViewError( aError.get() );
1034 ClearUndoManager();
1036 if ( ( m_bGraphicalDesign )
1037 && ( ( m_sName.isEmpty() && !editingCommand() )
1038 || ( m_sStatement.isEmpty() && editingCommand() )
1042 Application::PostUserEvent( LINK( this, OQueryController, OnExecuteAddTable ) );
1045 setModified(false);
1047 catch(const SQLException& e)
1049 DBG_UNHANDLED_EXCEPTION();
1050 // we caught an exception so we switch to text only mode
1052 m_bGraphicalDesign = false;
1053 getContainer()->initialize();
1054 ODataView* pWindow = getView();
1055 ScopedVclPtrInstance<OSQLMessageBox>(pWindow,e)->Execute();
1057 throw;
1061 void OQueryController::onLoadedMenu(const Reference< css::frame::XLayoutManager >& /*_xLayoutManager*/)
1063 ensureToolbars( *this, m_bGraphicalDesign );
1066 OUString OQueryController::getPrivateTitle( ) const
1068 OUString sName = m_sName;
1069 if ( sName.isEmpty() )
1071 if ( !editingCommand() )
1073 SolarMutexGuard aSolarGuard;
1074 ::osl::MutexGuard aGuard( getMutex() );
1075 OUString aDefaultName = ModuleRes( editingView() ? STR_VIEW_TITLE : STR_QRY_TITLE );
1076 sName = aDefaultName.getToken(0,' ');
1077 sName += OUString::number(getCurrentStartNumber());
1080 return sName;
1083 void OQueryController::setQueryComposer()
1085 if(isConnected())
1087 Reference< XSQLQueryComposerFactory > xFactory(getConnection(), UNO_QUERY);
1088 OSL_ENSURE(xFactory.is(),"Connection doesn't support a querycomposer");
1089 if ( xFactory.is() && getContainer() )
1093 m_xComposer = xFactory->createQueryComposer();
1094 getContainer()->setStatement(m_sStatement);
1096 catch(const Exception&)
1098 m_xComposer = nullptr;
1100 OSL_ENSURE(m_xComposer.is(),"No querycomposer available!");
1101 Reference<XTablesSupplier> xTablesSup(getConnection(), UNO_QUERY);
1102 deleteIterator();
1103 m_pSqlIterator = new ::connectivity::OSQLParseTreeIterator( getConnection(), xTablesSup->getTables(), m_aSqlParser, nullptr );
1108 bool OQueryController::Construct(vcl::Window* pParent)
1110 // TODO: we have to check if we should create the text view or the design view
1112 setView( VclPtr<OQueryContainerWindow>::Create( pParent, *this, getORB() ) );
1114 return OJoinController::Construct(pParent);
1117 OJoinDesignView* OQueryController::getJoinView()
1119 return getContainer()->getDesignView();
1122 void OQueryController::describeSupportedFeatures()
1124 OJoinController::describeSupportedFeatures();
1125 implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT );
1126 implDescribeSupportedFeature( ".uno:SbaNativeSql", ID_BROWSER_ESCAPEPROCESSING,CommandGroup::FORMAT );
1127 implDescribeSupportedFeature( ".uno:DBViewFunctions", SID_QUERY_VIEW_FUNCTIONS, CommandGroup::VIEW );
1128 implDescribeSupportedFeature( ".uno:DBViewTableNames", SID_QUERY_VIEW_TABLES, CommandGroup::VIEW );
1129 implDescribeSupportedFeature( ".uno:DBViewAliases", SID_QUERY_VIEW_ALIASES, CommandGroup::VIEW );
1130 implDescribeSupportedFeature( ".uno:DBDistinctValues", SID_QUERY_DISTINCT_VALUES, CommandGroup::FORMAT );
1131 implDescribeSupportedFeature( ".uno:DBChangeDesignMode",ID_BROWSER_SQL, CommandGroup::VIEW );
1132 implDescribeSupportedFeature( ".uno:DBClearQuery", SID_BROWSER_CLEAR_QUERY, CommandGroup::EDIT );
1133 implDescribeSupportedFeature( ".uno:SbaExecuteSql", ID_BROWSER_QUERY_EXECUTE, CommandGroup::VIEW );
1134 implDescribeSupportedFeature( ".uno:DBAddRelation", SID_RELATION_ADD_RELATION, CommandGroup::EDIT );
1135 implDescribeSupportedFeature( ".uno:DBQueryPreview", SID_DB_QUERY_PREVIEW, CommandGroup::VIEW );
1136 implDescribeSupportedFeature( ".uno:DBLimit", SID_QUERY_LIMIT, CommandGroup::FORMAT );
1137 implDescribeSupportedFeature( ".uno:DBQueryPropertiesDialog", SID_QUERY_PROP_DLG, CommandGroup::FORMAT );
1139 #if OSL_DEBUG_LEVEL > 0
1140 implDescribeSupportedFeature( ".uno:DBShowParseTree", ID_EDIT_QUERY_SQL );
1141 implDescribeSupportedFeature( ".uno:DBMakeDisjunct", ID_EDIT_QUERY_DESIGN );
1142 #endif
1145 void OQueryController::impl_onModifyChanged()
1147 OJoinController::impl_onModifyChanged();
1148 InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
1149 InvalidateFeature(ID_BROWSER_SAVEASDOC);
1150 InvalidateFeature(ID_BROWSER_QUERY_EXECUTE);
1153 void SAL_CALL OQueryController::disposing( const EventObject& Source ) throw(RuntimeException, std::exception)
1155 SolarMutexGuard aGuard;
1157 if ( getContainer() && Source.Source.is() )
1159 if ( Source.Source == m_aCurrentFrame.getFrame() )
1160 { // our frame is being disposed -> close the preview window (if we have one)
1161 Reference< XFrame2 > xPreviewFrame( getContainer()->getPreviewFrame() );
1162 ::comphelper::disposeComponent( xPreviewFrame );
1164 else if ( Source.Source == getContainer()->getPreviewFrame() )
1166 getContainer()->disposingPreview();
1170 OJoinController::disposing(Source);
1173 void OQueryController::reconnect(bool _bUI)
1175 deleteIterator();
1176 ::comphelper::disposeComponent(m_xComposer);
1178 OJoinController::reconnect( _bUI );
1180 if (isConnected())
1182 setQueryComposer();
1184 else
1186 if(m_bGraphicalDesign)
1188 m_bGraphicalDesign = false;
1189 // don't call Execute(SQL) because this changes the sql statement
1190 impl_setViewMode( nullptr );
1192 InvalidateAll();
1196 void OQueryController::saveViewSettings( ::comphelper::NamedValueCollection& o_rViewSettings, const bool i_includingCriteria ) const
1198 saveTableWindows( o_rViewSettings );
1200 OTableFields::const_iterator field = m_vTableFieldDesc.begin();
1201 OTableFields::const_iterator fieldEnd = m_vTableFieldDesc.end();
1203 ::comphelper::NamedValueCollection aAllFieldsData;
1204 ::comphelper::NamedValueCollection aFieldData;
1205 for ( sal_Int32 i = 1; field != fieldEnd; ++field, ++i )
1207 if ( !(*field)->IsEmpty() )
1209 aFieldData.clear();
1210 (*field)->Save( aFieldData, i_includingCriteria );
1212 const OUString sFieldSettingName = "Field" + OUString::number( i );
1213 aAllFieldsData.put( sFieldSettingName, aFieldData.getPropertyValues() );
1217 o_rViewSettings.put( "Fields", aAllFieldsData.getPropertyValues() );
1218 o_rViewSettings.put( "SplitterPosition", m_nSplitPos );
1219 o_rViewSettings.put( "VisibleRows", m_nVisibleRows );
1222 void OQueryController::loadViewSettings( const ::comphelper::NamedValueCollection& o_rViewSettings )
1224 loadTableWindows( o_rViewSettings );
1226 m_nSplitPos = o_rViewSettings.getOrDefault( "SplitterPosition", m_nSplitPos );
1227 m_nVisibleRows = o_rViewSettings.getOrDefault( "VisibleRows", m_nVisibleRows );
1228 m_aFieldInformation = o_rViewSettings.getOrDefault( "Fields", m_aFieldInformation );
1231 void OQueryController::execute_QueryPropDlg()
1233 ScopedVclPtrInstance<QueryPropertiesDialog> aQueryPropDlg(
1234 getContainer(), m_bDistinct, m_nLimit );
1236 if( aQueryPropDlg->Execute() == RET_OK )
1238 m_bDistinct = aQueryPropDlg->getDistinct();
1239 m_nLimit = aQueryPropDlg->getLimit();
1240 InvalidateFeature( SID_QUERY_DISTINCT_VALUES );
1241 InvalidateFeature( SID_QUERY_LIMIT, nullptr, true );
1245 sal_Int32 OQueryController::getColWidth(sal_uInt16 _nColPos) const
1247 if ( _nColPos < m_aFieldInformation.getLength() )
1249 rtl::Reference<OTableFieldDesc> pField( new OTableFieldDesc());
1250 pField->Load( m_aFieldInformation[ _nColPos ], false );
1251 return pField->GetColWidth();
1253 return 0;
1256 Reference<XNameAccess> OQueryController::getObjectContainer() const
1258 Reference< XNameAccess > xElements;
1259 if ( editingView() )
1261 Reference< XViewsSupplier > xViewsSupp( getConnection(), UNO_QUERY );
1262 if ( xViewsSupp.is() )
1263 xElements = xViewsSupp->getViews();
1265 else
1267 Reference< XQueriesSupplier > xQueriesSupp( getConnection(), UNO_QUERY );
1268 if ( xQueriesSupp.is() )
1269 xElements = xQueriesSupp->getQueries();
1270 else
1272 Reference< XQueryDefinitionsSupplier > xQueryDefsSupp( getDataSource(), UNO_QUERY );
1273 if ( xQueryDefsSupp.is() )
1274 xElements = xQueryDefsSupp->getQueryDefinitions();
1278 OSL_ENSURE( xElements.is(), "OQueryController::getObjectContainer: unable to obtain the container!" );
1279 return xElements;
1282 void OQueryController::executeQuery()
1284 // we don't need to check the connection here because we already check the composer
1285 // which can't live without his connection
1286 OUString sTranslatedStmt = translateStatement( false );
1288 OUString sDataSourceName = getDataSourceName();
1289 if ( !(sDataSourceName.isEmpty() || sTranslatedStmt.isEmpty()) )
1293 getContainer()->showPreview( getFrame() );
1294 InvalidateFeature(SID_DB_QUERY_PREVIEW);
1296 URL aWantToDispatch;
1297 aWantToDispatch.Complete = ".component:DB/DataSourceBrowser";
1299 OUString sFrameName( FRAME_NAME_QUERY_PREVIEW );
1300 sal_Int32 nSearchFlags = FrameSearchFlag::CHILDREN;
1302 Reference< XDispatch> xDisp;
1303 Reference< XDispatchProvider> xProv( getFrame()->findFrame( sFrameName, nSearchFlags ), UNO_QUERY );
1304 if(!xProv.is())
1306 xProv.set( getFrame(), UNO_QUERY );
1307 if (xProv.is())
1308 xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, nSearchFlags);
1310 else
1312 xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, FrameSearchFlag::SELF);
1314 if (xDisp.is())
1316 auto aProps(::comphelper::InitPropertySequence(
1318 { PROPERTY_DATASOURCENAME, makeAny(sDataSourceName) },
1319 { PROPERTY_COMMAND_TYPE, makeAny(CommandType::COMMAND) },
1320 { PROPERTY_COMMAND, makeAny(sTranslatedStmt) },
1321 { PROPERTY_ENABLE_BROWSER, makeAny(false) },
1322 { PROPERTY_ACTIVE_CONNECTION, makeAny(getConnection()) },
1323 { PROPERTY_UPDATE_CATALOGNAME, makeAny(m_sUpdateCatalogName) },
1324 { PROPERTY_UPDATE_SCHEMANAME, makeAny(m_sUpdateSchemaName) },
1325 { PROPERTY_UPDATE_TABLENAME, makeAny(m_sUpdateTableName) },
1326 { PROPERTY_ESCAPE_PROCESSING, makeAny(m_bEscapeProcessing) }
1327 }));
1329 xDisp->dispatch(aWantToDispatch, aProps);
1330 // check the state of the beamer
1331 // be notified when the beamer frame is closed
1332 Reference< XComponent > xComponent( getFrame()->findFrame( sFrameName, nSearchFlags ), UNO_QUERY );
1333 if (xComponent.is())
1335 OSL_ENSURE(Reference< XFrame >(xComponent, UNO_QUERY).get() == getContainer()->getPreviewFrame().get(),
1336 "OQueryController::executeQuery: oops ... which window do I have here?");
1337 Reference< XEventListener> xEvtL(static_cast<cppu::OWeakObject*>(this),UNO_QUERY);
1338 xComponent->addEventListener(xEvtL);
1341 else
1343 OSL_FAIL("Couldn't create a beamer window!");
1346 catch(const Exception&)
1348 OSL_FAIL("Couldn't create a beamer window!");
1353 bool OQueryController::askForNewName(const Reference<XNameAccess>& _xElements, bool _bSaveAs)
1355 OSL_ENSURE( !editingCommand(), "OQueryController::askForNewName: not to be called when designing an independent statement!" );
1356 if ( editingCommand() )
1357 return false;
1359 OSL_PRECOND( _xElements.is(), "OQueryController::askForNewName: invalid container!" );
1360 if ( !_xElements.is() )
1361 return false;
1363 bool bRet = true;
1364 bool bNew = _bSaveAs || !_xElements->hasByName( m_sName );
1365 if(bNew)
1367 OUString aDefaultName;
1368 if ( ( _bSaveAs && !bNew ) || ( bNew && !m_sName.isEmpty() ) )
1369 aDefaultName = m_sName;
1370 else
1372 OUString sName = ModuleRes( editingView() ? STR_VIEW_TITLE : STR_QRY_TITLE );
1373 aDefaultName = sName.getToken(0,' ');
1374 aDefaultName = ::dbtools::createUniqueName(_xElements,aDefaultName);
1377 DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::QUERY );
1378 ScopedVclPtrInstance<OSaveAsDlg> aDlg(
1379 getView(),
1380 m_nCommandType,
1381 getORB(),
1382 getConnection(),
1383 aDefaultName,
1384 aNameChecker,
1385 SAD_DEFAULT );
1387 bRet = ( aDlg->Execute() == RET_OK );
1388 if ( bRet )
1390 m_sName = aDlg->getName();
1391 if ( editingView() )
1393 m_sUpdateCatalogName = aDlg->getCatalog();
1394 m_sUpdateSchemaName = aDlg->getSchema();
1398 return bRet;
1401 bool OQueryController::doSaveAsDoc(bool _bSaveAs)
1403 OSL_ENSURE(isEditable(),"Slot ID_BROWSER_SAVEDOC should not be enabled!");
1404 if ( !editingCommand() && !haveDataSource() )
1406 OUString aMessage(ModuleRes(STR_DATASOURCE_DELETED));
1407 ScopedVclPtrInstance<OSQLWarningBox>(getView(), aMessage)->Execute();
1408 return false;
1411 Reference< XNameAccess > xElements = getObjectContainer();
1412 if ( !xElements.is() )
1413 return false;
1415 if ( !getContainer()->checkStatement() )
1416 return false;
1418 OUString sTranslatedStmt = translateStatement();
1419 if ( editingCommand() )
1421 setModified( false );
1422 // this is all we need to do here. translateStatement implicitly set our m_sStatement, and
1423 // notified it, and that's all
1424 return true;
1427 if ( sTranslatedStmt.isEmpty() )
1428 return false;
1430 // first we need a name for our query so ask the user
1431 // did we get a name
1432 OUString sOriginalName( m_sName );
1433 if ( !askForNewName( xElements, _bSaveAs ) || m_sName.isEmpty() )
1434 return false;
1436 SQLExceptionInfo aInfo;
1437 bool bSuccess = false;
1438 bool bNew = false;
1441 bNew = ( _bSaveAs )
1442 || ( !xElements->hasByName( m_sName ) );
1444 Reference<XPropertySet> xQuery;
1445 if ( bNew ) // just to make sure the query already exists
1447 // drop the query, in case it already exists
1448 if ( xElements->hasByName( m_sName ) )
1450 Reference< XDrop > xNameCont( xElements, UNO_QUERY );
1451 if ( xNameCont.is() )
1452 xNameCont->dropByName( m_sName );
1453 else
1455 Reference< XNameContainer > xCont( xElements, UNO_QUERY );
1456 if ( xCont.is() )
1457 xCont->removeByName( m_sName );
1461 // create a new (empty, uninitialized) query resp. view
1462 Reference< XDataDescriptorFactory > xFact( xElements, UNO_QUERY );
1463 if ( xFact.is() )
1465 xQuery = xFact->createDataDescriptor();
1466 // to set the name is only allowed when the query is new
1467 xQuery->setPropertyValue( PROPERTY_NAME, makeAny( m_sName ) );
1469 else
1471 Reference< XSingleServiceFactory > xSingleFac( xElements, UNO_QUERY );
1472 if ( xSingleFac.is() )
1473 xQuery.set(xSingleFac->createInstance(), css::uno::UNO_QUERY);
1476 else
1478 xElements->getByName( m_sName ) >>= xQuery;
1480 if ( !xQuery.is() )
1481 throw RuntimeException();
1483 // the new commands
1484 if ( editingView() && !bNew )
1486 OSL_ENSURE( xQuery == m_xAlterView, "OQueryController::doSaveAsDoc: already have another alterable view ...!?" );
1487 m_xAlterView.set( xQuery, UNO_QUERY_THROW );
1488 m_xAlterView->alterCommand( sTranslatedStmt );
1490 else
1491 { // we're creating a query, or a *new* view
1492 xQuery->setPropertyValue( PROPERTY_COMMAND, makeAny( sTranslatedStmt ) );
1494 if ( editingView() )
1496 xQuery->setPropertyValue( PROPERTY_CATALOGNAME, makeAny( m_sUpdateCatalogName ) );
1497 xQuery->setPropertyValue( PROPERTY_SCHEMANAME, makeAny( m_sUpdateSchemaName ) );
1500 if ( editingQuery() )
1502 xQuery->setPropertyValue( PROPERTY_UPDATE_TABLENAME, makeAny( m_sUpdateTableName ) );
1503 xQuery->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, css::uno::makeAny( m_bEscapeProcessing ) );
1505 xQuery->setPropertyValue( PROPERTY_LAYOUTINFORMATION, getViewData() );
1509 if ( bNew )
1511 Reference< XAppend > xAppend( xElements, UNO_QUERY );
1512 if ( xAppend.is() )
1514 xAppend->appendByDescriptor( xQuery );
1516 else
1518 Reference< XNameContainer > xCont( xElements, UNO_QUERY );
1519 if ( xCont.is() )
1520 xCont->insertByName( m_sName, makeAny( xQuery ) );
1523 if ( editingView() )
1525 Reference< XPropertySet > xViewProps;
1526 if ( xElements->hasByName( m_sName ) )
1527 xViewProps.set( xElements->getByName( m_sName ), UNO_QUERY );
1529 if ( !xViewProps.is() ) // correct name and try again
1530 m_sName = ::dbtools::composeTableName( getMetaData(), xQuery, ::dbtools::EComposeRule::InDataManipulation, false, false, false );
1532 OSL_ENSURE( xElements->hasByName( m_sName ), "OQueryController::doSaveAsDoc: newly created view does not exist!" );
1534 if ( xElements->hasByName( m_sName ) )
1535 m_xAlterView.set( xElements->getByName( m_sName ), UNO_QUERY );
1537 // now check if our datasource has set a tablefilter and if so, append the new table name to it
1538 ::dbaui::appendToFilter( getConnection(), m_sName, getORB(), getView() );
1540 Reference< XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY);
1541 if ( xEventListener.is() )
1543 TitleChangedEvent aEvent;
1544 xEventListener->titleChanged(aEvent);
1546 releaseNumberForComponent();
1549 setModified( false );
1550 bSuccess = true;
1553 catch(const SQLException&)
1555 if ( !bNew )
1556 m_sName = sOriginalName;
1557 aInfo = SQLExceptionInfo( ::cppu::getCaughtException() );
1559 catch(const Exception&)
1561 if ( !bNew )
1562 m_sName = sOriginalName;
1563 DBG_UNHANDLED_EXCEPTION();
1566 showError( aInfo );
1568 // if we successfully saved a view we were creating, then close the designer
1569 if ( bSuccess && editingView() && !m_xAlterView.is() )
1571 closeTask();
1574 if ( bSuccess && editingView() )
1575 InvalidateFeature( ID_BROWSER_EDITDOC );
1577 return bSuccess;
1580 namespace {
1581 struct CommentStrip
1583 OUString maComment;
1584 bool mbLastOnLine;
1585 CommentStrip( const OUString& rComment, bool bLastOnLine )
1586 : maComment( rComment), mbLastOnLine( bLastOnLine) {}
1591 /** Obtain all comments in a query.
1593 See also delComment() implementation for OSQLParser::parseTree().
1595 static ::std::vector< CommentStrip > getComment( const OUString& rQuery )
1597 ::std::vector< CommentStrip > aRet;
1598 // First a quick search if there is any "--" or "//" or "/*", if not then
1599 // the whole copying loop is pointless.
1600 if (rQuery.indexOf( "--" ) < 0 && rQuery.indexOf( "//" ) < 0 &&
1601 rQuery.indexOf( "/*" ) < 0)
1602 return aRet;
1604 const sal_Unicode* pCopy = rQuery.getStr();
1605 const sal_Int32 nQueryLen = rQuery.getLength();
1606 bool bIsText1 = false; // "text"
1607 bool bIsText2 = false; // 'text'
1608 bool bComment2 = false; // /* comment */
1609 bool bComment = false; // -- or // comment
1610 OUStringBuffer aBuf;
1611 for (sal_Int32 i=0; i < nQueryLen; ++i)
1613 if (bComment2)
1615 aBuf.append( &pCopy[i], 1);
1616 if ((i+1) < nQueryLen)
1618 if (pCopy[i]=='*' && pCopy[i+1]=='/')
1620 bComment2 = false;
1621 aBuf.append( &pCopy[++i], 1);
1622 aRet.push_back( CommentStrip( aBuf.makeStringAndClear(), false));
1625 else
1627 // comment can't close anymore, actually an error, but..
1628 aRet.push_back( CommentStrip( aBuf.makeStringAndClear(), false));
1630 continue;
1632 if (pCopy[i] == '\n' || i == nQueryLen-1)
1634 if (bComment)
1636 if (i == nQueryLen-1 && pCopy[i] != '\n')
1637 aBuf.append( &pCopy[i], 1);
1638 aRet.push_back( CommentStrip( aBuf.makeStringAndClear(), true));
1639 bComment = false;
1641 else if (!aRet.empty())
1642 aRet.back().mbLastOnLine = true;
1644 else if (!bComment)
1646 if (pCopy[i] == '\"' && !bIsText2)
1647 bIsText1 = !bIsText1;
1648 else if (pCopy[i] == '\'' && !bIsText1)
1649 bIsText2 = !bIsText2;
1650 if (!bIsText1 && !bIsText2 && (i+1) < nQueryLen)
1652 if ((pCopy[i]=='-' && pCopy[i+1]=='-') || (pCopy[i]=='/' && pCopy[i+1]=='/'))
1653 bComment = true;
1654 else if ((pCopy[i]=='/' && pCopy[i+1]=='*'))
1655 bComment2 = true;
1658 if (bComment || bComment2)
1659 aBuf.append( &pCopy[i], 1);
1661 return aRet;
1664 /** Concat/insert comments that were previously obtained with getComment().
1666 NOTE: The current parser implementation does not preserve newlines, so all
1667 comments are always appended to the entire query, also inline comments
1668 that would need positioning anyway that can't be obtained after
1669 recomposition. This is ugly but at least allows commented queries while
1670 preserving the comments _somehow_.
1672 static OUString concatComment( const OUString& rQuery, const ::std::vector< CommentStrip >& rComments )
1674 // No comments => return query.
1675 if (rComments.empty())
1676 return rQuery;
1678 const sal_Unicode* pBeg = rQuery.getStr();
1679 const sal_Int32 nLen = rQuery.getLength();
1680 const size_t nComments = rComments.size();
1681 // Obtaining the needed size once should be faster than reallocating.
1682 // Also add a blank or linefeed for each comment.
1683 sal_Int32 nBufSize = nLen + nComments;
1684 for (::std::vector< CommentStrip >::const_iterator it( rComments.begin()); it != rComments.end(); ++it)
1685 nBufSize += (*it).maComment.getLength();
1686 OUStringBuffer aBuf( nBufSize );
1687 sal_Int32 nIndBeg = 0;
1688 sal_Int32 nIndLF = rQuery.indexOf('\n');
1689 size_t i = 0;
1690 while (nIndLF >= 0 && i < nComments)
1692 aBuf.append( pBeg + nIndBeg, nIndLF - nIndBeg);
1695 aBuf.append( rComments[i].maComment);
1696 } while (!rComments[i++].mbLastOnLine && i < nComments);
1697 aBuf.append( pBeg + nIndLF, 1); // the LF
1698 nIndBeg = nIndLF + 1;
1699 nIndLF = (nIndBeg < nLen ? rQuery.indexOf( '\n', nIndBeg) : -1);
1701 // Append remainder of query.
1702 if (nIndBeg < nLen)
1703 aBuf.append( pBeg + nIndBeg, nLen - nIndBeg);
1704 // Append all remaining comments, preserve lines.
1705 bool bNewLine = false;
1706 for ( ; i < nComments; ++i)
1708 if (!bNewLine)
1709 aBuf.append( ' ');
1710 aBuf.append( rComments[i].maComment);
1711 if (rComments[i].mbLastOnLine)
1713 aBuf.append( '\n');
1714 bNewLine = true;
1716 else
1717 bNewLine = false;
1719 return aBuf.makeStringAndClear();
1722 OUString OQueryController::translateStatement( bool _bFireStatementChange )
1724 // now set the properties
1725 setStatement_fireEvent( getContainer()->getStatement(), _bFireStatementChange );
1726 OUString sTranslatedStmt;
1727 if(!m_sStatement.isEmpty() && m_xComposer.is() && m_bEscapeProcessing)
1731 OUString aErrorMsg;
1733 ::std::vector< CommentStrip > aComments = getComment( m_sStatement);
1735 ::connectivity::OSQLParseNode* pNode = m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign );
1736 if(pNode)
1738 pNode->parseNodeToStr( sTranslatedStmt, getConnection() );
1739 delete pNode;
1742 m_xComposer->setQuery(sTranslatedStmt);
1743 sTranslatedStmt = m_xComposer->getComposedQuery();
1744 sTranslatedStmt = concatComment( sTranslatedStmt, aComments);
1746 catch(const SQLException& e)
1748 ::dbtools::SQLExceptionInfo aInfo(e);
1749 showError(aInfo);
1750 // an error occurred so we clear the statement
1751 sTranslatedStmt.clear();
1754 else if(m_sStatement.isEmpty())
1756 ModuleRes aModuleRes(STR_QRY_NOSELECT);
1757 OUString sTmpStr(aModuleRes);
1758 showError(SQLException(sTmpStr,nullptr,"S1000",1000,Any()));
1760 else
1761 sTranslatedStmt = m_sStatement;
1763 return sTranslatedStmt;
1766 short OQueryController::saveModified()
1768 SolarMutexGuard aSolarGuard;
1769 ::osl::MutexGuard aGuard( getMutex() );
1770 short nRet = RET_YES;
1771 if ( !isConnected() || !isModified() )
1772 return nRet;
1774 if ( !m_bGraphicalDesign
1775 || ( !m_vTableFieldDesc.empty()
1776 && !m_vTableData.empty()
1780 OUString sMessageText( lcl_getObjectResourceString( STR_QUERY_SAVEMODIFIED, m_nCommandType ) );
1781 ScopedVclPtrInstance< QueryBox > aQry( getView(), WB_YES_NO_CANCEL | WB_DEF_YES, sMessageText );
1783 nRet = aQry->Execute();
1784 if ( ( nRet == RET_YES )
1785 && !doSaveAsDoc( false )
1788 nRet = RET_CANCEL;
1791 return nRet;
1794 void OQueryController::impl_reset( const bool i_bForceCurrentControllerSettings )
1796 bool bValid = false;
1798 Sequence< PropertyValue > aLayoutInformation;
1799 // get command from the query if a query name was supplied
1800 if ( !i_bForceCurrentControllerSettings && !editingCommand() )
1802 if ( !m_sName.isEmpty() )
1804 Reference< XNameAccess > xQueries = getObjectContainer();
1805 if ( xQueries.is() )
1807 Reference< XPropertySet > xProp;
1808 if( xQueries->hasByName( m_sName ) && ( xQueries->getByName( m_sName ) >>= xProp ) && xProp.is() )
1810 OUString sNewStatement;
1811 xProp->getPropertyValue( PROPERTY_COMMAND ) >>= sNewStatement;
1812 setStatement_fireEvent( sNewStatement );
1814 if ( editingQuery() )
1816 bool bNewEscapeProcessing( true );
1817 xProp->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bNewEscapeProcessing;
1818 setEscapeProcessing_fireEvent( bNewEscapeProcessing );
1821 m_bGraphicalDesign = m_bGraphicalDesign && m_bEscapeProcessing;
1822 bValid = true;
1826 if ( editingQuery() )
1827 xProp->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) >>= aLayoutInformation;
1829 catch( const Exception& )
1831 OSL_FAIL( "OQueryController::impl_reset: could not retrieve the layout information from the query!" );
1837 else
1839 bValid = true;
1840 // assume that we got all necessary information during initialization
1843 if ( bValid )
1845 // load the layoutInformation
1846 if ( aLayoutInformation.getLength() )
1850 loadViewSettings( aLayoutInformation );
1852 catch( const Exception& )
1854 DBG_UNHANDLED_EXCEPTION();
1858 if ( !m_sStatement.isEmpty() )
1860 setQueryComposer();
1862 bool bError( false );
1864 if ( !m_pSqlIterator )
1866 bError = true;
1868 else if ( m_bEscapeProcessing )
1870 OUString aErrorMsg;
1871 ::std::unique_ptr< ::connectivity::OSQLParseNode > pNode(
1872 m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign ) );
1874 if ( pNode.get() )
1876 delete m_pSqlIterator->getParseTree();
1877 m_pSqlIterator->setParseTree( pNode.release() );
1878 m_pSqlIterator->traverseAll();
1879 if ( m_pSqlIterator->hasErrors() )
1881 if ( !i_bForceCurrentControllerSettings && m_bGraphicalDesign && !editingView() )
1883 impl_showAutoSQLViewError( makeAny( m_pSqlIterator->getErrors() ) );
1885 bError = true;
1888 else
1890 if ( !i_bForceCurrentControllerSettings && !editingView() )
1892 OUString aTitle(ModuleRes(STR_SVT_SQL_SYNTAX_ERROR));
1893 ScopedVclPtrInstance< OSQLMessageBox > aDlg(getView(),aTitle,aErrorMsg);
1894 aDlg->Execute();
1896 bError = true;
1900 if ( bError )
1902 m_bGraphicalDesign = false;
1903 if ( editingView() )
1904 // if we're editing a view whose statement could not be parsed, default to "no escape processing"
1905 setEscapeProcessing_fireEvent( false );
1910 if(!m_pSqlIterator)
1911 setQueryComposer();
1912 OSL_ENSURE(m_pSqlIterator,"No SQLIterator set!");
1914 getContainer()->setNoneVisbleRow(m_nVisibleRows);
1917 void OQueryController::reset()
1919 impl_reset();
1920 getContainer()->reset( nullptr );
1921 ClearUndoManager();
1924 void OQueryController::setStatement_fireEvent( const OUString& _rNewStatement, bool _bFireStatementChange )
1926 Any aOldValue = makeAny( m_sStatement );
1927 m_sStatement = _rNewStatement;
1928 Any aNewValue = makeAny( m_sStatement );
1930 sal_Int32 nHandle = PROPERTY_ID_ACTIVECOMMAND;
1931 if ( _bFireStatementChange )
1932 fire( &nHandle, &aNewValue, &aOldValue, 1, false );
1935 void OQueryController::setEscapeProcessing_fireEvent( const bool _bEscapeProcessing )
1937 if ( _bEscapeProcessing == m_bEscapeProcessing )
1938 return;
1940 Any aOldValue = makeAny( m_bEscapeProcessing );
1941 m_bEscapeProcessing = _bEscapeProcessing;
1942 Any aNewValue = makeAny( m_bEscapeProcessing );
1944 sal_Int32 nHandle = PROPERTY_ID_ESCAPE_PROCESSING;
1945 fire( &nHandle, &aNewValue, &aOldValue, 1, false );
1948 IMPL_LINK_NOARG_TYPED( OQueryController, OnExecuteAddTable, void*, void )
1950 Execute( ID_BROWSER_ADDTABLE,Sequence<PropertyValue>() );
1953 bool OQueryController::allowViews() const
1955 return true;
1958 bool OQueryController::allowQueries() const
1960 OSL_ENSURE( getSdbMetaData().isConnected(), "OQueryController::allowQueries: illegal call!" );
1961 if ( !getSdbMetaData().supportsSubqueriesInFrom() )
1962 return false;
1964 const NamedValueCollection& rArguments( getInitParams() );
1965 sal_Int32 nCommandType = rArguments.getOrDefault( PROPERTY_COMMAND_TYPE, (sal_Int32)CommandType::QUERY );
1966 bool bCreatingView = ( nCommandType == CommandType::TABLE );
1967 return !bCreatingView;
1970 Any SAL_CALL OQueryController::getViewData() throw( RuntimeException, std::exception )
1972 ::osl::MutexGuard aGuard( getMutex() );
1974 getContainer()->SaveUIConfig();
1976 ::comphelper::NamedValueCollection aViewSettings;
1977 saveViewSettings( aViewSettings, false );
1979 return makeAny( aViewSettings.getPropertyValues() );
1982 void SAL_CALL OQueryController::restoreViewData(const Any& /*Data*/) throw( RuntimeException, std::exception )
1984 // TODO
1987 } // namespace dbaui
1989 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */