fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / dbaccess / source / ui / tabledesign / TableController.cxx
blob8c7bb1fe3b465993683a62bcb71c03bbe0ccb234
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "FieldDescriptions.hxx"
21 #include "TEditControl.hxx"
22 #include "TableController.hxx"
23 #include "TableDesignView.hxx"
24 #include "TableRow.hxx"
25 #include "TypeInfo.hxx"
26 #include "UITools.hxx"
27 #include "browserids.hxx"
28 #include "dbu_reghelper.hxx"
29 #include "dbu_tbl.hrc"
30 #include "dbustrings.hrc"
31 #include "defaultobjectnamecheck.hxx"
32 #include "dlgsave.hxx"
33 #include "dsmeta.hxx"
34 #include "indexdialog.hxx"
35 #include "sqlmessage.hxx"
36 #include "uiservices.hxx"
38 #include <com/sun/star/container/XChild.hpp>
39 #include <com/sun/star/container/XNameContainer.hpp>
40 #include <com/sun/star/frame/FrameSearchFlag.hpp>
41 #include <com/sun/star/frame/XTitleChangeListener.hpp>
42 #include <com/sun/star/frame/XUntitledNumbers.hpp>
43 #include <com/sun/star/io/XActiveDataSink.hpp>
44 #include <com/sun/star/io/XActiveDataSource.hpp>
45 #include <com/sun/star/sdb/CommandType.hpp>
46 #include <com/sun/star/sdb/SQLContext.hpp>
47 #include <com/sun/star/sdbc/ColumnValue.hpp>
48 #include <com/sun/star/sdbc/SQLWarning.hpp>
49 #include <com/sun/star/sdbc/XRow.hpp>
50 #include <com/sun/star/sdbcx/KeyType.hpp>
51 #include <com/sun/star/sdbcx/XAlterTable.hpp>
52 #include <com/sun/star/sdbcx/XAppend.hpp>
53 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
54 #include <com/sun/star/sdbcx/XDrop.hpp>
55 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
56 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
57 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
59 #include <comphelper/processfactory.hxx>
60 #include <comphelper/streamsection.hxx>
61 #include <comphelper/types.hxx>
62 #include <connectivity/dbexception.hxx>
63 #include <connectivity/dbtools.hxx>
64 #include <connectivity/dbmetadata.hxx>
65 #include <cppuhelper/exc_hlp.hxx>
66 #include <sfx2/sfxsids.hrc>
67 #include <tools/diagnose_ex.h>
68 #include <vcl/layout.hxx>
70 #include <boost/mem_fn.hpp>
71 #include <boost/bind.hpp>
73 #include <algorithm>
74 #include <functional>
76 extern "C" void SAL_CALL createRegistryInfo_OTableControl()
78 static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OTableController > aAutoRegistration;
81 using namespace ::com::sun::star;
82 using namespace ::com::sun::star::uno;
83 using namespace ::com::sun::star::io;
84 using namespace ::com::sun::star::beans;
85 using namespace ::com::sun::star::frame;
86 using namespace ::com::sun::star::lang;
87 using namespace ::com::sun::star::container;
88 using namespace ::com::sun::star::sdbcx;
89 using namespace ::com::sun::star::sdbc;
90 using namespace ::com::sun::star::sdb;
91 using namespace ::com::sun::star::ui;
92 using namespace ::com::sun::star::util;
93 using namespace ::dbtools;
94 using namespace ::dbaui;
95 using namespace ::comphelper;
97 // number of columns when creating it from scratch
98 #define NEWCOLS 128
100 namespace
102 void dropTable(const Reference<XNameAccess>& _rxTable,const OUString& _sTableName)
104 if ( _rxTable->hasByName(_sTableName) )
106 Reference<XDrop> xNameCont(_rxTable,UNO_QUERY);
107 OSL_ENSURE(xNameCont.is(),"No drop interface for tables!");
108 if ( xNameCont.is() )
109 xNameCont->dropByName(_sTableName);
114 OUString SAL_CALL OTableController::getImplementationName() throw( RuntimeException, std::exception )
116 return getImplementationName_Static();
119 OUString OTableController::getImplementationName_Static() throw( RuntimeException )
121 return OUString("org.openoffice.comp.dbu.OTableDesign");
124 Sequence< OUString> OTableController::getSupportedServiceNames_Static() throw( RuntimeException )
126 Sequence< OUString> aSupported(1);
127 aSupported[0] = "com.sun.star.sdb.TableDesign";
128 return aSupported;
131 Sequence< OUString> SAL_CALL OTableController::getSupportedServiceNames() throw(RuntimeException, std::exception)
133 return getSupportedServiceNames_Static();
136 Reference< XInterface > SAL_CALL OTableController::Create(const Reference<XMultiServiceFactory >& _rxFactory)
138 return *(new OTableController(comphelper::getComponentContext(_rxFactory)));
141 OTableController::OTableController(const Reference< XComponentContext >& _rM) : OTableController_BASE(_rM)
142 ,m_sTypeNames(ModuleRes(STR_TABLEDESIGN_DBFIELDTYPES))
143 ,m_pTypeInfo()
144 ,m_bAllowAutoIncrementValue(false)
145 ,m_bNew(true)
148 InvalidateAll();
149 m_pTypeInfo = TOTypeInfoSP(new OTypeInfo());
150 m_pTypeInfo->aUIName = m_sTypeNames.getToken(TYPE_OTHER, ';');
153 OTableController::~OTableController()
155 m_aTypeInfoIndex.clear();
156 m_aTypeInfo.clear();
160 void OTableController::startTableListening()
162 Reference< XComponent > xComponent(m_xTable, UNO_QUERY);
163 if (xComponent.is())
164 xComponent->addEventListener(static_cast<XModifyListener*>(this));
167 void OTableController::stopTableListening()
169 Reference< XComponent > xComponent(m_xTable, UNO_QUERY);
170 if (xComponent.is())
171 xComponent->removeEventListener(static_cast<XModifyListener*>(this));
174 void OTableController::disposing()
176 OTableController_BASE::disposing();
177 clearView();
179 m_vRowList.clear();
182 FeatureState OTableController::GetState(sal_uInt16 _nId) const
184 FeatureState aReturn;
185 // disabled automatically
187 switch (_nId)
189 case ID_BROWSER_CLOSE:
190 aReturn.bEnabled = true;
191 break;
192 case ID_BROWSER_EDITDOC:
193 aReturn.bChecked = isEditable();
194 aReturn.bEnabled = m_bNew || isEditable();// the editable flag is set through this one -> || isAddAllowed() || isDropAllowed() || isAlterAllowed();
195 break;
196 case ID_BROWSER_SAVEDOC:
197 aReturn.bEnabled = impl_isModified();
198 if ( aReturn.bEnabled )
200 aReturn.bEnabled = ::std::any_of(m_vRowList.begin(),m_vRowList.end(),
201 ::boost::mem_fn(&OTableRow::isValid));
203 break;
204 case ID_BROWSER_SAVEASDOC:
205 aReturn.bEnabled = isConnected() && isEditable();
206 if ( aReturn.bEnabled )
208 aReturn.bEnabled = ::std::any_of(m_vRowList.begin(),m_vRowList.end(),
209 ::boost::mem_fn(&OTableRow::isValid));
211 break;
213 case ID_BROWSER_CUT:
214 aReturn.bEnabled = isEditable() && m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isCutAllowed();
215 break;
216 case ID_BROWSER_COPY:
217 aReturn.bEnabled = m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isCopyAllowed();
218 break;
219 case ID_BROWSER_PASTE:
220 aReturn.bEnabled = isEditable() && m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isPasteAllowed();
221 break;
222 case SID_INDEXDESIGN:
223 aReturn.bEnabled =
224 ( ( ((!m_bNew && impl_isModified()) || impl_isModified())
225 || Reference< XIndexesSupplier >(m_xTable, UNO_QUERY).is()
227 && isConnected()
229 if ( aReturn.bEnabled )
231 aReturn.bEnabled = ::std::any_of(m_vRowList.begin(),m_vRowList.end(),
232 ::boost::mem_fn(&OTableRow::isValid));
234 break;
235 default:
236 aReturn = OTableController_BASE::GetState(_nId);
238 return aReturn;
241 void OTableController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
243 switch(_nId)
245 case ID_BROWSER_EDITDOC:
246 setEditable(!isEditable());
247 static_cast<OTableDesignView*>(getView())->setReadOnly(!isEditable());
248 InvalidateFeature(ID_BROWSER_PASTE);
249 InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
250 break;
251 case ID_BROWSER_SAVEASDOC:
252 doSaveDoc(true);
253 break;
254 case ID_BROWSER_SAVEDOC:
255 static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->SaveCurRow();
256 doSaveDoc(false);
257 break;
258 case ID_BROWSER_CUT:
259 static_cast<OTableDesignView*>(getView())->cut();
260 break;
261 case ID_BROWSER_COPY:
262 static_cast<OTableDesignView*>(getView())->copy();
263 break;
264 case ID_BROWSER_PASTE:
265 static_cast<OTableDesignView*>(getView())->paste();
266 break;
267 case SID_INDEXDESIGN:
268 doEditIndexes();
269 break;
270 default:
271 OTableController_BASE::Execute(_nId,aArgs);
273 InvalidateFeature(_nId);
276 bool OTableController::doSaveDoc(bool _bSaveAs)
278 if (!isConnected())
279 reconnect(true); // ask the user for a new connection
280 Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY);
282 if (!xTablesSup.is())
284 OUString aMessage(ModuleRes(STR_TABLEDESIGN_CONNECTION_MISSING));
285 ScopedVclPtrInstance<OSQLWarningBox>(getView(), aMessage )->Execute();
286 return false;
289 // check if a column exists
290 // TODO
292 Reference<XNameAccess> xTables;
293 OUString sCatalog, sSchema;
295 bool bNew = m_sName.isEmpty();
296 bNew = bNew || m_bNew || _bSaveAs;
300 xTables = xTablesSup->getTables();
301 OSL_ENSURE(xTables.is(),"The tables can't be null!");
302 bNew = bNew || (xTables.is() && !xTables->hasByName(m_sName));
304 // first we need a name for our query so ask the user
305 if(bNew)
307 OUString aDefaultName;
308 if (_bSaveAs && !bNew)
309 aDefaultName = m_sName;
310 else
312 OUString aName = ModuleRes(STR_TBL_TITLE);
313 aDefaultName = aName.getToken(0,' ');
314 aDefaultName = ::dbtools::createUniqueName(xTables,aDefaultName);
317 DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::TABLE );
318 ScopedVclPtrInstance< OSaveAsDlg > aDlg( getView(), CommandType::TABLE, getORB(), getConnection(), aDefaultName, aNameChecker );
319 if ( aDlg->Execute() != RET_OK )
320 return false;
322 m_sName = aDlg->getName();
323 sCatalog = aDlg->getCatalog();
324 sSchema = aDlg->getSchema();
327 // did we get a name
328 if(m_sName.isEmpty())
329 return false;
331 catch(Exception&)
333 OSL_FAIL("OTableController::doSaveDoc: nothing is expected to happen here!");
336 bool bAlter = false;
337 bool bError = false;
338 SQLExceptionInfo aInfo;
341 // check the columns for double names
342 if(!checkColumns(bNew || !xTables->hasByName(m_sName)))
344 return false;
347 Reference<XPropertySet> xTable;
348 if(bNew || !xTables->hasByName(m_sName)) // just to make sure the table already exists
350 dropTable(xTables,m_sName);
352 Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY);
353 OSL_ENSURE(xFact.is(),"OTableController::doSaveDoc: No XDataDescriptorFactory available!");
354 xTable = xFact->createDataDescriptor();
355 OSL_ENSURE(xTable.is(),"OTableController::doSaveDoc: Create query failed!");
356 // to set the name is only allowed when the query is new
357 xTable->setPropertyValue(PROPERTY_CATALOGNAME,makeAny(sCatalog));
358 xTable->setPropertyValue(PROPERTY_SCHEMANAME,makeAny(sSchema));
359 xTable->setPropertyValue(PROPERTY_NAME,makeAny(m_sName));
361 // now append the columns
362 Reference<XColumnsSupplier> xColSup(xTable,UNO_QUERY);
363 appendColumns(xColSup,bNew);
364 // now append the primary key
365 Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY);
366 appendPrimaryKey(xKeySup,bNew);
368 // now set the properties
369 if(bNew)
371 Reference<XAppend> xAppend(xTables,UNO_QUERY);
372 OSL_ENSURE(xAppend.is(),"OTableController::doSaveDoc: No XAppend Interface!");
373 xAppend->appendByDescriptor(xTable);
375 assignTable();
376 if(!m_xTable.is()) // correct name and try again
378 // it can be that someone inserted new data for us
379 m_sName = ::dbtools::composeTableName( getConnection()->getMetaData(), xTable, ::dbtools::eInDataManipulation, false, false, false );
380 assignTable();
382 // now check if our datasource has set a tablefilter and if append the new table name to it
383 ::dbaui::appendToFilter(getConnection(),m_sName,getORB(),getView()); // we are not interessted in the return value
384 Reference< frame::XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY);
385 if ( xEventListener.is() )
387 frame::TitleChangedEvent aEvent;
388 xEventListener->titleChanged(aEvent);
390 releaseNumberForComponent();
392 else if(m_xTable.is())
394 bAlter = true;
395 alterColumns();
397 reSyncRows();
399 catch(const SQLContext& e)
401 aInfo = SQLExceptionInfo(e);
403 catch(const SQLWarning& e)
405 aInfo = SQLExceptionInfo(e);
407 catch(const SQLException& e)
409 aInfo = SQLExceptionInfo(e);
411 catch(const ElementExistException& )
413 OUString sText( ModuleRes( STR_NAME_ALREADY_EXISTS ) );
414 sText = sText.replaceFirst( "#" , m_sName);
415 ScopedVclPtrInstance< OSQLMessageBox > aDlg( getView(), OUString( ModuleRes( STR_ERROR_DURING_CREATION ) ), sText, WB_OK, OSQLMessageBox::Error );
417 aDlg->Execute();
418 bError = true;
420 catch( const Exception& )
422 bError = true;
423 DBG_UNHANDLED_EXCEPTION();
426 if ( aInfo.isValid() )
427 aInfo.prepend( OUString( ModuleRes( STR_TABLEDESIGN_SAVE_ERROR ) ) );
428 showError(aInfo);
430 if (aInfo.isValid() || bError)
432 if(!bAlter || bNew)
434 m_sName.clear();
435 stopTableListening();
436 m_xTable = NULL;
439 return ! (aInfo.isValid() || bError);
442 void OTableController::doEditIndexes()
444 // table needs to be saved before editing indexes
445 if (m_bNew || isModified())
447 ScopedVclPtrInstance< MessageDialog > aAsk(getView(), ModuleRes(STR_QUERY_SAVE_TABLE_EDIT_INDEXES), VCL_MESSAGE_QUESTION, VCL_BUTTONS_YES_NO);
448 if (RET_YES != aAsk->Execute())
449 return;
451 if (!doSaveDoc(false))
452 return;
454 OSL_ENSURE(!m_bNew && !isModified(), "OTableController::doEditIndexes: what the hell did doSaveDoc do?");
457 Reference< XNameAccess > xIndexes; // will be the keys of the table
458 Sequence< OUString > aFieldNames; // will be the column names of the table
461 // get the keys
462 Reference< XIndexesSupplier > xIndexesSupp(m_xTable, UNO_QUERY);
463 if (xIndexesSupp.is())
465 xIndexes = xIndexesSupp->getIndexes();
466 OSL_ENSURE(xIndexes.is(), "OTableController::doEditIndexes: no keys got from the indexes supplier!");
468 else
469 OSL_FAIL("OTableController::doEditIndexes: should never have reached this (no indexes supplier)!");
471 // get the field names
472 Reference< XColumnsSupplier > xColSupp(m_xTable, UNO_QUERY);
473 OSL_ENSURE(xColSupp.is(), "OTableController::doEditIndexes: no columns supplier!");
474 if (xColSupp.is())
476 Reference< XNameAccess > xCols = xColSupp->getColumns();
477 OSL_ENSURE(xCols.is(), "OTableController::doEditIndexes: no columns!");
478 if (xCols.is())
479 aFieldNames = xCols->getElementNames();
482 catch( const Exception& )
484 DBG_UNHANDLED_EXCEPTION();
487 if (!xIndexes.is())
488 return;
490 ScopedVclPtrInstance< DbaIndexDialog > aDialog(getView(), aFieldNames, xIndexes, getConnection(), getORB(), isConnected() && getConnection()->getMetaData().is() ? getConnection()->getMetaData()->getMaxColumnsInIndex() : 0);
491 if (RET_OK != aDialog->Execute())
492 return;
496 void OTableController::impl_initialize()
500 OTableController_BASE::impl_initialize();
502 const NamedValueCollection& rArguments( getInitParams() );
504 rArguments.get_ensureType( OUString(PROPERTY_CURRENTTABLE), m_sName );
506 // read autoincrement value set in the datasource
507 ::dbaui::fillAutoIncrementValue(getDataSource(),m_bAllowAutoIncrementValue,m_sAutoIncrementValue);
509 assignTable();
511 catch( const Exception& )
513 DBG_UNHANDLED_EXCEPTION();
518 ::dbaui::fillTypeInfo(getConnection(),m_sTypeNames,m_aTypeInfo,m_aTypeInfoIndex); // fill the needed type information
520 catch(const SQLException&)
522 ScopedVclPtrInstance<OSQLWarningBox>(getView(), ModuleRes( STR_NO_TYPE_INFO_AVAILABLE ))->Execute();
523 throw;
527 loadData(); // fill the column information from the table
528 getView()->initialize(); // show the windows and fill with our information
529 ClearUndoManager();
530 setModified(sal_False); // and we are not modified yet
532 catch( const Exception& )
534 DBG_UNHANDLED_EXCEPTION();
538 bool OTableController::Construct(vcl::Window* pParent)
540 setView( VclPtr<OTableDesignView>::Create( pParent, getORB(), *this ) );
541 OTableController_BASE::Construct(pParent);
542 return true;
545 sal_Bool SAL_CALL OTableController::suspend(sal_Bool /*_bSuspend*/) throw( RuntimeException, std::exception )
547 if ( getBroadcastHelper().bInDispose || getBroadcastHelper().bDisposed )
548 return sal_True;
550 SolarMutexGuard aSolarGuard;
551 ::osl::MutexGuard aGuard( getMutex() );
552 if ( getView() && getView()->IsInModalMode() )
553 return sal_False;
554 if ( getView() )
555 static_cast<OTableDesignView*>(getView())->GrabFocus();
556 bool bCheck = true;
557 if ( isModified() )
559 if ( ::std::any_of(m_vRowList.begin(),m_vRowList.end(),
560 ::boost::mem_fn(&OTableRow::isValid)) )
562 ScopedVclPtrInstance<MessageDialog> aQry(getView(), "TableDesignSaveModifiedDialog",
563 "dbaccess/ui/tabledesignsavemodifieddialog.ui");
564 switch (aQry->Execute())
566 case RET_YES:
567 Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>());
568 if ( isModified() )
569 bCheck = false; // when we save the table this must be false else some press cancel
570 break;
571 case RET_CANCEL:
572 bCheck = false;
573 default:
574 break;
577 else if ( !m_bNew )
579 ScopedVclPtrInstance<MessageDialog> aQry(getView(), "DeleteAllRowsDialog",
580 "dbaccess/ui/deleteallrowsdialog.ui");
581 switch (aQry->Execute())
583 case RET_YES:
587 Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY);
588 Reference<XNameAccess> xTables = xTablesSup->getTables();
589 dropTable(xTables,m_sName);
591 catch(const Exception&)
593 OSL_FAIL("OTableController::suspend: nothing is expected to happen here!");
597 break;
598 case RET_CANCEL:
599 bCheck = false;
600 default:
601 break;
606 return bCheck;
609 void OTableController::describeSupportedFeatures()
611 OSingleDocumentController::describeSupportedFeatures();
613 implDescribeSupportedFeature( ".uno:Redo", ID_BROWSER_REDO, CommandGroup::EDIT );
614 implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVEDOC, CommandGroup::EDIT );
615 implDescribeSupportedFeature( ".uno:Undo", ID_BROWSER_UNDO, CommandGroup::EDIT );
616 implDescribeSupportedFeature( ".uno:HelpMenu", SID_HELPMENU, CommandGroup::APPLICATION );
617 implDescribeSupportedFeature( ".uno:NewDoc", SID_NEWDOC, CommandGroup::DOCUMENT );
618 implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT );
619 implDescribeSupportedFeature( ".uno:DBIndexDesign", SID_INDEXDESIGN, CommandGroup::APPLICATION );
620 implDescribeSupportedFeature( ".uno:EditDoc", ID_BROWSER_EDITDOC, CommandGroup::EDIT );
623 void OTableController::impl_onModifyChanged()
625 OSingleDocumentController::impl_onModifyChanged();
626 InvalidateFeature( SID_INDEXDESIGN );
629 void SAL_CALL OTableController::disposing( const EventObject& _rSource ) throw(RuntimeException, std::exception)
631 if ( _rSource.Source == m_xTable )
632 { // some deleted our table so we have a new one
633 stopTableListening();
634 m_xTable = NULL;
635 m_bNew = true;
636 setModified(sal_True);
638 else
639 OTableController_BASE::disposing( _rSource );
642 void OTableController::losingConnection( )
644 // let the base class do it's reconnect
645 OTableController_BASE::losingConnection( );
647 // remove from the table
648 Reference< XComponent > xComponent(m_xTable, UNO_QUERY);
649 if (xComponent.is())
651 Reference<XEventListener> xEvtL( static_cast< ::cppu::OWeakObject*>(this), UNO_QUERY);
652 xComponent->removeEventListener(xEvtL);
654 stopTableListening();
655 m_xTable = NULL;
656 assignTable();
657 if(!m_xTable.is())
659 m_bNew = true;
660 setModified(sal_True);
662 InvalidateAll();
665 TOTypeInfoSP OTableController::getTypeInfoByType(sal_Int32 _nDataType) const
667 return queryTypeInfoByType(_nDataType,m_aTypeInfo);
670 void OTableController::appendColumns(Reference<XColumnsSupplier>& _rxColSup, bool _bNew, bool _bKeyColumns)
674 // now append the columns
675 OSL_ENSURE(_rxColSup.is(),"No columns supplier");
676 if(!_rxColSup.is())
677 return;
678 Reference<XNameAccess> xColumns = _rxColSup->getColumns();
679 OSL_ENSURE(xColumns.is(),"No columns");
680 Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY);
682 Reference<XAppend> xAppend(xColumns,UNO_QUERY);
683 OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
685 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin();
686 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end();
687 for(;aIter != aEnd;++aIter)
689 OSL_ENSURE(*aIter,"OTableRow is null!");
690 OFieldDescription* pField = (*aIter)->GetActFieldDescr();
691 if ( !pField || (!_bNew && (*aIter)->IsReadOnly() && !_bKeyColumns) )
692 continue;
694 Reference<XPropertySet> xColumn;
695 if(pField->IsPrimaryKey() || !_bKeyColumns)
696 xColumn = xColumnFactory->createDataDescriptor();
697 if(xColumn.is())
699 if(!_bKeyColumns)
700 ::dbaui::setColumnProperties(xColumn,pField);
701 else
702 xColumn->setPropertyValue(PROPERTY_NAME,makeAny(pField->GetName()));
704 xAppend->appendByDescriptor(xColumn);
705 xColumn = NULL;
706 // now only the settings are missing
707 if(xColumns->hasByName(pField->GetName()))
709 xColumns->getByName(pField->GetName()) >>= xColumn;
710 if(xColumn.is())
711 pField->copyColumnSettingsTo(xColumn);
713 else
715 OSL_FAIL("OTableController::appendColumns: invalid field name!");
721 catch(const SQLException& )
723 showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
725 catch( const Exception& )
727 DBG_UNHANDLED_EXCEPTION();
731 void OTableController::appendPrimaryKey(Reference<XKeysSupplier>& _rxSup, bool _bNew)
733 if(!_rxSup.is())
734 return; // the database doesn't support keys
736 OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!");
737 Reference<XIndexAccess> xKeys(_rxSup->getKeys(),UNO_QUERY);
738 Reference<XPropertySet> xProp;
739 if (!xKeys.is())
740 return;
741 const sal_Int32 nCount = xKeys->getCount();
742 for(sal_Int32 i=0;i< nCount ;++i)
744 xKeys->getByIndex(i) >>= xProp;
745 sal_Int32 nKeyType = 0;
746 xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
747 if(KeyType::PRIMARY == nKeyType)
749 return; // primary key already exists after appending a column
752 Reference<XDataDescriptorFactory> xKeyFactory(xKeys,UNO_QUERY);
753 OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!");
754 if ( !xKeyFactory.is() )
755 return;
756 Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY);
757 OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
759 Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor();
760 OSL_ENSURE(xKey.is(),"Key is null!");
761 xKey->setPropertyValue(PROPERTY_TYPE,makeAny(KeyType::PRIMARY));
763 Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY);
764 if(xColSup.is())
766 appendColumns(xColSup,_bNew,true);
767 Reference<XNameAccess> xColumns = xColSup->getColumns();
768 if(xColumns->hasElements())
769 xAppend->appendByDescriptor(xKey);
773 void OTableController::loadData()
775 // if the data structure already exists, empty it
776 m_vRowList.clear();
778 ::boost::shared_ptr<OTableRow> pTabEdRow;
779 Reference< XDatabaseMetaData> xMetaData = getMetaData( );
780 // fill data structure with data from DataDefinitionObject
781 if(m_xTable.is() && xMetaData.is())
783 Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY);
784 OSL_ENSURE(xColSup.is(),"No XColumnsSupplier!");
785 Reference<XNameAccess> xColumns = xColSup->getColumns();
786 // ReadOnly-Flag
787 // For Drop no row may be editable
788 // For Add only the empty rows may be editable
789 // For Add and Drop all rows can be edited
790 // sal_Bool bReadOldRow = xMetaData->supportsAlterTableWithAddColumn() && xMetaData->supportsAlterTableWithDropColumn();
791 bool bIsAlterAllowed = isAlterAllowed();
792 Sequence< OUString> aColumns = xColumns->getElementNames();
793 const OUString* pIter = aColumns.getConstArray();
794 const OUString* pEnd = pIter + aColumns.getLength();
796 for(;pIter != pEnd;++pIter)
798 Reference<XPropertySet> xColumn;
799 xColumns->getByName(*pIter) >>= xColumn;
800 sal_Int32 nType = 0;
801 sal_Int32 nScale = 0;
802 sal_Int32 nPrecision = 0;
803 sal_Int32 nNullable = 0;
804 sal_Int32 nFormatKey = 0;
805 sal_Int32 nAlign = 0;
807 bool bIsAutoIncrement = false, bIsCurrency = false;
808 OUString sName,sDescription,sTypeName,sHelpText;
809 Any aControlDefault;
811 // get the properties from the column
812 xColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
813 xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName;
814 xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable;
815 xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bIsAutoIncrement;
816 xColumn->getPropertyValue(PROPERTY_ISCURRENCY) >>= bIsCurrency;
817 xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType;
818 xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale;
819 xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision;
820 xColumn->getPropertyValue(PROPERTY_DESCRIPTION) >>= sDescription;
822 if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_HELPTEXT))
823 xColumn->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText;
825 if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
826 aControlDefault = xColumn->getPropertyValue(PROPERTY_CONTROLDEFAULT);
827 if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_FORMATKEY))
828 xColumn->getPropertyValue(PROPERTY_FORMATKEY) >>= nFormatKey;
829 if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ALIGN))
830 xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign;
832 pTabEdRow.reset(new OTableRow());
833 pTabEdRow->SetReadOnly(!bIsAlterAllowed);
834 // search for type
835 bool bForce;
836 OUString sCreate("x");
837 TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,sCreate,nPrecision,nScale,bIsAutoIncrement,bForce);
838 if ( !pTypeInfo.get() )
839 pTypeInfo = m_pTypeInfo;
840 pTabEdRow->SetFieldType( pTypeInfo, bForce );
842 OFieldDescription* pActFieldDescr = pTabEdRow->GetActFieldDescr();
843 OSL_ENSURE(pActFieldDescr, "OTableController::loadData: invalid field description generated by the table row!");
844 if ( pActFieldDescr )
846 pActFieldDescr->SetName(sName);
847 pActFieldDescr->SetFormatKey(nFormatKey);
848 pActFieldDescr->SetDescription(sDescription);
849 pActFieldDescr->SetHelpText(sHelpText);
850 pActFieldDescr->SetAutoIncrement(bIsAutoIncrement);
851 pActFieldDescr->SetHorJustify(dbaui::mapTextJustify(nAlign));
852 pActFieldDescr->SetCurrency(bIsCurrency);
854 // special data
855 pActFieldDescr->SetIsNullable(nNullable);
856 pActFieldDescr->SetControlDefault(aControlDefault);
857 pActFieldDescr->SetPrecision(nPrecision);
858 pActFieldDescr->SetScale(nScale);
860 m_vRowList.push_back( pTabEdRow);
862 // fill the primary key information
863 Reference<XNameAccess> xKeyColumns = getKeyColumns();
864 if(xKeyColumns.is())
866 Sequence< OUString> aKeyColumns = xKeyColumns->getElementNames();
867 const OUString* pKeyBegin = aKeyColumns.getConstArray();
868 const OUString* pKeyEnd = pKeyBegin + aKeyColumns.getLength();
870 for(;pKeyBegin != pKeyEnd;++pKeyBegin)
872 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator rowIter = m_vRowList.begin();
873 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator rowEnd = m_vRowList.end();
874 for(;rowIter != rowEnd;++rowIter)
876 if((*rowIter)->GetActFieldDescr()->GetName() == *pKeyBegin)
878 (*rowIter)->SetPrimaryKey(true);
879 break;
886 // fill empty rows
888 OTypeInfoMap::iterator aTypeIter = m_aTypeInfo.find(DataType::VARCHAR);
889 if(aTypeIter == m_aTypeInfo.end())
890 aTypeIter = m_aTypeInfo.begin();
892 OSL_ENSURE(aTypeIter != m_aTypeInfo.end(),"We have no type information!");
894 bool bReadRow = !isAddAllowed();
895 for(sal_Int32 i=m_vRowList.size(); i < NEWCOLS; i++ )
897 pTabEdRow.reset(new OTableRow());
898 pTabEdRow->SetReadOnly(bReadRow);
899 m_vRowList.push_back( pTabEdRow);
903 Reference<XNameAccess> OTableController::getKeyColumns() const
905 return getPrimaryKeyColumns_throw(m_xTable);
908 bool OTableController::checkColumns(bool _bNew)
909 throw(css::sdbc::SQLException,
910 css::uno::RuntimeException, std::exception)
912 bool bOk = true;
913 bool bFoundPKey = false;
914 Reference< XDatabaseMetaData > xMetaData = getMetaData( );
915 DatabaseMetaData aMetaData( getConnection() );
917 ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers());
918 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
919 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
920 for(;aIter != aEnd;++aIter)
922 OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr();
923 if (pFieldDesc && !pFieldDesc->GetName().isEmpty())
925 bFoundPKey |= (*aIter)->IsPrimaryKey();
926 // first check for duplicate names
927 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter2 = aIter+1;
928 for(;aIter2 != aEnd;++aIter2)
930 OFieldDescription* pCompareDesc = (*aIter2)->GetActFieldDescr();
931 if (pCompareDesc && bCase(pCompareDesc->GetName(),pFieldDesc->GetName()))
933 OUString strMessage = ModuleRes(STR_TABLEDESIGN_DUPLICATE_NAME);
934 strMessage = strMessage.replaceFirst("$column$", pFieldDesc->GetName());
935 ScopedVclPtrInstance<OSQLWarningBox>(getView(), strMessage)->Execute();
936 return false;
941 if ( _bNew && !bFoundPKey && aMetaData.supportsPrimaryKeys() )
943 OUString sTitle(ModuleRes(STR_TABLEDESIGN_NO_PRIM_KEY_HEAD));
944 OUString sMsg(ModuleRes(STR_TABLEDESIGN_NO_PRIM_KEY));
945 ScopedVclPtrInstance< OSQLMessageBox > aBox(getView(), sTitle,sMsg, WB_YES_NO_CANCEL | WB_DEF_YES);
947 switch ( aBox->Execute() )
949 case RET_YES:
951 ::boost::shared_ptr<OTableRow> pNewRow(new OTableRow());
952 TOTypeInfoSP pTypeInfo = ::dbaui::queryPrimaryKeyType(m_aTypeInfo);
953 if ( !pTypeInfo.get() )
954 break;
956 pNewRow->SetFieldType( pTypeInfo );
957 OFieldDescription* pActFieldDescr = pNewRow->GetActFieldDescr();
959 pActFieldDescr->SetAutoIncrement(false);
960 pActFieldDescr->SetIsNullable(ColumnValue::NO_NULLS);
962 pActFieldDescr->SetName( createUniqueName(OUString("ID") ));
963 pActFieldDescr->SetPrimaryKey( true );
964 m_vRowList.insert(m_vRowList.begin(),pNewRow);
966 static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->Invalidate();
967 static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->RowInserted(0);
969 break;
970 case RET_CANCEL:
971 bOk = false;
972 break;
975 return bOk;
978 void OTableController::alterColumns()
980 Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY_THROW);
981 OSL_ENSURE(xColSup.is(),"What happen here?!");
983 Reference<XNameAccess> xColumns = xColSup->getColumns();
984 Reference<XIndexAccess> xIdxColumns(xColumns,UNO_QUERY_THROW);
985 OSL_ENSURE(xColumns.is(),"No columns");
986 if ( !xColumns.is() )
987 return;
988 Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY); // can be null
990 sal_Int32 nColumnCount = xIdxColumns->getCount();
991 Reference<XDrop> xDrop(xColumns,UNO_QUERY); // can be null
992 Reference<XAppend> xAppend(xColumns,UNO_QUERY); // can be null
993 Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); // can be null
995 bool bReload = false; // refresh the data
997 // contains all columns names which are already handled those which are not in the list will be deleted
998 Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1000 ::std::map< OUString,sal_Bool,::comphelper::UStringMixLess> aColumns(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers());
1001 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin();
1002 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end();
1003 // first look for columns where something other than the name changed
1004 sal_Int32 nPos = 0;
1005 for(;aIter != aEnd;++aIter,++nPos)
1007 OSL_ENSURE(*aIter,"OTableRow is null!");
1008 OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1009 if ( !pField )
1010 continue;
1011 if ( (*aIter)->IsReadOnly() )
1013 aColumns[pField->GetName()] = sal_True;
1014 continue;
1017 Reference<XPropertySet> xColumn;
1018 if ( xColumns->hasByName(pField->GetName()) )
1020 aColumns[pField->GetName()] = sal_True;
1021 xColumns->getByName(pField->GetName()) >>= xColumn;
1022 OSL_ENSURE(xColumn.is(),"Column is null!");
1024 sal_Int32 nType=0,nPrecision=0,nScale=0,nNullable=0;
1025 bool bAutoIncrement = false;
1026 OUString sTypeName,sDescription;
1028 xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType;
1029 xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision;
1030 xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale;
1031 xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable;
1032 xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bAutoIncrement;
1033 xColumn->getPropertyValue(PROPERTY_DESCRIPTION) >>= sDescription;
1035 try { xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; }
1036 catch( const Exception& )
1038 OSL_FAIL( "no TypeName property?!" );
1039 // since this is a last minute fix for #i41785#, I want to be on the safe side,
1040 // and catch errors here as early as possible (instead of the whole process of altering
1041 // the columns failing)
1042 // Normally, sdbcx::Column objects are expected to have a TypeName property
1045 // check if something changed
1046 if((nType != pField->GetType() ||
1047 sTypeName != pField->GetTypeName() ||
1048 (nPrecision != pField->GetPrecision() && nPrecision ) ||
1049 nScale != pField->GetScale() ||
1050 nNullable != pField->GetIsNullable() ||
1051 sDescription != pField->GetDescription() ||
1052 bAutoIncrement != pField->IsAutoIncrement())&&
1053 xColumnFactory.is())
1055 Reference<XPropertySet> xNewColumn;
1056 xNewColumn = xColumnFactory->createDataDescriptor();
1057 ::dbaui::setColumnProperties(xNewColumn,pField);
1058 // first try to alter the column
1059 bool bNotOk = false;
1062 // first try if we can alter the column
1063 if(xAlter.is())
1064 xAlter->alterColumnByName(pField->GetName(),xNewColumn);
1066 catch(const SQLException&)
1068 if(xDrop.is() && xAppend.is())
1070 OUString aMessage( ModuleRes( STR_TABLEDESIGN_ALTER_ERROR ) );
1071 aMessage = aMessage.replaceFirst( "$column$", pField->GetName() );
1073 SQLExceptionInfo aError( ::cppu::getCaughtException() );
1074 ScopedVclPtrInstance< OSQLWarningBox > aMsg( getView(), aMessage, WB_YES_NO | WB_DEF_YES , &aError );
1075 bNotOk = aMsg->Execute() == RET_YES;
1077 else
1078 throw;
1080 // if something went wrong or we can't alter columns
1081 // drop and append a new one
1082 if((!xAlter.is() || bNotOk) && xDrop.is() && xAppend.is())
1084 xDrop->dropByName(pField->GetName());
1087 xAppend->appendByDescriptor(xNewColumn);
1089 catch(const SQLException&)
1090 { // an error occurred so we try to reactivate the old one
1091 xAppend->appendByDescriptor(xColumn);
1092 throw;
1095 // exceptions are caught outside
1096 xNewColumn = NULL;
1097 if(xColumns->hasByName(pField->GetName()))
1098 xColumns->getByName(pField->GetName()) >>= xColumn;
1099 bReload = true;
1103 else if(xColumnFactory.is() && xAlter.is() && nPos < nColumnCount)
1104 { // we can't find the column so we could try it with the index before we drop and append a new column
1107 Reference<XPropertySet> xNewColumn;
1108 xNewColumn = xColumnFactory->createDataDescriptor();
1109 ::dbaui::setColumnProperties(xNewColumn,pField);
1110 xAlter->alterColumnByIndex(nPos,xNewColumn);
1111 if(xColumns->hasByName(pField->GetName()))
1112 { // ask for the append by name
1113 aColumns[pField->GetName()] = sal_True;
1114 xColumns->getByName(pField->GetName()) >>= xColumn;
1115 if(xColumn.is())
1116 pField->copyColumnSettingsTo(xColumn);
1118 else
1120 OSL_FAIL("OTableController::alterColumns: invalid column (2)!");
1123 catch(const SQLException&)
1124 { // we couldn't alter the column so we have to add new columns
1125 bReload = true;
1126 if(xDrop.is() && xAppend.is())
1128 OUString aMessage(ModuleRes(STR_TABLEDESIGN_ALTER_ERROR));
1129 aMessage = aMessage.replaceFirst("$column$",pField->GetName());
1130 ScopedVclPtrInstance< OSQLWarningBox > aMsg( getView(), aMessage, WB_YES_NO | WB_DEF_YES );
1131 if ( aMsg->Execute() != RET_YES )
1133 Reference<XPropertySet> xNewColumn(xIdxColumns->getByIndex(nPos),UNO_QUERY_THROW);
1134 OUString sName;
1135 xNewColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
1136 aColumns[sName] = sal_True;
1137 aColumns[pField->GetName()] = sal_True;
1138 continue;
1141 else
1142 throw;
1145 else
1146 bReload = true;
1148 // alter column settings
1149 aIter = m_vRowList.begin();
1151 // first look for columns where something other than the name changed
1152 for(nPos = 0;aIter != aEnd;++aIter,++nPos)
1154 OSL_ENSURE(*aIter,"OTableRow is null!");
1155 OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1156 if ( !pField )
1157 continue;
1158 if ( (*aIter)->IsReadOnly() )
1160 aColumns[pField->GetName()] = sal_True;
1161 continue;
1164 Reference<XPropertySet> xColumn;
1165 if ( xColumns->hasByName(pField->GetName()) )
1167 xColumns->getByName(pField->GetName()) >>= xColumn;
1168 Reference<XPropertySetInfo> xInfo = xColumn->getPropertySetInfo();
1169 if ( xInfo->hasPropertyByName(PROPERTY_HELPTEXT) )
1170 xColumn->setPropertyValue(PROPERTY_HELPTEXT,makeAny(pField->GetHelpText()));
1172 if(xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
1173 xColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,pField->GetControlDefault());
1174 if(xInfo->hasPropertyByName(PROPERTY_FORMATKEY))
1175 xColumn->setPropertyValue(PROPERTY_FORMATKEY,makeAny(pField->GetFormatKey()));
1176 if(xInfo->hasPropertyByName(PROPERTY_ALIGN))
1177 xColumn->setPropertyValue(PROPERTY_ALIGN,makeAny(dbaui::mapTextAllign(pField->GetHorJustify())));
1180 // second drop all columns which could be found by name
1181 Reference<XNameAccess> xKeyColumns = getKeyColumns();
1182 // now we have to look for the columns who could be deleted
1183 if ( xDrop.is() )
1185 Sequence< OUString> aColumnNames = xColumns->getElementNames();
1186 const OUString* pIter = aColumnNames.getConstArray();
1187 const OUString* pEnd = pIter + aColumnNames.getLength();
1188 for(;pIter != pEnd;++pIter)
1190 if(aColumns.find(*pIter) == aColumns.end()) // found a column to delete
1192 if(xKeyColumns.is() && xKeyColumns->hasByName(*pIter)) // check if this column is a member of the primary key
1194 OUString aMsgT(ModuleRes(STR_TBL_COLUMN_IS_KEYCOLUMN));
1195 aMsgT = aMsgT.replaceFirst("$column$",*pIter);
1196 OUString aTitle(ModuleRes(STR_TBL_COLUMN_IS_KEYCOLUMN_TITLE));
1197 ScopedVclPtrInstance< OSQLMessageBox > aMsg(getView(),aTitle,aMsgT,WB_YES_NO| WB_DEF_YES);
1198 if(aMsg->Execute() == RET_YES)
1200 xKeyColumns = NULL;
1201 dropPrimaryKey();
1203 else
1205 bReload = true;
1206 continue;
1211 xDrop->dropByName(*pIter);
1213 catch (const SQLException&)
1215 OUString sError( ModuleRes( STR_TABLEDESIGN_COULD_NOT_DROP_COL ) );
1216 sError = sError.replaceFirst( "$column$", *pIter );
1218 SQLException aNewException;
1219 aNewException.Message = sError;
1220 aNewException.SQLState = "S1000";
1221 aNewException.NextException = ::cppu::getCaughtException();
1223 throw aNewException;
1229 // third append the new columns
1230 aIter = m_vRowList.begin();
1231 for(;aIter != aEnd;++aIter)
1233 OSL_ENSURE(*aIter,"OTableRow is null!");
1234 OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1235 if ( !pField || (*aIter)->IsReadOnly() || aColumns.find(pField->GetName()) != aColumns.end() )
1236 continue;
1238 Reference<XPropertySet> xColumn;
1239 if(!xColumns->hasByName(pField->GetName()))
1241 if(xColumnFactory.is() && xAppend.is())
1242 {// column not found by its name so we assume it is new
1243 // Column is new
1244 xColumn = xColumnFactory->createDataDescriptor();
1245 ::dbaui::setColumnProperties(xColumn,pField);
1246 xAppend->appendByDescriptor(xColumn);
1247 if(xColumns->hasByName(pField->GetName()))
1248 { // ask for the append by name
1249 aColumns[pField->GetName()] = sal_True;
1250 xColumns->getByName(pField->GetName()) >>= xColumn;
1251 if(xColumn.is())
1252 pField->copyColumnSettingsTo(xColumn);
1254 else
1256 OSL_FAIL("OTableController::alterColumns: invalid column!");
1262 // check if we have to do something with the primary key
1263 bool bNeedDropKey = false;
1264 bool bNeedAppendKey = false;
1265 if ( xKeyColumns.is() )
1267 aIter = m_vRowList.begin();
1268 for(;aIter != aEnd;++aIter)
1270 OSL_ENSURE(*aIter,"OTableRow is null!");
1271 OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1272 if ( !pField )
1273 continue;
1275 if ( pField->IsPrimaryKey()
1276 && !xKeyColumns->hasByName( pField->GetName() )
1278 { // new primary key column inserted which isn't already in the columns selection
1279 bNeedDropKey = bNeedAppendKey = true;
1280 break;
1282 else if ( !pField->IsPrimaryKey()
1283 && xKeyColumns->hasByName( pField->GetName() )
1285 { // found a column which currently is in the primary key, but is marked not to be anymore
1286 bNeedDropKey = bNeedAppendKey = true;
1287 break;
1291 else
1292 { // no primary key available so we check if we should create one
1293 bNeedAppendKey = true;
1296 if ( bNeedDropKey && xKeyColumns.is() && xKeyColumns->getElementNames().getLength() )
1297 dropPrimaryKey();
1299 if ( bNeedAppendKey )
1301 Reference< XKeysSupplier > xKeySup( m_xTable, UNO_QUERY );
1302 appendPrimaryKey( xKeySup ,false);
1305 reSyncRows();
1307 if ( bReload )
1308 reload();
1311 void OTableController::dropPrimaryKey()
1313 SQLExceptionInfo aInfo;
1316 Reference<XKeysSupplier> xKeySup(m_xTable,UNO_QUERY);
1317 Reference<XIndexAccess> xKeys;
1318 if(xKeySup.is())
1319 xKeys = xKeySup->getKeys();
1321 if(xKeys.is())
1323 Reference<XPropertySet> xProp;
1324 for(sal_Int32 i=0;i< xKeys->getCount();++i)
1326 xProp.set(xKeys->getByIndex(i),UNO_QUERY);
1327 sal_Int32 nKeyType = 0;
1328 xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
1329 if(KeyType::PRIMARY == nKeyType)
1331 Reference<XDrop> xDrop(xKeys,UNO_QUERY);
1332 xDrop->dropByIndex(i); // delete the key
1333 break;
1338 catch(const SQLContext& e)
1340 aInfo = SQLExceptionInfo(e);
1342 catch(const SQLWarning& e)
1344 aInfo = SQLExceptionInfo(e);
1346 catch(const SQLException& e)
1348 aInfo = SQLExceptionInfo(e);
1350 catch( const Exception& )
1352 DBG_UNHANDLED_EXCEPTION();
1355 showError(aInfo);
1358 void OTableController::assignTable()
1360 // get the table
1361 if(!m_sName.isEmpty())
1363 Reference<XNameAccess> xNameAccess;
1364 Reference<XTablesSupplier> xSup(getConnection(),UNO_QUERY);
1365 if(xSup.is())
1367 xNameAccess = xSup->getTables();
1368 OSL_ENSURE(xNameAccess.is(),"no nameaccess for the queries!");
1370 if(xNameAccess->hasByName(m_sName))
1372 Reference<XPropertySet> xProp(xNameAccess->getByName(m_sName), css::uno::UNO_QUERY);
1373 if (xProp.is())
1375 m_xTable = xProp;
1376 startTableListening();
1378 // check if we set the table editable
1379 Reference<XDatabaseMetaData> xMeta = getConnection()->getMetaData();
1380 setEditable( xMeta.is() && !xMeta->isReadOnly() && (isAlterAllowed() || isDropAllowed() || isAddAllowed()) );
1381 if(!isEditable())
1383 ::std::for_each(m_vRowList.begin(),m_vRowList.end(),boost::bind( &OTableRow::SetReadOnly, _1, true));
1385 m_bNew = false;
1386 // be notified when the table is in disposing
1387 InvalidateAll();
1394 bool OTableController::isAddAllowed() const
1396 Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY);
1397 bool bAddAllowed = !m_xTable.is();
1398 if(xColsSup.is())
1399 bAddAllowed = Reference<XAppend>(xColsSup->getColumns(),UNO_QUERY).is();
1403 Reference< XDatabaseMetaData > xMetaData = getMetaData( );
1404 bAddAllowed = bAddAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithAddColumn());
1406 catch(Exception&)
1408 DBG_UNHANDLED_EXCEPTION();
1409 bAddAllowed = false;
1412 return bAddAllowed;
1415 bool OTableController::isDropAllowed() const
1417 Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY);
1418 bool bDropAllowed = !m_xTable.is();
1419 if(xColsSup.is())
1421 Reference<XNameAccess> xNameAccess = xColsSup->getColumns();
1422 bDropAllowed = Reference<XDrop>(xNameAccess,UNO_QUERY).is() && xNameAccess->hasElements();
1425 Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1426 bDropAllowed = bDropAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithDropColumn());
1428 return bDropAllowed;
1431 bool OTableController::isAlterAllowed() const
1433 bool bAllowed(!m_xTable.is() || Reference<XAlterTable>(m_xTable,UNO_QUERY).is());
1434 return bAllowed;
1437 void OTableController::reSyncRows()
1439 bool bAlterAllowed = isAlterAllowed();
1440 bool bAddAllowed = isAddAllowed();
1441 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin();
1442 ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end();
1443 for(;aIter != aEnd;++aIter)
1445 OSL_ENSURE(*aIter,"OTableRow is null!");
1446 OFieldDescription* pField = (*aIter)->GetActFieldDescr();
1447 if ( pField )
1448 (*aIter)->SetReadOnly(!bAlterAllowed);
1449 else
1450 (*aIter)->SetReadOnly(!bAddAllowed);
1453 static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our information
1455 ClearUndoManager();
1456 setModified(sal_False); // and we are not modified yet
1459 OUString OTableController::createUniqueName(const OUString& _rName)
1461 OUString sName = _rName;
1462 Reference< XDatabaseMetaData> xMetaData = getMetaData( );
1464 ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers());
1466 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
1467 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
1468 for(sal_Int32 i=0;aIter != aEnd;++aIter)
1470 OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr();
1471 if (pFieldDesc && !pFieldDesc->GetName().isEmpty() && bCase(sName,pFieldDesc->GetName()))
1472 { // found a second name of _rName so we need another
1473 sName = _rName + OUString::number(++i);
1474 aIter = m_vRowList.begin(); // and retry
1477 return sName;
1480 OUString OTableController::getPrivateTitle() const
1482 OUString sTitle;
1485 // get the table
1486 if ( !m_sName.isEmpty() && getConnection().is() )
1488 if ( m_xTable.is() )
1489 sTitle = ::dbtools::composeTableName( getConnection()->getMetaData(), m_xTable, ::dbtools::eInDataManipulation, false, false, false );
1490 else
1491 sTitle = m_sName;
1493 if ( sTitle.isEmpty() )
1495 OUString aName = ModuleRes(STR_TBL_TITLE);
1496 sTitle = aName.getToken(0,' ');
1497 sTitle += OUString::number(getCurrentStartNumber());
1500 catch( const Exception& )
1502 DBG_UNHANDLED_EXCEPTION();
1504 return sTitle;
1507 void OTableController::reload()
1509 loadData(); // fill the column information from the table
1510 static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our information
1511 ClearUndoManager();
1512 setModified(sal_False); // and we are not modified yet
1513 static_cast<OTableDesignView*>(getView())->Invalidate();
1516 sal_Int32 OTableController::getFirstEmptyRowPosition()
1518 sal_Int32 nRet = -1;
1519 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
1520 ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
1521 for(;aIter != aEnd;++aIter)
1523 if ( !*aIter || !(*aIter)->GetActFieldDescr() || (*aIter)->GetActFieldDescr()->GetName().isEmpty() )
1525 nRet = aIter - m_vRowList.begin();
1526 break;
1529 if ( nRet == -1 )
1531 bool bReadRow = !isAddAllowed();
1532 ::boost::shared_ptr<OTableRow> pTabEdRow(new OTableRow());
1533 pTabEdRow->SetReadOnly(bReadRow);
1534 nRet = m_vRowList.size();
1535 m_vRowList.push_back( pTabEdRow);
1537 return nRet;
1540 bool OTableController::isAutoIncrementPrimaryKey() const
1542 return getSdbMetaData().isAutoIncrementPrimaryKey();
1545 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */