Bump version to 5.0-14
[LibreOffice.git] / dbaccess / source / ui / querydesign / querycontroller.cxx
blobe7b2088f66c218ebd5e6bde8adafa8890e481d38
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/processfactory.hxx>
70 #include <comphelper/property.hxx>
71 #include <comphelper/seqstream.hxx>
72 #include <comphelper/streamsection.hxx>
73 #include <comphelper/types.hxx>
74 #include <connectivity/dbexception.hxx>
75 #include <connectivity/dbtools.hxx>
76 #include <cppuhelper/exc_hlp.hxx>
77 #include <sfx2/sfxsids.hrc>
78 #include <svtools/localresaccess.hxx>
79 #include <toolkit/helper/vclunohelper.hxx>
80 #include <tools/diagnose_ex.h>
81 #include <osl/diagnose.h>
82 #include <vcl/msgbox.hxx>
83 #include <vcl/svapp.hxx>
84 #include <osl/mutex.hxx>
85 #include <rtl/strbuf.hxx>
86 #include <vector>
88 extern "C" void SAL_CALL createRegistryInfo_OQueryControl()
90 static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OQueryController > aAutoRegistration;
93 namespace dbaui
95 using namespace ::com::sun::star::uno;
96 using namespace ::com::sun::star::beans;
97 using namespace ::com::sun::star::frame;
98 using namespace ::com::sun::star::util;
99 using namespace ::com::sun::star::lang;
101 class OViewController : public OQueryController
103 virtual OUString SAL_CALL getImplementationName() throw( RuntimeException, std::exception ) SAL_OVERRIDE
105 return getImplementationName_Static();
107 virtual Sequence< OUString> SAL_CALL getSupportedServiceNames() throw(RuntimeException, std::exception) SAL_OVERRIDE
109 return getSupportedServiceNames_Static();
112 public:
113 OViewController(const Reference< XComponentContext >& _rM) : OQueryController(_rM){}
115 // need by registration
116 static OUString getImplementationName_Static() throw( RuntimeException )
118 return OUString("org.openoffice.comp.dbu.OViewDesign");
120 static Sequence< OUString > getSupportedServiceNames_Static() throw( RuntimeException )
122 Sequence< OUString> aSupported(1);
123 aSupported.getArray()[0] = "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 > 1
142 namespace
144 void insertParseTree(SvTreeListBox* _pBox,::connectivity::OSQLParseNode* _pNode,SvTreeListEntry* _pParent = NULL)
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 SQL_NODE_KEYWORD:
171 rString += "SQL_KEYWORD:";
172 OString sT = OSQLParser::TokenIDToStr(_pNode->getTokenID());
173 rString += OStringToOUString(sT, RTL_TEXTENCODING_UTF8);
174 break;}
176 case SQL_NODE_COMPARISON:
178 rString += "SQL_COMPARISON:" + _pNode->getTokenValue(); // append Nodevalue
179 // and start new line
180 break;}
182 case SQL_NODE_NAME:
184 rString += "SQL_NAME:\"" + _pNode->getTokenValue() + "\"";
185 break;}
187 case SQL_NODE_STRING:
189 rString += "SQL_STRING:'" + _pNode->getTokenValue();
190 break;}
192 case SQL_NODE_INTNUM:
194 rString += "SQL_INTNUM:" + _pNode->getTokenValue();
195 break;}
197 case SQL_NODE_APPROXNUM:
199 rString += "SQL_APPROXNUM:" + _pNode->getTokenValue();
200 break;}
202 case SQL_NODE_PUNCTUATION:
204 rString += "SQL_PUNCTUATION:" + _pNode->getTokenValue(); // append Nodevalue
205 break;}
207 case SQL_NODE_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< ::com::sun::star::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(1);
314 aSupported.getArray()[0] = "com.sun.star.sdb.QueryDesign";
315 return aSupported;
318 Sequence< OUString> SAL_CALL OQueryController::getSupportedServiceNames() throw(RuntimeException, std::exception)
320 return getSupportedServiceNames_Static();
323 Reference< XInterface > SAL_CALL OQueryController::Create(const Reference<XMultiServiceFactory >& _rxFactory)
325 return *(new OQueryController(comphelper::getComponentContext(_rxFactory)));
328 OQueryController::OQueryController(const Reference< XComponentContext >& _rM)
329 :OJoinController(_rM)
330 ,OQueryController_PBase( getBroadcastHelper() )
331 ,m_pParseContext( new svxform::OSystemParseContext )
332 ,m_aSqlParser( _rM, m_pParseContext )
333 ,m_pSqlIterator(NULL)
334 ,m_nLimit(-1)
335 ,m_nVisibleRows(0x400)
336 ,m_nSplitPos(-1)
337 ,m_nCommandType( CommandType::QUERY )
338 ,m_bGraphicalDesign(false)
339 ,m_bDistinct(false)
340 ,m_bViewAlias(false)
341 ,m_bViewTable(false)
342 ,m_bViewFunction(false)
343 ,m_bEscapeProcessing(true)
345 InvalidateAll();
347 registerProperty( PROPERTY_ACTIVECOMMAND, PROPERTY_ID_ACTIVECOMMAND, PropertyAttribute::READONLY | PropertyAttribute::BOUND,
348 &m_sStatement, cppu::UnoType<decltype(m_sStatement)>::get() );
349 registerProperty( PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::READONLY | PropertyAttribute::BOUND,
350 &m_bEscapeProcessing, cppu::UnoType<decltype(m_bEscapeProcessing)>::get() );
353 OQueryController::~OQueryController()
355 if ( !getBroadcastHelper().bDisposed && !getBroadcastHelper().bInDispose )
357 OSL_FAIL("Please check who doesn't dispose this component!");
358 // increment ref count to prevent double call of Dtor
359 osl_atomic_increment( &m_refCount );
360 dispose();
364 IMPLEMENT_FORWARD_XINTERFACE2( OQueryController, OJoinController, OQueryController_PBase )
365 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OQueryController, OJoinController, OQueryController_PBase )
367 Reference< XPropertySetInfo > SAL_CALL OQueryController::getPropertySetInfo() throw(RuntimeException, std::exception)
369 Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
370 return xInfo;
373 sal_Bool SAL_CALL OQueryController::convertFastPropertyValue( Any& o_rConvertedValue, Any& o_rOldValue, sal_Int32 i_nHandle, const Any& i_rValue ) throw (IllegalArgumentException)
375 return OPropertyContainer::convertFastPropertyValue( o_rConvertedValue, o_rOldValue, i_nHandle, i_rValue );
378 void SAL_CALL OQueryController::setFastPropertyValue_NoBroadcast( sal_Int32 i_nHandle, const Any& i_rValue ) throw ( Exception, std::exception )
380 OPropertyContainer::setFastPropertyValue_NoBroadcast( i_nHandle, i_rValue );
383 void SAL_CALL OQueryController::getFastPropertyValue( Any& o_rValue, sal_Int32 i_nHandle ) const
385 switch ( i_nHandle )
387 case PROPERTY_ID_CURRENT_QUERY_DESIGN:
389 ::comphelper::NamedValueCollection aCurrentDesign;
390 aCurrentDesign.put( "GraphicalDesign", isGraphicalDesign() );
391 aCurrentDesign.put( OUString(PROPERTY_ESCAPE_PROCESSING), m_bEscapeProcessing );
393 if ( isGraphicalDesign() )
395 getContainer()->SaveUIConfig();
396 saveViewSettings( aCurrentDesign, true );
397 aCurrentDesign.put( "Statement", m_sStatement );
399 else
401 aCurrentDesign.put( "Statement", getContainer()->getStatement() );
404 o_rValue <<= aCurrentDesign.getPropertyValues();
406 break;
408 default:
409 OPropertyContainer::getFastPropertyValue( o_rValue, i_nHandle );
410 break;
414 ::cppu::IPropertyArrayHelper& OQueryController::getInfoHelper()
416 return *getArrayHelper();
419 ::cppu::IPropertyArrayHelper* OQueryController::createArrayHelper( ) const
421 Sequence< Property > aProps;
422 describeProperties( aProps );
424 // one additional property:
425 const sal_Int32 nLength = aProps.getLength();
426 aProps.realloc( nLength + 1 );
427 aProps[ nLength ] = Property(
428 "CurrentQueryDesign",
429 PROPERTY_ID_CURRENT_QUERY_DESIGN,
430 ::cppu::UnoType< Sequence< PropertyValue > >::get(),
431 PropertyAttribute::READONLY
434 ::std::sort(
435 aProps.getArray(),
436 aProps.getArray() + aProps.getLength(),
437 ::comphelper::PropertyCompareByName()
440 return new ::cppu::OPropertyArrayHelper(aProps);
443 void OQueryController::deleteIterator()
445 if(m_pSqlIterator)
447 delete m_pSqlIterator->getParseTree();
448 m_pSqlIterator->dispose();
449 delete m_pSqlIterator;
450 m_pSqlIterator = NULL;
454 void OQueryController::disposing()
456 OQueryController_PBase::disposing();
458 deleteIterator();
460 delete m_pParseContext;
462 clearFields();
463 OTableFields().swap(m_vUnUsedFieldsDesc);
465 ::comphelper::disposeComponent(m_xComposer);
466 OJoinController::disposing();
467 OQueryController_PBase::disposing();
470 void OQueryController::clearFields()
472 OTableFields().swap(m_vTableFieldDesc);
475 FeatureState OQueryController::GetState(sal_uInt16 _nId) const
477 FeatureState aReturn;
478 aReturn.bEnabled = true;
479 // (disabled automatically)
481 switch (_nId)
483 case ID_BROWSER_EDITDOC:
484 if ( editingCommand() )
485 aReturn.bEnabled = false;
486 else if ( editingView() && !m_xAlterView.is() )
487 aReturn.bEnabled = false;
488 else
489 aReturn = OJoinController::GetState( _nId );
490 break;
492 case ID_BROWSER_ESCAPEPROCESSING:
493 aReturn.bChecked = !m_bEscapeProcessing;
494 aReturn.bEnabled = ( m_pSqlIterator != NULL ) && !m_bGraphicalDesign;
495 break;
496 case SID_RELATION_ADD_RELATION:
497 aReturn.bEnabled = isEditable() && m_bGraphicalDesign && m_vTableData.size() > 1;
498 break;
499 case ID_BROWSER_SAVEASDOC:
500 aReturn.bEnabled = !editingCommand() && !editingView() && (!m_bGraphicalDesign || !(m_vTableFieldDesc.empty() || m_vTableData.empty()));
501 break;
502 case ID_BROWSER_SAVEDOC:
503 aReturn.bEnabled = impl_isModified() && (!m_bGraphicalDesign || !(m_vTableFieldDesc.empty() || m_vTableData.empty()));
504 break;
505 case SID_PRINTDOCDIRECT:
506 break;
507 case ID_BROWSER_CUT:
508 aReturn.bEnabled = isEditable() && getContainer() && getContainer()->isCutAllowed();
509 break;
510 case ID_BROWSER_COPY:
511 aReturn.bEnabled = getContainer() && getContainer()->isCopyAllowed();
512 break;
513 case ID_BROWSER_PASTE:
514 aReturn.bEnabled = isEditable() && getContainer() && getContainer()->isPasteAllowed();
515 break;
516 case ID_BROWSER_SQL:
517 aReturn.bEnabled = m_bEscapeProcessing && m_pSqlIterator;
518 aReturn.bChecked = m_bGraphicalDesign;
519 break;
520 case SID_BROWSER_CLEAR_QUERY:
521 aReturn.bEnabled = isEditable() && (!m_sStatement.isEmpty() || !m_vTableData.empty());
522 break;
523 case SID_QUERY_VIEW_FUNCTIONS:
524 case SID_QUERY_VIEW_TABLES:
525 case SID_QUERY_VIEW_ALIASES:
526 aReturn.bChecked = getContainer() && getContainer()->isSlotEnabled(_nId);
527 aReturn.bEnabled = m_bGraphicalDesign;
528 break;
529 case SID_QUERY_DISTINCT_VALUES:
530 aReturn.bEnabled = m_bGraphicalDesign && isEditable();
531 aReturn.bChecked = m_bDistinct;
532 break;
533 case SID_QUERY_LIMIT:
534 aReturn.bEnabled = m_bGraphicalDesign;
535 if( aReturn.bEnabled )
536 aReturn.aValue = makeAny( m_nLimit );
537 break;
538 case SID_QUERY_PROP_DLG:
539 aReturn.bEnabled = m_bGraphicalDesign;
540 break;
541 case ID_BROWSER_QUERY_EXECUTE:
542 aReturn.bEnabled = true;
543 break;
544 case SID_DB_QUERY_PREVIEW:
545 aReturn.bEnabled = true;
546 aReturn.bChecked = getContainer() && getContainer()->getPreviewFrame().is();
547 break;
548 #if OSL_DEBUG_LEVEL > 1
549 case ID_EDIT_QUERY_SQL:
550 break;
551 case ID_EDIT_QUERY_DESIGN:
552 break;
553 #endif
554 case ID_BROWSER_ADDTABLE:
555 if ( !m_bGraphicalDesign )
557 aReturn.bEnabled = false;
558 break;
560 // run through
561 default:
562 aReturn = OJoinController::GetState(_nId);
563 break;
565 return aReturn;
568 void OQueryController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
570 switch(_nId)
572 case ID_BROWSER_ESCAPEPROCESSING:
573 setEscapeProcessing_fireEvent( !m_bEscapeProcessing );
574 if ( !editingView() )
575 setModified(sal_True);
576 InvalidateFeature(ID_BROWSER_SQL);
577 break;
578 case ID_BROWSER_SAVEASDOC:
579 case ID_BROWSER_SAVEDOC:
580 grabFocusFromLimitBox(*this);
581 doSaveAsDoc(ID_BROWSER_SAVEASDOC == _nId);
582 break;
583 case SID_RELATION_ADD_RELATION:
585 OJoinDesignView* pView = getJoinView();
586 if( pView )
587 static_cast<OQueryTableView*>(pView->getTableView())->createNewConnection();
589 break;
590 case SID_PRINTDOCDIRECT:
591 break;
592 case ID_BROWSER_CUT:
593 getContainer()->cut();
594 break;
595 case ID_BROWSER_COPY:
596 getContainer()->copy();
597 break;
598 case ID_BROWSER_PASTE:
599 getContainer()->paste();
600 break;
601 case ID_BROWSER_SQL:
603 grabFocusFromLimitBox(*this);
604 if ( !getContainer()->checkStatement() )
605 break;
606 SQLExceptionInfo aError;
609 OUString aErrorMsg;
610 setStatement_fireEvent( getContainer()->getStatement() );
611 if(m_sStatement.isEmpty() && m_pSqlIterator)
613 // change the view of the data
614 delete m_pSqlIterator->getParseTree();
615 m_pSqlIterator->setParseTree(NULL);
616 m_bGraphicalDesign = !m_bGraphicalDesign;
617 impl_setViewMode( &aError );
619 else
621 ::connectivity::OSQLParseNode* pNode = m_aSqlParser.parseTree(aErrorMsg,m_sStatement,m_bGraphicalDesign);
622 if ( pNode )
624 delete m_pSqlIterator->getParseTree();
625 m_pSqlIterator->setParseTree(pNode);
626 m_pSqlIterator->traverseAll();
628 if ( m_pSqlIterator->hasErrors() )
630 aError = m_pSqlIterator->getErrors();
632 else
634 const OSQLTables& xTabs = m_pSqlIterator->getTables();
635 if ( m_pSqlIterator->getStatementType() != SQL_STATEMENT_SELECT || xTabs.begin() == xTabs.end() )
637 aError = SQLException(
638 OUString( ModuleRes( STR_QRY_NOSELECT ) ),
639 NULL,
640 "S1000",
641 1000,
642 Any()
645 else
647 // change the view of the data
648 m_bGraphicalDesign = !m_bGraphicalDesign;
649 OUString sNewStatement;
650 pNode->parseNodeToStr( sNewStatement, getConnection() );
651 setStatement_fireEvent( sNewStatement );
652 getContainer()->SaveUIConfig();
653 m_vTableConnectionData.clear();
654 impl_setViewMode( &aError );
658 else
660 aError = SQLException(
661 OUString( ModuleRes( STR_QRY_SYNTAX ) ),
662 NULL,
663 "S1000",
664 1000,
665 Any()
670 catch(const SQLException&)
672 aError = ::cppu::getCaughtException();
674 catch(const Exception&)
676 DBG_UNHANDLED_EXCEPTION();
679 if ( aError.isValid() )
680 showError( aError );
682 if(m_bGraphicalDesign)
684 InvalidateFeature(ID_BROWSER_ADDTABLE);
685 InvalidateFeature(SID_RELATION_ADD_RELATION);
688 break;
689 case SID_BROWSER_CLEAR_QUERY:
691 GetUndoManager().EnterListAction( OUString( ModuleRes(STR_QUERY_UNDO_TABWINDELETE) ), OUString() );
692 getContainer()->clear();
693 GetUndoManager().LeaveListAction();
695 setStatement_fireEvent( OUString() );
696 if(m_bGraphicalDesign)
697 InvalidateFeature(ID_BROWSER_ADDTABLE);
699 break;
700 case SID_QUERY_VIEW_FUNCTIONS:
701 case SID_QUERY_VIEW_TABLES:
702 case SID_QUERY_VIEW_ALIASES:
703 getContainer()->setSlotEnabled(_nId,!getContainer()->isSlotEnabled(_nId));
704 setModified(sal_True);
705 break;
706 case SID_QUERY_DISTINCT_VALUES:
707 m_bDistinct = !m_bDistinct;
708 setModified(sal_True);
709 break;
710 case SID_QUERY_LIMIT:
711 if ( aArgs.getLength() >= 1 && aArgs[0].Name == "DBLimit.Value" )
713 aArgs[0].Value >>= m_nLimit;
714 setModified(sal_True);
716 break;
717 case SID_QUERY_PROP_DLG:
718 grabFocusFromLimitBox(*this);
719 execute_QueryPropDlg();
720 break;
721 case ID_BROWSER_QUERY_EXECUTE:
722 grabFocusFromLimitBox(*this);
723 if ( getContainer()->checkStatement() )
724 executeQuery();
725 break;
726 case SID_DB_QUERY_PREVIEW:
729 Reference< ::com::sun::star::util::XCloseable > xCloseFrame( getContainer()->getPreviewFrame(), UNO_QUERY );
730 if ( xCloseFrame.is() )
734 xCloseFrame->close( sal_True );
736 catch(const Exception&)
738 OSL_FAIL( "OQueryController::Execute(SID_DB_QUERY_PREVIEW): *nobody* is expected to veto closing the preview frame!" );
741 else
742 Execute(ID_BROWSER_QUERY_EXECUTE,Sequence< PropertyValue >());
744 catch(const Exception&)
747 break;
748 case ID_QUERY_ZOOM_IN:
751 break;
752 case ID_QUERY_ZOOM_OUT:
755 break;
756 #if OSL_DEBUG_LEVEL > 1
757 case ID_EDIT_QUERY_DESIGN:
758 case ID_EDIT_QUERY_SQL:
760 OUString aErrorMsg;
761 setStatement_fireEvent( getContainer()->getStatement() );
762 ::connectivity::OSQLParseNode* pNode = m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign );
763 if ( pNode )
765 vcl::Window* pView = getView();
766 ScopedVclPtrInstance<ModalDialog> pWindow( pView, WB_STDMODAL | WB_SIZEMOVE | WB_CENTER );
767 pWindow->SetSizePixel( ::Size( pView->GetSizePixel().Width() / 2, pView->GetSizePixel().Height() / 2 ) );
768 ScopedVclPtrInstance<SvTreeListBox> pTreeBox( pWindow, WB_BORDER | WB_HASLINES | WB_HASBUTTONS | WB_HASBUTTONSATROOT | WB_HASLINESATROOT | WB_VSCROLL );
769 pTreeBox->SetPosSizePixel( ::Point( 6, 6 ), ::Size( pWindow->GetSizePixel().Width() - 12, pWindow->GetSizePixel().Height() - 12 ));
770 pTreeBox->SetNodeDefaultImages();
772 if ( _nId == ID_EDIT_QUERY_DESIGN )
774 ::connectivity::OSQLParseNode* pTemp = pNode ? pNode->getChild(3)->getChild(1) : NULL;
775 // no where clause found
776 if ( pTemp && !pTemp->isLeaf() )
778 ::connectivity::OSQLParseNode * pCondition = pTemp->getChild(1);
779 if ( pCondition ) // no where clause
781 ::connectivity::OSQLParseNode::negateSearchCondition(pCondition);
782 ::connectivity::OSQLParseNode *pNodeTmp = pTemp->getChild(1);
784 ::connectivity::OSQLParseNode::disjunctiveNormalForm(pNodeTmp);
785 pNodeTmp = pTemp->getChild(1);
786 ::connectivity::OSQLParseNode::absorptions(pNodeTmp);
787 pNodeTmp = pTemp->getChild(1);
788 OSQLParseNode::compress(pNodeTmp);
789 pNodeTmp = pTemp->getChild(1);
791 OUString sTemp;
792 pNode->parseNodeToStr(sTemp,getConnection());
793 getContainer()->setStatement(sTemp);
797 insertParseTree(pTreeBox,pNode);
799 pTreeBox->Show();
800 pWindow->Execute();
802 delete pNode;
804 break;
806 #endif
807 default:
808 OJoinController::Execute(_nId,aArgs);
809 return; // else we would invalidate twice
811 InvalidateFeature(_nId);
814 void OQueryController::impl_showAutoSQLViewError( const ::com::sun::star::uno::Any& _rErrorDetails )
816 SQLContext aErrorContext;
817 aErrorContext.Message = lcl_getObjectResourceString( STR_ERROR_PARSING_STATEMENT, m_nCommandType );
818 aErrorContext.Context = *this;
819 aErrorContext.Details = lcl_getObjectResourceString( STR_INFO_OPENING_IN_SQL_VIEW, m_nCommandType );
820 aErrorContext.NextException = _rErrorDetails;
821 showError( aErrorContext );
824 bool OQueryController::impl_setViewMode( ::dbtools::SQLExceptionInfo* _pErrorInfo )
826 OSL_PRECOND( getContainer(), "OQueryController::impl_setViewMode: illegal call!" );
828 bool wasModified = isModified();
830 SQLExceptionInfo aError;
831 bool bSuccess = getContainer()->switchView( &aError );
832 if ( !bSuccess )
834 m_bGraphicalDesign = !m_bGraphicalDesign;
835 // restore old state
836 getContainer()->switchView( NULL );
837 // don't pass &aError here, this would overwrite the error which the first switchView call
838 // returned in this location.
839 if ( _pErrorInfo )
840 *_pErrorInfo = aError;
841 else
842 showError( aError );
844 else
846 ensureToolbars( *this, m_bGraphicalDesign );
849 setModified( wasModified );
850 return bSuccess;
853 void OQueryController::impl_initialize()
855 OJoinController::impl_initialize();
857 const NamedValueCollection& rArguments( getInitParams() );
859 OUString sCommand;
860 m_nCommandType = CommandType::QUERY;
862 // reading parameters:
864 // legacy parameters first (later overwritten by regular parameters)
865 OUString sIndependentSQLCommand;
866 if ( rArguments.get_ensureType( "IndependentSQLCommand", sIndependentSQLCommand ) )
868 OSL_FAIL( "OQueryController::impl_initialize: IndependentSQLCommand is regognized for compatibility only!" );
869 sCommand = sIndependentSQLCommand;
870 m_nCommandType = CommandType::COMMAND;
873 OUString sCurrentQuery;
874 if ( rArguments.get_ensureType( "CurrentQuery", sCurrentQuery ) )
876 OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" );
877 sCommand = sCurrentQuery;
878 m_nCommandType = CommandType::QUERY;
881 bool bCreateView( false );
882 if ( rArguments.get_ensureType( "CreateView", bCreateView ) && bCreateView )
884 OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" );
885 m_nCommandType = CommandType::TABLE;
888 // non-legacy parameters which overwrite the legacy parameters
889 rArguments.get_ensureType( OUString(PROPERTY_COMMAND), sCommand );
890 rArguments.get_ensureType( OUString(PROPERTY_COMMAND_TYPE), m_nCommandType );
892 // translate Command/Type into proper members
893 // TODO/Later: all this (including those members) should be hidden behind some abstact interface,
894 // which is implemented for all the three commands
895 switch ( m_nCommandType )
897 case CommandType::QUERY:
898 m_sName = sCommand;
899 break;
900 case CommandType::TABLE:
901 m_sName = sCommand;
902 break;
903 case CommandType::COMMAND:
904 setStatement_fireEvent( sCommand );
905 m_sName.clear();
906 break;
907 default:
908 OSL_FAIL( "OQueryController::impl_initialize: logic error in code!" );
909 throw RuntimeException();
912 // more legacy parameters
913 bool bGraphicalDesign( true );
914 if ( rArguments.get_ensureType( OUString(PROPERTY_QUERYDESIGNVIEW), bGraphicalDesign ) )
916 OSL_FAIL( "OQueryController::impl_initialize: QueryDesignView is regognized for compatibility only!" );
917 m_bGraphicalDesign = bGraphicalDesign;
920 // more non-legacy
921 rArguments.get_ensureType( OUString(PROPERTY_GRAPHICAL_DESIGN), m_bGraphicalDesign );
923 bool bEscapeProcessing( true );
924 if ( rArguments.get_ensureType( OUString(PROPERTY_ESCAPE_PROCESSING), bEscapeProcessing ) )
926 setEscapeProcessing_fireEvent( bEscapeProcessing );
928 OSL_ENSURE( m_bEscapeProcessing || !m_bGraphicalDesign, "OQueryController::impl_initialize: can't do the graphical design without escape processing!" );
929 if ( !m_bEscapeProcessing )
930 m_bGraphicalDesign = false;
933 // initial design
934 bool bForceInitialDesign = false;
935 Sequence< PropertyValue > aCurrentQueryDesignProps;
936 aCurrentQueryDesignProps = rArguments.getOrDefault( "CurrentQueryDesign", aCurrentQueryDesignProps );
938 if ( aCurrentQueryDesignProps.getLength() )
940 ::comphelper::NamedValueCollection aCurrentQueryDesign( aCurrentQueryDesignProps );
941 if ( aCurrentQueryDesign.has( OUString(PROPERTY_GRAPHICAL_DESIGN) ) )
943 aCurrentQueryDesign.get_ensureType( OUString(PROPERTY_GRAPHICAL_DESIGN), m_bGraphicalDesign );
945 if ( aCurrentQueryDesign.has( OUString(PROPERTY_ESCAPE_PROCESSING) ) )
947 aCurrentQueryDesign.get_ensureType( OUString(PROPERTY_ESCAPE_PROCESSING), m_bEscapeProcessing );
949 if ( aCurrentQueryDesign.has( "Statement" ) )
951 OUString sStatement;
952 aCurrentQueryDesign.get_ensureType( "Statement", sStatement );
953 aCurrentQueryDesign.remove( "Statement" );
954 setStatement_fireEvent( sStatement );
957 loadViewSettings( aCurrentQueryDesign );
959 bForceInitialDesign = true;
962 if ( !ensureConnected( false ) )
963 { // we have no connection so what else should we do
964 m_bGraphicalDesign = false;
965 if ( editingView() )
967 connectionLostMessage();
968 throw SQLException();
972 // check the view capabilities
973 if ( isConnected() && editingView() )
975 Reference< XViewsSupplier > xViewsSup( getConnection(), UNO_QUERY );
976 Reference< XNameAccess > xViews;
977 if ( xViewsSup.is() )
978 xViews = xViewsSup->getViews();
980 if ( !xViews.is() )
981 { // we can't create views so we ask if the user wants to create a query instead
982 m_nCommandType = CommandType::QUERY;
983 bool bClose = false;
985 OUString aTitle( ModuleRes( STR_QUERYDESIGN_NO_VIEW_SUPPORT ) );
986 OUString aMessage( ModuleRes( STR_QUERYDESIGN_NO_VIEW_ASK ) );
987 ODataView* pWindow = getView();
988 ScopedVclPtrInstance< OSQLMessageBox > aDlg( pWindow, aTitle, aMessage, WB_YES_NO | WB_DEF_YES, OSQLMessageBox::Query );
989 bClose = aDlg->Execute() == RET_NO;
991 if ( bClose )
992 throw VetoException();
995 // now if we are to edit an existing view, check whether this is possible
996 if ( !m_sName.isEmpty() )
998 Any aView( xViews->getByName( m_sName ) );
999 // will throw if there is no such view
1000 if ( !( aView >>= m_xAlterView ) )
1002 throw IllegalArgumentException(
1003 OUString( ModuleRes( STR_NO_ALTER_VIEW_SUPPORT ) ),
1004 *this,
1011 OSL_ENSURE(getDataSource().is(),"OQueryController::impl_initialize: need a datasource!");
1015 getContainer()->initialize();
1016 impl_reset( bForceInitialDesign );
1018 SQLExceptionInfo aError;
1019 const bool bAttemptedGraphicalDesign = m_bGraphicalDesign;
1021 if ( bForceInitialDesign )
1023 getContainer()->forceInitialView();
1025 else
1027 impl_setViewMode( &aError );
1030 if ( aError.isValid() && bAttemptedGraphicalDesign && !m_bGraphicalDesign )
1032 // we tried initializing the graphical view, this failed, and we were automatically switched to SQL
1033 // view => tell this to the user
1034 if ( !editingView() )
1036 impl_showAutoSQLViewError( aError.get() );
1040 ClearUndoManager();
1042 if ( ( m_bGraphicalDesign )
1043 && ( ( m_sName.isEmpty() && !editingCommand() )
1044 || ( m_sStatement.isEmpty() && editingCommand() )
1048 Application::PostUserEvent( LINK( this, OQueryController, OnExecuteAddTable ) );
1051 setModified(sal_False);
1053 catch(const SQLException& e)
1055 DBG_UNHANDLED_EXCEPTION();
1056 // we caught an exception so we switch to text only mode
1058 m_bGraphicalDesign = false;
1059 getContainer()->initialize();
1060 ODataView* pWindow = getView();
1061 ScopedVclPtr<OSQLMessageBox>::Create(pWindow,e)->Execute();
1063 throw;
1067 void OQueryController::onLoadedMenu(const Reference< ::com::sun::star::frame::XLayoutManager >& /*_xLayoutManager*/)
1069 ensureToolbars( *this, m_bGraphicalDesign );
1072 OUString OQueryController::getPrivateTitle( ) const
1074 OUString sName = m_sName;
1075 if ( sName.isEmpty() )
1077 if ( !editingCommand() )
1079 SolarMutexGuard aSolarGuard;
1080 ::osl::MutexGuard aGuard( getMutex() );
1081 OUString aDefaultName = ModuleRes( editingView() ? STR_VIEW_TITLE : STR_QRY_TITLE );
1082 sName = aDefaultName.getToken(0,' ');
1083 sName += OUString::number(getCurrentStartNumber());
1086 return sName;
1089 void OQueryController::setQueryComposer()
1091 if(isConnected())
1093 Reference< XSQLQueryComposerFactory > xFactory(getConnection(), UNO_QUERY);
1094 OSL_ENSURE(xFactory.is(),"Connection doesn't support a querycomposer");
1095 if ( xFactory.is() && getContainer() )
1099 m_xComposer = xFactory->createQueryComposer();
1100 getContainer()->setStatement(m_sStatement);
1102 catch(const Exception&)
1104 m_xComposer = NULL;
1106 OSL_ENSURE(m_xComposer.is(),"No querycomposer available!");
1107 Reference<XTablesSupplier> xTablesSup(getConnection(), UNO_QUERY);
1108 deleteIterator();
1109 m_pSqlIterator = new ::connectivity::OSQLParseTreeIterator( getConnection(), xTablesSup->getTables(), m_aSqlParser, NULL );
1114 bool OQueryController::Construct(vcl::Window* pParent)
1116 // TODO: we have to check if we should create the text view or the design view
1118 setView( VclPtr<OQueryContainerWindow>::Create( pParent, *this, getORB() ) );
1120 return OJoinController::Construct(pParent);
1123 OJoinDesignView* OQueryController::getJoinView()
1125 return getContainer()->getDesignView();
1128 void OQueryController::describeSupportedFeatures()
1130 OJoinController::describeSupportedFeatures();
1131 implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT );
1132 implDescribeSupportedFeature( ".uno:SbaNativeSql", ID_BROWSER_ESCAPEPROCESSING,CommandGroup::FORMAT );
1133 implDescribeSupportedFeature( ".uno:DBViewFunctions", SID_QUERY_VIEW_FUNCTIONS, CommandGroup::VIEW );
1134 implDescribeSupportedFeature( ".uno:DBViewTableNames", SID_QUERY_VIEW_TABLES, CommandGroup::VIEW );
1135 implDescribeSupportedFeature( ".uno:DBViewAliases", SID_QUERY_VIEW_ALIASES, CommandGroup::VIEW );
1136 implDescribeSupportedFeature( ".uno:DBDistinctValues", SID_QUERY_DISTINCT_VALUES, CommandGroup::FORMAT );
1137 implDescribeSupportedFeature( ".uno:DBChangeDesignMode",ID_BROWSER_SQL, CommandGroup::VIEW );
1138 implDescribeSupportedFeature( ".uno:DBClearQuery", SID_BROWSER_CLEAR_QUERY, CommandGroup::EDIT );
1139 implDescribeSupportedFeature( ".uno:SbaExecuteSql", ID_BROWSER_QUERY_EXECUTE, CommandGroup::VIEW );
1140 implDescribeSupportedFeature( ".uno:DBAddRelation", SID_RELATION_ADD_RELATION, CommandGroup::EDIT );
1141 implDescribeSupportedFeature( ".uno:DBQueryPreview", SID_DB_QUERY_PREVIEW, CommandGroup::VIEW );
1142 implDescribeSupportedFeature( ".uno:DBLimit", SID_QUERY_LIMIT, CommandGroup::FORMAT );
1143 implDescribeSupportedFeature( ".uno:DBQueryPropertiesDialog", SID_QUERY_PROP_DLG, CommandGroup::FORMAT );
1145 #if OSL_DEBUG_LEVEL > 1
1146 implDescribeSupportedFeature( ".uno:DBShowParseTree", ID_EDIT_QUERY_SQL );
1147 implDescribeSupportedFeature( ".uno:DBMakeDisjunct", ID_EDIT_QUERY_DESIGN );
1148 #endif
1151 void OQueryController::impl_onModifyChanged()
1153 OJoinController::impl_onModifyChanged();
1154 InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
1155 InvalidateFeature(ID_BROWSER_SAVEASDOC);
1156 InvalidateFeature(ID_BROWSER_QUERY_EXECUTE);
1159 void SAL_CALL OQueryController::disposing( const EventObject& Source ) throw(RuntimeException, std::exception)
1161 SolarMutexGuard aGuard;
1163 if ( getContainer() && Source.Source.is() )
1165 if ( Source.Source == m_aCurrentFrame.getFrame() )
1166 { // our frame is being disposed -> close the preview window (if we have one)
1167 Reference< XFrame2 > xPreviewFrame( getContainer()->getPreviewFrame() );
1168 ::comphelper::disposeComponent( xPreviewFrame );
1170 else if ( Source.Source == getContainer()->getPreviewFrame() )
1172 getContainer()->disposingPreview();
1176 OJoinController::disposing(Source);
1179 void OQueryController::reconnect(bool _bUI)
1181 deleteIterator();
1182 ::comphelper::disposeComponent(m_xComposer);
1184 OJoinController::reconnect( _bUI );
1186 if (isConnected())
1188 setQueryComposer();
1190 else
1192 if(m_bGraphicalDesign)
1194 m_bGraphicalDesign = false;
1195 // don't call Execute(SQL) because this changes the sql statement
1196 impl_setViewMode( NULL );
1198 InvalidateAll();
1202 void OQueryController::saveViewSettings( ::comphelper::NamedValueCollection& o_rViewSettings, const bool i_includingCriteria ) const
1204 saveTableWindows( o_rViewSettings );
1206 OTableFields::const_iterator field = m_vTableFieldDesc.begin();
1207 OTableFields::const_iterator fieldEnd = m_vTableFieldDesc.end();
1209 ::comphelper::NamedValueCollection aAllFieldsData;
1210 ::comphelper::NamedValueCollection aFieldData;
1211 for ( sal_Int32 i = 1; field != fieldEnd; ++field, ++i )
1213 if ( !(*field)->IsEmpty() )
1215 aFieldData.clear();
1216 (*field)->Save( aFieldData, i_includingCriteria );
1218 const OUString sFieldSettingName = "Field" + OUString::number( i );
1219 aAllFieldsData.put( sFieldSettingName, aFieldData.getPropertyValues() );
1223 o_rViewSettings.put( "Fields", aAllFieldsData.getPropertyValues() );
1224 o_rViewSettings.put( "SplitterPosition", m_nSplitPos );
1225 o_rViewSettings.put( "VisibleRows", m_nVisibleRows );
1228 void OQueryController::loadViewSettings( const ::comphelper::NamedValueCollection& o_rViewSettings )
1230 loadTableWindows( o_rViewSettings );
1232 m_nSplitPos = o_rViewSettings.getOrDefault( "SplitterPosition", m_nSplitPos );
1233 m_nVisibleRows = o_rViewSettings.getOrDefault( "VisibleRows", m_nVisibleRows );
1234 m_aFieldInformation = o_rViewSettings.getOrDefault( "Fields", m_aFieldInformation );
1237 void OQueryController::execute_QueryPropDlg()
1239 ScopedVclPtrInstance<QueryPropertiesDialog> aQueryPropDlg(
1240 getContainer(), m_bDistinct, m_nLimit );
1242 if( aQueryPropDlg->Execute() == RET_OK )
1244 m_bDistinct = aQueryPropDlg->getDistinct();
1245 m_nLimit = aQueryPropDlg->getLimit();
1246 InvalidateFeature( SID_QUERY_DISTINCT_VALUES );
1247 InvalidateFeature( SID_QUERY_LIMIT, 0, true );
1251 sal_Int32 OQueryController::getColWidth(sal_uInt16 _nColPos) const
1253 if ( _nColPos < m_aFieldInformation.getLength() )
1255 ::std::unique_ptr<OTableFieldDesc> pField( new OTableFieldDesc());
1256 pField->Load( m_aFieldInformation[ _nColPos ], false );
1257 return pField->GetColWidth();
1259 return 0;
1262 Reference<XNameAccess> OQueryController::getObjectContainer() const
1264 Reference< XNameAccess > xElements;
1265 if ( editingView() )
1267 Reference< XViewsSupplier > xViewsSupp( getConnection(), UNO_QUERY );
1268 if ( xViewsSupp.is() )
1269 xElements = xViewsSupp->getViews();
1271 else
1273 Reference< XQueriesSupplier > xQueriesSupp( getConnection(), UNO_QUERY );
1274 if ( xQueriesSupp.is() )
1275 xElements = xQueriesSupp->getQueries();
1276 else
1278 Reference< XQueryDefinitionsSupplier > xQueryDefsSupp( getDataSource(), UNO_QUERY );
1279 if ( xQueryDefsSupp.is() )
1280 xElements = xQueryDefsSupp->getQueryDefinitions();
1284 OSL_ENSURE( xElements.is(), "OQueryController::getObjectContainer: unable to obtain the container!" );
1285 return xElements;
1288 void OQueryController::executeQuery()
1290 // we don't need to check the connection here because we already check the composer
1291 // which can't live without his connection
1292 OUString sTranslatedStmt = translateStatement( false );
1294 OUString sDataSourceName = getDataSourceName();
1295 if ( !(sDataSourceName.isEmpty() || sTranslatedStmt.isEmpty()) )
1299 getContainer()->showPreview( getFrame() );
1300 InvalidateFeature(SID_DB_QUERY_PREVIEW);
1302 URL aWantToDispatch;
1303 aWantToDispatch.Complete = ".component:DB/DataSourceBrowser";
1305 OUString sFrameName( FRAME_NAME_QUERY_PREVIEW );
1306 sal_Int32 nSearchFlags = FrameSearchFlag::CHILDREN;
1308 Reference< XDispatch> xDisp;
1309 Reference< XDispatchProvider> xProv( getFrame()->findFrame( sFrameName, nSearchFlags ), UNO_QUERY );
1310 if(!xProv.is())
1312 xProv.set( getFrame(), UNO_QUERY );
1313 if (xProv.is())
1314 xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, nSearchFlags);
1316 else
1318 xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, FrameSearchFlag::SELF);
1320 if (xDisp.is())
1322 Sequence< PropertyValue> aProps(9);
1323 aProps[0].Name = PROPERTY_DATASOURCENAME;
1324 aProps[0].Value <<= sDataSourceName;
1326 aProps[1].Name = PROPERTY_COMMAND_TYPE;
1327 aProps[1].Value <<= CommandType::COMMAND;
1329 aProps[2].Name = PROPERTY_COMMAND;
1330 aProps[2].Value <<= sTranslatedStmt;
1332 aProps[3].Name = PROPERTY_ENABLE_BROWSER;
1333 aProps[3].Value <<= false;
1335 aProps[4].Name = PROPERTY_ACTIVE_CONNECTION;
1336 aProps[4].Value <<= getConnection();
1338 aProps[5].Name = PROPERTY_UPDATE_CATALOGNAME;
1339 aProps[5].Value <<= m_sUpdateCatalogName;
1341 aProps[6].Name = PROPERTY_UPDATE_SCHEMANAME;
1342 aProps[6].Value <<= m_sUpdateSchemaName;
1344 aProps[7].Name = PROPERTY_UPDATE_TABLENAME;
1345 aProps[7].Value <<= m_sUpdateTableName;
1347 aProps[8].Name = PROPERTY_ESCAPE_PROCESSING;
1348 aProps[8].Value <<= m_bEscapeProcessing;
1350 xDisp->dispatch(aWantToDispatch, aProps);
1351 // check the state of the beamer
1352 // be notified when the beamer frame is closed
1353 Reference< XComponent > xComponent( getFrame()->findFrame( sFrameName, nSearchFlags ), UNO_QUERY );
1354 if (xComponent.is())
1356 OSL_ENSURE(Reference< XFrame >(xComponent, UNO_QUERY).get() == getContainer()->getPreviewFrame().get(),
1357 "OQueryController::executeQuery: oops ... which window do I have here?");
1358 Reference< XEventListener> xEvtL((::cppu::OWeakObject*)this,UNO_QUERY);
1359 xComponent->addEventListener(xEvtL);
1362 else
1364 OSL_FAIL("Couldn't create a beamer window!");
1367 catch(const Exception&)
1369 OSL_FAIL("Couldn't create a beamer window!");
1374 bool OQueryController::askForNewName(const Reference<XNameAccess>& _xElements, bool _bSaveAs)
1376 OSL_ENSURE( !editingCommand(), "OQueryController::askForNewName: not to be called when designing an independent statement!" );
1377 if ( editingCommand() )
1378 return false;
1380 OSL_PRECOND( _xElements.is(), "OQueryController::askForNewName: invalid container!" );
1381 if ( !_xElements.is() )
1382 return false;
1384 bool bRet = true;
1385 bool bNew = _bSaveAs || !_xElements->hasByName( m_sName );
1386 if(bNew)
1388 OUString aDefaultName;
1389 if ( ( _bSaveAs && !bNew ) || ( bNew && !m_sName.isEmpty() ) )
1390 aDefaultName = m_sName;
1391 else
1393 OUString sName = ModuleRes( editingView() ? STR_VIEW_TITLE : STR_QRY_TITLE );
1394 aDefaultName = sName.getToken(0,' ');
1395 aDefaultName = ::dbtools::createUniqueName(_xElements,aDefaultName);
1398 DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::QUERY );
1399 ScopedVclPtrInstance<OSaveAsDlg> aDlg(
1400 getView(),
1401 m_nCommandType,
1402 getORB(),
1403 getConnection(),
1404 aDefaultName,
1405 aNameChecker,
1406 SAD_DEFAULT );
1408 bRet = ( aDlg->Execute() == RET_OK );
1409 if ( bRet )
1411 m_sName = aDlg->getName();
1412 if ( editingView() )
1414 m_sUpdateCatalogName = aDlg->getCatalog();
1415 m_sUpdateSchemaName = aDlg->getSchema();
1419 return bRet;
1422 bool OQueryController::doSaveAsDoc(bool _bSaveAs)
1424 OSL_ENSURE(isEditable(),"Slot ID_BROWSER_SAVEDOC should not be enabled!");
1425 if ( !editingCommand() && !haveDataSource() )
1427 OUString aMessage(ModuleRes(STR_DATASOURCE_DELETED));
1428 ScopedVclPtr<OSQLWarningBox>::Create( getView(), aMessage )->Execute();
1429 return false;
1432 Reference< XNameAccess > xElements = getObjectContainer();
1433 if ( !xElements.is() )
1434 return false;
1436 if ( !getContainer()->checkStatement() )
1437 return false;
1439 OUString sTranslatedStmt = translateStatement();
1440 if ( editingCommand() )
1442 setModified( sal_False );
1443 // this is all we need to do here. translateStatement implicitly set our m_sStatement, and
1444 // notified it, and that's all
1445 return true;
1448 if ( sTranslatedStmt.isEmpty() )
1449 return false;
1451 // first we need a name for our query so ask the user
1452 // did we get a name
1453 OUString sOriginalName( m_sName );
1454 if ( !askForNewName( xElements, _bSaveAs ) || m_sName.isEmpty() )
1455 return false;
1457 SQLExceptionInfo aInfo;
1458 bool bSuccess = false;
1459 bool bNew = false;
1462 bNew = ( _bSaveAs )
1463 || ( !xElements->hasByName( m_sName ) );
1465 Reference<XPropertySet> xQuery;
1466 if ( bNew ) // just to make sure the query already exists
1468 // drop the query, in case it already exists
1469 if ( xElements->hasByName( m_sName ) )
1471 Reference< XDrop > xNameCont( xElements, UNO_QUERY );
1472 if ( xNameCont.is() )
1473 xNameCont->dropByName( m_sName );
1474 else
1476 Reference< XNameContainer > xCont( xElements, UNO_QUERY );
1477 if ( xCont.is() )
1478 xCont->removeByName( m_sName );
1482 // create a new (empty, uninitialized) query resp. view
1483 Reference< XDataDescriptorFactory > xFact( xElements, UNO_QUERY );
1484 if ( xFact.is() )
1486 xQuery = xFact->createDataDescriptor();
1487 // to set the name is only allowed when the query is new
1488 xQuery->setPropertyValue( PROPERTY_NAME, makeAny( m_sName ) );
1490 else
1492 Reference< XSingleServiceFactory > xSingleFac( xElements, UNO_QUERY );
1493 if ( xSingleFac.is() )
1494 xQuery.set(xSingleFac->createInstance(), css::uno::UNO_QUERY);
1497 else
1499 xElements->getByName( m_sName ) >>= xQuery;
1501 if ( !xQuery.is() )
1502 throw RuntimeException();
1504 // the new commands
1505 if ( editingView() && !bNew )
1507 OSL_ENSURE( xQuery == m_xAlterView, "OQueryController::doSaveAsDoc: already have another alterable view ...!?" );
1508 m_xAlterView.set( xQuery, UNO_QUERY_THROW );
1509 m_xAlterView->alterCommand( sTranslatedStmt );
1511 else
1512 { // we're creating a query, or a *new* view
1513 xQuery->setPropertyValue( PROPERTY_COMMAND, makeAny( sTranslatedStmt ) );
1515 if ( editingView() )
1517 xQuery->setPropertyValue( PROPERTY_CATALOGNAME, makeAny( m_sUpdateCatalogName ) );
1518 xQuery->setPropertyValue( PROPERTY_SCHEMANAME, makeAny( m_sUpdateSchemaName ) );
1521 if ( editingQuery() )
1523 xQuery->setPropertyValue( PROPERTY_UPDATE_TABLENAME, makeAny( m_sUpdateTableName ) );
1524 xQuery->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, css::uno::makeAny( m_bEscapeProcessing ) );
1526 xQuery->setPropertyValue( PROPERTY_LAYOUTINFORMATION, getViewData() );
1530 if ( bNew )
1532 Reference< XAppend > xAppend( xElements, UNO_QUERY );
1533 if ( xAppend.is() )
1535 xAppend->appendByDescriptor( xQuery );
1537 else
1539 Reference< XNameContainer > xCont( xElements, UNO_QUERY );
1540 if ( xCont.is() )
1541 xCont->insertByName( m_sName, makeAny( xQuery ) );
1544 if ( editingView() )
1546 Reference< XPropertySet > xViewProps;
1547 if ( xElements->hasByName( m_sName ) )
1548 xViewProps.set( xElements->getByName( m_sName ), UNO_QUERY );
1550 if ( !xViewProps.is() ) // correct name and try again
1551 m_sName = ::dbtools::composeTableName( getMetaData(), xQuery, ::dbtools::eInDataManipulation, false, false, false );
1553 OSL_ENSURE( xElements->hasByName( m_sName ), "OQueryController::doSaveAsDoc: newly creaed view does not exist!" );
1555 if ( xElements->hasByName( m_sName ) )
1556 m_xAlterView.set( xElements->getByName( m_sName ), UNO_QUERY );
1558 // now check if our datasource has set a tablefilter and if so, append the new table name to it
1559 ::dbaui::appendToFilter( getConnection(), m_sName, getORB(), getView() );
1561 Reference< XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY);
1562 if ( xEventListener.is() )
1564 TitleChangedEvent aEvent;
1565 xEventListener->titleChanged(aEvent);
1567 releaseNumberForComponent();
1570 setModified( sal_False );
1571 bSuccess = true;
1574 catch(const SQLException&)
1576 if ( !bNew )
1577 m_sName = sOriginalName;
1578 aInfo = SQLExceptionInfo( ::cppu::getCaughtException() );
1580 catch(const Exception&)
1582 if ( !bNew )
1583 m_sName = sOriginalName;
1584 DBG_UNHANDLED_EXCEPTION();
1587 showError( aInfo );
1589 // if we successfully saved a view we were creating, then close the designer
1590 if ( bSuccess && editingView() && !m_xAlterView.is() )
1592 closeTask();
1595 if ( bSuccess && editingView() )
1596 InvalidateFeature( ID_BROWSER_EDITDOC );
1598 return bSuccess;
1601 namespace {
1602 struct CommentStrip
1604 OUString maComment;
1605 bool mbLastOnLine;
1606 CommentStrip( const OUString& rComment, bool bLastOnLine )
1607 : maComment( rComment), mbLastOnLine( bLastOnLine) {}
1612 /** Obtain all comments in a query.
1614 See also delComment() implementation for OSQLParser::parseTree().
1616 static ::std::vector< CommentStrip > getComment( const OUString& rQuery )
1618 ::std::vector< CommentStrip > aRet;
1619 // First a quick search if there is any "--" or "//" or "/*", if not then
1620 // the whole copying loop is pointless.
1621 if (rQuery.indexOf( "--" ) < 0 && rQuery.indexOf( "//" ) < 0 &&
1622 rQuery.indexOf( "/*" ) < 0)
1623 return aRet;
1625 const sal_Unicode* pCopy = rQuery.getStr();
1626 const sal_Int32 nQueryLen = rQuery.getLength();
1627 bool bIsText1 = false; // "text"
1628 bool bIsText2 = false; // 'text'
1629 bool bComment2 = false; // /* comment */
1630 bool bComment = false; // -- or // comment
1631 OUStringBuffer aBuf;
1632 for (sal_Int32 i=0; i < nQueryLen; ++i)
1634 if (bComment2)
1636 aBuf.append( &pCopy[i], 1);
1637 if ((i+1) < nQueryLen)
1639 if (pCopy[i]=='*' && pCopy[i+1]=='/')
1641 bComment2 = false;
1642 aBuf.append( &pCopy[++i], 1);
1643 aRet.push_back( CommentStrip( aBuf.makeStringAndClear(), false));
1646 else
1648 // comment can't close anymore, actually an error, but..
1649 aRet.push_back( CommentStrip( aBuf.makeStringAndClear(), false));
1651 continue;
1653 if (pCopy[i] == '\n' || i == nQueryLen-1)
1655 if (bComment)
1657 if (i == nQueryLen-1 && pCopy[i] != '\n')
1658 aBuf.append( &pCopy[i], 1);
1659 aRet.push_back( CommentStrip( aBuf.makeStringAndClear(), true));
1660 bComment = false;
1662 else if (!aRet.empty())
1663 aRet.back().mbLastOnLine = true;
1665 else if (!bComment)
1667 if (pCopy[i] == '\"' && !bIsText2)
1668 bIsText1 = !bIsText1;
1669 else if (pCopy[i] == '\'' && !bIsText1)
1670 bIsText2 = !bIsText2;
1671 if (!bIsText1 && !bIsText2 && (i+1) < nQueryLen)
1673 if ((pCopy[i]=='-' && pCopy[i+1]=='-') || (pCopy[i]=='/' && pCopy[i+1]=='/'))
1674 bComment = true;
1675 else if ((pCopy[i]=='/' && pCopy[i+1]=='*'))
1676 bComment2 = true;
1679 if (bComment || bComment2)
1680 aBuf.append( &pCopy[i], 1);
1682 return aRet;
1685 /** Concat/insert comments that were previously obtained with getComment().
1687 NOTE: The current parser implementation does not preserve newlines, so all
1688 comments are always appended to the entire query, also inline comments
1689 that would need positioning anyway that can't be obtained after
1690 recomposition. This is ugly but at least allows commented queries while
1691 preserving the comments _somehow_.
1693 static OUString concatComment( const OUString& rQuery, const ::std::vector< CommentStrip >& rComments )
1695 // No comments => return query.
1696 if (rComments.empty())
1697 return rQuery;
1699 const sal_Unicode* pBeg = rQuery.getStr();
1700 const sal_Int32 nLen = rQuery.getLength();
1701 const size_t nComments = rComments.size();
1702 // Obtaining the needed size once should be faster than reallocating.
1703 // Also add a blank or linefeed for each comment.
1704 sal_Int32 nBufSize = nLen + nComments;
1705 for (::std::vector< CommentStrip >::const_iterator it( rComments.begin()); it != rComments.end(); ++it)
1706 nBufSize += (*it).maComment.getLength();
1707 OUStringBuffer aBuf( nBufSize );
1708 sal_Int32 nIndBeg = 0;
1709 sal_Int32 nIndLF = rQuery.indexOf('\n');
1710 size_t i = 0;
1711 while (nIndLF >= 0 && i < nComments)
1713 aBuf.append( pBeg + nIndBeg, nIndLF - nIndBeg);
1716 aBuf.append( rComments[i].maComment);
1717 } while (!rComments[i++].mbLastOnLine && i < nComments);
1718 aBuf.append( pBeg + nIndLF, 1); // the LF
1719 nIndBeg = nIndLF + 1;
1720 nIndLF = (nIndBeg < nLen ? rQuery.indexOf( '\n', nIndBeg) : -1);
1722 // Append remainder of query.
1723 if (nIndBeg < nLen)
1724 aBuf.append( pBeg + nIndBeg, nLen - nIndBeg);
1725 // Append all remaining comments, preserve lines.
1726 bool bNewLine = false;
1727 for ( ; i < nComments; ++i)
1729 if (!bNewLine)
1730 aBuf.append( ' ');
1731 aBuf.append( rComments[i].maComment);
1732 if (rComments[i].mbLastOnLine)
1734 aBuf.append( '\n');
1735 bNewLine = true;
1737 else
1738 bNewLine = false;
1740 return aBuf.makeStringAndClear();
1743 OUString OQueryController::translateStatement( bool _bFireStatementChange )
1745 // now set the properties
1746 setStatement_fireEvent( getContainer()->getStatement(), _bFireStatementChange );
1747 OUString sTranslatedStmt;
1748 if(!m_sStatement.isEmpty() && m_xComposer.is() && m_bEscapeProcessing)
1752 OUString aErrorMsg;
1754 ::std::vector< CommentStrip > aComments = getComment( m_sStatement);
1756 ::connectivity::OSQLParseNode* pNode = m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign );
1757 if(pNode)
1759 pNode->parseNodeToStr( sTranslatedStmt, getConnection() );
1760 delete pNode;
1763 m_xComposer->setQuery(sTranslatedStmt);
1764 sTranslatedStmt = m_xComposer->getComposedQuery();
1765 sTranslatedStmt = concatComment( sTranslatedStmt, aComments);
1767 catch(const SQLException& e)
1769 ::dbtools::SQLExceptionInfo aInfo(e);
1770 showError(aInfo);
1771 // an error occurred so we clear the statement
1772 sTranslatedStmt.clear();
1775 else if(m_sStatement.isEmpty())
1777 ModuleRes aModuleRes(STR_QRY_NOSELECT);
1778 OUString sTmpStr(aModuleRes);
1779 OUString sError(sTmpStr);
1780 showError(SQLException(sError,NULL,"S1000",1000,Any()));
1782 else
1783 sTranslatedStmt = m_sStatement;
1785 return sTranslatedStmt;
1788 short OQueryController::saveModified()
1790 SolarMutexGuard aSolarGuard;
1791 ::osl::MutexGuard aGuard( getMutex() );
1792 short nRet = RET_YES;
1793 if ( !isConnected() || !isModified() )
1794 return nRet;
1796 if ( !m_bGraphicalDesign
1797 || ( !m_vTableFieldDesc.empty()
1798 && !m_vTableData.empty()
1802 OUString sMessageText( lcl_getObjectResourceString( STR_QUERY_SAVEMODIFIED, m_nCommandType ) );
1803 ScopedVclPtrInstance< QueryBox > aQry( getView(), WB_YES_NO_CANCEL | WB_DEF_YES, sMessageText );
1805 nRet = aQry->Execute();
1806 if ( ( nRet == RET_YES )
1807 && !doSaveAsDoc( false )
1810 nRet = RET_CANCEL;
1813 return nRet;
1816 void OQueryController::impl_reset( const bool i_bForceCurrentControllerSettings )
1818 bool bValid = false;
1820 Sequence< PropertyValue > aLayoutInformation;
1821 // get command from the query if a query name was supplied
1822 if ( !i_bForceCurrentControllerSettings && !editingCommand() )
1824 if ( !m_sName.isEmpty() )
1826 Reference< XNameAccess > xQueries = getObjectContainer();
1827 if ( xQueries.is() )
1829 Reference< XPropertySet > xProp;
1830 if( xQueries->hasByName( m_sName ) && ( xQueries->getByName( m_sName ) >>= xProp ) && xProp.is() )
1832 OUString sNewStatement;
1833 xProp->getPropertyValue( PROPERTY_COMMAND ) >>= sNewStatement;
1834 setStatement_fireEvent( sNewStatement );
1836 if ( editingQuery() )
1838 bool bNewEscapeProcessing( true );
1839 xProp->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bNewEscapeProcessing;
1840 setEscapeProcessing_fireEvent( bNewEscapeProcessing );
1843 m_bGraphicalDesign = m_bGraphicalDesign && m_bEscapeProcessing;
1844 bValid = true;
1848 if ( editingQuery() )
1849 xProp->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) >>= aLayoutInformation;
1851 catch( const Exception& )
1853 OSL_FAIL( "OQueryController::impl_reset: could not retrieve the layout information from the query!" );
1859 else
1861 bValid = true;
1862 // assume that we got all necessary information during initialization
1865 if ( bValid )
1867 // load the layoutInformation
1868 if ( aLayoutInformation.getLength() )
1872 loadViewSettings( aLayoutInformation );
1874 catch( const Exception& )
1876 DBG_UNHANDLED_EXCEPTION();
1880 if ( !m_sStatement.isEmpty() )
1882 setQueryComposer();
1884 bool bError( false );
1886 if ( !m_pSqlIterator )
1888 bError = true;
1890 else if ( m_bEscapeProcessing )
1892 OUString aErrorMsg;
1893 ::std::unique_ptr< ::connectivity::OSQLParseNode > pNode(
1894 m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign ) );
1896 if ( pNode.get() )
1898 delete m_pSqlIterator->getParseTree();
1899 m_pSqlIterator->setParseTree( pNode.release() );
1900 m_pSqlIterator->traverseAll();
1901 if ( m_pSqlIterator->hasErrors() )
1903 if ( !i_bForceCurrentControllerSettings && m_bGraphicalDesign && !editingView() )
1905 impl_showAutoSQLViewError( makeAny( m_pSqlIterator->getErrors() ) );
1907 bError = true;
1910 else
1912 if ( !i_bForceCurrentControllerSettings && !editingView() )
1914 OUString aTitle(ModuleRes(STR_SVT_SQL_SYNTAX_ERROR));
1915 ScopedVclPtrInstance< OSQLMessageBox > aDlg(getView(),aTitle,aErrorMsg);
1916 aDlg->Execute();
1918 bError = true;
1922 if ( bError )
1924 m_bGraphicalDesign = false;
1925 if ( editingView() )
1926 // if we're editing a view whose statement could not be parsed, default to "no escape processing"
1927 setEscapeProcessing_fireEvent( false );
1932 if(!m_pSqlIterator)
1933 setQueryComposer();
1934 OSL_ENSURE(m_pSqlIterator,"No SQLIterator set!");
1936 getContainer()->setNoneVisbleRow(m_nVisibleRows);
1939 void OQueryController::reset()
1941 impl_reset();
1942 getContainer()->reset( NULL );
1943 ClearUndoManager();
1946 void OQueryController::setStatement_fireEvent( const OUString& _rNewStatement, bool _bFireStatementChange )
1948 Any aOldValue = makeAny( m_sStatement );
1949 m_sStatement = _rNewStatement;
1950 Any aNewValue = makeAny( m_sStatement );
1952 sal_Int32 nHandle = PROPERTY_ID_ACTIVECOMMAND;
1953 if ( _bFireStatementChange )
1954 fire( &nHandle, &aNewValue, &aOldValue, 1, sal_False );
1957 void OQueryController::setEscapeProcessing_fireEvent( const bool _bEscapeProcessing )
1959 if ( _bEscapeProcessing == m_bEscapeProcessing )
1960 return;
1962 Any aOldValue = makeAny( m_bEscapeProcessing );
1963 m_bEscapeProcessing = _bEscapeProcessing;
1964 Any aNewValue = makeAny( m_bEscapeProcessing );
1966 sal_Int32 nHandle = PROPERTY_ID_ESCAPE_PROCESSING;
1967 fire( &nHandle, &aNewValue, &aOldValue, 1, sal_False );
1970 IMPL_LINK_NOARG( OQueryController, OnExecuteAddTable )
1972 Execute( ID_BROWSER_ADDTABLE,Sequence<PropertyValue>() );
1973 return 0L;
1976 bool OQueryController::allowViews() const
1978 return true;
1981 bool OQueryController::allowQueries() const
1983 OSL_ENSURE( getSdbMetaData().isConnected(), "OQueryController::allowQueries: illegal call!" );
1984 if ( !getSdbMetaData().supportsSubqueriesInFrom() )
1985 return false;
1987 const NamedValueCollection& rArguments( getInitParams() );
1988 sal_Int32 nCommandType = rArguments.getOrDefault( OUString(PROPERTY_COMMAND_TYPE), (sal_Int32)CommandType::QUERY );
1989 bool bCreatingView = ( nCommandType == CommandType::TABLE );
1990 return !bCreatingView;
1993 Any SAL_CALL OQueryController::getViewData() throw( RuntimeException, std::exception )
1995 ::osl::MutexGuard aGuard( getMutex() );
1997 getContainer()->SaveUIConfig();
1999 ::comphelper::NamedValueCollection aViewSettings;
2000 saveViewSettings( aViewSettings, false );
2002 return makeAny( aViewSettings.getPropertyValues() );
2005 void SAL_CALL OQueryController::restoreViewData(const Any& /*Data*/) throw( RuntimeException, std::exception )
2007 // TODO
2010 } // namespace dbaui
2012 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */