1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_svx.hxx" 30 31 #include "svx/dbexch.hrc" 32 #include "svx/fmgridif.hxx" 33 #include "fmitems.hxx" 34 #include "fmprop.hrc" 35 #include "svx/fmtools.hxx" 36 #include "svx/fmresids.hrc" 37 #include "fmservs.hxx" 38 #include "fmurl.hxx" 39 #include "formcontrolfactory.hxx" 40 #include "gridcell.hxx" 41 #include "gridcols.hxx" 42 #include "svx/dbaexchange.hxx" 43 #include "svx/dialmgr.hxx" 44 #include "svx/dialogs.hrc" 45 #include "svx/fmgridcl.hxx" 46 #include "svx/svxdlg.hxx" 47 #include "svx/svxids.hrc" 48 #include "trace.hxx" 49 50 #include <com/sun/star/form/XConfirmDeleteListener.hpp> 51 #include <com/sun/star/form/XFormComponent.hpp> 52 #include <com/sun/star/form/XGridColumnFactory.hpp> 53 #include <com/sun/star/io/XPersistObject.hpp> 54 #include <com/sun/star/sdb/CommandType.hpp> 55 #include <com/sun/star/sdb/RowChangeAction.hpp> 56 #include <com/sun/star/sdb/XQueriesSupplier.hpp> 57 #include <com/sun/star/sdbc/DataType.hpp> 58 #include <com/sun/star/sdbc/XPreparedStatement.hpp> 59 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp> 60 #include <com/sun/star/sdbcx/XDeleteRows.hpp> 61 #include <com/sun/star/sdbcx/XTablesSupplier.hpp> 62 #include <com/sun/star/uno/XNamingService.hpp> 63 #include <com/sun/star/util/XNumberFormats.hpp> 64 #include <com/sun/star/util/XNumberFormatsSupplier.hpp> 65 #include <com/sun/star/util/XURLTransformer.hpp> 66 #include <com/sun/star/view/XSelectionSupplier.hpp> 67 68 #ifndef _SVSTDARR_STRINGSDTOR 69 #define _SVSTDARR_STRINGSDTOR 70 #define _SVSTDARR_ULONGS 71 #include <svl/svstdarr.hxx> 72 #endif 73 74 #include <comphelper/extract.hxx> 75 #include <comphelper/numbers.hxx> 76 #include <comphelper/processfactory.hxx> 77 #include <comphelper/property.hxx> 78 #include <connectivity/dbtools.hxx> 79 #include <sfx2/dispatch.hxx> 80 #include <sfx2/viewfrm.hxx> 81 #include <svl/eitem.hxx> 82 #include <svtools/fmtfield.hxx> 83 #include <svl/numuno.hxx> 84 #include <tools/multisel.hxx> 85 #include <tools/shl.hxx> 86 #include <tools/diagnose_ex.h> 87 #include <vcl/help.hxx> 88 #include <vcl/image.hxx> 89 #include <vcl/longcurr.hxx> 90 #include <vcl/menu.hxx> 91 92 #include <math.h> 93 94 using namespace ::com::sun::star::uno; 95 using namespace ::com::sun::star::view; 96 using namespace ::com::sun::star::beans; 97 using namespace ::com::sun::star::lang; 98 using namespace ::com::sun::star::sdbcx; 99 using namespace ::com::sun::star::sdbc; 100 using namespace ::com::sun::star::sdb; 101 using namespace ::com::sun::star::form; 102 using namespace ::com::sun::star::util; 103 using namespace ::com::sun::star::container; 104 using namespace ::cppu; 105 using namespace ::svxform; 106 using namespace ::svx; 107 108 //============================================================================== 109 //------------------------------------------------------------------------------ 110 ::rtl::OUString FieldServiceFromId(sal_Int32 nID) 111 { 112 switch (nID) 113 { 114 case SID_FM_EDIT : return FM_COL_TEXTFIELD; 115 case SID_FM_COMBOBOX : return FM_COL_COMBOBOX; 116 case SID_FM_LISTBOX : return FM_COL_LISTBOX; 117 case SID_FM_CHECKBOX : return FM_COL_CHECKBOX; 118 case SID_FM_DATEFIELD : return FM_COL_DATEFIELD; 119 case SID_FM_TIMEFIELD : return FM_COL_TIMEFIELD; 120 case SID_FM_NUMERICFIELD : return FM_COL_NUMERICFIELD; 121 case SID_FM_CURRENCYFIELD : return FM_COL_CURRENCYFIELD; 122 case SID_FM_PATTERNFIELD : return FM_COL_PATTERNFIELD; 123 case SID_FM_FORMATTEDFIELD : return FM_COL_FORMATTEDFIELD; 124 } 125 return ::rtl::OUString(); 126 } 127 128 //============================================================================== 129 struct FmGridHeaderData 130 { 131 ODataAccessDescriptor aDropData; 132 Point aDropPosPixel; 133 sal_Int8 nDropAction; 134 Reference< XInterface > xDroppedStatement; 135 Reference< XInterface > xDroppedResultSet; 136 }; 137 138 //============================================================================== 139 //------------------------------------------------------------------------------ 140 const sal_Int16 nChangeTypeOffset = 1000; 141 void SetMenuItem(const ImageList& rList, sal_uInt16 nID, Menu* pMenu, Menu& rNewMenu, sal_Bool bDesignMode = sal_True, sal_Int16 nOffset = nChangeTypeOffset) 142 { 143 pMenu->SetItemImage(nID, rList.GetImage(nID)); 144 pMenu->EnableItem(nID, bDesignMode); 145 rNewMenu.InsertItem(nID + nOffset, pMenu->GetItemText(nID)); 146 rNewMenu.SetItemImage(nID + nOffset, rList.GetImage(nID)); 147 rNewMenu.SetHelpId(nID + nOffset, pMenu->GetHelpId(nID)); 148 rNewMenu.EnableItem(nID + nOffset, bDesignMode); 149 } 150 151 //------------------------------------------------------------------------------ 152 FmGridHeader::FmGridHeader( BrowseBox* pParent, WinBits nWinBits) 153 :EditBrowserHeader(pParent, nWinBits) 154 ,DropTargetHelper(this) 155 ,m_pImpl(new FmGridHeaderData) 156 { 157 } 158 159 //------------------------------------------------------------------------------ 160 FmGridHeader::~FmGridHeader() 161 { 162 delete m_pImpl; 163 } 164 165 //------------------------------------------------------------------------------ 166 sal_uInt16 FmGridHeader::GetModelColumnPos(sal_uInt16 nId) const 167 { 168 return static_cast<FmGridControl*>(GetParent())->GetModelColumnPos(nId); 169 } 170 //--------------------------------------------------------------------------------------- 171 void FmGridHeader::notifyColumnSelect(sal_uInt16 nColumnId) 172 { 173 sal_uInt16 nPos = GetModelColumnPos(nColumnId); 174 Reference< XIndexAccess > xColumns(((FmGridControl*)GetParent())->GetPeer()->getColumns(), UNO_QUERY); 175 if ( nPos < xColumns->getCount() ) 176 { 177 Reference< XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY); 178 if ( xSelSupplier.is() ) 179 { 180 Reference< XPropertySet > xColumn; 181 xColumns->getByIndex(nPos) >>= xColumn; 182 xSelSupplier->select(makeAny(xColumn)); 183 } 184 } 185 } 186 //------------------------------------------------------------------------------ 187 void FmGridHeader::Select() 188 { 189 EditBrowserHeader::Select(); 190 notifyColumnSelect(GetCurItemId()); 191 } 192 193 //------------------------------------------------------------------------------ 194 void FmGridHeader::RequestHelp( const HelpEvent& rHEvt ) 195 { 196 sal_uInt16 nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) ); 197 if ( nItemId ) 198 { 199 if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) ) 200 { 201 Rectangle aItemRect = GetItemRect( nItemId ); 202 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() ); 203 aItemRect.Left() = aPt.X(); 204 aItemRect.Top() = aPt.Y(); 205 aPt = OutputToScreenPixel( aItemRect.BottomRight() ); 206 aItemRect.Right() = aPt.X(); 207 aItemRect.Bottom() = aPt.Y(); 208 209 sal_uInt16 nPos = GetModelColumnPos(nItemId); 210 Reference< ::com::sun::star::container::XIndexContainer > xColumns(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns()); 211 try 212 { 213 Reference< ::com::sun::star::beans::XPropertySet > xColumn(xColumns->getByIndex(nPos),UNO_QUERY); 214 ::rtl::OUString aHelpText; 215 xColumn->getPropertyValue(FM_PROP_HELPTEXT) >>= aHelpText; 216 if ( !aHelpText.getLength() ) 217 xColumn->getPropertyValue(FM_PROP_DESCRIPTION) >>= aHelpText; 218 if ( aHelpText.getLength() ) 219 { 220 if ( rHEvt.GetMode() & HELPMODE_BALLOON ) 221 Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aHelpText ); 222 else 223 Help::ShowQuickHelp( this, aItemRect, aHelpText ); 224 return; 225 } 226 } 227 catch(Exception&) 228 { 229 return; 230 } 231 } 232 } 233 EditBrowserHeader::RequestHelp( rHEvt ); 234 } 235 236 //------------------------------------------------------------------------------ 237 sal_Int8 FmGridHeader::AcceptDrop( const AcceptDropEvent& rEvt ) 238 { 239 // drop allowed in design mode only 240 if (!static_cast<FmGridControl*>(GetParent())->IsDesignMode()) 241 return DND_ACTION_NONE; 242 243 // search for recognized formats 244 const DataFlavorExVector& rFlavors = GetDataFlavorExVector(); 245 if (OColumnTransferable::canExtractColumnDescriptor(rFlavors, CTF_COLUMN_DESCRIPTOR | CTF_FIELD_DESCRIPTOR)) 246 return rEvt.mnAction; 247 248 return DND_ACTION_NONE; 249 } 250 251 //------------------------------------------------------------------------------ 252 sal_Int8 FmGridHeader::ExecuteDrop( const ExecuteDropEvent& _rEvt ) 253 { 254 if (!static_cast<FmGridControl*>(GetParent())->IsDesignMode()) 255 return DND_ACTION_NONE; 256 257 TransferableDataHelper aDroppedData(_rEvt.maDropEvent.Transferable); 258 259 // check the formats 260 sal_Bool bColumnDescriptor = OColumnTransferable::canExtractColumnDescriptor(aDroppedData.GetDataFlavorExVector(), CTF_COLUMN_DESCRIPTOR); 261 sal_Bool bFieldDescriptor = OColumnTransferable::canExtractColumnDescriptor(aDroppedData.GetDataFlavorExVector(), CTF_FIELD_DESCRIPTOR); 262 if (!bColumnDescriptor && !bFieldDescriptor) 263 { 264 DBG_ERROR("FmGridHeader::ExecuteDrop: should never have reached this (no extractable format)!"); 265 return DND_ACTION_NONE; 266 } 267 268 // extract the descriptor 269 ::rtl::OUString sDatasouce, sCommand, sFieldName,sDatabaseLocation,sConnnectionResource; 270 sal_Int32 nCommandType = CommandType::COMMAND; 271 Reference< XPreparedStatement > xStatement; 272 Reference< XResultSet > xResultSet; 273 Reference< XPropertySet > xField; 274 Reference< XConnection > xConnection; 275 276 ODataAccessDescriptor aColumn = OColumnTransferable::extractColumnDescriptor(aDroppedData); 277 if (aColumn.has(daDataSource)) aColumn[daDataSource] >>= sDatasouce; 278 if (aColumn.has(daDatabaseLocation)) aColumn[daDatabaseLocation] >>= sDatabaseLocation; 279 if (aColumn.has(daConnectionResource)) aColumn[daConnectionResource] >>= sConnnectionResource; 280 if (aColumn.has(daCommand)) aColumn[daCommand] >>= sCommand; 281 if (aColumn.has(daCommandType)) aColumn[daCommandType] >>= nCommandType; 282 if (aColumn.has(daColumnName)) aColumn[daColumnName] >>= sFieldName; 283 if (aColumn.has(daColumnObject))aColumn[daColumnObject] >>= xField; 284 if (aColumn.has(daConnection)) aColumn[daConnection] >>= xConnection; 285 286 if ( !sFieldName.getLength() 287 || !sCommand.getLength() 288 || ( !sDatasouce.getLength() 289 && !sDatabaseLocation.getLength() 290 && !xConnection.is() 291 ) 292 ) 293 { 294 DBG_ERROR( "FmGridHeader::ExecuteDrop: somebody started a nonsense drag operation!!" ); 295 return DND_ACTION_NONE; 296 } 297 298 try 299 { 300 // need a connection 301 if (!xConnection.is()) 302 { // the transferable did not contain the connection -> build an own one 303 try 304 { 305 ::rtl::OUString sSignificantSource( sDatasouce.getLength() ? sDatasouce : sDatabaseLocation ); 306 xConnection = OStaticDataAccessTools().getConnection_withFeedback(sSignificantSource, ::rtl::OUString(),::rtl::OUString(),static_cast<FmGridControl*>(GetParent())->getServiceManager()); 307 } 308 catch(NoSuchElementException&) 309 { // allowed, means sDatasouce isn't a valid data source name .... 310 } 311 catch(Exception&) 312 { 313 DBG_ERROR("FmGridHeader::ExecuteDrop: could not retrieve the database access object !"); 314 } 315 316 if (!xConnection.is()) 317 { 318 DBG_ERROR("FmGridHeader::ExecuteDrop: could not retrieve the database access object !"); 319 return DND_ACTION_NONE; 320 } 321 } 322 323 // try to obtain the column object 324 if (!xField.is()) 325 { 326 #ifdef DBG_UTIL 327 Reference< XServiceInfo > xServiceInfo(xConnection, UNO_QUERY); 328 DBG_ASSERT(xServiceInfo.is() && xServiceInfo->supportsService(SRV_SDB_CONNECTION), "FmGridHeader::ExecuteDrop: invalid connection (no database access connection !)"); 329 #endif 330 331 Reference< XNameAccess > xFields; 332 switch (nCommandType) 333 { 334 case CommandType::TABLE: 335 { 336 Reference< XTablesSupplier > xSupplyTables(xConnection, UNO_QUERY); 337 Reference< XColumnsSupplier > xSupplyColumns; 338 xSupplyTables->getTables()->getByName(sCommand) >>= xSupplyColumns; 339 xFields = xSupplyColumns->getColumns(); 340 } 341 break; 342 case CommandType::QUERY: 343 { 344 Reference< XQueriesSupplier > xSupplyQueries(xConnection, UNO_QUERY); 345 Reference< XColumnsSupplier > xSupplyColumns; 346 xSupplyQueries->getQueries()->getByName(sCommand) >>= xSupplyColumns; 347 xFields = xSupplyColumns->getColumns(); 348 } 349 break; 350 default: 351 { 352 xStatement = xConnection->prepareStatement(sCommand); 353 // not interested in any results 354 355 Reference< XPropertySet > xStatProps(xStatement,UNO_QUERY); 356 xStatProps->setPropertyValue(rtl::OUString::createFromAscii("MaxRows"), makeAny(sal_Int32(0))); 357 358 xResultSet = xStatement->executeQuery(); 359 Reference< XColumnsSupplier > xSupplyCols(xResultSet, UNO_QUERY); 360 if (xSupplyCols.is()) 361 xFields = xSupplyCols->getColumns(); 362 } 363 } 364 365 if (xFields.is() && xFields->hasByName(sFieldName)) 366 xFields->getByName(sFieldName) >>= xField; 367 368 if (!xField.is()) 369 { 370 ::comphelper::disposeComponent(xStatement); 371 return DND_ACTION_NONE; 372 } 373 } 374 375 // do the drop asynchronously 376 // (85957 - UI actions within the drop are not allowed, but we want to open a popup menu) 377 m_pImpl->aDropData = aColumn; 378 m_pImpl->aDropData[daConnection] <<= xConnection; 379 m_pImpl->aDropData[daColumnObject] <<= xField; 380 381 m_pImpl->nDropAction = _rEvt.mnAction; 382 m_pImpl->aDropPosPixel = _rEvt.maPosPixel; 383 m_pImpl->xDroppedStatement = xStatement; 384 m_pImpl->xDroppedResultSet = xResultSet; 385 386 PostUserEvent(LINK(this, FmGridHeader, OnAsyncExecuteDrop)); 387 } 388 catch (Exception&) 389 { 390 DBG_ERROR("FmGridHeader::ExecuteDrop: caught an exception while creatin' the column !"); 391 ::comphelper::disposeComponent(xStatement); 392 return sal_False; 393 } 394 395 return DND_ACTION_LINK; 396 } 397 398 //------------------------------------------------------------------------------ 399 IMPL_LINK( FmGridHeader, OnAsyncExecuteDrop, void*, /*NOTINTERESTEDIN*/ ) 400 { 401 ::rtl::OUString sCommand, sFieldName,sURL; 402 sal_Int32 nCommandType = CommandType::COMMAND; 403 Reference< XPropertySet > xField; 404 Reference< XConnection > xConnection; 405 406 ::rtl::OUString sDatasouce = m_pImpl->aDropData.getDataSource(); 407 if ( !sDatasouce.getLength() && m_pImpl->aDropData.has(daConnectionResource) ) 408 m_pImpl->aDropData[daConnectionResource] >>= sURL; 409 m_pImpl->aDropData[daCommand] >>= sCommand; 410 m_pImpl->aDropData[daCommandType] >>= nCommandType; 411 m_pImpl->aDropData[daColumnName] >>= sFieldName; 412 m_pImpl->aDropData[daConnection] >>= xConnection; 413 m_pImpl->aDropData[daColumnObject] >>= xField; 414 415 try 416 { 417 // need number formats 418 Reference< XNumberFormatsSupplier > xSupplier = OStaticDataAccessTools().getNumberFormats(xConnection, sal_True); 419 Reference< XNumberFormats > xNumberFormats; 420 if (xSupplier.is()) 421 xNumberFormats = xSupplier->getNumberFormats(); 422 if (!xNumberFormats.is()) 423 { 424 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet); 425 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement); 426 return 0L; 427 } 428 429 // Vom Feld werden nun zwei Informationen benoetigt: 430 // a.) Name des Feldes fuer Label und ControlSource 431 // b.) FormatKey, um festzustellen, welches Feld erzeugt werden soll 432 sal_Int32 nDataType = 0; 433 xField->getPropertyValue(FM_PROP_FIELDTYPE) >>= nDataType; 434 // diese Datentypen koennen im Gridcontrol nicht verarbeitet werden 435 switch (nDataType) 436 { 437 case DataType::BLOB: 438 case DataType::LONGVARBINARY: 439 case DataType::BINARY: 440 case DataType::VARBINARY: 441 case DataType::OTHER: 442 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet); 443 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement); 444 return 0L; 445 } 446 447 // Erstellen der Column 448 Reference< XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns()); 449 Reference< XGridColumnFactory > xFactory(xCols, UNO_QUERY); 450 451 Point aPos = OutputToScreenPixel(m_pImpl->aDropPosPixel); 452 sal_uInt16 nColId = GetItemId(m_pImpl->aDropPosPixel); 453 // EinfuegePosition, immer vor der aktuellen Spalte 454 sal_uInt16 nPos = GetModelColumnPos(nColId); 455 Reference< XPropertySet > xCol, xSecondCol; 456 457 // erzeugen der Column in abhaengigkeit vom type, default textfeld 458 SvULongs aPossibleTypes; 459 switch (nDataType) 460 { 461 case DataType::BIT: 462 case DataType::BOOLEAN: 463 aPossibleTypes.Insert(SID_FM_CHECKBOX, aPossibleTypes.Count()); 464 break; 465 case DataType::TINYINT: 466 case DataType::SMALLINT: 467 case DataType::INTEGER: 468 aPossibleTypes.Insert(SID_FM_NUMERICFIELD, aPossibleTypes.Count()); 469 aPossibleTypes.Insert(SID_FM_FORMATTEDFIELD, aPossibleTypes.Count()); 470 break; 471 case DataType::REAL: 472 case DataType::DOUBLE: 473 case DataType::NUMERIC: 474 case DataType::DECIMAL: 475 aPossibleTypes.Insert(SID_FM_FORMATTEDFIELD, aPossibleTypes.Count()); 476 aPossibleTypes.Insert(SID_FM_NUMERICFIELD, aPossibleTypes.Count()); 477 break; 478 case DataType::TIMESTAMP: 479 aPossibleTypes.Insert(SID_FM_TWOFIELDS_DATE_N_TIME, aPossibleTypes.Count()); 480 aPossibleTypes.Insert(SID_FM_DATEFIELD, aPossibleTypes.Count()); 481 aPossibleTypes.Insert(SID_FM_TIMEFIELD, aPossibleTypes.Count()); 482 aPossibleTypes.Insert(SID_FM_FORMATTEDFIELD, aPossibleTypes.Count()); 483 break; 484 case DataType::DATE: 485 aPossibleTypes.Insert(SID_FM_DATEFIELD, aPossibleTypes.Count()); 486 aPossibleTypes.Insert(SID_FM_FORMATTEDFIELD, aPossibleTypes.Count()); 487 break; 488 case DataType::TIME: 489 aPossibleTypes.Insert(SID_FM_TIMEFIELD, aPossibleTypes.Count()); 490 aPossibleTypes.Insert(SID_FM_FORMATTEDFIELD, aPossibleTypes.Count()); 491 break; 492 case DataType::CHAR: 493 case DataType::VARCHAR: 494 case DataType::LONGVARCHAR: 495 default: 496 aPossibleTypes.Insert(SID_FM_EDIT, aPossibleTypes.Count()); 497 aPossibleTypes.Insert(SID_FM_FORMATTEDFIELD, aPossibleTypes.Count()); 498 break; 499 } 500 // if it's a currency field, a a "currency field" option 501 try 502 { 503 if ( ::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField) 504 && ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY))) 505 aPossibleTypes.Insert(SID_FM_CURRENCYFIELD, 0); 506 } 507 catch(Exception&) 508 { 509 DBG_ERROR("FmGridHeader::ExecuteDrop: Exception occured!"); 510 } 511 512 sal_Int32 nPreferedType = -1; 513 sal_Bool bDateNTimeCol = sal_False; 514 if (aPossibleTypes.Count() != 0) 515 { 516 nPreferedType = aPossibleTypes[0]; 517 if ((m_pImpl->nDropAction == DND_ACTION_LINK) && (aPossibleTypes.Count() > 1)) 518 { 519 ImageList aImageList( SVX_RES(RID_SVXIMGLIST_FMEXPL) ); 520 521 PopupMenu aInsertMenu(SVX_RES(RID_SVXMNU_COLS)); 522 PopupMenu aTypeMenu; 523 PopupMenu* pMenu = aInsertMenu.GetPopupMenu(SID_FM_INSERTCOL); 524 for (sal_uInt32 i=0; i<aPossibleTypes.Count(); ++i) 525 SetMenuItem(aImageList, sal_uInt16(aPossibleTypes[(sal_uInt16)i]), pMenu, aTypeMenu, sal_True, 0); 526 nPreferedType = aTypeMenu.Execute(this, m_pImpl->aDropPosPixel); 527 } 528 529 bDateNTimeCol = nPreferedType == SID_FM_TWOFIELDS_DATE_N_TIME; 530 sal_uInt16 nColCount = bDateNTimeCol ? 2 : 1; 531 ::rtl::OUString sFieldService; 532 while (nColCount--) 533 { 534 if (bDateNTimeCol) 535 nPreferedType = nColCount ? SID_FM_DATEFIELD : SID_FM_TIMEFIELD; 536 537 sFieldService = FieldServiceFromId(nPreferedType); 538 Reference< XPropertySet > xThisRoundCol; 539 if ( sFieldService.getLength() ) 540 xThisRoundCol = xFactory->createColumn(sFieldService); 541 if (nColCount) 542 xSecondCol = xThisRoundCol; 543 else 544 xCol = xThisRoundCol; 545 } 546 } 547 548 if (!xCol.is() || (bDateNTimeCol && !xSecondCol.is())) 549 { 550 ::comphelper::disposeComponent(xCol); // in case only the creation of the second column failed 551 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet); 552 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement); 553 return 0L; 554 } 555 556 if (bDateNTimeCol) 557 { 558 String sTimePostfix( SVX_RES( RID_STR_POSTFIX_TIME ) ); 559 xCol->setPropertyValue(FM_PROP_LABEL, makeAny( ::rtl::OUString( sFieldName + sTimePostfix ) ) ); 560 561 String sDatePostfix( SVX_RES( RID_STR_POSTFIX_DATE ) ); 562 xSecondCol->setPropertyValue(FM_PROP_LABEL, makeAny( ::rtl::OUString( sFieldName + sDatePostfix ) ) ); 563 } 564 else 565 xCol->setPropertyValue(FM_PROP_LABEL, makeAny(sFieldName)); 566 567 FormControlFactory aControlFactory( ::comphelper::getProcessServiceFactory() ); 568 aControlFactory.initializeControlModel( DocumentClassification::classifyHostDocument( xCols ), xCol ); 569 aControlFactory.initializeFieldDependentProperties( xField, xCol, xNumberFormats ); 570 571 xCol->setPropertyValue(FM_PROP_CONTROLSOURCE, makeAny(sFieldName)); 572 if ( xSecondCol.is() ) 573 xSecondCol->setPropertyValue(FM_PROP_CONTROLSOURCE, makeAny(sFieldName)); 574 575 if (bDateNTimeCol) 576 { 577 String sRealName,sPurePostfix; 578 579 String aPostfix[] = { 580 String( SVX_RES( RID_STR_POSTFIX_DATE ) ), 581 String( SVX_RES( RID_STR_POSTFIX_TIME ) ) 582 }; 583 584 for ( size_t i=0; i<2; ++i ) 585 { 586 sPurePostfix = aPostfix[i]; 587 sPurePostfix.EraseLeadingChars(' '); 588 sPurePostfix.EraseLeadingChars('('); 589 sPurePostfix.EraseTrailingChars(')'); 590 sRealName = sFieldName; 591 sRealName += '_'; 592 sRealName += sPurePostfix; 593 if (i) 594 xSecondCol->setPropertyValue(FM_PROP_NAME, makeAny(::rtl::OUString(sRealName))); 595 else 596 xCol->setPropertyValue(FM_PROP_NAME, makeAny(::rtl::OUString(sRealName))); 597 } 598 } 599 else 600 xCol->setPropertyValue(FM_PROP_NAME, makeAny(sFieldName)); 601 602 // jetzt einfuegen 603 Any aElement; 604 aElement <<= xCol; 605 xCols->insertByIndex(nPos, aElement); 606 607 if (bDateNTimeCol) 608 { 609 aElement <<= xSecondCol; 610 xCols->insertByIndex(nPos == (sal_uInt16)-1 ? nPos : ++nPos, aElement); 611 } 612 613 // ist die component::Form an die Datenbankangebunden? 614 Reference< XFormComponent > xFormCp(xCols, UNO_QUERY); 615 Reference< XPropertySet > xForm(xFormCp->getParent(), UNO_QUERY); 616 if (xForm.is()) 617 { 618 if (!::comphelper::getString(xForm->getPropertyValue(FM_PROP_DATASOURCE)).getLength()) 619 { 620 if ( sDatasouce.getLength() ) 621 xForm->setPropertyValue(FM_PROP_DATASOURCE, makeAny(sDatasouce)); 622 else 623 xForm->setPropertyValue(FM_PROP_URL, makeAny(sURL)); 624 } 625 626 if (!::comphelper::getString(xForm->getPropertyValue(FM_PROP_COMMAND)).getLength()) 627 { 628 xForm->setPropertyValue(FM_PROP_COMMAND, makeAny(sCommand)); 629 Any aCommandType; 630 switch (nCommandType) 631 { 632 case CommandType::TABLE: 633 aCommandType <<= (sal_Int32)CommandType::TABLE; 634 break; 635 case CommandType::QUERY: 636 aCommandType <<= (sal_Int32)CommandType::QUERY; 637 break; 638 default: 639 aCommandType <<= (sal_Int32)CommandType::COMMAND; 640 xForm->setPropertyValue(FM_PROP_ESCAPE_PROCESSING, bool2any((sal_Bool)(2 == nCommandType))); 641 break; 642 } 643 xForm->setPropertyValue(FM_PROP_COMMANDTYPE, aCommandType); 644 } 645 } 646 } 647 catch (Exception&) 648 { 649 DBG_ERROR("FmGridHeader::OnAsyncExecuteDrop: caught an exception while creatin' the column !"); 650 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet); 651 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement); 652 return 0L; 653 } 654 655 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet); 656 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement); 657 return 1L; 658 } 659 660 //------------------------------------------------------------------------------ 661 void FmGridHeader::PreExecuteColumnContextMenu(sal_uInt16 nColId, PopupMenu& rMenu) 662 { 663 sal_Bool bDesignMode = static_cast<FmGridControl*>(GetParent())->IsDesignMode(); 664 665 Reference< ::com::sun::star::container::XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns()); 666 // Aufbau des Insert Menues 667 // mark the column if nColId != HEADERBAR_ITEM_NOTFOUND 668 if(nColId > 0) 669 { 670 sal_uInt16 nPos2 = GetModelColumnPos(nColId); 671 672 Reference< ::com::sun::star::container::XIndexContainer > xColumns(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns()); 673 Reference< ::com::sun::star::beans::XPropertySet> xColumn; 674 ::cppu::extractInterface(xColumn, xColumns->getByIndex(nPos2)); 675 Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY); 676 if (xSelSupplier.is()) 677 xSelSupplier->select(makeAny(xColumn)); 678 } 679 680 // EinfuegePosition, immer vor der aktuellen Spalte 681 sal_uInt16 nPos = GetModelColumnPos(nColId); 682 sal_Bool bMarked = nColId && static_cast<FmGridControl*>(GetParent())->isColumnMarked(nColId); 683 684 ImageList aImageList( SVX_RES(RID_SVXIMGLIST_FMEXPL) ); 685 PopupMenu* pControlMenu = new PopupMenu; 686 687 PopupMenu* pMenu = rMenu.GetPopupMenu(SID_FM_INSERTCOL); 688 if (pMenu) 689 { 690 SetMenuItem(aImageList, SID_FM_EDIT, pMenu, *pControlMenu, bDesignMode); 691 SetMenuItem(aImageList, SID_FM_CHECKBOX, pMenu, *pControlMenu, bDesignMode); 692 SetMenuItem(aImageList, SID_FM_COMBOBOX, pMenu, *pControlMenu, bDesignMode); 693 SetMenuItem(aImageList, SID_FM_LISTBOX, pMenu, *pControlMenu, bDesignMode); 694 SetMenuItem(aImageList, SID_FM_DATEFIELD, pMenu, *pControlMenu, bDesignMode); 695 SetMenuItem(aImageList, SID_FM_TIMEFIELD, pMenu, *pControlMenu, bDesignMode); 696 SetMenuItem(aImageList, SID_FM_NUMERICFIELD, pMenu, *pControlMenu, bDesignMode); 697 SetMenuItem(aImageList, SID_FM_CURRENCYFIELD, pMenu, *pControlMenu, bDesignMode); 698 SetMenuItem(aImageList, SID_FM_PATTERNFIELD, pMenu, *pControlMenu, bDesignMode); 699 SetMenuItem(aImageList, SID_FM_FORMATTEDFIELD, pMenu, *pControlMenu, bDesignMode); 700 } 701 702 if (pMenu && xCols.is() && nColId) 703 { 704 Reference< ::com::sun::star::beans::XPropertySet > xSet; 705 ::cppu::extractInterface(xSet, xCols->getByIndex(nPos)); 706 sal_Int16 nClassId; 707 xSet->getPropertyValue(FM_PROP_CLASSID) >>= nClassId; 708 709 Reference< ::com::sun::star::io::XPersistObject > xServiceQuestion(xSet, UNO_QUERY); 710 sal_Int32 nColType = xServiceQuestion.is() ? getColumnTypeByModelName(xServiceQuestion->getServiceName()) : 0; 711 if (nColType == TYPE_TEXTFIELD) 712 { // edit fields and formatted fields have the same service name, thus getColumnTypeByModelName returns TYPE_TEXTFIELD 713 // in both cases. And as columns don't have an ::com::sun::star::lang::XServiceInfo interface, we have to distinguish both 714 // types via the existence of special properties 715 Reference< ::com::sun::star::beans::XPropertySet > xProps(xSet, UNO_QUERY); 716 if (xProps.is()) 717 { 718 Reference< ::com::sun::star::beans::XPropertySetInfo > xPropsInfo = xProps->getPropertySetInfo(); 719 if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(FM_PROP_FORMATSSUPPLIER)) 720 nColType = TYPE_FORMATTEDFIELD; 721 } 722 } 723 724 pControlMenu->EnableItem(SID_FM_EDIT + nChangeTypeOffset, bDesignMode && (nColType != TYPE_TEXTFIELD)); 725 pControlMenu->EnableItem(SID_FM_COMBOBOX + nChangeTypeOffset, bDesignMode && (nColType != TYPE_COMBOBOX)); 726 pControlMenu->EnableItem(SID_FM_LISTBOX + nChangeTypeOffset, bDesignMode && (nColType != TYPE_LISTBOX)); 727 pControlMenu->EnableItem(SID_FM_CHECKBOX + nChangeTypeOffset, bDesignMode && (nColType != TYPE_CHECKBOX)); 728 pControlMenu->EnableItem(SID_FM_DATEFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_DATEFIELD)); 729 pControlMenu->EnableItem(SID_FM_NUMERICFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_NUMERICFIELD)); 730 pControlMenu->EnableItem(SID_FM_TIMEFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_TIMEFIELD)); 731 pControlMenu->EnableItem(SID_FM_CURRENCYFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_CURRENCYFIELD)); 732 pControlMenu->EnableItem(SID_FM_PATTERNFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_PATTERNFIELD)); 733 pControlMenu->EnableItem(SID_FM_FORMATTEDFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_FORMATTEDFIELD)); 734 rMenu.SetPopupMenu(SID_FM_CHANGECOL, pControlMenu); 735 } 736 737 rMenu.EnableItem(SID_FM_INSERTCOL, bDesignMode && xCols.is()); 738 rMenu.EnableItem(SID_FM_DELETECOL, bDesignMode && bMarked && xCols.is()); 739 rMenu.EnableItem(SID_FM_CHANGECOL, bDesignMode && bMarked && xCols.is()); 740 rMenu.EnableItem(SID_FM_SHOW_PROPERTY_BROWSER, bDesignMode && bMarked && xCols.is()); 741 742 PopupMenu* pShowColsMenu = rMenu.GetPopupMenu(SID_FM_SHOWCOLS); 743 sal_uInt16 nHiddenCols = 0; 744 if (pShowColsMenu) 745 { 746 if (xCols.is()) 747 { 748 // check for hidden cols 749 Reference< ::com::sun::star::beans::XPropertySet > xCurCol; 750 Any aHidden,aName; 751 for (sal_uInt16 i=0; i<xCols->getCount(); ++i) 752 { 753 ::cppu::extractInterface(xCurCol, xCols->getByIndex(i)); 754 DBG_ASSERT(xCurCol.is(), "FmGridHeader::PreExecuteColumnContextMenu : the Peer has invalid columns !"); 755 aHidden = xCurCol->getPropertyValue(FM_PROP_HIDDEN); 756 DBG_ASSERT(aHidden.getValueType().getTypeClass() == TypeClass_BOOLEAN, 757 "FmGridHeader::PreExecuteColumnContextMenu : the property 'hidden' should be boolean !"); 758 if (::comphelper::getBOOL(aHidden)) 759 { 760 // put the column name into the 'show col' menu 761 if (nHiddenCols < 16) 762 { // (only the first 16 items to keep the menu rather small) 763 aName = xCurCol->getPropertyValue(FM_PROP_LABEL); 764 pShowColsMenu->InsertItem(nHiddenCols + 1, ::comphelper::getString(aName), 0, nHiddenCols); 765 // the ID is arbitrary, but should be unique within the whole menu 766 } 767 ++nHiddenCols; 768 } 769 } 770 } 771 pShowColsMenu->EnableItem(SID_FM_SHOWCOLS_MORE, xCols.is() && (nHiddenCols > 16)); 772 pShowColsMenu->EnableItem(SID_FM_SHOWALLCOLS, xCols.is() && (nHiddenCols > 0)); 773 } 774 775 // allow the 'hide column' item ? 776 sal_Bool bAllowHide = bMarked; // a column is marked 777 bAllowHide = bAllowHide || (!bDesignMode && (nPos != (sal_uInt16)-1)); // OR we are in alive mode and have hit a column 778 bAllowHide = bAllowHide && xCols.is(); // AND we have a column container 779 bAllowHide = bAllowHide && (xCols->getCount()-nHiddenCols > 1); // AND there are at least two visible columns 780 rMenu.EnableItem(SID_FM_HIDECOL, bAllowHide); 781 782 sal_Bool bChecked = sal_False; 783 if (bMarked) 784 { 785 786 SfxViewFrame* pCurrentFrame = SfxViewFrame::Current(); 787 SfxItemState eState = SFX_ITEM_UNKNOWN; 788 // ask the bindings of the current view frame (which should be the one we're residing in) for the state 789 if (pCurrentFrame) 790 { 791 SfxPoolItem* pItem = NULL; 792 eState = pCurrentFrame->GetBindings().QueryState(SID_FM_CTL_PROPERTIES, pItem); 793 794 if (eState >= SFX_ITEM_AVAILABLE && pItem ) 795 { 796 bChecked = pItem->ISA(SfxBoolItem) && ((SfxBoolItem*)pItem)->GetValue(); 797 rMenu.CheckItem(SID_FM_SHOW_PROPERTY_BROWSER,bChecked); 798 } 799 delete pItem; 800 } 801 } 802 } 803 804 enum InspectorAction { eOpenInspector, eCloseInspector, eUpdateInspector, eNone }; 805 806 //------------------------------------------------------------------------------ 807 void FmGridHeader::PostExecuteColumnContextMenu(sal_uInt16 nColId, const PopupMenu& rMenu, sal_uInt16 nExecutionResult) 808 { 809 Reference< ::com::sun::star::container::XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns()); 810 sal_uInt16 nPos = GetModelColumnPos(nColId); 811 812 // remove and delet the menu we inserted in PreExecuteColumnContextMenu 813 PopupMenu* pControlMenu = rMenu.GetPopupMenu(SID_FM_CHANGECOL); 814 delete pControlMenu; 815 816 ::rtl::OUString aFieldType; 817 sal_Bool bReplace = sal_False; 818 InspectorAction eInspectorAction = eNone; 819 Reference< XPropertySet > xColumnToInspect; 820 switch (nExecutionResult) 821 { 822 case SID_FM_DELETECOL: 823 { 824 Reference< XInterface > xCol; 825 ::cppu::extractInterface(xCol, xCols->getByIndex(nPos)); 826 xCols->removeByIndex(nPos); 827 ::comphelper::disposeComponent(xCol); 828 } break; 829 case SID_FM_SHOW_PROPERTY_BROWSER: 830 eInspectorAction = rMenu.IsItemChecked( SID_FM_SHOW_PROPERTY_BROWSER ) ? eOpenInspector : eCloseInspector; 831 xColumnToInspect.set( xCols->getByIndex( nPos ), UNO_QUERY ); 832 break; 833 case SID_FM_EDIT + nChangeTypeOffset: 834 bReplace = sal_True; 835 case SID_FM_EDIT: 836 aFieldType = FM_COL_TEXTFIELD; 837 break; 838 case SID_FM_COMBOBOX + nChangeTypeOffset: 839 bReplace = sal_True; 840 case SID_FM_COMBOBOX: 841 aFieldType = FM_COL_COMBOBOX; 842 break; 843 case SID_FM_LISTBOX + nChangeTypeOffset: 844 bReplace = sal_True; 845 case SID_FM_LISTBOX: 846 aFieldType = FM_COL_LISTBOX; 847 break; 848 case SID_FM_CHECKBOX + nChangeTypeOffset: 849 bReplace = sal_True; 850 case SID_FM_CHECKBOX: 851 aFieldType = FM_COL_CHECKBOX; 852 break; 853 case SID_FM_DATEFIELD + nChangeTypeOffset: 854 bReplace = sal_True; 855 case SID_FM_DATEFIELD: 856 aFieldType = FM_COL_DATEFIELD; 857 break; 858 case SID_FM_TIMEFIELD + nChangeTypeOffset: 859 bReplace = sal_True; 860 case SID_FM_TIMEFIELD: 861 aFieldType = FM_COL_TIMEFIELD; 862 break; 863 case SID_FM_NUMERICFIELD + nChangeTypeOffset: 864 bReplace = sal_True; 865 case SID_FM_NUMERICFIELD: 866 aFieldType = FM_COL_NUMERICFIELD; 867 break; 868 case SID_FM_CURRENCYFIELD + nChangeTypeOffset: 869 bReplace = sal_True; 870 case SID_FM_CURRENCYFIELD: 871 aFieldType = FM_COL_CURRENCYFIELD; 872 break; 873 case SID_FM_PATTERNFIELD + nChangeTypeOffset: 874 bReplace = sal_True; 875 case SID_FM_PATTERNFIELD: 876 aFieldType = FM_COL_PATTERNFIELD; 877 break; 878 case SID_FM_FORMATTEDFIELD + nChangeTypeOffset: 879 bReplace = sal_True; 880 case SID_FM_FORMATTEDFIELD: 881 aFieldType = FM_COL_FORMATTEDFIELD; 882 break; 883 case SID_FM_HIDECOL: 884 { 885 Reference< ::com::sun::star::beans::XPropertySet > xCurCol; 886 ::cppu::extractInterface(xCurCol, xCols->getByIndex(nPos)); 887 xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny((sal_Bool)sal_True)); 888 } 889 break; 890 case SID_FM_SHOWCOLS_MORE: 891 { 892 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); 893 if(pFact) 894 { 895 AbstractFmShowColsDialog* pDlg = pFact->CreateFmShowColsDialog(NULL); 896 DBG_ASSERT(pDlg, "Dialogdiet fail!");//CHINA001 897 pDlg->SetColumns(xCols); 898 pDlg->Execute(); 899 delete pDlg; 900 } 901 902 } 903 break; 904 case SID_FM_SHOWALLCOLS: 905 { 906 // just iterate through all the cols ... 907 Reference< ::com::sun::star::beans::XPropertySet > xCurCol; 908 for (sal_uInt16 i=0; i<xCols->getCount(); ++i) 909 { 910 ::cppu::extractInterface(xCurCol, xCols->getByIndex(i)); 911 xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny((sal_Bool)sal_False)); 912 } 913 // TODO : there must be a more clever way to do this .... 914 // with the above the view is updated after every single model update ... 915 } 916 break; 917 default: 918 if (nExecutionResult>0 && nExecutionResult<=16) 919 { // it was a "show column/<colname>" command (there are at most 16 such items) 920 // search the nExecutionResult'th hidden col 921 Reference< ::com::sun::star::beans::XPropertySet > xCurCol; 922 for (sal_uInt16 i=0; i<xCols->getCount() && nExecutionResult; ++i) 923 { 924 ::cppu::extractInterface(xCurCol, xCols->getByIndex(i)); 925 Any aHidden = xCurCol->getPropertyValue(FM_PROP_HIDDEN); 926 if (::comphelper::getBOOL(aHidden)) 927 if (!--nExecutionResult) 928 { 929 xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny((sal_Bool)sal_False)); 930 break; 931 } 932 } 933 } 934 break; 935 } 936 937 if ( aFieldType.getLength() ) 938 { 939 try 940 { 941 Reference< XGridColumnFactory > xFactory( xCols, UNO_QUERY_THROW ); 942 Reference< XPropertySet > xNewCol( xFactory->createColumn( aFieldType ), UNO_SET_THROW ); 943 944 if ( bReplace ) 945 { 946 // ein paar Properties hinueberretten 947 Reference< XPropertySet > xReplaced( xCols->getByIndex( nPos ), UNO_QUERY ); 948 949 OStaticDataAccessTools().TransferFormComponentProperties( 950 xReplaced, xNewCol, Application::GetSettings().GetUILocale() ); 951 952 xCols->replaceByIndex( nPos, makeAny( xNewCol ) ); 953 ::comphelper::disposeComponent( xReplaced ); 954 955 eInspectorAction = eUpdateInspector; 956 xColumnToInspect = xNewCol; 957 } 958 else 959 { 960 FormControlFactory factory( ::comphelper::getProcessServiceFactory() ); 961 962 ::rtl::OUString sLabel = factory.getDefaultUniqueName_ByComponentType( 963 Reference< XNameAccess >( xCols, UNO_QUERY_THROW ), xNewCol ); 964 xNewCol->setPropertyValue( FM_PROP_LABEL, makeAny( sLabel ) ); 965 xNewCol->setPropertyValue( FM_PROP_NAME, makeAny( sLabel ) ); 966 967 factory.initializeControlModel( DocumentClassification::classifyHostDocument( xCols ), xNewCol ); 968 969 xCols->insertByIndex( nPos, makeAny( xNewCol ) ); 970 } 971 } 972 catch( const Exception& ) 973 { 974 DBG_UNHANDLED_EXCEPTION(); 975 } 976 } 977 978 SfxViewFrame* pCurrentFrame = SfxViewFrame::Current(); 979 OSL_ENSURE( pCurrentFrame, "FmGridHeader::PostExecuteColumnContextMenu: no view frame -> no bindings -> no property browser!" ); 980 if ( pCurrentFrame ) 981 { 982 if ( eInspectorAction == eUpdateInspector ) 983 { 984 if ( !pCurrentFrame->HasChildWindow( SID_FM_SHOW_PROPERTIES ) ) 985 eInspectorAction = eNone; 986 } 987 988 if ( eInspectorAction != eNone ) 989 { 990 FmInterfaceItem aIFaceItem( SID_FM_SHOW_PROPERTY_BROWSER, xColumnToInspect ); 991 SfxBoolItem aShowItem( SID_FM_SHOW_PROPERTIES, eInspectorAction == eCloseInspector ? sal_False : sal_True ); 992 993 pCurrentFrame->GetBindings().GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SFX_CALLMODE_ASYNCHRON, 994 &aIFaceItem, &aShowItem, 0L ); 995 } 996 } 997 } 998 999 //------------------------------------------------------------------------------ 1000 void FmGridHeader::triggerColumnContextMenu( const ::Point& _rPreferredPos ) 1001 { 1002 // the affected col 1003 sal_uInt16 nColId = GetItemId( _rPreferredPos ); 1004 1005 // the menu 1006 PopupMenu aContextMenu( SVX_RES( RID_SVXMNU_COLS ) ); 1007 1008 // let derivees modify the menu 1009 PreExecuteColumnContextMenu( nColId, aContextMenu ); 1010 aContextMenu.RemoveDisabledEntries( sal_True, sal_True ); 1011 1012 // execute the menu 1013 sal_uInt16 nResult = aContextMenu.Execute( this, _rPreferredPos ); 1014 1015 // let derivees handle the result 1016 PostExecuteColumnContextMenu( nColId, aContextMenu, nResult ); 1017 } 1018 1019 //------------------------------------------------------------------------------ 1020 void FmGridHeader::Command(const CommandEvent& rEvt) 1021 { 1022 switch (rEvt.GetCommand()) 1023 { 1024 case COMMAND_CONTEXTMENU: 1025 { 1026 if (!rEvt.IsMouseEvent()) 1027 return; 1028 1029 triggerColumnContextMenu( rEvt.GetMousePosPixel() ); 1030 } 1031 break; 1032 default: 1033 EditBrowserHeader::Command(rEvt); 1034 } 1035 } 1036 1037 //------------------------------------------------------------------------------ 1038 FmGridControl::FmGridControl( 1039 Reference< ::com::sun::star::lang::XMultiServiceFactory > _rxFactory, 1040 Window* pParent, 1041 FmXGridPeer* _pPeer, 1042 WinBits nBits) 1043 :DbGridControl(_rxFactory, pParent, nBits) 1044 ,m_pPeer(_pPeer) 1045 ,m_nCurrentSelectedColumn(-1) 1046 ,m_nMarkedColumnId(BROWSER_INVALIDID) 1047 ,m_bSelecting(sal_False) 1048 ,m_bInColumnMove(sal_False) 1049 { 1050 EnableInteractiveRowHeight( ); 1051 } 1052 1053 //------------------------------------------------------------------------------ 1054 void FmGridControl::Command(const CommandEvent& _rEvt) 1055 { 1056 if ( COMMAND_CONTEXTMENU == _rEvt.GetCommand() ) 1057 { 1058 FmGridHeader* pMyHeader = static_cast< FmGridHeader* >( GetHeaderBar() ); 1059 if ( pMyHeader && !_rEvt.IsMouseEvent() ) 1060 { // context menu requested by keyboard 1061 if ( 1 == GetSelectColumnCount() || IsDesignMode() ) 1062 { 1063 sal_uInt16 nSelId = GetColumnId( 1064 sal::static_int_cast< sal_uInt16 >( FirstSelectedColumn() ) ); 1065 ::Rectangle aColRect( GetFieldRectPixel( 0, nSelId, sal_False ) ); 1066 1067 Point aRelativePos( pMyHeader->ScreenToOutputPixel( OutputToScreenPixel( aColRect.TopCenter() ) ) ); 1068 pMyHeader->triggerColumnContextMenu( aRelativePos, FmGridHeader::AccessControl() ); 1069 1070 // handled 1071 return; 1072 } 1073 } 1074 } 1075 1076 DbGridControl::Command( _rEvt ); 1077 } 1078 1079 // ::com::sun::star::beans::XPropertyChangeListener 1080 //------------------------------------------------------------------------------ 1081 void FmGridControl::propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& evt) 1082 { 1083 if (evt.PropertyName == FM_PROP_ROWCOUNT) 1084 { 1085 // if we're not in the main thread call AdjustRows asynchronously 1086 implAdjustInSolarThread(sal_True); 1087 return; 1088 } 1089 1090 const DbGridRowRef& xRow = GetCurrentRow(); 1091 // waehrend Positionierung wird kein abgleich der Properties vorgenommen 1092 Reference<XPropertySet> xSet(evt.Source,UNO_QUERY); 1093 if (xRow.Is() && (::cppu::any2bool(xSet->getPropertyValue(FM_PROP_ISNEW))|| CompareBookmark(getDataSource()->getBookmark(), xRow->GetBookmark()))) 1094 { 1095 if (evt.PropertyName == FM_PROP_ISMODIFIED) 1096 { 1097 // modified or clean ? 1098 GridRowStatus eStatus = ::comphelper::getBOOL(evt.NewValue) ? GRS_MODIFIED : GRS_CLEAN; 1099 if (eStatus != xRow->GetStatus()) 1100 { 1101 xRow->SetStatus(eStatus); 1102 vos::OGuard aGuard( Application::GetSolarMutex() ); 1103 RowModified(GetCurrentPos()); 1104 } 1105 } 1106 } 1107 } 1108 1109 //------------------------------------------------------------------------------ 1110 void FmGridControl::SetDesignMode(sal_Bool bMode) 1111 { 1112 sal_Bool bOldMode = IsDesignMode(); 1113 DbGridControl::SetDesignMode(bMode); 1114 if (bOldMode != bMode) 1115 { 1116 if (!bMode) 1117 { 1118 // selection aufheben 1119 markColumn(USHRT_MAX); 1120 } 1121 else 1122 { 1123 Reference< ::com::sun::star::container::XIndexContainer > xColumns(GetPeer()->getColumns()); 1124 Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY); 1125 if (xSelSupplier.is()) 1126 { 1127 Any aSelection = xSelSupplier->getSelection(); 1128 Reference< ::com::sun::star::beans::XPropertySet > xColumn; 1129 if (aSelection.getValueType().getTypeClass() == TypeClass_INTERFACE) 1130 ::cppu::extractInterface(xColumn, aSelection); 1131 Reference< XInterface > xCurrent; 1132 for (sal_uInt16 i=0; i<xColumns->getCount(); ++i) 1133 { 1134 ::cppu::extractInterface(xCurrent, xColumns->getByIndex(i)); 1135 if (xCurrent == xColumn) 1136 { 1137 markColumn(GetColumnIdFromModelPos(i)); 1138 break; 1139 } 1140 } 1141 } 1142 } 1143 } 1144 } 1145 1146 //------------------------------------------------------------------------------ 1147 void FmGridControl::DeleteSelectedRows() 1148 { 1149 if (!m_pSeekCursor) 1150 return; 1151 1152 // how many rows are selected? 1153 sal_Int32 nSelectedRows = GetSelectRowCount(); 1154 1155 // the current line should be deleted but it is currently in edit mode 1156 if ( IsCurrentAppending() ) 1157 return; 1158 // is the insert row selected 1159 if (GetEmptyRow().Is() && IsRowSelected(GetRowCount() - 1)) 1160 nSelectedRows -= 1; 1161 1162 // nothing to do 1163 if (nSelectedRows <= 0) 1164 return; 1165 1166 // try to confirm the delete 1167 Reference< ::com::sun::star::frame::XDispatchProvider > xDispatcher = (::com::sun::star::frame::XDispatchProvider*)GetPeer(); 1168 if (xDispatcher.is()) 1169 { 1170 ::com::sun::star::util::URL aUrl; 1171 aUrl.Complete = FMURL_CONFIRM_DELETION; 1172 // #100312# ------------ 1173 Reference< ::com::sun::star::util::XURLTransformer > xTransformer( 1174 ::comphelper::getProcessServiceFactory()->createInstance( 1175 ::rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer")), UNO_QUERY); 1176 if( xTransformer.is() ) 1177 xTransformer->parseStrict( aUrl ); 1178 1179 Reference< ::com::sun::star::frame::XDispatch > xDispatch = xDispatcher->queryDispatch(aUrl, rtl::OUString(), 0); 1180 Reference< ::com::sun::star::form::XConfirmDeleteListener > xConfirm(xDispatch, UNO_QUERY); 1181 if (xConfirm.is()) 1182 { 1183 ::com::sun::star::sdb::RowChangeEvent aEvent; 1184 aEvent.Source = (Reference< XInterface > )(*getDataSource()); 1185 aEvent.Rows = nSelectedRows; 1186 aEvent.Action = ::com::sun::star::sdb::RowChangeAction::DELETE; 1187 if (!xConfirm->confirmDelete(aEvent)) 1188 return; 1189 } 1190 } 1191 1192 const MultiSelection* pRowSelection = GetSelection(); 1193 if ( pRowSelection && pRowSelection->IsAllSelected() ) 1194 { 1195 BeginCursorAction(); 1196 CursorWrapper* pCursor = getDataSource(); 1197 Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*pCursor, UNO_QUERY); 1198 try 1199 { 1200 pCursor->beforeFirst(); 1201 while( pCursor->next() ) 1202 xUpdateCursor->deleteRow(); 1203 1204 SetUpdateMode(sal_False); 1205 SetNoSelection(); 1206 1207 xUpdateCursor->moveToInsertRow(); 1208 } 1209 catch(const Exception&) 1210 { 1211 OSL_ENSURE(0,"Exception caught while deleting rows!"); 1212 } 1213 // An den DatenCursor anpassen 1214 AdjustDataSource(sal_True); 1215 EndCursorAction(); 1216 SetUpdateMode(sal_True); 1217 } 1218 else 1219 { 1220 Reference< ::com::sun::star::sdbcx::XDeleteRows > xDeleteThem((Reference< XInterface >)*getDataSource(), UNO_QUERY); 1221 1222 // colect the bookmarks of the selected rows 1223 Sequence < Any> aBookmarks = getSelectionBookmarks(); 1224 1225 // determine the next row to position after deletion 1226 Any aBookmark; 1227 sal_Bool bNewPos = sal_False; 1228 // if the current row isn't selected we take the row as row after deletion 1229 OSL_ENSURE( GetCurrentRow().Is(), "FmGridControl::DeleteSelectedRows: no current row here?" ); 1230 // crash reports suggest it can happen we don't have a current row - how? 1231 // #154303# / 2008-04-23 / frank.schoenheit@sun.com 1232 if ( !IsRowSelected( GetCurrentPos() ) && !IsCurrentAppending() && GetCurrentRow().Is() ) 1233 { 1234 aBookmark = GetCurrentRow()->GetBookmark(); 1235 bNewPos = sal_True; 1236 } 1237 else 1238 { 1239 // we look for the first row after the selected block for selection 1240 long nIdx = LastSelectedRow() + 1; 1241 if (nIdx < GetRowCount() - 1) 1242 { 1243 // there is a next row to position on 1244 if (SeekCursor(nIdx)) 1245 { 1246 GetSeekRow()->SetState(m_pSeekCursor, sal_True); 1247 1248 bNewPos = sal_True; 1249 // if it's not the row for inserting we keep the bookmark 1250 if (!IsInsertionRow(nIdx)) 1251 aBookmark = m_pSeekCursor->getBookmark(); 1252 } 1253 } 1254 else 1255 { 1256 // we look for the first row before the selected block for selection after deletion 1257 nIdx = FirstSelectedRow() - 1; 1258 if (nIdx >= 0 && SeekCursor(nIdx)) 1259 { 1260 GetSeekRow()->SetState(m_pSeekCursor, sal_True); 1261 1262 bNewPos = sal_True; 1263 aBookmark = m_pSeekCursor->getBookmark(); 1264 } 1265 } 1266 } 1267 1268 // Sind alle Zeilen Selectiert 1269 // Zweite bedingung falls keine einguegeZeile existiert 1270 sal_Bool bAllSelected = GetTotalCount() == nSelectedRows || GetRowCount() == nSelectedRows; 1271 1272 BeginCursorAction(); 1273 1274 // now delete the row 1275 Sequence <sal_Int32> aDeletedRows; 1276 SetUpdateMode( sal_False ); 1277 try 1278 { 1279 aDeletedRows = xDeleteThem->deleteRows(aBookmarks); 1280 } 1281 catch(SQLException&) 1282 { 1283 } 1284 SetUpdateMode( sal_True ); 1285 1286 // how many rows are deleted? 1287 sal_Int32 nDeletedRows = 0; 1288 const sal_Int32* pSuccess = aDeletedRows.getConstArray(); 1289 for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++) 1290 { 1291 if (pSuccess[i]) 1292 ++nDeletedRows; 1293 } 1294 1295 // sind Zeilen geloescht worden? 1296 if (nDeletedRows) 1297 { 1298 SetUpdateMode(sal_False); 1299 SetNoSelection(); 1300 try 1301 { 1302 // did we delete all the rows than try to move to the next possible row 1303 if (nDeletedRows == aDeletedRows.getLength()) 1304 { 1305 // there exists a new position to move on 1306 if (bNewPos) 1307 { 1308 if (aBookmark.hasValue()) 1309 getDataSource()->moveToBookmark(aBookmark); 1310 // no valid bookmark so move to the insert row 1311 else 1312 { 1313 Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY); 1314 xUpdateCursor->moveToInsertRow(); 1315 } 1316 } 1317 else 1318 { 1319 Reference< ::com::sun::star::beans::XPropertySet > xSet((Reference< XInterface >)*m_pDataCursor, UNO_QUERY); 1320 1321 sal_Int32 nRecordCount(0); 1322 xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount; 1323 if ( m_pDataCursor->rowDeleted() ) 1324 --nRecordCount; 1325 1326 // there are no rows left and we have an insert row 1327 if (!nRecordCount && GetEmptyRow().Is()) 1328 { 1329 Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY); 1330 xUpdateCursor->moveToInsertRow(); 1331 } 1332 else if (nRecordCount) 1333 // move to the first row 1334 getDataSource()->first(); 1335 } 1336 } 1337 // not all the rows where deleted, so move to the first row which remained in the resultset 1338 else 1339 { 1340 for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++) 1341 { 1342 if (!pSuccess[i]) 1343 { 1344 getDataSource()->moveToBookmark(aBookmarks.getConstArray()[i]); 1345 break; 1346 } 1347 } 1348 } 1349 } 1350 catch(const Exception&) 1351 { 1352 try 1353 { 1354 // positioning went wrong so try to move to the first row 1355 getDataSource()->first(); 1356 } 1357 catch(const Exception&) 1358 { 1359 } 1360 } 1361 1362 // An den DatenCursor anpassen 1363 AdjustDataSource(sal_True); 1364 1365 // es konnten nicht alle Zeilen geloescht werden 1366 // da nie nicht geloeschten wieder selektieren 1367 if (nDeletedRows < nSelectedRows) 1368 { 1369 // waren alle selektiert 1370 if (bAllSelected) 1371 { 1372 SelectAll(); 1373 if (IsInsertionRow(GetRowCount() - 1)) // einfuegeZeile nicht 1374 SelectRow(GetRowCount() - 1, sal_False); 1375 } 1376 else 1377 { 1378 // select the remaining rows 1379 for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++) 1380 { 1381 try 1382 { 1383 if (!pSuccess[i]) 1384 { 1385 m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark()); 1386 SetSeekPos(m_pSeekCursor->getRow() - 1); 1387 SelectRow(GetSeekPos()); 1388 } 1389 } 1390 catch(const Exception&) 1391 { 1392 // keep the seekpos in all cases 1393 SetSeekPos(m_pSeekCursor->getRow() - 1); 1394 } 1395 } 1396 } 1397 } 1398 1399 EndCursorAction(); 1400 SetUpdateMode(sal_True); 1401 } 1402 else // Zeile konnte nicht geloescht werden 1403 { 1404 EndCursorAction(); 1405 try 1406 { 1407 // currentrow is the insert row? 1408 if (!IsCurrentAppending()) 1409 getDataSource()->refreshRow(); 1410 } 1411 catch(const Exception&) 1412 { 1413 } 1414 } 1415 } 1416 1417 // if there is no selection anymore we can start editing 1418 if (!GetSelectRowCount()) 1419 ActivateCell(); 1420 } 1421 1422 1423 // XCurrentRecordListener 1424 //------------------------------------------------------------------------------ 1425 void FmGridControl::positioned(const ::com::sun::star::lang::EventObject& /*rEvent*/) 1426 { 1427 TRACE_RANGE("FmGridControl::positioned"); 1428 // position on the data source (force it to be done in the main thread) 1429 implAdjustInSolarThread(sal_False); 1430 } 1431 1432 //------------------------------------------------------------------------------ 1433 sal_Bool FmGridControl::commit() 1434 { 1435 // Commit nur ausfuehren, wenn nicht bereits ein Update vom ::com::sun::star::form::component::GridControl ausgefuehrt 1436 // wird 1437 if (!IsUpdating()) 1438 { 1439 if (Controller().Is() && Controller()->IsModified()) 1440 { 1441 if (!SaveModified()) 1442 return sal_False; 1443 } 1444 } 1445 return sal_True; 1446 } 1447 1448 //------------------------------------------------------------------------------ 1449 void FmGridControl::inserted(const ::com::sun::star::lang::EventObject& /*rEvent*/) 1450 { 1451 const DbGridRowRef& xRow = GetCurrentRow(); 1452 if (!xRow.Is()) 1453 return; 1454 1455 // Zeile ist eingefuegt worden, dann den status und mode zuruecksetzen 1456 xRow->SetState(m_pDataCursor, sal_False); 1457 xRow->SetNew(sal_False); 1458 1459 } 1460 1461 // XCancelUpdateRecordListener 1462 //------------------------------------------------------------------------------ 1463 void FmGridControl::restored(const ::com::sun::star::lang::EventObject& rEvent) 1464 { 1465 if (!GetCurrentRow().Is()) 1466 return; 1467 1468 sal_Bool bAppending = GetCurrentRow()->IsNew(); 1469 sal_Bool bDirty = GetCurrentRow()->IsModified(); 1470 if (bAppending && (EditBrowseBox::IsModified() || bDirty)) 1471 { 1472 if (Controller().Is()) 1473 Controller()->ClearModified(); 1474 1475 // jetzt die Zeile herausnehmen 1476 RowRemoved(GetRowCount() - 1, 1, sal_True); 1477 GetNavigationBar().InvalidateAll(); 1478 } 1479 1480 positioned(rEvent); 1481 } 1482 1483 //------------------------------------------------------------------------------ 1484 BrowserHeader* FmGridControl::imp_CreateHeaderBar(BrowseBox* pParent) 1485 { 1486 DBG_ASSERT( pParent == this, "FmGridControl::imp_CreateHeaderBar: parent?" ); 1487 return new FmGridHeader( pParent ); 1488 } 1489 1490 //------------------------------------------------------------------------------ 1491 void FmGridControl::markColumn(sal_uInt16 nId) 1492 { 1493 if (GetHeaderBar() && m_nMarkedColumnId != nId) 1494 { 1495 // deselektieren 1496 if (m_nMarkedColumnId != BROWSER_INVALIDID) 1497 { 1498 HeaderBarItemBits aBits = GetHeaderBar()->GetItemBits(m_nMarkedColumnId) & ~HIB_FLAT; 1499 GetHeaderBar()->SetItemBits(m_nMarkedColumnId, aBits); 1500 } 1501 1502 1503 if (nId != BROWSER_INVALIDID) 1504 { 1505 HeaderBarItemBits aBits = GetHeaderBar()->GetItemBits(nId) | HIB_FLAT; 1506 GetHeaderBar()->SetItemBits(nId, aBits); 1507 } 1508 m_nMarkedColumnId = nId; 1509 } 1510 } 1511 1512 //------------------------------------------------------------------------------ 1513 sal_Bool FmGridControl::isColumnMarked(sal_uInt16 nId) const 1514 { 1515 return m_nMarkedColumnId == nId; 1516 } 1517 1518 //------------------------------------------------------------------------------ 1519 long FmGridControl::QueryMinimumRowHeight() 1520 { 1521 long nMinimalLogicHeight = 20; // 0.2 cm 1522 long nMinimalPixelHeight = LogicToPixel( Point( 0, nMinimalLogicHeight ), MAP_10TH_MM ).Y(); 1523 return CalcZoom( nMinimalPixelHeight ); 1524 } 1525 1526 //------------------------------------------------------------------------------ 1527 void FmGridControl::RowHeightChanged() 1528 { 1529 DbGridControl::RowHeightChanged(); 1530 1531 Reference< XPropertySet > xModel( GetPeer()->getColumns(), UNO_QUERY ); 1532 DBG_ASSERT( xModel.is(), "FmGridControl::RowHeightChanged: no model!" ); 1533 if ( xModel.is() ) 1534 { 1535 try 1536 { 1537 sal_Int32 nUnzoomedPixelHeight = CalcReverseZoom( GetDataRowHeight() ); 1538 Any aProperty = makeAny( (sal_Int32)PixelToLogic( Point( 0, nUnzoomedPixelHeight ), MAP_10TH_MM ).Y() ); 1539 xModel->setPropertyValue( FM_PROP_ROWHEIGHT, aProperty ); 1540 } 1541 catch( const Exception& ) 1542 { 1543 OSL_ENSURE( sal_False, "FmGridControl::RowHeightChanged: caught an exception!" ); 1544 } 1545 } 1546 } 1547 1548 //------------------------------------------------------------------------------ 1549 void FmGridControl::ColumnResized(sal_uInt16 nId) 1550 { 1551 DbGridControl::ColumnResized(nId); 1552 1553 // Wert ans model uebergeben 1554 DbGridColumn* pCol = DbGridControl::GetColumns().GetObject(GetModelColumnPos(nId)); 1555 Reference< ::com::sun::star::beans::XPropertySet > xColModel(pCol->getModel()); 1556 if (xColModel.is()) 1557 { 1558 Any aWidth; 1559 sal_Int32 nColumnWidth = GetColumnWidth(nId); 1560 nColumnWidth = CalcReverseZoom(nColumnWidth); 1561 // Umrechnen in 10THMM 1562 aWidth <<= (sal_Int32)PixelToLogic(Point(nColumnWidth,0),MAP_10TH_MM).X(); 1563 xColModel->setPropertyValue(FM_PROP_WIDTH, aWidth); 1564 } 1565 } 1566 1567 //------------------------------------------------------------------------------ 1568 void FmGridControl::CellModified() 1569 { 1570 DbGridControl::CellModified(); 1571 GetPeer()->CellModified(); 1572 } 1573 1574 //------------------------------------------------------------------------------ 1575 void FmGridControl::BeginCursorAction() 1576 { 1577 DbGridControl::BeginCursorAction(); 1578 m_pPeer->stopCursorListening(); 1579 } 1580 1581 //------------------------------------------------------------------------------ 1582 void FmGridControl::EndCursorAction() 1583 { 1584 m_pPeer->startCursorListening(); 1585 DbGridControl::EndCursorAction(); 1586 } 1587 1588 //------------------------------------------------------------------------------ 1589 void FmGridControl::ColumnMoved(sal_uInt16 nId) 1590 { 1591 m_bInColumnMove = sal_True; 1592 1593 DbGridControl::ColumnMoved(nId); 1594 Reference< ::com::sun::star::container::XIndexContainer > xColumns(GetPeer()->getColumns()); 1595 1596 if (xColumns.is()) 1597 { 1598 // suchen der Spalte und verschieben im Model 1599 // ColumnPos holen 1600 DbGridColumn* pCol = DbGridControl::GetColumns().GetObject(GetModelColumnPos(nId)); 1601 Reference< ::com::sun::star::beans::XPropertySet > xCol; 1602 1603 // Einfuegen muß sich an den Column Positionen orientieren 1604 sal_Int32 i; 1605 Reference< XInterface > xCurrent; 1606 for (i = 0; !xCol.is() && i < xColumns->getCount(); i++) 1607 { 1608 ::cppu::extractInterface(xCurrent, xColumns->getByIndex(i)); 1609 if (xCurrent == pCol->getModel()) 1610 { 1611 xCol = pCol->getModel(); 1612 break; 1613 } 1614 } 1615 1616 DBG_ASSERT(i < xColumns->getCount(), "Falscher ::com::sun::star::sdbcx::Index"); 1617 xColumns->removeByIndex(i); 1618 Any aElement; 1619 aElement <<= xCol; 1620 xColumns->insertByIndex(GetModelColumnPos(nId), aElement); 1621 pCol->setModel(xCol); 1622 // if the column which is shown here is selected ... 1623 if ( isColumnSelected(nId,pCol) ) 1624 markColumn(nId); // ... -> mark it 1625 } 1626 1627 m_bInColumnMove = sal_False; 1628 } 1629 1630 //------------------------------------------------------------------------------ 1631 void FmGridControl::InitColumnsByModels(const Reference< ::com::sun::star::container::XIndexContainer >& xColumns) 1632 { 1633 // Spalten wieder neu setzen 1634 // wenn es nur eine HandleColumn gibt, dann nicht 1635 if (GetModelColCount()) 1636 { 1637 RemoveColumns(); 1638 InsertHandleColumn(); 1639 } 1640 1641 if (!xColumns.is()) 1642 return; 1643 1644 SetUpdateMode(sal_False); 1645 1646 // Einfuegen mu� sich an den Column Positionen orientieren 1647 sal_Int32 i; 1648 String aName; 1649 Any aWidth; 1650 for (i = 0; i < xColumns->getCount(); ++i) 1651 { 1652 Reference< ::com::sun::star::beans::XPropertySet > xCol; 1653 ::cppu::extractInterface(xCol, xColumns->getByIndex(i)); 1654 1655 aName = (const sal_Unicode*)::comphelper::getString(xCol->getPropertyValue(FM_PROP_LABEL)); 1656 1657 aWidth = xCol->getPropertyValue(FM_PROP_WIDTH); 1658 sal_Int32 nWidth = 0; 1659 if (aWidth >>= nWidth) 1660 nWidth = LogicToPixel(Point(nWidth,0),MAP_10TH_MM).X(); 1661 1662 AppendColumn(aName, (sal_uInt16)nWidth); 1663 DbGridColumn* pCol = DbGridControl::GetColumns().GetObject(i); 1664 pCol->setModel(xCol); 1665 } 1666 1667 // und jetzt noch die hidden columns rausnehmen 1668 // (wir haben das nicht gleich in der oberen Schleife gemacht, da wir dann Probleme mit den 1669 // IDs der Spalten bekommen haetten : AppendColumn vergibt die automatisch, die Spalte _nach_ 1670 // einer versteckten braucht aber eine um eine erhoehte ID .... 1671 Any aHidden; 1672 for (i = 0; i < xColumns->getCount(); ++i) 1673 { 1674 Reference< ::com::sun::star::beans::XPropertySet > xCol; 1675 ::cppu::extractInterface(xCol, xColumns->getByIndex(i)); 1676 aHidden = xCol->getPropertyValue(FM_PROP_HIDDEN); 1677 if (::comphelper::getBOOL(aHidden)) 1678 HideColumn(GetColumnIdFromModelPos((sal_uInt16)i)); 1679 } 1680 1681 SetUpdateMode(sal_True); 1682 } 1683 1684 //------------------------------------------------------------------------------ 1685 void FmGridControl::InitColumnByField( 1686 DbGridColumn* _pColumn, const Reference< XPropertySet >& _rxColumnModel, 1687 const Reference< XNameAccess >& _rxFieldsByNames, const Reference< XIndexAccess >& _rxFieldsByIndex ) 1688 { 1689 DBG_ASSERT( _rxFieldsByNames == _rxFieldsByIndex, "FmGridControl::InitColumnByField: invalid container interfaces!" ); 1690 1691 // lookup the column which belongs to the control source 1692 ::rtl::OUString sFieldName; 1693 _rxColumnModel->getPropertyValue( FM_PROP_CONTROLSOURCE ) >>= sFieldName; 1694 Reference< XPropertySet > xField; 1695 _rxColumnModel->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField; 1696 1697 1698 if ( !xField.is() && /*sFieldName.getLength() && */_rxFieldsByNames->hasByName( sFieldName ) ) // #i93452# do not check for name length 1699 _rxFieldsByNames->getByName( sFieldName ) >>= xField; 1700 1701 // determine the position of this column 1702 sal_Int32 nFieldPos = -1; 1703 if ( xField.is() ) 1704 { 1705 Reference< XPropertySet > xCheck; 1706 sal_Int32 nFieldCount = _rxFieldsByIndex->getCount(); 1707 for ( sal_Int32 i = 0; i < nFieldCount; ++i) 1708 { 1709 _rxFieldsByIndex->getByIndex( i ) >>= xCheck; 1710 if ( xField.get() == xCheck.get() ) 1711 { 1712 nFieldPos = i; 1713 break; 1714 } 1715 } 1716 } 1717 1718 if ( xField.is() && ( nFieldPos >= 0 ) ) 1719 { 1720 // some data types are not allowed 1721 sal_Int32 nDataType = DataType::OTHER; 1722 xField->getPropertyValue( FM_PROP_FIELDTYPE ) >>= nDataType; 1723 1724 sal_Bool bIllegalType = sal_False; 1725 switch ( nDataType ) 1726 { 1727 case DataType::BLOB: 1728 case DataType::LONGVARBINARY: 1729 case DataType::BINARY: 1730 case DataType::VARBINARY: 1731 case DataType::OTHER: 1732 bIllegalType = sal_True; 1733 break; 1734 } 1735 1736 if ( bIllegalType ) 1737 { 1738 _pColumn->SetObject( (sal_Int16)nFieldPos ); 1739 return; 1740 } 1741 /* 1742 // handle readonly columns 1743 sal_Bool bReadOnly = sal_True; 1744 xField->getPropertyValue( FM_PROP_ISREADONLY ) >>= bReadOnly; 1745 _pColumn->SetReadOnly( bReadOnly ); 1746 */ 1747 } 1748 1749 // the control type is determined by the ColumnServiceName 1750 static ::rtl::OUString s_sPropColumnServiceName( RTL_CONSTASCII_USTRINGPARAM( "ColumnServiceName" ) ); 1751 if ( !::comphelper::hasProperty( s_sPropColumnServiceName, _rxColumnModel ) ) 1752 return; 1753 1754 _pColumn->setModel( _rxColumnModel ); 1755 1756 ::rtl::OUString sColumnServiceName; 1757 _rxColumnModel->getPropertyValue( s_sPropColumnServiceName ) >>= sColumnServiceName; 1758 1759 sal_Int32 nTypeId = getColumnTypeByModelName( sColumnServiceName ); 1760 _pColumn->CreateControl( nFieldPos, xField, nTypeId ); 1761 } 1762 1763 //------------------------------------------------------------------------------ 1764 void FmGridControl::InitColumnsByFields(const Reference< ::com::sun::star::container::XIndexAccess >& _rxFields) 1765 { 1766 if ( !_rxFields.is() ) 1767 return; 1768 1769 // Spalten initialisieren 1770 Reference< XIndexContainer > xColumns( GetPeer()->getColumns() ); 1771 Reference< XNameAccess > xFieldsAsNames( _rxFields, UNO_QUERY ); 1772 1773 // Einfuegen muss sich an den Column Positionen orientieren 1774 for (sal_Int32 i = 0; i < xColumns->getCount(); i++) 1775 { 1776 DbGridColumn* pCol = GetColumns().GetObject(i); 1777 OSL_ENSURE(pCol,"No grid column!"); 1778 if ( pCol ) 1779 { 1780 Reference< XPropertySet > xColumnModel; 1781 ::cppu::extractInterface( xColumnModel, xColumns->getByIndex( i ) ); 1782 1783 InitColumnByField( pCol, xColumnModel, xFieldsAsNames, _rxFields ); 1784 } 1785 } 1786 } 1787 1788 //------------------------------------------------------------------------------ 1789 void FmGridControl::HideColumn(sal_uInt16 nId) 1790 { 1791 DbGridControl::HideColumn(nId); 1792 1793 sal_uInt16 nPos = GetModelColumnPos(nId); 1794 if (nPos == (sal_uInt16)-1) 1795 return; 1796 1797 DbGridColumn* pColumn = GetColumns().GetObject(nPos); 1798 if (pColumn->IsHidden()) 1799 GetPeer()->columnHidden(pColumn); 1800 1801 if (nId == m_nMarkedColumnId) 1802 m_nMarkedColumnId = (sal_uInt16)-1; 1803 } 1804 // ----------------------------------------------------------------------------- 1805 sal_Bool FmGridControl::isColumnSelected(sal_uInt16 /*nId*/,DbGridColumn* _pColumn) 1806 { 1807 OSL_ENSURE(_pColumn,"Column can not be null!"); 1808 sal_Bool bSelected = sal_False; 1809 // if the column which is shown here is selected ... 1810 Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(GetPeer()->getColumns(), UNO_QUERY); 1811 if ( xSelSupplier.is() ) 1812 { 1813 Reference< ::com::sun::star::beans::XPropertySet > xColumn; 1814 xSelSupplier->getSelection() >>= xColumn; 1815 bSelected = (xColumn.get() == _pColumn->getModel().get()); 1816 } 1817 return bSelected; 1818 } 1819 1820 //------------------------------------------------------------------------------ 1821 void FmGridControl::ShowColumn(sal_uInt16 nId) 1822 { 1823 DbGridControl::ShowColumn(nId); 1824 1825 sal_uInt16 nPos = GetModelColumnPos(nId); 1826 if (nPos == (sal_uInt16)-1) 1827 return; 1828 1829 DbGridColumn* pColumn = GetColumns().GetObject(nPos); 1830 if (!pColumn->IsHidden()) 1831 GetPeer()->columnVisible(pColumn); 1832 1833 // if the column which is shown here is selected ... 1834 if ( isColumnSelected(nId,pColumn) ) 1835 markColumn(nId); // ... -> mark it 1836 } 1837 1838 //------------------------------------------------------------------------------ 1839 sal_Bool FmGridControl::selectBookmarks(const Sequence< Any >& _rBookmarks) 1840 { 1841 vos::OGuard aGuard( Application::GetSolarMutex() ); 1842 // need to lock the SolarMutex so that no paint call disturbs us ... 1843 1844 if ( !m_pSeekCursor ) 1845 { 1846 DBG_ERROR( "FmGridControl::selectBookmarks: no seek cursor!" ); 1847 return sal_False; 1848 } 1849 1850 const Any* pBookmark = _rBookmarks.getConstArray(); 1851 const Any* pBookmarkEnd = pBookmark + _rBookmarks.getLength(); 1852 1853 SetNoSelection(); 1854 1855 sal_Bool bAllSuccessfull = sal_True; 1856 try 1857 { 1858 for (; pBookmark != pBookmarkEnd; ++pBookmark) 1859 { 1860 // move the seek cursor to the row given 1861 if (m_pSeekCursor->moveToBookmark(*pBookmark)) 1862 SelectRow( m_pSeekCursor->getRow() - 1); 1863 else 1864 bAllSuccessfull = sal_False; 1865 } 1866 } 1867 catch(Exception&) 1868 { 1869 DBG_ERROR("FmGridControl::selectBookmarks: could not move to one of the bookmarks!"); 1870 return sal_False; 1871 } 1872 1873 return bAllSuccessfull; 1874 } 1875 1876 //------------------------------------------------------------------------------ 1877 Sequence< Any> FmGridControl::getSelectionBookmarks() 1878 { 1879 // lock our update so no paint-triggered seeks interfere ... 1880 SetUpdateMode(sal_False); 1881 1882 sal_Int32 nSelectedRows = GetSelectRowCount(), i = 0; 1883 Sequence< Any> aBookmarks(nSelectedRows); 1884 if ( nSelectedRows ) 1885 { 1886 Any* pBookmarks = (Any*)aBookmarks.getArray(); 1887 1888 // (I'm not sure if the problem isn't deeper : The szenario : a large table displayed by a grid with a 1889 // thread-safe cursor (dBase). On loading the sdb-cursor started a counting thread. While this counting progress 1890 // was running, I tried do delete 3 records from within the grid. Deletion caused a SeekCursor, which did a 1891 // m_pSeekCursor->moveRelative and a m_pSeekCursor->getPosition. 1892 // Unfortunally the first call caused a propertyChanged(RECORDCOUNT) which resulted in a repaint of the 1893 // navigation bar and the grid. The latter itself will result in SeekRow calls. So after (successfully) returning 1894 // from the moveRelative the getPosition returns an invalid value. And so the SeekCursor fails. 1895 // In the consequence ALL parts of code where two calls to the seek cursor are done, while the second call _relys_ on 1896 // the first one, should be secured against recursion, with a broad-minded interpretion of "recursion" : if any of these 1897 // code parts is executed, no other should be accessible. But this sounds very difficult to achieve .... 1898 // ) 1899 1900 // The next problem caused by the same behaviuor (SeekCursor causes a propertyChanged) : when adjusting rows we implicitly 1901 // change our selection. So a "FirstSelected(); SeekCursor(); NextSelected();" may produce unpredictable results. 1902 // That's why we _first_ collect the indicies of the selected rows and _then_ their bookmarks. 1903 long nIdx = FirstSelectedRow(); 1904 while (nIdx >= 0) 1905 { 1906 // (we misuse the bookmarks array for this ...) 1907 pBookmarks[i++] <<= (sal_Int32)nIdx; 1908 nIdx = NextSelectedRow(); 1909 } 1910 DBG_ASSERT(i == nSelectedRows, "FmGridControl::DeleteSelectedRows : could not collect the row indicies !"); 1911 1912 for (i=0; i<nSelectedRows; ++i) 1913 { 1914 nIdx = ::comphelper::getINT32(pBookmarks[i]); 1915 if (IsInsertionRow(nIdx)) 1916 { 1917 // leerzeile nicht loeschen 1918 aBookmarks.realloc(--nSelectedRows); 1919 SelectRow(nIdx,sal_False); // selection aufheben fuer leerzeile 1920 break; 1921 } 1922 1923 // Zunaechst den DatenCursor auf den selektierten Satz pos. 1924 if (SeekCursor(nIdx)) 1925 { 1926 GetSeekRow()->SetState(m_pSeekCursor, sal_True); 1927 1928 pBookmarks[i] = m_pSeekCursor->getBookmark(); 1929 } 1930 #ifdef DBG_UTIL 1931 else 1932 DBG_ERROR("FmGridControl::DeleteSelectedRows : a bookmark could not be determined !"); 1933 #endif 1934 } 1935 } 1936 SetUpdateMode(sal_True); 1937 1938 // if one of the SeekCursor-calls failed .... 1939 aBookmarks.realloc(i); 1940 1941 // (the alternative : while collecting the bookmarks lock our propertyChanged, this should resolve both our problems. 1942 // but this would be incompatible as we need a locking flag, then ...) 1943 1944 return aBookmarks; 1945 } 1946 // ----------------------------------------------------------------------------- 1947 namespace 1948 { 1949 ::rtl::OUString getColumnPropertyFromPeer(FmXGridPeer* _pPeer,sal_Int32 _nPosition,const ::rtl::OUString& _sPropName) 1950 { 1951 ::rtl::OUString sRetText; 1952 if ( _pPeer && _nPosition != -1) 1953 { 1954 Reference<XIndexContainer> xIndex = _pPeer->getColumns(); 1955 if ( xIndex.is() && xIndex->getCount() > _nPosition ) 1956 { 1957 Reference<XPropertySet> xProp; 1958 xIndex->getByIndex( _nPosition ) >>= xProp; 1959 if ( xProp.is() ) 1960 xProp->getPropertyValue( _sPropName ) >>= sRetText; 1961 } 1962 } 1963 return sRetText; 1964 } 1965 } 1966 // Object data and state ------------------------------------------------------ 1967 ::rtl::OUString FmGridControl::GetAccessibleObjectName( ::svt::AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const 1968 { 1969 ::rtl::OUString sRetText; 1970 switch( _eObjType ) 1971 { 1972 case ::svt::BBTYPE_BROWSEBOX: 1973 if ( GetPeer() ) 1974 { 1975 Reference<XPropertySet> xProp(GetPeer()->getColumns(),UNO_QUERY); 1976 if ( xProp.is() ) 1977 xProp->getPropertyValue(FM_PROP_NAME) >>= sRetText; 1978 } 1979 break; 1980 case ::svt::BBTYPE_COLUMNHEADERCELL: 1981 sRetText = getColumnPropertyFromPeer( 1982 GetPeer(), 1983 GetModelColumnPos( 1984 sal::static_int_cast< sal_uInt16 >(_nPosition)), 1985 FM_PROP_LABEL); 1986 break; 1987 default: 1988 sRetText = DbGridControl::GetAccessibleObjectName(_eObjType,_nPosition); 1989 } 1990 return sRetText; 1991 } 1992 // ----------------------------------------------------------------------------- 1993 1994 ::rtl::OUString FmGridControl::GetAccessibleObjectDescription( ::svt::AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const 1995 { 1996 ::rtl::OUString sRetText; 1997 switch( _eObjType ) 1998 { 1999 case ::svt::BBTYPE_BROWSEBOX: 2000 if ( GetPeer() ) 2001 { 2002 Reference<XPropertySet> xProp(GetPeer()->getColumns(),UNO_QUERY); 2003 if ( xProp.is() ) 2004 { 2005 xProp->getPropertyValue(FM_PROP_HELPTEXT) >>= sRetText; 2006 if ( !sRetText.getLength() ) 2007 xProp->getPropertyValue(FM_PROP_DESCRIPTION) >>= sRetText; 2008 } 2009 } 2010 break; 2011 case ::svt::BBTYPE_COLUMNHEADERCELL: 2012 sRetText = getColumnPropertyFromPeer( 2013 GetPeer(), 2014 GetModelColumnPos( 2015 sal::static_int_cast< sal_uInt16 >(_nPosition)), 2016 FM_PROP_HELPTEXT); 2017 if ( !sRetText.getLength() ) 2018 sRetText = getColumnPropertyFromPeer( 2019 GetPeer(), 2020 GetModelColumnPos( 2021 sal::static_int_cast< sal_uInt16 >(_nPosition)), 2022 FM_PROP_DESCRIPTION); 2023 2024 break; 2025 default: 2026 sRetText = DbGridControl::GetAccessibleObjectDescription(_eObjType,_nPosition); 2027 } 2028 return sRetText; 2029 } 2030 // ----------------------------------------------------------------------------- 2031 void FmGridControl::Select() 2032 { 2033 DbGridControl::Select(); 2034 // ... betrifft das unsere Spalten ? 2035 const MultiSelection* pColumnSelection = GetColumnSelection(); 2036 2037 sal_uInt16 nSelectedColumn = 2038 pColumnSelection && pColumnSelection->GetSelectCount() 2039 ? sal::static_int_cast< sal_uInt16 >( 2040 ((MultiSelection*)pColumnSelection)->FirstSelected()) 2041 : SAL_MAX_UINT16; 2042 // die HandleColumn wird nicht selektiert 2043 switch (nSelectedColumn) 2044 { 2045 case SAL_MAX_UINT16: break; // no selection 2046 case 0 : nSelectedColumn = SAL_MAX_UINT16; break; 2047 // handle col can't be seledted 2048 default : 2049 // get the model col pos instead of the view col pos 2050 nSelectedColumn = GetModelColumnPos(GetColumnIdFromViewPos(nSelectedColumn - 1)); 2051 break; 2052 } 2053 2054 if (nSelectedColumn != m_nCurrentSelectedColumn) 2055 { 2056 // VOR dem Aufruf des select am SelectionSupplier ! 2057 m_nCurrentSelectedColumn = nSelectedColumn; 2058 2059 if (!m_bSelecting) 2060 { 2061 m_bSelecting = sal_True; 2062 2063 try 2064 { 2065 Reference< XIndexAccess > xColumns(GetPeer()->getColumns(), UNO_QUERY); 2066 Reference< XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY); 2067 if (xSelSupplier.is()) 2068 { 2069 if (nSelectedColumn != SAL_MAX_UINT16) 2070 { 2071 Reference< XPropertySet > xColumn; 2072 ::cppu::extractInterface(xColumn,xColumns->getByIndex(nSelectedColumn)); 2073 xSelSupplier->select(makeAny(xColumn)); 2074 } 2075 else 2076 { 2077 xSelSupplier->select(Any()); 2078 } 2079 } 2080 } 2081 catch(Exception&) 2082 { 2083 } 2084 2085 2086 m_bSelecting = sal_False; 2087 } 2088 } 2089 } 2090 // ----------------------------------------------------------------------------- 2091 sal_Int32 FmGridControl::GetSelectedColumn() const 2092 { 2093 return m_nCurrentSelectedColumn; 2094 } 2095 // ----------------------------------------------------------------------------- 2096 void FmGridControl::KeyInput( const KeyEvent& rKEvt ) 2097 { 2098 sal_Bool bDone = sal_False; 2099 const KeyCode& rKeyCode = rKEvt.GetKeyCode(); 2100 if ( IsDesignMode() 2101 && !rKeyCode.IsShift() 2102 && !rKeyCode.IsMod1() 2103 && !rKeyCode.IsMod2() 2104 && GetParent() ) 2105 { 2106 switch ( rKeyCode.GetCode() ) 2107 { 2108 case KEY_ESCAPE: 2109 GetParent()->GrabFocus(); 2110 bDone = sal_True; 2111 break; 2112 case KEY_DELETE: 2113 if ( GetSelectColumnCount() && GetPeer() && m_nCurrentSelectedColumn >= 0 ) 2114 { 2115 Reference< ::com::sun::star::container::XIndexContainer > xCols(GetPeer()->getColumns()); 2116 if ( xCols.is() ) 2117 { 2118 try 2119 { 2120 if ( m_nCurrentSelectedColumn < xCols->getCount() ) 2121 { 2122 Reference< XInterface > xCol; 2123 xCols->getByIndex(m_nCurrentSelectedColumn) >>= xCol; 2124 xCols->removeByIndex(m_nCurrentSelectedColumn); 2125 ::comphelper::disposeComponent(xCol); 2126 } 2127 } 2128 catch(const Exception&) 2129 { 2130 OSL_ENSURE(0,"exception occured while deleting a column"); 2131 } 2132 } 2133 } 2134 bDone = sal_True; 2135 break; 2136 } 2137 } 2138 if ( !bDone ) 2139 DbGridControl::KeyInput( rKEvt ); 2140 } 2141 // ----------------------------------------------------------------------------- 2142 2143 2144 2145