/************************************************************************* * * 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: fmgridcl.cxx,v $ * $Revision: 1.64.94.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 * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_svx.hxx" #include "dbexch.hrc" #include "fmgridif.hxx" #include "fmitems.hxx" #include "fmprop.hrc" #include "fmresids.hrc" #include "fmservs.hxx" #include "fmurl.hxx" #include "formcontrolfactory.hxx" #include "gridcell.hxx" #include "gridcols.hxx" #include "svx/dbaexchange.hxx" #include "svx/dialmgr.hxx" #include "svx/dialogs.hrc" #include "svx/fmgridcl.hxx" #include "svx/svxdlg.hxx" #include "svx/svxids.hrc" #include "trace.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef _SVSTDARR_STRINGSDTOR #define _SVSTDARR_STRINGSDTOR #define _SVSTDARR_ULONGS #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star::uno; using namespace ::com::sun::star::view; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::sdbcx; using namespace ::com::sun::star::sdbc; using namespace ::com::sun::star::sdb; using namespace ::com::sun::star::form; using namespace ::com::sun::star::util; using namespace ::com::sun::star::container; using namespace ::cppu; using namespace ::svxform; using namespace ::svx; //============================================================================== //------------------------------------------------------------------------------ ::rtl::OUString FieldServiceFromId(sal_Int32 nID) { switch (nID) { case SID_FM_EDIT : return FM_COL_TEXTFIELD; case SID_FM_COMBOBOX : return FM_COL_COMBOBOX; case SID_FM_LISTBOX : return FM_COL_LISTBOX; case SID_FM_CHECKBOX : return FM_COL_CHECKBOX; case SID_FM_DATEFIELD : return FM_COL_DATEFIELD; case SID_FM_TIMEFIELD : return FM_COL_TIMEFIELD; case SID_FM_NUMERICFIELD : return FM_COL_NUMERICFIELD; case SID_FM_CURRENCYFIELD : return FM_COL_CURRENCYFIELD; case SID_FM_PATTERNFIELD : return FM_COL_PATTERNFIELD; case SID_FM_FORMATTEDFIELD : return FM_COL_FORMATTEDFIELD; } return ::rtl::OUString(); } //============================================================================== struct FmGridHeaderData { ODataAccessDescriptor aDropData; Point aDropPosPixel; sal_Int8 nDropAction; Reference< XInterface > xDroppedStatement; Reference< XInterface > xDroppedResultSet; }; //============================================================================== //------------------------------------------------------------------------------ const sal_Int16 nChangeTypeOffset = 1000; void SetMenuItem(const ImageList& rList, sal_uInt16 nID, Menu* pMenu, Menu& rNewMenu, sal_Bool bDesignMode = sal_True, sal_Int16 nOffset = nChangeTypeOffset) { pMenu->SetItemImage(nID, rList.GetImage(nID)); pMenu->EnableItem(nID, bDesignMode); rNewMenu.InsertItem(nID + nOffset, pMenu->GetItemText(nID)); rNewMenu.SetItemImage(nID + nOffset, rList.GetImage(nID)); rNewMenu.SetHelpId(nID + nOffset, pMenu->GetHelpId(nID)); rNewMenu.EnableItem(nID + nOffset, bDesignMode); } //------------------------------------------------------------------------------ FmGridHeader::FmGridHeader( BrowseBox* pParent, WinBits nWinBits) :EditBrowserHeader(pParent, nWinBits) ,DropTargetHelper(this) ,m_pImpl(new FmGridHeaderData) { } //------------------------------------------------------------------------------ FmGridHeader::~FmGridHeader() { delete m_pImpl; } //------------------------------------------------------------------------------ sal_uInt16 FmGridHeader::GetModelColumnPos(sal_uInt16 nId) const { return static_cast(GetParent())->GetModelColumnPos(nId); } //--------------------------------------------------------------------------------------- void FmGridHeader::notifyColumnSelect(sal_uInt16 nColumnId) { sal_uInt16 nPos = GetModelColumnPos(nColumnId); Reference< XIndexAccess > xColumns(((FmGridControl*)GetParent())->GetPeer()->getColumns(), UNO_QUERY); if ( nPos < xColumns->getCount() ) { Reference< XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY); if ( xSelSupplier.is() ) { Reference< XPropertySet > xColumn; xColumns->getByIndex(nPos) >>= xColumn; xSelSupplier->select(makeAny(xColumn)); } } } //------------------------------------------------------------------------------ void FmGridHeader::Select() { EditBrowserHeader::Select(); notifyColumnSelect(GetCurItemId()); } //------------------------------------------------------------------------------ void FmGridHeader::RequestHelp( const HelpEvent& rHEvt ) { sal_uInt16 nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) ); if ( nItemId ) { if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) ) { Rectangle aItemRect = GetItemRect( nItemId ); Point aPt = OutputToScreenPixel( aItemRect.TopLeft() ); aItemRect.Left() = aPt.X(); aItemRect.Top() = aPt.Y(); aPt = OutputToScreenPixel( aItemRect.BottomRight() ); aItemRect.Right() = aPt.X(); aItemRect.Bottom() = aPt.Y(); sal_uInt16 nPos = GetModelColumnPos(nItemId); Reference< ::com::sun::star::container::XIndexContainer > xColumns(static_cast(GetParent())->GetPeer()->getColumns()); try { Reference< ::com::sun::star::beans::XPropertySet > xColumn; ::cppu::extractInterface(xColumn, xColumns->getByIndex(nPos)); ::rtl::OUString aHelpText; xColumn->getPropertyValue(FM_PROP_HELPTEXT) >>= aHelpText; if ( aHelpText.getLength() ) { if ( rHEvt.GetMode() & HELPMODE_BALLOON ) Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aHelpText ); else Help::ShowQuickHelp( this, aItemRect, aHelpText ); return; } } catch(Exception&) { return; } } } EditBrowserHeader::RequestHelp( rHEvt ); } //------------------------------------------------------------------------------ sal_Int8 FmGridHeader::AcceptDrop( const AcceptDropEvent& rEvt ) { // drop allowed in design mode only if (!static_cast(GetParent())->IsDesignMode()) return DND_ACTION_NONE; // search for recognized formats const DataFlavorExVector& rFlavors = GetDataFlavorExVector(); if (OColumnTransferable::canExtractColumnDescriptor(rFlavors, CTF_COLUMN_DESCRIPTOR | CTF_FIELD_DESCRIPTOR)) return rEvt.mnAction; return DND_ACTION_NONE; } //------------------------------------------------------------------------------ sal_Int8 FmGridHeader::ExecuteDrop( const ExecuteDropEvent& _rEvt ) { if (!static_cast(GetParent())->IsDesignMode()) return DND_ACTION_NONE; TransferableDataHelper aDroppedData(_rEvt.maDropEvent.Transferable); // check the formats sal_Bool bColumnDescriptor = OColumnTransferable::canExtractColumnDescriptor(aDroppedData.GetDataFlavorExVector(), CTF_COLUMN_DESCRIPTOR); sal_Bool bFieldDescriptor = OColumnTransferable::canExtractColumnDescriptor(aDroppedData.GetDataFlavorExVector(), CTF_FIELD_DESCRIPTOR); if (!bColumnDescriptor && !bFieldDescriptor) { DBG_ERROR("FmGridHeader::ExecuteDrop: should never have reached this (no extractable format)!"); return DND_ACTION_NONE; } // extract the descriptor ::rtl::OUString sDatasouce, sCommand, sFieldName,sDatabaseLocation,sConnnectionResource; sal_Int32 nCommandType = CommandType::COMMAND; Reference< XPreparedStatement > xStatement; Reference< XResultSet > xResultSet; Reference< XPropertySet > xField; Reference< XConnection > xConnection; ODataAccessDescriptor aColumn = OColumnTransferable::extractColumnDescriptor(aDroppedData); if (aColumn.has(daDataSource)) aColumn[daDataSource] >>= sDatasouce; if (aColumn.has(daDatabaseLocation)) aColumn[daDatabaseLocation] >>= sDatabaseLocation; if (aColumn.has(daConnectionResource)) aColumn[daConnectionResource] >>= sConnnectionResource; if (aColumn.has(daCommand)) aColumn[daCommand] >>= sCommand; if (aColumn.has(daCommandType)) aColumn[daCommandType] >>= nCommandType; if (aColumn.has(daColumnName)) aColumn[daColumnName] >>= sFieldName; if (aColumn.has(daColumnObject))aColumn[daColumnObject] >>= xField; if (aColumn.has(daConnection)) aColumn[daConnection] >>= xConnection; if ( !sFieldName.getLength() || !sCommand.getLength() || ( !sDatasouce.getLength() && !sDatabaseLocation.getLength() && !xConnection.is() ) ) { DBG_ERROR( "FmGridHeader::ExecuteDrop: somebody started a nonsense drag operation!!" ); return DND_ACTION_NONE; } try { // need a connection if (!xConnection.is()) { // the transferable did not contain the connection -> build an own one try { ::rtl::OUString sSignificantSource( sDatasouce.getLength() ? sDatasouce : sDatabaseLocation ); xConnection = OStaticDataAccessTools().getConnection_withFeedback(sSignificantSource, ::rtl::OUString(),::rtl::OUString(),static_cast(GetParent())->getServiceManager()); } catch(NoSuchElementException&) { // allowed, means sDatasouce isn't a valid data source name .... } catch(Exception&) { DBG_ERROR("FmGridHeader::ExecuteDrop: could not retrieve the database access object !"); } if (!xConnection.is()) { DBG_ERROR("FmGridHeader::ExecuteDrop: could not retrieve the database access object !"); return DND_ACTION_NONE; } } // try to obtain the column object if (!xField.is()) { #ifdef DBG_UTIL Reference< XServiceInfo > xServiceInfo(xConnection, UNO_QUERY); DBG_ASSERT(xServiceInfo.is() && xServiceInfo->supportsService(SRV_SDB_CONNECTION), "FmGridHeader::ExecuteDrop: invalid connection (no database access connection !)"); #endif Reference< XNameAccess > xFields; switch (nCommandType) { case CommandType::TABLE: { Reference< XTablesSupplier > xSupplyTables(xConnection, UNO_QUERY); Reference< XColumnsSupplier > xSupplyColumns; xSupplyTables->getTables()->getByName(sCommand) >>= xSupplyColumns; xFields = xSupplyColumns->getColumns(); } break; case CommandType::QUERY: { Reference< XQueriesSupplier > xSupplyQueries(xConnection, UNO_QUERY); Reference< XColumnsSupplier > xSupplyColumns; xSupplyQueries->getQueries()->getByName(sCommand) >>= xSupplyColumns; xFields = xSupplyColumns->getColumns(); } break; default: { xStatement = xConnection->prepareStatement(sCommand); // not interested in any results Reference< XPropertySet > xStatProps(xStatement,UNO_QUERY); xStatProps->setPropertyValue(rtl::OUString::createFromAscii("MaxRows"), makeAny(sal_Int32(0))); xResultSet = xStatement->executeQuery(); Reference< XColumnsSupplier > xSupplyCols(xResultSet, UNO_QUERY); if (xSupplyCols.is()) xFields = xSupplyCols->getColumns(); } } if (xFields.is() && xFields->hasByName(sFieldName)) xFields->getByName(sFieldName) >>= xField; if (!xField.is()) { ::comphelper::disposeComponent(xStatement); return DND_ACTION_NONE; } } // do the drop asynchronously // (85957 - UI actions within the drop are not allowed, but we want to open a popup menu) m_pImpl->aDropData = aColumn; m_pImpl->aDropData[daConnection] <<= xConnection; m_pImpl->aDropData[daColumnObject] <<= xField; m_pImpl->nDropAction = _rEvt.mnAction; m_pImpl->aDropPosPixel = _rEvt.maPosPixel; m_pImpl->xDroppedStatement = xStatement; m_pImpl->xDroppedResultSet = xResultSet; PostUserEvent(LINK(this, FmGridHeader, OnAsyncExecuteDrop)); } catch (Exception&) { DBG_ERROR("FmGridHeader::ExecuteDrop: caught an exception while creatin' the column !"); ::comphelper::disposeComponent(xStatement); return sal_False; } return DND_ACTION_LINK; } //------------------------------------------------------------------------------ IMPL_LINK( FmGridHeader, OnAsyncExecuteDrop, void*, /*NOTINTERESTEDIN*/ ) { ::rtl::OUString sCommand, sFieldName,sURL; sal_Int32 nCommandType = CommandType::COMMAND; Reference< XPropertySet > xField; Reference< XConnection > xConnection; ::rtl::OUString sDatasouce = m_pImpl->aDropData.getDataSource(); if ( !sDatasouce.getLength() && m_pImpl->aDropData.has(daConnectionResource) ) m_pImpl->aDropData[daConnectionResource] >>= sURL; m_pImpl->aDropData[daCommand] >>= sCommand; m_pImpl->aDropData[daCommandType] >>= nCommandType; m_pImpl->aDropData[daColumnName] >>= sFieldName; m_pImpl->aDropData[daConnection] >>= xConnection; m_pImpl->aDropData[daColumnObject] >>= xField; try { // need number formats Reference< XNumberFormatsSupplier > xSupplier = OStaticDataAccessTools().getNumberFormats(xConnection, sal_True); Reference< XNumberFormats > xNumberFormats; if (xSupplier.is()) xNumberFormats = xSupplier->getNumberFormats(); if (!xNumberFormats.is()) { ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet); ::comphelper::disposeComponent(m_pImpl->xDroppedStatement); return 0L; } // Vom Feld werden nun zwei Informationen benoetigt: // a.) Name des Feldes fuer Label und ControlSource // b.) FormatKey, um festzustellen, welches Feld erzeugt werden soll sal_Int32 nDataType = 0; xField->getPropertyValue(FM_PROP_FIELDTYPE) >>= nDataType; // diese Datentypen koennen im Gridcontrol nicht verarbeitet werden switch (nDataType) { case DataType::LONGVARBINARY: case DataType::BINARY: case DataType::VARBINARY: case DataType::OTHER: ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet); ::comphelper::disposeComponent(m_pImpl->xDroppedStatement); return 0L; } // Erstellen der Column Reference< XIndexContainer > xCols(static_cast(GetParent())->GetPeer()->getColumns()); Reference< XGridColumnFactory > xFactory(xCols, UNO_QUERY); Point aPos = OutputToScreenPixel(m_pImpl->aDropPosPixel); sal_uInt16 nColId = GetItemId(m_pImpl->aDropPosPixel); // EinfuegePosition, immer vor der aktuellen Spalte sal_uInt16 nPos = GetModelColumnPos(nColId); Reference< XPropertySet > xCol, xSecondCol; // erzeugen der Column in abhaengigkeit vom type, default textfeld SvULongs aPossibleTypes; switch (nDataType) { case DataType::BIT: case DataType::BOOLEAN: aPossibleTypes.Insert(SID_FM_CHECKBOX, aPossibleTypes.Count()); break; case DataType::TINYINT: case DataType::SMALLINT: case DataType::INTEGER: aPossibleTypes.Insert(SID_FM_NUMERICFIELD, aPossibleTypes.Count()); aPossibleTypes.Insert(SID_FM_FORMATTEDFIELD, aPossibleTypes.Count()); break; case DataType::REAL: case DataType::DOUBLE: case DataType::NUMERIC: case DataType::DECIMAL: aPossibleTypes.Insert(SID_FM_FORMATTEDFIELD, aPossibleTypes.Count()); aPossibleTypes.Insert(SID_FM_NUMERICFIELD, aPossibleTypes.Count()); break; case DataType::TIMESTAMP: aPossibleTypes.Insert(SID_FM_TWOFIELDS_DATE_N_TIME, aPossibleTypes.Count()); aPossibleTypes.Insert(SID_FM_DATEFIELD, aPossibleTypes.Count()); aPossibleTypes.Insert(SID_FM_TIMEFIELD, aPossibleTypes.Count()); aPossibleTypes.Insert(SID_FM_FORMATTEDFIELD, aPossibleTypes.Count()); break; case DataType::DATE: aPossibleTypes.Insert(SID_FM_DATEFIELD, aPossibleTypes.Count()); aPossibleTypes.Insert(SID_FM_FORMATTEDFIELD, aPossibleTypes.Count()); break; case DataType::TIME: aPossibleTypes.Insert(SID_FM_TIMEFIELD, aPossibleTypes.Count()); aPossibleTypes.Insert(SID_FM_FORMATTEDFIELD, aPossibleTypes.Count()); break; case DataType::CHAR: case DataType::VARCHAR: case DataType::LONGVARCHAR: default: aPossibleTypes.Insert(SID_FM_EDIT, aPossibleTypes.Count()); aPossibleTypes.Insert(SID_FM_FORMATTEDFIELD, aPossibleTypes.Count()); break; } // if it's a currency field, a a "currency field" option try { if ( ::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField) && ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY))) aPossibleTypes.Insert(SID_FM_CURRENCYFIELD, 0); } catch(Exception&) { DBG_ERROR("FmGridHeader::ExecuteDrop: Exception occured!"); } sal_Int32 nPreferedType = -1; sal_Bool bDateNTimeCol = sal_False; if (aPossibleTypes.Count() != 0) { nPreferedType = aPossibleTypes[0]; if ((m_pImpl->nDropAction == DND_ACTION_LINK) && (aPossibleTypes.Count() > 1)) { ImageList aImageList( SVX_RES(RID_SVXIMGLIST_FMEXPL) ); PopupMenu aInsertMenu(SVX_RES(RID_SVXMNU_COLS)); PopupMenu aTypeMenu; PopupMenu* pMenu = aInsertMenu.GetPopupMenu(SID_FM_INSERTCOL); for (sal_uInt32 i=0; iaDropPosPixel); } bDateNTimeCol = nPreferedType == SID_FM_TWOFIELDS_DATE_N_TIME; sal_uInt16 nColCount = bDateNTimeCol ? 2 : 1; ::rtl::OUString sFieldService; while (nColCount--) { if (bDateNTimeCol) nPreferedType = nColCount ? SID_FM_DATEFIELD : SID_FM_TIMEFIELD; sFieldService = FieldServiceFromId(nPreferedType); Reference< XPropertySet > xThisRoundCol; if ( sFieldService.getLength() ) xThisRoundCol = xFactory->createColumn(sFieldService); if (nColCount) xSecondCol = xThisRoundCol; else xCol = xThisRoundCol; } } if (!xCol.is() || (bDateNTimeCol && !xSecondCol.is())) { ::comphelper::disposeComponent(xCol); // in case only the creation of the second column failed ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet); ::comphelper::disposeComponent(m_pImpl->xDroppedStatement); return 0L; } if (bDateNTimeCol) { String sTimePostfix( SVX_RES( RID_STR_POSTFIX_TIME ) ); xCol->setPropertyValue(FM_PROP_LABEL, makeAny( ::rtl::OUString( sFieldName + sTimePostfix ) ) ); String sDatePostfix( SVX_RES( RID_STR_POSTFIX_DATE ) ); xSecondCol->setPropertyValue(FM_PROP_LABEL, makeAny( ::rtl::OUString( sFieldName + sDatePostfix ) ) ); } else xCol->setPropertyValue(FM_PROP_LABEL, makeAny(sFieldName)); FormControlFactory aControlFactory( ::comphelper::getProcessServiceFactory() ); aControlFactory.initializeControlModel( DocumentClassification::classifyHostDocument( xCols ), xCol ); aControlFactory.initializeFieldDependentProperties( xField, xCol, xNumberFormats ); xCol->setPropertyValue(FM_PROP_CONTROLSOURCE, makeAny(sFieldName)); if ( xSecondCol.is() ) xSecondCol->setPropertyValue(FM_PROP_CONTROLSOURCE, makeAny(sFieldName)); if (bDateNTimeCol) { String sRealName,sPurePostfix; String aPostfix[] = { String( SVX_RES( RID_STR_POSTFIX_DATE ) ), String( SVX_RES( RID_STR_POSTFIX_TIME ) ) }; for ( size_t i=0; i<2; ++i ) { sPurePostfix = aPostfix[i]; sPurePostfix.EraseLeadingChars(' '); sPurePostfix.EraseLeadingChars('('); sPurePostfix.EraseTrailingChars(')'); sRealName = sFieldName; sRealName += '_'; sRealName += sPurePostfix; if (i) xSecondCol->setPropertyValue(FM_PROP_NAME, makeAny(::rtl::OUString(sRealName))); else xCol->setPropertyValue(FM_PROP_NAME, makeAny(::rtl::OUString(sRealName))); } } else xCol->setPropertyValue(FM_PROP_NAME, makeAny(sFieldName)); // jetzt einfuegen Any aElement; aElement <<= xCol; xCols->insertByIndex(nPos, aElement); if (bDateNTimeCol) { aElement <<= xSecondCol; xCols->insertByIndex(nPos == (sal_uInt16)-1 ? nPos : ++nPos, aElement); } // ist die component::Form an die Datenbankangebunden? Reference< XFormComponent > xFormCp(xCols, UNO_QUERY); Reference< XPropertySet > xForm(xFormCp->getParent(), UNO_QUERY); if (xForm.is()) { if (!::comphelper::getString(xForm->getPropertyValue(FM_PROP_DATASOURCE)).getLength()) { if ( sDatasouce.getLength() ) xForm->setPropertyValue(FM_PROP_DATASOURCE, makeAny(sDatasouce)); else xForm->setPropertyValue(FM_PROP_URL, makeAny(sURL)); } if (!::comphelper::getString(xForm->getPropertyValue(FM_PROP_COMMAND)).getLength()) { xForm->setPropertyValue(FM_PROP_COMMAND, makeAny(sCommand)); Any aCommandType; switch (nCommandType) { case CommandType::TABLE: aCommandType <<= (sal_Int32)CommandType::TABLE; break; case CommandType::QUERY: aCommandType <<= (sal_Int32)CommandType::QUERY; break; default: aCommandType <<= (sal_Int32)CommandType::COMMAND; xForm->setPropertyValue(FM_PROP_ESCAPE_PROCESSING, bool2any((sal_Bool)(2 == nCommandType))); break; } xForm->setPropertyValue(FM_PROP_COMMANDTYPE, aCommandType); } } } catch (Exception&) { DBG_ERROR("FmGridHeader::OnAsyncExecuteDrop: caught an exception while creatin' the column !"); ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet); ::comphelper::disposeComponent(m_pImpl->xDroppedStatement); return 0L; } ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet); ::comphelper::disposeComponent(m_pImpl->xDroppedStatement); return 1L; } //------------------------------------------------------------------------------ void FmGridHeader::PreExecuteColumnContextMenu(sal_uInt16 nColId, PopupMenu& rMenu) { sal_Bool bDesignMode = static_cast(GetParent())->IsDesignMode(); Reference< ::com::sun::star::container::XIndexContainer > xCols(static_cast(GetParent())->GetPeer()->getColumns()); // Aufbau des Insert Menues // mark the column if nColId != HEADERBAR_ITEM_NOTFOUND if(nColId > 0) { sal_uInt16 nPos2 = GetModelColumnPos(nColId); Reference< ::com::sun::star::container::XIndexContainer > xColumns(static_cast(GetParent())->GetPeer()->getColumns()); Reference< ::com::sun::star::beans::XPropertySet> xColumn; ::cppu::extractInterface(xColumn, xColumns->getByIndex(nPos2)); Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY); if (xSelSupplier.is()) xSelSupplier->select(makeAny(xColumn)); } // EinfuegePosition, immer vor der aktuellen Spalte sal_uInt16 nPos = GetModelColumnPos(nColId); sal_Bool bMarked = nColId && static_cast(GetParent())->isColumnMarked(nColId); ImageList aImageList( SVX_RES(RID_SVXIMGLIST_FMEXPL) ); PopupMenu* pControlMenu = new PopupMenu; PopupMenu* pMenu = rMenu.GetPopupMenu(SID_FM_INSERTCOL); if (pMenu) { SetMenuItem(aImageList, SID_FM_EDIT, pMenu, *pControlMenu, bDesignMode); SetMenuItem(aImageList, SID_FM_CHECKBOX, pMenu, *pControlMenu, bDesignMode); SetMenuItem(aImageList, SID_FM_COMBOBOX, pMenu, *pControlMenu, bDesignMode); SetMenuItem(aImageList, SID_FM_LISTBOX, pMenu, *pControlMenu, bDesignMode); SetMenuItem(aImageList, SID_FM_DATEFIELD, pMenu, *pControlMenu, bDesignMode); SetMenuItem(aImageList, SID_FM_TIMEFIELD, pMenu, *pControlMenu, bDesignMode); SetMenuItem(aImageList, SID_FM_NUMERICFIELD, pMenu, *pControlMenu, bDesignMode); SetMenuItem(aImageList, SID_FM_CURRENCYFIELD, pMenu, *pControlMenu, bDesignMode); SetMenuItem(aImageList, SID_FM_PATTERNFIELD, pMenu, *pControlMenu, bDesignMode); SetMenuItem(aImageList, SID_FM_FORMATTEDFIELD, pMenu, *pControlMenu, bDesignMode); } if (pMenu && xCols.is() && nColId) { Reference< ::com::sun::star::beans::XPropertySet > xSet; ::cppu::extractInterface(xSet, xCols->getByIndex(nPos)); sal_Int16 nClassId; xSet->getPropertyValue(FM_PROP_CLASSID) >>= nClassId; Reference< ::com::sun::star::io::XPersistObject > xServiceQuestion(xSet, UNO_QUERY); sal_Int32 nColType = xServiceQuestion.is() ? getColumnTypeByModelName(xServiceQuestion->getServiceName()) : 0; if (nColType == TYPE_TEXTFIELD) { // edit fields and formatted fields have the same service name, thus getColumnTypeByModelName returns TYPE_TEXTFIELD // in both cases. And as columns don't have an ::com::sun::star::lang::XServiceInfo interface, we have to distinguish both // types via the existence of special properties Reference< ::com::sun::star::beans::XPropertySet > xProps(xSet, UNO_QUERY); if (xProps.is()) { Reference< ::com::sun::star::beans::XPropertySetInfo > xPropsInfo = xProps->getPropertySetInfo(); if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(FM_PROP_FORMATSSUPPLIER)) nColType = TYPE_FORMATTEDFIELD; } } pControlMenu->EnableItem(SID_FM_EDIT + nChangeTypeOffset, bDesignMode && (nColType != TYPE_TEXTFIELD)); pControlMenu->EnableItem(SID_FM_COMBOBOX + nChangeTypeOffset, bDesignMode && (nColType != TYPE_COMBOBOX)); pControlMenu->EnableItem(SID_FM_LISTBOX + nChangeTypeOffset, bDesignMode && (nColType != TYPE_LISTBOX)); pControlMenu->EnableItem(SID_FM_CHECKBOX + nChangeTypeOffset, bDesignMode && (nColType != TYPE_CHECKBOX)); pControlMenu->EnableItem(SID_FM_DATEFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_DATEFIELD)); pControlMenu->EnableItem(SID_FM_NUMERICFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_NUMERICFIELD)); pControlMenu->EnableItem(SID_FM_TIMEFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_TIMEFIELD)); pControlMenu->EnableItem(SID_FM_CURRENCYFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_CURRENCYFIELD)); pControlMenu->EnableItem(SID_FM_PATTERNFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_PATTERNFIELD)); pControlMenu->EnableItem(SID_FM_FORMATTEDFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_FORMATTEDFIELD)); rMenu.SetPopupMenu(SID_FM_CHANGECOL, pControlMenu); } rMenu.EnableItem(SID_FM_INSERTCOL, bDesignMode && xCols.is()); rMenu.EnableItem(SID_FM_DELETECOL, bDesignMode && bMarked && xCols.is()); rMenu.EnableItem(SID_FM_CHANGECOL, bDesignMode && bMarked && xCols.is()); rMenu.EnableItem(SID_FM_SHOW_PROPERTY_BROWSER, bDesignMode && bMarked && xCols.is()); PopupMenu* pShowColsMenu = rMenu.GetPopupMenu(SID_FM_SHOWCOLS); sal_uInt16 nHiddenCols = 0; if (pShowColsMenu) { if (xCols.is()) { // check for hidden cols Reference< ::com::sun::star::beans::XPropertySet > xCurCol; Any aHidden,aName; for (sal_uInt16 i=0; igetCount(); ++i) { ::cppu::extractInterface(xCurCol, xCols->getByIndex(i)); DBG_ASSERT(xCurCol.is(), "FmGridHeader::PreExecuteColumnContextMenu : the Peer has invalid columns !"); aHidden = xCurCol->getPropertyValue(FM_PROP_HIDDEN); DBG_ASSERT(aHidden.getValueType().getTypeClass() == TypeClass_BOOLEAN, "FmGridHeader::PreExecuteColumnContextMenu : the property 'hidden' should be boolean !"); if (::comphelper::getBOOL(aHidden)) { // put the column name into the 'show col' menu if (nHiddenCols < 16) { // (only the first 16 items to keep the menu rather small) aName = xCurCol->getPropertyValue(FM_PROP_LABEL); pShowColsMenu->InsertItem(nHiddenCols + 1, ::comphelper::getString(aName), 0, nHiddenCols); // the ID is arbitrary, but should be unique within the whole menu } ++nHiddenCols; } } } pShowColsMenu->EnableItem(SID_FM_SHOWCOLS_MORE, xCols.is() && (nHiddenCols > 16)); pShowColsMenu->EnableItem(SID_FM_SHOWALLCOLS, xCols.is() && (nHiddenCols > 0)); } // allow the 'hide column' item ? sal_Bool bAllowHide = bMarked; // a column is marked bAllowHide = bAllowHide || (!bDesignMode && (nPos != (sal_uInt16)-1)); // OR we are in alive mode and have hit a column bAllowHide = bAllowHide && xCols.is(); // AND we have a column container bAllowHide = bAllowHide && (xCols->getCount()-nHiddenCols > 1); // AND there are at least two visible columns rMenu.EnableItem(SID_FM_HIDECOL, bAllowHide); sal_Bool bChecked = sal_False; if (bMarked) { SfxViewFrame* pCurrentFrame = SfxViewFrame::Current(); SfxItemState eState = SFX_ITEM_UNKNOWN; // ask the bindings of the current view frame (which should be the one we're residing in) for the state if (pCurrentFrame) { SfxPoolItem* pItem = NULL; eState = pCurrentFrame->GetBindings().QueryState(SID_FM_CTL_PROPERTIES, pItem); if (eState >= SFX_ITEM_AVAILABLE && pItem ) { bChecked = pItem->ISA(SfxBoolItem) && ((SfxBoolItem*)pItem)->GetValue(); rMenu.CheckItem(SID_FM_SHOW_PROPERTY_BROWSER,bChecked); } delete pItem; } } } enum InspectorAction { eOpenInspector, eCloseInspector, eUpdateInspector, eNone }; //------------------------------------------------------------------------------ void FmGridHeader::PostExecuteColumnContextMenu(sal_uInt16 nColId, const PopupMenu& rMenu, sal_uInt16 nExecutionResult) { Reference< ::com::sun::star::container::XIndexContainer > xCols(static_cast(GetParent())->GetPeer()->getColumns()); sal_uInt16 nPos = GetModelColumnPos(nColId); // remove and delet the menu we inserted in PreExecuteColumnContextMenu PopupMenu* pControlMenu = rMenu.GetPopupMenu(SID_FM_CHANGECOL); delete pControlMenu; ::rtl::OUString aFieldType; sal_Bool bReplace = sal_False; InspectorAction eInspectorAction = eNone; Reference< XPropertySet > xColumnToInspect; switch (nExecutionResult) { case SID_FM_DELETECOL: { Reference< XInterface > xCol; ::cppu::extractInterface(xCol, xCols->getByIndex(nPos)); xCols->removeByIndex(nPos); ::comphelper::disposeComponent(xCol); } break; case SID_FM_SHOW_PROPERTY_BROWSER: eInspectorAction = rMenu.IsItemChecked( SID_FM_SHOW_PROPERTY_BROWSER ) ? eOpenInspector : eCloseInspector; xColumnToInspect.set( xCols->getByIndex( nPos ), UNO_QUERY ); break; case SID_FM_EDIT + nChangeTypeOffset: bReplace = sal_True; case SID_FM_EDIT: aFieldType = FM_COL_TEXTFIELD; break; case SID_FM_COMBOBOX + nChangeTypeOffset: bReplace = sal_True; case SID_FM_COMBOBOX: aFieldType = FM_COL_COMBOBOX; break; case SID_FM_LISTBOX + nChangeTypeOffset: bReplace = sal_True; case SID_FM_LISTBOX: aFieldType = FM_COL_LISTBOX; break; case SID_FM_CHECKBOX + nChangeTypeOffset: bReplace = sal_True; case SID_FM_CHECKBOX: aFieldType = FM_COL_CHECKBOX; break; case SID_FM_DATEFIELD + nChangeTypeOffset: bReplace = sal_True; case SID_FM_DATEFIELD: aFieldType = FM_COL_DATEFIELD; break; case SID_FM_TIMEFIELD + nChangeTypeOffset: bReplace = sal_True; case SID_FM_TIMEFIELD: aFieldType = FM_COL_TIMEFIELD; break; case SID_FM_NUMERICFIELD + nChangeTypeOffset: bReplace = sal_True; case SID_FM_NUMERICFIELD: aFieldType = FM_COL_NUMERICFIELD; break; case SID_FM_CURRENCYFIELD + nChangeTypeOffset: bReplace = sal_True; case SID_FM_CURRENCYFIELD: aFieldType = FM_COL_CURRENCYFIELD; break; case SID_FM_PATTERNFIELD + nChangeTypeOffset: bReplace = sal_True; case SID_FM_PATTERNFIELD: aFieldType = FM_COL_PATTERNFIELD; break; case SID_FM_FORMATTEDFIELD + nChangeTypeOffset: bReplace = sal_True; case SID_FM_FORMATTEDFIELD: aFieldType = FM_COL_FORMATTEDFIELD; break; case SID_FM_HIDECOL: { Reference< ::com::sun::star::beans::XPropertySet > xCurCol; ::cppu::extractInterface(xCurCol, xCols->getByIndex(nPos)); xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny((sal_Bool)sal_True)); } break; case SID_FM_SHOWCOLS_MORE: { //CHINA001 FmShowColsDialog dlg(NULL); //CHINA001 dlg.SetColumns(xCols); //CHINA001 dlg.Execute(); SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); if(pFact) { AbstractFmShowColsDialog* pDlg = pFact->CreateFmShowColsDialog(NULL, RID_SVX_DLG_SHOWGRIDCOLUMNS); DBG_ASSERT(pDlg, "Dialogdiet fail!");//CHINA001 pDlg->SetColumns(xCols); pDlg->Execute(); delete pDlg; } } break; case SID_FM_SHOWALLCOLS: { // just iterate through all the cols ... Reference< ::com::sun::star::beans::XPropertySet > xCurCol; for (sal_uInt16 i=0; igetCount(); ++i) { ::cppu::extractInterface(xCurCol, xCols->getByIndex(i)); xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny((sal_Bool)sal_False)); } // TODO : there must be a more clever way to do this .... // with the above the view is updated after every single model update ... } break; default: if (nExecutionResult>0 && nExecutionResult<=16) { // it was a "show column/" command (there are at most 16 such items) // search the nExecutionResult'th hidden col Reference< ::com::sun::star::beans::XPropertySet > xCurCol; for (sal_uInt16 i=0; igetCount() && nExecutionResult; ++i) { ::cppu::extractInterface(xCurCol, xCols->getByIndex(i)); Any aHidden = xCurCol->getPropertyValue(FM_PROP_HIDDEN); if (::comphelper::getBOOL(aHidden)) if (!--nExecutionResult) { xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny((sal_Bool)sal_False)); break; } } } break; } if ( aFieldType.getLength() ) { try { Reference< XGridColumnFactory > xFactory( xCols, UNO_QUERY_THROW ); Reference< XPropertySet > xNewCol( xFactory->createColumn( aFieldType ), UNO_SET_THROW ); if ( bReplace ) { // ein paar Properties hinueberretten Reference< XPropertySet > xReplaced( xCols->getByIndex( nPos ), UNO_QUERY ); OStaticDataAccessTools().TransferFormComponentProperties( xReplaced, xNewCol, Application::GetSettings().GetUILocale() ); xCols->replaceByIndex( nPos, makeAny( xNewCol ) ); ::comphelper::disposeComponent( xReplaced ); eInspectorAction = eUpdateInspector; xColumnToInspect = xNewCol; } else { // Standardlabel setzen ::rtl::OUString sLabelBase = String( SVX_RES( RID_STR_COLUMN ) ); // disambiguate the name Reference< XNameAccess > xColNames( xCols, UNO_QUERY ); ::rtl::OUString sLabel; for ( sal_Int32 i=1; i<65535; ++i ) { sLabel = sLabelBase; sLabel += ::rtl::OUString::valueOf( (sal_Int32)i ); if ( !xColNames->hasByName( sLabel ) ) break; } // no fallback in case the name is not unique (which is rather improbable) .... xNewCol->setPropertyValue( FM_PROP_LABEL, makeAny( sLabel ) ); xNewCol->setPropertyValue( FM_PROP_NAME, makeAny( sLabel ) ); FormControlFactory determine( ::comphelper::getProcessServiceFactory() ); determine.initializeControlModel( DocumentClassification::classifyHostDocument( xCols ), xNewCol ); xCols->insertByIndex( nPos, makeAny( xNewCol ) ); } } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } } SfxViewFrame* pCurrentFrame = SfxViewFrame::Current(); OSL_ENSURE( pCurrentFrame, "FmGridHeader::PostExecuteColumnContextMenu: no view frame -> no bindings -> no property browser!" ); if ( pCurrentFrame ) { if ( eInspectorAction == eUpdateInspector ) { if ( !pCurrentFrame->HasChildWindow( SID_FM_SHOW_PROPERTIES ) ) eInspectorAction = eNone; } if ( eInspectorAction != eNone ) { FmInterfaceItem aIFaceItem( SID_FM_SHOW_PROPERTY_BROWSER, xColumnToInspect ); SfxBoolItem aShowItem( SID_FM_SHOW_PROPERTIES, eInspectorAction == eCloseInspector ? FALSE : TRUE ); pCurrentFrame->GetBindings().GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SFX_CALLMODE_ASYNCHRON, &aIFaceItem, &aShowItem, 0L ); } } } //------------------------------------------------------------------------------ void FmGridHeader::triggerColumnContextMenu( const ::Point& _rPreferredPos ) { // the affected col sal_uInt16 nColId = GetItemId( _rPreferredPos ); // the menu PopupMenu aContextMenu( SVX_RES( RID_SVXMNU_COLS ) ); // let derivees modify the menu PreExecuteColumnContextMenu( nColId, aContextMenu ); aContextMenu.RemoveDisabledEntries( sal_True, sal_True ); // execute the menu sal_uInt16 nResult = aContextMenu.Execute( this, _rPreferredPos ); // let derivees handle the result PostExecuteColumnContextMenu( nColId, aContextMenu, nResult ); } //------------------------------------------------------------------------------ void FmGridHeader::Command(const CommandEvent& rEvt) { switch (rEvt.GetCommand()) { case COMMAND_CONTEXTMENU: { if (!rEvt.IsMouseEvent()) return; triggerColumnContextMenu( rEvt.GetMousePosPixel() ); } break; default: EditBrowserHeader::Command(rEvt); } } //------------------------------------------------------------------------------ FmGridControl::FmGridControl( Reference< ::com::sun::star::lang::XMultiServiceFactory > _rxFactory, Window* pParent, FmXGridPeer* _pPeer, WinBits nBits) :DbGridControl(_rxFactory, pParent, nBits) ,m_pPeer(_pPeer) ,m_nCurrentSelectedColumn(-1) ,m_nMarkedColumnId(BROWSER_INVALIDID) ,m_bSelecting(sal_False) ,m_bInColumnMove(sal_False) { EnableInteractiveRowHeight( ); } //------------------------------------------------------------------------------ void FmGridControl::Command(const CommandEvent& _rEvt) { if ( COMMAND_CONTEXTMENU == _rEvt.GetCommand() ) { FmGridHeader* pMyHeader = static_cast< FmGridHeader* >( GetHeaderBar() ); if ( pMyHeader && !_rEvt.IsMouseEvent() ) { // context menu requested by keyboard if ( 1 == GetSelectColumnCount() || IsDesignMode() ) { sal_uInt16 nSelId = GetColumnId( sal::static_int_cast< USHORT >( FirstSelectedColumn() ) ); ::Rectangle aColRect( GetFieldRectPixel( 0, nSelId, sal_False ) ); Point aRelativePos( pMyHeader->ScreenToOutputPixel( OutputToScreenPixel( aColRect.TopCenter() ) ) ); pMyHeader->triggerColumnContextMenu( aRelativePos, FmGridHeader::AccessControl() ); // handled return; } } } DbGridControl::Command( _rEvt ); } // ::com::sun::star::beans::XPropertyChangeListener //------------------------------------------------------------------------------ void FmGridControl::propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& evt) { if (evt.PropertyName == FM_PROP_ROWCOUNT) { // if we're not in the main thread call AdjustRows asynchronously implAdjustInSolarThread(sal_True); return; } const DbGridRowRef& xRow = GetCurrentRow(); // waehrend Positionierung wird kein abgleich der Properties vorgenommen Reference xSet(evt.Source,UNO_QUERY); if (xRow.Is() && (::cppu::any2bool(xSet->getPropertyValue(FM_PROP_ISNEW))|| CompareBookmark(getDataSource()->getBookmark(), xRow->GetBookmark()))) { if (evt.PropertyName == FM_PROP_ISMODIFIED) { // modified or clean ? GridRowStatus eStatus = ::comphelper::getBOOL(evt.NewValue) ? GRS_MODIFIED : GRS_CLEAN; if (eStatus != xRow->GetStatus()) { xRow->SetStatus(eStatus); vos::OGuard aGuard( Application::GetSolarMutex() ); RowModified(GetCurrentPos()); } } } } //------------------------------------------------------------------------------ void FmGridControl::SetDesignMode(sal_Bool bMode) { sal_Bool bOldMode = IsDesignMode(); DbGridControl::SetDesignMode(bMode); if (bOldMode != bMode) { if (!bMode) { // selection aufheben markColumn(USHRT_MAX); } else { Reference< ::com::sun::star::container::XIndexContainer > xColumns(GetPeer()->getColumns()); Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY); if (xSelSupplier.is()) { Any aSelection = xSelSupplier->getSelection(); Reference< ::com::sun::star::beans::XPropertySet > xColumn; if (aSelection.getValueType().getTypeClass() == TypeClass_INTERFACE) ::cppu::extractInterface(xColumn, aSelection); Reference< XInterface > xCurrent; for (sal_uInt16 i=0; igetCount(); ++i) { ::cppu::extractInterface(xCurrent, xColumns->getByIndex(i)); if (xCurrent == xColumn) { markColumn(GetColumnIdFromModelPos(i)); break; } } } } } } //------------------------------------------------------------------------------ void FmGridControl::DeleteSelectedRows() { if (!m_pSeekCursor) return; // how many rows are selected? sal_Int32 nSelectedRows = GetSelectRowCount(); // the current line should be deleted but it is currently in edit mode if ( IsCurrentAppending() ) return; // is the insert row selected if (GetEmptyRow().Is() && IsRowSelected(GetRowCount() - 1)) nSelectedRows -= 1; // nothing to do if (nSelectedRows <= 0) return; // try to confirm the delete Reference< ::com::sun::star::frame::XDispatchProvider > xDispatcher = (::com::sun::star::frame::XDispatchProvider*)GetPeer(); if (xDispatcher.is()) { ::com::sun::star::util::URL aUrl; aUrl.Complete = FMURL_CONFIRM_DELETION; // #100312# ------------ Reference< ::com::sun::star::util::XURLTransformer > xTransformer( ::comphelper::getProcessServiceFactory()->createInstance( ::rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer")), UNO_QUERY); if( xTransformer.is() ) xTransformer->parseStrict( aUrl ); Reference< ::com::sun::star::frame::XDispatch > xDispatch = xDispatcher->queryDispatch(aUrl, rtl::OUString(), 0); Reference< ::com::sun::star::form::XConfirmDeleteListener > xConfirm(xDispatch, UNO_QUERY); if (xConfirm.is()) { ::com::sun::star::sdb::RowChangeEvent aEvent; aEvent.Source = (Reference< XInterface > )(*getDataSource()); aEvent.Rows = nSelectedRows; aEvent.Action = ::com::sun::star::sdb::RowChangeAction::DELETE; if (!xConfirm->confirmDelete(aEvent)) return; } } const MultiSelection* pRowSelection = GetSelection(); if ( pRowSelection && pRowSelection->IsAllSelected() ) { BeginCursorAction(); CursorWrapper* pCursor = getDataSource(); Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*pCursor, UNO_QUERY); try { pCursor->beforeFirst(); while( pCursor->next() ) xUpdateCursor->deleteRow(); SetUpdateMode(sal_False); SetNoSelection(); xUpdateCursor->moveToInsertRow(); } catch(const Exception&) { OSL_ENSURE(0,"Exception caught while deleting rows!"); } // An den DatenCursor anpassen AdjustDataSource(sal_True); EndCursorAction(); SetUpdateMode(sal_True); } else { Reference< ::com::sun::star::sdbcx::XDeleteRows > xDeleteThem((Reference< XInterface >)*getDataSource(), UNO_QUERY); // colect the bookmarks of the selected rows Sequence < Any> aBookmarks = getSelectionBookmarks(); // determine the next row to position after deletion Any aBookmark; sal_Bool bNewPos = sal_False; // if the current row isn't selected we take the row as row after deletion OSL_ENSURE( GetCurrentRow().Is(), "FmGridControl::DeleteSelectedRows: no current row here?" ); // crash reports suggest it can happen we don't have a current row - how? // #154303# / 2008-04-23 / frank.schoenheit@sun.com if ( !IsRowSelected( GetCurrentPos() ) && !IsCurrentAppending() && GetCurrentRow().Is() ) { aBookmark = GetCurrentRow()->GetBookmark(); bNewPos = sal_True; } else { // we look for the first row after the selected block for selection long nIdx = LastSelectedRow() + 1; if (nIdx < GetRowCount() - 1) { // there is a next row to position on if (SeekCursor(nIdx)) { GetSeekRow()->SetState(m_pSeekCursor, sal_True); bNewPos = sal_True; // if it's not the row for inserting we keep the bookmark if (!IsInsertionRow(nIdx)) aBookmark = m_pSeekCursor->getBookmark(); } } else { // we look for the first row before the selected block for selection after deletion nIdx = FirstSelectedRow() - 1; if (nIdx >= 0 && SeekCursor(nIdx)) { GetSeekRow()->SetState(m_pSeekCursor, sal_True); bNewPos = sal_True; aBookmark = m_pSeekCursor->getBookmark(); } } } // Sind alle Zeilen Selectiert // Zweite bedingung falls keine einguegeZeile existiert sal_Bool bAllSelected = GetTotalCount() == nSelectedRows || GetRowCount() == nSelectedRows; BeginCursorAction(); // now delete the row Sequence aDeletedRows; SetUpdateMode( FALSE ); try { aDeletedRows = xDeleteThem->deleteRows(aBookmarks); } catch(SQLException&) { } SetUpdateMode( TRUE ); // how many rows are deleted? sal_Int32 nDeletedRows = 0; const sal_Int32* pSuccess = aDeletedRows.getConstArray(); for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++) { if (pSuccess[i]) ++nDeletedRows; } // sind Zeilen geloescht worden? if (nDeletedRows) { SetUpdateMode(sal_False); SetNoSelection(); try { // did we delete all the rows than try to move to the next possible row if (nDeletedRows == aDeletedRows.getLength()) { // there exists a new position to move on if (bNewPos) { if (aBookmark.hasValue()) getDataSource()->moveToBookmark(aBookmark); // no valid bookmark so move to the insert row else { Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY); xUpdateCursor->moveToInsertRow(); } } else { Reference< ::com::sun::star::beans::XPropertySet > xSet((Reference< XInterface >)*m_pDataCursor, UNO_QUERY); sal_Int32 nRecordCount(0); xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount; if ( m_pDataCursor->rowDeleted() ) --nRecordCount; // there are no rows left and we have an insert row if (!nRecordCount && GetEmptyRow().Is()) { Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY); xUpdateCursor->moveToInsertRow(); } else if (nRecordCount) // move to the first row getDataSource()->first(); } } // not all the rows where deleted, so move to the first row which remained in the resultset else { for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++) { if (!pSuccess[i]) { getDataSource()->moveToBookmark(aBookmarks.getConstArray()[i]); break; } } } } catch(const Exception&) { try { // positioning went wrong so try to move to the first row getDataSource()->first(); } catch(const Exception&) { } } // An den DatenCursor anpassen AdjustDataSource(sal_True); // es konnten nicht alle Zeilen geloescht werden // da nie nicht geloeschten wieder selektieren if (nDeletedRows < nSelectedRows) { // waren alle selektiert if (bAllSelected) { SelectAll(); if (IsInsertionRow(GetRowCount() - 1)) // einfuegeZeile nicht SelectRow(GetRowCount() - 1, sal_False); } else { // select the remaining rows for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++) { try { if (!pSuccess[i]) { m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark()); SetSeekPos(m_pSeekCursor->getRow() - 1); SelectRow(GetSeekPos()); } } catch(const Exception&) { // keep the seekpos in all cases SetSeekPos(m_pSeekCursor->getRow() - 1); } } } } EndCursorAction(); SetUpdateMode(sal_True); } else // Zeile konnte nicht geloescht werden { EndCursorAction(); try { // currentrow is the insert row? if (!IsCurrentAppending()) getDataSource()->refreshRow(); } catch(const Exception&) { } } } // if there is no selection anymore we can start editing if (!GetSelectRowCount()) ActivateCell(); } // XCurrentRecordListener //------------------------------------------------------------------------------ void FmGridControl::positioned(const ::com::sun::star::lang::EventObject& /*rEvent*/) { TRACE_RANGE("FmGridControl::positioned"); // position on the data source (force it to be done in the main thread) implAdjustInSolarThread(sal_False); } //------------------------------------------------------------------------------ sal_Bool FmGridControl::commit() { // Commit nur ausfuehren, wenn nicht bereits ein Update vom ::com::sun::star::form::component::GridControl ausgefuehrt // wird if (!IsUpdating()) { if (Controller().Is() && Controller()->IsModified()) { if (!SaveModified()) return sal_False; } } return sal_True; } //------------------------------------------------------------------------------ void FmGridControl::inserted(const ::com::sun::star::lang::EventObject& /*rEvent*/) { const DbGridRowRef& xRow = GetCurrentRow(); if (!xRow.Is()) return; // Zeile ist eingefuegt worden, dann den status und mode zuruecksetzen xRow->SetState(m_pDataCursor, sal_False); xRow->SetNew(sal_False); } // XCancelUpdateRecordListener //------------------------------------------------------------------------------ void FmGridControl::restored(const ::com::sun::star::lang::EventObject& rEvent) { if (!GetCurrentRow().Is()) return; sal_Bool bAppending = GetCurrentRow()->IsNew(); sal_Bool bDirty = GetCurrentRow()->IsModified(); if (bAppending && (EditBrowseBox::IsModified() || bDirty)) { if (Controller().Is()) Controller()->ClearModified(); // jetzt die Zeile herausnehmen RowRemoved(GetRowCount() - 1, 1, sal_True); GetNavigationBar().InvalidateAll(); } positioned(rEvent); } //------------------------------------------------------------------------------ BrowserHeader* FmGridControl::imp_CreateHeaderBar(BrowseBox* pParent) { DBG_ASSERT( pParent == this, "FmGridControl::imp_CreateHeaderBar: parent?" ); return new FmGridHeader( pParent ); } //------------------------------------------------------------------------------ void FmGridControl::markColumn(sal_uInt16 nId) { if (GetHeaderBar() && m_nMarkedColumnId != nId) { // deselektieren if (m_nMarkedColumnId != BROWSER_INVALIDID) { HeaderBarItemBits aBits = GetHeaderBar()->GetItemBits(m_nMarkedColumnId) & ~HIB_FLAT; GetHeaderBar()->SetItemBits(m_nMarkedColumnId, aBits); } if (nId != BROWSER_INVALIDID) { HeaderBarItemBits aBits = GetHeaderBar()->GetItemBits(nId) | HIB_FLAT; GetHeaderBar()->SetItemBits(nId, aBits); } m_nMarkedColumnId = nId; } } //------------------------------------------------------------------------------ sal_Bool FmGridControl::isColumnMarked(sal_uInt16 nId) const { return m_nMarkedColumnId == nId; } //------------------------------------------------------------------------------ long FmGridControl::QueryMinimumRowHeight() { long nMinimalLogicHeight = 20; // 0.2 cm long nMinimalPixelHeight = LogicToPixel( Point( 0, nMinimalLogicHeight ), MAP_10TH_MM ).Y(); return CalcZoom( nMinimalPixelHeight ); } //------------------------------------------------------------------------------ void FmGridControl::RowHeightChanged() { DbGridControl::RowHeightChanged(); Reference< XPropertySet > xModel( GetPeer()->getColumns(), UNO_QUERY ); DBG_ASSERT( xModel.is(), "FmGridControl::RowHeightChanged: no model!" ); if ( xModel.is() ) { try { sal_Int32 nUnzoomedPixelHeight = CalcReverseZoom( GetDataRowHeight() ); Any aProperty = makeAny( (sal_Int32)PixelToLogic( Point( 0, nUnzoomedPixelHeight ), MAP_10TH_MM ).Y() ); xModel->setPropertyValue( FM_PROP_ROWHEIGHT, aProperty ); } catch( const Exception& ) { OSL_ENSURE( sal_False, "FmGridControl::RowHeightChanged: caught an exception!" ); } } } //------------------------------------------------------------------------------ void FmGridControl::ColumnResized(sal_uInt16 nId) { DbGridControl::ColumnResized(nId); // Wert ans model uebergeben DbGridColumn* pCol = DbGridControl::GetColumns().GetObject(GetModelColumnPos(nId)); Reference< ::com::sun::star::beans::XPropertySet > xColModel(pCol->getModel()); if (xColModel.is()) { Any aWidth; sal_Int32 nColumnWidth = GetColumnWidth(nId); nColumnWidth = CalcReverseZoom(nColumnWidth); // Umrechnen in 10THMM aWidth <<= (sal_Int32)PixelToLogic(Point(nColumnWidth,0),MAP_10TH_MM).X(); xColModel->setPropertyValue(FM_PROP_WIDTH, aWidth); } } //------------------------------------------------------------------------------ void FmGridControl::CellModified() { DbGridControl::CellModified(); GetPeer()->CellModified(); } //------------------------------------------------------------------------------ void FmGridControl::BeginCursorAction() { DbGridControl::BeginCursorAction(); m_pPeer->stopCursorListening(); } //------------------------------------------------------------------------------ void FmGridControl::EndCursorAction() { m_pPeer->startCursorListening(); DbGridControl::EndCursorAction(); } //------------------------------------------------------------------------------ void FmGridControl::ColumnMoved(sal_uInt16 nId) { m_bInColumnMove = sal_True; DbGridControl::ColumnMoved(nId); Reference< ::com::sun::star::container::XIndexContainer > xColumns(GetPeer()->getColumns()); if (xColumns.is()) { // suchen der Spalte und verschieben im Model // ColumnPos holen DbGridColumn* pCol = DbGridControl::GetColumns().GetObject(GetModelColumnPos(nId)); Reference< ::com::sun::star::beans::XPropertySet > xCol; // Einfuegen muß sich an den Column Positionen orientieren sal_Int32 i; Reference< XInterface > xCurrent; for (i = 0; !xCol.is() && i < xColumns->getCount(); i++) { ::cppu::extractInterface(xCurrent, xColumns->getByIndex(i)); if (xCurrent == pCol->getModel()) { xCol = pCol->getModel(); break; } } DBG_ASSERT(i < xColumns->getCount(), "Falscher ::com::sun::star::sdbcx::Index"); xColumns->removeByIndex(i); Any aElement; aElement <<= xCol; xColumns->insertByIndex(GetModelColumnPos(nId), aElement); pCol->setModel(xCol); // if the column which is shown here is selected ... if ( isColumnSelected(nId,pCol) ) markColumn(nId); // ... -> mark it } m_bInColumnMove = sal_False; } //------------------------------------------------------------------------------ void FmGridControl::InitColumnsByModels(const Reference< ::com::sun::star::container::XIndexContainer >& xColumns) { // Spalten wieder neu setzen // wenn es nur eine HandleColumn gibt, dann nicht if (GetModelColCount()) { RemoveColumns(); InsertHandleColumn(); } if (!xColumns.is()) return; SetUpdateMode(sal_False); // Einfuegen mu� sich an den Column Positionen orientieren sal_Int32 i; String aName; Any aWidth; for (i = 0; i < xColumns->getCount(); ++i) { Reference< ::com::sun::star::beans::XPropertySet > xCol; ::cppu::extractInterface(xCol, xColumns->getByIndex(i)); aName = (const sal_Unicode*)::comphelper::getString(xCol->getPropertyValue(FM_PROP_LABEL)); aWidth = xCol->getPropertyValue(FM_PROP_WIDTH); sal_Int32 nWidth = 0; if (aWidth >>= nWidth) nWidth = LogicToPixel(Point(nWidth,0),MAP_10TH_MM).X(); AppendColumn(aName, (sal_uInt16)nWidth); DbGridColumn* pCol = DbGridControl::GetColumns().GetObject(i); pCol->setModel(xCol); } // und jetzt noch die hidden columns rausnehmen // (wir haben das nicht gleich in der oberen Schleife gemacht, da wir dann Probleme mit den // IDs der Spalten bekommen haetten : AppendColumn vergibt die automatisch, die Spalte _nach_ // einer versteckten braucht aber eine um eine erhoehte ID .... Any aHidden; for (i = 0; i < xColumns->getCount(); ++i) { Reference< ::com::sun::star::beans::XPropertySet > xCol; ::cppu::extractInterface(xCol, xColumns->getByIndex(i)); aHidden = xCol->getPropertyValue(FM_PROP_HIDDEN); if (::comphelper::getBOOL(aHidden)) HideColumn(GetColumnIdFromModelPos((sal_uInt16)i)); } SetUpdateMode(sal_True); } //------------------------------------------------------------------------------ void FmGridControl::InitColumnByField( DbGridColumn* _pColumn, const Reference< XPropertySet >& _rxColumnModel, const Reference< XNameAccess >& _rxFieldsByNames, const Reference< XIndexAccess >& _rxFieldsByIndex ) { DBG_ASSERT( _rxFieldsByNames == _rxFieldsByIndex, "FmGridControl::InitColumnByField: invalid container interfaces!" ); // lookup the column which belongs to the control source ::rtl::OUString sFieldName; _rxColumnModel->getPropertyValue( FM_PROP_CONTROLSOURCE ) >>= sFieldName; Reference< XPropertySet > xField; _rxColumnModel->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField; if ( !xField.is() && /*sFieldName.getLength() && */_rxFieldsByNames->hasByName( sFieldName ) ) // #i93452# do not check for name length _rxFieldsByNames->getByName( sFieldName ) >>= xField; // determine the position of this column sal_Int32 nFieldPos = -1; if ( xField.is() ) { Reference< XPropertySet > xCheck; sal_Int32 nFieldCount = _rxFieldsByIndex->getCount(); for ( sal_Int32 i = 0; i < nFieldCount; ++i) { _rxFieldsByIndex->getByIndex( i ) >>= xCheck; if ( xField.get() == xCheck.get() ) { nFieldPos = i; break; } } } if ( xField.is() && ( nFieldPos >= 0 ) ) { // some data types are not allowed sal_Int32 nDataType = DataType::OTHER; xField->getPropertyValue( FM_PROP_FIELDTYPE ) >>= nDataType; sal_Bool bIllegalType = sal_False; switch ( nDataType ) { case DataType::LONGVARBINARY: case DataType::BINARY: case DataType::VARBINARY: case DataType::OTHER: bIllegalType = sal_True; break; } if ( bIllegalType ) { _pColumn->SetObject( (sal_Int16)nFieldPos ); return; } // handle readonly columns sal_Bool bReadOnly = sal_True; xField->getPropertyValue( FM_PROP_ISREADONLY ) >>= bReadOnly; _pColumn->SetReadOnly( bReadOnly ); } // the control type is determined by the ColumnServiceName static ::rtl::OUString s_sPropColumnServiceName( RTL_CONSTASCII_USTRINGPARAM( "ColumnServiceName" ) ); if ( !::comphelper::hasProperty( s_sPropColumnServiceName, _rxColumnModel ) ) return; _pColumn->setModel( _rxColumnModel ); ::rtl::OUString sColumnServiceName; _rxColumnModel->getPropertyValue( s_sPropColumnServiceName ) >>= sColumnServiceName; sal_Int32 nTypeId = getColumnTypeByModelName( sColumnServiceName ); _pColumn->CreateControl( nFieldPos, xField, nTypeId ); } //------------------------------------------------------------------------------ void FmGridControl::InitColumnsByFields(const Reference< ::com::sun::star::container::XIndexAccess >& _rxFields) { if ( !_rxFields.is() ) return; // Spalten initialisieren Reference< XIndexContainer > xColumns( GetPeer()->getColumns() ); Reference< XNameAccess > xFieldsAsNames( _rxFields, UNO_QUERY ); // Einfuegen mu� sich an den Column Positionen orientieren for (sal_Int32 i = 0; i < xColumns->getCount(); i++) { DbGridColumn* pCol = GetColumns().GetObject(i); Reference< XPropertySet > xColumnModel; ::cppu::extractInterface( xColumnModel, xColumns->getByIndex( i ) ); InitColumnByField( pCol, xColumnModel, xFieldsAsNames, _rxFields ); } } //------------------------------------------------------------------------------ void FmGridControl::HideColumn(sal_uInt16 nId) { DbGridControl::HideColumn(nId); sal_uInt16 nPos = GetModelColumnPos(nId); if (nPos == (sal_uInt16)-1) return; DbGridColumn* pColumn = GetColumns().GetObject(nPos); if (pColumn->IsHidden()) GetPeer()->columnHidden(pColumn); if (nId == m_nMarkedColumnId) m_nMarkedColumnId = (sal_uInt16)-1; } // ----------------------------------------------------------------------------- sal_Bool FmGridControl::isColumnSelected(sal_uInt16 /*nId*/,DbGridColumn* _pColumn) { OSL_ENSURE(_pColumn,"Column can not be null!"); sal_Bool bSelected = sal_False; // if the column which is shown here is selected ... Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(GetPeer()->getColumns(), UNO_QUERY); if ( xSelSupplier.is() ) { Reference< ::com::sun::star::beans::XPropertySet > xColumn; xSelSupplier->getSelection() >>= xColumn; bSelected = (xColumn.get() == _pColumn->getModel().get()); } return bSelected; } //------------------------------------------------------------------------------ void FmGridControl::ShowColumn(sal_uInt16 nId) { DbGridControl::ShowColumn(nId); sal_uInt16 nPos = GetModelColumnPos(nId); if (nPos == (sal_uInt16)-1) return; DbGridColumn* pColumn = GetColumns().GetObject(nPos); if (!pColumn->IsHidden()) GetPeer()->columnVisible(pColumn); // if the column which is shown here is selected ... if ( isColumnSelected(nId,pColumn) ) markColumn(nId); // ... -> mark it } //------------------------------------------------------------------------------ sal_Bool FmGridControl::selectBookmarks(const Sequence< Any >& _rBookmarks) { vos::OGuard aGuard( Application::GetSolarMutex() ); // need to lock the SolarMutex so that no paint call disturbs us ... if ( !m_pSeekCursor ) { DBG_ERROR( "FmGridControl::selectBookmarks: no seek cursor!" ); return sal_False; } const Any* pBookmark = _rBookmarks.getConstArray(); const Any* pBookmarkEnd = pBookmark + _rBookmarks.getLength(); SetNoSelection(); sal_Bool bAllSuccessfull = sal_True; try { for (; pBookmark != pBookmarkEnd; ++pBookmark) { // move the seek cursor to the row given if (m_pSeekCursor->moveToBookmark(*pBookmark)) SelectRow( m_pSeekCursor->getRow() - 1); else bAllSuccessfull = sal_False; } } catch(Exception&) { DBG_ERROR("FmGridControl::selectBookmarks: could not move to one of the bookmarks!"); return sal_False; } return bAllSuccessfull; } //------------------------------------------------------------------------------ Sequence< Any> FmGridControl::getSelectionBookmarks() { // lock our update so no paint-triggered seeks interfere ... SetUpdateMode(sal_False); sal_Int32 nSelectedRows = GetSelectRowCount(), i = 0; Sequence< Any> aBookmarks(nSelectedRows); if ( nSelectedRows ) { Any* pBookmarks = (Any*)aBookmarks.getArray(); // (I'm not sure if the problem isn't deeper : The szenario : a large table displayed by a grid with a // thread-safe cursor (dBase). On loading the sdb-cursor started a counting thread. While this counting progress // was running, I tried do delete 3 records from within the grid. Deletion caused a SeekCursor, which did a // m_pSeekCursor->moveRelative and a m_pSeekCursor->getPosition. // Unfortunally the first call caused a propertyChanged(RECORDCOUNT) which resulted in a repaint of the // navigation bar and the grid. The latter itself will result in SeekRow calls. So after (successfully) returning // from the moveRelative the getPosition returns an invalid value. And so the SeekCursor fails. // In the consequence ALL parts of code where two calls to the seek cursor are done, while the second call _relys_ on // the first one, should be secured against recursion, with a broad-minded interpretion of "recursion" : if any of these // code parts is executed, no other should be accessible. But this sounds very difficult to achieve .... // ) // The next problem caused by the same behaviuor (SeekCursor causes a propertyChanged) : when adjusting rows we implicitly // change our selection. So a "FirstSelected(); SeekCursor(); NextSelected();" may produce unpredictable results. // That's why we _first_ collect the indicies of the selected rows and _then_ their bookmarks. long nIdx = FirstSelectedRow(); while (nIdx >= 0) { // (we misuse the bookmarks array for this ...) pBookmarks[i++] <<= (sal_Int32)nIdx; nIdx = NextSelectedRow(); } DBG_ASSERT(i == nSelectedRows, "FmGridControl::DeleteSelectedRows : could not collect the row indicies !"); for (i=0; iSetState(m_pSeekCursor, sal_True); pBookmarks[i] = m_pSeekCursor->getBookmark(); } #ifdef DBG_UTIL else DBG_ERROR("FmGridControl::DeleteSelectedRows : a bookmark could not be determined !"); #endif } } SetUpdateMode(sal_True); // if one of the SeekCursor-calls failed .... aBookmarks.realloc(i); // (the alternative : while collecting the bookmarks lock our propertyChanged, this should resolve both our problems. // but this would be incompatible as we need a locking flag, then ...) return aBookmarks; } // ----------------------------------------------------------------------------- namespace { ::rtl::OUString getColumnPropertyFromPeer(FmXGridPeer* _pPeer,sal_Int32 _nPosition,const ::rtl::OUString& _sPropName) { ::rtl::OUString sRetText; if ( _pPeer && _nPosition != -1) { Reference xIndex = _pPeer->getColumns(); if ( xIndex.is() && xIndex->getCount() > _nPosition ) { Reference xProp; xIndex->getByIndex( _nPosition ) >>= xProp; if ( xProp.is() ) xProp->getPropertyValue( _sPropName ) >>= sRetText; } } return sRetText; } } // Object data and state ------------------------------------------------------ ::rtl::OUString FmGridControl::GetAccessibleObjectName( ::svt::AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const { ::rtl::OUString sRetText; switch( _eObjType ) { case ::svt::BBTYPE_BROWSEBOX: if ( GetPeer() ) { Reference xProp(GetPeer()->getColumns(),UNO_QUERY); if ( xProp.is() ) xProp->getPropertyValue(FM_PROP_NAME) >>= sRetText; } break; case ::svt::BBTYPE_COLUMNHEADERCELL: sRetText = getColumnPropertyFromPeer( GetPeer(), GetModelColumnPos( sal::static_int_cast< sal_uInt16 >(_nPosition)), FM_PROP_LABEL); break; default: sRetText = DbGridControl::GetAccessibleObjectName(_eObjType,_nPosition); } return sRetText; } // ----------------------------------------------------------------------------- ::rtl::OUString FmGridControl::GetAccessibleObjectDescription( ::svt::AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const { ::rtl::OUString sRetText; switch( _eObjType ) { case ::svt::BBTYPE_BROWSEBOX: if ( GetPeer() ) { Reference xProp(GetPeer()->getColumns(),UNO_QUERY); if ( xProp.is() ) xProp->getPropertyValue(FM_PROP_HELPTEXT) >>= sRetText; } break; case ::svt::BBTYPE_COLUMNHEADERCELL: sRetText = getColumnPropertyFromPeer( GetPeer(), GetModelColumnPos( sal::static_int_cast< sal_uInt16 >(_nPosition)), FM_PROP_HELPTEXT); break; default: sRetText = DbGridControl::GetAccessibleObjectDescription(_eObjType,_nPosition); } return sRetText; } // ----------------------------------------------------------------------------- void FmGridControl::Select() { DbGridControl::Select(); // ... betrifft das unsere Spalten ? const MultiSelection* pColumnSelection = GetColumnSelection(); sal_uInt16 nSelectedColumn = pColumnSelection && pColumnSelection->GetSelectCount() ? sal::static_int_cast< sal_uInt16 >( ((MultiSelection*)pColumnSelection)->FirstSelected()) : SAL_MAX_UINT16; // die HandleColumn wird nicht selektiert switch (nSelectedColumn) { case -1 : break; // no selection case 0 : nSelectedColumn = SAL_MAX_UINT16; break; // handle col can't be seledted default : // get the model col pos instead of the view col pos nSelectedColumn = GetModelColumnPos(GetColumnIdFromViewPos(nSelectedColumn - 1)); break; } if (nSelectedColumn != m_nCurrentSelectedColumn) { // VOR dem Aufruf des select am SelectionSupplier ! m_nCurrentSelectedColumn = nSelectedColumn; if (!m_bSelecting) { m_bSelecting = sal_True; try { Reference< XIndexAccess > xColumns(GetPeer()->getColumns(), UNO_QUERY); Reference< XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY); if (xSelSupplier.is()) { if (nSelectedColumn != SAL_MAX_UINT16) { Reference< XPropertySet > xColumn; ::cppu::extractInterface(xColumn,xColumns->getByIndex(nSelectedColumn)); xSelSupplier->select(makeAny(xColumn)); } else { xSelSupplier->select(Any()); } } } catch(Exception&) { } m_bSelecting = sal_False; } } } // ----------------------------------------------------------------------------- sal_Int32 FmGridControl::GetSelectedColumn() const { return m_nCurrentSelectedColumn; } // ----------------------------------------------------------------------------- void FmGridControl::KeyInput( const KeyEvent& rKEvt ) { sal_Bool bDone = sal_False; const KeyCode& rKeyCode = rKEvt.GetKeyCode(); if ( IsDesignMode() && !rKeyCode.IsShift() && !rKeyCode.IsMod1() && !rKeyCode.IsMod2() && GetParent() ) { switch ( rKeyCode.GetCode() ) { case KEY_ESCAPE: GetParent()->GrabFocus(); bDone = sal_True; break; case KEY_DELETE: if ( GetSelectColumnCount() && GetPeer() && m_nCurrentSelectedColumn >= 0 ) { Reference< ::com::sun::star::container::XIndexContainer > xCols(GetPeer()->getColumns()); if ( xCols.is() ) { try { if ( m_nCurrentSelectedColumn < xCols->getCount() ) { Reference< XInterface > xCol; xCols->getByIndex(m_nCurrentSelectedColumn) >>= xCol; xCols->removeByIndex(m_nCurrentSelectedColumn); ::comphelper::disposeComponent(xCol); } } catch(const Exception&) { OSL_ENSURE(0,"exception occured while deleting a column"); } } } bDone = sal_True; break; } } if ( !bDone ) DbGridControl::KeyInput( rKEvt ); } // -----------------------------------------------------------------------------