1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_dbaccess.hxx"
26 
27 #ifndef _SBA_EXTCTRLR_HXX
28 #include "exsrcbrw.hxx"
29 #endif
30 #ifndef _COM_SUN_STAR_FORM_FORMCOMPONENTTYPE_HPP_
31 #include <com/sun/star/form/FormComponentType.hpp>
32 #endif
33 #ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_
34 #include <com/sun/star/util/XURLTransformer.hpp>
35 #endif
36 #ifndef _COM_SUN_STAR_FORM_XGRIDCOLUMNFACTORY_HPP_
37 #include <com/sun/star/form/XGridColumnFactory.hpp>
38 #endif
39 #ifndef _COM_SUN_STAR_FORM_XLOADABLE_HPP_
40 #include <com/sun/star/form/XLoadable.hpp>
41 #endif
42 #ifndef _COM_SUN_STAR_FRAME_FRAMESEARCHFLAG_HPP_
43 #include <com/sun/star/frame/FrameSearchFlag.hpp>
44 #endif
45 #ifndef _SBA_FORMADAPTER_HXX
46 #include "formadapter.hxx"
47 #endif
48 #ifndef _COMPHELPER_PROCESSFACTORY_HXX_
49 #include <comphelper/processfactory.hxx>
50 #endif
51 #ifndef DBACCESS_SHARED_DBUSTRINGS_HRC
52 #include "dbustrings.hrc"
53 #endif
54 #ifndef _DBU_REGHELPER_HXX_
55 #include "dbu_reghelper.hxx"
56 #endif
57 #ifndef TOOLS_DIAGNOSE_EX_H
58 #include <tools/diagnose_ex.h>
59 #endif
60 
61 using namespace ::com::sun::star::uno;
62 using namespace ::com::sun::star::sdb;
63 using namespace ::com::sun::star::sdbc;
64 using namespace ::com::sun::star::sdbcx;
65 using namespace ::com::sun::star::beans;
66 using namespace ::com::sun::star::container;
67 using namespace ::com::sun::star::lang;
68 using namespace ::com::sun::star::form;
69 using namespace ::com::sun::star::frame;
70 using namespace dbaui;
71 
72 //==============================================================================
73 //= SbaExternalSourceBrowser
74 //==============================================================================
75 extern "C" void SAL_CALL createRegistryInfo_OFormGridView()
76 {
77 	static OMultiInstanceAutoRegistration< SbaExternalSourceBrowser > aAutoRegistration;
78 }
79 //------------------------------------------------------------------------------
80 Any SAL_CALL SbaExternalSourceBrowser::queryInterface(const Type& _rType) throw (RuntimeException)
81 {
82 	Any aRet = SbaXDataBrowserController::queryInterface(_rType);
83 	if(!aRet.hasValue())
84 		aRet = ::cppu::queryInterface(_rType,
85 								(::com::sun::star::util::XModifyBroadcaster*)this,
86 								(::com::sun::star::form::XLoadListener*)this);
87 
88 	return aRet;
89 }
90 DBG_NAME(SbaExternalSourceBrowser)
91 //------------------------------------------------------------------------------
92 SbaExternalSourceBrowser::SbaExternalSourceBrowser(const Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rM)
93 	:SbaXDataBrowserController(_rM)
94 	,m_aModifyListeners(getMutex())
95 	,m_pDataSourceImpl(NULL)
96 	,m_bInQueryDispatch( sal_False )
97 {
98     DBG_CTOR(SbaExternalSourceBrowser,NULL);
99 
100 }
101 
102 //------------------------------------------------------------------------------
103 SbaExternalSourceBrowser::~SbaExternalSourceBrowser()
104 {
105 
106     DBG_DTOR(SbaExternalSourceBrowser,NULL);
107 }
108 
109 //-------------------------------------------------------------------------
110 ::comphelper::StringSequence SAL_CALL SbaExternalSourceBrowser::getSupportedServiceNames() throw(RuntimeException)
111 {
112 	return getSupportedServiceNames_Static();
113 }
114 // -------------------------------------------------------------------------
115 ::rtl::OUString SbaExternalSourceBrowser::getImplementationName_Static() throw(RuntimeException)
116 {
117 	return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("org.openoffice.comp.dbu.OFormGridView"));
118 }
119 //-------------------------------------------------------------------------
120 ::comphelper::StringSequence SbaExternalSourceBrowser::getSupportedServiceNames_Static() throw(RuntimeException)
121 {
122 	::comphelper::StringSequence aSupported(1);
123 	aSupported.getArray()[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdb.FormGridView"));
124 	return aSupported;
125 }
126 //-------------------------------------------------------------------------
127 Reference< XInterface > SAL_CALL SbaExternalSourceBrowser::Create(const Reference<XMultiServiceFactory >& _rxFactory)
128 {
129 	return *(new SbaExternalSourceBrowser(_rxFactory));
130 }
131 //-------------------------------------------------------------------------
132 ::rtl::OUString SAL_CALL SbaExternalSourceBrowser::getImplementationName() throw(RuntimeException)
133 {
134 	return getImplementationName_Static();
135 }
136 //------------------------------------------------------------------------------
137 Reference< XRowSet >  SbaExternalSourceBrowser::CreateForm()
138 {
139 	m_pDataSourceImpl = new SbaXFormAdapter();
140 	return m_pDataSourceImpl;
141 }
142 
143 //------------------------------------------------------------------------------
144 sal_Bool SbaExternalSourceBrowser::InitializeForm(const Reference< XPropertySet > & /*i_formProperties*/)
145 {
146 	return sal_True;
147 }
148 
149 //------------------------------------------------------------------
150 sal_Bool SbaExternalSourceBrowser::LoadForm()
151 {
152 	// as we don't have a main form (yet), we have nothing to do
153 	// we don't call FormLoaded, because this expects a working data source
154 	return sal_True;
155 }
156 
157 
158 //------------------------------------------------------------------
159 void SbaExternalSourceBrowser::modified(const ::com::sun::star::lang::EventObject& aEvent) throw( RuntimeException )
160 {
161 	SbaXDataBrowserController::modified(aEvent);
162 
163 	// multiplex this event to all my listeners
164 	::com::sun::star::lang::EventObject aEvt(*this);
165 	::cppu::OInterfaceIteratorHelper aIt(m_aModifyListeners);
166 	while (aIt.hasMoreElements())
167 		((::com::sun::star::util::XModifyListener*)aIt.next())->modified(aEvt);
168 }
169 
170 //------------------------------------------------------------------
171 void SAL_CALL SbaExternalSourceBrowser::dispatch(const ::com::sun::star::util::URL& aURL, const Sequence< ::com::sun::star::beans::PropertyValue>& aArgs) throw(::com::sun::star::uno::RuntimeException)
172 {
173 	const ::com::sun::star::beans::PropertyValue* pArguments = aArgs.getConstArray();
174 	if (aURL.Complete.equals(::rtl::OUString::createFromAscii(".uno:FormSlots/AddGridColumn")))
175 	{
176 		// search the argument describing the column to create
177 		::rtl::OUString sControlType;
178 		sal_Int32 nControlPos = -1;
179 		Sequence< ::com::sun::star::beans::PropertyValue> aControlProps;
180 		sal_uInt16 i;
181 		for ( i = 0; i < aArgs.getLength(); ++i, ++pArguments )
182 		{
183 			if (pArguments->Name.equals(::rtl::OUString::createFromAscii("ColumnType")))
184 			{
185 				sal_Bool bCorrectType = pArguments->Value.getValueType().equals(::getCppuType((const ::rtl::OUString*)0));
186 				OSL_ENSURE(bCorrectType, "invalid type for argument \"ColumnType\" !");
187 				if (bCorrectType)
188 					sControlType = ::comphelper::getString(pArguments->Value);
189 			}
190 			else if (pArguments->Name.equals(::rtl::OUString::createFromAscii("ColumnPosition")))
191 			{
192 				sal_Bool bCorrectType = pArguments->Value.getValueType().equals(::getCppuType((const sal_Int16*)0));
193 				OSL_ENSURE(bCorrectType, "invalid type for argument \"ColumnPosition\" !");
194 				if (bCorrectType)
195 					nControlPos = ::comphelper::getINT16(pArguments->Value);
196 			}
197 			else if (pArguments->Name.equals(::rtl::OUString::createFromAscii("ColumnProperties")))
198 			{
199 				sal_Bool bCorrectType = pArguments->Value.getValueType().equals(::getCppuType((const Sequence< ::com::sun::star::beans::PropertyValue>*)0));
200 				OSL_ENSURE(bCorrectType, "invalid type for argument \"ColumnProperties\" !");
201 				if (bCorrectType)
202 					aControlProps = *(Sequence< ::com::sun::star::beans::PropertyValue>*)pArguments->Value.getValue();
203 			}
204 			else
205 				OSL_ENSURE(sal_False, ((ByteString("SbaExternalSourceBrowser::dispatch(AddGridColumn) : unknown argument (") += ByteString((const sal_Unicode*)pArguments->Name, gsl_getSystemTextEncoding()).GetBuffer()) += ") !").GetBuffer());
206 		}
207 		if (!sControlType.getLength())
208 		{
209 			OSL_ENSURE(sal_False, "SbaExternalSourceBrowser::dispatch(AddGridColumn) : missing argument (ColumnType) !");
210 			sControlType = ::rtl::OUString::createFromAscii("TextField");
211 		}
212 		OSL_ENSURE(aControlProps.getLength(), "SbaExternalSourceBrowser::dispatch(AddGridColumn) : missing argument (ColumnProperties) !");
213 
214 		// create the col
215 		Reference< ::com::sun::star::form::XGridColumnFactory >  xColFactory(getControlModel(), UNO_QUERY);
216 		Reference< ::com::sun::star::beans::XPropertySet >	xNewCol = xColFactory->createColumn(sControlType);
217 		Reference< XPropertySetInfo > xNewColProperties;
218 		if (xNewCol.is())
219 			xNewColProperties = xNewCol->getPropertySetInfo();
220 		// set it's properties
221 		if (xNewColProperties.is())
222 		{
223 			const ::com::sun::star::beans::PropertyValue* pControlProps = aControlProps.getConstArray();
224 			for (i=0; i<aControlProps.getLength(); ++i, ++pControlProps)
225 			{
226 				try
227 				{
228 					if (xNewColProperties->hasPropertyByName(pControlProps->Name))
229 						xNewCol->setPropertyValue(pControlProps->Name, pControlProps->Value);
230 				}
231 				catch(Exception&)
232 				{
233 					OSL_ENSURE(sal_False,
234 						(	ByteString("SbaExternalSourceBrowser::dispatch : could not set a column property (")
235 						+=	ByteString(pControlProps->Name.getStr(), (sal_uInt16)pControlProps->Name.getLength(), RTL_TEXTENCODING_ASCII_US)
236 						+=	ByteString(")!")).GetBuffer());
237 				}
238 			}
239 		}
240 
241 		// correct the position
242 		Reference< ::com::sun::star::container::XIndexContainer >  xColContainer(getControlModel(), UNO_QUERY);
243 
244 		if (nControlPos > xColContainer->getCount())
245 			nControlPos = xColContainer->getCount();
246 		if (nControlPos < 0)
247 			nControlPos = 0;
248 
249 		// append the column
250 		xColContainer->insertByIndex(nControlPos, makeAny(xNewCol));
251 	}
252 	else if (aURL.Complete.equals(::rtl::OUString::createFromAscii(".uno:FormSlots/ClearView")))
253 	{
254 		ClearView();
255 	}
256 	else if (aURL.Complete.equals(::rtl::OUString::createFromAscii(".uno:FormSlots/AttachToForm")))
257 	{
258 		if (!m_pDataSourceImpl)
259 			return;
260 
261 		Reference< XRowSet >  xMasterForm;
262 		// search the arguments for he master form
263 		for (sal_uInt16 i=0; i<aArgs.getLength(); ++i, ++pArguments)
264 		{
265 			if ((pArguments->Name.equals(::rtl::OUString::createFromAscii("MasterForm"))) && (pArguments->Value.getValueTypeClass() == TypeClass_INTERFACE))
266 			{
267 				xMasterForm = Reference< XRowSet > (*(Reference< XInterface > *)pArguments->Value.getValue(), UNO_QUERY);
268 				break;
269 			}
270 		}
271 		if (!xMasterForm.is())
272 		{
273 			OSL_ENSURE(sal_False, "SbaExternalSourceBrowser::dispatch(FormSlots/AttachToForm) : please specify a form to attach to as argument !");
274 			return;
275 		}
276 
277 		Attach(xMasterForm);
278 	}
279 	else
280 		SbaXDataBrowserController::dispatch(aURL, aArgs);
281 }
282 
283 //------------------------------------------------------------------
284 Reference< ::com::sun::star::frame::XDispatch >  SAL_CALL SbaExternalSourceBrowser::queryDispatch(const ::com::sun::star::util::URL& aURL, const ::rtl::OUString& aTargetFrameName, sal_Int32 nSearchFlags) throw( RuntimeException )
285 {
286 	Reference< ::com::sun::star::frame::XDispatch >  xReturn;
287 	if (m_bInQueryDispatch)
288 		return xReturn;
289 
290 	m_bInQueryDispatch = sal_True;
291 
292 	if	(	(aURL.Complete.equals(::rtl::OUString::createFromAscii(".uno:FormSlots/AttachToForm")))
293 			// attach a new external form
294 		||	(aURL.Complete.equals(::rtl::OUString::createFromAscii(".uno:FormSlots/AddGridColumn")))
295 			// add a column to the grid
296 		||	(aURL.Complete.equals(::rtl::OUString::createFromAscii(".uno:FormSlots/ClearView")))
297 			// clear the grid
298 		)
299 		xReturn = (::com::sun::star::frame::XDispatch*)this;
300 
301 	if	(	!xReturn.is()
302 		&&	(	(aURL.Complete.equals(::rtl::OUString::createFromAscii(".uno:FormSlots/moveToFirst")))
303 			||	(aURL.Complete.equals(::rtl::OUString::createFromAscii(".uno:FormSlots/moveToPrev")))
304 			||	(aURL.Complete.equals(::rtl::OUString::createFromAscii(".uno:FormSlots/moveToNext")))
305 			||	(aURL.Complete.equals(::rtl::OUString::createFromAscii(".uno:FormSlots/moveToLast")))
306 			||	(aURL.Complete.equals(::rtl::OUString::createFromAscii(".uno:FormSlots/moveToNew")))
307 			||	(aURL.Complete.equals(::rtl::OUString::createFromAscii(".uno:FormSlots/undoRecord")))
308 			)
309 		)
310 	{
311 		OSL_ENSURE(aURL.Mark.getLength() == 0, "SbaExternalSourceBrowser::queryDispatch : the ::com::sun::star::util::URL shouldn't have a mark !");
312 		::com::sun::star::util::URL aNewUrl = aURL;
313 
314 		// split the ::com::sun::star::util::URL
315 		OSL_ENSURE( m_xUrlTransformer.is(), "SbaExternalSourceBrowser::queryDispatch : could not create an URLTransformer !" );
316 		if ( m_xUrlTransformer.is() )
317 			m_xUrlTransformer->parseStrict( aNewUrl );
318 
319 		// set a new mark
320 		aNewUrl.Mark = ::rtl::OUString::createFromAscii("DB/FormGridView");
321 			// this controller is instantiated when somebody dispatches the ".component:DB/FormGridView" in any
322 			// frame, so we use "FormGridView" as mark that a dispatch request came from this view
323 
324 		if (m_xUrlTransformer.is())
325 			m_xUrlTransformer->assemble(aNewUrl);
326 
327 		Reference< XDispatchProvider >  xFrameDispatcher( getFrame(), UNO_QUERY );
328 		if (xFrameDispatcher.is())
329 			xReturn = xFrameDispatcher->queryDispatch(aNewUrl, aTargetFrameName, FrameSearchFlag::PARENT);
330 
331 	}
332 
333 	if (!xReturn.is())
334 		xReturn = SbaXDataBrowserController::queryDispatch(aURL, aTargetFrameName, nSearchFlags);
335 
336 	m_bInQueryDispatch = sal_False;
337 	return xReturn;
338 }
339 
340 //------------------------------------------------------------------
341 void SAL_CALL SbaExternalSourceBrowser::disposing()
342 {
343 	// say our modify listeners goodbye
344 	::com::sun::star::lang::EventObject aEvt;
345 	aEvt.Source = (XWeak*) this;
346 	m_aModifyListeners.disposeAndClear(aEvt);
347 
348 	stopListening();
349 
350 	SbaXDataBrowserController::disposing();
351 }
352 
353 //------------------------------------------------------------------
354 void SAL_CALL SbaExternalSourceBrowser::addModifyListener(const Reference< ::com::sun::star::util::XModifyListener > & aListener) throw( RuntimeException )
355 {
356 	m_aModifyListeners.addInterface(aListener);
357 }
358 
359 //------------------------------------------------------------------
360 void SAL_CALL SbaExternalSourceBrowser::removeModifyListener(const Reference< ::com::sun::star::util::XModifyListener > & aListener) throw( RuntimeException )
361 {
362 	m_aModifyListeners.removeInterface(aListener);
363 }
364 
365 //------------------------------------------------------------------
366 void SAL_CALL SbaExternalSourceBrowser::unloading(const ::com::sun::star::lang::EventObject& aEvent) throw( RuntimeException )
367 {
368 	if (m_pDataSourceImpl && (m_pDataSourceImpl->getAttachedForm() == aEvent.Source))
369 	{
370 		ClearView();
371 	}
372 
373 	SbaXDataBrowserController::unloading(aEvent);
374 }
375 
376 //------------------------------------------------------------------
377 void SbaExternalSourceBrowser::Attach(const Reference< XRowSet > & xMaster)
378 {
379 	Any aOldPos;
380 	sal_Bool bWasInsertRow = sal_False;
381 	sal_Bool bBeforeFirst	= sal_True;
382 	sal_Bool bAfterLast 	= sal_True;
383 	Reference< XResultSet > xResultSet(xMaster, UNO_QUERY);
384 	Reference< XRowLocate > xCursor(xMaster, UNO_QUERY);
385 	Reference< XPropertySet > xMasterProps(xMaster, UNO_QUERY);
386 
387 	try
388 	{
389 		// switch the control to design mode
390 		if (getBrowserView() && getBrowserView()->getGridControl().is())
391 			getBrowserView()->getGridControl()->setDesignMode(sal_True);
392 
393 		// the grid will move the form's cursor to the first record, but we want the form to remain unchanged
394 		// restore the old position
395 		if (xCursor.is() && xResultSet.is())
396 		{
397 			bBeforeFirst = xResultSet->isBeforeFirst();
398 			bAfterLast	 = xResultSet->isAfterLast();
399 			if(!bBeforeFirst && !bAfterLast)
400 				aOldPos = xCursor->getBookmark();
401 		}
402 
403 		if (xMasterProps.is())
404 			xMasterProps->getPropertyValue(PROPERTY_ISNEW) >>= bWasInsertRow;
405 	}
406     catch( const Exception& )
407     {
408         DBG_UNHANDLED_EXCEPTION();
409     }
410 
411 	onStartLoading( Reference< XLoadable >( xMaster, UNO_QUERY ) );
412 
413 	stopListening();
414 	m_pDataSourceImpl->AttachForm(xMaster);
415 	startListening();
416 
417 	if (xMaster.is())
418 	{
419 		// at this point we have to reset the formatter for the new form
420 		initFormatter();
421 		// assume that the master form is already loaded
422 #if OSL_DEBUG_LEVEL > 0
423 		{
424 			Reference< XLoadable > xLoadable( xMaster, UNO_QUERY );
425 			OSL_ENSURE( xLoadable.is() && xLoadable->isLoaded(), "SbaExternalSourceBrowser::Attach: master is not loaded!" );
426 		}
427 #endif
428 
429 		LoadFinished(sal_True);
430 
431 		Reference< XResultSetUpdate >  xUpdate(xMaster, UNO_QUERY);
432 		try
433 		{
434 			if (bWasInsertRow && xUpdate.is())
435 				xUpdate->moveToInsertRow();
436 			else if (xCursor.is() && aOldPos.hasValue())
437 				xCursor->moveToBookmark(aOldPos);
438 			else if(bBeforeFirst && xResultSet.is())
439 				xResultSet->beforeFirst();
440 			else if(bAfterLast && xResultSet.is())
441 				xResultSet->afterLast();
442 		}
443 		catch(Exception&)
444 		{
445 			OSL_ENSURE(sal_False, "SbaExternalSourceBrowser::Attach : couldn't restore the cursor position !");
446 		}
447 
448 	}
449 }
450 
451 //------------------------------------------------------------------
452 void SbaExternalSourceBrowser::ClearView()
453 {
454 	// set a new (empty) datasource
455 	Attach(Reference< XRowSet > ());
456 
457 
458 	// clear all cols in the grid
459 	Reference< ::com::sun::star::container::XIndexContainer >  xColContainer(getControlModel(), UNO_QUERY);
460 	while (xColContainer->getCount() > 0)
461 		xColContainer->removeByIndex(0);
462 }
463 
464 //------------------------------------------------------------------
465 void SAL_CALL SbaExternalSourceBrowser::disposing(const ::com::sun::star::lang::EventObject& Source) throw( RuntimeException )
466 {
467 	if (m_pDataSourceImpl && (m_pDataSourceImpl->getAttachedForm() == Source.Source))
468 	{
469 		ClearView();
470 	}
471 
472 	SbaXDataBrowserController::disposing(Source);
473 }
474 
475 //------------------------------------------------------------------
476 void SbaExternalSourceBrowser::startListening()
477 {
478 	if (m_pDataSourceImpl && m_pDataSourceImpl->getAttachedForm().is())
479 	{
480 		Reference< ::com::sun::star::form::XLoadable >	xLoadable(m_pDataSourceImpl->getAttachedForm(), UNO_QUERY);
481 		xLoadable->addLoadListener((::com::sun::star::form::XLoadListener*)this);
482 	}
483 }
484 
485 //------------------------------------------------------------------
486 void SbaExternalSourceBrowser::stopListening()
487 {
488 	if (m_pDataSourceImpl && m_pDataSourceImpl->getAttachedForm().is())
489 	{
490 		Reference< ::com::sun::star::form::XLoadable >	xLoadable(m_pDataSourceImpl->getAttachedForm(), UNO_QUERY);
491 		xLoadable->removeLoadListener((::com::sun::star::form::XLoadListener*)this);
492 	}
493 }
494 
495 //==================================================================
496 //==================================================================
497