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 _DBAUI_INDEXDIALOG_HXX_
32 #include "indexdialog.hxx"
33 #endif
34 #ifndef _DBU_DLG_HRC_
35 #include "dbu_dlg.hrc"
36 #endif
37 #ifndef _DBA_DBACCESS_HELPID_HRC_
38 #include "dbaccess_helpid.hrc"
39 #endif
40 #ifndef _DBAUI_INDEXDIALOG_HRC_
41 #include "indexdialog.hrc"
42 #endif
43 #ifndef _DBAUI_INDEXFIELDSCONTROL_HXX_
44 #include "indexfieldscontrol.hxx"
45 #endif
46 #ifndef _DBAUI_INDEXCOLLECTION_HXX_
47 #include "indexcollection.hxx"
48 #endif
49 #ifndef _SV_MSGBOX_HXX
50 #include <vcl/msgbox.hxx>
51 #endif
52 #ifndef _COM_SUN_STAR_SDB_SQLCONTEXT_HPP_
53 #include <com/sun/star/sdb/SQLContext.hpp>
54 #endif
55 #ifndef DBAUI_TOOLS_HXX
56 #include "UITools.hxx"
57 #endif
58 #ifndef _SVTOOLS_IMGDEF_HXX
59 #include <svtools/imgdef.hxx>
60 #endif
61 #ifndef DBACCESS_UI_BROWSER_ID_HXX
62 #include "browserids.hxx"
63 #endif
64 #ifndef _CONNECTIVITY_DBTOOLS_HXX_
65 #include <connectivity/dbtools.hxx>
66 #endif
67 //......................................................................
68 namespace dbaui
69 {
70 //......................................................................
71 
72 	using namespace ::com::sun::star::uno;
73 	using namespace ::com::sun::star::container;
74 	using namespace ::com::sun::star::sdbc;
75 	using namespace ::com::sun::star::sdb;
76 	using namespace ::com::sun::star::lang;
77 	using namespace ::dbtools;
78 
79 	//==================================================================
80 	//= helper
81 	//==================================================================
82 	//------------------------------------------------------------------
83 	sal_Bool operator ==(const OIndexField& _rLHS, const OIndexField& _rRHS)
84 	{
85 		return	(_rLHS.sFieldName == _rRHS.sFieldName)
86 			&&	(_rLHS.bSortAscending == _rRHS.bSortAscending);
87 	}
88 
89 	//------------------------------------------------------------------
90 	sal_Bool operator !=(const OIndexField& _rLHS, const OIndexField& _rRHS)
91 	{
92 		return !(_rLHS == _rRHS);
93 	}
94 
95 	//------------------------------------------------------------------
96 	sal_Bool operator ==(const IndexFields& _rLHS, const IndexFields& _rRHS)
97 	{
98 		if (_rLHS.size() != _rRHS.size())
99 			return sal_False;
100 
101 		ConstIndexFieldsIterator aLeft = _rLHS.begin();
102         ConstIndexFieldsIterator aLeftEnd = _rLHS.end();
103 		ConstIndexFieldsIterator aRight = _rRHS.begin();
104 		for	(; aLeft != aLeftEnd; ++aLeft, ++aRight)
105 		{
106 			if (*aLeft != *aRight)
107 				return sal_False;
108 		}
109 
110 		return sal_True;
111 	}
112 
113 	//------------------------------------------------------------------
114 	sal_Bool operator !=(const IndexFields& _rLHS, const IndexFields& _rRHS)
115 	{
116 		return !(_rLHS == _rRHS);
117 	}
118 
119 	//==================================================================
120 	//= DbaIndexList
121 	//==================================================================
122 	//------------------------------------------------------------------
123 	DbaIndexList::DbaIndexList(Window* _pParent, const ResId& _rId)
124 		:SvTreeListBox(_pParent, _rId)
125 		,m_bSuspendSelectHdl(sal_False)
126 	{
127 	}
128 
129 	extern sal_Bool isCharOk(sal_Unicode _cChar,sal_Bool _bFirstChar,sal_Bool _bUpperCase,const ::rtl::OUString& _sAllowedChars);
130 	//------------------------------------------------------------------
131 	sal_Bool DbaIndexList::EditedEntry( SvLBoxEntry* _pEntry, const String& _rNewText )
132 	{
133 		// first check if this is valid SQL92 name
134 		if ( isSQL92CheckEnabled(m_xConnection) )
135 		{
136 			Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
137 			if ( xMeta.is() )
138 			{
139 				::rtl::OUString sNewName(_rNewText);
140 				::rtl::OUString sAlias = ::dbtools::convertName2SQLName(sNewName,xMeta->getExtraNameCharacters());
141 				if ( ( xMeta->supportsMixedCaseQuotedIdentifiers() )
142 						?
143 						sAlias != sNewName
144 						:
145 				!sNewName.equalsIgnoreAsciiCase(sAlias))
146 					return sal_False;
147 			}
148 		}
149 
150 		if (!SvTreeListBox::EditedEntry(_pEntry, _rNewText))
151 			return sal_False;
152 
153 		String sOldText = GetEntryText(_pEntry);
154 		SvTreeListBox::SetEntryText(_pEntry, _rNewText);
155 
156 		sal_Bool bValid = sal_True;
157 		if (m_aEndEditHdl.IsSet())
158 			bValid = (0 != m_aEndEditHdl.Call(_pEntry));
159 
160 		if (bValid)
161 			return sal_True;
162 
163 		SvTreeListBox::SetEntryText(_pEntry, sOldText);
164 
165 		return sal_False;
166 	}
167 
168 	//------------------------------------------------------------------
169 	void DbaIndexList::enableSelectHandler()
170 	{
171 		DBG_ASSERT(m_bSuspendSelectHdl, "DbaIndexList::enableSelectHandler: invalid call (this is not cumulative)!");
172 		m_bSuspendSelectHdl = sal_False;
173 	}
174 
175 	//------------------------------------------------------------------
176 	void DbaIndexList::disableSelectHandler()
177 	{
178 		DBG_ASSERT(!m_bSuspendSelectHdl, "DbaIndexList::enableSelectHandler: invalid call (this is not cumulative)!");
179 		m_bSuspendSelectHdl = sal_True;
180 	}
181 
182 	//------------------------------------------------------------------
183 	void DbaIndexList::SelectNoHandlerCall( SvLBoxEntry* _pEntry )
184 	{
185 		disableSelectHandler();
186 		Select(_pEntry, sal_True);
187 		enableSelectHandler();
188 	}
189 
190 	//------------------------------------------------------------------
191 	sal_Bool DbaIndexList::Select( SvLBoxEntry* pEntry, sal_Bool _bSelect )
192 	{
193 		sal_Bool bReturn = SvTreeListBox::Select(pEntry, _bSelect);
194 
195 		if (m_aSelectHdl.IsSet() && !m_bSuspendSelectHdl && _bSelect)
196 			m_aSelectHdl.Call(this);
197 
198 		return bReturn;
199 	}
200 
201 	//==================================================================
202 	//= DbaIndexDialog
203 	//==================================================================
204 DBG_NAME(DbaIndexDialog)
205 //------------------------------------------------------------------
206 	DbaIndexDialog::DbaIndexDialog(	Window* _pParent, const Sequence< ::rtl::OUString >& _rFieldNames,
207 									const Reference< XNameAccess >& _rxIndexes,
208 									const Reference< XConnection >& _rxConnection,
209 									const Reference< XMultiServiceFactory >& _rxORB,sal_Int32 _nMaxColumnsInIndex)
210 		:ModalDialog( _pParent, ModuleRes(DLG_INDEXDESIGN))
211 		,m_xConnection(_rxConnection)
212 		,m_aGeometrySettings(E_DIALOG, ::rtl::OUString::createFromAscii("dbaccess.tabledesign.indexdialog"))
213 		,m_aActions							(this, ModuleRes(TLB_ACTIONS))
214 		,m_aIndexes							(this, ModuleRes(CTR_INDEXLIST))
215 		,m_aIndexDetails					(this, ModuleRes(FL_INDEXDETAILS))
216 		,m_aDescriptionLabel				(this, ModuleRes(FT_DESC_LABEL))
217 		,m_aDescription						(this, ModuleRes(FT_DESCRIPTION))
218 		,m_aUnique							(this, ModuleRes(CB_UNIQUE))
219 		,m_aFieldsLabel						(this, ModuleRes(FT_FIELDS))
220 		,m_pFields(new IndexFieldsControl	(this, ModuleRes(CTR_FIELDS),_nMaxColumnsInIndex,::dbtools::getBooleanDataSourceSetting( m_xConnection, "AddIndexAppendix" )))
221 		,m_aClose							(this, ModuleRes(PB_CLOSE))
222 		,m_aHelp							(this, ModuleRes(HB_HELP))
223 		,m_pIndexes(NULL)
224 		,m_pPreviousSelection(NULL)
225 		,m_bEditAgain(sal_False)
226 		,m_xORB(_rxORB)
227 	{
228         DBG_CTOR(DbaIndexDialog,NULL);
229 
230 		FreeResource();
231 
232 		m_aActions.SetSelectHdl(LINK(this, DbaIndexDialog, OnIndexAction));
233 
234 		m_aIndexes.SetSelectHdl(LINK(this, DbaIndexDialog, OnIndexSelected));
235 		m_aIndexes.SetEndEditHdl(LINK(this, DbaIndexDialog, OnEntryEdited));
236 		m_aIndexes.SetSelectionMode(SINGLE_SELECTION);
237 		m_aIndexes.SetHighlightRange();
238 		m_aIndexes.setConnection(m_xConnection);
239 
240 		m_pFields->Init(_rFieldNames);
241 
242 		setToolBox(&m_aActions);
243 
244 		m_pIndexes = new OIndexCollection();
245 		try
246 		{
247 			m_pIndexes->attach(_rxIndexes);
248 		}
249 		catch(SQLException& e)
250 		{
251 			::dbaui::showError(SQLExceptionInfo(e),_pParent,_rxORB);
252 		}
253 		catch(Exception&)
254 		{
255 			OSL_ENSURE(sal_False, "DbaIndexDialog::DbaIndexDialog: could not retrieve basic information from the UNO collection!");
256 		}
257 
258 		fillIndexList();
259 
260 		m_aUnique.SetClickHdl(LINK(this, DbaIndexDialog, OnModified));
261 		m_pFields->SetModifyHdl(LINK(this, DbaIndexDialog, OnModified));
262 
263 		m_aClose.SetClickHdl(LINK(this, DbaIndexDialog, OnCloseDialog));
264 
265 		// get our most recent geometry settings
266 //		if (m_aGeometrySettings.Exists())
267 //		{
268 //			Point aPos;
269 //			m_aGeometrySettings.GetPosition(aPos.X(), aPos.Y());
270 //			SetPosPixel(aPos);
271 //		}
272 
273 		// if all of the indexes have an empty description, we're not interested in displaying it
274 		Indexes::const_iterator aCheck;
275 
276 		for (	aCheck = m_pIndexes->begin();
277 				aCheck != m_pIndexes->end();
278 				++aCheck
279 			)
280 		{
281 			if (aCheck->sDescription.getLength())
282 				break;
283 		}
284 
285 		if (aCheck == m_pIndexes->end())
286 		{
287 			sal_Int32 nMoveUp = m_aUnique.GetPosPixel().Y() - m_aDescriptionLabel.GetPosPixel().Y();
288 
289 			// hide the controls which are necessary for the description
290 			m_aDescription.Hide();
291 			m_aDescriptionLabel.Hide();
292 
293 			// move other controls up
294 			Point aPos = m_aUnique.GetPosPixel();
295 			aPos.Y() -= nMoveUp;
296 			m_aUnique.SetPosPixel(aPos);
297 
298 			aPos = m_aFieldsLabel.GetPosPixel();
299 			aPos.Y() -= nMoveUp;
300 			m_aFieldsLabel.SetPosPixel(aPos);
301 
302 			aPos = m_pFields->GetPosPixel();
303 			aPos.Y() -= nMoveUp;
304 			m_pFields->SetPosPixel(aPos);
305 
306 			// and enlarge the fields list
307 			Size aSize = m_pFields->GetSizePixel();
308 			aSize.Height() += nMoveUp;
309 			m_pFields->SetSizePixel(aSize);
310 		}
311 	}
312 
313 	//------------------------------------------------------------------
314 	void DbaIndexDialog::updateToolbox()
315 	{
316 		m_aActions.EnableItem(ID_INDEX_NEW, !m_aIndexes.IsEditingActive());
317 
318 		SvLBoxEntry* pSelected = m_aIndexes.FirstSelected();
319 		sal_Bool bSelectedAnything = NULL != pSelected;
320 
321 
322 		if (pSelected)
323 		{
324 			// is the current entry modified?
325 			Indexes::const_iterator aSelectedPos = m_pIndexes->begin() + reinterpret_cast<sal_IntPtr>(pSelected->GetUserData());
326 			m_aActions.EnableItem(ID_INDEX_SAVE, aSelectedPos->isModified() || aSelectedPos->isNew());
327 			m_aActions.EnableItem(ID_INDEX_RESET, aSelectedPos->isModified() || aSelectedPos->isNew());
328             bSelectedAnything = bSelectedAnything && !aSelectedPos->bPrimaryKey;
329 		}
330 		else
331 		{
332 			m_aActions.EnableItem(ID_INDEX_SAVE, sal_False);
333 			m_aActions.EnableItem(ID_INDEX_RESET, sal_False);
334 		}
335         m_aActions.EnableItem(ID_INDEX_DROP, bSelectedAnything);
336 		m_aActions.EnableItem(ID_INDEX_RENAME, bSelectedAnything);
337 	}
338 
339 	//------------------------------------------------------------------
340 	void DbaIndexDialog::fillIndexList()
341 	{
342 		sal_Bool bHiContrast = GetSettings().GetStyleSettings().GetHighContrastMode();
343 		Image aPKeyIcon(ModuleRes( bHiContrast ? IMG_PKEYICON_SCH : IMG_PKEYICON));
344 		// fill the list with the index names
345 		m_aIndexes.Clear();
346 		Indexes::iterator aIndexLoop = m_pIndexes->begin();
347 		Indexes::iterator aEnd = m_pIndexes->end();
348 		for (; aIndexLoop != aEnd; ++aIndexLoop)
349 		{
350 			SvLBoxEntry* pNewEntry = NULL;
351 			if (aIndexLoop->bPrimaryKey)
352 				pNewEntry = m_aIndexes.InsertEntry(aIndexLoop->sName, aPKeyIcon, aPKeyIcon);
353 			else
354 				pNewEntry = m_aIndexes.InsertEntry(aIndexLoop->sName);
355 
356 			pNewEntry->SetUserData(reinterpret_cast< void* >(sal_Int32(aIndexLoop - m_pIndexes->begin())));
357 		}
358 
359 		OnIndexSelected(&m_aIndexes);
360 	}
361 
362 	//------------------------------------------------------------------
363 	DbaIndexDialog::~DbaIndexDialog( )
364 	{
365 		setToolBox(NULL);
366 		delete m_pIndexes;
367 		delete m_pFields;
368 
369 		// save our geometry settings
370 //		Point aPos = GetPosPixel();
371 //		m_aGeometrySettings.SetPosition(aPos.X(), aPos.Y());
372 
373         DBG_DTOR(DbaIndexDialog,NULL);
374     }
375 
376 	//------------------------------------------------------------------
377 	sal_Bool DbaIndexDialog::implCommit(SvLBoxEntry* _pEntry)
378 	{
379 		DBG_ASSERT(_pEntry, "DbaIndexDialog::implCommit: invalid entry!");
380 
381 		Indexes::iterator aCommitPos = m_pIndexes->begin() + reinterpret_cast<sal_IntPtr>(_pEntry->GetUserData());
382 
383 		// if it's not a new index, remove it
384 		// (we can't modify indexes, only drop'n'insert)
385 		if (!aCommitPos->isNew())
386 			if (!implDropIndex(_pEntry, sal_False))
387 				return sal_False;
388 
389 		// create the new index
390 		SQLExceptionInfo aExceptionInfo;
391 		try
392 		{
393 			m_pIndexes->commitNewIndex(aCommitPos);
394 		}
395 		catch(SQLContext& e) { aExceptionInfo = SQLExceptionInfo(e); }
396 		catch(SQLWarning& e) { aExceptionInfo = SQLExceptionInfo(e); }
397 		catch(SQLException& e) { aExceptionInfo = SQLExceptionInfo(e); }
398 
399 		// reflect the new selection in the toolbox
400 		updateToolbox();
401 
402 		if (aExceptionInfo.isValid())
403 			showError(aExceptionInfo, this, m_xORB);
404 		else
405 		{
406 			m_aUnique.SaveValue();
407 			m_pFields->SaveValue();
408 		}
409 
410 		return !aExceptionInfo.isValid();
411 	}
412 
413 	//------------------------------------------------------------------
414 	void DbaIndexDialog::OnNewIndex()
415 	{
416 		// commit the current entry, if necessary
417 		if (!implCommitPreviouslySelected())
418 			return;
419 
420 		// get a new unique name for the new index
421 		String sNewIndexName;
422 		const String sNewIndexNameBase(ModuleRes(STR_LOGICAL_INDEX_NAME));
423 		sal_Int32 i;
424 
425 		for ( i = 1; i < 0x7FFFFFFF; ++i )
426 		{
427 			sNewIndexName = sNewIndexNameBase;
428 			sNewIndexName += String::CreateFromInt32(i);
429 			if (m_pIndexes->end() == m_pIndexes->find(sNewIndexName))
430 				break;
431 		}
432 		if ((i>0x7FFFFFFF) || (i<0))
433 		{
434 			DBG_ERROR("DbaIndexDialog::OnNewIndex: no free index name found!");
435 			// can't do anything ... of course we try another base, but this could end with the same result ...
436 			return;
437 		}
438 
439 		SvLBoxEntry* pNewEntry = m_aIndexes.InsertEntry(sNewIndexName);
440 		m_pIndexes->insert(sNewIndexName);
441 
442 		// update the user data on the entries in the list box:
443 		// they're iterators of the index collection, and thus they have changed when removing the index
444 		for (SvLBoxEntry* pAdjust = m_aIndexes.First(); pAdjust; pAdjust = m_aIndexes.Next(pAdjust))
445 		{
446 			Indexes::iterator aAfterInsertPos = m_pIndexes->find(m_aIndexes.GetEntryText(pAdjust));
447 			DBG_ASSERT(aAfterInsertPos != m_pIndexes->end(), "DbaIndexDialog::OnNewIndex: problems with on of the entries!");
448 			pAdjust->SetUserData(reinterpret_cast< void* >(sal_Int32(aAfterInsertPos - m_pIndexes->begin())));
449 		}
450 
451 		// select the entry and start in-place editing
452 		m_aIndexes.SelectNoHandlerCall(pNewEntry);
453 		OnIndexSelected(&m_aIndexes);
454 		m_aIndexes.EditEntry(pNewEntry);
455 		updateToolbox();
456 	}
457 
458 	//------------------------------------------------------------------
459 	void DbaIndexDialog::OnDropIndex(sal_Bool _bConfirm)
460 	{
461 		// the selected index
462 		SvLBoxEntry* pSelected = m_aIndexes.FirstSelected();
463 		DBG_ASSERT(pSelected, "DbaIndexDialog::OnDropIndex: invalid call!");
464 		if (pSelected)
465 		{
466 			// let the user confirm the drop
467 			if (_bConfirm)
468 			{
469 				String sConfirm(ModuleRes(STR_CONFIRM_DROP_INDEX));
470 				sConfirm.SearchAndReplaceAscii("$name$", m_aIndexes.GetEntryText(pSelected));
471 				QueryBox aConfirm(this, WB_YES_NO, sConfirm);
472 				if (RET_YES != aConfirm.Execute())
473 					return;
474 			}
475 
476 			// do the drop
477 			implDropIndex(pSelected, sal_True);
478 
479 			// reflect the new selection in the toolbox
480 			updateToolbox();
481 		}
482 	}
483 
484 	//------------------------------------------------------------------
485 	sal_Bool DbaIndexDialog::implDropIndex(SvLBoxEntry* _pEntry, sal_Bool _bRemoveFromCollection)
486 	{
487 		// do the drop
488 		Indexes::iterator aDropPos = m_pIndexes->begin() + reinterpret_cast<sal_IntPtr>(_pEntry->GetUserData());
489 		DBG_ASSERT(aDropPos != m_pIndexes->end(), "DbaIndexDialog::OnDropIndex: did not find the index in my collection!");
490 
491 		SQLExceptionInfo aExceptionInfo;
492 		sal_Bool bSuccess = sal_False;
493 		try
494 		{
495 			if (_bRemoveFromCollection)
496 				bSuccess = m_pIndexes->drop(aDropPos);
497 			else
498 				bSuccess = m_pIndexes->dropNoRemove(aDropPos);
499 		}
500 		catch(SQLContext& e) { aExceptionInfo = SQLExceptionInfo(e); }
501 		catch(SQLWarning& e) { aExceptionInfo = SQLExceptionInfo(e); }
502 		catch(SQLException& e) { aExceptionInfo = SQLExceptionInfo(e); }
503 
504 		if (aExceptionInfo.isValid())
505 			showError(aExceptionInfo, this, m_xORB);
506 		else if (bSuccess && _bRemoveFromCollection)
507 		{
508 			SvLBoxTreeList* pModel = m_aIndexes.GetModel();
509 
510 			m_aIndexes.disableSelectHandler();
511 			pModel->Remove(_pEntry);
512 			m_aIndexes.enableSelectHandler();
513 
514 			// update the user data on the entries in the list box:
515 			// they're iterators of the index collection, and thus they have changed when removing the index
516 			for (SvLBoxEntry* pAdjust = m_aIndexes.First(); pAdjust; pAdjust = m_aIndexes.Next(pAdjust))
517 			{
518 				Indexes::iterator aAfterDropPos = m_pIndexes->find(m_aIndexes.GetEntryText(pAdjust));
519 				DBG_ASSERT(aAfterDropPos != m_pIndexes->end(), "DbaIndexDialog::OnDropIndex: problems with on of the remaining entries!");
520 				pAdjust->SetUserData(reinterpret_cast< void* >(sal_Int32(aAfterDropPos - m_pIndexes->begin())));
521 			}
522 
523 			// if the remvoved entry was the selected on ...
524 			if (m_pPreviousSelection == _pEntry)
525 				m_pPreviousSelection = NULL;
526 
527 			// the Remove automatically selected another entry (if possible), but we disabled the calling of the handler
528 			// to prevent that we missed something ... call the handler directly
529 			OnIndexSelected(&m_aIndexes);
530 		}
531 
532 		return !aExceptionInfo.isValid();
533 	}
534 
535 	//------------------------------------------------------------------
536 	void DbaIndexDialog::OnRenameIndex()
537 	{
538 		// the selected index
539 		SvLBoxEntry* pSelected = m_aIndexes.FirstSelected();
540 		DBG_ASSERT(pSelected, "DbaIndexDialog::OnRenameIndex: invalid call!");
541 
542 		// save the changes made 'til here
543 		// Upon leaving the edit mode, the control will be re-initialized with the
544 		// settings from the current entry
545 		implSaveModified(sal_False);
546 
547 		m_aIndexes.EditEntry(pSelected);
548 		updateToolbox();
549 	}
550 
551 	//------------------------------------------------------------------
552 	void DbaIndexDialog::OnSaveIndex()
553 	{
554 		// the selected index
555 #if OSL_DEBUG_LEVEL > 0
556 		SvLBoxEntry* pSelected = m_aIndexes.FirstSelected();
557 		OSL_ENSURE( pSelected, "DbaIndexDialog::OnSaveIndex: invalid call!" );
558 #endif
559 
560 		implCommitPreviouslySelected();
561 		updateToolbox();
562 	}
563 
564 	//------------------------------------------------------------------
565 	void DbaIndexDialog::OnResetIndex()
566 	{
567 		// the selected index
568 		SvLBoxEntry* pSelected = m_aIndexes.FirstSelected();
569 		DBG_ASSERT(pSelected, "DbaIndexDialog::OnResetIndex: invalid call!");
570 
571 		Indexes::iterator aResetPos = m_pIndexes->begin() + reinterpret_cast<sal_IntPtr>(pSelected->GetUserData());
572 
573 		if (aResetPos->isNew())
574 		{
575 			OnDropIndex(sal_False);
576 			return;
577 		}
578 
579 		SQLExceptionInfo aExceptionInfo;
580 		try
581 		{
582 			m_pIndexes->resetIndex(aResetPos);
583 		}
584 		catch(SQLContext& e) { aExceptionInfo = SQLExceptionInfo(e); }
585 		catch(SQLWarning& e) { aExceptionInfo = SQLExceptionInfo(e); }
586 		catch(SQLException& e) { aExceptionInfo = SQLExceptionInfo(e); }
587 
588 		if (aExceptionInfo.isValid())
589 			showError(aExceptionInfo, this, m_xORB);
590 		else
591 			m_aIndexes.SetEntryText(pSelected, aResetPos->sName);
592 
593 		updateControls(pSelected);
594 		updateToolbox();
595 	}
596 
597 	//------------------------------------------------------------------
598 	IMPL_LINK( DbaIndexDialog, OnIndexAction, ToolBox*, /*NOTINTERESTEDIN*/ )
599 	{
600 		sal_uInt16 nClicked = m_aActions.GetCurItemId();
601 		switch (nClicked)
602 		{
603 			case ID_INDEX_NEW:
604 				OnNewIndex();
605 				break;
606 			case ID_INDEX_DROP:
607 				OnDropIndex();
608 				break;
609 			case ID_INDEX_RENAME:
610 				OnRenameIndex();
611 				break;
612 			case ID_INDEX_SAVE:
613 				OnSaveIndex();
614 				break;
615 			case ID_INDEX_RESET:
616 				OnResetIndex();
617 				break;
618 		}
619 		return 0L;
620 	}
621 
622 	//------------------------------------------------------------------
623 	IMPL_LINK( DbaIndexDialog, OnCloseDialog, void*, /*NOTINTERESTEDIN*/ )
624 	{
625 		if (m_aIndexes.IsEditingActive())
626 		{
627 			DBG_ASSERT(!m_bEditAgain, "DbaIndexDialog::OnCloseDialog: somebody was faster than hell!");
628 				// this means somebody entered a new name, which was invalid, which cause us to posted us an event,
629 				// and before the event arrived the user clicked onto "close". VERY fast, this user ....
630 			m_aIndexes.EndEditing(sal_False);
631 			if (m_bEditAgain)
632 				// could not commit the new name (started a new - asynchronous - edit trial)
633 				return 1L;
634 		}
635 
636 		// the currently selected entry
637 		const SvLBoxEntry* pSelected = m_aIndexes.FirstSelected();
638 		DBG_ASSERT(pSelected == m_pPreviousSelection, "DbaIndexDialog::OnCloseDialog: inconsistence!");
639 
640 		sal_Int32 nResponse = RET_NO;
641 		if (pSelected)
642 		{
643 			// the descriptor
644 			Indexes::const_iterator aSelected = m_pIndexes->begin() + reinterpret_cast<sal_IntPtr>(pSelected->GetUserData());
645 
646 			if (aSelected->isModified() || aSelected->isNew())
647 			{
648 				QueryBox aQuestion(this, ModuleRes(QUERY_SAVE_CURRENT_INDEX));
649 				nResponse = aQuestion.Execute();
650 			}
651 		}
652 
653 		switch (nResponse)
654 		{
655 			case RET_YES:
656 				if (!implCommitPreviouslySelected())
657 					return 1L;
658 				break;
659 			case RET_NO:
660 				break;
661 			default:
662 				return 1L;
663 		}
664 
665 		EndDialog(RET_OK);
666 
667 		return 0L;
668 	}
669 
670 	//------------------------------------------------------------------
671 	IMPL_LINK( DbaIndexDialog, OnEditIndexAgain, SvLBoxEntry*, _pEntry )
672 	{
673 		m_bEditAgain = sal_False;
674 		m_aIndexes.EditEntry(_pEntry);
675 		return 0L;
676 	}
677 
678 	//------------------------------------------------------------------
679 	IMPL_LINK( DbaIndexDialog, OnEntryEdited, SvLBoxEntry*, _pEntry )
680 	{
681 		Indexes::iterator aPosition = m_pIndexes->begin() + reinterpret_cast<sal_IntPtr>(_pEntry->GetUserData());
682 
683 		DBG_ASSERT(aPosition >= m_pIndexes->begin() && aPosition < m_pIndexes->end(),
684 			"DbaIndexDialog::OnEntryEdited: invalid entry!");
685 
686 		String sNewName = m_aIndexes.GetEntryText(_pEntry);
687 
688 		Indexes::const_iterator aSameName = m_pIndexes->find(sNewName);
689 		if ((aSameName != aPosition) && (m_pIndexes->end() != aSameName))
690 		{
691 			String sError(ModuleRes(STR_INDEX_NAME_ALREADY_USED));
692 			sError.SearchAndReplaceAscii("$name$", sNewName);
693 			ErrorBox aError(this, WB_OK, sError);
694 			aError.Execute();
695 
696 			updateToolbox();
697 			m_bEditAgain = sal_True;
698 			PostUserEvent(LINK(this, DbaIndexDialog, OnEditIndexAgain), _pEntry);
699 			return 0L;
700 		}
701 
702 		aPosition->sName = sNewName;
703 
704 		// rename can be done by a drop/insert combination only
705 		if (aPosition->isNew())
706 		{
707 			updateToolbox();
708 			// no commitment needed here ....
709 			return 1L;
710 		}
711 
712 		if (aPosition->sName != aPosition->getOriginalName())
713 		{
714 			aPosition->setModified(sal_True);
715 			updateToolbox();
716 		}
717 
718 		return 1L;
719 	}
720 
721 	//------------------------------------------------------------------
722 	sal_Bool DbaIndexDialog::implSaveModified(sal_Bool _bPlausibility)
723 	{
724 		if (m_pPreviousSelection)
725 		{
726 			// try to commit the previously selected index
727 			if (m_pFields->IsModified() && !m_pFields->SaveModified())
728 				return sal_False;
729 
730 			Indexes::iterator aPreviouslySelected = m_pIndexes->begin() + reinterpret_cast<sal_IntPtr>(m_pPreviousSelection->GetUserData());
731 
732 			// the unique flag
733 			aPreviouslySelected->bUnique = m_aUnique.IsChecked();
734 			if (m_aUnique.GetSavedValue() != m_aUnique.GetState())
735 				aPreviouslySelected->setModified(sal_True);
736 
737 			// the fields
738 			m_pFields->commitTo(aPreviouslySelected->aFields);
739 			if (m_pFields->GetSavedValue() != aPreviouslySelected->aFields)
740 				aPreviouslySelected->setModified(sal_True);
741 
742 			// plausibility checks
743 			if (_bPlausibility && !implCheckPlausibility(aPreviouslySelected))
744 				return sal_False;
745 		}
746 
747 		return sal_True;
748 	}
749 
750 	//------------------------------------------------------------------
751 	sal_Bool DbaIndexDialog::implCheckPlausibility(const ConstIndexesIterator& _rPos)
752 	{
753 		// need at least one field
754 		if (0 == _rPos->aFields.size())
755 		{
756 			ErrorBox aError(this, ModuleRes(ERR_NEED_INDEX_FIELDS));
757 			aError.Execute();
758 			m_pFields->GrabFocus();
759 			return sal_False;
760 		}
761 
762 		// no double fields
763 		DECLARE_STL_STDKEY_SET( String, StringBag );
764 		StringBag aExistentFields;
765 		for (	ConstIndexFieldsIterator aFieldCheck = _rPos->aFields.begin();
766 				aFieldCheck != _rPos->aFields.end();
767 				++aFieldCheck
768 			)
769 		{
770 			if (aExistentFields.end() != aExistentFields.find(aFieldCheck->sFieldName))
771 			{
772 				// a column is specified twice ... won't work anyway, so prevent this here and now
773 				String sMessage(ModuleRes(STR_INDEXDESIGN_DOUBLE_COLUMN_NAME));
774 				sMessage.SearchAndReplaceAscii("$name$", aFieldCheck->sFieldName);
775 				ErrorBox aError(this, WB_OK, sMessage);
776 				aError.Execute();
777 				m_pFields->GrabFocus();
778 				return sal_False;
779 			}
780 			aExistentFields.insert(aFieldCheck->sFieldName);
781 		}
782 
783 		return sal_True;
784 	}
785 
786 	//------------------------------------------------------------------
787 	sal_Bool DbaIndexDialog::implCommitPreviouslySelected()
788 	{
789 		if (m_pPreviousSelection)
790 		{
791 			Indexes::iterator aPreviouslySelected = m_pIndexes->begin() + reinterpret_cast<sal_IntPtr>(m_pPreviousSelection->GetUserData());
792 
793 			if (!implSaveModified())
794 				return sal_False;
795 
796 			// commit the index (if necessary)
797 			if (aPreviouslySelected->isModified() && !implCommit(m_pPreviousSelection))
798 				return sal_False;
799 		}
800 
801 		return sal_True;
802 	}
803 
804 	//------------------------------------------------------------------
805 	IMPL_LINK( DbaIndexDialog, OnModified, void*, /*NOTINTERESTEDIN*/ )
806 	{
807 		DBG_ASSERT(m_pPreviousSelection, "DbaIndexDialog, OnModified: invalid call!");
808 		Indexes::iterator aPosition = m_pIndexes->begin() + reinterpret_cast<sal_IntPtr>(m_pPreviousSelection->GetUserData());
809 
810 		aPosition->setModified(sal_True);
811 		updateToolbox();
812 
813 		return 1L;
814 	}
815 
816 	//------------------------------------------------------------------
817 	void DbaIndexDialog::updateControls(const SvLBoxEntry* _pEntry)
818 	{
819 		if (_pEntry)
820 		{
821 			// the descriptor of the selected index
822 			Indexes::const_iterator aSelectedIndex = m_pIndexes->begin() + reinterpret_cast<sal_IntPtr>(_pEntry->GetUserData());
823 
824 			// fill the controls
825 			m_aUnique.Check(aSelectedIndex->bUnique);
826 			m_aUnique.Enable(!aSelectedIndex->bPrimaryKey);
827 			m_aUnique.SaveValue();
828 
829 			m_pFields->initializeFrom(aSelectedIndex->aFields);
830 			m_pFields->Enable(!aSelectedIndex->bPrimaryKey);
831 			m_pFields->SaveValue();
832 
833 			m_aDescription.SetText(aSelectedIndex->sDescription);
834 			m_aDescription.Enable(!aSelectedIndex->bPrimaryKey);
835 
836 			m_aDescriptionLabel.Enable(!aSelectedIndex->bPrimaryKey);
837 		}
838 		else
839 		{
840 			m_aUnique.Check(sal_False);
841 			m_pFields->initializeFrom(IndexFields());
842 			m_aDescription.SetText(String());
843 		}
844 	}
845 
846 	//------------------------------------------------------------------
847 	IMPL_LINK( DbaIndexDialog, OnIndexSelected, DbaIndexList*, /*NOTINTERESTEDIN*/ )
848 	{
849 		m_aIndexes.EndSelection();
850 
851 		if (m_aIndexes.IsEditingActive())
852 			m_aIndexes.EndEditing(sal_False);
853 
854 		// commit the old data
855 		if (m_aIndexes.FirstSelected() != m_pPreviousSelection)
856 		{	// (this call may happen in case somebody ended an in-place edit with 'return', so we need to check this before committing)
857 			if (!implCommitPreviouslySelected())
858 			{
859 				m_aIndexes.SelectNoHandlerCall(m_pPreviousSelection);
860 				return 1L;
861 			}
862 		}
863 
864 		sal_Bool bHaveSelection = (NULL != m_aIndexes.FirstSelected());
865 
866 		// disable/enable the detail controls
867 		m_aIndexDetails.Enable(bHaveSelection);
868 		m_aUnique.Enable(bHaveSelection);
869 		m_aDescriptionLabel.Enable(bHaveSelection);
870 		m_aFieldsLabel.Enable(bHaveSelection);
871 		m_pFields->Enable(bHaveSelection);
872 
873 		SvLBoxEntry* pNewSelection = m_aIndexes.FirstSelected();
874 		updateControls(pNewSelection);
875 		if (bHaveSelection)
876 			m_aIndexes.GrabFocus();
877 
878 		m_pPreviousSelection = pNewSelection;
879 
880 		updateToolbox();
881 		return 0L;
882 	}
883 	// -----------------------------------------------------------------------------
884 	void DbaIndexDialog::StateChanged( StateChangedType nType )
885 	{
886 		ModalDialog::StateChanged( nType );
887 
888 		if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
889 		{
890 			// Check if we need to get new images for normal/high contrast mode
891 			checkImageList();
892 		}
893 		else if ( nType == STATE_CHANGE_TEXT )
894 		{
895 			// The physical toolbar changed its outlook and shows another logical toolbar!
896 			// We have to set the correct high contrast mode on the new tbx manager.
897 			//	pMgr->SetHiContrast( IsHiContrastMode() );
898 			checkImageList();
899 		}
900 	}
901 	// -----------------------------------------------------------------------------
902 	void DbaIndexDialog::DataChanged( const DataChangedEvent& rDCEvt )
903 	{
904 		ModalDialog::DataChanged( rDCEvt );
905 
906 		if ((( rDCEvt.GetType() == DATACHANGED_SETTINGS	)	||
907 			( rDCEvt.GetType() == DATACHANGED_DISPLAY	))	&&
908 			( rDCEvt.GetFlags() & SETTINGS_STYLE		))
909 		{
910 			// Check if we need to get new images for normal/high contrast mode
911 			checkImageList();
912 		}
913 	}
914 	//------------------------------------------------------------------
915 	ImageList DbaIndexDialog::getImageList(sal_Int16 _eBitmapSet,sal_Bool _bHiContast) const
916 	{
917 		sal_Int16 nN = IMG_INDEX_DLG_SC;
918 		sal_Int16 nH = IMG_INDEX_DLG_SCH;
919 		if ( _eBitmapSet == SFX_SYMBOLS_SIZE_LARGE )
920 		{
921 			nN = IMG_INDEX_DLG_LC;
922 			nH = IMG_INDEX_DLG_LCH;
923 		} // if ( _eBitmapSet == SFX_SYMBOLS_LARGE )
924 		return ImageList(ModuleRes( _bHiContast ? nH : nN ));
925 	}
926 	//------------------------------------------------------------------
927 	void DbaIndexDialog::resizeControls(const Size& _rDiff)
928 	{
929 		// we use large images so we must change them
930 		Size aTbNewSize = m_aActions.GetSizePixel();
931 		if ( _rDiff.Width() || _rDiff.Height() )
932 		{
933 			Size aDlgSize = GetSizePixel();
934 			// adjust size of dlg
935 			SetSizePixel(Size(aDlgSize.Width() + _rDiff.Width(),
936 							  aDlgSize.Height() + _rDiff.Height())
937 						);
938 			Size aIndexSize = m_aIndexes.GetSizePixel();
939 			m_aIndexes.SetPosSizePixel(m_aIndexes.GetPosPixel() + Point(0,_rDiff.Height()),
940 									Size(aIndexSize.Width() + _rDiff.Width(),
941 									     aIndexSize.Height()));
942 
943 			//now move the rest to the left side
944 			Point aMove(_rDiff.Width(),_rDiff.Height());
945 			m_aIndexDetails.SetPosPixel(m_aIndexDetails.GetPosPixel() + aMove);
946 			m_aDescriptionLabel.SetPosPixel(m_aDescriptionLabel.GetPosPixel() + aMove);
947 			m_aDescription.SetPosPixel(m_aDescription.GetPosPixel() + aMove);
948 			m_aUnique.SetPosPixel(m_aUnique.GetPosPixel() + aMove);
949 			m_aFieldsLabel.SetPosPixel(m_aFieldsLabel.GetPosPixel() + aMove);
950 			OSL_ENSURE(m_pFields,"NO valid fields!");
951 			m_pFields->SetPosPixel(m_pFields->GetPosPixel() + aMove);
952 			m_aClose.SetPosPixel(m_aClose.GetPosPixel() + aMove);
953 			m_aHelp.SetPosPixel(m_aHelp.GetPosPixel() + aMove);
954 
955 			Invalidate();
956 		}
957 	}
958 
959 //......................................................................
960 }	// namespace dbaui
961 //......................................................................
962 
963