diff options
Diffstat (limited to 'dbaccess/source/ui/tabledesign/TableController.cxx')
-rw-r--r-- | dbaccess/source/ui/tabledesign/TableController.cxx | 1632 |
1 files changed, 1632 insertions, 0 deletions
diff --git a/dbaccess/source/ui/tabledesign/TableController.cxx b/dbaccess/source/ui/tabledesign/TableController.cxx new file mode 100644 index 000000000000..1eed02543cda --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableController.cxx @@ -0,0 +1,1632 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: TableController.cxx,v $ + * $Revision: 1.122.24.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_dbaccess.hxx" + +#include "FieldDescriptions.hxx" +#include "TEditControl.hxx" +#include "TableController.hxx" +#include "TableDesignView.hxx" +#include "TableRow.hxx" +#include "TypeInfo.hxx" +#include "UITools.hxx" +#include "browserids.hxx" +#include "dbu_reghelper.hxx" +#include "dbu_tbl.hrc" +#include "dbustrings.hrc" +#include "defaultobjectnamecheck.hxx" +#include "dlgsave.hxx" +#include "dsmeta.hxx" +#include "indexdialog.hxx" +#include "sqlmessage.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/frame/XTitleChangeListener.hpp> +#include <com/sun/star/frame/XUntitledNumbers.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <com/sun/star/sdbcx/XAlterTable.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XDrop.hpp> +#include <com/sun/star/sdbcx/XIndexesSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +/** === end UNO includes === **/ + +#include <comphelper/extract.hxx> +#include <comphelper/streamsection.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbmetadata.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <sfx2/sfxsids.hrc> +#include <tools/diagnose_ex.h> +#include <tools/string.hxx> +#include <vcl/msgbox.hxx> + +#include <boost/mem_fn.hpp> +#include <boost/bind.hpp> + +#include <algorithm> +#include <functional> + +extern "C" void SAL_CALL createRegistryInfo_OTableControl() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OTableController > aAutoRegistration; +} + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::ui; +using namespace ::com::sun::star::util; +using namespace ::dbtools; +using namespace ::dbaui; +using namespace ::comphelper; + +namespace +{ + void dropTable(const Reference<XNameAccess>& _rxTable,const ::rtl::OUString& _sTableName) + { + if ( _rxTable->hasByName(_sTableName) ) + { + Reference<XDrop> xNameCont(_rxTable,UNO_QUERY); + OSL_ENSURE(xNameCont.is(),"No drop interface for tables!"); + if ( xNameCont.is() ) + xNameCont->dropByName(_sTableName); + } + } + //------------------------------------------------------------------------------ + struct OTableRowCompare : public ::std::binary_function< ::boost::shared_ptr<OTableRow> , ::rtl::OUString, bool> + { + bool operator() (const ::boost::shared_ptr<OTableRow> lhs, const ::rtl::OUString& rhs) const + { + OFieldDescription* pField = lhs->GetActFieldDescr(); + return pField && pField->GetName() == rhs; + } + }; + +} + +//------------------------------------------------------------------------------ +::rtl::OUString SAL_CALL OTableController::getImplementationName() throw( RuntimeException ) +{ + return getImplementationName_Static(); +} + +//------------------------------------------------------------------------------ +::rtl::OUString OTableController::getImplementationName_Static() throw( RuntimeException ) +{ + return ::rtl::OUString::createFromAscii("org.openoffice.comp.dbu.OTableDesign"); +} +//------------------------------------------------------------------------------ +Sequence< ::rtl::OUString> OTableController::getSupportedServiceNames_Static(void) throw( RuntimeException ) +{ + Sequence< ::rtl::OUString> aSupported(1); + aSupported.getArray()[0] = ::rtl::OUString::createFromAscii("com.sun.star.sdb.TableDesign"); + return aSupported; +} +//------------------------------------------------------------------------- +Sequence< ::rtl::OUString> SAL_CALL OTableController::getSupportedServiceNames() throw(RuntimeException) +{ + return getSupportedServiceNames_Static(); +} +// ------------------------------------------------------------------------- +Reference< XInterface > SAL_CALL OTableController::Create(const Reference<XMultiServiceFactory >& _rxFactory) +{ + return *(new OTableController(_rxFactory)); +} + +DBG_NAME(OTableController) +// ----------------------------------------------------------------------------- +OTableController::OTableController(const Reference< XMultiServiceFactory >& _rM) : OTableController_BASE(_rM) + ,m_sTypeNames(ModuleRes(STR_TABLEDESIGN_DBFIELDTYPES)) + ,m_pTypeInfo() + ,m_bAllowAutoIncrementValue(sal_False) + ,m_bNew(sal_True) +{ + DBG_CTOR(OTableController,NULL); + + InvalidateAll(); + m_pTypeInfo = TOTypeInfoSP(new OTypeInfo()); + m_pTypeInfo->aUIName = m_sTypeNames.GetToken(TYPE_OTHER); +} +// ----------------------------------------------------------------------------- +OTableController::~OTableController() +{ + m_aTypeInfoIndex.clear(); + m_aTypeInfo.clear(); + + DBG_DTOR(OTableController,NULL); +} + +// ----------------------------------------------------------------------------- +void OTableController::startTableListening() +{ + Reference< XComponent > xComponent(m_xTable, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(static_cast<XModifyListener*>(this)); +} + +// ----------------------------------------------------------------------------- +void OTableController::stopTableListening() +{ + Reference< XComponent > xComponent(m_xTable, UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener(static_cast<XModifyListener*>(this)); +} + +// ----------------------------------------------------------------------------- +void OTableController::disposing() +{ + OTableController_BASE::disposing(); + m_pView = NULL; + + m_vRowList.clear(); +} +// ----------------------------------------------------------------------------- +FeatureState OTableController::GetState(sal_uInt16 _nId) const +{ + FeatureState aReturn; + // (disabled automatically) + + switch (_nId) + { + case ID_BROWSER_CLOSE: + aReturn.bEnabled = sal_True; + break; + case ID_BROWSER_EDITDOC: + aReturn.bChecked = isEditable(); + aReturn.bEnabled = m_bNew || isEditable();// the editable flag is set through this one -> || isAddAllowed() || isDropAllowed() || isAlterAllowed(); + break; + case ID_BROWSER_SAVEDOC: + aReturn.bEnabled = isModified(); + if ( aReturn.bEnabled ) + { + ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(), + ::boost::mem_fn(&OTableRow::isValid)); + aReturn.bEnabled = aIter != m_vRowList.end(); + } + break; + case ID_BROWSER_SAVEASDOC: + aReturn.bEnabled = isConnected() && isEditable(); + if ( aReturn.bEnabled ) + { + ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(), + ::boost::mem_fn(&OTableRow::isValid)); + aReturn.bEnabled = aIter != m_vRowList.end(); + } + break; + + case ID_BROWSER_CUT: + aReturn.bEnabled = isEditable() && m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isCutAllowed(); + break; + case ID_BROWSER_COPY: + aReturn.bEnabled = m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isCopyAllowed(); + break; + case ID_BROWSER_PASTE: + aReturn.bEnabled = isEditable() && m_aCurrentFrame.isActive() && getView() && static_cast<OTableDesignView*>(getView())->isPasteAllowed(); + break; + case SID_INDEXDESIGN: + aReturn.bEnabled = + ( ( ((!m_bNew && isModified()) || isModified()) + || Reference< XIndexesSupplier >(m_xTable, UNO_QUERY).is() + ) + && isConnected() + ); + if ( aReturn.bEnabled ) + { + ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(), + ::boost::mem_fn(&OTableRow::isValid)); + aReturn.bEnabled = aIter != m_vRowList.end(); + } + break; + default: + aReturn = OTableController_BASE::GetState(_nId); + } + return aReturn; +} +// ----------------------------------------------------------------------------- +void OTableController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs) +{ + switch(_nId) + { + case ID_BROWSER_EDITDOC: + setEditable(!isEditable()); + static_cast<OTableDesignView*>(getView())->setReadOnly(!isEditable()); + InvalidateFeature(ID_BROWSER_PASTE); + InvalidateFeature(SID_BROWSER_CLEAR_QUERY); + break; + case ID_BROWSER_SAVEASDOC: + doSaveDoc(sal_True); + break; + case ID_BROWSER_SAVEDOC: + static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->SaveCurRow(); + doSaveDoc(sal_False); + break; + case ID_BROWSER_CUT: + static_cast<OTableDesignView*>(getView())->cut(); + break; + case ID_BROWSER_COPY: + static_cast<OTableDesignView*>(getView())->copy(); + break; + case ID_BROWSER_PASTE: + static_cast<OTableDesignView*>(getView())->paste(); + break; + case SID_INDEXDESIGN: + doEditIndexes(); + break; + default: + OTableController_BASE::Execute(_nId,aArgs); + } + InvalidateFeature(_nId); +} + +// ----------------------------------------------------------------------------- +sal_Bool OTableController::doSaveDoc(sal_Bool _bSaveAs) +{ + if (!isConnected()) + reconnect(sal_True); // ask the user for a new connection + Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY); + + if (!xTablesSup.is()) + { + String aMessage(ModuleRes(STR_TABLEDESIGN_CONNECTION_MISSING)); + OSQLWarningBox( getView(), aMessage ).Execute(); + return sal_False; + } + + // check if a column exists + // TODO + + Reference<XNameAccess> xTables; + ::rtl::OUString sCatalog, sSchema; + + sal_Bool bNew = (0 == m_sName.getLength()); + bNew = bNew || m_bNew || _bSaveAs; + + try + { + xTables = xTablesSup->getTables(); + OSL_ENSURE(xTables.is(),"The tables can't be null!"); + bNew = bNew || (xTables.is() && !xTables->hasByName(m_sName)); + + // first we need a name for our query so ask the user + if(bNew) + { + String aDefaultName; + if (_bSaveAs && !bNew) + aDefaultName = String(m_sName); + else + { + String aName = String(ModuleRes(STR_TBL_TITLE)); + aDefaultName = aName.GetToken(0,' '); + //aDefaultName = getPrivateTitle(); + aDefaultName = ::dbtools::createUniqueName(xTables,aDefaultName); + } + + DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::TABLE ); + OSaveAsDlg aDlg( getView(), CommandType::TABLE, getORB(), getConnection(), aDefaultName, aNameChecker ); + if ( aDlg.Execute() != RET_OK ) + return sal_False; + + m_sName = aDlg.getName(); + sCatalog = aDlg.getCatalog(); + sSchema = aDlg.getSchema(); + } + + // did we get a name + if(!m_sName.getLength()) + return sal_False; + } + catch(Exception&) + { + OSL_ENSURE(sal_False, "OTableController::doSaveDoc: nothing is expected to happen here!"); + } + + sal_Bool bAlter = sal_False; + sal_Bool bError = sal_False; + SQLExceptionInfo aInfo; + try + { + // check the columns for double names + if(!checkColumns(bNew || !xTables->hasByName(m_sName))) + { + // #105323# OJ + return sal_False; + } + + Reference<XPropertySet> xTable; + if(bNew || !xTables->hasByName(m_sName)) // just to make sure the table already exists + { + dropTable(xTables,m_sName); + + Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY); + OSL_ENSURE(xFact.is(),"OTableController::doSaveDoc: No XDataDescriptorFactory available!"); + xTable = xFact->createDataDescriptor(); + OSL_ENSURE(xTable.is(),"OTableController::doSaveDoc: Create query failed!"); + // to set the name is only allowed when the wuery is new + xTable->setPropertyValue(PROPERTY_CATALOGNAME,makeAny(sCatalog)); + xTable->setPropertyValue(PROPERTY_SCHEMANAME,makeAny(sSchema)); + xTable->setPropertyValue(PROPERTY_NAME,makeAny(m_sName)); + + // now append the columns + Reference<XColumnsSupplier> xColSup(xTable,UNO_QUERY); + appendColumns(xColSup,bNew); + // now append the primary key + Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY); + appendPrimaryKey(xKeySup,bNew); + } + // now set the properties + if(bNew) + { + Reference<XAppend> xAppend(xTables,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"OTableController::doSaveDoc: No XAppend Interface!"); + xAppend->appendByDescriptor(xTable); + + assignTable(); + if(!m_xTable.is()) // correct name and try again + { + // it can be that someone inserted new data for us + m_sName = ::dbtools::composeTableName( getConnection()->getMetaData(), xTable, ::dbtools::eInDataManipulation, false, false, false ); + assignTable(); + } + // now check if our datasource has set a tablefilter and if append the new table name to it + ::dbaui::appendToFilter(getConnection(),m_sName,getORB(),getView()); // we are not interessted in the return value + Reference< frame::XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY); + if ( xEventListener.is() ) + { + frame::TitleChangedEvent aEvent; + xEventListener->titleChanged(aEvent); + } + releaseNumberForComponent(); + } + else if(m_xTable.is()) + { + bAlter = sal_True; + alterColumns(); + } + reSyncRows(); + } + catch(const SQLContext& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const SQLWarning& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const SQLException& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const ElementExistException& ) + { + String sText( ModuleRes( STR_NAME_ALREADY_EXISTS ) ); + sText.SearchAndReplaceAscii( "#" , m_sName); + OSQLMessageBox aDlg( getView(), String( ModuleRes( STR_ERROR_DURING_CREATION ) ), sText, WB_OK, OSQLMessageBox::Error ); + + aDlg.Execute(); + bError = sal_True; + } + catch( const Exception& ) + { + bError = sal_True; + DBG_UNHANDLED_EXCEPTION(); + } + + if ( aInfo.isValid() ) + aInfo.prepend( String( ModuleRes( STR_TABLEDESIGN_SAVE_ERROR ) ) ); + showError(aInfo); + + if (aInfo.isValid() || bError) + { + if(!bAlter || bNew) + { + m_sName = ::rtl::OUString(); + stopTableListening(); + m_xTable = NULL; + } + // reload(); // a error occured so we have to reload + } + return ! (aInfo.isValid() || bError); +} + +// ----------------------------------------------------------------------------- +void OTableController::doEditIndexes() +{ + // table needs to be saved before editing indexes + if (m_bNew || isModified()) + { + QueryBox aAsk(getView(), ModuleRes(QUERY_SAVE_TABLE_EDIT_INDEXES)); + if (RET_YES != aAsk.Execute()) + return; + + if (!doSaveDoc(sal_False)) + return; + + OSL_ENSURE(!m_bNew && !isModified(), "OTableController::doEditIndexes: what the hell did doSaveDoc do?"); + } + + Reference< XNameAccess > xIndexes; // will be the keys of the table + Sequence< ::rtl::OUString > aFieldNames; // will be the column names of the table + try + { + // get the keys + Reference< XIndexesSupplier > xIndexesSupp(m_xTable, UNO_QUERY); + if (xIndexesSupp.is()) + { + xIndexes = xIndexesSupp->getIndexes(); + OSL_ENSURE(xIndexes.is(), "OTableController::doEditIndexes: no keys got from the indexes supplier!"); + } + else + OSL_ENSURE(sal_False, "OTableController::doEditIndexes: should never have reached this (no indexes supplier)!"); + + // get the field names + Reference< XColumnsSupplier > xColSupp(m_xTable, UNO_QUERY); + OSL_ENSURE(xColSupp.is(), "OTableController::doEditIndexes: no columns supplier!"); + if (xColSupp.is()) + { + Reference< XNameAccess > xCols = xColSupp->getColumns(); + OSL_ENSURE(xCols.is(), "OTableController::doEditIndexes: no columns!"); + if (xCols.is()) + aFieldNames = xCols->getElementNames(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + if (!xIndexes.is()) + return; + + DbaIndexDialog aDialog(getView(), aFieldNames, xIndexes, getConnection(),getORB(),isConnected() ? getConnection()->getMetaData().is() && getConnection()->getMetaData()->getMaxColumnsInIndex() : sal_Int32(0)); + if (RET_OK != aDialog.Execute()) + return; + +} + +// ----------------------------------------------------------------------------- +void OTableController::impl_initialize() +{ + try + { + OTableController_BASE::impl_initialize(); + + const NamedValueCollection& rArguments( getInitParams() ); + + rArguments.get_ensureType( (::rtl::OUString)PROPERTY_CURRENTTABLE, m_sName ); + + // read autoincrement value set in the datasource + ::dbaui::fillAutoIncrementValue(getDataSource(),m_bAllowAutoIncrementValue,m_sAutoIncrementValue); + + assignTable(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + try + { + ::dbaui::fillTypeInfo(getConnection(),m_sTypeNames,m_aTypeInfo,m_aTypeInfoIndex); // fill the needed type information + } + catch(const SQLException&) + { + OSQLWarningBox( getView(), ModuleRes( STR_NO_TYPE_INFO_AVAILABLE ) ).Execute(); + throw; + } + try + { + loadData(); // fill the column information form the table + getView()->initialize(); // show the windows and fill with our informations + getUndoMgr()->Clear(); // clear all undo redo things + setModified(sal_False); // and we are not modified yet + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} +// ----------------------------------------------------------------------------- +sal_Bool OTableController::Construct(Window* pParent) +{ + m_pView = new OTableDesignView( pParent, getORB(), *this ); + OTableController_BASE::Construct(pParent); +// m_pView->Construct(); +// m_pView->Show(); + return sal_True; +} +// ----------------------------------------------------------------------------- +sal_Bool SAL_CALL OTableController::suspend(sal_Bool /*_bSuspend*/) throw( RuntimeException ) +{ + if ( getBroadcastHelper().bInDispose || getBroadcastHelper().bDisposed ) + return sal_True; + + vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ::osl::MutexGuard aGuard( getMutex() ); + if ( getView() && getView()->IsInModalMode() ) + return sal_False; + if ( getView() ) + static_cast<OTableDesignView*>(getView())->GrabFocus(); + sal_Bool bCheck = sal_True; + if ( isModified() ) + { + ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = ::std::find_if(m_vRowList.begin(),m_vRowList.end(), + ::boost::mem_fn(&OTableRow::isValid)); + if ( aIter != m_vRowList.end() ) + { + QueryBox aQry(getView(), ModuleRes(TABLE_DESIGN_SAVEMODIFIED)); + switch (aQry.Execute()) + { + case RET_YES: + Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>()); + if ( isModified() ) + bCheck = sal_False; // when we save the table this must be false else some press cancel + break; + case RET_CANCEL: + bCheck = sal_False; + default: + break; + } + } + else if ( !m_bNew ) + { + QueryBox aQry(getView(), ModuleRes(TABLE_DESIGN_ALL_ROWS_DELETED)); + switch (aQry.Execute()) + { + case RET_YES: + { + try + { + Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY); + Reference<XNameAccess> xTables = xTablesSup->getTables(); + dropTable(xTables,m_sName); + } + catch(const Exception&) + { + OSL_ENSURE(sal_False, "OTableController::suspend: nothing is expected to happen here!"); + } + + } + break; + case RET_CANCEL: + bCheck = sal_False; + default: + break; + } + } + } +/* + if ( bCheck ) + OSingleDocumentController::suspend(_bSuspend); +*/ + return bCheck; +} +// ----------------------------------------------------------------------------- +void OTableController::describeSupportedFeatures() +{ + OSingleDocumentController::describeSupportedFeatures(); + + implDescribeSupportedFeature( ".uno:Redo", ID_BROWSER_REDO, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVEDOC, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Undo", ID_BROWSER_UNDO, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:HelpMenu", SID_HELPMENU, CommandGroup::APPLICATION ); + implDescribeSupportedFeature( ".uno:NewDoc", SID_NEWDOC, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:DBIndexDesign", SID_INDEXDESIGN, CommandGroup::APPLICATION ); + implDescribeSupportedFeature( ".uno:EditDoc", ID_BROWSER_EDITDOC, CommandGroup::EDIT ); +} +// ----------------------------------------------------------------------------- +SfxUndoManager* OTableController::getUndoMgr() +{ + return &m_aUndoManager; +} +// ----------------------------------------------------------------------------- +void OTableController::setModified(sal_Bool _bModified) +{ + OSingleDocumentController::setModified(_bModified); + InvalidateFeature(SID_INDEXDESIGN); +} +// ----------------------------------------------------------------------------- +void SAL_CALL OTableController::disposing( const EventObject& _rSource ) throw(RuntimeException) +{ + if ( _rSource.Source == m_xTable ) + { // some deleted our table so we have a new one + stopTableListening(); + m_xTable = NULL; + m_bNew = sal_True; + setModified(sal_True); + } + else + OTableController_BASE::disposing( _rSource ); +} +// ----------------------------------------------------------------------------- +void OTableController::Save(const Reference< XObjectOutputStream>& _rxOut) +{ + OStreamSection aSection(_rxOut.get()); + +} +// ----------------------------------------------------------------------------- +void OTableController::Load(const Reference< XObjectInputStream>& _rxIn) +{ + OStreamSection aSection(_rxIn.get()); +} + +// ----------------------------------------------------------------------------- +void OTableController::losingConnection( ) +{ + // let the base class do it's reconnect + OTableController_BASE::losingConnection( ); + + // remove from the table + Reference< XComponent > xComponent(m_xTable, UNO_QUERY); + if (xComponent.is()) + { + Reference<XEventListener> xEvtL( static_cast< ::cppu::OWeakObject*>(this), UNO_QUERY); + xComponent->removeEventListener(xEvtL); + } + stopTableListening(); + m_xTable = NULL; + assignTable(); + if(!m_xTable.is()) + { + m_bNew = sal_True; + setModified(sal_True); + } + InvalidateAll(); +} +// ----------------------------------------------------------------------------- +TOTypeInfoSP OTableController::getTypeInfoByType(sal_Int32 _nDataType) const +{ + return queryTypeInfoByType(_nDataType,m_aTypeInfo); +} +// ----------------------------------------------------------------------------- +void OTableController::appendColumns(Reference<XColumnsSupplier>& _rxColSup,sal_Bool _bNew,sal_Bool _bKeyColumns) +{ + try + { + // now append the columns + OSL_ENSURE(_rxColSup.is(),"No columns supplier"); + if(!_rxColSup.is()) + return; + Reference<XNameAccess> xColumns = _rxColSup->getColumns(); + OSL_ENSURE(xColumns.is(),"No columns"); + Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); + + Reference<XAppend> xAppend(xColumns,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin(); + ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end(); + for(;aIter != aEnd;++aIter) + { + OSL_ENSURE(*aIter,"OTableRow is null!"); + OFieldDescription* pField = (*aIter)->GetActFieldDescr(); + if ( !pField || (!_bNew && (*aIter)->IsReadOnly() && !_bKeyColumns) ) + continue; + + Reference<XPropertySet> xColumn; + if(pField->IsPrimaryKey() || !_bKeyColumns) + xColumn = xColumnFactory->createDataDescriptor(); + if(xColumn.is()) + { + if(!_bKeyColumns) + ::dbaui::setColumnProperties(xColumn,pField); + else + xColumn->setPropertyValue(PROPERTY_NAME,makeAny(pField->GetName())); + + xAppend->appendByDescriptor(xColumn); + xColumn = NULL; + // now only the settings are missing + if(xColumns->hasByName(pField->GetName())) + { + xColumns->getByName(pField->GetName()) >>= xColumn; + if(xColumn.is()) + pField->copyColumnSettingsTo(xColumn); + } + else + { + OSL_ENSURE(sal_False, "OTableController::appendColumns: invalid field name!"); + } + + } + } + } + catch(const SQLException& ) + { + showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} +// ----------------------------------------------------------------------------- +void OTableController::appendPrimaryKey(Reference<XKeysSupplier>& _rxSup,sal_Bool _bNew) +{ + if(!_rxSup.is()) + return; // the database doesn't support keys + + OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!"); + Reference<XIndexAccess> xKeys(_rxSup->getKeys(),UNO_QUERY); + Reference<XPropertySet> xProp; + const sal_Int32 nCount = xKeys->getCount(); + for(sal_Int32 i=0;i< nCount ;++i) + { + xKeys->getByIndex(i) >>= xProp; + sal_Int32 nKeyType = 0; + xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; + if(KeyType::PRIMARY == nKeyType) + { + return; // primary key already exists after appending a column + } + } + Reference<XDataDescriptorFactory> xKeyFactory(xKeys,UNO_QUERY); + OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!"); + if ( !xKeyFactory.is() ) + return; + Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor(); + OSL_ENSURE(xKey.is(),"Key is null!"); + xKey->setPropertyValue(PROPERTY_TYPE,makeAny(KeyType::PRIMARY)); + + Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY); + if(xColSup.is()) + { + appendColumns(xColSup,_bNew,sal_True); + Reference<XNameAccess> xColumns = xColSup->getColumns(); + if(xColumns->hasElements()) + xAppend->appendByDescriptor(xKey); + } +} +// ----------------------------------------------------------------------------- +void OTableController::loadData() +{ + ////////////////////////////////////////////////////////////////////// + // Wenn Datenstruktur bereits vorhanden, Struktur leeren + m_vRowList.clear(); + + ::boost::shared_ptr<OTableRow> pTabEdRow; + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + ////////////////////////////////////////////////////////////////////// + // Datenstruktur mit Daten aus DatenDefinitionsObjekt fuellen + if(m_xTable.is() && xMetaData.is()) + { + Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY); + OSL_ENSURE(xColSup.is(),"No XColumnsSupplier!"); + Reference<XNameAccess> xColumns = xColSup->getColumns(); + OFieldDescription* pActFieldDescr = NULL; + String aType; + ////////////////////////////////////////////////////////////////////// + // ReadOnly-Flag + // Bei Drop darf keine Zeile editierbar sein. + // Bei Add duerfen nur die leeren Zeilen editierbar sein. + // Bei Add und Drop koennen alle Zeilen editiert werden. + // sal_Bool bReadOldRow = xMetaData->supportsAlterTableWithAddColumn() && xMetaData->supportsAlterTableWithDropColumn(); + sal_Bool bIsAlterAllowed = isAlterAllowed(); + Sequence< ::rtl::OUString> aColumns = xColumns->getElementNames(); + const ::rtl::OUString* pIter = aColumns.getConstArray(); + const ::rtl::OUString* pEnd = pIter + aColumns.getLength(); + + for(;pIter != pEnd;++pIter) + { + Reference<XPropertySet> xColumn; + xColumns->getByName(*pIter) >>= xColumn; + sal_Int32 nType = 0; + sal_Int32 nScale = 0; + sal_Int32 nPrecision = 0; + sal_Int32 nNullable = 0; + sal_Int32 nFormatKey = 0; + sal_Int32 nAlign = 0; + + sal_Bool bIsAutoIncrement = false, bIsCurrency = false; + ::rtl::OUString sName,sDescription,sTypeName; + Any aControlDefault; + + // get the properties from the column + xColumn->getPropertyValue(PROPERTY_NAME) >>= sName; + xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; + xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable; + xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bIsAutoIncrement; + xColumn->getPropertyValue(PROPERTY_ISCURRENCY) >>= bIsCurrency; + xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType; + xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale; + xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision; + + + if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_HELPTEXT)) + xColumn->getPropertyValue(PROPERTY_HELPTEXT) >>= sDescription; + if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_CONTROLDEFAULT)) + aControlDefault = xColumn->getPropertyValue(PROPERTY_CONTROLDEFAULT); + if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_FORMATKEY)) + xColumn->getPropertyValue(PROPERTY_FORMATKEY) >>= nFormatKey; + if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ALIGN)) + xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign; + + pTabEdRow.reset(new OTableRow()); + pTabEdRow->SetReadOnly(!bIsAlterAllowed); + // search for type + sal_Bool bForce; + ::rtl::OUString sCreate(RTL_CONSTASCII_USTRINGPARAM("x")); + TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,sCreate,nPrecision,nScale,bIsAutoIncrement,bForce); + if ( !pTypeInfo.get() ) + pTypeInfo = m_pTypeInfo; + pTabEdRow->SetFieldType( pTypeInfo, bForce ); + + pActFieldDescr = pTabEdRow->GetActFieldDescr(); + OSL_ENSURE(pActFieldDescr, "OTableController::loadData: invalid field description generated by the table row!"); + if ( pActFieldDescr ) + { + pActFieldDescr->SetName(sName); + pActFieldDescr->SetFormatKey(nFormatKey); + // pActFieldDescr->SetPrimaryKey(pPrimary->GetValue()); + pActFieldDescr->SetDescription(sDescription); + pActFieldDescr->SetAutoIncrement(bIsAutoIncrement); + pActFieldDescr->SetHorJustify(dbaui::mapTextJustify(nAlign)); + pActFieldDescr->SetCurrency(bIsCurrency); + + ////////////////////////////////////////////////////////////////////// + // Spezielle Daten + pActFieldDescr->SetIsNullable(nNullable); + pActFieldDescr->SetControlDefault(aControlDefault); + pActFieldDescr->SetPrecision(nPrecision); + pActFieldDescr->SetScale(nScale); + } + m_vRowList.push_back( pTabEdRow); + } + // fill the primary key information + Reference<XNameAccess> xKeyColumns = getKeyColumns(); + if(xKeyColumns.is()) + { + Sequence< ::rtl::OUString> aKeyColumns = xKeyColumns->getElementNames(); + const ::rtl::OUString* pKeyBegin = aKeyColumns.getConstArray(); + const ::rtl::OUString* pKeyEnd = pKeyBegin + aKeyColumns.getLength(); + + for(;pKeyBegin != pKeyEnd;++pKeyBegin) + { + ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator rowIter = m_vRowList.begin(); + ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator rowEnd = m_vRowList.end(); + for(;rowIter != rowEnd;++rowIter) + { + if((*rowIter)->GetActFieldDescr()->GetName() == *pKeyBegin) + { + (*rowIter)->SetPrimaryKey(sal_True); + break; + } + } + } + } + } + + ////////////////////////////////////////////////////////////////////// + // Leere Zeilen fuellen + + OTypeInfoMap::iterator aTypeIter = m_aTypeInfo.find(DataType::VARCHAR); + if(aTypeIter == m_aTypeInfo.end()) + aTypeIter = m_aTypeInfo.begin(); + + OSL_ENSURE(aTypeIter != m_aTypeInfo.end(),"We have no type infomation!"); + + bool bReadRow = !isAddAllowed(); + for(sal_Int32 i=m_vRowList.size(); i<128; i++ ) + { + pTabEdRow.reset(new OTableRow()); + pTabEdRow->SetReadOnly(bReadRow); + m_vRowList.push_back( pTabEdRow); + } +} +// ----------------------------------------------------------------------------- +Reference<XNameAccess> OTableController::getKeyColumns() const +{ + // use keys and indexes for excat postioning + // first the keys + Reference<XKeysSupplier> xKeySup(m_xTable,UNO_QUERY); + Reference<XIndexAccess> xKeys; + if(xKeySup.is()) + xKeys = xKeySup->getKeys(); + + Reference<XColumnsSupplier> xKeyColsSup; + Reference<XNameAccess> xKeyColumns; + if(xKeys.is()) + { + Reference<XPropertySet> xProp; + sal_Int32 nCount = xKeys->getCount(); + for(sal_Int32 i=0;i< nCount;++i) + { + xKeys->getByIndex(i) >>= xProp; + OSL_ENSURE(xProp.is(),"Key is invalid: NULL!"); + if ( xProp.is() ) + { + sal_Int32 nKeyType = 0; + xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; + if(KeyType::PRIMARY == nKeyType) + { + xKeyColsSup.set(xProp,UNO_QUERY); + OSL_ENSURE(xKeyColsSup.is(),"Columnsupplier is null!"); + xKeyColumns = xKeyColsSup->getColumns(); + break; + } + } + } + } + + return xKeyColumns; +} +// ----------------------------------------------------------------------------- +sal_Bool OTableController::checkColumns(sal_Bool _bNew) throw(::com::sun::star::sdbc::SQLException) +{ + sal_Bool bOk = sal_True; + sal_Bool bFoundPKey = sal_False; + Reference< XDatabaseMetaData > xMetaData = getMetaData( ); + DatabaseMetaData aMetaData( getConnection() ); + + ::comphelper::UStringMixEqual bCase(xMetaData.is() ? xMetaData->supportsMixedCaseQuotedIdentifiers() : sal_True); + ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin(); + ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end(); + for(;aIter != aEnd;++aIter) + { + OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr(); + if (pFieldDesc && pFieldDesc->GetName().getLength()) + { + bFoundPKey |= (*aIter)->IsPrimaryKey(); + // first check for duplicate names + ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter2 = aIter+1; + for(;aIter2 != aEnd;++aIter2) + { + OFieldDescription* pCompareDesc = (*aIter2)->GetActFieldDescr(); + if (pCompareDesc && bCase(pCompareDesc->GetName(),pFieldDesc->GetName())) + { + String strMessage = String(ModuleRes(STR_TABLEDESIGN_DUPLICATE_NAME)); + strMessage.SearchAndReplaceAscii("$column$", pFieldDesc->GetName()); + OSQLWarningBox( getView(), strMessage ).Execute(); + return sal_False; + } + } + } + } + if ( _bNew && !bFoundPKey && aMetaData.supportsPrimaryKeys() ) + { + String sTitle(ModuleRes(STR_TABLEDESIGN_NO_PRIM_KEY_HEAD)); + String sMsg(ModuleRes(STR_TABLEDESIGN_NO_PRIM_KEY)); + OSQLMessageBox aBox(getView(), sTitle,sMsg, WB_YES_NO_CANCEL | WB_DEF_YES); + + switch ( aBox.Execute() ) + { + case RET_YES: + { + ::boost::shared_ptr<OTableRow> pNewRow(new OTableRow()); + TOTypeInfoSP pTypeInfo = ::dbaui::queryPrimaryKeyType(m_aTypeInfo); + if ( !pTypeInfo.get() ) + break; + + pNewRow->SetFieldType( pTypeInfo ); + OFieldDescription* pActFieldDescr = pNewRow->GetActFieldDescr(); + + pActFieldDescr->SetAutoIncrement(sal_False); // #95927# pTypeInfo->bAutoIncrement + pActFieldDescr->SetIsNullable(ColumnValue::NO_NULLS); + + pActFieldDescr->SetName( createUniqueName(::rtl::OUString::createFromAscii("ID") )); + pActFieldDescr->SetPrimaryKey( sal_True ); + m_vRowList.insert(m_vRowList.begin(),pNewRow); + + static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->Invalidate(); + static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->RowInserted(0); + } + break; + case RET_CANCEL: + bOk = sal_False; + break; + } + } + return bOk; +} +// ----------------------------------------------------------------------------- +void OTableController::alterColumns() +{ + Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY_THROW); + OSL_ENSURE(xColSup.is(),"What happen here?!"); + + Reference<XNameAccess> xColumns = xColSup->getColumns(); + Reference<XIndexAccess> xIdxColumns(xColumns,UNO_QUERY_THROW); + OSL_ENSURE(xColumns.is(),"No columns"); + if ( !xColumns.is() ) + return; + Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY); // can be null + + sal_Int32 nColumnCount = xIdxColumns->getCount(); + Reference<XDrop> xDrop(xColumns,UNO_QUERY); // can be null + Reference<XAppend> xAppend(xColumns,UNO_QUERY); // can be null + Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); // can be null + + sal_Bool bReload = sal_False; // refresh the data + + // contains all columns names which are already handled those which are not in the list will be deleted + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + + ::std::map< ::rtl::OUString,sal_Bool,::comphelper::UStringMixLess> aColumns(xMetaData.is() ? (xMetaData->supportsMixedCaseQuotedIdentifiers() ? true : false): sal_True); + ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin(); + ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end(); + // first look for columns where something other than the name changed + sal_Int32 nPos = 0; + for(;aIter != aEnd;++aIter,++nPos) + { + OSL_ENSURE(*aIter,"OTableRow is null!"); + OFieldDescription* pField = (*aIter)->GetActFieldDescr(); + if ( !pField ) + continue; + if ( (*aIter)->IsReadOnly() ) + { + aColumns[pField->GetName()] = sal_True; + continue; + } + + Reference<XPropertySet> xColumn; + if ( xColumns->hasByName(pField->GetName()) ) + { + aColumns[pField->GetName()] = sal_True; + xColumns->getByName(pField->GetName()) >>= xColumn; + OSL_ENSURE(xColumn.is(),"Column is null!"); + + sal_Int32 nType=0,nPrecision=0,nScale=0,nNullable=0; + sal_Bool bAutoIncrement = false; + ::rtl::OUString sTypeName; + + xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType; + xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision; + xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale; + xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable; + xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bAutoIncrement; + + try { xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "no TypeName property?!" ); + // since this is a last minute fix for #i41785#, I want to be on the safe side, + // and catch errors here as early as possible (instead of the whole process of altering + // the columns failing) + // Normally, sdbcx::Column objects are expected to have a TypeName property + } + + // xColumn->getPropertyValue(PROPERTY_ISCURRENCY,::cppu::bool2any(pField->IsCurrency())); + // check if something changed + if((nType != pField->GetType() || + sTypeName != pField->GetTypeName() || + (nPrecision != pField->GetPrecision() && nPrecision ) || + nScale != pField->GetScale() || + nNullable != pField->GetIsNullable() || + bAutoIncrement != pField->IsAutoIncrement())&& + xColumnFactory.is()) + { + Reference<XPropertySet> xNewColumn; + xNewColumn = xColumnFactory->createDataDescriptor(); + ::dbaui::setColumnProperties(xNewColumn,pField); + // first try to alter the column + sal_Bool bNotOk = sal_False; + try + { + // first try if we can alter the column + if(xAlter.is()) + xAlter->alterColumnByName(pField->GetName(),xNewColumn); + } + catch(const SQLException&) + { + if(xDrop.is() && xAppend.is()) + { + String aMessage( ModuleRes( STR_TABLEDESIGN_ALTER_ERROR ) ); + aMessage.SearchAndReplaceAscii( "$column$", pField->GetName() ); + + SQLExceptionInfo aError( ::cppu::getCaughtException() ); + OSQLWarningBox aMsg( getView(), aMessage, WB_YES_NO | WB_DEF_YES , &aError ); + bNotOk = aMsg.Execute() == RET_YES; + } + else + throw; + } + // if something went wrong or we can't alter columns + // drop and append a new one + if((!xAlter.is() || bNotOk) && xDrop.is() && xAppend.is()) + { + xDrop->dropByName(pField->GetName()); + try + { + xAppend->appendByDescriptor(xNewColumn); + } + catch(const SQLException&) + { // an error occured so we try to reactivate the old one + xAppend->appendByDescriptor(xColumn); + throw; + } + } + // exceptions are caught outside + xNewColumn = NULL; + if(xColumns->hasByName(pField->GetName())) + xColumns->getByName(pField->GetName()) >>= xColumn; + bReload = sal_True; + } + + + } + else if(xColumnFactory.is() && xAlter.is() && nPos < nColumnCount) + { // we can't find the column so we could try it with the index before we drop and append a new column + try + { + Reference<XPropertySet> xNewColumn; + xNewColumn = xColumnFactory->createDataDescriptor(); + ::dbaui::setColumnProperties(xNewColumn,pField); + xAlter->alterColumnByIndex(nPos,xNewColumn); + if(xColumns->hasByName(pField->GetName())) + { // ask for the append by name + aColumns[pField->GetName()] = sal_True; + xColumns->getByName(pField->GetName()) >>= xColumn; + if(xColumn.is()) + pField->copyColumnSettingsTo(xColumn); + } + else + { + OSL_ENSURE(sal_False, "OTableController::alterColumns: invalid column (2)!"); + } + } + catch(const SQLException&) + { // we couldn't alter the column so we have to add new columns + bReload = sal_True; + if(xDrop.is() && xAppend.is()) + { + String aMessage(ModuleRes(STR_TABLEDESIGN_ALTER_ERROR)); + aMessage.SearchAndReplaceAscii("$column$",pField->GetName()); + OSQLWarningBox aMsg( getView(), aMessage, WB_YES_NO | WB_DEF_YES ); + if ( aMsg.Execute() != RET_YES ) + { + Reference<XPropertySet> xNewColumn(xIdxColumns->getByIndex(nPos),UNO_QUERY_THROW); + ::rtl::OUString sName; + xNewColumn->getPropertyValue(PROPERTY_NAME) >>= sName; + aColumns[sName] = sal_True; + aColumns[pField->GetName()] = sal_True; + continue; + } + } + else + throw; + } + } + else + bReload = sal_True; + } // for(sal_Int32 nPos = 0;aIter != aEnd;++aIter,++nPos) + // alter column settings + aIter = m_vRowList.begin(); + + // first look for columns where something other than the name changed + for(nPos = 0;aIter != aEnd;++aIter,++nPos) + { + OSL_ENSURE(*aIter,"OTableRow is null!"); + OFieldDescription* pField = (*aIter)->GetActFieldDescr(); + if ( !pField ) + continue; + if ( (*aIter)->IsReadOnly() ) + { + aColumns[pField->GetName()] = sal_True; + continue; + } + + Reference<XPropertySet> xColumn; + if ( xColumns->hasByName(pField->GetName()) ) + { + xColumns->getByName(pField->GetName()) >>= xColumn; + Reference<XPropertySetInfo> xInfo = xColumn->getPropertySetInfo(); + if ( xInfo->hasPropertyByName(PROPERTY_HELPTEXT) ) + xColumn->setPropertyValue(PROPERTY_HELPTEXT,makeAny(pField->GetDescription())); + if(xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT)) + xColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,pField->GetControlDefault()); + if(xInfo->hasPropertyByName(PROPERTY_FORMATKEY)) + xColumn->setPropertyValue(PROPERTY_FORMATKEY,makeAny(pField->GetFormatKey())); + if(xInfo->hasPropertyByName(PROPERTY_ALIGN)) + xColumn->setPropertyValue(PROPERTY_ALIGN,makeAny(dbaui::mapTextAllign(pField->GetHorJustify()))); + } // if ( xColumns->hasByName(pField->GetName()) ) + } + // second drop all columns which could be found by name + Reference<XNameAccess> xKeyColumns = getKeyColumns(); + // now we have to look for the columns who could be deleted + if ( xDrop.is() ) + { + Sequence< ::rtl::OUString> aColumnNames = xColumns->getElementNames(); + const ::rtl::OUString* pIter = aColumnNames.getConstArray(); + const ::rtl::OUString* pEnd = pIter + aColumnNames.getLength(); + for(;pIter != pEnd;++pIter) + { + if(aColumns.find(*pIter) == aColumns.end()) // found a column to delete + { + if(xKeyColumns.is() && xKeyColumns->hasByName(*pIter)) // check if this column is a member of the primary key + { + String aMsgT(ModuleRes(STR_TBL_COLUMN_IS_KEYCOLUMN)); + aMsgT.SearchAndReplaceAscii("$column$",*pIter); + String aTitle(ModuleRes(STR_TBL_COLUMN_IS_KEYCOLUMN_TITLE)); + OSQLMessageBox aMsg(getView(),aTitle,aMsgT,WB_YES_NO| WB_DEF_YES); + if(aMsg.Execute() == RET_YES) + { + xKeyColumns = NULL; + dropPrimaryKey(); + } + else + { + bReload = sal_True; + continue; + } + } + try + { + xDrop->dropByName(*pIter); + } + catch (const SQLException&) + { + String sError( ModuleRes( STR_TABLEDESIGN_COULD_NOT_DROP_COL ) ); + sError.SearchAndReplaceAscii( "$column$", *pIter ); + + SQLException aNewException; + aNewException.Message = sError; + aNewException.SQLState = ::rtl::OUString::createFromAscii( "S1000" ); + aNewException.NextException = ::cppu::getCaughtException(); + + throw aNewException; + } + } + } + } + + // third append the new columns + aIter = m_vRowList.begin(); + for(;aIter != aEnd;++aIter) + { + OSL_ENSURE(*aIter,"OTableRow is null!"); + OFieldDescription* pField = (*aIter)->GetActFieldDescr(); + if ( !pField || (*aIter)->IsReadOnly() || aColumns.find(pField->GetName()) != aColumns.end() ) + continue; + + Reference<XPropertySet> xColumn; + if(!xColumns->hasByName(pField->GetName())) + { + if(xColumnFactory.is() && xAppend.is()) + {// column not found by its name so we assume it is new + // Column is new + xColumn = xColumnFactory->createDataDescriptor(); + ::dbaui::setColumnProperties(xColumn,pField); + xAppend->appendByDescriptor(xColumn); + if(xColumns->hasByName(pField->GetName())) + { // ask for the append by name + aColumns[pField->GetName()] = sal_True; + xColumns->getByName(pField->GetName()) >>= xColumn; + if(xColumn.is()) + pField->copyColumnSettingsTo(xColumn); + } + else + { + OSL_ENSURE(sal_False, "OTableController::alterColumns: invalid column!"); + } + } + } + } + + + // check if we have to do something with the primary key + sal_Bool bNeedDropKey = sal_False; + sal_Bool bNeedAppendKey = sal_False; + if ( xKeyColumns.is() ) + { + aIter = m_vRowList.begin(); + for(;aIter != aEnd;++aIter) + { + OSL_ENSURE(*aIter,"OTableRow is null!"); + OFieldDescription* pField = (*aIter)->GetActFieldDescr(); + if ( !pField ) + continue; + + if ( pField->IsPrimaryKey() + && !xKeyColumns->hasByName( pField->GetName() ) + ) + { // new primary key column inserted which isn't already in the columns selection + bNeedDropKey = bNeedAppendKey = sal_True; + break; + } + else if ( !pField->IsPrimaryKey() + && xKeyColumns->hasByName( pField->GetName() ) + ) + { // found a column which currently is in the primary key, but is marked not to be anymore + bNeedDropKey = bNeedAppendKey = sal_True; + break; + } + } + } + else + { // no primary key available so we check if we should create one + bNeedAppendKey = sal_True; + } + + if ( bNeedDropKey && xKeyColumns.is() && xKeyColumns->getElementNames().getLength() ) + dropPrimaryKey(); + + if ( bNeedAppendKey ) + { + Reference< XKeysSupplier > xKeySup( m_xTable, UNO_QUERY ); + appendPrimaryKey( xKeySup ,sal_False); + } + + reSyncRows(); + + if ( bReload ) + reload(); +} +// ----------------------------------------------------------------------------- +void OTableController::dropPrimaryKey() +{ + SQLExceptionInfo aInfo; + try + { + Reference<XKeysSupplier> xKeySup(m_xTable,UNO_QUERY); + Reference<XIndexAccess> xKeys; + if(xKeySup.is()) + xKeys = xKeySup->getKeys(); + + if(xKeys.is()) + { + Reference<XPropertySet> xProp; + for(sal_Int32 i=0;i< xKeys->getCount();++i) + { + xProp.set(xKeys->getByIndex(i),UNO_QUERY); + sal_Int32 nKeyType = 0; + xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; + if(KeyType::PRIMARY == nKeyType) + { + Reference<XDrop> xDrop(xKeys,UNO_QUERY); + xDrop->dropByIndex(i); // delete the key + break; + } + } + } + } + catch(const SQLContext& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const SQLWarning& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const SQLException& e) + { + aInfo = SQLExceptionInfo(e); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + showError(aInfo); +} +// ----------------------------------------------------------------------------- +void OTableController::assignTable() +{ + ::rtl::OUString sComposedName; + // get the table + if(m_sName.getLength()) + { + Reference<XNameAccess> xNameAccess; + Reference<XTablesSupplier> xSup(getConnection(),UNO_QUERY); + if(xSup.is()) + { + xNameAccess = xSup->getTables(); + OSL_ENSURE(xNameAccess.is(),"no nameaccess for the queries!"); + + Reference<XPropertySet> xProp; + if(xNameAccess->hasByName(m_sName) && ::cppu::extractInterface(xProp,xNameAccess->getByName(m_sName)) && xProp.is()) + { + m_xTable = xProp; + startTableListening(); + + // check if we set the table editable + Reference<XDatabaseMetaData> xMeta = getConnection()->getMetaData(); + setEditable( xMeta.is() && !xMeta->isReadOnly() && (isAlterAllowed() || isDropAllowed() || isAddAllowed()) ); + if(!isEditable()) + { + ::std::for_each(m_vRowList.begin(),m_vRowList.end(),boost::bind( &OTableRow::SetReadOnly, _1, boost::cref( sal_True ))); + } + m_bNew = sal_False; + // be notified when the table is in disposing + InvalidateAll(); + } + } + } + //updateTitle(); +} +// ----------------------------------------------------------------------------- +sal_Bool OTableController::isAddAllowed() const +{ + Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY); + sal_Bool bAddAllowed = !m_xTable.is(); + if(xColsSup.is()) + bAddAllowed = Reference<XAppend>(xColsSup->getColumns(),UNO_QUERY).is(); + + try + { + Reference< XDatabaseMetaData > xMetaData = getMetaData( ); + bAddAllowed = bAddAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithAddColumn()); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + bAddAllowed = sal_False; + } + + return bAddAllowed; +} +// ----------------------------------------------------------------------------- +sal_Bool OTableController::isDropAllowed() const +{ + Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY); + sal_Bool bDropAllowed = !m_xTable.is(); + if(xColsSup.is()) + { + Reference<XNameAccess> xNameAccess = xColsSup->getColumns(); + bDropAllowed = Reference<XDrop>(xNameAccess,UNO_QUERY).is() && xNameAccess->hasElements(); + } + + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + bDropAllowed = bDropAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithDropColumn()); + + return bDropAllowed; +} +// ----------------------------------------------------------------------------- +sal_Bool OTableController::isAlterAllowed() const +{ + sal_Bool bAllowed(!m_xTable.is() || Reference<XAlterTable>(m_xTable,UNO_QUERY).is()); + return bAllowed; +} +// ----------------------------------------------------------------------------- +void OTableController::reSyncRows() +{ + sal_Bool bAlterAllowed = isAlterAllowed(); + sal_Bool bAddAllowed = isAddAllowed(); + ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aIter = m_vRowList.begin(); + ::std::vector< ::boost::shared_ptr<OTableRow> >::iterator aEnd = m_vRowList.end(); + for(;aIter != aEnd;++aIter) + { + OSL_ENSURE(*aIter,"OTableRow is null!"); + OFieldDescription* pField = (*aIter)->GetActFieldDescr(); + if ( pField ) + (*aIter)->SetReadOnly(!bAlterAllowed); + else + (*aIter)->SetReadOnly(!bAddAllowed); + + } + static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our informations + + getUndoMgr()->Clear(); // clear all undo redo things + setModified(sal_False); // and we are not modified yet +} +// ----------------------------------------------------------------------------- +::rtl::OUString OTableController::createUniqueName(const ::rtl::OUString& _rName) +{ + ::rtl::OUString sName = _rName; + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + + ::comphelper::UStringMixEqual bCase(xMetaData.is() ? xMetaData->supportsMixedCaseQuotedIdentifiers() : sal_True); + + ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin(); + ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end(); + for(sal_Int32 i=0;aIter != aEnd;++aIter) + { + OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr(); + if (pFieldDesc && pFieldDesc->GetName().getLength() && bCase(sName,pFieldDesc->GetName())) + { // found a second name of _rName so we need another + sName = _rName + ::rtl::OUString::valueOf(++i); + aIter = m_vRowList.begin(); // and retry + } + } + return sName; +} +// ----------------------------------------------------------------------------- +::rtl::OUString OTableController::getPrivateTitle() const +{ + ::rtl::OUString sTitle; + try + { + // get the table + if ( m_sName.getLength() && getConnection().is() ) + { + if ( m_xTable.is() ) + sTitle = ::dbtools::composeTableName( getConnection()->getMetaData(), m_xTable, ::dbtools::eInDataManipulation, false, false, false ); + else + sTitle = m_sName; + } + if ( !sTitle.getLength() ) + { + String aName = String(ModuleRes(STR_TBL_TITLE)); + sTitle = aName.GetToken(0,' '); + sTitle += ::rtl::OUString::valueOf(getCurrentStartNumber()); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return sTitle; +} +// ----------------------------------------------------------------------------- +void OTableController::reload() +{ + loadData(); // fill the column information form the table + static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our informations + getUndoMgr()->Clear(); // clear all undo redo things + setModified(sal_False); // and we are not modified yet + static_cast<OTableDesignView*>(getView())->Invalidate(); +} +// ----------------------------------------------------------------------------- +sal_Int32 OTableController::getFirstEmptyRowPosition() const +{ + sal_Int32 nRet = -1; + ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin(); + ::std::vector< ::boost::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end(); + for(;aIter != aEnd;++aIter) + { + if ( !*aIter || !(*aIter)->GetActFieldDescr() || !(*aIter)->GetActFieldDescr()->GetName().getLength() ) + { + nRet = aIter - m_vRowList.begin(); + break; + } + } + return nRet; +} +// ----------------------------------------------------------------------------- +bool OTableController::isAutoIncrementPrimaryKey() const +{ + return getSdbMetaData().isAutoIncrementPrimaryKey(); +} +// ----------------------------------------------------------------------------- |