update dev300-m58
[ooovba.git] / svx / source / fmcomp / fmgridcl.cxx
blobb681ddc6850cabaf280037bf2e2d6c8824877d7d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: fmgridcl.cxx,v $
10 * $Revision: 1.64.94.3 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 #include "dbexch.hrc"
35 #include "fmgridif.hxx"
36 #include "fmitems.hxx"
37 #include "fmprop.hrc"
38 #include "fmresids.hrc"
39 #include "fmservs.hxx"
40 #include "fmurl.hxx"
41 #include "formcontrolfactory.hxx"
42 #include "gridcell.hxx"
43 #include "gridcols.hxx"
44 #include "svx/dbaexchange.hxx"
45 #include "svx/dialmgr.hxx"
46 #include "svx/dialogs.hrc"
47 #include "svx/fmgridcl.hxx"
48 #include "svx/svxdlg.hxx"
49 #include "svx/svxids.hrc"
50 #include "trace.hxx"
52 #include <com/sun/star/form/XConfirmDeleteListener.hpp>
53 #include <com/sun/star/form/XFormComponent.hpp>
54 #include <com/sun/star/form/XGridColumnFactory.hpp>
55 #include <com/sun/star/io/XPersistObject.hpp>
56 #include <com/sun/star/sdb/CommandType.hpp>
57 #include <com/sun/star/sdb/RowChangeAction.hpp>
58 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
59 #include <com/sun/star/sdbc/DataType.hpp>
60 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
61 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
62 #include <com/sun/star/sdbcx/XDeleteRows.hpp>
63 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
64 #include <com/sun/star/uno/XNamingService.hpp>
65 #include <com/sun/star/util/XNumberFormats.hpp>
66 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
67 #include <com/sun/star/util/XURLTransformer.hpp>
68 #include <com/sun/star/view/XSelectionSupplier.hpp>
70 #ifndef _SVSTDARR_STRINGSDTOR
71 #define _SVSTDARR_STRINGSDTOR
72 #define _SVSTDARR_ULONGS
73 #include <svtools/svstdarr.hxx>
74 #endif
76 #include <comphelper/extract.hxx>
77 #include <comphelper/numbers.hxx>
78 #include <comphelper/processfactory.hxx>
79 #include <comphelper/property.hxx>
80 #include <connectivity/dbtools.hxx>
81 #include <sfx2/dispatch.hxx>
82 #include <sfx2/viewfrm.hxx>
83 #include <svtools/eitem.hxx>
84 #include <svtools/fmtfield.hxx>
85 #include <svtools/numuno.hxx>
86 #include <tools/multisel.hxx>
87 #include <tools/shl.hxx>
88 #include <tools/diagnose_ex.h>
89 #include <vcl/help.hxx>
90 #include <vcl/image.hxx>
91 #include <vcl/longcurr.hxx>
92 #include <vcl/menu.hxx>
94 #include <math.h>
96 using namespace ::com::sun::star::uno;
97 using namespace ::com::sun::star::view;
98 using namespace ::com::sun::star::beans;
99 using namespace ::com::sun::star::lang;
100 using namespace ::com::sun::star::sdbcx;
101 using namespace ::com::sun::star::sdbc;
102 using namespace ::com::sun::star::sdb;
103 using namespace ::com::sun::star::form;
104 using namespace ::com::sun::star::util;
105 using namespace ::com::sun::star::container;
106 using namespace ::cppu;
107 using namespace ::svxform;
108 using namespace ::svx;
110 //==============================================================================
111 //------------------------------------------------------------------------------
112 ::rtl::OUString FieldServiceFromId(sal_Int32 nID)
114 switch (nID)
116 case SID_FM_EDIT : return FM_COL_TEXTFIELD;
117 case SID_FM_COMBOBOX : return FM_COL_COMBOBOX;
118 case SID_FM_LISTBOX : return FM_COL_LISTBOX;
119 case SID_FM_CHECKBOX : return FM_COL_CHECKBOX;
120 case SID_FM_DATEFIELD : return FM_COL_DATEFIELD;
121 case SID_FM_TIMEFIELD : return FM_COL_TIMEFIELD;
122 case SID_FM_NUMERICFIELD : return FM_COL_NUMERICFIELD;
123 case SID_FM_CURRENCYFIELD : return FM_COL_CURRENCYFIELD;
124 case SID_FM_PATTERNFIELD : return FM_COL_PATTERNFIELD;
125 case SID_FM_FORMATTEDFIELD : return FM_COL_FORMATTEDFIELD;
127 return ::rtl::OUString();
130 //==============================================================================
131 struct FmGridHeaderData
133 ODataAccessDescriptor aDropData;
134 Point aDropPosPixel;
135 sal_Int8 nDropAction;
136 Reference< XInterface > xDroppedStatement;
137 Reference< XInterface > xDroppedResultSet;
140 //==============================================================================
141 //------------------------------------------------------------------------------
142 const sal_Int16 nChangeTypeOffset = 1000;
143 void SetMenuItem(const ImageList& rList, sal_uInt16 nID, Menu* pMenu, Menu& rNewMenu, sal_Bool bDesignMode = sal_True, sal_Int16 nOffset = nChangeTypeOffset)
145 pMenu->SetItemImage(nID, rList.GetImage(nID));
146 pMenu->EnableItem(nID, bDesignMode);
147 rNewMenu.InsertItem(nID + nOffset, pMenu->GetItemText(nID));
148 rNewMenu.SetItemImage(nID + nOffset, rList.GetImage(nID));
149 rNewMenu.SetHelpId(nID + nOffset, pMenu->GetHelpId(nID));
150 rNewMenu.EnableItem(nID + nOffset, bDesignMode);
153 //------------------------------------------------------------------------------
154 FmGridHeader::FmGridHeader( BrowseBox* pParent, WinBits nWinBits)
155 :EditBrowserHeader(pParent, nWinBits)
156 ,DropTargetHelper(this)
157 ,m_pImpl(new FmGridHeaderData)
161 //------------------------------------------------------------------------------
162 FmGridHeader::~FmGridHeader()
164 delete m_pImpl;
167 //------------------------------------------------------------------------------
168 sal_uInt16 FmGridHeader::GetModelColumnPos(sal_uInt16 nId) const
170 return static_cast<FmGridControl*>(GetParent())->GetModelColumnPos(nId);
172 //---------------------------------------------------------------------------------------
173 void FmGridHeader::notifyColumnSelect(sal_uInt16 nColumnId)
175 sal_uInt16 nPos = GetModelColumnPos(nColumnId);
176 Reference< XIndexAccess > xColumns(((FmGridControl*)GetParent())->GetPeer()->getColumns(), UNO_QUERY);
177 if ( nPos < xColumns->getCount() )
179 Reference< XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
180 if ( xSelSupplier.is() )
182 Reference< XPropertySet > xColumn;
183 xColumns->getByIndex(nPos) >>= xColumn;
184 xSelSupplier->select(makeAny(xColumn));
188 //------------------------------------------------------------------------------
189 void FmGridHeader::Select()
191 EditBrowserHeader::Select();
192 notifyColumnSelect(GetCurItemId());
195 //------------------------------------------------------------------------------
196 void FmGridHeader::RequestHelp( const HelpEvent& rHEvt )
198 sal_uInt16 nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
199 if ( nItemId )
201 if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) )
203 Rectangle aItemRect = GetItemRect( nItemId );
204 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
205 aItemRect.Left() = aPt.X();
206 aItemRect.Top() = aPt.Y();
207 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
208 aItemRect.Right() = aPt.X();
209 aItemRect.Bottom() = aPt.Y();
211 sal_uInt16 nPos = GetModelColumnPos(nItemId);
212 Reference< ::com::sun::star::container::XIndexContainer > xColumns(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
215 Reference< ::com::sun::star::beans::XPropertySet > xColumn;
216 ::cppu::extractInterface(xColumn, xColumns->getByIndex(nPos));
217 ::rtl::OUString aHelpText;
218 xColumn->getPropertyValue(FM_PROP_HELPTEXT) >>= aHelpText;
219 if ( aHelpText.getLength() )
221 if ( rHEvt.GetMode() & HELPMODE_BALLOON )
222 Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aHelpText );
223 else
224 Help::ShowQuickHelp( this, aItemRect, aHelpText );
225 return;
228 catch(Exception&)
230 return;
234 EditBrowserHeader::RequestHelp( rHEvt );
237 //------------------------------------------------------------------------------
238 sal_Int8 FmGridHeader::AcceptDrop( const AcceptDropEvent& rEvt )
240 // drop allowed in design mode only
241 if (!static_cast<FmGridControl*>(GetParent())->IsDesignMode())
242 return DND_ACTION_NONE;
244 // search for recognized formats
245 const DataFlavorExVector& rFlavors = GetDataFlavorExVector();
246 if (OColumnTransferable::canExtractColumnDescriptor(rFlavors, CTF_COLUMN_DESCRIPTOR | CTF_FIELD_DESCRIPTOR))
247 return rEvt.mnAction;
249 return DND_ACTION_NONE;
252 //------------------------------------------------------------------------------
253 sal_Int8 FmGridHeader::ExecuteDrop( const ExecuteDropEvent& _rEvt )
255 if (!static_cast<FmGridControl*>(GetParent())->IsDesignMode())
256 return DND_ACTION_NONE;
258 TransferableDataHelper aDroppedData(_rEvt.maDropEvent.Transferable);
260 // check the formats
261 sal_Bool bColumnDescriptor = OColumnTransferable::canExtractColumnDescriptor(aDroppedData.GetDataFlavorExVector(), CTF_COLUMN_DESCRIPTOR);
262 sal_Bool bFieldDescriptor = OColumnTransferable::canExtractColumnDescriptor(aDroppedData.GetDataFlavorExVector(), CTF_FIELD_DESCRIPTOR);
263 if (!bColumnDescriptor && !bFieldDescriptor)
265 DBG_ERROR("FmGridHeader::ExecuteDrop: should never have reached this (no extractable format)!");
266 return DND_ACTION_NONE;
269 // extract the descriptor
270 ::rtl::OUString sDatasouce, sCommand, sFieldName,sDatabaseLocation,sConnnectionResource;
271 sal_Int32 nCommandType = CommandType::COMMAND;
272 Reference< XPreparedStatement > xStatement;
273 Reference< XResultSet > xResultSet;
274 Reference< XPropertySet > xField;
275 Reference< XConnection > xConnection;
277 ODataAccessDescriptor aColumn = OColumnTransferable::extractColumnDescriptor(aDroppedData);
278 if (aColumn.has(daDataSource)) aColumn[daDataSource] >>= sDatasouce;
279 if (aColumn.has(daDatabaseLocation)) aColumn[daDatabaseLocation] >>= sDatabaseLocation;
280 if (aColumn.has(daConnectionResource)) aColumn[daConnectionResource] >>= sConnnectionResource;
281 if (aColumn.has(daCommand)) aColumn[daCommand] >>= sCommand;
282 if (aColumn.has(daCommandType)) aColumn[daCommandType] >>= nCommandType;
283 if (aColumn.has(daColumnName)) aColumn[daColumnName] >>= sFieldName;
284 if (aColumn.has(daColumnObject))aColumn[daColumnObject] >>= xField;
285 if (aColumn.has(daConnection)) aColumn[daConnection] >>= xConnection;
287 if ( !sFieldName.getLength()
288 || !sCommand.getLength()
289 || ( !sDatasouce.getLength()
290 && !sDatabaseLocation.getLength()
291 && !xConnection.is()
295 DBG_ERROR( "FmGridHeader::ExecuteDrop: somebody started a nonsense drag operation!!" );
296 return DND_ACTION_NONE;
301 // need a connection
302 if (!xConnection.is())
303 { // the transferable did not contain the connection -> build an own one
306 ::rtl::OUString sSignificantSource( sDatasouce.getLength() ? sDatasouce : sDatabaseLocation );
307 xConnection = OStaticDataAccessTools().getConnection_withFeedback(sSignificantSource, ::rtl::OUString(),::rtl::OUString(),static_cast<FmGridControl*>(GetParent())->getServiceManager());
309 catch(NoSuchElementException&)
310 { // allowed, means sDatasouce isn't a valid data source name ....
312 catch(Exception&)
314 DBG_ERROR("FmGridHeader::ExecuteDrop: could not retrieve the database access object !");
317 if (!xConnection.is())
319 DBG_ERROR("FmGridHeader::ExecuteDrop: could not retrieve the database access object !");
320 return DND_ACTION_NONE;
324 // try to obtain the column object
325 if (!xField.is())
327 #ifdef DBG_UTIL
328 Reference< XServiceInfo > xServiceInfo(xConnection, UNO_QUERY);
329 DBG_ASSERT(xServiceInfo.is() && xServiceInfo->supportsService(SRV_SDB_CONNECTION), "FmGridHeader::ExecuteDrop: invalid connection (no database access connection !)");
330 #endif
332 Reference< XNameAccess > xFields;
333 switch (nCommandType)
335 case CommandType::TABLE:
337 Reference< XTablesSupplier > xSupplyTables(xConnection, UNO_QUERY);
338 Reference< XColumnsSupplier > xSupplyColumns;
339 xSupplyTables->getTables()->getByName(sCommand) >>= xSupplyColumns;
340 xFields = xSupplyColumns->getColumns();
342 break;
343 case CommandType::QUERY:
345 Reference< XQueriesSupplier > xSupplyQueries(xConnection, UNO_QUERY);
346 Reference< XColumnsSupplier > xSupplyColumns;
347 xSupplyQueries->getQueries()->getByName(sCommand) >>= xSupplyColumns;
348 xFields = xSupplyColumns->getColumns();
350 break;
351 default:
353 xStatement = xConnection->prepareStatement(sCommand);
354 // not interested in any results
356 Reference< XPropertySet > xStatProps(xStatement,UNO_QUERY);
357 xStatProps->setPropertyValue(rtl::OUString::createFromAscii("MaxRows"), makeAny(sal_Int32(0)));
359 xResultSet = xStatement->executeQuery();
360 Reference< XColumnsSupplier > xSupplyCols(xResultSet, UNO_QUERY);
361 if (xSupplyCols.is())
362 xFields = xSupplyCols->getColumns();
366 if (xFields.is() && xFields->hasByName(sFieldName))
367 xFields->getByName(sFieldName) >>= xField;
369 if (!xField.is())
371 ::comphelper::disposeComponent(xStatement);
372 return DND_ACTION_NONE;
376 // do the drop asynchronously
377 // (85957 - UI actions within the drop are not allowed, but we want to open a popup menu)
378 m_pImpl->aDropData = aColumn;
379 m_pImpl->aDropData[daConnection] <<= xConnection;
380 m_pImpl->aDropData[daColumnObject] <<= xField;
382 m_pImpl->nDropAction = _rEvt.mnAction;
383 m_pImpl->aDropPosPixel = _rEvt.maPosPixel;
384 m_pImpl->xDroppedStatement = xStatement;
385 m_pImpl->xDroppedResultSet = xResultSet;
387 PostUserEvent(LINK(this, FmGridHeader, OnAsyncExecuteDrop));
389 catch (Exception&)
391 DBG_ERROR("FmGridHeader::ExecuteDrop: caught an exception while creatin' the column !");
392 ::comphelper::disposeComponent(xStatement);
393 return sal_False;
396 return DND_ACTION_LINK;
399 //------------------------------------------------------------------------------
400 IMPL_LINK( FmGridHeader, OnAsyncExecuteDrop, void*, /*NOTINTERESTEDIN*/ )
402 ::rtl::OUString sCommand, sFieldName,sURL;
403 sal_Int32 nCommandType = CommandType::COMMAND;
404 Reference< XPropertySet > xField;
405 Reference< XConnection > xConnection;
407 ::rtl::OUString sDatasouce = m_pImpl->aDropData.getDataSource();
408 if ( !sDatasouce.getLength() && m_pImpl->aDropData.has(daConnectionResource) )
409 m_pImpl->aDropData[daConnectionResource] >>= sURL;
410 m_pImpl->aDropData[daCommand] >>= sCommand;
411 m_pImpl->aDropData[daCommandType] >>= nCommandType;
412 m_pImpl->aDropData[daColumnName] >>= sFieldName;
413 m_pImpl->aDropData[daConnection] >>= xConnection;
414 m_pImpl->aDropData[daColumnObject] >>= xField;
418 // need number formats
419 Reference< XNumberFormatsSupplier > xSupplier = OStaticDataAccessTools().getNumberFormats(xConnection, sal_True);
420 Reference< XNumberFormats > xNumberFormats;
421 if (xSupplier.is())
422 xNumberFormats = xSupplier->getNumberFormats();
423 if (!xNumberFormats.is())
425 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
426 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
427 return 0L;
430 // Vom Feld werden nun zwei Informationen benoetigt:
431 // a.) Name des Feldes fuer Label und ControlSource
432 // b.) FormatKey, um festzustellen, welches Feld erzeugt werden soll
433 sal_Int32 nDataType = 0;
434 xField->getPropertyValue(FM_PROP_FIELDTYPE) >>= nDataType;
435 // diese Datentypen koennen im Gridcontrol nicht verarbeitet werden
436 switch (nDataType)
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;
447 // Erstellen der Column
448 Reference< XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
449 Reference< XGridColumnFactory > xFactory(xCols, UNO_QUERY);
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;
457 // erzeugen der Column in abhaengigkeit vom type, default textfeld
458 SvULongs aPossibleTypes;
459 switch (nDataType)
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;
500 // if it's a currency field, a a "currency field" option
503 if ( ::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField)
504 && ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY)))
505 aPossibleTypes.Insert(SID_FM_CURRENCYFIELD, 0);
507 catch(Exception&)
509 DBG_ERROR("FmGridHeader::ExecuteDrop: Exception occured!");
512 sal_Int32 nPreferedType = -1;
513 sal_Bool bDateNTimeCol = sal_False;
514 if (aPossibleTypes.Count() != 0)
516 nPreferedType = aPossibleTypes[0];
517 if ((m_pImpl->nDropAction == DND_ACTION_LINK) && (aPossibleTypes.Count() > 1))
519 ImageList aImageList( SVX_RES(RID_SVXIMGLIST_FMEXPL) );
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);
529 bDateNTimeCol = nPreferedType == SID_FM_TWOFIELDS_DATE_N_TIME;
530 sal_uInt16 nColCount = bDateNTimeCol ? 2 : 1;
531 ::rtl::OUString sFieldService;
532 while (nColCount--)
534 if (bDateNTimeCol)
535 nPreferedType = nColCount ? SID_FM_DATEFIELD : SID_FM_TIMEFIELD;
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;
548 if (!xCol.is() || (bDateNTimeCol && !xSecondCol.is()))
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;
556 if (bDateNTimeCol)
558 String sTimePostfix( SVX_RES( RID_STR_POSTFIX_TIME ) );
559 xCol->setPropertyValue(FM_PROP_LABEL, makeAny( ::rtl::OUString( sFieldName + sTimePostfix ) ) );
561 String sDatePostfix( SVX_RES( RID_STR_POSTFIX_DATE ) );
562 xSecondCol->setPropertyValue(FM_PROP_LABEL, makeAny( ::rtl::OUString( sFieldName + sDatePostfix ) ) );
564 else
565 xCol->setPropertyValue(FM_PROP_LABEL, makeAny(sFieldName));
567 FormControlFactory aControlFactory( ::comphelper::getProcessServiceFactory() );
568 aControlFactory.initializeControlModel( DocumentClassification::classifyHostDocument( xCols ), xCol );
569 aControlFactory.initializeFieldDependentProperties( xField, xCol, xNumberFormats );
571 xCol->setPropertyValue(FM_PROP_CONTROLSOURCE, makeAny(sFieldName));
572 if ( xSecondCol.is() )
573 xSecondCol->setPropertyValue(FM_PROP_CONTROLSOURCE, makeAny(sFieldName));
575 if (bDateNTimeCol)
577 String sRealName,sPurePostfix;
579 String aPostfix[] = {
580 String( SVX_RES( RID_STR_POSTFIX_DATE ) ),
581 String( SVX_RES( RID_STR_POSTFIX_TIME ) )
584 for ( size_t i=0; i<2; ++i )
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)));
599 else
600 xCol->setPropertyValue(FM_PROP_NAME, makeAny(sFieldName));
602 // jetzt einfuegen
603 Any aElement;
604 aElement <<= xCol;
605 xCols->insertByIndex(nPos, aElement);
607 if (bDateNTimeCol)
609 aElement <<= xSecondCol;
610 xCols->insertByIndex(nPos == (sal_uInt16)-1 ? nPos : ++nPos, aElement);
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())
618 if (!::comphelper::getString(xForm->getPropertyValue(FM_PROP_DATASOURCE)).getLength())
620 if ( sDatasouce.getLength() )
621 xForm->setPropertyValue(FM_PROP_DATASOURCE, makeAny(sDatasouce));
622 else
623 xForm->setPropertyValue(FM_PROP_URL, makeAny(sURL));
626 if (!::comphelper::getString(xForm->getPropertyValue(FM_PROP_COMMAND)).getLength())
628 xForm->setPropertyValue(FM_PROP_COMMAND, makeAny(sCommand));
629 Any aCommandType;
630 switch (nCommandType)
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;
643 xForm->setPropertyValue(FM_PROP_COMMANDTYPE, aCommandType);
647 catch (Exception&)
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;
655 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
656 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
657 return 1L;
660 //------------------------------------------------------------------------------
661 void FmGridHeader::PreExecuteColumnContextMenu(sal_uInt16 nColId, PopupMenu& rMenu)
663 sal_Bool bDesignMode = static_cast<FmGridControl*>(GetParent())->IsDesignMode();
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)
670 sal_uInt16 nPos2 = GetModelColumnPos(nColId);
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));
680 // EinfuegePosition, immer vor der aktuellen Spalte
681 sal_uInt16 nPos = GetModelColumnPos(nColId);
682 sal_Bool bMarked = nColId && static_cast<FmGridControl*>(GetParent())->isColumnMarked(nColId);
684 ImageList aImageList( SVX_RES(RID_SVXIMGLIST_FMEXPL) );
685 PopupMenu* pControlMenu = new PopupMenu;
687 PopupMenu* pMenu = rMenu.GetPopupMenu(SID_FM_INSERTCOL);
688 if (pMenu)
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);
702 if (pMenu && xCols.is() && nColId)
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;
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())
718 Reference< ::com::sun::star::beans::XPropertySetInfo > xPropsInfo = xProps->getPropertySetInfo();
719 if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(FM_PROP_FORMATSSUPPLIER))
720 nColType = TYPE_FORMATTEDFIELD;
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);
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());
742 PopupMenu* pShowColsMenu = rMenu.GetPopupMenu(SID_FM_SHOWCOLS);
743 sal_uInt16 nHiddenCols = 0;
744 if (pShowColsMenu)
746 if (xCols.is())
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)
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))
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
767 ++nHiddenCols;
771 pShowColsMenu->EnableItem(SID_FM_SHOWCOLS_MORE, xCols.is() && (nHiddenCols > 16));
772 pShowColsMenu->EnableItem(SID_FM_SHOWALLCOLS, xCols.is() && (nHiddenCols > 0));
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);
782 sal_Bool bChecked = sal_False;
783 if (bMarked)
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)
791 SfxPoolItem* pItem = NULL;
792 eState = pCurrentFrame->GetBindings().QueryState(SID_FM_CTL_PROPERTIES, pItem);
794 if (eState >= SFX_ITEM_AVAILABLE && pItem )
796 bChecked = pItem->ISA(SfxBoolItem) && ((SfxBoolItem*)pItem)->GetValue();
797 rMenu.CheckItem(SID_FM_SHOW_PROPERTY_BROWSER,bChecked);
799 delete pItem;
804 enum InspectorAction { eOpenInspector, eCloseInspector, eUpdateInspector, eNone };
806 //------------------------------------------------------------------------------
807 void FmGridHeader::PostExecuteColumnContextMenu(sal_uInt16 nColId, const PopupMenu& rMenu, sal_uInt16 nExecutionResult)
809 Reference< ::com::sun::star::container::XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
810 sal_uInt16 nPos = GetModelColumnPos(nColId);
812 // remove and delet the menu we inserted in PreExecuteColumnContextMenu
813 PopupMenu* pControlMenu = rMenu.GetPopupMenu(SID_FM_CHANGECOL);
814 delete pControlMenu;
816 ::rtl::OUString aFieldType;
817 sal_Bool bReplace = sal_False;
818 InspectorAction eInspectorAction = eNone;
819 Reference< XPropertySet > xColumnToInspect;
820 switch (nExecutionResult)
822 case SID_FM_DELETECOL:
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:
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));
889 break;
890 case SID_FM_SHOWCOLS_MORE:
892 //CHINA001 FmShowColsDialog dlg(NULL);
893 //CHINA001 dlg.SetColumns(xCols);
894 //CHINA001 dlg.Execute();
895 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
896 if(pFact)
898 AbstractFmShowColsDialog* pDlg = pFact->CreateFmShowColsDialog(NULL, RID_SVX_DLG_SHOWGRIDCOLUMNS);
899 DBG_ASSERT(pDlg, "Dialogdiet fail!");//CHINA001
900 pDlg->SetColumns(xCols);
901 pDlg->Execute();
902 delete pDlg;
906 break;
907 case SID_FM_SHOWALLCOLS:
909 // just iterate through all the cols ...
910 Reference< ::com::sun::star::beans::XPropertySet > xCurCol;
911 for (sal_uInt16 i=0; i<xCols->getCount(); ++i)
913 ::cppu::extractInterface(xCurCol, xCols->getByIndex(i));
914 xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny((sal_Bool)sal_False));
916 // TODO : there must be a more clever way to do this ....
917 // with the above the view is updated after every single model update ...
919 break;
920 default:
921 if (nExecutionResult>0 && nExecutionResult<=16)
922 { // it was a "show column/<colname>" command (there are at most 16 such items)
923 // search the nExecutionResult'th hidden col
924 Reference< ::com::sun::star::beans::XPropertySet > xCurCol;
925 for (sal_uInt16 i=0; i<xCols->getCount() && nExecutionResult; ++i)
927 ::cppu::extractInterface(xCurCol, xCols->getByIndex(i));
928 Any aHidden = xCurCol->getPropertyValue(FM_PROP_HIDDEN);
929 if (::comphelper::getBOOL(aHidden))
930 if (!--nExecutionResult)
932 xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny((sal_Bool)sal_False));
933 break;
937 break;
940 if ( aFieldType.getLength() )
944 Reference< XGridColumnFactory > xFactory( xCols, UNO_QUERY_THROW );
945 Reference< XPropertySet > xNewCol( xFactory->createColumn( aFieldType ), UNO_SET_THROW );
947 if ( bReplace )
949 // ein paar Properties hinueberretten
950 Reference< XPropertySet > xReplaced( xCols->getByIndex( nPos ), UNO_QUERY );
952 OStaticDataAccessTools().TransferFormComponentProperties(
953 xReplaced, xNewCol, Application::GetSettings().GetUILocale() );
955 xCols->replaceByIndex( nPos, makeAny( xNewCol ) );
956 ::comphelper::disposeComponent( xReplaced );
958 eInspectorAction = eUpdateInspector;
959 xColumnToInspect = xNewCol;
961 else
963 // Standardlabel setzen
964 ::rtl::OUString sLabelBase = String( SVX_RES( RID_STR_COLUMN ) );
965 // disambiguate the name
966 Reference< XNameAccess > xColNames( xCols, UNO_QUERY );
967 ::rtl::OUString sLabel;
968 for ( sal_Int32 i=1; i<65535; ++i )
970 sLabel = sLabelBase;
971 sLabel += ::rtl::OUString::valueOf( (sal_Int32)i );
972 if ( !xColNames->hasByName( sLabel ) )
973 break;
975 // no fallback in case the name is not unique (which is rather improbable) ....
976 xNewCol->setPropertyValue( FM_PROP_LABEL, makeAny( sLabel ) );
977 xNewCol->setPropertyValue( FM_PROP_NAME, makeAny( sLabel ) );
979 FormControlFactory determine( ::comphelper::getProcessServiceFactory() );
980 determine.initializeControlModel( DocumentClassification::classifyHostDocument( xCols ), xNewCol );
982 xCols->insertByIndex( nPos, makeAny( xNewCol ) );
985 catch( const Exception& )
987 DBG_UNHANDLED_EXCEPTION();
991 SfxViewFrame* pCurrentFrame = SfxViewFrame::Current();
992 OSL_ENSURE( pCurrentFrame, "FmGridHeader::PostExecuteColumnContextMenu: no view frame -> no bindings -> no property browser!" );
993 if ( pCurrentFrame )
995 if ( eInspectorAction == eUpdateInspector )
997 if ( !pCurrentFrame->HasChildWindow( SID_FM_SHOW_PROPERTIES ) )
998 eInspectorAction = eNone;
1001 if ( eInspectorAction != eNone )
1003 FmInterfaceItem aIFaceItem( SID_FM_SHOW_PROPERTY_BROWSER, xColumnToInspect );
1004 SfxBoolItem aShowItem( SID_FM_SHOW_PROPERTIES, eInspectorAction == eCloseInspector ? FALSE : TRUE );
1006 pCurrentFrame->GetBindings().GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SFX_CALLMODE_ASYNCHRON,
1007 &aIFaceItem, &aShowItem, 0L );
1012 //------------------------------------------------------------------------------
1013 void FmGridHeader::triggerColumnContextMenu( const ::Point& _rPreferredPos )
1015 // the affected col
1016 sal_uInt16 nColId = GetItemId( _rPreferredPos );
1018 // the menu
1019 PopupMenu aContextMenu( SVX_RES( RID_SVXMNU_COLS ) );
1021 // let derivees modify the menu
1022 PreExecuteColumnContextMenu( nColId, aContextMenu );
1023 aContextMenu.RemoveDisabledEntries( sal_True, sal_True );
1025 // execute the menu
1026 sal_uInt16 nResult = aContextMenu.Execute( this, _rPreferredPos );
1028 // let derivees handle the result
1029 PostExecuteColumnContextMenu( nColId, aContextMenu, nResult );
1032 //------------------------------------------------------------------------------
1033 void FmGridHeader::Command(const CommandEvent& rEvt)
1035 switch (rEvt.GetCommand())
1037 case COMMAND_CONTEXTMENU:
1039 if (!rEvt.IsMouseEvent())
1040 return;
1042 triggerColumnContextMenu( rEvt.GetMousePosPixel() );
1044 break;
1045 default:
1046 EditBrowserHeader::Command(rEvt);
1050 //------------------------------------------------------------------------------
1051 FmGridControl::FmGridControl(
1052 Reference< ::com::sun::star::lang::XMultiServiceFactory > _rxFactory,
1053 Window* pParent,
1054 FmXGridPeer* _pPeer,
1055 WinBits nBits)
1056 :DbGridControl(_rxFactory, pParent, nBits)
1057 ,m_pPeer(_pPeer)
1058 ,m_nCurrentSelectedColumn(-1)
1059 ,m_nMarkedColumnId(BROWSER_INVALIDID)
1060 ,m_bSelecting(sal_False)
1061 ,m_bInColumnMove(sal_False)
1063 EnableInteractiveRowHeight( );
1066 //------------------------------------------------------------------------------
1067 void FmGridControl::Command(const CommandEvent& _rEvt)
1069 if ( COMMAND_CONTEXTMENU == _rEvt.GetCommand() )
1071 FmGridHeader* pMyHeader = static_cast< FmGridHeader* >( GetHeaderBar() );
1072 if ( pMyHeader && !_rEvt.IsMouseEvent() )
1073 { // context menu requested by keyboard
1074 if ( 1 == GetSelectColumnCount() || IsDesignMode() )
1076 sal_uInt16 nSelId = GetColumnId(
1077 sal::static_int_cast< USHORT >( FirstSelectedColumn() ) );
1078 ::Rectangle aColRect( GetFieldRectPixel( 0, nSelId, sal_False ) );
1080 Point aRelativePos( pMyHeader->ScreenToOutputPixel( OutputToScreenPixel( aColRect.TopCenter() ) ) );
1081 pMyHeader->triggerColumnContextMenu( aRelativePos, FmGridHeader::AccessControl() );
1083 // handled
1084 return;
1089 DbGridControl::Command( _rEvt );
1092 // ::com::sun::star::beans::XPropertyChangeListener
1093 //------------------------------------------------------------------------------
1094 void FmGridControl::propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& evt)
1096 if (evt.PropertyName == FM_PROP_ROWCOUNT)
1098 // if we're not in the main thread call AdjustRows asynchronously
1099 implAdjustInSolarThread(sal_True);
1100 return;
1103 const DbGridRowRef& xRow = GetCurrentRow();
1104 // waehrend Positionierung wird kein abgleich der Properties vorgenommen
1105 Reference<XPropertySet> xSet(evt.Source,UNO_QUERY);
1106 if (xRow.Is() && (::cppu::any2bool(xSet->getPropertyValue(FM_PROP_ISNEW))|| CompareBookmark(getDataSource()->getBookmark(), xRow->GetBookmark())))
1108 if (evt.PropertyName == FM_PROP_ISMODIFIED)
1110 // modified or clean ?
1111 GridRowStatus eStatus = ::comphelper::getBOOL(evt.NewValue) ? GRS_MODIFIED : GRS_CLEAN;
1112 if (eStatus != xRow->GetStatus())
1114 xRow->SetStatus(eStatus);
1115 vos::OGuard aGuard( Application::GetSolarMutex() );
1116 RowModified(GetCurrentPos());
1122 //------------------------------------------------------------------------------
1123 void FmGridControl::SetDesignMode(sal_Bool bMode)
1125 sal_Bool bOldMode = IsDesignMode();
1126 DbGridControl::SetDesignMode(bMode);
1127 if (bOldMode != bMode)
1129 if (!bMode)
1131 // selection aufheben
1132 markColumn(USHRT_MAX);
1134 else
1136 Reference< ::com::sun::star::container::XIndexContainer > xColumns(GetPeer()->getColumns());
1137 Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
1138 if (xSelSupplier.is())
1140 Any aSelection = xSelSupplier->getSelection();
1141 Reference< ::com::sun::star::beans::XPropertySet > xColumn;
1142 if (aSelection.getValueType().getTypeClass() == TypeClass_INTERFACE)
1143 ::cppu::extractInterface(xColumn, aSelection);
1144 Reference< XInterface > xCurrent;
1145 for (sal_uInt16 i=0; i<xColumns->getCount(); ++i)
1147 ::cppu::extractInterface(xCurrent, xColumns->getByIndex(i));
1148 if (xCurrent == xColumn)
1150 markColumn(GetColumnIdFromModelPos(i));
1151 break;
1159 //------------------------------------------------------------------------------
1160 void FmGridControl::DeleteSelectedRows()
1162 if (!m_pSeekCursor)
1163 return;
1165 // how many rows are selected?
1166 sal_Int32 nSelectedRows = GetSelectRowCount();
1168 // the current line should be deleted but it is currently in edit mode
1169 if ( IsCurrentAppending() )
1170 return;
1171 // is the insert row selected
1172 if (GetEmptyRow().Is() && IsRowSelected(GetRowCount() - 1))
1173 nSelectedRows -= 1;
1175 // nothing to do
1176 if (nSelectedRows <= 0)
1177 return;
1179 // try to confirm the delete
1180 Reference< ::com::sun::star::frame::XDispatchProvider > xDispatcher = (::com::sun::star::frame::XDispatchProvider*)GetPeer();
1181 if (xDispatcher.is())
1183 ::com::sun::star::util::URL aUrl;
1184 aUrl.Complete = FMURL_CONFIRM_DELETION;
1185 // #100312# ------------
1186 Reference< ::com::sun::star::util::XURLTransformer > xTransformer(
1187 ::comphelper::getProcessServiceFactory()->createInstance(
1188 ::rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer")), UNO_QUERY);
1189 if( xTransformer.is() )
1190 xTransformer->parseStrict( aUrl );
1192 Reference< ::com::sun::star::frame::XDispatch > xDispatch = xDispatcher->queryDispatch(aUrl, rtl::OUString(), 0);
1193 Reference< ::com::sun::star::form::XConfirmDeleteListener > xConfirm(xDispatch, UNO_QUERY);
1194 if (xConfirm.is())
1196 ::com::sun::star::sdb::RowChangeEvent aEvent;
1197 aEvent.Source = (Reference< XInterface > )(*getDataSource());
1198 aEvent.Rows = nSelectedRows;
1199 aEvent.Action = ::com::sun::star::sdb::RowChangeAction::DELETE;
1200 if (!xConfirm->confirmDelete(aEvent))
1201 return;
1205 const MultiSelection* pRowSelection = GetSelection();
1206 if ( pRowSelection && pRowSelection->IsAllSelected() )
1208 BeginCursorAction();
1209 CursorWrapper* pCursor = getDataSource();
1210 Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*pCursor, UNO_QUERY);
1213 pCursor->beforeFirst();
1214 while( pCursor->next() )
1215 xUpdateCursor->deleteRow();
1217 SetUpdateMode(sal_False);
1218 SetNoSelection();
1220 xUpdateCursor->moveToInsertRow();
1222 catch(const Exception&)
1224 OSL_ENSURE(0,"Exception caught while deleting rows!");
1226 // An den DatenCursor anpassen
1227 AdjustDataSource(sal_True);
1228 EndCursorAction();
1229 SetUpdateMode(sal_True);
1231 else
1233 Reference< ::com::sun::star::sdbcx::XDeleteRows > xDeleteThem((Reference< XInterface >)*getDataSource(), UNO_QUERY);
1235 // colect the bookmarks of the selected rows
1236 Sequence < Any> aBookmarks = getSelectionBookmarks();
1238 // determine the next row to position after deletion
1239 Any aBookmark;
1240 sal_Bool bNewPos = sal_False;
1241 // if the current row isn't selected we take the row as row after deletion
1242 OSL_ENSURE( GetCurrentRow().Is(), "FmGridControl::DeleteSelectedRows: no current row here?" );
1243 // crash reports suggest it can happen we don't have a current row - how?
1244 // #154303# / 2008-04-23 / frank.schoenheit@sun.com
1245 if ( !IsRowSelected( GetCurrentPos() ) && !IsCurrentAppending() && GetCurrentRow().Is() )
1247 aBookmark = GetCurrentRow()->GetBookmark();
1248 bNewPos = sal_True;
1250 else
1252 // we look for the first row after the selected block for selection
1253 long nIdx = LastSelectedRow() + 1;
1254 if (nIdx < GetRowCount() - 1)
1256 // there is a next row to position on
1257 if (SeekCursor(nIdx))
1259 GetSeekRow()->SetState(m_pSeekCursor, sal_True);
1261 bNewPos = sal_True;
1262 // if it's not the row for inserting we keep the bookmark
1263 if (!IsInsertionRow(nIdx))
1264 aBookmark = m_pSeekCursor->getBookmark();
1267 else
1269 // we look for the first row before the selected block for selection after deletion
1270 nIdx = FirstSelectedRow() - 1;
1271 if (nIdx >= 0 && SeekCursor(nIdx))
1273 GetSeekRow()->SetState(m_pSeekCursor, sal_True);
1275 bNewPos = sal_True;
1276 aBookmark = m_pSeekCursor->getBookmark();
1281 // Sind alle Zeilen Selectiert
1282 // Zweite bedingung falls keine einguegeZeile existiert
1283 sal_Bool bAllSelected = GetTotalCount() == nSelectedRows || GetRowCount() == nSelectedRows;
1285 BeginCursorAction();
1287 // now delete the row
1288 Sequence <sal_Int32> aDeletedRows;
1289 SetUpdateMode( FALSE );
1292 aDeletedRows = xDeleteThem->deleteRows(aBookmarks);
1294 catch(SQLException&)
1297 SetUpdateMode( TRUE );
1299 // how many rows are deleted?
1300 sal_Int32 nDeletedRows = 0;
1301 const sal_Int32* pSuccess = aDeletedRows.getConstArray();
1302 for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++)
1304 if (pSuccess[i])
1305 ++nDeletedRows;
1308 // sind Zeilen geloescht worden?
1309 if (nDeletedRows)
1311 SetUpdateMode(sal_False);
1312 SetNoSelection();
1315 // did we delete all the rows than try to move to the next possible row
1316 if (nDeletedRows == aDeletedRows.getLength())
1318 // there exists a new position to move on
1319 if (bNewPos)
1321 if (aBookmark.hasValue())
1322 getDataSource()->moveToBookmark(aBookmark);
1323 // no valid bookmark so move to the insert row
1324 else
1326 Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY);
1327 xUpdateCursor->moveToInsertRow();
1330 else
1332 Reference< ::com::sun::star::beans::XPropertySet > xSet((Reference< XInterface >)*m_pDataCursor, UNO_QUERY);
1334 sal_Int32 nRecordCount(0);
1335 xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
1336 if ( m_pDataCursor->rowDeleted() )
1337 --nRecordCount;
1339 // there are no rows left and we have an insert row
1340 if (!nRecordCount && GetEmptyRow().Is())
1342 Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY);
1343 xUpdateCursor->moveToInsertRow();
1345 else if (nRecordCount)
1346 // move to the first row
1347 getDataSource()->first();
1350 // not all the rows where deleted, so move to the first row which remained in the resultset
1351 else
1353 for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++)
1355 if (!pSuccess[i])
1357 getDataSource()->moveToBookmark(aBookmarks.getConstArray()[i]);
1358 break;
1363 catch(const Exception&)
1367 // positioning went wrong so try to move to the first row
1368 getDataSource()->first();
1370 catch(const Exception&)
1375 // An den DatenCursor anpassen
1376 AdjustDataSource(sal_True);
1378 // es konnten nicht alle Zeilen geloescht werden
1379 // da nie nicht geloeschten wieder selektieren
1380 if (nDeletedRows < nSelectedRows)
1382 // waren alle selektiert
1383 if (bAllSelected)
1385 SelectAll();
1386 if (IsInsertionRow(GetRowCount() - 1)) // einfuegeZeile nicht
1387 SelectRow(GetRowCount() - 1, sal_False);
1389 else
1391 // select the remaining rows
1392 for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++)
1396 if (!pSuccess[i])
1398 m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
1399 SetSeekPos(m_pSeekCursor->getRow() - 1);
1400 SelectRow(GetSeekPos());
1403 catch(const Exception&)
1405 // keep the seekpos in all cases
1406 SetSeekPos(m_pSeekCursor->getRow() - 1);
1412 EndCursorAction();
1413 SetUpdateMode(sal_True);
1415 else // Zeile konnte nicht geloescht werden
1417 EndCursorAction();
1420 // currentrow is the insert row?
1421 if (!IsCurrentAppending())
1422 getDataSource()->refreshRow();
1424 catch(const Exception&)
1430 // if there is no selection anymore we can start editing
1431 if (!GetSelectRowCount())
1432 ActivateCell();
1436 // XCurrentRecordListener
1437 //------------------------------------------------------------------------------
1438 void FmGridControl::positioned(const ::com::sun::star::lang::EventObject& /*rEvent*/)
1440 TRACE_RANGE("FmGridControl::positioned");
1441 // position on the data source (force it to be done in the main thread)
1442 implAdjustInSolarThread(sal_False);
1445 //------------------------------------------------------------------------------
1446 sal_Bool FmGridControl::commit()
1448 // Commit nur ausfuehren, wenn nicht bereits ein Update vom ::com::sun::star::form::component::GridControl ausgefuehrt
1449 // wird
1450 if (!IsUpdating())
1452 if (Controller().Is() && Controller()->IsModified())
1454 if (!SaveModified())
1455 return sal_False;
1458 return sal_True;
1461 //------------------------------------------------------------------------------
1462 void FmGridControl::inserted(const ::com::sun::star::lang::EventObject& /*rEvent*/)
1464 const DbGridRowRef& xRow = GetCurrentRow();
1465 if (!xRow.Is())
1466 return;
1468 // Zeile ist eingefuegt worden, dann den status und mode zuruecksetzen
1469 xRow->SetState(m_pDataCursor, sal_False);
1470 xRow->SetNew(sal_False);
1474 // XCancelUpdateRecordListener
1475 //------------------------------------------------------------------------------
1476 void FmGridControl::restored(const ::com::sun::star::lang::EventObject& rEvent)
1478 if (!GetCurrentRow().Is())
1479 return;
1481 sal_Bool bAppending = GetCurrentRow()->IsNew();
1482 sal_Bool bDirty = GetCurrentRow()->IsModified();
1483 if (bAppending && (EditBrowseBox::IsModified() || bDirty))
1485 if (Controller().Is())
1486 Controller()->ClearModified();
1488 // jetzt die Zeile herausnehmen
1489 RowRemoved(GetRowCount() - 1, 1, sal_True);
1490 GetNavigationBar().InvalidateAll();
1493 positioned(rEvent);
1496 //------------------------------------------------------------------------------
1497 BrowserHeader* FmGridControl::imp_CreateHeaderBar(BrowseBox* pParent)
1499 DBG_ASSERT( pParent == this, "FmGridControl::imp_CreateHeaderBar: parent?" );
1500 return new FmGridHeader( pParent );
1503 //------------------------------------------------------------------------------
1504 void FmGridControl::markColumn(sal_uInt16 nId)
1506 if (GetHeaderBar() && m_nMarkedColumnId != nId)
1508 // deselektieren
1509 if (m_nMarkedColumnId != BROWSER_INVALIDID)
1511 HeaderBarItemBits aBits = GetHeaderBar()->GetItemBits(m_nMarkedColumnId) & ~HIB_FLAT;
1512 GetHeaderBar()->SetItemBits(m_nMarkedColumnId, aBits);
1516 if (nId != BROWSER_INVALIDID)
1518 HeaderBarItemBits aBits = GetHeaderBar()->GetItemBits(nId) | HIB_FLAT;
1519 GetHeaderBar()->SetItemBits(nId, aBits);
1521 m_nMarkedColumnId = nId;
1525 //------------------------------------------------------------------------------
1526 sal_Bool FmGridControl::isColumnMarked(sal_uInt16 nId) const
1528 return m_nMarkedColumnId == nId;
1531 //------------------------------------------------------------------------------
1532 long FmGridControl::QueryMinimumRowHeight()
1534 long nMinimalLogicHeight = 20; // 0.2 cm
1535 long nMinimalPixelHeight = LogicToPixel( Point( 0, nMinimalLogicHeight ), MAP_10TH_MM ).Y();
1536 return CalcZoom( nMinimalPixelHeight );
1539 //------------------------------------------------------------------------------
1540 void FmGridControl::RowHeightChanged()
1542 DbGridControl::RowHeightChanged();
1544 Reference< XPropertySet > xModel( GetPeer()->getColumns(), UNO_QUERY );
1545 DBG_ASSERT( xModel.is(), "FmGridControl::RowHeightChanged: no model!" );
1546 if ( xModel.is() )
1550 sal_Int32 nUnzoomedPixelHeight = CalcReverseZoom( GetDataRowHeight() );
1551 Any aProperty = makeAny( (sal_Int32)PixelToLogic( Point( 0, nUnzoomedPixelHeight ), MAP_10TH_MM ).Y() );
1552 xModel->setPropertyValue( FM_PROP_ROWHEIGHT, aProperty );
1554 catch( const Exception& )
1556 OSL_ENSURE( sal_False, "FmGridControl::RowHeightChanged: caught an exception!" );
1561 //------------------------------------------------------------------------------
1562 void FmGridControl::ColumnResized(sal_uInt16 nId)
1564 DbGridControl::ColumnResized(nId);
1566 // Wert ans model uebergeben
1567 DbGridColumn* pCol = DbGridControl::GetColumns().GetObject(GetModelColumnPos(nId));
1568 Reference< ::com::sun::star::beans::XPropertySet > xColModel(pCol->getModel());
1569 if (xColModel.is())
1571 Any aWidth;
1572 sal_Int32 nColumnWidth = GetColumnWidth(nId);
1573 nColumnWidth = CalcReverseZoom(nColumnWidth);
1574 // Umrechnen in 10THMM
1575 aWidth <<= (sal_Int32)PixelToLogic(Point(nColumnWidth,0),MAP_10TH_MM).X();
1576 xColModel->setPropertyValue(FM_PROP_WIDTH, aWidth);
1580 //------------------------------------------------------------------------------
1581 void FmGridControl::CellModified()
1583 DbGridControl::CellModified();
1584 GetPeer()->CellModified();
1587 //------------------------------------------------------------------------------
1588 void FmGridControl::BeginCursorAction()
1590 DbGridControl::BeginCursorAction();
1591 m_pPeer->stopCursorListening();
1594 //------------------------------------------------------------------------------
1595 void FmGridControl::EndCursorAction()
1597 m_pPeer->startCursorListening();
1598 DbGridControl::EndCursorAction();
1601 //------------------------------------------------------------------------------
1602 void FmGridControl::ColumnMoved(sal_uInt16 nId)
1604 m_bInColumnMove = sal_True;
1606 DbGridControl::ColumnMoved(nId);
1607 Reference< ::com::sun::star::container::XIndexContainer > xColumns(GetPeer()->getColumns());
1609 if (xColumns.is())
1611 // suchen der Spalte und verschieben im Model
1612 // ColumnPos holen
1613 DbGridColumn* pCol = DbGridControl::GetColumns().GetObject(GetModelColumnPos(nId));
1614 Reference< ::com::sun::star::beans::XPropertySet > xCol;
1616 // Einfuegen muß sich an den Column Positionen orientieren
1617 sal_Int32 i;
1618 Reference< XInterface > xCurrent;
1619 for (i = 0; !xCol.is() && i < xColumns->getCount(); i++)
1621 ::cppu::extractInterface(xCurrent, xColumns->getByIndex(i));
1622 if (xCurrent == pCol->getModel())
1624 xCol = pCol->getModel();
1625 break;
1629 DBG_ASSERT(i < xColumns->getCount(), "Falscher ::com::sun::star::sdbcx::Index");
1630 xColumns->removeByIndex(i);
1631 Any aElement;
1632 aElement <<= xCol;
1633 xColumns->insertByIndex(GetModelColumnPos(nId), aElement);
1634 pCol->setModel(xCol);
1635 // if the column which is shown here is selected ...
1636 if ( isColumnSelected(nId,pCol) )
1637 markColumn(nId); // ... -> mark it
1640 m_bInColumnMove = sal_False;
1643 //------------------------------------------------------------------------------
1644 void FmGridControl::InitColumnsByModels(const Reference< ::com::sun::star::container::XIndexContainer >& xColumns)
1646 // Spalten wieder neu setzen
1647 // wenn es nur eine HandleColumn gibt, dann nicht
1648 if (GetModelColCount())
1650 RemoveColumns();
1651 InsertHandleColumn();
1654 if (!xColumns.is())
1655 return;
1657 SetUpdateMode(sal_False);
1659 // Einfuegen mu� sich an den Column Positionen orientieren
1660 sal_Int32 i;
1661 String aName;
1662 Any aWidth;
1663 for (i = 0; i < xColumns->getCount(); ++i)
1665 Reference< ::com::sun::star::beans::XPropertySet > xCol;
1666 ::cppu::extractInterface(xCol, xColumns->getByIndex(i));
1668 aName = (const sal_Unicode*)::comphelper::getString(xCol->getPropertyValue(FM_PROP_LABEL));
1670 aWidth = xCol->getPropertyValue(FM_PROP_WIDTH);
1671 sal_Int32 nWidth = 0;
1672 if (aWidth >>= nWidth)
1673 nWidth = LogicToPixel(Point(nWidth,0),MAP_10TH_MM).X();
1675 AppendColumn(aName, (sal_uInt16)nWidth);
1676 DbGridColumn* pCol = DbGridControl::GetColumns().GetObject(i);
1677 pCol->setModel(xCol);
1680 // und jetzt noch die hidden columns rausnehmen
1681 // (wir haben das nicht gleich in der oberen Schleife gemacht, da wir dann Probleme mit den
1682 // IDs der Spalten bekommen haetten : AppendColumn vergibt die automatisch, die Spalte _nach_
1683 // einer versteckten braucht aber eine um eine erhoehte ID ....
1684 Any aHidden;
1685 for (i = 0; i < xColumns->getCount(); ++i)
1687 Reference< ::com::sun::star::beans::XPropertySet > xCol;
1688 ::cppu::extractInterface(xCol, xColumns->getByIndex(i));
1689 aHidden = xCol->getPropertyValue(FM_PROP_HIDDEN);
1690 if (::comphelper::getBOOL(aHidden))
1691 HideColumn(GetColumnIdFromModelPos((sal_uInt16)i));
1694 SetUpdateMode(sal_True);
1697 //------------------------------------------------------------------------------
1698 void FmGridControl::InitColumnByField(
1699 DbGridColumn* _pColumn, const Reference< XPropertySet >& _rxColumnModel,
1700 const Reference< XNameAccess >& _rxFieldsByNames, const Reference< XIndexAccess >& _rxFieldsByIndex )
1702 DBG_ASSERT( _rxFieldsByNames == _rxFieldsByIndex, "FmGridControl::InitColumnByField: invalid container interfaces!" );
1704 // lookup the column which belongs to the control source
1705 ::rtl::OUString sFieldName;
1706 _rxColumnModel->getPropertyValue( FM_PROP_CONTROLSOURCE ) >>= sFieldName;
1707 Reference< XPropertySet > xField;
1708 _rxColumnModel->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField;
1711 if ( !xField.is() && /*sFieldName.getLength() && */_rxFieldsByNames->hasByName( sFieldName ) ) // #i93452# do not check for name length
1712 _rxFieldsByNames->getByName( sFieldName ) >>= xField;
1714 // determine the position of this column
1715 sal_Int32 nFieldPos = -1;
1716 if ( xField.is() )
1718 Reference< XPropertySet > xCheck;
1719 sal_Int32 nFieldCount = _rxFieldsByIndex->getCount();
1720 for ( sal_Int32 i = 0; i < nFieldCount; ++i)
1722 _rxFieldsByIndex->getByIndex( i ) >>= xCheck;
1723 if ( xField.get() == xCheck.get() )
1725 nFieldPos = i;
1726 break;
1731 if ( xField.is() && ( nFieldPos >= 0 ) )
1733 // some data types are not allowed
1734 sal_Int32 nDataType = DataType::OTHER;
1735 xField->getPropertyValue( FM_PROP_FIELDTYPE ) >>= nDataType;
1737 sal_Bool bIllegalType = sal_False;
1738 switch ( nDataType )
1740 case DataType::LONGVARBINARY:
1741 case DataType::BINARY:
1742 case DataType::VARBINARY:
1743 case DataType::OTHER:
1744 bIllegalType = sal_True;
1745 break;
1748 if ( bIllegalType )
1750 _pColumn->SetObject( (sal_Int16)nFieldPos );
1751 return;
1754 // handle readonly columns
1755 sal_Bool bReadOnly = sal_True;
1756 xField->getPropertyValue( FM_PROP_ISREADONLY ) >>= bReadOnly;
1757 _pColumn->SetReadOnly( bReadOnly );
1760 // the control type is determined by the ColumnServiceName
1761 static ::rtl::OUString s_sPropColumnServiceName( RTL_CONSTASCII_USTRINGPARAM( "ColumnServiceName" ) );
1762 if ( !::comphelper::hasProperty( s_sPropColumnServiceName, _rxColumnModel ) )
1763 return;
1765 _pColumn->setModel( _rxColumnModel );
1767 ::rtl::OUString sColumnServiceName;
1768 _rxColumnModel->getPropertyValue( s_sPropColumnServiceName ) >>= sColumnServiceName;
1770 sal_Int32 nTypeId = getColumnTypeByModelName( sColumnServiceName );
1771 _pColumn->CreateControl( nFieldPos, xField, nTypeId );
1774 //------------------------------------------------------------------------------
1775 void FmGridControl::InitColumnsByFields(const Reference< ::com::sun::star::container::XIndexAccess >& _rxFields)
1777 if ( !_rxFields.is() )
1778 return;
1780 // Spalten initialisieren
1781 Reference< XIndexContainer > xColumns( GetPeer()->getColumns() );
1782 Reference< XNameAccess > xFieldsAsNames( _rxFields, UNO_QUERY );
1784 // Einfuegen mu� sich an den Column Positionen orientieren
1785 for (sal_Int32 i = 0; i < xColumns->getCount(); i++)
1787 DbGridColumn* pCol = GetColumns().GetObject(i);
1788 Reference< XPropertySet > xColumnModel;
1789 ::cppu::extractInterface( xColumnModel, xColumns->getByIndex( i ) );
1791 InitColumnByField( pCol, xColumnModel, xFieldsAsNames, _rxFields );
1795 //------------------------------------------------------------------------------
1796 void FmGridControl::HideColumn(sal_uInt16 nId)
1798 DbGridControl::HideColumn(nId);
1800 sal_uInt16 nPos = GetModelColumnPos(nId);
1801 if (nPos == (sal_uInt16)-1)
1802 return;
1804 DbGridColumn* pColumn = GetColumns().GetObject(nPos);
1805 if (pColumn->IsHidden())
1806 GetPeer()->columnHidden(pColumn);
1808 if (nId == m_nMarkedColumnId)
1809 m_nMarkedColumnId = (sal_uInt16)-1;
1811 // -----------------------------------------------------------------------------
1812 sal_Bool FmGridControl::isColumnSelected(sal_uInt16 /*nId*/,DbGridColumn* _pColumn)
1814 OSL_ENSURE(_pColumn,"Column can not be null!");
1815 sal_Bool bSelected = sal_False;
1816 // if the column which is shown here is selected ...
1817 Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(GetPeer()->getColumns(), UNO_QUERY);
1818 if ( xSelSupplier.is() )
1820 Reference< ::com::sun::star::beans::XPropertySet > xColumn;
1821 xSelSupplier->getSelection() >>= xColumn;
1822 bSelected = (xColumn.get() == _pColumn->getModel().get());
1824 return bSelected;
1827 //------------------------------------------------------------------------------
1828 void FmGridControl::ShowColumn(sal_uInt16 nId)
1830 DbGridControl::ShowColumn(nId);
1832 sal_uInt16 nPos = GetModelColumnPos(nId);
1833 if (nPos == (sal_uInt16)-1)
1834 return;
1836 DbGridColumn* pColumn = GetColumns().GetObject(nPos);
1837 if (!pColumn->IsHidden())
1838 GetPeer()->columnVisible(pColumn);
1840 // if the column which is shown here is selected ...
1841 if ( isColumnSelected(nId,pColumn) )
1842 markColumn(nId); // ... -> mark it
1845 //------------------------------------------------------------------------------
1846 sal_Bool FmGridControl::selectBookmarks(const Sequence< Any >& _rBookmarks)
1848 vos::OGuard aGuard( Application::GetSolarMutex() );
1849 // need to lock the SolarMutex so that no paint call disturbs us ...
1851 if ( !m_pSeekCursor )
1853 DBG_ERROR( "FmGridControl::selectBookmarks: no seek cursor!" );
1854 return sal_False;
1857 const Any* pBookmark = _rBookmarks.getConstArray();
1858 const Any* pBookmarkEnd = pBookmark + _rBookmarks.getLength();
1860 SetNoSelection();
1862 sal_Bool bAllSuccessfull = sal_True;
1865 for (; pBookmark != pBookmarkEnd; ++pBookmark)
1867 // move the seek cursor to the row given
1868 if (m_pSeekCursor->moveToBookmark(*pBookmark))
1869 SelectRow( m_pSeekCursor->getRow() - 1);
1870 else
1871 bAllSuccessfull = sal_False;
1874 catch(Exception&)
1876 DBG_ERROR("FmGridControl::selectBookmarks: could not move to one of the bookmarks!");
1877 return sal_False;
1880 return bAllSuccessfull;
1883 //------------------------------------------------------------------------------
1884 Sequence< Any> FmGridControl::getSelectionBookmarks()
1886 // lock our update so no paint-triggered seeks interfere ...
1887 SetUpdateMode(sal_False);
1889 sal_Int32 nSelectedRows = GetSelectRowCount(), i = 0;
1890 Sequence< Any> aBookmarks(nSelectedRows);
1891 if ( nSelectedRows )
1893 Any* pBookmarks = (Any*)aBookmarks.getArray();
1895 // (I'm not sure if the problem isn't deeper : The szenario : a large table displayed by a grid with a
1896 // thread-safe cursor (dBase). On loading the sdb-cursor started a counting thread. While this counting progress
1897 // was running, I tried do delete 3 records from within the grid. Deletion caused a SeekCursor, which did a
1898 // m_pSeekCursor->moveRelative and a m_pSeekCursor->getPosition.
1899 // Unfortunally the first call caused a propertyChanged(RECORDCOUNT) which resulted in a repaint of the
1900 // navigation bar and the grid. The latter itself will result in SeekRow calls. So after (successfully) returning
1901 // from the moveRelative the getPosition returns an invalid value. And so the SeekCursor fails.
1902 // In the consequence ALL parts of code where two calls to the seek cursor are done, while the second call _relys_ on
1903 // the first one, should be secured against recursion, with a broad-minded interpretion of "recursion" : if any of these
1904 // code parts is executed, no other should be accessible. But this sounds very difficult to achieve ....
1905 // )
1907 // The next problem caused by the same behaviuor (SeekCursor causes a propertyChanged) : when adjusting rows we implicitly
1908 // change our selection. So a "FirstSelected(); SeekCursor(); NextSelected();" may produce unpredictable results.
1909 // That's why we _first_ collect the indicies of the selected rows and _then_ their bookmarks.
1910 long nIdx = FirstSelectedRow();
1911 while (nIdx >= 0)
1913 // (we misuse the bookmarks array for this ...)
1914 pBookmarks[i++] <<= (sal_Int32)nIdx;
1915 nIdx = NextSelectedRow();
1917 DBG_ASSERT(i == nSelectedRows, "FmGridControl::DeleteSelectedRows : could not collect the row indicies !");
1919 for (i=0; i<nSelectedRows; ++i)
1921 nIdx = ::comphelper::getINT32(pBookmarks[i]);
1922 if (IsInsertionRow(nIdx))
1924 // leerzeile nicht loeschen
1925 aBookmarks.realloc(--nSelectedRows);
1926 SelectRow(nIdx,sal_False); // selection aufheben fuer leerzeile
1927 break;
1930 // Zunaechst den DatenCursor auf den selektierten Satz pos.
1931 if (SeekCursor(nIdx))
1933 GetSeekRow()->SetState(m_pSeekCursor, sal_True);
1935 pBookmarks[i] = m_pSeekCursor->getBookmark();
1937 #ifdef DBG_UTIL
1938 else
1939 DBG_ERROR("FmGridControl::DeleteSelectedRows : a bookmark could not be determined !");
1940 #endif
1943 SetUpdateMode(sal_True);
1945 // if one of the SeekCursor-calls failed ....
1946 aBookmarks.realloc(i);
1948 // (the alternative : while collecting the bookmarks lock our propertyChanged, this should resolve both our problems.
1949 // but this would be incompatible as we need a locking flag, then ...)
1951 return aBookmarks;
1953 // -----------------------------------------------------------------------------
1954 namespace
1956 ::rtl::OUString getColumnPropertyFromPeer(FmXGridPeer* _pPeer,sal_Int32 _nPosition,const ::rtl::OUString& _sPropName)
1958 ::rtl::OUString sRetText;
1959 if ( _pPeer && _nPosition != -1)
1961 Reference<XIndexContainer> xIndex = _pPeer->getColumns();
1962 if ( xIndex.is() && xIndex->getCount() > _nPosition )
1964 Reference<XPropertySet> xProp;
1965 xIndex->getByIndex( _nPosition ) >>= xProp;
1966 if ( xProp.is() )
1967 xProp->getPropertyValue( _sPropName ) >>= sRetText;
1970 return sRetText;
1973 // Object data and state ------------------------------------------------------
1974 ::rtl::OUString FmGridControl::GetAccessibleObjectName( ::svt::AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const
1976 ::rtl::OUString sRetText;
1977 switch( _eObjType )
1979 case ::svt::BBTYPE_BROWSEBOX:
1980 if ( GetPeer() )
1982 Reference<XPropertySet> xProp(GetPeer()->getColumns(),UNO_QUERY);
1983 if ( xProp.is() )
1984 xProp->getPropertyValue(FM_PROP_NAME) >>= sRetText;
1986 break;
1987 case ::svt::BBTYPE_COLUMNHEADERCELL:
1988 sRetText = getColumnPropertyFromPeer(
1989 GetPeer(),
1990 GetModelColumnPos(
1991 sal::static_int_cast< sal_uInt16 >(_nPosition)),
1992 FM_PROP_LABEL);
1993 break;
1994 default:
1995 sRetText = DbGridControl::GetAccessibleObjectName(_eObjType,_nPosition);
1997 return sRetText;
1999 // -----------------------------------------------------------------------------
2001 ::rtl::OUString FmGridControl::GetAccessibleObjectDescription( ::svt::AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const
2003 ::rtl::OUString sRetText;
2004 switch( _eObjType )
2006 case ::svt::BBTYPE_BROWSEBOX:
2007 if ( GetPeer() )
2009 Reference<XPropertySet> xProp(GetPeer()->getColumns(),UNO_QUERY);
2010 if ( xProp.is() )
2011 xProp->getPropertyValue(FM_PROP_HELPTEXT) >>= sRetText;
2013 break;
2014 case ::svt::BBTYPE_COLUMNHEADERCELL:
2015 sRetText = getColumnPropertyFromPeer(
2016 GetPeer(),
2017 GetModelColumnPos(
2018 sal::static_int_cast< sal_uInt16 >(_nPosition)),
2019 FM_PROP_HELPTEXT);
2020 break;
2021 default:
2022 sRetText = DbGridControl::GetAccessibleObjectDescription(_eObjType,_nPosition);
2024 return sRetText;
2026 // -----------------------------------------------------------------------------
2027 void FmGridControl::Select()
2029 DbGridControl::Select();
2030 // ... betrifft das unsere Spalten ?
2031 const MultiSelection* pColumnSelection = GetColumnSelection();
2033 sal_uInt16 nSelectedColumn =
2034 pColumnSelection && pColumnSelection->GetSelectCount()
2035 ? sal::static_int_cast< sal_uInt16 >(
2036 ((MultiSelection*)pColumnSelection)->FirstSelected())
2037 : SAL_MAX_UINT16;
2038 // die HandleColumn wird nicht selektiert
2039 switch (nSelectedColumn)
2041 case -1 : break; // no selection
2042 case 0 : nSelectedColumn = SAL_MAX_UINT16; break;
2043 // handle col can't be seledted
2044 default :
2045 // get the model col pos instead of the view col pos
2046 nSelectedColumn = GetModelColumnPos(GetColumnIdFromViewPos(nSelectedColumn - 1));
2047 break;
2050 if (nSelectedColumn != m_nCurrentSelectedColumn)
2052 // VOR dem Aufruf des select am SelectionSupplier !
2053 m_nCurrentSelectedColumn = nSelectedColumn;
2055 if (!m_bSelecting)
2057 m_bSelecting = sal_True;
2061 Reference< XIndexAccess > xColumns(GetPeer()->getColumns(), UNO_QUERY);
2062 Reference< XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
2063 if (xSelSupplier.is())
2065 if (nSelectedColumn != SAL_MAX_UINT16)
2067 Reference< XPropertySet > xColumn;
2068 ::cppu::extractInterface(xColumn,xColumns->getByIndex(nSelectedColumn));
2069 xSelSupplier->select(makeAny(xColumn));
2071 else
2073 xSelSupplier->select(Any());
2077 catch(Exception&)
2082 m_bSelecting = sal_False;
2086 // -----------------------------------------------------------------------------
2087 sal_Int32 FmGridControl::GetSelectedColumn() const
2089 return m_nCurrentSelectedColumn;
2091 // -----------------------------------------------------------------------------
2092 void FmGridControl::KeyInput( const KeyEvent& rKEvt )
2094 sal_Bool bDone = sal_False;
2095 const KeyCode& rKeyCode = rKEvt.GetKeyCode();
2096 if ( IsDesignMode()
2097 && !rKeyCode.IsShift()
2098 && !rKeyCode.IsMod1()
2099 && !rKeyCode.IsMod2()
2100 && GetParent() )
2102 switch ( rKeyCode.GetCode() )
2104 case KEY_ESCAPE:
2105 GetParent()->GrabFocus();
2106 bDone = sal_True;
2107 break;
2108 case KEY_DELETE:
2109 if ( GetSelectColumnCount() && GetPeer() && m_nCurrentSelectedColumn >= 0 )
2111 Reference< ::com::sun::star::container::XIndexContainer > xCols(GetPeer()->getColumns());
2112 if ( xCols.is() )
2116 if ( m_nCurrentSelectedColumn < xCols->getCount() )
2118 Reference< XInterface > xCol;
2119 xCols->getByIndex(m_nCurrentSelectedColumn) >>= xCol;
2120 xCols->removeByIndex(m_nCurrentSelectedColumn);
2121 ::comphelper::disposeComponent(xCol);
2124 catch(const Exception&)
2126 OSL_ENSURE(0,"exception occured while deleting a column");
2130 bDone = sal_True;
2131 break;
2134 if ( !bDone )
2135 DbGridControl::KeyInput( rKEvt );
2137 // -----------------------------------------------------------------------------