update credits
[LibreOffice.git] / svx / source / fmcomp / fmgridcl.cxx
blob374af649308de32bc7352303567d95c14997cf1a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "svx/fmgridif.hxx"
21 #include "fmitems.hxx"
22 #include "fmprop.hrc"
23 #include "svx/fmtools.hxx"
24 #include "svx/fmresids.hrc"
25 #include "fmservs.hxx"
26 #include "fmurl.hxx"
27 #include "formcontrolfactory.hxx"
28 #include "gridcell.hxx"
29 #include "gridcols.hxx"
30 #include "svx/dbaexchange.hxx"
31 #include "svx/dialmgr.hxx"
32 #include "svx/dialogs.hrc"
33 #include "svx/fmgridcl.hxx"
34 #include "svx/svxdlg.hxx"
35 #include "svx/svxids.hrc"
37 #include <com/sun/star/form/XConfirmDeleteListener.hpp>
38 #include <com/sun/star/form/XFormComponent.hpp>
39 #include <com/sun/star/form/XGridColumnFactory.hpp>
40 #include <com/sun/star/io/XPersistObject.hpp>
41 #include <com/sun/star/sdb/CommandType.hpp>
42 #include <com/sun/star/sdb/RowChangeAction.hpp>
43 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
44 #include <com/sun/star/sdbc/DataType.hpp>
45 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
46 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
47 #include <com/sun/star/sdbcx/XDeleteRows.hpp>
48 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
49 #include <com/sun/star/uno/XNamingService.hpp>
50 #include <com/sun/star/util/XNumberFormats.hpp>
51 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
52 #include <com/sun/star/util/URLTransformer.hpp>
53 #include <com/sun/star/util/XURLTransformer.hpp>
54 #include <com/sun/star/view/XSelectionSupplier.hpp>
55 #include <comphelper/extract.hxx>
56 #include <comphelper/numbers.hxx>
57 #include <comphelper/processfactory.hxx>
58 #include <comphelper/property.hxx>
59 #include <comphelper/string.hxx>
60 #include <connectivity/dbtools.hxx>
61 #include <sfx2/dispatch.hxx>
62 #include <sfx2/viewfrm.hxx>
63 #include <svl/eitem.hxx>
64 #include <svtools/fmtfield.hxx>
65 #include <svl/numuno.hxx>
66 #include <tools/multisel.hxx>
67 #include <tools/shl.hxx>
68 #include <tools/diagnose_ex.h>
69 #include <vcl/help.hxx>
70 #include <vcl/image.hxx>
71 #include <vcl/longcurr.hxx>
72 #include <vcl/menu.hxx>
74 #include <math.h>
76 using namespace ::com::sun::star::uno;
77 using namespace ::com::sun::star::view;
78 using namespace ::com::sun::star::beans;
79 using namespace ::com::sun::star::lang;
80 using namespace ::com::sun::star::sdbcx;
81 using namespace ::com::sun::star::sdbc;
82 using namespace ::com::sun::star::sdb;
83 using namespace ::com::sun::star::form;
84 using namespace ::com::sun::star::util;
85 using namespace ::com::sun::star::container;
86 using namespace ::cppu;
87 using namespace ::svxform;
88 using namespace ::svx;
90 //==============================================================================
91 //------------------------------------------------------------------------------
92 OUString FieldServiceFromId(sal_Int32 nID)
94 switch (nID)
96 case SID_FM_EDIT : return FM_COL_TEXTFIELD;
97 case SID_FM_COMBOBOX : return FM_COL_COMBOBOX;
98 case SID_FM_LISTBOX : return FM_COL_LISTBOX;
99 case SID_FM_CHECKBOX : return FM_COL_CHECKBOX;
100 case SID_FM_DATEFIELD : return FM_COL_DATEFIELD;
101 case SID_FM_TIMEFIELD : return FM_COL_TIMEFIELD;
102 case SID_FM_NUMERICFIELD : return FM_COL_NUMERICFIELD;
103 case SID_FM_CURRENCYFIELD : return FM_COL_CURRENCYFIELD;
104 case SID_FM_PATTERNFIELD : return FM_COL_PATTERNFIELD;
105 case SID_FM_FORMATTEDFIELD : return FM_COL_FORMATTEDFIELD;
107 return OUString();
110 //==============================================================================
111 struct FmGridHeaderData
113 ODataAccessDescriptor aDropData;
114 Point aDropPosPixel;
115 sal_Int8 nDropAction;
116 Reference< XInterface > xDroppedStatement;
117 Reference< XInterface > xDroppedResultSet;
120 //==============================================================================
121 //------------------------------------------------------------------------------
122 const sal_Int16 nChangeTypeOffset = 1000;
123 void SetMenuItem(const ImageList& rList, sal_uInt16 nID, Menu* pMenu, Menu& rNewMenu, sal_Bool bDesignMode = sal_True, sal_Int16 nOffset = nChangeTypeOffset)
125 pMenu->SetItemImage(nID, rList.GetImage(nID));
126 pMenu->EnableItem(nID, bDesignMode);
127 rNewMenu.InsertItem(nID + nOffset, pMenu->GetItemText(nID));
128 rNewMenu.SetItemImage(nID + nOffset, rList.GetImage(nID));
129 rNewMenu.SetHelpId(nID + nOffset, pMenu->GetHelpId(nID));
130 rNewMenu.EnableItem(nID + nOffset, bDesignMode);
133 //------------------------------------------------------------------------------
134 FmGridHeader::FmGridHeader( BrowseBox* pParent, WinBits nWinBits)
135 :EditBrowserHeader(pParent, nWinBits)
136 ,DropTargetHelper(this)
137 ,m_pImpl(new FmGridHeaderData)
141 //------------------------------------------------------------------------------
142 FmGridHeader::~FmGridHeader()
144 delete m_pImpl;
147 //------------------------------------------------------------------------------
148 sal_uInt16 FmGridHeader::GetModelColumnPos(sal_uInt16 nId) const
150 return static_cast<FmGridControl*>(GetParent())->GetModelColumnPos(nId);
152 //---------------------------------------------------------------------------------------
153 void FmGridHeader::notifyColumnSelect(sal_uInt16 nColumnId)
155 sal_uInt16 nPos = GetModelColumnPos(nColumnId);
156 Reference< XIndexAccess > xColumns(((FmGridControl*)GetParent())->GetPeer()->getColumns(), UNO_QUERY);
157 if ( nPos < xColumns->getCount() )
159 Reference< XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
160 if ( xSelSupplier.is() )
162 Reference< XPropertySet > xColumn;
163 xColumns->getByIndex(nPos) >>= xColumn;
164 xSelSupplier->select(makeAny(xColumn));
168 //------------------------------------------------------------------------------
169 void FmGridHeader::Select()
171 EditBrowserHeader::Select();
172 notifyColumnSelect(GetCurItemId());
175 //------------------------------------------------------------------------------
176 void FmGridHeader::RequestHelp( const HelpEvent& rHEvt )
178 sal_uInt16 nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
179 if ( nItemId )
181 if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) )
183 Rectangle aItemRect = GetItemRect( nItemId );
184 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
185 aItemRect.Left() = aPt.X();
186 aItemRect.Top() = aPt.Y();
187 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
188 aItemRect.Right() = aPt.X();
189 aItemRect.Bottom() = aPt.Y();
191 sal_uInt16 nPos = GetModelColumnPos(nItemId);
192 Reference< ::com::sun::star::container::XIndexContainer > xColumns(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
195 Reference< ::com::sun::star::beans::XPropertySet > xColumn(xColumns->getByIndex(nPos),UNO_QUERY);
196 OUString aHelpText;
197 xColumn->getPropertyValue(FM_PROP_HELPTEXT) >>= aHelpText;
198 if ( aHelpText.isEmpty() )
199 xColumn->getPropertyValue(FM_PROP_DESCRIPTION) >>= aHelpText;
200 if ( !aHelpText.isEmpty() )
202 if ( rHEvt.GetMode() & HELPMODE_BALLOON )
203 Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aHelpText );
204 else
205 Help::ShowQuickHelp( this, aItemRect, aHelpText );
206 return;
209 catch(Exception&)
211 return;
215 EditBrowserHeader::RequestHelp( rHEvt );
218 //------------------------------------------------------------------------------
219 sal_Int8 FmGridHeader::AcceptDrop( const AcceptDropEvent& rEvt )
221 // drop allowed in design mode only
222 if (!static_cast<FmGridControl*>(GetParent())->IsDesignMode())
223 return DND_ACTION_NONE;
225 // search for recognized formats
226 const DataFlavorExVector& rFlavors = GetDataFlavorExVector();
227 if (OColumnTransferable::canExtractColumnDescriptor(rFlavors, CTF_COLUMN_DESCRIPTOR | CTF_FIELD_DESCRIPTOR))
228 return rEvt.mnAction;
230 return DND_ACTION_NONE;
233 //------------------------------------------------------------------------------
234 sal_Int8 FmGridHeader::ExecuteDrop( const ExecuteDropEvent& _rEvt )
236 if (!static_cast<FmGridControl*>(GetParent())->IsDesignMode())
237 return DND_ACTION_NONE;
239 TransferableDataHelper aDroppedData(_rEvt.maDropEvent.Transferable);
241 // check the formats
242 sal_Bool bColumnDescriptor = OColumnTransferable::canExtractColumnDescriptor(aDroppedData.GetDataFlavorExVector(), CTF_COLUMN_DESCRIPTOR);
243 sal_Bool bFieldDescriptor = OColumnTransferable::canExtractColumnDescriptor(aDroppedData.GetDataFlavorExVector(), CTF_FIELD_DESCRIPTOR);
244 if (!bColumnDescriptor && !bFieldDescriptor)
246 OSL_FAIL("FmGridHeader::ExecuteDrop: should never have reached this (no extractable format)!");
247 return DND_ACTION_NONE;
250 // extract the descriptor
251 OUString sDatasouce, sCommand, sFieldName,sDatabaseLocation,sConnnectionResource;
252 sal_Int32 nCommandType = CommandType::COMMAND;
253 Reference< XPreparedStatement > xStatement;
254 Reference< XResultSet > xResultSet;
255 Reference< XPropertySet > xField;
256 Reference< XConnection > xConnection;
258 ODataAccessDescriptor aColumn = OColumnTransferable::extractColumnDescriptor(aDroppedData);
259 if (aColumn.has(daDataSource)) aColumn[daDataSource] >>= sDatasouce;
260 if (aColumn.has(daDatabaseLocation)) aColumn[daDatabaseLocation] >>= sDatabaseLocation;
261 if (aColumn.has(daConnectionResource)) aColumn[daConnectionResource] >>= sConnnectionResource;
262 if (aColumn.has(daCommand)) aColumn[daCommand] >>= sCommand;
263 if (aColumn.has(daCommandType)) aColumn[daCommandType] >>= nCommandType;
264 if (aColumn.has(daColumnName)) aColumn[daColumnName] >>= sFieldName;
265 if (aColumn.has(daColumnObject))aColumn[daColumnObject] >>= xField;
266 if (aColumn.has(daConnection)) aColumn[daConnection] >>= xConnection;
268 if ( sFieldName.isEmpty()
269 || sCommand.isEmpty()
270 || ( sDatasouce.isEmpty()
271 && sDatabaseLocation.isEmpty()
272 && !xConnection.is()
276 OSL_FAIL( "FmGridHeader::ExecuteDrop: somebody started a nonsense drag operation!!" );
277 return DND_ACTION_NONE;
282 // need a connection
283 if (!xConnection.is())
284 { // the transferable did not contain the connection -> build an own one
287 OUString sSignificantSource( sDatasouce.isEmpty() ? sDatabaseLocation : sDatasouce );
288 xConnection = OStaticDataAccessTools().getConnection_withFeedback(sSignificantSource, OUString(), OUString(),
289 static_cast<FmGridControl*>(GetParent())->getContext() );
291 catch(NoSuchElementException&)
292 { // allowed, means sDatasouce isn't a valid data source name ....
294 catch(Exception&)
296 OSL_FAIL("FmGridHeader::ExecuteDrop: could not retrieve the database access object !");
299 if (!xConnection.is())
301 OSL_FAIL("FmGridHeader::ExecuteDrop: could not retrieve the database access object !");
302 return DND_ACTION_NONE;
306 // try to obtain the column object
307 if (!xField.is())
309 #ifdef DBG_UTIL
310 Reference< XServiceInfo > xServiceInfo(xConnection, UNO_QUERY);
311 DBG_ASSERT(xServiceInfo.is() && xServiceInfo->supportsService(SRV_SDB_CONNECTION), "FmGridHeader::ExecuteDrop: invalid connection (no database access connection !)");
312 #endif
314 Reference< XNameAccess > xFields;
315 switch (nCommandType)
317 case CommandType::TABLE:
319 Reference< XTablesSupplier > xSupplyTables(xConnection, UNO_QUERY);
320 Reference< XColumnsSupplier > xSupplyColumns;
321 xSupplyTables->getTables()->getByName(sCommand) >>= xSupplyColumns;
322 xFields = xSupplyColumns->getColumns();
324 break;
325 case CommandType::QUERY:
327 Reference< XQueriesSupplier > xSupplyQueries(xConnection, UNO_QUERY);
328 Reference< XColumnsSupplier > xSupplyColumns;
329 xSupplyQueries->getQueries()->getByName(sCommand) >>= xSupplyColumns;
330 xFields = xSupplyColumns->getColumns();
332 break;
333 default:
335 xStatement = xConnection->prepareStatement(sCommand);
336 // not interested in any results
338 Reference< XPropertySet > xStatProps(xStatement,UNO_QUERY);
339 xStatProps->setPropertyValue(OUString("MaxRows"), makeAny(sal_Int32(0)));
341 xResultSet = xStatement->executeQuery();
342 Reference< XColumnsSupplier > xSupplyCols(xResultSet, UNO_QUERY);
343 if (xSupplyCols.is())
344 xFields = xSupplyCols->getColumns();
348 if (xFields.is() && xFields->hasByName(sFieldName))
349 xFields->getByName(sFieldName) >>= xField;
351 if (!xField.is())
353 ::comphelper::disposeComponent(xStatement);
354 return DND_ACTION_NONE;
358 // do the drop asynchronously
359 // (85957 - UI actions within the drop are not allowed, but we want to open a popup menu)
360 m_pImpl->aDropData = aColumn;
361 m_pImpl->aDropData[daConnection] <<= xConnection;
362 m_pImpl->aDropData[daColumnObject] <<= xField;
364 m_pImpl->nDropAction = _rEvt.mnAction;
365 m_pImpl->aDropPosPixel = _rEvt.maPosPixel;
366 m_pImpl->xDroppedStatement = xStatement;
367 m_pImpl->xDroppedResultSet = xResultSet;
369 PostUserEvent(LINK(this, FmGridHeader, OnAsyncExecuteDrop));
371 catch (Exception&)
373 OSL_FAIL("FmGridHeader::ExecuteDrop: caught an exception while creatin' the column !");
374 ::comphelper::disposeComponent(xStatement);
375 return sal_False;
378 return DND_ACTION_LINK;
381 //------------------------------------------------------------------------------
382 IMPL_LINK( FmGridHeader, OnAsyncExecuteDrop, void*, /*NOTINTERESTEDIN*/ )
384 OUString sCommand, sFieldName,sURL;
385 sal_Int32 nCommandType = CommandType::COMMAND;
386 Reference< XPropertySet > xField;
387 Reference< XConnection > xConnection;
389 OUString sDatasouce = m_pImpl->aDropData.getDataSource();
390 if ( sDatasouce.isEmpty() && m_pImpl->aDropData.has(daConnectionResource) )
391 m_pImpl->aDropData[daConnectionResource] >>= sURL;
392 m_pImpl->aDropData[daCommand] >>= sCommand;
393 m_pImpl->aDropData[daCommandType] >>= nCommandType;
394 m_pImpl->aDropData[daColumnName] >>= sFieldName;
395 m_pImpl->aDropData[daConnection] >>= xConnection;
396 m_pImpl->aDropData[daColumnObject] >>= xField;
400 // need number formats
401 Reference< XNumberFormatsSupplier > xSupplier = OStaticDataAccessTools().getNumberFormats(xConnection, sal_True);
402 Reference< XNumberFormats > xNumberFormats;
403 if (xSupplier.is())
404 xNumberFormats = xSupplier->getNumberFormats();
405 if (!xNumberFormats.is())
407 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
408 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
409 return 0L;
412 // Vom Feld werden nun zwei Informationen benoetigt:
413 // a.) Name des Feldes fuer Label und ControlSource
414 // b.) FormatKey, um festzustellen, welches Feld erzeugt werden soll
415 sal_Int32 nDataType = 0;
416 xField->getPropertyValue(FM_PROP_FIELDTYPE) >>= nDataType;
417 // diese Datentypen koennen im Gridcontrol nicht verarbeitet werden
418 switch (nDataType)
420 case DataType::BLOB:
421 case DataType::LONGVARBINARY:
422 case DataType::BINARY:
423 case DataType::VARBINARY:
424 case DataType::OTHER:
425 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
426 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
427 return 0L;
430 // Erstellen der Column
431 Reference< XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
432 Reference< XGridColumnFactory > xFactory(xCols, UNO_QUERY);
434 sal_uInt16 nColId = GetItemId(m_pImpl->aDropPosPixel);
435 // EinfuegePosition, immer vor der aktuellen Spalte
436 sal_uInt16 nPos = GetModelColumnPos(nColId);
437 Reference< XPropertySet > xCol, xSecondCol;
439 // Create Column based on type, default textfield
440 std::vector<sal_uInt16> aPossibleTypes;
441 switch (nDataType)
443 case DataType::BIT:
444 case DataType::BOOLEAN:
445 aPossibleTypes.push_back(SID_FM_CHECKBOX);
446 break;
447 case DataType::TINYINT:
448 case DataType::SMALLINT:
449 case DataType::INTEGER:
450 aPossibleTypes.push_back(SID_FM_NUMERICFIELD);
451 aPossibleTypes.push_back(SID_FM_FORMATTEDFIELD);
452 break;
453 case DataType::REAL:
454 case DataType::DOUBLE:
455 case DataType::NUMERIC:
456 case DataType::DECIMAL:
457 aPossibleTypes.push_back(SID_FM_FORMATTEDFIELD);
458 aPossibleTypes.push_back(SID_FM_NUMERICFIELD);
459 break;
460 case DataType::TIMESTAMP:
461 aPossibleTypes.push_back(SID_FM_TWOFIELDS_DATE_N_TIME);
462 aPossibleTypes.push_back(SID_FM_DATEFIELD);
463 aPossibleTypes.push_back(SID_FM_TIMEFIELD);
464 aPossibleTypes.push_back(SID_FM_FORMATTEDFIELD);
465 break;
466 case DataType::DATE:
467 aPossibleTypes.push_back(SID_FM_DATEFIELD);
468 aPossibleTypes.push_back(SID_FM_FORMATTEDFIELD);
469 break;
470 case DataType::TIME:
471 aPossibleTypes.push_back(SID_FM_TIMEFIELD);
472 aPossibleTypes.push_back(SID_FM_FORMATTEDFIELD);
473 break;
474 case DataType::CHAR:
475 case DataType::VARCHAR:
476 case DataType::LONGVARCHAR:
477 default:
478 aPossibleTypes.push_back(SID_FM_EDIT);
479 aPossibleTypes.push_back(SID_FM_FORMATTEDFIELD);
480 break;
482 // if it's a currency field, a a "currency field" option
485 if ( ::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField)
486 && ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY)))
487 aPossibleTypes.insert(aPossibleTypes.begin(), SID_FM_CURRENCYFIELD);
489 catch(Exception&)
491 OSL_FAIL("FmGridHeader::ExecuteDrop: Exception occurred!");
494 sal_Bool bDateNTimeCol = sal_False;
495 if (!aPossibleTypes.empty())
497 sal_Int32 nPreferedType = aPossibleTypes[0];
498 if ((m_pImpl->nDropAction == DND_ACTION_LINK) && (aPossibleTypes.size() > 1))
500 ImageList aImageList( SVX_RES(RID_SVXIMGLIST_FMEXPL) );
502 PopupMenu aInsertMenu(SVX_RES(RID_SVXMNU_COLS));
503 PopupMenu aTypeMenu;
504 PopupMenu* pMenu = aInsertMenu.GetPopupMenu(SID_FM_INSERTCOL);
505 for (std::vector<sal_uInt16>::const_iterator iter = aPossibleTypes.begin(); iter != aPossibleTypes.end(); ++iter)
506 SetMenuItem(aImageList, *iter, pMenu, aTypeMenu, sal_True, 0);
507 nPreferedType = aTypeMenu.Execute(this, m_pImpl->aDropPosPixel);
510 bDateNTimeCol = nPreferedType == SID_FM_TWOFIELDS_DATE_N_TIME;
511 sal_uInt16 nColCount = bDateNTimeCol ? 2 : 1;
512 OUString sFieldService;
513 while (nColCount--)
515 if (bDateNTimeCol)
516 nPreferedType = nColCount ? SID_FM_DATEFIELD : SID_FM_TIMEFIELD;
518 sFieldService = FieldServiceFromId(nPreferedType);
519 Reference< XPropertySet > xThisRoundCol;
520 if ( !sFieldService.isEmpty() )
521 xThisRoundCol = xFactory->createColumn(sFieldService);
522 if (nColCount)
523 xSecondCol = xThisRoundCol;
524 else
525 xCol = xThisRoundCol;
529 if (!xCol.is() || (bDateNTimeCol && !xSecondCol.is()))
531 ::comphelper::disposeComponent(xCol); // in case only the creation of the second column failed
532 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
533 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
534 return 0L;
537 if (bDateNTimeCol)
539 String sTimePostfix( SVX_RES( RID_STR_POSTFIX_TIME ) );
540 xCol->setPropertyValue(FM_PROP_LABEL, makeAny( OUString( sFieldName + sTimePostfix ) ) );
542 String sDatePostfix( SVX_RES( RID_STR_POSTFIX_DATE ) );
543 xSecondCol->setPropertyValue(FM_PROP_LABEL, makeAny( OUString( sFieldName + sDatePostfix ) ) );
545 else
546 xCol->setPropertyValue(FM_PROP_LABEL, makeAny(sFieldName));
548 FormControlFactory aControlFactory( ::comphelper::getProcessServiceFactory() );
549 aControlFactory.initializeControlModel( DocumentClassification::classifyHostDocument( xCols ), xCol );
550 aControlFactory.initializeFieldDependentProperties( xField, xCol, xNumberFormats );
552 xCol->setPropertyValue(FM_PROP_CONTROLSOURCE, makeAny(sFieldName));
553 if ( xSecondCol.is() )
554 xSecondCol->setPropertyValue(FM_PROP_CONTROLSOURCE, makeAny(sFieldName));
556 if (bDateNTimeCol)
558 String sRealName,sPurePostfix;
560 String aPostfix[] = {
561 String( SVX_RES( RID_STR_POSTFIX_DATE ) ),
562 String( SVX_RES( RID_STR_POSTFIX_TIME ) )
565 for ( size_t i=0; i<2; ++i )
567 sPurePostfix = comphelper::string::stripStart(aPostfix[i], ' ');
568 sPurePostfix = comphelper::string::stripStart(sPurePostfix, '(');
569 sPurePostfix = comphelper::string::stripEnd(sPurePostfix, ')');
570 sRealName = sFieldName;
571 sRealName += '_';
572 sRealName += sPurePostfix;
573 if (i)
574 xSecondCol->setPropertyValue(FM_PROP_NAME, makeAny(OUString(sRealName)));
575 else
576 xCol->setPropertyValue(FM_PROP_NAME, makeAny(OUString(sRealName)));
579 else
580 xCol->setPropertyValue(FM_PROP_NAME, makeAny(sFieldName));
582 // jetzt einfuegen
583 Any aElement;
584 aElement <<= xCol;
585 xCols->insertByIndex(nPos, aElement);
587 if (bDateNTimeCol)
589 aElement <<= xSecondCol;
590 xCols->insertByIndex(nPos == (sal_uInt16)-1 ? nPos : ++nPos, aElement);
593 // ist die component::Form an die Datenbankangebunden?
594 Reference< XFormComponent > xFormCp(xCols, UNO_QUERY);
595 Reference< XPropertySet > xForm(xFormCp->getParent(), UNO_QUERY);
596 if (xForm.is())
598 if (::comphelper::getString(xForm->getPropertyValue(FM_PROP_DATASOURCE)).isEmpty())
600 if ( !sDatasouce.isEmpty() )
601 xForm->setPropertyValue(FM_PROP_DATASOURCE, makeAny(sDatasouce));
602 else
603 xForm->setPropertyValue(FM_PROP_URL, makeAny(sURL));
606 if (::comphelper::getString(xForm->getPropertyValue(FM_PROP_COMMAND)).isEmpty())
608 xForm->setPropertyValue(FM_PROP_COMMAND, makeAny(sCommand));
609 Any aCommandType;
610 switch (nCommandType)
612 case CommandType::TABLE:
613 aCommandType <<= (sal_Int32)CommandType::TABLE;
614 break;
615 case CommandType::QUERY:
616 aCommandType <<= (sal_Int32)CommandType::QUERY;
617 break;
618 default:
619 aCommandType <<= (sal_Int32)CommandType::COMMAND;
620 xForm->setPropertyValue(FM_PROP_ESCAPE_PROCESSING, bool2any((sal_Bool)(2 == nCommandType)));
621 break;
623 xForm->setPropertyValue(FM_PROP_COMMANDTYPE, aCommandType);
627 catch (Exception&)
629 OSL_FAIL("FmGridHeader::OnAsyncExecuteDrop: caught an exception while creatin' the column !");
630 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
631 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
632 return 0L;
635 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
636 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
637 return 1L;
640 //------------------------------------------------------------------------------
641 void FmGridHeader::PreExecuteColumnContextMenu(sal_uInt16 nColId, PopupMenu& rMenu)
643 sal_Bool bDesignMode = static_cast<FmGridControl*>(GetParent())->IsDesignMode();
645 Reference< ::com::sun::star::container::XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
646 // Aufbau des Insert Menues
647 // mark the column if nColId != HEADERBAR_ITEM_NOTFOUND
648 if(nColId > 0)
650 sal_uInt16 nPos2 = GetModelColumnPos(nColId);
652 Reference< ::com::sun::star::container::XIndexContainer > xColumns(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
653 Reference< ::com::sun::star::beans::XPropertySet> xColumn;
654 ::cppu::extractInterface(xColumn, xColumns->getByIndex(nPos2));
655 Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
656 if (xSelSupplier.is())
657 xSelSupplier->select(makeAny(xColumn));
660 // EinfuegePosition, immer vor der aktuellen Spalte
661 sal_uInt16 nPos = GetModelColumnPos(nColId);
662 sal_Bool bMarked = nColId && static_cast<FmGridControl*>(GetParent())->isColumnMarked(nColId);
664 ImageList aImageList( SVX_RES(RID_SVXIMGLIST_FMEXPL) );
665 PopupMenu* pControlMenu = new PopupMenu;
667 PopupMenu* pMenu = rMenu.GetPopupMenu(SID_FM_INSERTCOL);
668 if (pMenu)
670 SetMenuItem(aImageList, SID_FM_EDIT, pMenu, *pControlMenu, bDesignMode);
671 SetMenuItem(aImageList, SID_FM_CHECKBOX, pMenu, *pControlMenu, bDesignMode);
672 SetMenuItem(aImageList, SID_FM_COMBOBOX, pMenu, *pControlMenu, bDesignMode);
673 SetMenuItem(aImageList, SID_FM_LISTBOX, pMenu, *pControlMenu, bDesignMode);
674 SetMenuItem(aImageList, SID_FM_DATEFIELD, pMenu, *pControlMenu, bDesignMode);
675 SetMenuItem(aImageList, SID_FM_TIMEFIELD, pMenu, *pControlMenu, bDesignMode);
676 SetMenuItem(aImageList, SID_FM_NUMERICFIELD, pMenu, *pControlMenu, bDesignMode);
677 SetMenuItem(aImageList, SID_FM_CURRENCYFIELD, pMenu, *pControlMenu, bDesignMode);
678 SetMenuItem(aImageList, SID_FM_PATTERNFIELD, pMenu, *pControlMenu, bDesignMode);
679 SetMenuItem(aImageList, SID_FM_FORMATTEDFIELD, pMenu, *pControlMenu, bDesignMode);
682 if (pMenu && xCols.is() && nColId)
684 Reference< ::com::sun::star::beans::XPropertySet > xSet;
685 ::cppu::extractInterface(xSet, xCols->getByIndex(nPos));
686 sal_Int16 nClassId;
687 xSet->getPropertyValue(FM_PROP_CLASSID) >>= nClassId;
689 Reference< ::com::sun::star::io::XPersistObject > xServiceQuestion(xSet, UNO_QUERY);
690 sal_Int32 nColType = xServiceQuestion.is() ? getColumnTypeByModelName(xServiceQuestion->getServiceName()) : 0;
691 if (nColType == TYPE_TEXTFIELD)
692 { // edit fields and formatted fields have the same service name, thus getColumnTypeByModelName returns TYPE_TEXTFIELD
693 // in both cases. And as columns don't have an ::com::sun::star::lang::XServiceInfo interface, we have to distinguish both
694 // types via the existence of special properties
695 Reference< ::com::sun::star::beans::XPropertySet > xProps(xSet, UNO_QUERY);
696 if (xProps.is())
698 Reference< ::com::sun::star::beans::XPropertySetInfo > xPropsInfo = xProps->getPropertySetInfo();
699 if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(FM_PROP_FORMATSSUPPLIER))
700 nColType = TYPE_FORMATTEDFIELD;
704 pControlMenu->EnableItem(SID_FM_EDIT + nChangeTypeOffset, bDesignMode && (nColType != TYPE_TEXTFIELD));
705 pControlMenu->EnableItem(SID_FM_COMBOBOX + nChangeTypeOffset, bDesignMode && (nColType != TYPE_COMBOBOX));
706 pControlMenu->EnableItem(SID_FM_LISTBOX + nChangeTypeOffset, bDesignMode && (nColType != TYPE_LISTBOX));
707 pControlMenu->EnableItem(SID_FM_CHECKBOX + nChangeTypeOffset, bDesignMode && (nColType != TYPE_CHECKBOX));
708 pControlMenu->EnableItem(SID_FM_DATEFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_DATEFIELD));
709 pControlMenu->EnableItem(SID_FM_NUMERICFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_NUMERICFIELD));
710 pControlMenu->EnableItem(SID_FM_TIMEFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_TIMEFIELD));
711 pControlMenu->EnableItem(SID_FM_CURRENCYFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_CURRENCYFIELD));
712 pControlMenu->EnableItem(SID_FM_PATTERNFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_PATTERNFIELD));
713 pControlMenu->EnableItem(SID_FM_FORMATTEDFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_FORMATTEDFIELD));
714 rMenu.SetPopupMenu(SID_FM_CHANGECOL, pControlMenu);
717 rMenu.EnableItem(SID_FM_INSERTCOL, bDesignMode && xCols.is());
718 rMenu.EnableItem(SID_FM_DELETECOL, bDesignMode && bMarked && xCols.is());
719 rMenu.EnableItem(SID_FM_CHANGECOL, bDesignMode && bMarked && xCols.is());
720 rMenu.EnableItem(SID_FM_SHOW_PROPERTY_BROWSER, bDesignMode && bMarked && xCols.is());
722 PopupMenu* pShowColsMenu = rMenu.GetPopupMenu(SID_FM_SHOWCOLS);
723 sal_uInt16 nHiddenCols = 0;
724 if (pShowColsMenu)
726 if (xCols.is())
728 // check for hidden cols
729 Reference< ::com::sun::star::beans::XPropertySet > xCurCol;
730 Any aHidden,aName;
731 for (sal_uInt16 i=0; i<xCols->getCount(); ++i)
733 ::cppu::extractInterface(xCurCol, xCols->getByIndex(i));
734 DBG_ASSERT(xCurCol.is(), "FmGridHeader::PreExecuteColumnContextMenu : the Peer has invalid columns !");
735 aHidden = xCurCol->getPropertyValue(FM_PROP_HIDDEN);
736 DBG_ASSERT(aHidden.getValueType().getTypeClass() == TypeClass_BOOLEAN,
737 "FmGridHeader::PreExecuteColumnContextMenu : the property 'hidden' should be boolean !");
738 if (::comphelper::getBOOL(aHidden))
740 // put the column name into the 'show col' menu
741 if (nHiddenCols < 16)
742 { // (only the first 16 items to keep the menu rather small)
743 aName = xCurCol->getPropertyValue(FM_PROP_LABEL);
744 pShowColsMenu->InsertItem(nHiddenCols + 1, ::comphelper::getString(aName),
745 0, OString(), nHiddenCols);
746 // the ID is arbitrary, but should be unique within the whole menu
748 ++nHiddenCols;
752 pShowColsMenu->EnableItem(SID_FM_SHOWCOLS_MORE, xCols.is() && (nHiddenCols > 16));
753 pShowColsMenu->EnableItem(SID_FM_SHOWALLCOLS, xCols.is() && (nHiddenCols > 0));
756 // allow the 'hide column' item ?
757 sal_Bool bAllowHide = bMarked; // a column is marked
758 bAllowHide = bAllowHide || (!bDesignMode && (nPos != (sal_uInt16)-1)); // OR we are in alive mode and have hit a column
759 bAllowHide = bAllowHide && xCols.is(); // AND we have a column container
760 bAllowHide = bAllowHide && (xCols->getCount()-nHiddenCols > 1); // AND there are at least two visible columns
761 rMenu.EnableItem(SID_FM_HIDECOL, bAllowHide);
763 sal_Bool bChecked = sal_False;
764 if (bMarked)
767 SfxViewFrame* pCurrentFrame = SfxViewFrame::Current();
768 SfxItemState eState = SFX_ITEM_UNKNOWN;
769 // ask the bindings of the current view frame (which should be the one we're residing in) for the state
770 if (pCurrentFrame)
772 SfxPoolItem* pItem = NULL;
773 eState = pCurrentFrame->GetBindings().QueryState(SID_FM_CTL_PROPERTIES, pItem);
775 if (eState >= SFX_ITEM_AVAILABLE && pItem )
777 bChecked = pItem->ISA(SfxBoolItem) && ((SfxBoolItem*)pItem)->GetValue();
778 rMenu.CheckItem(SID_FM_SHOW_PROPERTY_BROWSER,bChecked);
780 delete pItem;
785 enum InspectorAction { eOpenInspector, eCloseInspector, eUpdateInspector, eNone };
787 //------------------------------------------------------------------------------
788 void FmGridHeader::PostExecuteColumnContextMenu(sal_uInt16 nColId, const PopupMenu& rMenu, sal_uInt16 nExecutionResult)
790 Reference< ::com::sun::star::container::XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
791 sal_uInt16 nPos = GetModelColumnPos(nColId);
793 // remove and delet the menu we inserted in PreExecuteColumnContextMenu
794 PopupMenu* pControlMenu = rMenu.GetPopupMenu(SID_FM_CHANGECOL);
795 delete pControlMenu;
797 OUString aFieldType;
798 sal_Bool bReplace = sal_False;
799 InspectorAction eInspectorAction = eNone;
800 Reference< XPropertySet > xColumnToInspect;
801 switch (nExecutionResult)
803 case SID_FM_DELETECOL:
805 Reference< XInterface > xCol;
806 ::cppu::extractInterface(xCol, xCols->getByIndex(nPos));
807 xCols->removeByIndex(nPos);
808 ::comphelper::disposeComponent(xCol);
809 } break;
810 case SID_FM_SHOW_PROPERTY_BROWSER:
811 eInspectorAction = rMenu.IsItemChecked( SID_FM_SHOW_PROPERTY_BROWSER ) ? eOpenInspector : eCloseInspector;
812 xColumnToInspect.set( xCols->getByIndex( nPos ), UNO_QUERY );
813 break;
814 case SID_FM_EDIT + nChangeTypeOffset:
815 bReplace = sal_True;
816 case SID_FM_EDIT:
817 aFieldType = FM_COL_TEXTFIELD;
818 break;
819 case SID_FM_COMBOBOX + nChangeTypeOffset:
820 bReplace = sal_True;
821 case SID_FM_COMBOBOX:
822 aFieldType = FM_COL_COMBOBOX;
823 break;
824 case SID_FM_LISTBOX + nChangeTypeOffset:
825 bReplace = sal_True;
826 case SID_FM_LISTBOX:
827 aFieldType = FM_COL_LISTBOX;
828 break;
829 case SID_FM_CHECKBOX + nChangeTypeOffset:
830 bReplace = sal_True;
831 case SID_FM_CHECKBOX:
832 aFieldType = FM_COL_CHECKBOX;
833 break;
834 case SID_FM_DATEFIELD + nChangeTypeOffset:
835 bReplace = sal_True;
836 case SID_FM_DATEFIELD:
837 aFieldType = FM_COL_DATEFIELD;
838 break;
839 case SID_FM_TIMEFIELD + nChangeTypeOffset:
840 bReplace = sal_True;
841 case SID_FM_TIMEFIELD:
842 aFieldType = FM_COL_TIMEFIELD;
843 break;
844 case SID_FM_NUMERICFIELD + nChangeTypeOffset:
845 bReplace = sal_True;
846 case SID_FM_NUMERICFIELD:
847 aFieldType = FM_COL_NUMERICFIELD;
848 break;
849 case SID_FM_CURRENCYFIELD + nChangeTypeOffset:
850 bReplace = sal_True;
851 case SID_FM_CURRENCYFIELD:
852 aFieldType = FM_COL_CURRENCYFIELD;
853 break;
854 case SID_FM_PATTERNFIELD + nChangeTypeOffset:
855 bReplace = sal_True;
856 case SID_FM_PATTERNFIELD:
857 aFieldType = FM_COL_PATTERNFIELD;
858 break;
859 case SID_FM_FORMATTEDFIELD + nChangeTypeOffset:
860 bReplace = sal_True;
861 case SID_FM_FORMATTEDFIELD:
862 aFieldType = FM_COL_FORMATTEDFIELD;
863 break;
864 case SID_FM_HIDECOL:
866 Reference< ::com::sun::star::beans::XPropertySet > xCurCol;
867 ::cppu::extractInterface(xCurCol, xCols->getByIndex(nPos));
868 xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny((sal_Bool)sal_True));
870 break;
871 case SID_FM_SHOWCOLS_MORE:
873 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
874 if(pFact)
876 AbstractFmShowColsDialog* pDlg = pFact->CreateFmShowColsDialog(NULL);
877 DBG_ASSERT(pDlg, "Dialogdiet fail!");
878 pDlg->SetColumns(xCols);
879 pDlg->Execute();
880 delete pDlg;
884 break;
885 case SID_FM_SHOWALLCOLS:
887 // just iterate through all the cols ...
888 Reference< ::com::sun::star::beans::XPropertySet > xCurCol;
889 for (sal_uInt16 i=0; i<xCols->getCount(); ++i)
891 ::cppu::extractInterface(xCurCol, xCols->getByIndex(i));
892 xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny((sal_Bool)sal_False));
894 // TODO : there must be a more clever way to do this ....
895 // with the above the view is updated after every single model update ...
897 break;
898 default:
899 if (nExecutionResult>0 && nExecutionResult<=16)
900 { // it was a "show column/<colname>" command (there are at most 16 such items)
901 // search the nExecutionResult'th hidden col
902 Reference< ::com::sun::star::beans::XPropertySet > xCurCol;
903 for (sal_uInt16 i=0; i<xCols->getCount() && nExecutionResult; ++i)
905 ::cppu::extractInterface(xCurCol, xCols->getByIndex(i));
906 Any aHidden = xCurCol->getPropertyValue(FM_PROP_HIDDEN);
907 if (::comphelper::getBOOL(aHidden))
908 if (!--nExecutionResult)
910 xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny((sal_Bool)sal_False));
911 break;
915 break;
918 if ( !aFieldType.isEmpty() )
922 Reference< XGridColumnFactory > xFactory( xCols, UNO_QUERY_THROW );
923 Reference< XPropertySet > xNewCol( xFactory->createColumn( aFieldType ), UNO_SET_THROW );
925 if ( bReplace )
927 // ein paar Properties hinueberretten
928 Reference< XPropertySet > xReplaced( xCols->getByIndex( nPos ), UNO_QUERY );
930 OStaticDataAccessTools().TransferFormComponentProperties(
931 xReplaced, xNewCol, Application::GetSettings().GetUILanguageTag().getLocale() );
933 xCols->replaceByIndex( nPos, makeAny( xNewCol ) );
934 ::comphelper::disposeComponent( xReplaced );
936 eInspectorAction = eUpdateInspector;
937 xColumnToInspect = xNewCol;
939 else
941 FormControlFactory factory( ::comphelper::getProcessServiceFactory() );
943 OUString sLabel = factory.getDefaultUniqueName_ByComponentType(
944 Reference< XNameAccess >( xCols, UNO_QUERY_THROW ), xNewCol );
945 xNewCol->setPropertyValue( FM_PROP_LABEL, makeAny( sLabel ) );
946 xNewCol->setPropertyValue( FM_PROP_NAME, makeAny( sLabel ) );
948 factory.initializeControlModel( DocumentClassification::classifyHostDocument( xCols ), xNewCol );
950 xCols->insertByIndex( nPos, makeAny( xNewCol ) );
953 catch( const Exception& )
955 DBG_UNHANDLED_EXCEPTION();
959 SfxViewFrame* pCurrentFrame = SfxViewFrame::Current();
960 OSL_ENSURE( pCurrentFrame, "FmGridHeader::PostExecuteColumnContextMenu: no view frame -> no bindings -> no property browser!" );
961 if ( pCurrentFrame )
963 if ( eInspectorAction == eUpdateInspector )
965 if ( !pCurrentFrame->HasChildWindow( SID_FM_SHOW_PROPERTIES ) )
966 eInspectorAction = eNone;
969 if ( eInspectorAction != eNone )
971 FmInterfaceItem aIFaceItem( SID_FM_SHOW_PROPERTY_BROWSER, xColumnToInspect );
972 SfxBoolItem aShowItem( SID_FM_SHOW_PROPERTIES, eInspectorAction == eCloseInspector ? sal_False : sal_True );
974 pCurrentFrame->GetBindings().GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SFX_CALLMODE_ASYNCHRON,
975 &aIFaceItem, &aShowItem, 0L );
980 //------------------------------------------------------------------------------
981 void FmGridHeader::triggerColumnContextMenu( const ::Point& _rPreferredPos )
983 // the affected col
984 sal_uInt16 nColId = GetItemId( _rPreferredPos );
986 // the menu
987 PopupMenu aContextMenu( SVX_RES( RID_SVXMNU_COLS ) );
989 // let derivees modify the menu
990 PreExecuteColumnContextMenu( nColId, aContextMenu );
991 aContextMenu.RemoveDisabledEntries( sal_True, sal_True );
993 // execute the menu
994 sal_uInt16 nResult = aContextMenu.Execute( this, _rPreferredPos );
996 // let derivees handle the result
997 PostExecuteColumnContextMenu( nColId, aContextMenu, nResult );
1000 //------------------------------------------------------------------------------
1001 void FmGridHeader::Command(const CommandEvent& rEvt)
1003 switch (rEvt.GetCommand())
1005 case COMMAND_CONTEXTMENU:
1007 if (!rEvt.IsMouseEvent())
1008 return;
1010 triggerColumnContextMenu( rEvt.GetMousePosPixel() );
1012 break;
1013 default:
1014 EditBrowserHeader::Command(rEvt);
1018 //------------------------------------------------------------------------------
1019 FmGridControl::FmGridControl(
1020 const Reference< ::com::sun::star::uno::XComponentContext >& _rxContext,
1021 Window* pParent,
1022 FmXGridPeer* _pPeer,
1023 WinBits nBits)
1024 :DbGridControl(_rxContext, pParent, nBits)
1025 ,m_pPeer(_pPeer)
1026 ,m_nCurrentSelectedColumn(-1)
1027 ,m_nMarkedColumnId(BROWSER_INVALIDID)
1028 ,m_bSelecting(sal_False)
1029 ,m_bInColumnMove(sal_False)
1031 EnableInteractiveRowHeight( );
1034 //------------------------------------------------------------------------------
1035 void FmGridControl::Command(const CommandEvent& _rEvt)
1037 if ( COMMAND_CONTEXTMENU == _rEvt.GetCommand() )
1039 FmGridHeader* pMyHeader = static_cast< FmGridHeader* >( GetHeaderBar() );
1040 if ( pMyHeader && !_rEvt.IsMouseEvent() )
1041 { // context menu requested by keyboard
1042 if ( 1 == GetSelectColumnCount() || IsDesignMode() )
1044 sal_uInt16 nSelId = GetColumnId(
1045 sal::static_int_cast< sal_uInt16 >( FirstSelectedColumn() ) );
1046 ::Rectangle aColRect( GetFieldRectPixel( 0, nSelId, sal_False ) );
1048 Point aRelativePos( pMyHeader->ScreenToOutputPixel( OutputToScreenPixel( aColRect.TopCenter() ) ) );
1049 pMyHeader->triggerColumnContextMenu( aRelativePos, FmGridHeader::AccessControl() );
1051 // handled
1052 return;
1057 DbGridControl::Command( _rEvt );
1060 // ::com::sun::star::beans::XPropertyChangeListener
1061 //------------------------------------------------------------------------------
1062 void FmGridControl::propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& evt)
1064 if (evt.PropertyName == FM_PROP_ROWCOUNT)
1066 // if we're not in the main thread call AdjustRows asynchronously
1067 implAdjustInSolarThread(sal_True);
1068 return;
1071 const DbGridRowRef& xRow = GetCurrentRow();
1072 // waehrend Positionierung wird kein abgleich der Properties vorgenommen
1073 Reference<XPropertySet> xSet(evt.Source,UNO_QUERY);
1074 if (xRow.Is() && (::cppu::any2bool(xSet->getPropertyValue(FM_PROP_ISNEW))|| CompareBookmark(getDataSource()->getBookmark(), xRow->GetBookmark())))
1076 if (evt.PropertyName == FM_PROP_ISMODIFIED)
1078 // modified or clean ?
1079 GridRowStatus eStatus = ::comphelper::getBOOL(evt.NewValue) ? GRS_MODIFIED : GRS_CLEAN;
1080 if (eStatus != xRow->GetStatus())
1082 xRow->SetStatus(eStatus);
1083 SolarMutexGuard aGuard;
1084 RowModified(GetCurrentPos());
1090 //------------------------------------------------------------------------------
1091 void FmGridControl::SetDesignMode(sal_Bool bMode)
1093 sal_Bool bOldMode = IsDesignMode();
1094 DbGridControl::SetDesignMode(bMode);
1095 if (bOldMode != bMode)
1097 if (!bMode)
1099 // selection aufheben
1100 markColumn(USHRT_MAX);
1102 else
1104 Reference< ::com::sun::star::container::XIndexContainer > xColumns(GetPeer()->getColumns());
1105 Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
1106 if (xSelSupplier.is())
1108 Any aSelection = xSelSupplier->getSelection();
1109 Reference< ::com::sun::star::beans::XPropertySet > xColumn;
1110 if (aSelection.getValueType().getTypeClass() == TypeClass_INTERFACE)
1111 ::cppu::extractInterface(xColumn, aSelection);
1112 Reference< XInterface > xCurrent;
1113 for (sal_uInt16 i=0; i<xColumns->getCount(); ++i)
1115 ::cppu::extractInterface(xCurrent, xColumns->getByIndex(i));
1116 if (xCurrent == xColumn)
1118 markColumn(GetColumnIdFromModelPos(i));
1119 break;
1127 //------------------------------------------------------------------------------
1128 void FmGridControl::DeleteSelectedRows()
1130 if (!m_pSeekCursor)
1131 return;
1133 // how many rows are selected?
1134 sal_Int32 nSelectedRows = GetSelectRowCount();
1136 // the current line should be deleted but it is currently in edit mode
1137 if ( IsCurrentAppending() )
1138 return;
1139 // is the insert row selected
1140 if (GetEmptyRow().Is() && IsRowSelected(GetRowCount() - 1))
1141 nSelectedRows -= 1;
1143 // nothing to do
1144 if (nSelectedRows <= 0)
1145 return;
1147 // try to confirm the delete
1148 Reference< ::com::sun::star::frame::XDispatchProvider > xDispatcher = (::com::sun::star::frame::XDispatchProvider*)GetPeer();
1149 if (xDispatcher.is())
1151 ::com::sun::star::util::URL aUrl;
1152 aUrl.Complete = FMURL_CONFIRM_DELETION;
1153 // #100312# ------------
1154 Reference< ::com::sun::star::util::XURLTransformer > xTransformer(
1155 ::com::sun::star::util::URLTransformer::create(::comphelper::getProcessComponentContext()) );
1156 xTransformer->parseStrict( aUrl );
1158 Reference< ::com::sun::star::frame::XDispatch > xDispatch = xDispatcher->queryDispatch(aUrl, OUString(), 0);
1159 Reference< ::com::sun::star::form::XConfirmDeleteListener > xConfirm(xDispatch, UNO_QUERY);
1160 if (xConfirm.is())
1162 ::com::sun::star::sdb::RowChangeEvent aEvent;
1163 aEvent.Source = (Reference< XInterface > )(*getDataSource());
1164 aEvent.Rows = nSelectedRows;
1165 aEvent.Action = ::com::sun::star::sdb::RowChangeAction::DELETE;
1166 if (!xConfirm->confirmDelete(aEvent))
1167 return;
1171 const MultiSelection* pRowSelection = GetSelection();
1172 if ( pRowSelection && pRowSelection->IsAllSelected() )
1174 BeginCursorAction();
1175 CursorWrapper* pCursor = getDataSource();
1176 Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*pCursor, UNO_QUERY);
1179 pCursor->beforeFirst();
1180 while( pCursor->next() )
1181 xUpdateCursor->deleteRow();
1183 SetUpdateMode(sal_False);
1184 SetNoSelection();
1186 xUpdateCursor->moveToInsertRow();
1188 catch(const Exception&)
1190 OSL_FAIL("Exception caught while deleting rows!");
1192 // An den DatenCursor anpassen
1193 AdjustDataSource(sal_True);
1194 EndCursorAction();
1195 SetUpdateMode(sal_True);
1197 else
1199 Reference< ::com::sun::star::sdbcx::XDeleteRows > xDeleteThem((Reference< XInterface >)*getDataSource(), UNO_QUERY);
1201 // colect the bookmarks of the selected rows
1202 Sequence < Any> aBookmarks = getSelectionBookmarks();
1204 // determine the next row to position after deletion
1205 Any aBookmark;
1206 sal_Bool bNewPos = sal_False;
1207 // if the current row isn't selected we take the row as row after deletion
1208 OSL_ENSURE( GetCurrentRow().Is(), "FmGridControl::DeleteSelectedRows: no current row here?" );
1209 // crash reports suggest it can happen we don't have a current row - how?
1210 // #154303# / 2008-04-23 / frank.schoenheit@sun.com
1211 if ( !IsRowSelected( GetCurrentPos() ) && !IsCurrentAppending() && GetCurrentRow().Is() )
1213 aBookmark = GetCurrentRow()->GetBookmark();
1214 bNewPos = sal_True;
1216 else
1218 // we look for the first row after the selected block for selection
1219 long nIdx = LastSelectedRow() + 1;
1220 if (nIdx < GetRowCount() - 1)
1222 // there is a next row to position on
1223 if (SeekCursor(nIdx))
1225 GetSeekRow()->SetState(m_pSeekCursor, sal_True);
1227 bNewPos = sal_True;
1228 // if it's not the row for inserting we keep the bookmark
1229 if (!IsInsertionRow(nIdx))
1230 aBookmark = m_pSeekCursor->getBookmark();
1233 else
1235 // we look for the first row before the selected block for selection after deletion
1236 nIdx = FirstSelectedRow() - 1;
1237 if (nIdx >= 0 && SeekCursor(nIdx))
1239 GetSeekRow()->SetState(m_pSeekCursor, sal_True);
1241 bNewPos = sal_True;
1242 aBookmark = m_pSeekCursor->getBookmark();
1247 // Sind alle Zeilen Selectiert
1248 // Zweite bedingung falls keine einguegeZeile existiert
1249 sal_Bool bAllSelected = GetTotalCount() == nSelectedRows || GetRowCount() == nSelectedRows;
1251 BeginCursorAction();
1253 // now delete the row
1254 Sequence <sal_Int32> aDeletedRows;
1255 SetUpdateMode( sal_False );
1258 aDeletedRows = xDeleteThem->deleteRows(aBookmarks);
1260 catch(SQLException&)
1263 SetUpdateMode( sal_True );
1265 // how many rows are deleted?
1266 sal_Int32 nDeletedRows = 0;
1267 const sal_Int32* pSuccess = aDeletedRows.getConstArray();
1268 for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++)
1270 if (pSuccess[i])
1271 ++nDeletedRows;
1274 // sind Zeilen geloescht worden?
1275 if (nDeletedRows)
1277 SetUpdateMode(sal_False);
1278 SetNoSelection();
1281 // did we delete all the rows than try to move to the next possible row
1282 if (nDeletedRows == aDeletedRows.getLength())
1284 // there exists a new position to move on
1285 if (bNewPos)
1287 if (aBookmark.hasValue())
1288 getDataSource()->moveToBookmark(aBookmark);
1289 // no valid bookmark so move to the insert row
1290 else
1292 Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY);
1293 xUpdateCursor->moveToInsertRow();
1296 else
1298 Reference< ::com::sun::star::beans::XPropertySet > xSet((Reference< XInterface >)*m_pDataCursor, UNO_QUERY);
1300 sal_Int32 nRecordCount(0);
1301 xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
1302 if ( m_pDataCursor->rowDeleted() )
1303 --nRecordCount;
1305 // there are no rows left and we have an insert row
1306 if (!nRecordCount && GetEmptyRow().Is())
1308 Reference< XResultSetUpdate > xUpdateCursor((Reference< XInterface >)*m_pDataCursor, UNO_QUERY);
1309 xUpdateCursor->moveToInsertRow();
1311 else if (nRecordCount)
1312 // move to the first row
1313 getDataSource()->first();
1316 // not all the rows where deleted, so move to the first row which remained in the resultset
1317 else
1319 for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++)
1321 if (!pSuccess[i])
1323 getDataSource()->moveToBookmark(aBookmarks.getConstArray()[i]);
1324 break;
1329 catch(const Exception&)
1333 // positioning went wrong so try to move to the first row
1334 getDataSource()->first();
1336 catch(const Exception&)
1341 // An den DatenCursor anpassen
1342 AdjustDataSource(sal_True);
1344 // es konnten nicht alle Zeilen geloescht werden
1345 // da nie nicht geloeschten wieder selektieren
1346 if (nDeletedRows < nSelectedRows)
1348 // waren alle selektiert
1349 if (bAllSelected)
1351 SelectAll();
1352 if (IsInsertionRow(GetRowCount() - 1)) // einfuegeZeile nicht
1353 SelectRow(GetRowCount() - 1, sal_False);
1355 else
1357 // select the remaining rows
1358 for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++)
1362 if (!pSuccess[i])
1364 m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
1365 SetSeekPos(m_pSeekCursor->getRow() - 1);
1366 SelectRow(GetSeekPos());
1369 catch(const Exception&)
1371 // keep the seekpos in all cases
1372 SetSeekPos(m_pSeekCursor->getRow() - 1);
1378 EndCursorAction();
1379 SetUpdateMode(sal_True);
1381 else // Zeile konnte nicht geloescht werden
1383 EndCursorAction();
1386 // currentrow is the insert row?
1387 if (!IsCurrentAppending())
1388 getDataSource()->refreshRow();
1390 catch(const Exception&)
1396 // if there is no selection anymore we can start editing
1397 if (!GetSelectRowCount())
1398 ActivateCell();
1402 // XCurrentRecordListener
1403 //------------------------------------------------------------------------------
1404 void FmGridControl::positioned(const ::com::sun::star::lang::EventObject& /*rEvent*/)
1406 SAL_INFO("svx.fmcmop", "FmGridControl::positioned");
1407 // position on the data source (force it to be done in the main thread)
1408 implAdjustInSolarThread(sal_False);
1411 //------------------------------------------------------------------------------
1412 sal_Bool FmGridControl::commit()
1414 // Commit nur ausfuehren, wenn nicht bereits ein Update vom ::com::sun::star::form::component::GridControl ausgefuehrt
1415 // wird
1416 if (!IsUpdating())
1418 if (Controller().Is() && Controller()->IsModified())
1420 if (!SaveModified())
1421 return sal_False;
1424 return sal_True;
1427 //------------------------------------------------------------------------------
1428 void FmGridControl::inserted(const ::com::sun::star::lang::EventObject& /*rEvent*/)
1430 const DbGridRowRef& xRow = GetCurrentRow();
1431 if (!xRow.Is())
1432 return;
1434 // Zeile ist eingefuegt worden, dann den status und mode zuruecksetzen
1435 xRow->SetState(m_pDataCursor, sal_False);
1436 xRow->SetNew(sal_False);
1440 //------------------------------------------------------------------------------
1441 BrowserHeader* FmGridControl::imp_CreateHeaderBar(BrowseBox* pParent)
1443 DBG_ASSERT( pParent == this, "FmGridControl::imp_CreateHeaderBar: parent?" );
1444 return new FmGridHeader( pParent );
1447 //------------------------------------------------------------------------------
1448 void FmGridControl::markColumn(sal_uInt16 nId)
1450 if (GetHeaderBar() && m_nMarkedColumnId != nId)
1452 // deselektieren
1453 if (m_nMarkedColumnId != BROWSER_INVALIDID)
1455 HeaderBarItemBits aBits = GetHeaderBar()->GetItemBits(m_nMarkedColumnId) & ~HIB_FLAT;
1456 GetHeaderBar()->SetItemBits(m_nMarkedColumnId, aBits);
1460 if (nId != BROWSER_INVALIDID)
1462 HeaderBarItemBits aBits = GetHeaderBar()->GetItemBits(nId) | HIB_FLAT;
1463 GetHeaderBar()->SetItemBits(nId, aBits);
1465 m_nMarkedColumnId = nId;
1469 //------------------------------------------------------------------------------
1470 sal_Bool FmGridControl::isColumnMarked(sal_uInt16 nId) const
1472 return m_nMarkedColumnId == nId;
1475 //------------------------------------------------------------------------------
1476 long FmGridControl::QueryMinimumRowHeight()
1478 long nMinimalLogicHeight = 20; // 0.2 cm
1479 long nMinimalPixelHeight = LogicToPixel( Point( 0, nMinimalLogicHeight ), MAP_10TH_MM ).Y();
1480 return CalcZoom( nMinimalPixelHeight );
1483 //------------------------------------------------------------------------------
1484 void FmGridControl::RowHeightChanged()
1486 DbGridControl::RowHeightChanged();
1488 Reference< XPropertySet > xModel( GetPeer()->getColumns(), UNO_QUERY );
1489 DBG_ASSERT( xModel.is(), "FmGridControl::RowHeightChanged: no model!" );
1490 if ( xModel.is() )
1494 sal_Int32 nUnzoomedPixelHeight = CalcReverseZoom( GetDataRowHeight() );
1495 Any aProperty = makeAny( (sal_Int32)PixelToLogic( Point( 0, nUnzoomedPixelHeight ), MAP_10TH_MM ).Y() );
1496 xModel->setPropertyValue( FM_PROP_ROWHEIGHT, aProperty );
1498 catch( const Exception& )
1500 OSL_FAIL( "FmGridControl::RowHeightChanged: caught an exception!" );
1505 //------------------------------------------------------------------------------
1506 void FmGridControl::ColumnResized(sal_uInt16 nId)
1508 DbGridControl::ColumnResized(nId);
1510 // Wert ans model uebergeben
1511 DbGridColumn* pCol = DbGridControl::GetColumns().at( GetModelColumnPos(nId) );
1512 Reference< ::com::sun::star::beans::XPropertySet > xColModel(pCol->getModel());
1513 if (xColModel.is())
1515 Any aWidth;
1516 sal_Int32 nColumnWidth = GetColumnWidth(nId);
1517 nColumnWidth = CalcReverseZoom(nColumnWidth);
1518 // Umrechnen in 10THMM
1519 aWidth <<= (sal_Int32)PixelToLogic(Point(nColumnWidth,0),MAP_10TH_MM).X();
1520 xColModel->setPropertyValue(FM_PROP_WIDTH, aWidth);
1524 //------------------------------------------------------------------------------
1525 void FmGridControl::CellModified()
1527 DbGridControl::CellModified();
1528 GetPeer()->CellModified();
1531 //------------------------------------------------------------------------------
1532 void FmGridControl::BeginCursorAction()
1534 DbGridControl::BeginCursorAction();
1535 m_pPeer->stopCursorListening();
1538 //------------------------------------------------------------------------------
1539 void FmGridControl::EndCursorAction()
1541 m_pPeer->startCursorListening();
1542 DbGridControl::EndCursorAction();
1545 //------------------------------------------------------------------------------
1546 void FmGridControl::ColumnMoved(sal_uInt16 nId)
1548 m_bInColumnMove = sal_True;
1550 DbGridControl::ColumnMoved(nId);
1551 Reference< ::com::sun::star::container::XIndexContainer > xColumns(GetPeer()->getColumns());
1553 if (xColumns.is())
1555 // suchen der Spalte und verschieben im Model
1556 // ColumnPos holen
1557 DbGridColumn* pCol = DbGridControl::GetColumns().at( GetModelColumnPos(nId) );
1558 Reference< ::com::sun::star::beans::XPropertySet > xCol;
1560 // Einfuegen muß sich an den Column Positionen orientieren
1561 sal_Int32 i;
1562 Reference< XInterface > xCurrent;
1563 for (i = 0; !xCol.is() && i < xColumns->getCount(); i++)
1565 ::cppu::extractInterface(xCurrent, xColumns->getByIndex(i));
1566 if (xCurrent == pCol->getModel())
1568 xCol = pCol->getModel();
1569 break;
1573 DBG_ASSERT(i < xColumns->getCount(), "Falscher ::com::sun::star::sdbcx::Index");
1574 xColumns->removeByIndex(i);
1575 Any aElement;
1576 aElement <<= xCol;
1577 xColumns->insertByIndex(GetModelColumnPos(nId), aElement);
1578 pCol->setModel(xCol);
1579 // if the column which is shown here is selected ...
1580 if ( isColumnSelected(nId,pCol) )
1581 markColumn(nId); // ... -> mark it
1584 m_bInColumnMove = sal_False;
1587 //------------------------------------------------------------------------------
1588 void FmGridControl::InitColumnsByModels(const Reference< ::com::sun::star::container::XIndexContainer >& xColumns)
1590 // Spalten wieder neu setzen
1591 // wenn es nur eine HandleColumn gibt, dann nicht
1592 if (GetModelColCount())
1594 RemoveColumns();
1595 InsertHandleColumn();
1598 if (!xColumns.is())
1599 return;
1601 SetUpdateMode(sal_False);
1603 // Einfuegen mu� sich an den Column Positionen orientieren
1604 sal_Int32 i;
1605 Any aWidth;
1606 for (i = 0; i < xColumns->getCount(); ++i)
1608 Reference< ::com::sun::star::beans::XPropertySet > xCol;
1609 ::cppu::extractInterface(xCol, xColumns->getByIndex(i));
1611 OUString aName(
1612 comphelper::getString(xCol->getPropertyValue(FM_PROP_LABEL)));
1614 aWidth = xCol->getPropertyValue(FM_PROP_WIDTH);
1615 sal_Int32 nWidth = 0;
1616 if (aWidth >>= nWidth)
1617 nWidth = LogicToPixel(Point(nWidth,0),MAP_10TH_MM).X();
1619 AppendColumn(aName, (sal_uInt16)nWidth);
1620 DbGridColumn* pCol = DbGridControl::GetColumns().at( i );
1621 pCol->setModel(xCol);
1624 // und jetzt noch die hidden columns rausnehmen
1625 // (wir haben das nicht gleich in der oberen Schleife gemacht, da wir dann Probleme mit den
1626 // IDs der Spalten bekommen haetten : AppendColumn vergibt die automatisch, die Spalte _nach_
1627 // einer versteckten braucht aber eine um eine erhoehte ID ....
1628 Any aHidden;
1629 for (i = 0; i < xColumns->getCount(); ++i)
1631 Reference< ::com::sun::star::beans::XPropertySet > xCol;
1632 ::cppu::extractInterface(xCol, xColumns->getByIndex(i));
1633 aHidden = xCol->getPropertyValue(FM_PROP_HIDDEN);
1634 if (::comphelper::getBOOL(aHidden))
1635 HideColumn(GetColumnIdFromModelPos((sal_uInt16)i));
1638 SetUpdateMode(sal_True);
1641 //------------------------------------------------------------------------------
1642 void FmGridControl::InitColumnByField(
1643 DbGridColumn* _pColumn, const Reference< XPropertySet >& _rxColumnModel,
1644 const Reference< XNameAccess >& _rxFieldsByNames, const Reference< XIndexAccess >& _rxFieldsByIndex )
1646 DBG_ASSERT( _rxFieldsByNames == _rxFieldsByIndex, "FmGridControl::InitColumnByField: invalid container interfaces!" );
1648 // lookup the column which belongs to the control source
1649 OUString sFieldName;
1650 _rxColumnModel->getPropertyValue( FM_PROP_CONTROLSOURCE ) >>= sFieldName;
1651 Reference< XPropertySet > xField;
1652 _rxColumnModel->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField;
1655 if ( !xField.is() && /*sFieldName.getLength() && */_rxFieldsByNames->hasByName( sFieldName ) ) // #i93452# do not check for name length
1656 _rxFieldsByNames->getByName( sFieldName ) >>= xField;
1658 // determine the position of this column
1659 sal_Int32 nFieldPos = -1;
1660 if ( xField.is() )
1662 Reference< XPropertySet > xCheck;
1663 sal_Int32 nFieldCount = _rxFieldsByIndex->getCount();
1664 for ( sal_Int32 i = 0; i < nFieldCount; ++i)
1666 _rxFieldsByIndex->getByIndex( i ) >>= xCheck;
1667 if ( xField.get() == xCheck.get() )
1669 nFieldPos = i;
1670 break;
1675 if ( xField.is() && ( nFieldPos >= 0 ) )
1677 // some data types are not allowed
1678 sal_Int32 nDataType = DataType::OTHER;
1679 xField->getPropertyValue( FM_PROP_FIELDTYPE ) >>= nDataType;
1681 sal_Bool bIllegalType = sal_False;
1682 switch ( nDataType )
1684 case DataType::BLOB:
1685 case DataType::LONGVARBINARY:
1686 case DataType::BINARY:
1687 case DataType::VARBINARY:
1688 case DataType::OTHER:
1689 bIllegalType = sal_True;
1690 break;
1693 if ( bIllegalType )
1695 _pColumn->SetObject( (sal_Int16)nFieldPos );
1696 return;
1700 // the control type is determined by the ColumnServiceName
1701 static OUString s_sPropColumnServiceName( "ColumnServiceName" );
1702 if ( !::comphelper::hasProperty( s_sPropColumnServiceName, _rxColumnModel ) )
1703 return;
1705 _pColumn->setModel( _rxColumnModel );
1707 OUString sColumnServiceName;
1708 _rxColumnModel->getPropertyValue( s_sPropColumnServiceName ) >>= sColumnServiceName;
1710 sal_Int32 nTypeId = getColumnTypeByModelName( sColumnServiceName );
1711 _pColumn->CreateControl( nFieldPos, xField, nTypeId );
1714 //------------------------------------------------------------------------------
1715 void FmGridControl::InitColumnsByFields(const Reference< ::com::sun::star::container::XIndexAccess >& _rxFields)
1717 if ( !_rxFields.is() )
1718 return;
1720 // Spalten initialisieren
1721 Reference< XIndexContainer > xColumns( GetPeer()->getColumns() );
1722 Reference< XNameAccess > xFieldsAsNames( _rxFields, UNO_QUERY );
1724 // Einfuegen muss sich an den Column Positionen orientieren
1725 for (sal_Int32 i = 0; i < xColumns->getCount(); i++)
1727 DbGridColumn* pCol = GetColumns().at( i );
1728 OSL_ENSURE(pCol,"No grid column!");
1729 if ( pCol )
1731 Reference< XPropertySet > xColumnModel;
1732 ::cppu::extractInterface( xColumnModel, xColumns->getByIndex( i ) );
1734 InitColumnByField( pCol, xColumnModel, xFieldsAsNames, _rxFields );
1739 //------------------------------------------------------------------------------
1740 void FmGridControl::HideColumn(sal_uInt16 nId)
1742 DbGridControl::HideColumn(nId);
1744 sal_uInt16 nPos = GetModelColumnPos(nId);
1745 if (nPos == (sal_uInt16)-1)
1746 return;
1748 DbGridColumn* pColumn = GetColumns().at( nPos );
1749 if (pColumn->IsHidden())
1750 GetPeer()->columnHidden(pColumn);
1752 if (nId == m_nMarkedColumnId)
1753 m_nMarkedColumnId = (sal_uInt16)-1;
1755 // -----------------------------------------------------------------------------
1756 sal_Bool FmGridControl::isColumnSelected(sal_uInt16 /*nId*/,DbGridColumn* _pColumn)
1758 OSL_ENSURE(_pColumn,"Column can not be null!");
1759 sal_Bool bSelected = sal_False;
1760 // if the column which is shown here is selected ...
1761 Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(GetPeer()->getColumns(), UNO_QUERY);
1762 if ( xSelSupplier.is() )
1764 Reference< ::com::sun::star::beans::XPropertySet > xColumn;
1765 xSelSupplier->getSelection() >>= xColumn;
1766 bSelected = (xColumn.get() == _pColumn->getModel().get());
1768 return bSelected;
1771 //------------------------------------------------------------------------------
1772 void FmGridControl::ShowColumn(sal_uInt16 nId)
1774 DbGridControl::ShowColumn(nId);
1776 sal_uInt16 nPos = GetModelColumnPos(nId);
1777 if (nPos == (sal_uInt16)-1)
1778 return;
1780 DbGridColumn* pColumn = GetColumns().at( nPos );
1781 if (!pColumn->IsHidden())
1782 GetPeer()->columnVisible(pColumn);
1784 // if the column which is shown here is selected ...
1785 if ( isColumnSelected(nId,pColumn) )
1786 markColumn(nId); // ... -> mark it
1789 //------------------------------------------------------------------------------
1790 sal_Bool FmGridControl::selectBookmarks(const Sequence< Any >& _rBookmarks)
1792 SolarMutexGuard aGuard;
1793 // need to lock the SolarMutex so that no paint call disturbs us ...
1795 if ( !m_pSeekCursor )
1797 OSL_FAIL( "FmGridControl::selectBookmarks: no seek cursor!" );
1798 return sal_False;
1801 const Any* pBookmark = _rBookmarks.getConstArray();
1802 const Any* pBookmarkEnd = pBookmark + _rBookmarks.getLength();
1804 SetNoSelection();
1806 sal_Bool bAllSuccessfull = sal_True;
1809 for (; pBookmark != pBookmarkEnd; ++pBookmark)
1811 // move the seek cursor to the row given
1812 if (m_pSeekCursor->moveToBookmark(*pBookmark))
1813 SelectRow( m_pSeekCursor->getRow() - 1);
1814 else
1815 bAllSuccessfull = sal_False;
1818 catch(Exception&)
1820 OSL_FAIL("FmGridControl::selectBookmarks: could not move to one of the bookmarks!");
1821 return sal_False;
1824 return bAllSuccessfull;
1827 //------------------------------------------------------------------------------
1828 Sequence< Any> FmGridControl::getSelectionBookmarks()
1830 // lock our update so no paint-triggered seeks interfere ...
1831 SetUpdateMode(sal_False);
1833 sal_Int32 nSelectedRows = GetSelectRowCount(), i = 0;
1834 Sequence< Any> aBookmarks(nSelectedRows);
1835 if ( nSelectedRows )
1837 Any* pBookmarks = (Any*)aBookmarks.getArray();
1839 // (I'm not sure if the problem isn't deeper : The szenario : a large table displayed by a grid with a
1840 // thread-safe cursor (dBase). On loading the sdb-cursor started a counting thread. While this counting progress
1841 // was running, I tried do delete 3 records from within the grid. Deletion caused a SeekCursor, which did a
1842 // m_pSeekCursor->moveRelative and a m_pSeekCursor->getPosition.
1843 // Unfortunally the first call caused a propertyChanged(RECORDCOUNT) which resulted in a repaint of the
1844 // navigation bar and the grid. The latter itself will result in SeekRow calls. So after (successfully) returning
1845 // from the moveRelative the getPosition returns an invalid value. And so the SeekCursor fails.
1846 // In the consequence ALL parts of code where two calls to the seek cursor are done, while the second call _relys_ on
1847 // the first one, should be secured against recursion, with a broad-minded interpretion of "recursion" : if any of these
1848 // code parts is executed, no other should be accessible. But this sounds very difficult to achieve ....
1849 // )
1851 // The next problem caused by the same behaviuor (SeekCursor causes a propertyChanged) : when adjusting rows we implicitly
1852 // change our selection. So a "FirstSelected(); SeekCursor(); NextSelected();" may produce unpredictable results.
1853 // That's why we _first_ collect the indicies of the selected rows and _then_ their bookmarks.
1854 long nIdx = FirstSelectedRow();
1855 while (nIdx >= 0)
1857 // (we misuse the bookmarks array for this ...)
1858 pBookmarks[i++] <<= (sal_Int32)nIdx;
1859 nIdx = NextSelectedRow();
1861 DBG_ASSERT(i == nSelectedRows, "FmGridControl::DeleteSelectedRows : could not collect the row indicies !");
1863 for (i=0; i<nSelectedRows; ++i)
1865 nIdx = ::comphelper::getINT32(pBookmarks[i]);
1866 if (IsInsertionRow(nIdx))
1868 // leerzeile nicht loeschen
1869 aBookmarks.realloc(--nSelectedRows);
1870 SelectRow(nIdx,sal_False); // selection aufheben fuer leerzeile
1871 break;
1874 // Zunaechst den DatenCursor auf den selektierten Satz pos.
1875 if (SeekCursor(nIdx))
1877 GetSeekRow()->SetState(m_pSeekCursor, sal_True);
1879 pBookmarks[i] = m_pSeekCursor->getBookmark();
1881 #ifdef DBG_UTIL
1882 else
1883 OSL_FAIL("FmGridControl::DeleteSelectedRows : a bookmark could not be determined !");
1884 #endif
1887 SetUpdateMode(sal_True);
1889 // if one of the SeekCursor-calls failed ....
1890 aBookmarks.realloc(i);
1892 // (the alternative : while collecting the bookmarks lock our propertyChanged, this should resolve both our problems.
1893 // but this would be incompatible as we need a locking flag, then ...)
1895 return aBookmarks;
1897 // -----------------------------------------------------------------------------
1898 namespace
1900 OUString getColumnPropertyFromPeer(FmXGridPeer* _pPeer,sal_Int32 _nPosition,const OUString& _sPropName)
1902 OUString sRetText;
1903 if ( _pPeer && _nPosition != -1)
1905 Reference<XIndexContainer> xIndex = _pPeer->getColumns();
1906 if ( xIndex.is() && xIndex->getCount() > _nPosition )
1908 Reference<XPropertySet> xProp;
1909 xIndex->getByIndex( _nPosition ) >>= xProp;
1910 if ( xProp.is() )
1912 try {
1913 xProp->getPropertyValue( _sPropName ) >>= sRetText;
1914 } catch (UnknownPropertyException const& e) {
1915 SAL_WARN("svx.form",
1916 "exception caught: " << e.Message);
1921 return sRetText;
1924 // Object data and state ------------------------------------------------------
1925 OUString FmGridControl::GetAccessibleObjectName( ::svt::AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const
1927 OUString sRetText;
1928 switch( _eObjType )
1930 case ::svt::BBTYPE_BROWSEBOX:
1931 if ( GetPeer() )
1933 Reference<XPropertySet> xProp(GetPeer()->getColumns(),UNO_QUERY);
1934 if ( xProp.is() )
1935 xProp->getPropertyValue(FM_PROP_NAME) >>= sRetText;
1937 break;
1938 case ::svt::BBTYPE_COLUMNHEADERCELL:
1939 sRetText = getColumnPropertyFromPeer(
1940 GetPeer(),
1941 GetModelColumnPos(
1942 sal::static_int_cast< sal_uInt16 >(_nPosition)),
1943 FM_PROP_LABEL);
1944 break;
1945 default:
1946 sRetText = DbGridControl::GetAccessibleObjectName(_eObjType,_nPosition);
1948 return sRetText;
1950 // -----------------------------------------------------------------------------
1952 OUString FmGridControl::GetAccessibleObjectDescription( ::svt::AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const
1954 OUString sRetText;
1955 switch( _eObjType )
1957 case ::svt::BBTYPE_BROWSEBOX:
1958 if ( GetPeer() )
1960 Reference<XPropertySet> xProp(GetPeer()->getColumns(),UNO_QUERY);
1961 if ( xProp.is() )
1963 xProp->getPropertyValue(FM_PROP_HELPTEXT) >>= sRetText;
1964 if ( sRetText.isEmpty() )
1965 xProp->getPropertyValue(FM_PROP_DESCRIPTION) >>= sRetText;
1968 break;
1969 case ::svt::BBTYPE_COLUMNHEADERCELL:
1970 sRetText = getColumnPropertyFromPeer(
1971 GetPeer(),
1972 GetModelColumnPos(
1973 sal::static_int_cast< sal_uInt16 >(_nPosition)),
1974 FM_PROP_HELPTEXT);
1975 if ( sRetText.isEmpty() )
1976 sRetText = getColumnPropertyFromPeer(
1977 GetPeer(),
1978 GetModelColumnPos(
1979 sal::static_int_cast< sal_uInt16 >(_nPosition)),
1980 FM_PROP_DESCRIPTION);
1982 break;
1983 default:
1984 sRetText = DbGridControl::GetAccessibleObjectDescription(_eObjType,_nPosition);
1986 return sRetText;
1988 // -----------------------------------------------------------------------------
1989 void FmGridControl::Select()
1991 DbGridControl::Select();
1992 // ... betrifft das unsere Spalten ?
1993 const MultiSelection* pColumnSelection = GetColumnSelection();
1995 sal_uInt16 nSelectedColumn =
1996 pColumnSelection && pColumnSelection->GetSelectCount()
1997 ? sal::static_int_cast< sal_uInt16 >(
1998 ((MultiSelection*)pColumnSelection)->FirstSelected())
1999 : SAL_MAX_UINT16;
2000 // die HandleColumn wird nicht selektiert
2001 switch (nSelectedColumn)
2003 case SAL_MAX_UINT16: break; // no selection
2004 case 0 : nSelectedColumn = SAL_MAX_UINT16; break;
2005 // handle col can't be seledted
2006 default :
2007 // get the model col pos instead of the view col pos
2008 nSelectedColumn = GetModelColumnPos(GetColumnIdFromViewPos(nSelectedColumn - 1));
2009 break;
2012 if (nSelectedColumn != m_nCurrentSelectedColumn)
2014 // VOR dem Aufruf des select am SelectionSupplier !
2015 m_nCurrentSelectedColumn = nSelectedColumn;
2017 if (!m_bSelecting)
2019 m_bSelecting = sal_True;
2023 Reference< XIndexAccess > xColumns(GetPeer()->getColumns(), UNO_QUERY);
2024 Reference< XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
2025 if (xSelSupplier.is())
2027 if (nSelectedColumn != SAL_MAX_UINT16)
2029 Reference< XPropertySet > xColumn;
2030 ::cppu::extractInterface(xColumn,xColumns->getByIndex(nSelectedColumn));
2031 xSelSupplier->select(makeAny(xColumn));
2033 else
2035 xSelSupplier->select(Any());
2039 catch(Exception&)
2044 m_bSelecting = sal_False;
2048 // -----------------------------------------------------------------------------
2049 sal_Int32 FmGridControl::GetSelectedColumn() const
2051 return m_nCurrentSelectedColumn;
2053 // -----------------------------------------------------------------------------
2054 void FmGridControl::KeyInput( const KeyEvent& rKEvt )
2056 sal_Bool bDone = sal_False;
2057 const KeyCode& rKeyCode = rKEvt.GetKeyCode();
2058 if ( IsDesignMode()
2059 && !rKeyCode.IsShift()
2060 && !rKeyCode.IsMod1()
2061 && !rKeyCode.IsMod2()
2062 && GetParent() )
2064 switch ( rKeyCode.GetCode() )
2066 case KEY_ESCAPE:
2067 GetParent()->GrabFocus();
2068 bDone = sal_True;
2069 break;
2070 case KEY_DELETE:
2071 if ( GetSelectColumnCount() && GetPeer() && m_nCurrentSelectedColumn >= 0 )
2073 Reference< ::com::sun::star::container::XIndexContainer > xCols(GetPeer()->getColumns());
2074 if ( xCols.is() )
2078 if ( m_nCurrentSelectedColumn < xCols->getCount() )
2080 Reference< XInterface > xCol;
2081 xCols->getByIndex(m_nCurrentSelectedColumn) >>= xCol;
2082 xCols->removeByIndex(m_nCurrentSelectedColumn);
2083 ::comphelper::disposeComponent(xCol);
2086 catch(const Exception&)
2088 OSL_FAIL("exception occurred while deleting a column");
2092 bDone = sal_True;
2093 break;
2096 if ( !bDone )
2097 DbGridControl::KeyInput( rKEvt );
2099 // -----------------------------------------------------------------------------
2103 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */