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