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 #include "FieldDescriptions.hxx"
32 #include "TEditControl.hxx"
33 #include "TableController.hxx"
34 #include "TableDesignView.hxx"
35 #include "TableRow.hxx"
36 #include "TypeInfo.hxx"
37 #include "UITools.hxx"
38 #include "browserids.hxx"
39 #include "dbu_reghelper.hxx"
40 #include "dbu_tbl.hrc"
41 #include "dbustrings.hrc"
42 #include "defaultobjectnamecheck.hxx"
43 #include "dlgsave.hxx"
44 #include "dsmeta.hxx"
45 #include "indexdialog.hxx"
46 #include "sqlmessage.hxx"
47 
48 /** === begin UNO includes === **/
49 #include <com/sun/star/container/XChild.hpp>
50 #include <com/sun/star/container/XNameContainer.hpp>
51 #include <com/sun/star/frame/FrameSearchFlag.hpp>
52 #include <com/sun/star/frame/XTitleChangeListener.hpp>
53 #include <com/sun/star/frame/XUntitledNumbers.hpp>
54 #include <com/sun/star/io/XActiveDataSink.hpp>
55 #include <com/sun/star/io/XActiveDataSource.hpp>
56 #include <com/sun/star/sdb/CommandType.hpp>
57 #include <com/sun/star/sdb/SQLContext.hpp>
58 #include <com/sun/star/sdbc/ColumnValue.hpp>
59 #include <com/sun/star/sdbc/SQLWarning.hpp>
60 #include <com/sun/star/sdbc/XRow.hpp>
61 #include <com/sun/star/sdbcx/KeyType.hpp>
62 #include <com/sun/star/sdbcx/XAlterTable.hpp>
63 #include <com/sun/star/sdbcx/XAppend.hpp>
64 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
65 #include <com/sun/star/sdbcx/XDrop.hpp>
66 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
67 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
68 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
69 /** === end UNO includes === **/
70 
71 #include <comphelper/extract.hxx>
72 #include <comphelper/streamsection.hxx>
73 #include <comphelper/types.hxx>
74 #include <connectivity/dbexception.hxx>
75 #include <connectivity/dbtools.hxx>
76 #include <connectivity/dbmetadata.hxx>
77 #include <cppuhelper/exc_hlp.hxx>
78 #include <sfx2/sfxsids.hrc>
79 #include <tools/diagnose_ex.h>
80 #include <tools/string.hxx>
81 #include <vcl/msgbox.hxx>
82 
83 #include <boost/mem_fn.hpp>
84 #include <boost/bind.hpp>
85 
86 #include <algorithm>
87 #include <functional>
88 
89 extern "C" void SAL_CALL createRegistryInfo_OTableControl()
90 {
91 	static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OTableController > aAutoRegistration;
92 }
93 
94 using namespace ::com::sun::star;
95 using namespace ::com::sun::star::uno;
96 using namespace ::com::sun::star::io;
97 using namespace ::com::sun::star::beans;
98 using namespace ::com::sun::star::frame;
99 using namespace ::com::sun::star::util;
100 using namespace ::com::sun::star::lang;
101 using namespace ::com::sun::star::container;
102 using namespace ::com::sun::star::sdbcx;
103 using namespace ::com::sun::star::sdbc;
104 using namespace ::com::sun::star::sdb;
105 using namespace ::com::sun::star::ui;
106 using namespace ::com::sun::star::util;
107 using namespace ::dbtools;
108 using namespace ::dbaui;
109 using namespace ::comphelper;
110 
111 // Anzahl Spalten beim Neuanlegen
112 #define NEWCOLS		   128
113 
114 namespace
115 {
116 	void dropTable(const Reference<XNameAccess>& _rxTable,const ::rtl::OUString& _sTableName)
117 	{
118 		if ( _rxTable->hasByName(_sTableName) )
119 		{
120 			Reference<XDrop> xNameCont(_rxTable,UNO_QUERY);
121 			OSL_ENSURE(xNameCont.is(),"No drop interface for tables!");
122 			if ( xNameCont.is() )
123 				xNameCont->dropByName(_sTableName);
124 		}
125 	}
126 	//------------------------------------------------------------------------------
127 	struct OTableRowCompare : public ::std::binary_function<  ::boost::shared_ptr<OTableRow> , ::rtl::OUString, bool>
128 	{
129 		bool operator() (const  ::boost::shared_ptr<OTableRow>  lhs, const ::rtl::OUString& rhs) const
130 		{
131 			OFieldDescription* pField = lhs->GetActFieldDescr();
132 			return pField && pField->GetName() == rhs;
133 		}
134 	};
135 
136 }
137 
138 //------------------------------------------------------------------------------
139 ::rtl::OUString SAL_CALL OTableController::getImplementationName() throw( RuntimeException )
140 {
141 	return getImplementationName_Static();
142 }
143 
144 //------------------------------------------------------------------------------
145 ::rtl::OUString OTableController::getImplementationName_Static() throw( RuntimeException )
146 {
147 	return ::rtl::OUString::createFromAscii("org.openoffice.comp.dbu.OTableDesign");
148 }
149 //------------------------------------------------------------------------------
150 Sequence< ::rtl::OUString> OTableController::getSupportedServiceNames_Static(void) throw( RuntimeException )
151 {
152 	Sequence< ::rtl::OUString> aSupported(1);
153 	aSupported.getArray()[0] = ::rtl::OUString::createFromAscii("com.sun.star.sdb.TableDesign");
154 	return aSupported;
155 }
156 //-------------------------------------------------------------------------
157 Sequence< ::rtl::OUString> SAL_CALL OTableController::getSupportedServiceNames() throw(RuntimeException)
158 {
159 	return getSupportedServiceNames_Static();
160 }
161 // -------------------------------------------------------------------------
162 Reference< XInterface > SAL_CALL OTableController::Create(const Reference<XMultiServiceFactory >& _rxFactory)
163 {
164 	return *(new OTableController(_rxFactory));
165 }
166 
167 DBG_NAME(OTableController)
168 // -----------------------------------------------------------------------------
169 OTableController::OTableController(const Reference< XMultiServiceFactory >& _rM) : OTableController_BASE(_rM)
170 	,m_sTypeNames(ModuleRes(STR_TABLEDESIGN_DBFIELDTYPES))
171 	,m_pTypeInfo()
172 	,m_bAllowAutoIncrementValue(sal_False)
173 	,m_bNew(sal_True)
174 {
175     DBG_CTOR(OTableController,NULL);
176 
177 	InvalidateAll();
178 	m_pTypeInfo = TOTypeInfoSP(new OTypeInfo());
179 	m_pTypeInfo->aUIName = m_sTypeNames.GetToken(TYPE_OTHER);
180 }
181 // -----------------------------------------------------------------------------
182 OTableController::~OTableController()
183 {
184 	m_aTypeInfoIndex.clear();
185 	m_aTypeInfo.clear();
186 
187     DBG_DTOR(OTableController,NULL);
188 }
189 
190 // -----------------------------------------------------------------------------
191 void OTableController::startTableListening()
192 {
193 	Reference< XComponent >  xComponent(m_xTable, UNO_QUERY);
194 	if (xComponent.is())
195 		xComponent->addEventListener(static_cast<XModifyListener*>(this));
196 }
197 
198 // -----------------------------------------------------------------------------
199 void OTableController::stopTableListening()
200 {
201 	Reference< XComponent >  xComponent(m_xTable, UNO_QUERY);
202 	if (xComponent.is())
203 		xComponent->removeEventListener(static_cast<XModifyListener*>(this));
204 }
205 
206 // -----------------------------------------------------------------------------
207 void OTableController::disposing()
208 {
209 	OTableController_BASE::disposing();
210     clearView();
211 
212     m_vRowList.clear();
213 }
214 // -----------------------------------------------------------------------------
215 FeatureState OTableController::GetState(sal_uInt16 _nId) const
216 {
217 	FeatureState aReturn;
218 	// (disabled automatically)
219 
220 	switch (_nId)
221 	{
222 		case ID_BROWSER_CLOSE:
223 			aReturn.bEnabled = sal_True;
224 			break;
225 		case ID_BROWSER_EDITDOC:
226 			aReturn.bChecked = isEditable();
227 			aReturn.bEnabled = m_bNew || isEditable();// the editable flag is set through this one -> || isAddAllowed() || isDropAllowed() || isAlterAllowed();
228 			break;
229 		case ID_BROWSER_SAVEDOC:
230 			aReturn.bEnabled = impl_isModified();
231 			if ( aReturn.bEnabled )
232 			{
233 				::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(),
234                     ::boost::mem_fn(&OTableRow::isValid));
235 				aReturn.bEnabled = aIter != m_vRowList.end();
236 			}
237 			break;
238 		case ID_BROWSER_SAVEASDOC:
239 			aReturn.bEnabled = isConnected() && isEditable();
240 			if ( aReturn.bEnabled )
241 			{
242 				::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(),
243                     ::boost::mem_fn(&OTableRow::isValid));
244 				aReturn.bEnabled = aIter != m_vRowList.end();
245 			}
246 			break;
247 
248 		case ID_BROWSER_CUT:
249 			aReturn.bEnabled = isEditable() && m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isCutAllowed();
250 			break;
251 		case ID_BROWSER_COPY:
252 			aReturn.bEnabled = m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isCopyAllowed();
253 			break;
254 		case ID_BROWSER_PASTE:
255 			aReturn.bEnabled = isEditable() && m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isPasteAllowed();
256 			break;
257 		case SID_INDEXDESIGN:
258 			aReturn.bEnabled =
259 				(	(	((!m_bNew && impl_isModified()) || impl_isModified())
260 					||	Reference< XIndexesSupplier >(m_xTable, UNO_QUERY).is()
261 					)
262 				&&	isConnected()
263 				);
264 			if ( aReturn.bEnabled )
265 			{
266 				::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(),
267                     ::boost::mem_fn(&OTableRow::isValid));
268 				aReturn.bEnabled = aIter != m_vRowList.end();
269 			}
270 			break;
271 		default:
272 			aReturn = OTableController_BASE::GetState(_nId);
273 	}
274 	return aReturn;
275 }
276 // -----------------------------------------------------------------------------
277 void OTableController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
278 {
279 	switch(_nId)
280 	{
281 		case ID_BROWSER_EDITDOC:
282 			setEditable(!isEditable());
283 			static_cast<OTableDesignView*>(getView())->setReadOnly(!isEditable());
284 			InvalidateFeature(ID_BROWSER_PASTE);
285 			InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
286 			break;
287 		case ID_BROWSER_SAVEASDOC:
288 			doSaveDoc(sal_True);
289 			break;
290 		case ID_BROWSER_SAVEDOC:
291 			static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->SaveCurRow();
292 			doSaveDoc(sal_False);
293 			break;
294 		case ID_BROWSER_CUT:
295 			static_cast<OTableDesignView*>(getView())->cut();
296 			break;
297 		case ID_BROWSER_COPY:
298 			static_cast<OTableDesignView*>(getView())->copy();
299 			break;
300 		case ID_BROWSER_PASTE:
301 			static_cast<OTableDesignView*>(getView())->paste();
302 			break;
303 		case SID_INDEXDESIGN:
304 			doEditIndexes();
305 			break;
306 		default:
307 			OTableController_BASE::Execute(_nId,aArgs);
308 	}
309 	InvalidateFeature(_nId);
310 }
311 
312 // -----------------------------------------------------------------------------
313 sal_Bool OTableController::doSaveDoc(sal_Bool _bSaveAs)
314 {
315 	if (!isConnected())
316 		reconnect(sal_True); // ask the user for a new connection
317 	Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY);
318 
319 	if (!xTablesSup.is())
320 	{
321 		String aMessage(ModuleRes(STR_TABLEDESIGN_CONNECTION_MISSING));
322         OSQLWarningBox( getView(), aMessage ).Execute();
323 		return sal_False;
324 	}
325 
326 	// check if a column exists
327 	// TODO
328 
329 	Reference<XNameAccess> xTables;
330 	::rtl::OUString sCatalog, sSchema;
331 
332 	sal_Bool bNew = (0 == m_sName.getLength());
333 	bNew = bNew || m_bNew || _bSaveAs;
334 
335 	try
336 	{
337 		xTables = xTablesSup->getTables();
338 		OSL_ENSURE(xTables.is(),"The tables can't be null!");
339 		bNew = bNew || (xTables.is() && !xTables->hasByName(m_sName));
340 
341 		// first we need a name for our query so ask the user
342 		if(bNew)
343 		{
344 			String aDefaultName;
345 			if (_bSaveAs && !bNew)
346 				 aDefaultName = String(m_sName);
347 			else
348             {
349                 String aName = String(ModuleRes(STR_TBL_TITLE));
350 			    aDefaultName = aName.GetToken(0,' ');
351                 //aDefaultName = getPrivateTitle();
352                 aDefaultName = ::dbtools::createUniqueName(xTables,aDefaultName);
353             }
354 
355             DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::TABLE );
356 			OSaveAsDlg aDlg( getView(), CommandType::TABLE, getORB(), getConnection(), aDefaultName, aNameChecker );
357 			if ( aDlg.Execute() != RET_OK )
358                 return sal_False;
359 
360             m_sName = aDlg.getName();
361 			sCatalog = aDlg.getCatalog();
362 			sSchema	 = aDlg.getSchema();
363 		}
364 
365 		// did we get a name
366 		if(!m_sName.getLength())
367 			return sal_False;
368 	}
369 	catch(Exception&)
370 	{
371 		OSL_ENSURE(sal_False, "OTableController::doSaveDoc: nothing is expected to happen here!");
372 	}
373 
374 	sal_Bool bAlter = sal_False;
375 	sal_Bool bError = sal_False;
376 	SQLExceptionInfo aInfo;
377 	try
378 	{
379 		// check the columns for double names
380 		if(!checkColumns(bNew || !xTables->hasByName(m_sName)))
381 		{
382 			// #105323# OJ
383 			return sal_False;
384 		}
385 
386 		Reference<XPropertySet> xTable;
387 		if(bNew || !xTables->hasByName(m_sName)) // just to make sure the table already exists
388 		{
389 			dropTable(xTables,m_sName);
390 
391 			Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY);
392 			OSL_ENSURE(xFact.is(),"OTableController::doSaveDoc: No XDataDescriptorFactory available!");
393 			xTable = xFact->createDataDescriptor();
394 			OSL_ENSURE(xTable.is(),"OTableController::doSaveDoc: Create query failed!");
395 			// to set the name is only allowed when the wuery is new
396 			xTable->setPropertyValue(PROPERTY_CATALOGNAME,makeAny(sCatalog));
397 			xTable->setPropertyValue(PROPERTY_SCHEMANAME,makeAny(sSchema));
398 			xTable->setPropertyValue(PROPERTY_NAME,makeAny(m_sName));
399 
400 			// now append the columns
401 			Reference<XColumnsSupplier> xColSup(xTable,UNO_QUERY);
402 			appendColumns(xColSup,bNew);
403 			// now append the primary key
404 			Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY);
405 			appendPrimaryKey(xKeySup,bNew);
406 		}
407 		// now set the properties
408 		if(bNew)
409 		{
410 			Reference<XAppend> xAppend(xTables,UNO_QUERY);
411 			OSL_ENSURE(xAppend.is(),"OTableController::doSaveDoc: No XAppend Interface!");
412 			xAppend->appendByDescriptor(xTable);
413 
414 			assignTable();
415 			if(!m_xTable.is()) // correct name and try again
416 			{
417 				// it can be that someone inserted new data for us
418 				m_sName = ::dbtools::composeTableName( getConnection()->getMetaData(), xTable, ::dbtools::eInDataManipulation, false, false, false );
419 				assignTable();
420 			}
421 			// now check if our datasource has set a tablefilter and if append the new table name to it
422 			::dbaui::appendToFilter(getConnection(),m_sName,getORB(),getView()); // we are not interessted in the return value
423             Reference< frame::XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY);
424             if ( xEventListener.is() )
425             {
426                 frame::TitleChangedEvent aEvent;
427                 xEventListener->titleChanged(aEvent);
428             }
429             releaseNumberForComponent();
430 		}
431 		else if(m_xTable.is())
432 		{
433 			bAlter = sal_True;
434 			alterColumns();
435 		}
436 		reSyncRows();
437 	}
438 	catch(const SQLContext& e)
439 	{
440 		aInfo = SQLExceptionInfo(e);
441 	}
442 	catch(const SQLWarning& e)
443 	{
444 		aInfo = SQLExceptionInfo(e);
445 	}
446 	catch(const SQLException& e)
447 	{
448 		aInfo = SQLExceptionInfo(e);
449 	}
450 	catch(const ElementExistException& )
451 	{
452 		String sText( ModuleRes( STR_NAME_ALREADY_EXISTS ) );
453 		sText.SearchAndReplaceAscii( "#" , m_sName);
454 		OSQLMessageBox aDlg( getView(), String( ModuleRes( STR_ERROR_DURING_CREATION ) ), sText, WB_OK, OSQLMessageBox::Error );
455 
456 		aDlg.Execute();
457 		bError = sal_True;
458 	}
459     catch( const Exception& )
460     {
461         bError = sal_True;
462         DBG_UNHANDLED_EXCEPTION();
463     }
464 
465     if ( aInfo.isValid() )
466         aInfo.prepend( String( ModuleRes( STR_TABLEDESIGN_SAVE_ERROR ) ) );
467 	showError(aInfo);
468 
469 	if (aInfo.isValid() || bError)
470 	{
471 		if(!bAlter || bNew)
472 		{
473 			m_sName = ::rtl::OUString();
474 			stopTableListening();
475 			m_xTable = NULL;
476 		}
477 		//	reload(); // a error occured so we have to reload
478 	}
479 	return ! (aInfo.isValid() || bError);
480 }
481 
482 // -----------------------------------------------------------------------------
483 void OTableController::doEditIndexes()
484 {
485 	// table needs to be saved before editing indexes
486 	if (m_bNew || isModified())
487 	{
488 		QueryBox aAsk(getView(), ModuleRes(QUERY_SAVE_TABLE_EDIT_INDEXES));
489 		if (RET_YES != aAsk.Execute())
490 			return;
491 
492 		if (!doSaveDoc(sal_False))
493 			return;
494 
495 		OSL_ENSURE(!m_bNew && !isModified(), "OTableController::doEditIndexes: what the hell did doSaveDoc do?");
496 	}
497 
498 	Reference< XNameAccess > xIndexes;			// will be the keys of the table
499 	Sequence< ::rtl::OUString > aFieldNames;	// will be the column names of the table
500 	try
501 	{
502 		// get the keys
503 		Reference< XIndexesSupplier > xIndexesSupp(m_xTable, UNO_QUERY);
504 		if (xIndexesSupp.is())
505 		{
506 			xIndexes = xIndexesSupp->getIndexes();
507 			OSL_ENSURE(xIndexes.is(), "OTableController::doEditIndexes: no keys got from the indexes supplier!");
508 		}
509 		else
510 			OSL_ENSURE(sal_False, "OTableController::doEditIndexes: should never have reached this (no indexes supplier)!");
511 
512 		// get the field names
513 		Reference< XColumnsSupplier > xColSupp(m_xTable, UNO_QUERY);
514 		OSL_ENSURE(xColSupp.is(), "OTableController::doEditIndexes: no columns supplier!");
515 		if (xColSupp.is())
516 		{
517 			Reference< XNameAccess > xCols = xColSupp->getColumns();
518 			OSL_ENSURE(xCols.is(), "OTableController::doEditIndexes: no columns!");
519 			if (xCols.is())
520 				aFieldNames = xCols->getElementNames();
521 		}
522 	}
523     catch( const Exception& )
524     {
525         DBG_UNHANDLED_EXCEPTION();
526     }
527 
528 	if (!xIndexes.is())
529 		return;
530 
531 	DbaIndexDialog aDialog(getView(), aFieldNames, xIndexes, getConnection(),getORB(),isConnected() ? getConnection()->getMetaData().is() && getConnection()->getMetaData()->getMaxColumnsInIndex() : sal_Int32(0));
532 	if (RET_OK != aDialog.Execute())
533 		return;
534 
535 }
536 
537 // -----------------------------------------------------------------------------
538 void OTableController::impl_initialize()
539 {
540 	try
541 	{
542 		OTableController_BASE::impl_initialize();
543 
544         const NamedValueCollection& rArguments( getInitParams() );
545 
546         rArguments.get_ensureType( (::rtl::OUString)PROPERTY_CURRENTTABLE, m_sName );
547 
548         // read autoincrement value set in the datasource
549 		::dbaui::fillAutoIncrementValue(getDataSource(),m_bAllowAutoIncrementValue,m_sAutoIncrementValue);
550 
551 		assignTable();
552 	}
553     catch( const Exception& )
554     {
555         DBG_UNHANDLED_EXCEPTION();
556     }
557 
558 	try
559 	{
560 		::dbaui::fillTypeInfo(getConnection(),m_sTypeNames,m_aTypeInfo,m_aTypeInfoIndex);				// fill the needed type information
561 	}
562 	catch(const SQLException&)
563 	{
564 		OSQLWarningBox( getView(), ModuleRes( STR_NO_TYPE_INFO_AVAILABLE ) ).Execute();
565 		throw;
566 	}
567 	try
568 	{
569 		loadData();					// fill the column information form the table
570 		getView()->initialize();	// show the windows and fill with our informations
571 		ClearUndoManager();
572 		setModified(sal_False);		// and we are not modified yet
573 	}
574     catch( const Exception& )
575     {
576         DBG_UNHANDLED_EXCEPTION();
577     }
578 }
579 // -----------------------------------------------------------------------------
580 sal_Bool OTableController::Construct(Window* pParent)
581 {
582 	setView( * new OTableDesignView( pParent, getORB(), *this ) );
583 	OTableController_BASE::Construct(pParent);
584 //	m_pView->Construct();
585 //	m_pView->Show();
586 	return sal_True;
587 }
588 // -----------------------------------------------------------------------------
589 sal_Bool SAL_CALL OTableController::suspend(sal_Bool /*_bSuspend*/) throw( RuntimeException )
590 {
591 	if ( getBroadcastHelper().bInDispose || getBroadcastHelper().bDisposed )
592 		return sal_True;
593 
594 	vos::OGuard aSolarGuard( Application::GetSolarMutex() );
595 	::osl::MutexGuard aGuard( getMutex() );
596     if ( getView() && getView()->IsInModalMode() )
597         return sal_False;
598     if ( getView() )
599         static_cast<OTableDesignView*>(getView())->GrabFocus();
600 	sal_Bool bCheck = sal_True;
601 	if ( isModified() )
602 	{
603 		::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(),
604             ::boost::mem_fn(&OTableRow::isValid));
605 		if ( aIter != m_vRowList.end() )
606 		{
607 			QueryBox aQry(getView(), ModuleRes(TABLE_DESIGN_SAVEMODIFIED));
608 			switch (aQry.Execute())
609 			{
610 				case RET_YES:
611 					Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>());
612 					if ( isModified() )
613 						bCheck = sal_False; // when we save the table this must be false else some press cancel
614 					break;
615 				case RET_CANCEL:
616 					bCheck = sal_False;
617 				default:
618 					break;
619 			}
620 		}
621 		else if ( !m_bNew )
622 		{
623 			QueryBox aQry(getView(), ModuleRes(TABLE_DESIGN_ALL_ROWS_DELETED));
624 			switch (aQry.Execute())
625 			{
626 				case RET_YES:
627 					{
628 						try
629 						{
630 							Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY);
631 							Reference<XNameAccess> xTables = xTablesSup->getTables();
632 							dropTable(xTables,m_sName);
633 						}
634 						catch(const Exception&)
635 						{
636 							OSL_ENSURE(sal_False, "OTableController::suspend: nothing is expected to happen here!");
637 						}
638 
639 					}
640 					break;
641 				case RET_CANCEL:
642 					bCheck = sal_False;
643 				default:
644 					break;
645 			}
646 		}
647 	}
648 /*
649 	if ( bCheck )
650 		OSingleDocumentController::suspend(_bSuspend);
651 */
652 	return bCheck;
653 }
654 // -----------------------------------------------------------------------------
655 void OTableController::describeSupportedFeatures()
656 {
657 	OSingleDocumentController::describeSupportedFeatures();
658 
659     implDescribeSupportedFeature( ".uno:Redo",          ID_BROWSER_REDO,        CommandGroup::EDIT );
660 	implDescribeSupportedFeature( ".uno:Save",          ID_BROWSER_SAVEDOC,     CommandGroup::EDIT );
661 	implDescribeSupportedFeature( ".uno:Undo",          ID_BROWSER_UNDO,        CommandGroup::EDIT );
662 	implDescribeSupportedFeature( ".uno:HelpMenu",      SID_HELPMENU,           CommandGroup::APPLICATION );
663 	implDescribeSupportedFeature( ".uno:NewDoc",        SID_NEWDOC,             CommandGroup::DOCUMENT );
664 	implDescribeSupportedFeature( ".uno:SaveAs",        ID_BROWSER_SAVEASDOC,   CommandGroup::DOCUMENT );
665 	implDescribeSupportedFeature( ".uno:DBIndexDesign", SID_INDEXDESIGN,        CommandGroup::APPLICATION );
666 	implDescribeSupportedFeature( ".uno:EditDoc",       ID_BROWSER_EDITDOC,     CommandGroup::EDIT );
667 }
668 // -----------------------------------------------------------------------------
669 void OTableController::impl_onModifyChanged()
670 {
671     OSingleDocumentController::impl_onModifyChanged();
672     InvalidateFeature( SID_INDEXDESIGN );
673 }
674 // -----------------------------------------------------------------------------
675 void SAL_CALL OTableController::disposing( const EventObject& _rSource ) throw(RuntimeException)
676 {
677 	if ( _rSource.Source == m_xTable )
678 	{	// some deleted our table so we have a new one
679 		stopTableListening();
680 		m_xTable	= NULL;
681 		m_bNew		= sal_True;
682 		setModified(sal_True);
683 	}
684 	else
685 		OTableController_BASE::disposing( _rSource );
686 }
687 // -----------------------------------------------------------------------------
688 void OTableController::Save(const Reference< XObjectOutputStream>& _rxOut)
689 {
690 	OStreamSection aSection(_rxOut.get());
691 
692 }
693 // -----------------------------------------------------------------------------
694 void OTableController::Load(const Reference< XObjectInputStream>& _rxIn)
695 {
696 	OStreamSection aSection(_rxIn.get());
697 }
698 
699 // -----------------------------------------------------------------------------
700 void OTableController::losingConnection( )
701 {
702 	// let the base class do it's reconnect
703 	OTableController_BASE::losingConnection( );
704 
705 	// remove from the table
706 	Reference< XComponent >  xComponent(m_xTable, UNO_QUERY);
707 	if (xComponent.is())
708 	{
709 		Reference<XEventListener> xEvtL( static_cast< ::cppu::OWeakObject*>(this), UNO_QUERY);
710 		xComponent->removeEventListener(xEvtL);
711 	}
712 	stopTableListening();
713 	m_xTable	= NULL;
714 	assignTable();
715 	if(!m_xTable.is())
716 	{
717 		m_bNew		= sal_True;
718 		setModified(sal_True);
719 	}
720 	InvalidateAll();
721 }
722 // -----------------------------------------------------------------------------
723 TOTypeInfoSP OTableController::getTypeInfoByType(sal_Int32 _nDataType) const
724 {
725 	return queryTypeInfoByType(_nDataType,m_aTypeInfo);
726 }
727 // -----------------------------------------------------------------------------
728 void OTableController::appendColumns(Reference<XColumnsSupplier>& _rxColSup,sal_Bool _bNew,sal_Bool _bKeyColumns)
729 {
730 	try
731 	{
732 		// now append the columns
733 		OSL_ENSURE(_rxColSup.is(),"No columns supplier");
734 		if(!_rxColSup.is())
735 			return;
736 		Reference<XNameAccess> xColumns = _rxColSup->getColumns();
737 		OSL_ENSURE(xColumns.is(),"No columns");
738 		Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY);
739 
740 		Reference<XAppend> xAppend(xColumns,UNO_QUERY);
741 		OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
742 
743 		::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin();
744 		::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end();
745 		for(;aIter != aEnd;++aIter)
746 		{
747 			OSL_ENSURE(*aIter,"OTableRow is null!");
748 			OFieldDescription* pField = (*aIter)->GetActFieldDescr();
749 			if ( !pField || (!_bNew && (*aIter)->IsReadOnly() && !_bKeyColumns) )
750 				continue;
751 
752 			Reference<XPropertySet> xColumn;
753 			if(pField->IsPrimaryKey() || !_bKeyColumns)
754 				xColumn = xColumnFactory->createDataDescriptor();
755 			if(xColumn.is())
756 			{
757 				if(!_bKeyColumns)
758 					::dbaui::setColumnProperties(xColumn,pField);
759 				else
760 					xColumn->setPropertyValue(PROPERTY_NAME,makeAny(pField->GetName()));
761 
762 				xAppend->appendByDescriptor(xColumn);
763 				xColumn = NULL;
764 				// now only the settings are missing
765 				if(xColumns->hasByName(pField->GetName()))
766 				{
767 					xColumns->getByName(pField->GetName()) >>= xColumn;
768 					if(xColumn.is())
769 						pField->copyColumnSettingsTo(xColumn);
770 				}
771 				else
772 				{
773 					OSL_ENSURE(sal_False, "OTableController::appendColumns: invalid field name!");
774 				}
775 
776 			}
777 		}
778 	}
779 	catch(const SQLException& )
780 	{
781         showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
782 	}
783     catch( const Exception& )
784     {
785         DBG_UNHANDLED_EXCEPTION();
786     }
787 }
788 // -----------------------------------------------------------------------------
789 void OTableController::appendPrimaryKey(Reference<XKeysSupplier>& _rxSup,sal_Bool _bNew)
790 {
791 	if(!_rxSup.is())
792 		return; // the database doesn't support keys
793 
794 	OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!");
795     Reference<XIndexAccess> xKeys(_rxSup->getKeys(),UNO_QUERY);
796     Reference<XPropertySet> xProp;
797     const sal_Int32 nCount = xKeys->getCount();
798 	for(sal_Int32 i=0;i< nCount ;++i)
799 	{
800 		xKeys->getByIndex(i) >>= xProp;
801 		sal_Int32 nKeyType = 0;
802 		xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
803 		if(KeyType::PRIMARY == nKeyType)
804 		{
805             return; // primary key already exists after appending a column
806 		}
807 	}
808 	Reference<XDataDescriptorFactory> xKeyFactory(xKeys,UNO_QUERY);
809 	OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!");
810 	if ( !xKeyFactory.is() )
811 		return;
812 	Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY);
813 	OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
814 
815 	Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor();
816 	OSL_ENSURE(xKey.is(),"Key is null!");
817 	xKey->setPropertyValue(PROPERTY_TYPE,makeAny(KeyType::PRIMARY));
818 
819 	Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY);
820 	if(xColSup.is())
821 	{
822 		appendColumns(xColSup,_bNew,sal_True);
823 		Reference<XNameAccess> xColumns = xColSup->getColumns();
824 		if(xColumns->hasElements())
825 			xAppend->appendByDescriptor(xKey);
826 	}
827 }
828 // -----------------------------------------------------------------------------
829 void OTableController::loadData()
830 {
831 	//////////////////////////////////////////////////////////////////////
832 	// Wenn Datenstruktur bereits vorhanden, Struktur leeren
833 	m_vRowList.clear();
834 
835 	::boost::shared_ptr<OTableRow>  pTabEdRow;
836 	Reference< XDatabaseMetaData> xMetaData = getMetaData( );
837 	//////////////////////////////////////////////////////////////////////
838 	// Datenstruktur mit Daten aus DatenDefinitionsObjekt fuellen
839 	if(m_xTable.is() && xMetaData.is())
840 	{
841 		Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY);
842 		OSL_ENSURE(xColSup.is(),"No XColumnsSupplier!");
843 		Reference<XNameAccess> xColumns = xColSup->getColumns();
844 		OFieldDescription* pActFieldDescr = NULL;
845 		String aType;
846 		//////////////////////////////////////////////////////////////////////
847 		// ReadOnly-Flag
848 		// Bei Drop darf keine Zeile editierbar sein.
849 		// Bei Add duerfen nur die leeren Zeilen editierbar sein.
850 		// Bei Add und Drop koennen alle Zeilen editiert werden.
851 		//	sal_Bool bReadOldRow = xMetaData->supportsAlterTableWithAddColumn() && xMetaData->supportsAlterTableWithDropColumn();
852 		sal_Bool bIsAlterAllowed = isAlterAllowed();
853 		Sequence< ::rtl::OUString> aColumns = xColumns->getElementNames();
854 		const ::rtl::OUString* pIter	= aColumns.getConstArray();
855 		const ::rtl::OUString* pEnd		= pIter + aColumns.getLength();
856 
857 		for(;pIter != pEnd;++pIter)
858 		{
859 			Reference<XPropertySet> xColumn;
860 			xColumns->getByName(*pIter) >>= xColumn;
861 			sal_Int32 nType			= 0;
862 			sal_Int32 nScale		= 0;
863 			sal_Int32 nPrecision	= 0;
864 			sal_Int32 nNullable		= 0;
865 			sal_Int32 nFormatKey	= 0;
866 			sal_Int32 nAlign		= 0;
867 
868 			sal_Bool bIsAutoIncrement = false, bIsCurrency = false;
869 			::rtl::OUString sName,sDescription,sTypeName,sHelpText;
870 			Any aControlDefault;
871 
872 			// get the properties from the column
873 			xColumn->getPropertyValue(PROPERTY_NAME)			>>= sName;
874 			xColumn->getPropertyValue(PROPERTY_TYPENAME)		>>= sTypeName;
875 			xColumn->getPropertyValue(PROPERTY_ISNULLABLE)		>>= nNullable;
876 			xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT)	>>= bIsAutoIncrement;
877 			xColumn->getPropertyValue(PROPERTY_ISCURRENCY)		>>= bIsCurrency;
878 			xColumn->getPropertyValue(PROPERTY_TYPE)			>>= nType;
879 			xColumn->getPropertyValue(PROPERTY_SCALE)			>>= nScale;
880 			xColumn->getPropertyValue(PROPERTY_PRECISION)		>>= nPrecision;
881             xColumn->getPropertyValue(PROPERTY_DESCRIPTION)	    >>= sDescription;
882 
883 			if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_HELPTEXT))
884 				xColumn->getPropertyValue(PROPERTY_HELPTEXT)	>>= sHelpText;
885 
886 			if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
887 				aControlDefault = xColumn->getPropertyValue(PROPERTY_CONTROLDEFAULT);
888 			if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_FORMATKEY))
889 				xColumn->getPropertyValue(PROPERTY_FORMATKEY)	>>= nFormatKey;
890 			if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ALIGN))
891 				xColumn->getPropertyValue(PROPERTY_ALIGN)		>>= nAlign;
892 
893 			pTabEdRow.reset(new OTableRow());
894 			pTabEdRow->SetReadOnly(!bIsAlterAllowed);
895 			// search for type
896 			sal_Bool bForce;
897 			::rtl::OUString sCreate(RTL_CONSTASCII_USTRINGPARAM("x"));
898 			TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,sCreate,nPrecision,nScale,bIsAutoIncrement,bForce);
899 			if ( !pTypeInfo.get() )
900 				pTypeInfo = m_pTypeInfo;
901 			pTabEdRow->SetFieldType( pTypeInfo, bForce );
902 
903 			pActFieldDescr = pTabEdRow->GetActFieldDescr();
904 			OSL_ENSURE(pActFieldDescr, "OTableController::loadData: invalid field description generated by the table row!");
905 			if ( pActFieldDescr )
906 			{
907 				pActFieldDescr->SetName(sName);
908 				pActFieldDescr->SetFormatKey(nFormatKey);
909 				//	pActFieldDescr->SetPrimaryKey(pPrimary->GetValue());
910 				pActFieldDescr->SetDescription(sDescription);
911                 pActFieldDescr->SetHelpText(sHelpText);
912 				pActFieldDescr->SetAutoIncrement(bIsAutoIncrement);
913 				pActFieldDescr->SetHorJustify(dbaui::mapTextJustify(nAlign));
914 				pActFieldDescr->SetCurrency(bIsCurrency);
915 
916 				//////////////////////////////////////////////////////////////////////
917 				// Spezielle Daten
918 				pActFieldDescr->SetIsNullable(nNullable);
919 				pActFieldDescr->SetControlDefault(aControlDefault);
920 				pActFieldDescr->SetPrecision(nPrecision);
921 				pActFieldDescr->SetScale(nScale);
922 			}
923 			m_vRowList.push_back( pTabEdRow);
924 		}
925 		// fill the primary  key information
926 		Reference<XNameAccess> xKeyColumns	= getKeyColumns();
927 		if(xKeyColumns.is())
928 		{
929 			Sequence< ::rtl::OUString> aKeyColumns = xKeyColumns->getElementNames();
930 			const ::rtl::OUString* pKeyBegin	= aKeyColumns.getConstArray();
931 			const ::rtl::OUString* pKeyEnd		= pKeyBegin + aKeyColumns.getLength();
932 
933 			for(;pKeyBegin != pKeyEnd;++pKeyBegin)
934 			{
935 				::std::vector< ::boost::shared_ptr<OTableRow> >::iterator rowIter = m_vRowList.begin();
936                 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator rowEnd = m_vRowList.end();
937                 for(;rowIter != rowEnd;++rowIter)
938 				{
939 					if((*rowIter)->GetActFieldDescr()->GetName() == *pKeyBegin)
940 					{
941 						(*rowIter)->SetPrimaryKey(sal_True);
942 						break;
943 					}
944 				}
945 			}
946 		}
947 	}
948 
949 	//////////////////////////////////////////////////////////////////////
950 	// Leere Zeilen fuellen
951 
952 	OTypeInfoMap::iterator aTypeIter = m_aTypeInfo.find(DataType::VARCHAR);
953 	if(aTypeIter == m_aTypeInfo.end())
954 		aTypeIter = m_aTypeInfo.begin();
955 
956 	OSL_ENSURE(aTypeIter != m_aTypeInfo.end(),"We have no type infomation!");
957 
958 	bool bReadRow = !isAddAllowed();
959 	for(sal_Int32 i=m_vRowList.size(); i < NEWCOLS; i++ )
960 	{
961 		pTabEdRow.reset(new OTableRow());
962 		pTabEdRow->SetReadOnly(bReadRow);
963 		m_vRowList.push_back( pTabEdRow);
964 	}
965 }
966 // -----------------------------------------------------------------------------
967 Reference<XNameAccess> OTableController::getKeyColumns() const
968 {
969     return getPrimaryKeyColumns_throw(m_xTable);
970 }
971 // -----------------------------------------------------------------------------
972 sal_Bool OTableController::checkColumns(sal_Bool _bNew) throw(::com::sun::star::sdbc::SQLException)
973 {
974 	sal_Bool bOk = sal_True;
975 	sal_Bool bFoundPKey = sal_False;
976 	Reference< XDatabaseMetaData > xMetaData = getMetaData( );
977     DatabaseMetaData aMetaData( getConnection() );
978 
979 	::comphelper::UStringMixEqual bCase(xMetaData.is() ? xMetaData->supportsMixedCaseQuotedIdentifiers() : sal_True);
980 	::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
981     ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
982 	for(;aIter != aEnd;++aIter)
983 	{
984 		OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr();
985 		if (pFieldDesc && pFieldDesc->GetName().getLength())
986 		{
987 			bFoundPKey |=  (*aIter)->IsPrimaryKey();
988 			// first check for duplicate names
989 			::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter2 = aIter+1;
990 			for(;aIter2 != aEnd;++aIter2)
991 			{
992 				OFieldDescription* pCompareDesc = (*aIter2)->GetActFieldDescr();
993 				if (pCompareDesc && bCase(pCompareDesc->GetName(),pFieldDesc->GetName()))
994 				{
995 					String strMessage = String(ModuleRes(STR_TABLEDESIGN_DUPLICATE_NAME));
996 					strMessage.SearchAndReplaceAscii("$column$", pFieldDesc->GetName());
997 					OSQLWarningBox( getView(), strMessage ).Execute();
998 					return sal_False;
999 				}
1000 			}
1001 		}
1002 	}
1003 	if ( _bNew && !bFoundPKey && aMetaData.supportsPrimaryKeys() )
1004 	{
1005         String sTitle(ModuleRes(STR_TABLEDESIGN_NO_PRIM_KEY_HEAD));
1006 	    String sMsg(ModuleRes(STR_TABLEDESIGN_NO_PRIM_KEY));
1007 	    OSQLMessageBox aBox(getView(), sTitle,sMsg, WB_YES_NO_CANCEL | WB_DEF_YES);
1008 
1009 	    switch ( aBox.Execute() )
1010         {
1011         case RET_YES:
1012 	    {
1013 		    ::boost::shared_ptr<OTableRow>  pNewRow(new OTableRow());
1014 		    TOTypeInfoSP pTypeInfo = ::dbaui::queryPrimaryKeyType(m_aTypeInfo);
1015 		    if ( !pTypeInfo.get() )
1016                 break;
1017 
1018             pNewRow->SetFieldType( pTypeInfo );
1019 		    OFieldDescription* pActFieldDescr = pNewRow->GetActFieldDescr();
1020 
1021 		    pActFieldDescr->SetAutoIncrement(sal_False); // #95927# pTypeInfo->bAutoIncrement
1022 		    pActFieldDescr->SetIsNullable(ColumnValue::NO_NULLS);
1023 
1024 		    pActFieldDescr->SetName( createUniqueName(::rtl::OUString::createFromAscii("ID") ));
1025 		    pActFieldDescr->SetPrimaryKey( sal_True );
1026 		    m_vRowList.insert(m_vRowList.begin(),pNewRow);
1027 
1028 		    static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->Invalidate();
1029 		    static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->RowInserted(0);
1030 	    }
1031         break;
1032         case RET_CANCEL:
1033             bOk = sal_False;
1034             break;
1035         }
1036 	}
1037 	return bOk;
1038 }
1039 // -----------------------------------------------------------------------------
1040 void OTableController::alterColumns()
1041 {
1042 	Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY_THROW);
1043 	OSL_ENSURE(xColSup.is(),"What happen here?!");
1044 
1045 	Reference<XNameAccess> xColumns = xColSup->getColumns();
1046 	Reference<XIndexAccess> xIdxColumns(xColumns,UNO_QUERY_THROW);
1047 	OSL_ENSURE(xColumns.is(),"No columns");
1048     if ( !xColumns.is() )
1049         return;
1050 	Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY);	// can be null
1051 
1052 	sal_Int32 nColumnCount = xIdxColumns->getCount();
1053 	Reference<XDrop> xDrop(xColumns,UNO_QUERY);			// can be null
1054 	Reference<XAppend> xAppend(xColumns,UNO_QUERY);		// can be null
1055 	Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); // can be null
1056 
1057 	sal_Bool bReload = sal_False; // refresh the data
1058 
1059 	// contains all columns names which are already handled those which are not in the list will be deleted
1060 	Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1061 
1062 	::std::map< ::rtl::OUString,sal_Bool,::comphelper::UStringMixLess> aColumns(xMetaData.is() ? (xMetaData->supportsMixedCaseQuotedIdentifiers() ? true : false): sal_True);
1063 	::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin();
1064 	::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end();
1065 	// first look for columns where something other than the name changed
1066     sal_Int32 nPos = 0;
1067 	for(;aIter != aEnd;++aIter,++nPos)
1068 	{
1069 		OSL_ENSURE(*aIter,"OTableRow is null!");
1070 		OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1071 		if ( !pField )
1072 			continue;
1073 		if ( (*aIter)->IsReadOnly() )
1074 		{
1075 			aColumns[pField->GetName()] = sal_True;
1076 			continue;
1077 		}
1078 
1079 		Reference<XPropertySet> xColumn;
1080 		if ( xColumns->hasByName(pField->GetName()) )
1081 		{
1082 			aColumns[pField->GetName()] = sal_True;
1083 			xColumns->getByName(pField->GetName()) >>= xColumn;
1084 			OSL_ENSURE(xColumn.is(),"Column is null!");
1085 
1086 			sal_Int32 nType=0,nPrecision=0,nScale=0,nNullable=0;
1087 			sal_Bool bAutoIncrement = false;
1088 			::rtl::OUString sTypeName,sDescription;
1089 
1090 			xColumn->getPropertyValue(PROPERTY_TYPE)			>>= nType;
1091 			xColumn->getPropertyValue(PROPERTY_PRECISION)		>>= nPrecision;
1092 			xColumn->getPropertyValue(PROPERTY_SCALE)			>>= nScale;
1093 			xColumn->getPropertyValue(PROPERTY_ISNULLABLE)		>>= nNullable;
1094 			xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bAutoIncrement;
1095             xColumn->getPropertyValue(PROPERTY_DESCRIPTION)	    >>= sDescription;
1096 
1097             try { xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; }
1098             catch( const Exception& )
1099             {
1100             	OSL_ENSURE( sal_False, "no TypeName property?!" );
1101                 // since this is a last minute fix for #i41785#, I want to be on the safe side,
1102                 // and catch errors here as early as possible (instead of the whole process of altering
1103                 // the columns failing)
1104                 // Normally, sdbcx::Column objects are expected to have a TypeName property
1105             }
1106 
1107 			//	xColumn->getPropertyValue(PROPERTY_ISCURRENCY,::cppu::bool2any(pField->IsCurrency()));
1108 			// check if something changed
1109 			if((nType != pField->GetType()					||
1110                 sTypeName != pField->GetTypeName()         ||
1111                 (nPrecision != pField->GetPrecision() && nPrecision )		||
1112 				nScale != pField->GetScale()				||
1113 				nNullable != pField->GetIsNullable()		||
1114                 sDescription != pField->GetDescription()		||
1115 				bAutoIncrement != pField->IsAutoIncrement())&&
1116 				xColumnFactory.is())
1117 			{
1118 				Reference<XPropertySet> xNewColumn;
1119 				xNewColumn = xColumnFactory->createDataDescriptor();
1120 				::dbaui::setColumnProperties(xNewColumn,pField);
1121 				// first try to alter the column
1122 				sal_Bool bNotOk = sal_False;
1123 				try
1124 				{
1125 					// first try if we can alter the column
1126 					if(xAlter.is())
1127 						xAlter->alterColumnByName(pField->GetName(),xNewColumn);
1128 				}
1129 				catch(const SQLException&)
1130 				{
1131 					if(xDrop.is() && xAppend.is())
1132 					{
1133 						String aMessage( ModuleRes( STR_TABLEDESIGN_ALTER_ERROR ) );
1134 						aMessage.SearchAndReplaceAscii( "$column$", pField->GetName() );
1135 
1136                         SQLExceptionInfo aError( ::cppu::getCaughtException() );
1137 						OSQLWarningBox aMsg( getView(), aMessage, WB_YES_NO | WB_DEF_YES , &aError );
1138 						bNotOk = aMsg.Execute() == RET_YES;
1139 					}
1140 					else
1141 						throw;
1142 				}
1143 				// if something went wrong or we can't alter columns
1144 				// drop and append a new one
1145 				if((!xAlter.is() || bNotOk) && xDrop.is() && xAppend.is())
1146 				{
1147 					xDrop->dropByName(pField->GetName());
1148 					try
1149 					{
1150 						xAppend->appendByDescriptor(xNewColumn);
1151 					}
1152 					catch(const SQLException&)
1153 					{ // an error occured so we try to reactivate the old one
1154 						xAppend->appendByDescriptor(xColumn);
1155 						throw;
1156 					}
1157 				}
1158 				// exceptions are caught outside
1159 				xNewColumn = NULL;
1160 				if(xColumns->hasByName(pField->GetName()))
1161 					xColumns->getByName(pField->GetName()) >>= xColumn;
1162 				bReload = sal_True;
1163 			}
1164 
1165 
1166 		}
1167 		else if(xColumnFactory.is() && xAlter.is() && nPos < nColumnCount)
1168 		{ // we can't find the column so we could try it with the index before we drop and append a new column
1169 			try
1170 			{
1171 				Reference<XPropertySet> xNewColumn;
1172 				xNewColumn = xColumnFactory->createDataDescriptor();
1173 				::dbaui::setColumnProperties(xNewColumn,pField);
1174 				xAlter->alterColumnByIndex(nPos,xNewColumn);
1175 				if(xColumns->hasByName(pField->GetName()))
1176 				{	// ask for the append by name
1177 					aColumns[pField->GetName()] = sal_True;
1178 					xColumns->getByName(pField->GetName()) >>= xColumn;
1179 					if(xColumn.is())
1180 						pField->copyColumnSettingsTo(xColumn);
1181 				}
1182 				else
1183 				{
1184 					OSL_ENSURE(sal_False, "OTableController::alterColumns: invalid column (2)!");
1185 				}
1186 			}
1187 			catch(const SQLException&)
1188 			{ // we couldn't alter the column so we have to add new columns
1189 				bReload = sal_True;
1190 				if(xDrop.is() && xAppend.is())
1191 				{
1192 					String aMessage(ModuleRes(STR_TABLEDESIGN_ALTER_ERROR));
1193 					aMessage.SearchAndReplaceAscii("$column$",pField->GetName());
1194 					OSQLWarningBox aMsg( getView(), aMessage, WB_YES_NO | WB_DEF_YES );
1195 					if ( aMsg.Execute() != RET_YES )
1196 					{
1197                         Reference<XPropertySet> xNewColumn(xIdxColumns->getByIndex(nPos),UNO_QUERY_THROW);
1198                         ::rtl::OUString sName;
1199                         xNewColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
1200                         aColumns[sName] = sal_True;
1201                         aColumns[pField->GetName()] = sal_True;
1202 						continue;
1203 					}
1204 				}
1205 				else
1206 					throw;
1207 			}
1208 		}
1209 		else
1210 			bReload = sal_True;
1211 	} // for(sal_Int32 nPos = 0;aIter != aEnd;++aIter,++nPos)
1212     // alter column settings
1213     aIter = m_vRowList.begin();
1214 
1215 	// first look for columns where something other than the name changed
1216 	for(nPos = 0;aIter != aEnd;++aIter,++nPos)
1217 	{
1218 		OSL_ENSURE(*aIter,"OTableRow is null!");
1219 		OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1220 		if ( !pField )
1221 			continue;
1222 		if ( (*aIter)->IsReadOnly() )
1223 		{
1224 			aColumns[pField->GetName()] = sal_True;
1225 			continue;
1226 		}
1227 
1228 		Reference<XPropertySet> xColumn;
1229 		if ( xColumns->hasByName(pField->GetName()) )
1230 		{
1231 			xColumns->getByName(pField->GetName()) >>= xColumn;
1232             Reference<XPropertySetInfo> xInfo = xColumn->getPropertySetInfo();
1233             if ( xInfo->hasPropertyByName(PROPERTY_HELPTEXT) )
1234 				xColumn->setPropertyValue(PROPERTY_HELPTEXT,makeAny(pField->GetHelpText()));
1235 
1236 			if(xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
1237 				xColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,pField->GetControlDefault());
1238 			if(xInfo->hasPropertyByName(PROPERTY_FORMATKEY))
1239 				xColumn->setPropertyValue(PROPERTY_FORMATKEY,makeAny(pField->GetFormatKey()));
1240 			if(xInfo->hasPropertyByName(PROPERTY_ALIGN))
1241 				xColumn->setPropertyValue(PROPERTY_ALIGN,makeAny(dbaui::mapTextAllign(pField->GetHorJustify())));
1242         } // if ( xColumns->hasByName(pField->GetName()) )
1243     }
1244 	// second drop all columns which could be found by name
1245 	Reference<XNameAccess> xKeyColumns	= getKeyColumns();
1246 	// now we have to look for the columns who could be deleted
1247 	if ( xDrop.is() )
1248 	{
1249 		Sequence< ::rtl::OUString> aColumnNames = xColumns->getElementNames();
1250 		const ::rtl::OUString* pIter = aColumnNames.getConstArray();
1251 		const ::rtl::OUString* pEnd = pIter + aColumnNames.getLength();
1252 		for(;pIter != pEnd;++pIter)
1253 		{
1254 			if(aColumns.find(*pIter) == aColumns.end()) // found a column to delete
1255 			{
1256 				if(xKeyColumns.is() && xKeyColumns->hasByName(*pIter)) // check if this column is a member of the primary key
1257 				{
1258 					String aMsgT(ModuleRes(STR_TBL_COLUMN_IS_KEYCOLUMN));
1259 					aMsgT.SearchAndReplaceAscii("$column$",*pIter);
1260 					String aTitle(ModuleRes(STR_TBL_COLUMN_IS_KEYCOLUMN_TITLE));
1261 					OSQLMessageBox aMsg(getView(),aTitle,aMsgT,WB_YES_NO| WB_DEF_YES);
1262 					if(aMsg.Execute() == RET_YES)
1263 					{
1264 						xKeyColumns = NULL;
1265 						dropPrimaryKey();
1266 					}
1267 					else
1268 					{
1269 						bReload = sal_True;
1270 						continue;
1271 					}
1272 				}
1273                 try
1274                 {
1275                     xDrop->dropByName(*pIter);
1276 			    }
1277                 catch (const SQLException&)
1278                 {
1279                     String sError( ModuleRes( STR_TABLEDESIGN_COULD_NOT_DROP_COL ) );
1280                     sError.SearchAndReplaceAscii( "$column$", *pIter );
1281 
1282                     SQLException aNewException;
1283                     aNewException.Message = sError;
1284                     aNewException.SQLState = ::rtl::OUString::createFromAscii( "S1000" );
1285                     aNewException.NextException = ::cppu::getCaughtException();
1286 
1287                     throw aNewException;
1288                 }
1289             }
1290         }
1291 	}
1292 
1293 	// third append the new columns
1294 	aIter = m_vRowList.begin();
1295 	for(;aIter != aEnd;++aIter)
1296 	{
1297 		OSL_ENSURE(*aIter,"OTableRow is null!");
1298 		OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1299 		if ( !pField || (*aIter)->IsReadOnly() || aColumns.find(pField->GetName()) != aColumns.end() )
1300 			continue;
1301 
1302 		Reference<XPropertySet> xColumn;
1303 		if(!xColumns->hasByName(pField->GetName()))
1304 		{
1305 			if(xColumnFactory.is() && xAppend.is())
1306 			{// column not found by its name so we assume it is new
1307 				// Column is new
1308 				xColumn = xColumnFactory->createDataDescriptor();
1309 				::dbaui::setColumnProperties(xColumn,pField);
1310 				xAppend->appendByDescriptor(xColumn);
1311 				if(xColumns->hasByName(pField->GetName()))
1312 				{	// ask for the append by name
1313 					aColumns[pField->GetName()] = sal_True;
1314 					xColumns->getByName(pField->GetName()) >>= xColumn;
1315 					if(xColumn.is())
1316 						pField->copyColumnSettingsTo(xColumn);
1317 				}
1318 				else
1319 				{
1320 					OSL_ENSURE(sal_False, "OTableController::alterColumns: invalid column!");
1321 				}
1322 			}
1323 		}
1324 	}
1325 
1326 
1327 	// check if we have to do something with the primary key
1328 	sal_Bool bNeedDropKey = sal_False;
1329 	sal_Bool bNeedAppendKey = sal_False;
1330 	if ( xKeyColumns.is() )
1331 	{
1332 		aIter = m_vRowList.begin();
1333 		for(;aIter != aEnd;++aIter)
1334 		{
1335 			OSL_ENSURE(*aIter,"OTableRow is null!");
1336 			OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1337 			if ( !pField )
1338 				continue;
1339 
1340 			if	(	pField->IsPrimaryKey()
1341 				&&	!xKeyColumns->hasByName( pField->GetName() )
1342 				)
1343 			{	// new primary key column inserted which isn't already in the columns selection
1344 				bNeedDropKey = bNeedAppendKey = sal_True;
1345 				break;
1346 			}
1347 			else if	(	!pField->IsPrimaryKey()
1348 					&&	xKeyColumns->hasByName( pField->GetName() )
1349 					)
1350 			{	// found a column which currently is in the primary key, but is marked not to be anymore
1351 				bNeedDropKey = bNeedAppendKey = sal_True;
1352 				break;
1353 			}
1354 		}
1355 	}
1356 	else
1357 	{	// no primary key available so we check if we should create one
1358 		bNeedAppendKey = sal_True;
1359 	}
1360 
1361 	if ( bNeedDropKey && xKeyColumns.is() && xKeyColumns->getElementNames().getLength() )
1362 		dropPrimaryKey();
1363 
1364 	if ( bNeedAppendKey )
1365 	{
1366 		Reference< XKeysSupplier > xKeySup( m_xTable, UNO_QUERY );
1367 		appendPrimaryKey( xKeySup ,sal_False);
1368 	}
1369 
1370 	reSyncRows();
1371 
1372 	if ( bReload )
1373 		reload();
1374 }
1375 // -----------------------------------------------------------------------------
1376 void OTableController::dropPrimaryKey()
1377 {
1378     SQLExceptionInfo aInfo;
1379     try
1380     {
1381 	    Reference<XKeysSupplier> xKeySup(m_xTable,UNO_QUERY);
1382 	    Reference<XIndexAccess> xKeys;
1383 	    if(xKeySup.is())
1384 		    xKeys = xKeySup->getKeys();
1385 
1386 	    if(xKeys.is())
1387 	    {
1388 		    Reference<XPropertySet> xProp;
1389 		    for(sal_Int32 i=0;i< xKeys->getCount();++i)
1390 		    {
1391                 xProp.set(xKeys->getByIndex(i),UNO_QUERY);
1392 			    sal_Int32 nKeyType = 0;
1393 			    xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
1394 			    if(KeyType::PRIMARY == nKeyType)
1395 			    {
1396 				    Reference<XDrop> xDrop(xKeys,UNO_QUERY);
1397 				    xDrop->dropByIndex(i); // delete the key
1398 				    break;
1399 			    }
1400 		    }
1401 	    }
1402     }
1403     catch(const SQLContext& e)
1404 	{
1405 		aInfo = SQLExceptionInfo(e);
1406 	}
1407 	catch(const SQLWarning& e)
1408 	{
1409 		aInfo = SQLExceptionInfo(e);
1410 	}
1411 	catch(const SQLException& e)
1412 	{
1413 		aInfo = SQLExceptionInfo(e);
1414 	}
1415     catch( const Exception& )
1416     {
1417         DBG_UNHANDLED_EXCEPTION();
1418     }
1419 
1420 	showError(aInfo);
1421 }
1422 // -----------------------------------------------------------------------------
1423 void OTableController::assignTable()
1424 {
1425 	::rtl::OUString sComposedName;
1426 	// get the table
1427 	if(m_sName.getLength())
1428 	{
1429 		Reference<XNameAccess> xNameAccess;
1430 		Reference<XTablesSupplier> xSup(getConnection(),UNO_QUERY);
1431 		if(xSup.is())
1432 		{
1433 			xNameAccess = xSup->getTables();
1434 			OSL_ENSURE(xNameAccess.is(),"no nameaccess for the queries!");
1435 
1436 			Reference<XPropertySet> xProp;
1437 			if(xNameAccess->hasByName(m_sName) && ::cppu::extractInterface(xProp,xNameAccess->getByName(m_sName)) && xProp.is())
1438 			{
1439 				m_xTable = xProp;
1440 				startTableListening();
1441 
1442 				// check if we set the table editable
1443 				Reference<XDatabaseMetaData> xMeta = getConnection()->getMetaData();
1444 				setEditable( xMeta.is() && !xMeta->isReadOnly() && (isAlterAllowed() || isDropAllowed() || isAddAllowed()) );
1445 				if(!isEditable())
1446 				{
1447                     ::std::for_each(m_vRowList.begin(),m_vRowList.end(),boost::bind( &OTableRow::SetReadOnly, _1, boost::cref( sal_True )));
1448 				}
1449 				m_bNew = sal_False;
1450 				// be notified when the table is in disposing
1451 				InvalidateAll();
1452 			}
1453 		}
1454 	}
1455 	//updateTitle();
1456 }
1457 // -----------------------------------------------------------------------------
1458 sal_Bool OTableController::isAddAllowed() const
1459 {
1460 	Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY);
1461 	sal_Bool bAddAllowed = !m_xTable.is();
1462 	if(xColsSup.is())
1463 		bAddAllowed = Reference<XAppend>(xColsSup->getColumns(),UNO_QUERY).is();
1464 
1465     try
1466     {
1467 	    Reference< XDatabaseMetaData > xMetaData = getMetaData( );
1468 	    bAddAllowed = bAddAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithAddColumn());
1469     }
1470     catch(Exception&)
1471     {
1472         DBG_UNHANDLED_EXCEPTION();
1473         bAddAllowed = sal_False;
1474     }
1475 
1476 	return bAddAllowed;
1477 }
1478 // -----------------------------------------------------------------------------
1479 sal_Bool OTableController::isDropAllowed() const
1480 {
1481 	Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY);
1482 	sal_Bool bDropAllowed = !m_xTable.is();
1483 	if(xColsSup.is())
1484 	{
1485 		Reference<XNameAccess> xNameAccess = xColsSup->getColumns();
1486 		bDropAllowed = Reference<XDrop>(xNameAccess,UNO_QUERY).is() && xNameAccess->hasElements();
1487 	}
1488 
1489 	Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1490 	bDropAllowed = bDropAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithDropColumn());
1491 
1492 	return bDropAllowed;
1493 }
1494 // -----------------------------------------------------------------------------
1495 sal_Bool OTableController::isAlterAllowed() const
1496 {
1497 	sal_Bool bAllowed(!m_xTable.is() || Reference<XAlterTable>(m_xTable,UNO_QUERY).is());
1498 	return bAllowed;
1499 }
1500 // -----------------------------------------------------------------------------
1501 void OTableController::reSyncRows()
1502 {
1503 	sal_Bool bAlterAllowed	= isAlterAllowed();
1504 	sal_Bool bAddAllowed	= isAddAllowed();
1505 	::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin();
1506     ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end();
1507 	for(;aIter != aEnd;++aIter)
1508 	{
1509 		OSL_ENSURE(*aIter,"OTableRow is null!");
1510 		OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1511 		if ( pField )
1512 			(*aIter)->SetReadOnly(!bAlterAllowed);
1513 		else
1514 			(*aIter)->SetReadOnly(!bAddAllowed);
1515 
1516 	}
1517 	static_cast<OTableDesignView*>(getView())->reSync();	// show the windows and fill with our informations
1518 
1519 	ClearUndoManager();
1520 	setModified(sal_False);		// and we are not modified yet
1521 }
1522 // -----------------------------------------------------------------------------
1523 ::rtl::OUString OTableController::createUniqueName(const ::rtl::OUString& _rName)
1524 {
1525 	::rtl::OUString sName = _rName;
1526 	Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1527 
1528 	::comphelper::UStringMixEqual bCase(xMetaData.is() ? xMetaData->supportsMixedCaseQuotedIdentifiers() : sal_True);
1529 
1530 	::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
1531     ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
1532 	for(sal_Int32 i=0;aIter != aEnd;++aIter)
1533 	{
1534 		OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr();
1535 		if (pFieldDesc && pFieldDesc->GetName().getLength() && bCase(sName,pFieldDesc->GetName()))
1536 		{ // found a second name of _rName so we need another
1537 			sName = _rName + ::rtl::OUString::valueOf(++i);
1538 			aIter = m_vRowList.begin(); // and retry
1539 		}
1540 	}
1541 	return sName;
1542 }
1543 // -----------------------------------------------------------------------------
1544 ::rtl::OUString OTableController::getPrivateTitle() const
1545 {
1546     ::rtl::OUString sTitle;
1547 	try
1548 	{
1549 		// get the table
1550 		if ( m_sName.getLength() && getConnection().is() )
1551 		{
1552 			if ( m_xTable.is() )
1553 				sTitle = ::dbtools::composeTableName( getConnection()->getMetaData(), m_xTable, ::dbtools::eInDataManipulation, false, false, false );
1554 			else
1555 				sTitle = m_sName;
1556 		}
1557 		if ( !sTitle.getLength() )
1558 		{
1559             String aName = String(ModuleRes(STR_TBL_TITLE));
1560 			sTitle = aName.GetToken(0,' ');
1561             sTitle += ::rtl::OUString::valueOf(getCurrentStartNumber());
1562 		}
1563 	}
1564 	catch( const Exception& )
1565 	{
1566         DBG_UNHANDLED_EXCEPTION();
1567 	}
1568     return sTitle;
1569 }
1570 // -----------------------------------------------------------------------------
1571 void OTableController::reload()
1572 {
1573 	loadData();					// fill the column information form the table
1574 	static_cast<OTableDesignView*>(getView())->reSync();	// show the windows and fill with our informations
1575 	ClearUndoManager();
1576 	setModified(sal_False);		// and we are not modified yet
1577 	static_cast<OTableDesignView*>(getView())->Invalidate();
1578 }
1579 // -----------------------------------------------------------------------------
1580 sal_Int32 OTableController::getFirstEmptyRowPosition()
1581 {
1582 	sal_Int32 nRet = -1;
1583 	::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
1584 	::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
1585 	for(;aIter != aEnd;++aIter)
1586 	{
1587 		if ( !*aIter || !(*aIter)->GetActFieldDescr() || !(*aIter)->GetActFieldDescr()->GetName().getLength() )
1588 		{
1589 			nRet = aIter - m_vRowList.begin();
1590 			break;
1591 		}
1592 	}
1593     if ( nRet == -1 )
1594     {
1595         bool bReadRow = !isAddAllowed();
1596 	    ::boost::shared_ptr<OTableRow> pTabEdRow(new OTableRow());
1597 	    pTabEdRow->SetReadOnly(bReadRow);
1598         nRet = m_vRowList.size();
1599 	    m_vRowList.push_back( pTabEdRow);
1600     }
1601 	return nRet;
1602 }
1603 // -----------------------------------------------------------------------------
1604 bool OTableController::isAutoIncrementPrimaryKey() const
1605 {
1606     return getSdbMetaData().isAutoIncrementPrimaryKey();
1607 }
1608 // -----------------------------------------------------------------------------
1609