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