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_extensions.hxx"
30 #include "gridwizard.hxx"
31 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
32 #include <com/sun/star/sdbc/DataType.hpp>
33 #include <comphelper/stl_types.hxx>
34 #include <tools/string.hxx>
35 #include <com/sun/star/form/XGridColumnFactory.hpp>
36 #include <com/sun/star/awt/MouseWheelBehavior.hpp>
37 #include <com/sun/star/container/XNameContainer.hpp>
38 #include <tools/debug.hxx>
39 #include "dbptools.hxx"
40 #include "dbpilots.hrc"
41 
42 #define GW_STATE_DATASOURCE_SELECTION	0
43 #define GW_STATE_FIELDSELECTION			1
44 
45 //.........................................................................
46 namespace dbp
47 {
48 //.........................................................................
49 
50 	using namespace ::com::sun::star::uno;
51 	using namespace ::com::sun::star::lang;
52 	using namespace ::com::sun::star::beans;
53 	using namespace ::com::sun::star::sdbc;
54 	using namespace ::com::sun::star::container;
55 	using namespace ::com::sun::star::form;
56 	using namespace ::com::sun::star::awt;
57 	using namespace ::svt;
58 
59 	//=====================================================================
60 	//= OGridWizard
61 	//=====================================================================
62 	//---------------------------------------------------------------------
63 	OGridWizard::OGridWizard( Window* _pParent,
64 			const Reference< XPropertySet >& _rxObjectModel, const Reference< XMultiServiceFactory >& _rxORB )
65 		:OControlWizard(_pParent, ModuleRes(RID_DLG_GRIDWIZARD), _rxObjectModel, _rxORB)
66 		,m_bHadDataSelection(sal_True)
67 	{
68 		initControlSettings(&m_aSettings);
69 
70 		m_pPrevPage->SetHelpId(HID_GRIDWIZARD_PREVIOUS);
71 		m_pNextPage->SetHelpId(HID_GRIDWIZARD_NEXT);
72 		m_pCancel->SetHelpId(HID_GRIDWIZARD_CANCEL);
73 		m_pFinish->SetHelpId(HID_GRIDWIZARD_FINISH);
74 
75 		// if we do not need the data source selection page ...
76 		if (!needDatasourceSelection())
77 		{	// ... skip it!
78 			skip(1);
79 			m_bHadDataSelection = sal_False;
80 		}
81 	}
82 
83 	//---------------------------------------------------------------------
84 	sal_Bool OGridWizard::approveControl(sal_Int16 _nClassId)
85 	{
86 		if (FormComponentType::GRIDCONTROL != _nClassId)
87 			return sal_False;
88 
89 		Reference< XGridColumnFactory > xColumnFactory(getContext().xObjectModel, UNO_QUERY);
90 		if (!xColumnFactory.is())
91 			return sal_False;
92 
93 		return sal_True;
94 	}
95 
96 	//---------------------------------------------------------------------
97 	void OGridWizard::implApplySettings()
98 	{
99 		const OControlWizardContext& rContext = getContext();
100 
101 		// the factory for the columns
102 		Reference< XGridColumnFactory > xColumnFactory(rContext.xObjectModel, UNO_QUERY);
103 		DBG_ASSERT(xColumnFactory.is(), "OGridWizard::implApplySettings: should never have made it 'til here!");
104 			// (if we're here, what the hell happened in approveControl??)
105 
106 		// the container for the columns
107 		Reference< XNameContainer > xColumnContainer(rContext.xObjectModel, UNO_QUERY);
108 		DBG_ASSERT(xColumnContainer.is(), "OGridWizard::implApplySettings: no container!");
109 
110 		if (!xColumnFactory.is() || !xColumnContainer.is())
111 			return;
112 
113 		static const ::rtl::OUString s_sDataFieldProperty	= ::rtl::OUString::createFromAscii("DataField");
114 		static const ::rtl::OUString s_sLabelProperty		= ::rtl::OUString::createFromAscii("Label");
115 		static const ::rtl::OUString s_sWidthProperty		= ::rtl::OUString::createFromAscii("Width");
116 		static const ::rtl::OUString s_sMouseWheelBehavior  = ::rtl::OUString::createFromAscii("MouseWheelBehavior");
117 		static const ::rtl::OUString s_sEmptyString;
118 
119 		// collect "descriptors" for the to-be-created (grid)columns
120 		DECLARE_STL_VECTOR( ::rtl::OUString, StringArray );
121 		StringArray aColumnServiceNames;	// service names to be used with the XGridColumnFactory
122 		StringArray aColumnLabelPostfixes;	// postfixes to append to the column labels
123 		StringArray aFormFieldNames;		// data field names
124 
125 		aColumnServiceNames.reserve(getSettings().aSelectedFields.getLength());
126 		aColumnLabelPostfixes.reserve(getSettings().aSelectedFields.getLength());
127 		aFormFieldNames.reserve(getSettings().aSelectedFields.getLength());
128 
129 		// loop through the selected field names
130 		const ::rtl::OUString* pSelectedFields = getSettings().aSelectedFields.getConstArray();
131 		const ::rtl::OUString* pEnd = pSelectedFields + getSettings().aSelectedFields.getLength();
132 		for (;pSelectedFields < pEnd; ++pSelectedFields)
133 		{
134 			// get the information for the selected column
135 			sal_Int32 nFieldType = DataType::OTHER;
136 			OControlWizardContext::TNameTypeMap::const_iterator aFind = rContext.aTypes.find(*pSelectedFields);
137 			if ( aFind != rContext.aTypes.end() )
138 				nFieldType = aFind->second;
139 
140 			aFormFieldNames.push_back(*pSelectedFields);
141 			switch (nFieldType)
142 			{
143 				case DataType::BIT:
144 				case DataType::BOOLEAN:
145 					aColumnServiceNames.push_back(::rtl::OUString::createFromAscii("CheckBox"));
146 					aColumnLabelPostfixes.push_back(s_sEmptyString);
147 					break;
148 
149 				case DataType::TINYINT:
150 				case DataType::SMALLINT:
151 				case DataType::INTEGER:
152 					aColumnServiceNames.push_back(::rtl::OUString::createFromAscii("NumericField"));
153 					aColumnLabelPostfixes.push_back(s_sEmptyString);
154 					break;
155 
156 				case DataType::FLOAT:
157 				case DataType::REAL:
158 				case DataType::DOUBLE:
159 				case DataType::NUMERIC:
160 				case DataType::DECIMAL:
161 					aColumnServiceNames.push_back(::rtl::OUString::createFromAscii("FormattedField"));
162 					aColumnLabelPostfixes.push_back(s_sEmptyString);
163 					break;
164 
165 				case DataType::DATE:
166 					aColumnServiceNames.push_back(::rtl::OUString::createFromAscii("DateField"));
167 					aColumnLabelPostfixes.push_back(s_sEmptyString);
168 					break;
169 
170 				case DataType::TIME:
171 					aColumnServiceNames.push_back(::rtl::OUString::createFromAscii("TimeField"));
172 					aColumnLabelPostfixes.push_back(s_sEmptyString);
173 					break;
174 
175 				case DataType::TIMESTAMP:
176 					aColumnServiceNames.push_back(::rtl::OUString::createFromAscii("DateField"));
177 					aColumnLabelPostfixes.push_back(String(ModuleRes(RID_STR_DATEPOSTFIX)));
178 
179 					aFormFieldNames.push_back(*pSelectedFields);
180 					aColumnServiceNames.push_back(::rtl::OUString::createFromAscii("TimeField"));
181 					aColumnLabelPostfixes.push_back(String(ModuleRes(RID_STR_TIMEPOSTFIX)));
182 					break;
183 
184 				default:
185 					aColumnServiceNames.push_back(::rtl::OUString::createFromAscii("TextField"));
186 					aColumnLabelPostfixes.push_back(s_sEmptyString);
187 			}
188 		}
189 
190 		DBG_ASSERT(	aFormFieldNames.size() == aColumnServiceNames.size()
191 				&&	aColumnServiceNames.size() == aColumnLabelPostfixes.size(),
192 				"OGridWizard::implApplySettings: inconsistent descriptor sequences!");
193 
194 		// now loop through the descriptions and create the (grid)columns out of th descriptors
195 		{
196 			Reference< XNameAccess > xExistenceChecker(xColumnContainer.get());
197 
198 			ConstStringArrayIterator pColumnServiceName = aColumnServiceNames.begin();
199 			ConstStringArrayIterator pColumnLabelPostfix = aColumnLabelPostfixes.begin();
200 			ConstStringArrayIterator pFormFieldName = aFormFieldNames.begin();
201 			ConstStringArrayIterator pColumnServiceNameEnd = aColumnServiceNames.end();
202 
203 			for (;pColumnServiceName < pColumnServiceNameEnd; ++pColumnServiceName, ++pColumnLabelPostfix, ++pFormFieldName)
204 			{
205 				// create a (grid)column for the (resultset)column
206 				try
207 				{
208 					Reference< XPropertySet > xColumn( xColumnFactory->createColumn(*pColumnServiceName), UNO_SET_THROW );
209 					Reference< XPropertySetInfo > xColumnPSI( xColumn->getPropertySetInfo(), UNO_SET_THROW );
210 
211 					::rtl::OUString sColumnName(*pColumnServiceName);
212 					disambiguateName(xExistenceChecker, sColumnName);
213 
214 					// the data field the column should be bound to
215 					xColumn->setPropertyValue(s_sDataFieldProperty, makeAny(*pFormFieldName));
216 					// the label
217 					xColumn->setPropertyValue(s_sLabelProperty, makeAny(::rtl::OUString(*pFormFieldName) += *pColumnLabelPostfix));
218 					// the width (<void/> => column will be auto-sized)
219 					xColumn->setPropertyValue(s_sWidthProperty, Any());
220 
221 					if ( xColumnPSI->hasPropertyByName( s_sMouseWheelBehavior ) )
222 						xColumn->setPropertyValue( s_sMouseWheelBehavior, makeAny( MouseWheelBehavior::SCROLL_DISABLED ) );
223 
224 					// insert the column
225 					xColumnContainer->insertByName(sColumnName, makeAny(xColumn));
226 				}
227 				catch(Exception&)
228 				{
229 					DBG_ERROR(	::rtl::OString("OGridWizard::implApplySettings: unexpected exception while creating the grid column for field ")
230 							+=	::rtl::OString(pFormFieldName->getStr(), pFormFieldName->getLength(), gsl_getSystemTextEncoding())
231 							+=	::rtl::OString("!"));
232 				}
233 			}
234 		}
235 	}
236 
237 	//---------------------------------------------------------------------
238 	OWizardPage* OGridWizard::createPage(WizardState _nState)
239 	{
240 		switch (_nState)
241 		{
242 			case GW_STATE_DATASOURCE_SELECTION:
243 				return new OTableSelectionPage(this);
244 			case GW_STATE_FIELDSELECTION:
245 				return new OGridFieldsSelection(this);
246 		}
247 
248 		return NULL;
249 	}
250 
251 	//---------------------------------------------------------------------
252 	WizardTypes::WizardState OGridWizard::determineNextState( WizardState _nCurrentState ) const
253 	{
254 		switch (_nCurrentState)
255 		{
256 			case GW_STATE_DATASOURCE_SELECTION:
257 				return GW_STATE_FIELDSELECTION;
258 			case GW_STATE_FIELDSELECTION:
259 				return WZS_INVALID_STATE;
260 		}
261 
262 		return WZS_INVALID_STATE;
263 	}
264 
265 	//---------------------------------------------------------------------
266 	void OGridWizard::enterState(WizardState _nState)
267 	{
268 		OControlWizard::enterState(_nState);
269 
270 		enableButtons(WZB_PREVIOUS, m_bHadDataSelection ? (GW_STATE_DATASOURCE_SELECTION < _nState) : GW_STATE_FIELDSELECTION < _nState);
271 		enableButtons(WZB_NEXT, GW_STATE_FIELDSELECTION != _nState);
272 		if (_nState < GW_STATE_FIELDSELECTION)
273 			enableButtons(WZB_FINISH, sal_False);
274 
275 		if (GW_STATE_FIELDSELECTION == _nState)
276 			defaultButton(WZB_FINISH);
277 	}
278 
279 	//---------------------------------------------------------------------
280 	sal_Bool OGridWizard::leaveState(WizardState _nState)
281 	{
282 		if (!OControlWizard::leaveState(_nState))
283 			return sal_False;
284 
285 		if (GW_STATE_FIELDSELECTION == _nState)
286 			defaultButton(WZB_NEXT);
287 
288 		return sal_True;
289 	}
290 
291 	//---------------------------------------------------------------------
292 	sal_Bool OGridWizard::onFinish()
293 	{
294 		if ( !OControlWizard::onFinish() )
295 			return sal_False;
296 
297 		implApplySettings();
298 
299 		return sal_True;
300 	}
301 
302 	//=====================================================================
303 	//= OGridFieldsSelection
304 	//=====================================================================
305 	//---------------------------------------------------------------------
306 	OGridFieldsSelection::OGridFieldsSelection( OGridWizard* _pParent )
307 		:OGridPage(_pParent, ModuleRes(RID_PAGE_GW_FIELDSELECTION))
308 		,m_aFrame				(this, ModuleRes(FL_FRAME))
309 		,m_aExistFieldsLabel	(this, ModuleRes(FT_EXISTING_FIELDS))
310 		,m_aExistFields			(this, ModuleRes(LB_EXISTING_FIELDS))
311 		,m_aSelectOne			(this, ModuleRes(PB_FIELDRIGHT))
312 		,m_aSelectAll			(this, ModuleRes(PB_ALLFIELDSRIGHT))
313 		,m_aDeselectOne			(this, ModuleRes(PB_FIELDLEFT))
314 		,m_aDeselectAll			(this, ModuleRes(PB_ALLFIELDSLEFT))
315 		,m_aSelFieldsLabel		(this, ModuleRes(FT_SELECTED_FIELDS))
316 		,m_aSelFields			(this, ModuleRes(LB_SELECTED_FIELDS))
317 	{
318 		FreeResource();
319 
320 		enableFormDatasourceDisplay();
321 
322 		m_aSelectOne.SetClickHdl(LINK(this, OGridFieldsSelection, OnMoveOneEntry));
323 		m_aSelectAll.SetClickHdl(LINK(this, OGridFieldsSelection, OnMoveAllEntries));
324 		m_aDeselectOne.SetClickHdl(LINK(this, OGridFieldsSelection, OnMoveOneEntry));
325 		m_aDeselectAll.SetClickHdl(LINK(this, OGridFieldsSelection, OnMoveAllEntries));
326 
327 		m_aExistFields.SetSelectHdl(LINK(this, OGridFieldsSelection, OnEntrySelected));
328 		m_aSelFields.SetSelectHdl(LINK(this, OGridFieldsSelection, OnEntrySelected));
329 		m_aExistFields.SetDoubleClickHdl(LINK(this, OGridFieldsSelection, OnEntryDoubleClicked));
330 		m_aSelFields.SetDoubleClickHdl(LINK(this, OGridFieldsSelection, OnEntryDoubleClicked));
331 	}
332 
333 	//---------------------------------------------------------------------
334 	void OGridFieldsSelection::ActivatePage()
335 	{
336 		OGridPage::ActivatePage();
337 		m_aExistFields.GrabFocus();
338 	}
339 
340 	//---------------------------------------------------------------------
341 	bool OGridFieldsSelection::canAdvance() const
342 	{
343 		return false;
344 			// we're the last page in our wizard
345 	}
346 
347 	//---------------------------------------------------------------------
348 	void OGridFieldsSelection::initializePage()
349 	{
350 		OGridPage::initializePage();
351 
352 		const OControlWizardContext& rContext = getContext();
353 		fillListBox(m_aExistFields, rContext.aFieldNames);
354 
355 		m_aSelFields.Clear();
356 		const OGridSettings& rSettings = getSettings();
357 		const ::rtl::OUString* pSelected = rSettings.aSelectedFields.getConstArray();
358 		const ::rtl::OUString* pEnd = pSelected + rSettings.aSelectedFields.getLength();
359 		for (; pSelected < pEnd; ++pSelected)
360 		{
361 			m_aSelFields.InsertEntry(*pSelected);
362 			m_aExistFields.RemoveEntry(*pSelected);
363 		}
364 
365 		implCheckButtons();
366 	}
367 
368 	//---------------------------------------------------------------------
369 	sal_Bool OGridFieldsSelection::commitPage( ::svt::WizardTypes::CommitPageReason _eReason )
370 	{
371 		if (!OGridPage::commitPage(_eReason))
372 			return sal_False;
373 
374 		OGridSettings& rSettings = getSettings();
375 		sal_uInt16 nSelected = m_aSelFields.GetEntryCount();
376 
377 		rSettings.aSelectedFields.realloc(nSelected);
378 		::rtl::OUString* pSelected = rSettings.aSelectedFields.getArray();
379 
380 		for (sal_uInt16 i=0; i<nSelected; ++i, ++pSelected)
381 			*pSelected = m_aSelFields.GetEntry(i);
382 
383 		return sal_True;
384 	}
385 
386 	//---------------------------------------------------------------------
387 	void OGridFieldsSelection::implCheckButtons()
388 	{
389 		m_aSelectOne.Enable(m_aExistFields.GetSelectEntryCount() != 0);
390 		m_aSelectAll.Enable(m_aExistFields.GetEntryCount() != 0);
391 
392 		m_aDeselectOne.Enable(m_aSelFields.GetSelectEntryCount() != 0);
393 		m_aDeselectAll.Enable(m_aSelFields.GetEntryCount() != 0);
394 
395 		getDialog()->enableButtons(WZB_FINISH, 0 != m_aSelFields.GetEntryCount());
396 	}
397 
398 	//---------------------------------------------------------------------
399 	IMPL_LINK(OGridFieldsSelection, OnEntryDoubleClicked, ListBox*, _pList)
400 	{
401 		PushButton* pSimulateButton = &m_aExistFields == _pList ? &m_aSelectOne : &m_aDeselectOne;
402 		if (pSimulateButton->IsEnabled())
403 			return OnMoveOneEntry( pSimulateButton );
404 		else
405 			return 1L;
406 	}
407 
408 	//---------------------------------------------------------------------
409 	IMPL_LINK(OGridFieldsSelection, OnEntrySelected, ListBox*, /*NOTINTERESTEDIN*/)
410 	{
411 		implCheckButtons();
412 		return 0L;
413 	}
414 
415 	//---------------------------------------------------------------------
416 	IMPL_LINK(OGridFieldsSelection, OnMoveOneEntry, PushButton*, _pButton)
417 	{
418 		sal_Bool bMoveRight = (&m_aSelectOne == _pButton);
419 		ListBox& rMoveTo = bMoveRight ? m_aSelFields : m_aExistFields;
420 
421 		// the index of the selected entry
422 		sal_uInt16 nSelected = bMoveRight ? m_aExistFields.GetSelectEntryPos() : m_aSelFields.GetSelectEntryPos();
423 		// the (original) relative position of the entry
424 		sal_IntPtr nRelativeIndex = reinterpret_cast<sal_IntPtr>(bMoveRight ? m_aExistFields.GetEntryData(nSelected) : m_aSelFields.GetEntryData(nSelected));
425 
426 		sal_uInt16 nInsertPos = LISTBOX_APPEND;
427 		if (!bMoveRight)
428 		{	// need to determine an insert pos which reflects the original
429 			nInsertPos = 0;
430 			while (nInsertPos < rMoveTo.GetEntryCount())
431 			{
432 				if (reinterpret_cast<sal_IntPtr>(rMoveTo.GetEntryData(nInsertPos)) > nRelativeIndex)
433 					break;
434 				++nInsertPos;
435 			}
436 		}
437 
438 		// the text of the entry to move
439 		String sMovingEntry = bMoveRight ? m_aExistFields.GetEntry(nSelected) : m_aSelFields.GetEntry(nSelected);
440 
441 		// insert the entry
442 		nInsertPos = rMoveTo.InsertEntry(sMovingEntry, nInsertPos);
443 		// preserve it's "relative position" entry data
444 		rMoveTo.SetEntryData(nInsertPos, reinterpret_cast<void*>(nRelativeIndex));
445 
446 		// remove the entry from it's old list
447 		if (bMoveRight)
448 		{
449 			sal_uInt16 nSelectPos = m_aExistFields.GetSelectEntryPos();
450 			m_aExistFields.RemoveEntry(nSelected);
451 			if ((LISTBOX_ENTRY_NOTFOUND != nSelectPos) && (nSelectPos < m_aExistFields.GetEntryCount()))
452 				m_aExistFields.SelectEntryPos(nSelectPos);
453 
454 			m_aExistFields.GrabFocus();
455 		}
456 		else
457 		{
458 			sal_uInt16 nSelectPos = m_aSelFields.GetSelectEntryPos();
459 			m_aSelFields.RemoveEntry(nSelected);
460 			if ((LISTBOX_ENTRY_NOTFOUND != nSelectPos) && (nSelectPos < m_aSelFields.GetEntryCount()))
461 				m_aSelFields.SelectEntryPos(nSelectPos);
462 
463 			m_aSelFields.GrabFocus();
464 		}
465 
466 		implCheckButtons();
467 		return 0;
468 	}
469 
470 	//---------------------------------------------------------------------
471 	IMPL_LINK(OGridFieldsSelection, OnMoveAllEntries, PushButton*, _pButton)
472 	{
473 		sal_Bool bMoveRight = (&m_aSelectAll == _pButton);
474 		m_aExistFields.Clear();
475 		m_aSelFields.Clear();
476 		fillListBox(bMoveRight ? m_aSelFields : m_aExistFields, getContext().aFieldNames);
477 
478 		implCheckButtons();
479 		return 0;
480 	}
481 
482 //.........................................................................
483 }	// namespace dbp
484 //.........................................................................
485 
486