1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <databaseobjectview.hxx>
21 #include <strings.hxx>
22 #include <asyncmodaldialog.hxx>
23 
24 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
25 #include <com/sun/star/frame/TaskCreator.hpp>
26 #include <com/sun/star/frame/XFrame.hpp>
27 #include <com/sun/star/sdb/CommandType.hpp>
28 #include <com/sun/star/sdb/application/XTableUIProvider.hpp>
29 #include <com/sun/star/beans/NamedValue.hpp>
30 
31 #include <connectivity/dbtools.hxx>
32 #include <osl/diagnose.h>
33 #include <toolkit/helper/vclunohelper.hxx>
34 #include <tools/diagnose_ex.h>
35 #include <vcl/window.hxx>
36 
37 namespace dbaui
38 {
39 
40     using namespace ::com::sun::star::uno;
41     using namespace ::com::sun::star::sdbc;
42     using namespace ::com::sun::star::sdb;
43     using namespace ::com::sun::star::sdb::application;
44     using namespace ::com::sun::star::ui::dialogs;
45     using namespace ::com::sun::star::frame;
46     using namespace ::com::sun::star::lang;
47     using namespace ::com::sun::star::beans;
48     using namespace ::com::sun::star::awt;
49 
50     // DatabaseObjectView
DatabaseObjectView(const Reference<XComponentContext> & _rxORB,const Reference<XDatabaseDocumentUI> & _rxApplication,const Reference<XFrame> & _rxParentFrame,const OUString & _rComponentURL)51     DatabaseObjectView::DatabaseObjectView( const Reference< XComponentContext >& _rxORB,
52             const Reference< XDatabaseDocumentUI >& _rxApplication,
53             const Reference< XFrame >& _rxParentFrame,
54             const OUString& _rComponentURL )
55         :m_xORB             ( _rxORB            )
56         ,m_xParentFrame     ( _rxParentFrame    )
57         ,m_xFrameLoader     (                   )
58         ,m_xApplication     ( _rxApplication    )
59         ,m_sComponentURL    ( _rComponentURL    )
60     {
61         OSL_ENSURE( m_xORB.is(), "DatabaseObjectView::DatabaseObjectView: invalid service factory!" );
62         OSL_ENSURE( m_xApplication.is(), "DatabaseObjectView::DatabaseObjectView: invalid connection!" );
63     }
64 
getConnection() const65     Reference< XConnection > DatabaseObjectView::getConnection() const
66     {
67         Reference< XConnection > xConnection;
68         if ( m_xApplication.is() )
69             xConnection = m_xApplication->getActiveConnection();
70         return xConnection;
71     }
72 
createNew(const Reference<XDataSource> & _xDataSource,const::comphelper::NamedValueCollection & i_rDispatchArgs)73     Reference< XComponent > DatabaseObjectView::createNew( const Reference< XDataSource >& _xDataSource, const ::comphelper::NamedValueCollection& i_rDispatchArgs )
74     {
75         return doCreateView( makeAny( _xDataSource ), OUString(), i_rDispatchArgs );
76     }
77 
openExisting(const Any & _rDataSource,const OUString & _rName,const::comphelper::NamedValueCollection & i_rDispatchArgs)78     Reference< XComponent > DatabaseObjectView::openExisting( const Any& _rDataSource, const OUString& _rName,
79             const ::comphelper::NamedValueCollection& i_rDispatchArgs )
80     {
81         return doCreateView( _rDataSource, _rName, i_rDispatchArgs );
82     }
83 
doCreateView(const Any & _rDataSource,const OUString & _rObjectName,const::comphelper::NamedValueCollection & i_rCreationArgs)84     Reference< XComponent > DatabaseObjectView::doCreateView( const Any& _rDataSource, const OUString& _rObjectName,
85         const ::comphelper::NamedValueCollection& i_rCreationArgs )
86     {
87         ::comphelper::NamedValueCollection aDispatchArgs;
88 
89         aDispatchArgs.merge( i_rCreationArgs, false );    // false => do not overwrite
90         fillDispatchArgs( aDispatchArgs, _rDataSource, _rObjectName );
91         aDispatchArgs.merge( i_rCreationArgs, true );    // true => do overwrite
92 
93         return doDispatch( aDispatchArgs );
94     }
95 
doDispatch(const::comphelper::NamedValueCollection & i_rDispatchArgs)96     Reference< XComponent > DatabaseObjectView::doDispatch( const ::comphelper::NamedValueCollection& i_rDispatchArgs )
97     {
98         Reference< XComponent > xReturn;
99         if ( m_xORB.is() )
100         {
101             try
102             {
103                 // if we have no externally provided frame, create one
104                 if ( !m_xFrameLoader.is() )
105                 {
106                     Reference< XSingleServiceFactory > xFact = TaskCreator::create(m_xORB);
107                     Sequence< Any > lArgs(3);
108                     NamedValue      aProp;
109                     sal_Int32       nArg = 0;
110 
111                     aProp.Name    = "ParentFrame";
112                     aProp.Value <<= m_xParentFrame;
113                     lArgs[nArg++] <<= aProp;
114 
115                     aProp.Name    = "TopWindow";
116                     aProp.Value <<= true;
117                     lArgs[nArg++] <<= aProp;
118 
119                     aProp.Name    = "SupportPersistentWindowState";
120                     aProp.Value <<= true;
121                     lArgs[nArg++] <<= aProp;
122 
123                     m_xFrameLoader.set(xFact->createInstanceWithArguments(lArgs), UNO_QUERY_THROW);
124 
125                     // everything we load can be considered a "top level document", so set the respective bit at the window.
126                     // This, amongst other things, triggers that the component in this task participates in the
127                     // "ThisComponent"-game for the global application Basic.
128                     const Reference< XFrame > xFrame( m_xFrameLoader, UNO_QUERY_THROW );
129                     const Reference< XWindow > xFrameWindow( xFrame->getContainerWindow(), UNO_SET_THROW );
130                     VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( xFrameWindow );
131                     ENSURE_OR_THROW( pContainerWindow, "no implementation access to the frame's container window!" );
132                     pContainerWindow->SetExtendedStyle( pContainerWindow->GetExtendedStyle() | WindowExtendedStyle::Document );
133                 }
134 
135                 Reference< XComponentLoader > xFrameLoader( m_xFrameLoader, UNO_SET_THROW );
136                 xReturn = xFrameLoader->loadComponentFromURL(
137                     m_sComponentURL,
138                     "_self",
139                     0,
140                     i_rDispatchArgs.getPropertyValues()
141                 );
142             }
143             catch( const Exception& )
144             {
145                 DBG_UNHANDLED_EXCEPTION("dbaccess");
146             }
147         }
148         return xReturn;
149     }
150 
fillDispatchArgs(::comphelper::NamedValueCollection & i_rDispatchArgs,const Any & _aDataSource,const OUString &)151     void DatabaseObjectView::fillDispatchArgs(
152             ::comphelper::NamedValueCollection& i_rDispatchArgs,
153             const Any& _aDataSource,
154             const OUString& /* _rName */
155         )
156     {
157         OUString sDataSource;
158         Reference<XDataSource> xDataSource;
159         if ( _aDataSource >>= sDataSource )
160         {
161             i_rDispatchArgs.put( OUString(PROPERTY_DATASOURCENAME), sDataSource );
162         }
163         else if ( _aDataSource >>= xDataSource )
164         {
165             i_rDispatchArgs.put( OUString(PROPERTY_DATASOURCE), xDataSource );
166         }
167 
168         i_rDispatchArgs.put( OUString(PROPERTY_ACTIVE_CONNECTION), getConnection() );
169     }
170 
171     // QueryDesigner
QueryDesigner(const Reference<XComponentContext> & _rxORB,const Reference<XDatabaseDocumentUI> & _rxApplication,const Reference<XFrame> & _rxParentFrame,bool _bCreateView)172     QueryDesigner::QueryDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication,
173         const Reference< XFrame >& _rxParentFrame, bool _bCreateView )
174         :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, _bCreateView ? OUString(URL_COMPONENT_VIEWDESIGN) : OUString(URL_COMPONENT_QUERYDESIGN) )
175         ,m_nCommandType( _bCreateView ? CommandType::TABLE : CommandType::QUERY )
176     {
177     }
178 
fillDispatchArgs(::comphelper::NamedValueCollection & i_rDispatchArgs,const Any & _aDataSource,const OUString & _rObjectName)179     void QueryDesigner::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource,
180         const OUString& _rObjectName )
181     {
182         DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rObjectName );
183 
184         const bool bIncludeQueryName = !_rObjectName.isEmpty();
185         const bool bGraphicalDesign = i_rDispatchArgs.getOrDefault( PROPERTY_GRAPHICAL_DESIGN, true );
186         const bool bEditViewAsSQLCommand = ( m_nCommandType == CommandType::TABLE ) && !bGraphicalDesign;
187 
188         i_rDispatchArgs.put( OUString(PROPERTY_COMMAND_TYPE), m_nCommandType );
189 
190         if ( bIncludeQueryName )
191         {
192             i_rDispatchArgs.put( OUString(PROPERTY_COMMAND), _rObjectName );
193         }
194 
195         if ( bEditViewAsSQLCommand )
196         {
197             i_rDispatchArgs.put( OUString(PROPERTY_ESCAPE_PROCESSING), false );
198         }
199     }
200 
201     // TableDesigner
TableDesigner(const Reference<XComponentContext> & _rxORB,const Reference<XDatabaseDocumentUI> & _rxApplication,const Reference<XFrame> & _rxParentFrame)202     TableDesigner::TableDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame )
203         :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast< OUString >( URL_COMPONENT_TABLEDESIGN ) )
204     {
205     }
206 
fillDispatchArgs(::comphelper::NamedValueCollection & i_rDispatchArgs,const Any & _aDataSource,const OUString & _rObjectName)207     void TableDesigner::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource,
208         const OUString& _rObjectName )
209     {
210         DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rObjectName );
211 
212         if ( !_rObjectName.isEmpty() )
213         {
214             i_rDispatchArgs.put( OUString(PROPERTY_CURRENTTABLE), _rObjectName );
215         }
216     }
217 
doCreateView(const Any & _rDataSource,const OUString & _rObjectName,const::comphelper::NamedValueCollection & i_rCreationArgs)218     Reference< XComponent > TableDesigner::doCreateView( const Any& _rDataSource, const OUString& _rObjectName,
219         const ::comphelper::NamedValueCollection& i_rCreationArgs )
220     {
221         bool bIsNewDesign =  _rObjectName.isEmpty();
222 
223         // let's see whether the connection can provide a dedicated table designer
224         Reference< XInterface > xDesigner;
225         if ( !bIsNewDesign )
226             xDesigner = impl_getConnectionProvidedDesigner_nothrow( _rObjectName );
227 
228         if ( !xDesigner.is() )
229             return DatabaseObjectView::doCreateView( _rDataSource, _rObjectName, i_rCreationArgs );
230 
231         // try whether the designer is a dialog
232         Reference< XExecutableDialog > xDialog( xDesigner, UNO_QUERY_THROW );
233         try { AsyncDialogExecutor::executeModalDialogAsync( xDialog ); }
234         catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); }
235         return nullptr;
236     }
237 
impl_getConnectionProvidedDesigner_nothrow(const OUString & _rTableName)238     Reference< XInterface > TableDesigner::impl_getConnectionProvidedDesigner_nothrow( const OUString& _rTableName )
239     {
240         Reference< XInterface > xDesigner;
241         try
242         {
243             Reference< XTableUIProvider > xTableUIProv( getConnection(), UNO_QUERY );
244             if ( xTableUIProv.is() )
245                 xDesigner = xTableUIProv->getTableEditor( getApplicationUI(), _rTableName );
246         }
247         catch( const Exception& )
248         {
249             DBG_UNHANDLED_EXCEPTION("dbaccess");
250         }
251         return xDesigner;
252     }
253 
254     // ResultSetBrowser
ResultSetBrowser(const Reference<XComponentContext> & _rxORB,const Reference<XDatabaseDocumentUI> & _rxApplication,const Reference<XFrame> & _rxParentFrame,bool _bTable)255     ResultSetBrowser::ResultSetBrowser( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame,
256             bool _bTable )
257         :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast < OUString >( URL_COMPONENT_DATASOURCEBROWSER ) )
258         ,m_bTable(_bTable)
259     {
260     }
261 
fillDispatchArgs(::comphelper::NamedValueCollection & i_rDispatchArgs,const Any & _aDataSource,const OUString & _rQualifiedName)262     void ResultSetBrowser::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource,
263         const OUString& _rQualifiedName)
264     {
265         DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rQualifiedName );
266         OSL_ENSURE( !_rQualifiedName.isEmpty(),"A Table name must be set");
267         OUString sCatalog;
268         OUString sSchema;
269         OUString sTable;
270         if ( m_bTable )
271             ::dbtools::qualifiedNameComponents( getConnection()->getMetaData(), _rQualifiedName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
272 
273         i_rDispatchArgs.put( OUString(PROPERTY_COMMAND_TYPE), (m_bTable ? CommandType::TABLE : CommandType::QUERY) );
274         i_rDispatchArgs.put( OUString(PROPERTY_COMMAND), _rQualifiedName );
275         i_rDispatchArgs.put( OUString(PROPERTY_ENABLE_BROWSER), false );
276 
277         if ( m_bTable )
278         {
279             i_rDispatchArgs.put( OUString(PROPERTY_UPDATE_CATALOGNAME), sCatalog );
280             i_rDispatchArgs.put( OUString(PROPERTY_UPDATE_SCHEMANAME), sSchema );
281             i_rDispatchArgs.put( OUString(PROPERTY_UPDATE_TABLENAME), sTable );
282         }
283     }
284 
285     // RelationDesigner
RelationDesigner(const Reference<XComponentContext> & _rxORB,const Reference<XDatabaseDocumentUI> & _rxApplication,const Reference<XFrame> & _rxParentFrame)286     RelationDesigner::RelationDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame )
287         :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast< OUString >( URL_COMPONENT_RELATIONDESIGN ) )
288     {
289     }
290 }   // namespace dbaui
291 
292 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
293