fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / svx / source / fmcomp / fmgridcl.cxx
blob413bae057c3900d188fd2e6ba56dd046b2e236ec
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/numbers.hxx>
56 #include <comphelper/processfactory.hxx>
57 #include <comphelper/property.hxx>
58 #include <comphelper/string.hxx>
59 #include <connectivity/dbtools.hxx>
60 #include <sfx2/dispatch.hxx>
61 #include <sfx2/viewfrm.hxx>
62 #include <svl/eitem.hxx>
63 #include <svtools/fmtfield.hxx>
64 #include <svl/numuno.hxx>
65 #include <tools/multisel.hxx>
66 #include <tools/diagnose_ex.h>
67 #include <vcl/help.hxx>
68 #include <vcl/image.hxx>
69 #include <vcl/longcurr.hxx>
70 #include <vcl/menu.hxx>
71 #include <vcl/settings.hxx>
73 #include <math.h>
74 #include <boost/scoped_ptr.hpp>
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;
89 using namespace ::dbtools;
91 OUString FieldServiceFromId(sal_Int32 nID)
93 switch (nID)
95 case SID_FM_EDIT : return OUString(FM_COL_TEXTFIELD);
96 case SID_FM_COMBOBOX : return OUString(FM_COL_COMBOBOX);
97 case SID_FM_LISTBOX : return OUString(FM_COL_LISTBOX);
98 case SID_FM_CHECKBOX : return OUString(FM_COL_CHECKBOX);
99 case SID_FM_DATEFIELD : return OUString(FM_COL_DATEFIELD);
100 case SID_FM_TIMEFIELD : return OUString(FM_COL_TIMEFIELD);
101 case SID_FM_NUMERICFIELD : return OUString(FM_COL_NUMERICFIELD);
102 case SID_FM_CURRENCYFIELD : return OUString(FM_COL_CURRENCYFIELD);
103 case SID_FM_PATTERNFIELD : return OUString(FM_COL_PATTERNFIELD);
104 case SID_FM_FORMATTEDFIELD : return OUString(FM_COL_FORMATTEDFIELD);
106 return OUString();
109 struct FmGridHeaderData
111 ODataAccessDescriptor aDropData;
112 Point aDropPosPixel;
113 sal_Int8 nDropAction;
114 Reference< XInterface > xDroppedStatement;
115 Reference< XInterface > xDroppedResultSet;
118 const sal_Int16 nChangeTypeOffset = 1000;
119 void SetMenuItem(const ImageList& rList, sal_uInt16 nID, Menu* pMenu, Menu& rNewMenu, bool bDesignMode = true, sal_Int16 nOffset = nChangeTypeOffset)
121 pMenu->SetItemImage(nID, rList.GetImage(nID));
122 pMenu->EnableItem(nID, bDesignMode);
123 rNewMenu.InsertItem(nID + nOffset, pMenu->GetItemText(nID));
124 rNewMenu.SetItemImage(nID + nOffset, rList.GetImage(nID));
125 rNewMenu.SetHelpId(nID + nOffset, pMenu->GetHelpId(nID));
126 rNewMenu.EnableItem(nID + nOffset, bDesignMode);
129 FmGridHeader::FmGridHeader( BrowseBox* pParent, WinBits nWinBits)
130 :EditBrowserHeader(pParent, nWinBits)
131 ,DropTargetHelper(this)
132 ,m_pImpl(new FmGridHeaderData)
136 FmGridHeader::~FmGridHeader()
138 disposeOnce();
141 void FmGridHeader::dispose()
143 delete m_pImpl;
144 m_pImpl = NULL;
145 svt::EditBrowserHeader::dispose();
148 sal_uInt16 FmGridHeader::GetModelColumnPos(sal_uInt16 nId) const
150 return static_cast<FmGridControl*>(GetParent())->GetModelColumnPos(nId);
153 void FmGridHeader::notifyColumnSelect(sal_uInt16 nColumnId)
155 sal_uInt16 nPos = GetModelColumnPos(nColumnId);
156 Reference< XIndexAccess > xColumns(static_cast<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));
169 void FmGridHeader::Select()
171 EditBrowserHeader::Select();
172 notifyColumnSelect(GetCurItemId());
175 void FmGridHeader::RequestHelp( const HelpEvent& rHEvt )
177 sal_uInt16 nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
178 if ( nItemId )
180 if ( rHEvt.GetMode() & (HelpEventMode::QUICK | HelpEventMode::BALLOON) )
182 Rectangle aItemRect = GetItemRect( nItemId );
183 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
184 aItemRect.Left() = aPt.X();
185 aItemRect.Top() = aPt.Y();
186 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
187 aItemRect.Right() = aPt.X();
188 aItemRect.Bottom() = aPt.Y();
190 sal_uInt16 nPos = GetModelColumnPos(nItemId);
191 Reference< ::com::sun::star::container::XIndexContainer > xColumns(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
194 Reference< ::com::sun::star::beans::XPropertySet > xColumn(xColumns->getByIndex(nPos),UNO_QUERY);
195 OUString aHelpText;
196 xColumn->getPropertyValue(FM_PROP_HELPTEXT) >>= aHelpText;
197 if ( aHelpText.isEmpty() )
198 xColumn->getPropertyValue(FM_PROP_DESCRIPTION) >>= aHelpText;
199 if ( !aHelpText.isEmpty() )
201 if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
202 Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aHelpText );
203 else
204 Help::ShowQuickHelp( this, aItemRect, aHelpText );
205 return;
208 catch(Exception&)
210 return;
214 EditBrowserHeader::RequestHelp( rHEvt );
217 sal_Int8 FmGridHeader::AcceptDrop( const AcceptDropEvent& rEvt )
219 // drop allowed in design mode only
220 if (!static_cast<FmGridControl*>(GetParent())->IsDesignMode())
221 return DND_ACTION_NONE;
223 // search for recognized formats
224 const DataFlavorExVector& rFlavors = GetDataFlavorExVector();
225 if (OColumnTransferable::canExtractColumnDescriptor(rFlavors, ColumnTransferFormatFlags::COLUMN_DESCRIPTOR | ColumnTransferFormatFlags::FIELD_DESCRIPTOR))
226 return rEvt.mnAction;
228 return DND_ACTION_NONE;
231 sal_Int8 FmGridHeader::ExecuteDrop( const ExecuteDropEvent& _rEvt )
233 if (!static_cast<FmGridControl*>(GetParent())->IsDesignMode())
234 return DND_ACTION_NONE;
236 TransferableDataHelper aDroppedData(_rEvt.maDropEvent.Transferable);
238 // check the formats
239 bool bColumnDescriptor = OColumnTransferable::canExtractColumnDescriptor(aDroppedData.GetDataFlavorExVector(), ColumnTransferFormatFlags::COLUMN_DESCRIPTOR);
240 bool bFieldDescriptor = OColumnTransferable::canExtractColumnDescriptor(aDroppedData.GetDataFlavorExVector(), ColumnTransferFormatFlags::FIELD_DESCRIPTOR);
241 if (!bColumnDescriptor && !bFieldDescriptor)
243 OSL_FAIL("FmGridHeader::ExecuteDrop: should never have reached this (no extractable format)!");
244 return DND_ACTION_NONE;
247 // extract the descriptor
248 OUString sDatasource, sCommand, sFieldName,sDatabaseLocation,sConnnectionResource;
249 sal_Int32 nCommandType = CommandType::COMMAND;
250 Reference< XPreparedStatement > xStatement;
251 Reference< XResultSet > xResultSet;
252 Reference< XPropertySet > xField;
253 Reference< XConnection > xConnection;
255 ODataAccessDescriptor aColumn = OColumnTransferable::extractColumnDescriptor(aDroppedData);
256 if (aColumn.has(daDataSource)) aColumn[daDataSource] >>= sDatasource;
257 if (aColumn.has(daDatabaseLocation)) aColumn[daDatabaseLocation] >>= sDatabaseLocation;
258 if (aColumn.has(daConnectionResource)) aColumn[daConnectionResource] >>= sConnnectionResource;
259 if (aColumn.has(daCommand)) aColumn[daCommand] >>= sCommand;
260 if (aColumn.has(daCommandType)) aColumn[daCommandType] >>= nCommandType;
261 if (aColumn.has(daColumnName)) aColumn[daColumnName] >>= sFieldName;
262 if (aColumn.has(daColumnObject))aColumn[daColumnObject] >>= xField;
263 if (aColumn.has(daConnection)) aColumn[daConnection] >>= xConnection;
265 if ( sFieldName.isEmpty()
266 || sCommand.isEmpty()
267 || ( sDatasource.isEmpty()
268 && sDatabaseLocation.isEmpty()
269 && !xConnection.is()
273 OSL_FAIL( "FmGridHeader::ExecuteDrop: somebody started a nonsense drag operation!!" );
274 return DND_ACTION_NONE;
279 // need a connection
280 if (!xConnection.is())
281 { // the transferable did not contain the connection -> build an own one
284 OUString sSignificantSource( sDatasource.isEmpty() ? sDatabaseLocation : sDatasource );
285 xConnection = getConnection_withFeedback(sSignificantSource, OUString(), OUString(),
286 static_cast<FmGridControl*>(GetParent())->getContext() );
288 catch(NoSuchElementException&)
289 { // allowed, means sDatasource isn't a valid data source name ....
291 catch(Exception&)
293 OSL_FAIL("FmGridHeader::ExecuteDrop: could not retrieve the database access object !");
296 if (!xConnection.is())
298 OSL_FAIL("FmGridHeader::ExecuteDrop: could not retrieve the database access object !");
299 return DND_ACTION_NONE;
303 // try to obtain the column object
304 if (!xField.is())
306 #ifdef DBG_UTIL
307 Reference< XServiceInfo > xServiceInfo(xConnection, UNO_QUERY);
308 DBG_ASSERT(xServiceInfo.is() && xServiceInfo->supportsService(SRV_SDB_CONNECTION), "FmGridHeader::ExecuteDrop: invalid connection (no database access connection !)");
309 #endif
311 Reference< XNameAccess > xFields;
312 switch (nCommandType)
314 case CommandType::TABLE:
316 Reference< XTablesSupplier > xSupplyTables(xConnection, UNO_QUERY);
317 Reference< XColumnsSupplier > xSupplyColumns;
318 xSupplyTables->getTables()->getByName(sCommand) >>= xSupplyColumns;
319 xFields = xSupplyColumns->getColumns();
321 break;
322 case CommandType::QUERY:
324 Reference< XQueriesSupplier > xSupplyQueries(xConnection, UNO_QUERY);
325 Reference< XColumnsSupplier > xSupplyColumns;
326 xSupplyQueries->getQueries()->getByName(sCommand) >>= xSupplyColumns;
327 xFields = xSupplyColumns->getColumns();
329 break;
330 default:
332 xStatement = xConnection->prepareStatement(sCommand);
333 // not interested in any results
335 Reference< XPropertySet > xStatProps(xStatement,UNO_QUERY);
336 xStatProps->setPropertyValue("MaxRows", makeAny(sal_Int32(0)));
338 xResultSet = xStatement->executeQuery();
339 Reference< XColumnsSupplier > xSupplyCols(xResultSet, UNO_QUERY);
340 if (xSupplyCols.is())
341 xFields = xSupplyCols->getColumns();
345 if (xFields.is() && xFields->hasByName(sFieldName))
346 xFields->getByName(sFieldName) >>= xField;
348 if (!xField.is())
350 ::comphelper::disposeComponent(xStatement);
351 return DND_ACTION_NONE;
355 // do the drop asynchronously
356 // (85957 - UI actions within the drop are not allowed, but we want to open a popup menu)
357 m_pImpl->aDropData = aColumn;
358 m_pImpl->aDropData[daConnection] <<= xConnection;
359 m_pImpl->aDropData[daColumnObject] <<= xField;
361 m_pImpl->nDropAction = _rEvt.mnAction;
362 m_pImpl->aDropPosPixel = _rEvt.maPosPixel;
363 m_pImpl->xDroppedStatement = xStatement;
364 m_pImpl->xDroppedResultSet = xResultSet;
366 PostUserEvent(LINK(this, FmGridHeader, OnAsyncExecuteDrop), NULL, true);
368 catch (Exception&)
370 OSL_FAIL("FmGridHeader::ExecuteDrop: caught an exception while creatin' the column !");
371 ::comphelper::disposeComponent(xStatement);
372 return DND_ACTION_NONE;
375 return DND_ACTION_LINK;
378 IMPL_LINK_NOARG( FmGridHeader, OnAsyncExecuteDrop )
380 OUString sCommand, sFieldName,sURL;
381 sal_Int32 nCommandType = CommandType::COMMAND;
382 Reference< XPropertySet > xField;
383 Reference< XConnection > xConnection;
385 OUString sDatasource = m_pImpl->aDropData.getDataSource();
386 if ( sDatasource.isEmpty() && m_pImpl->aDropData.has(daConnectionResource) )
387 m_pImpl->aDropData[daConnectionResource] >>= sURL;
388 m_pImpl->aDropData[daCommand] >>= sCommand;
389 m_pImpl->aDropData[daCommandType] >>= nCommandType;
390 m_pImpl->aDropData[daColumnName] >>= sFieldName;
391 m_pImpl->aDropData[daConnection] >>= xConnection;
392 m_pImpl->aDropData[daColumnObject] >>= xField;
396 // need number formats
397 Reference< XNumberFormatsSupplier > xSupplier = getNumberFormats(xConnection, true);
398 Reference< XNumberFormats > xNumberFormats;
399 if (xSupplier.is())
400 xNumberFormats = xSupplier->getNumberFormats();
401 if (!xNumberFormats.is())
403 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
404 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
405 return 0L;
408 // Vom Feld werden nun zwei Informationen benoetigt:
409 // a.) Name des Feldes fuer Label und ControlSource
410 // b.) FormatKey, um festzustellen, welches Feld erzeugt werden soll
411 sal_Int32 nDataType = 0;
412 xField->getPropertyValue(FM_PROP_FIELDTYPE) >>= nDataType;
413 // diese Datentypen koennen im Gridcontrol nicht verarbeitet werden
414 switch (nDataType)
416 case DataType::BLOB:
417 case DataType::LONGVARBINARY:
418 case DataType::BINARY:
419 case DataType::VARBINARY:
420 case DataType::OTHER:
421 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
422 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
423 return 0L;
426 // Erstellen der Column
427 Reference< XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
428 Reference< XGridColumnFactory > xFactory(xCols, UNO_QUERY);
430 sal_uInt16 nColId = GetItemId(m_pImpl->aDropPosPixel);
431 // EinfuegePosition, immer vor der aktuellen Spalte
432 sal_uInt16 nPos = GetModelColumnPos(nColId);
433 Reference< XPropertySet > xCol, xSecondCol;
435 // Create Column based on type, default textfield
436 std::vector<sal_uInt16> aPossibleTypes;
437 switch (nDataType)
439 case DataType::BIT:
440 case DataType::BOOLEAN:
441 aPossibleTypes.push_back(SID_FM_CHECKBOX);
442 break;
443 case DataType::TINYINT:
444 case DataType::SMALLINT:
445 case DataType::INTEGER:
446 aPossibleTypes.push_back(SID_FM_NUMERICFIELD);
447 aPossibleTypes.push_back(SID_FM_FORMATTEDFIELD);
448 break;
449 case DataType::REAL:
450 case DataType::DOUBLE:
451 case DataType::NUMERIC:
452 case DataType::DECIMAL:
453 aPossibleTypes.push_back(SID_FM_FORMATTEDFIELD);
454 aPossibleTypes.push_back(SID_FM_NUMERICFIELD);
455 break;
456 case DataType::TIMESTAMP:
457 aPossibleTypes.push_back(SID_FM_TWOFIELDS_DATE_N_TIME);
458 aPossibleTypes.push_back(SID_FM_DATEFIELD);
459 aPossibleTypes.push_back(SID_FM_TIMEFIELD);
460 aPossibleTypes.push_back(SID_FM_FORMATTEDFIELD);
461 break;
462 case DataType::DATE:
463 aPossibleTypes.push_back(SID_FM_DATEFIELD);
464 aPossibleTypes.push_back(SID_FM_FORMATTEDFIELD);
465 break;
466 case DataType::TIME:
467 aPossibleTypes.push_back(SID_FM_TIMEFIELD);
468 aPossibleTypes.push_back(SID_FM_FORMATTEDFIELD);
469 break;
470 case DataType::CHAR:
471 case DataType::VARCHAR:
472 case DataType::LONGVARCHAR:
473 default:
474 aPossibleTypes.push_back(SID_FM_EDIT);
475 aPossibleTypes.push_back(SID_FM_FORMATTEDFIELD);
476 break;
478 // if it's a currency field, a "currency field" option
481 if ( ::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField)
482 && ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY)))
483 aPossibleTypes.insert(aPossibleTypes.begin(), SID_FM_CURRENCYFIELD);
485 catch(Exception&)
487 OSL_FAIL("FmGridHeader::ExecuteDrop: Exception occurred!");
490 bool bDateNTimeCol = false;
491 if (!aPossibleTypes.empty())
493 sal_Int32 nPreferredType = aPossibleTypes[0];
494 if ((m_pImpl->nDropAction == DND_ACTION_LINK) && (aPossibleTypes.size() > 1))
496 ImageList aImageList( SVX_RES(RID_SVXIMGLIST_FMEXPL) );
498 PopupMenu aInsertMenu(SVX_RES(RID_SVXMNU_COLS));
499 PopupMenu aTypeMenu;
500 PopupMenu* pMenu = aInsertMenu.GetPopupMenu(SID_FM_INSERTCOL);
501 for (std::vector<sal_uInt16>::const_iterator iter = aPossibleTypes.begin(); iter != aPossibleTypes.end(); ++iter)
502 SetMenuItem(aImageList, *iter, pMenu, aTypeMenu, true, 0);
503 nPreferredType = aTypeMenu.Execute(this, m_pImpl->aDropPosPixel);
506 bDateNTimeCol = nPreferredType == SID_FM_TWOFIELDS_DATE_N_TIME;
507 sal_uInt16 nColCount = bDateNTimeCol ? 2 : 1;
508 OUString sFieldService;
509 while (nColCount--)
511 if (bDateNTimeCol)
512 nPreferredType = nColCount ? SID_FM_DATEFIELD : SID_FM_TIMEFIELD;
514 sFieldService = FieldServiceFromId(nPreferredType);
515 Reference< XPropertySet > xThisRoundCol;
516 if ( !sFieldService.isEmpty() )
517 xThisRoundCol = xFactory->createColumn(sFieldService);
518 if (nColCount)
519 xSecondCol = xThisRoundCol;
520 else
521 xCol = xThisRoundCol;
525 if (!xCol.is() || (bDateNTimeCol && !xSecondCol.is()))
527 ::comphelper::disposeComponent(xCol); // in case only the creation of the second column failed
528 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
529 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
530 return 0L;
533 if (bDateNTimeCol)
535 OUString sTimePostfix(SVX_RESSTR(RID_STR_POSTFIX_TIME));
536 xCol->setPropertyValue(FM_PROP_LABEL, makeAny( OUString( sFieldName + sTimePostfix ) ) );
538 OUString sDatePostfix(SVX_RESSTR( RID_STR_POSTFIX_DATE));
539 xSecondCol->setPropertyValue(FM_PROP_LABEL, makeAny( OUString( sFieldName + sDatePostfix ) ) );
541 else
542 xCol->setPropertyValue(FM_PROP_LABEL, makeAny(sFieldName));
544 // jetzt einfuegen
545 Any aElement;
546 aElement <<= xCol;
548 xCols->insertByIndex(nPos, aElement);
550 FormControlFactory aControlFactory;
551 aControlFactory.initializeControlModel( DocumentClassification::classifyHostDocument( xCols ), xCol );
552 FormControlFactory::initializeFieldDependentProperties( xField, xCol, xNumberFormats );
554 xCol->setPropertyValue(FM_PROP_CONTROLSOURCE, makeAny(sFieldName));
555 if ( xSecondCol.is() )
556 xSecondCol->setPropertyValue(FM_PROP_CONTROLSOURCE, makeAny(sFieldName));
558 if (bDateNTimeCol)
560 OUString sRealName,sPurePostfix;
562 OUString aPostfix[] = {
563 SVX_RESSTR(RID_STR_POSTFIX_DATE),
564 SVX_RESSTR(RID_STR_POSTFIX_TIME)
567 for ( size_t i=0; i<2; ++i )
569 sPurePostfix = comphelper::string::stripStart(aPostfix[i], ' ');
570 sPurePostfix = comphelper::string::stripStart(sPurePostfix, '(');
571 sPurePostfix = comphelper::string::stripEnd(sPurePostfix, ')');
572 sRealName = sFieldName;
573 sRealName += "_";
574 sRealName += sPurePostfix;
575 if (i)
576 xSecondCol->setPropertyValue(FM_PROP_NAME, makeAny(OUString(sRealName)));
577 else
578 xCol->setPropertyValue(FM_PROP_NAME, makeAny(OUString(sRealName)));
581 else
582 xCol->setPropertyValue(FM_PROP_NAME, makeAny(sFieldName));
584 if (bDateNTimeCol)
586 aElement <<= xSecondCol;
587 xCols->insertByIndex(nPos == (sal_uInt16)-1 ? nPos : ++nPos, aElement);
590 // ist die component::Form an die Datenbankangebunden?
591 Reference< XFormComponent > xFormCp(xCols, UNO_QUERY);
592 Reference< XPropertySet > xForm(xFormCp->getParent(), UNO_QUERY);
593 if (xForm.is())
595 if (::comphelper::getString(xForm->getPropertyValue(FM_PROP_DATASOURCE)).isEmpty())
597 if ( !sDatasource.isEmpty() )
598 xForm->setPropertyValue(FM_PROP_DATASOURCE, makeAny(sDatasource));
599 else
600 xForm->setPropertyValue(FM_PROP_URL, makeAny(sURL));
603 if (::comphelper::getString(xForm->getPropertyValue(FM_PROP_COMMAND)).isEmpty())
605 xForm->setPropertyValue(FM_PROP_COMMAND, makeAny(sCommand));
606 Any aCommandType;
607 switch (nCommandType)
609 case CommandType::TABLE:
610 aCommandType <<= (sal_Int32)CommandType::TABLE;
611 break;
612 case CommandType::QUERY:
613 aCommandType <<= (sal_Int32)CommandType::QUERY;
614 break;
615 default:
616 aCommandType <<= (sal_Int32)CommandType::COMMAND;
617 xForm->setPropertyValue(FM_PROP_ESCAPE_PROCESSING, css::uno::Any(2 == nCommandType));
618 break;
620 xForm->setPropertyValue(FM_PROP_COMMANDTYPE, aCommandType);
624 catch (Exception&)
626 OSL_FAIL("FmGridHeader::OnAsyncExecuteDrop: caught an exception while creatin' the column !");
627 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
628 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
629 return 0L;
632 ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
633 ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
634 return 1L;
637 void FmGridHeader::PreExecuteColumnContextMenu(sal_uInt16 nColId, PopupMenu& rMenu)
639 bool bDesignMode = static_cast<FmGridControl*>(GetParent())->IsDesignMode();
641 Reference< ::com::sun::star::container::XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
642 // Aufbau des Insert Menues
643 // mark the column if nColId != HEADERBAR_ITEM_NOTFOUND
644 if(nColId > 0)
646 sal_uInt16 nPos2 = GetModelColumnPos(nColId);
648 Reference< ::com::sun::star::container::XIndexContainer > xColumns(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
649 Reference< ::com::sun::star::beans::XPropertySet> xColumn(
650 xColumns->getByIndex(nPos2), css::uno::UNO_QUERY);
651 Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
652 if (xSelSupplier.is())
653 xSelSupplier->select(makeAny(xColumn));
656 // EinfuegePosition, immer vor der aktuellen Spalte
657 sal_uInt16 nPos = GetModelColumnPos(nColId);
658 bool bMarked = nColId && static_cast<FmGridControl*>(GetParent())->isColumnMarked(nColId);
660 ImageList aImageList( SVX_RES(RID_SVXIMGLIST_FMEXPL) );
661 PopupMenu* pControlMenu = new PopupMenu;
663 PopupMenu* pMenu = rMenu.GetPopupMenu(SID_FM_INSERTCOL);
664 if (pMenu)
666 SetMenuItem(aImageList, SID_FM_EDIT, pMenu, *pControlMenu, bDesignMode);
667 SetMenuItem(aImageList, SID_FM_CHECKBOX, pMenu, *pControlMenu, bDesignMode);
668 SetMenuItem(aImageList, SID_FM_COMBOBOX, pMenu, *pControlMenu, bDesignMode);
669 SetMenuItem(aImageList, SID_FM_LISTBOX, pMenu, *pControlMenu, bDesignMode);
670 SetMenuItem(aImageList, SID_FM_DATEFIELD, pMenu, *pControlMenu, bDesignMode);
671 SetMenuItem(aImageList, SID_FM_TIMEFIELD, pMenu, *pControlMenu, bDesignMode);
672 SetMenuItem(aImageList, SID_FM_NUMERICFIELD, pMenu, *pControlMenu, bDesignMode);
673 SetMenuItem(aImageList, SID_FM_CURRENCYFIELD, pMenu, *pControlMenu, bDesignMode);
674 SetMenuItem(aImageList, SID_FM_PATTERNFIELD, pMenu, *pControlMenu, bDesignMode);
675 SetMenuItem(aImageList, SID_FM_FORMATTEDFIELD, pMenu, *pControlMenu, bDesignMode);
678 if (pMenu && xCols.is() && nColId)
680 Reference< ::com::sun::star::beans::XPropertySet > xSet(
681 xCols->getByIndex(nPos), css::uno::UNO_QUERY);
682 sal_Int16 nClassId;
683 xSet->getPropertyValue(FM_PROP_CLASSID) >>= nClassId;
685 Reference< ::com::sun::star::io::XPersistObject > xServiceQuestion(xSet, UNO_QUERY);
686 sal_Int32 nColType = xServiceQuestion.is() ? getColumnTypeByModelName(xServiceQuestion->getServiceName()) : 0;
687 if (nColType == TYPE_TEXTFIELD)
688 { // edit fields and formatted fields have the same service name, thus getColumnTypeByModelName returns TYPE_TEXTFIELD
689 // in both cases. And as columns don't have an ::com::sun::star::lang::XServiceInfo interface, we have to distinguish both
690 // types via the existence of special properties
691 Reference< ::com::sun::star::beans::XPropertySet > xProps(xSet, UNO_QUERY);
692 if (xProps.is())
694 Reference< ::com::sun::star::beans::XPropertySetInfo > xPropsInfo = xProps->getPropertySetInfo();
695 if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(FM_PROP_FORMATSSUPPLIER))
696 nColType = TYPE_FORMATTEDFIELD;
700 pControlMenu->EnableItem(SID_FM_EDIT + nChangeTypeOffset, bDesignMode && (nColType != TYPE_TEXTFIELD));
701 pControlMenu->EnableItem(SID_FM_COMBOBOX + nChangeTypeOffset, bDesignMode && (nColType != TYPE_COMBOBOX));
702 pControlMenu->EnableItem(SID_FM_LISTBOX + nChangeTypeOffset, bDesignMode && (nColType != TYPE_LISTBOX));
703 pControlMenu->EnableItem(SID_FM_CHECKBOX + nChangeTypeOffset, bDesignMode && (nColType != TYPE_CHECKBOX));
704 pControlMenu->EnableItem(SID_FM_DATEFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_DATEFIELD));
705 pControlMenu->EnableItem(SID_FM_NUMERICFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_NUMERICFIELD));
706 pControlMenu->EnableItem(SID_FM_TIMEFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_TIMEFIELD));
707 pControlMenu->EnableItem(SID_FM_CURRENCYFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_CURRENCYFIELD));
708 pControlMenu->EnableItem(SID_FM_PATTERNFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_PATTERNFIELD));
709 pControlMenu->EnableItem(SID_FM_FORMATTEDFIELD + nChangeTypeOffset, bDesignMode && (nColType != TYPE_FORMATTEDFIELD));
710 rMenu.SetPopupMenu(SID_FM_CHANGECOL, pControlMenu);
713 rMenu.EnableItem(SID_FM_INSERTCOL, bDesignMode && xCols.is());
714 rMenu.EnableItem(SID_FM_DELETECOL, bDesignMode && bMarked && xCols.is());
715 rMenu.EnableItem(SID_FM_CHANGECOL, bDesignMode && bMarked && xCols.is());
716 rMenu.EnableItem(SID_FM_SHOW_PROPERTY_BROWSER, bDesignMode && bMarked && xCols.is());
718 PopupMenu* pShowColsMenu = rMenu.GetPopupMenu(SID_FM_SHOWCOLS);
719 sal_uInt16 nHiddenCols = 0;
720 if (pShowColsMenu)
722 if (xCols.is())
724 // check for hidden cols
725 Reference< ::com::sun::star::beans::XPropertySet > xCurCol;
726 Any aHidden,aName;
727 for (sal_uInt16 i=0; i<xCols->getCount(); ++i)
729 xCurCol.set(xCols->getByIndex(i), css::uno::UNO_QUERY);
730 DBG_ASSERT(xCurCol.is(), "FmGridHeader::PreExecuteColumnContextMenu : the Peer has invalid columns !");
731 aHidden = xCurCol->getPropertyValue(FM_PROP_HIDDEN);
732 DBG_ASSERT(aHidden.getValueType().getTypeClass() == TypeClass_BOOLEAN,
733 "FmGridHeader::PreExecuteColumnContextMenu : the property 'hidden' should be boolean !");
734 if (::comphelper::getBOOL(aHidden))
736 // put the column name into the 'show col' menu
737 if (nHiddenCols < 16)
738 { // (only the first 16 items to keep the menu rather small)
739 aName = xCurCol->getPropertyValue(FM_PROP_LABEL);
740 pShowColsMenu->InsertItem(nHiddenCols + 1, ::comphelper::getString(aName),
741 MenuItemBits::NONE, OString(), nHiddenCols);
742 // the ID is arbitrary, but should be unique within the whole menu
744 ++nHiddenCols;
748 pShowColsMenu->EnableItem(SID_FM_SHOWCOLS_MORE, xCols.is() && (nHiddenCols > 16));
749 pShowColsMenu->EnableItem(SID_FM_SHOWALLCOLS, xCols.is() && (nHiddenCols > 0));
752 // allow the 'hide column' item ?
753 bool bAllowHide = bMarked; // a column is marked
754 bAllowHide = bAllowHide || (!bDesignMode && (nPos != (sal_uInt16)-1)); // OR we are in alive mode and have hit a column
755 bAllowHide = bAllowHide && xCols.is(); // AND we have a column container
756 bAllowHide = bAllowHide && (xCols->getCount()-nHiddenCols > 1); // AND there are at least two visible columns
757 rMenu.EnableItem(SID_FM_HIDECOL, bAllowHide);
759 if (bMarked)
762 SfxViewFrame* pCurrentFrame = SfxViewFrame::Current();
763 SfxItemState eState = SfxItemState::UNKNOWN;
764 // ask the bindings of the current view frame (which should be the one we're residing in) for the state
765 if (pCurrentFrame)
767 SfxPoolItem* pItem = NULL;
768 eState = pCurrentFrame->GetBindings().QueryState(SID_FM_CTL_PROPERTIES, pItem);
770 if (eState >= SfxItemState::DEFAULT && pItem )
772 bool bChecked = pItem->ISA(SfxBoolItem) && static_cast<SfxBoolItem*>(pItem)->GetValue();
773 rMenu.CheckItem(SID_FM_SHOW_PROPERTY_BROWSER,bChecked);
775 delete pItem;
780 enum InspectorAction { eOpenInspector, eCloseInspector, eUpdateInspector, eNone };
782 void FmGridHeader::PostExecuteColumnContextMenu(sal_uInt16 nColId, const PopupMenu& rMenu, sal_uInt16 nExecutionResult)
784 Reference< ::com::sun::star::container::XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
785 sal_uInt16 nPos = GetModelColumnPos(nColId);
787 // remove and delete the menu we inserted in PreExecuteColumnContextMenu
788 PopupMenu* pControlMenu = rMenu.GetPopupMenu(SID_FM_CHANGECOL);
789 delete pControlMenu;
791 OUString aFieldType;
792 bool bReplace = false;
793 InspectorAction eInspectorAction = eNone;
794 Reference< XPropertySet > xColumnToInspect;
795 switch (nExecutionResult)
797 case SID_FM_DELETECOL:
799 Reference< XInterface > xCol(
800 xCols->getByIndex(nPos), css::uno::UNO_QUERY);
801 xCols->removeByIndex(nPos);
802 ::comphelper::disposeComponent(xCol);
803 } break;
804 case SID_FM_SHOW_PROPERTY_BROWSER:
805 eInspectorAction = rMenu.IsItemChecked( SID_FM_SHOW_PROPERTY_BROWSER ) ? eOpenInspector : eCloseInspector;
806 xColumnToInspect.set( xCols->getByIndex( nPos ), UNO_QUERY );
807 break;
808 case SID_FM_EDIT + nChangeTypeOffset:
809 bReplace = true;
810 case SID_FM_EDIT:
811 aFieldType = FM_COL_TEXTFIELD;
812 break;
813 case SID_FM_COMBOBOX + nChangeTypeOffset:
814 bReplace = true;
815 case SID_FM_COMBOBOX:
816 aFieldType = FM_COL_COMBOBOX;
817 break;
818 case SID_FM_LISTBOX + nChangeTypeOffset:
819 bReplace = true;
820 case SID_FM_LISTBOX:
821 aFieldType = FM_COL_LISTBOX;
822 break;
823 case SID_FM_CHECKBOX + nChangeTypeOffset:
824 bReplace = true;
825 case SID_FM_CHECKBOX:
826 aFieldType = FM_COL_CHECKBOX;
827 break;
828 case SID_FM_DATEFIELD + nChangeTypeOffset:
829 bReplace = true;
830 case SID_FM_DATEFIELD:
831 aFieldType = FM_COL_DATEFIELD;
832 break;
833 case SID_FM_TIMEFIELD + nChangeTypeOffset:
834 bReplace = true;
835 case SID_FM_TIMEFIELD:
836 aFieldType = FM_COL_TIMEFIELD;
837 break;
838 case SID_FM_NUMERICFIELD + nChangeTypeOffset:
839 bReplace = true;
840 case SID_FM_NUMERICFIELD:
841 aFieldType = FM_COL_NUMERICFIELD;
842 break;
843 case SID_FM_CURRENCYFIELD + nChangeTypeOffset:
844 bReplace = true;
845 case SID_FM_CURRENCYFIELD:
846 aFieldType = FM_COL_CURRENCYFIELD;
847 break;
848 case SID_FM_PATTERNFIELD + nChangeTypeOffset:
849 bReplace = true;
850 case SID_FM_PATTERNFIELD:
851 aFieldType = FM_COL_PATTERNFIELD;
852 break;
853 case SID_FM_FORMATTEDFIELD + nChangeTypeOffset:
854 bReplace = true;
855 case SID_FM_FORMATTEDFIELD:
856 aFieldType = FM_COL_FORMATTEDFIELD;
857 break;
858 case SID_FM_HIDECOL:
860 Reference< ::com::sun::star::beans::XPropertySet > xCurCol(
861 xCols->getByIndex(nPos), css::uno::UNO_QUERY);
862 xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny(true));
864 break;
865 case SID_FM_SHOWCOLS_MORE:
867 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
868 if(pFact)
870 boost::scoped_ptr<AbstractFmShowColsDialog> pDlg(pFact->CreateFmShowColsDialog(NULL));
871 DBG_ASSERT(pDlg, "Dialog creation failed!");
872 pDlg->SetColumns(xCols);
873 pDlg->Execute();
877 break;
878 case SID_FM_SHOWALLCOLS:
880 // just iterate through all the cols ...
881 Reference< ::com::sun::star::beans::XPropertySet > xCurCol;
882 for (sal_uInt16 i=0; i<xCols->getCount(); ++i)
884 xCurCol.set(xCols->getByIndex(i), css::uno::UNO_QUERY);
885 xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny(false));
887 // TODO : there must be a more clever way to do this ....
888 // with the above the view is updated after every single model update ...
890 break;
891 default:
892 if (nExecutionResult>0 && nExecutionResult<=16)
893 { // it was a "show column/<colname>" command (there are at most 16 such items)
894 // search the nExecutionResult'th hidden col
895 Reference< ::com::sun::star::beans::XPropertySet > xCurCol;
896 for (sal_uInt16 i=0; i<xCols->getCount() && nExecutionResult; ++i)
898 xCurCol.set(xCols->getByIndex(i), css::uno::UNO_QUERY);
899 Any aHidden = xCurCol->getPropertyValue(FM_PROP_HIDDEN);
900 if (::comphelper::getBOOL(aHidden))
901 if (!--nExecutionResult)
903 xCurCol->setPropertyValue(FM_PROP_HIDDEN, makeAny(false));
904 break;
908 break;
911 if ( !aFieldType.isEmpty() )
915 Reference< XGridColumnFactory > xFactory( xCols, UNO_QUERY_THROW );
916 Reference< XPropertySet > xNewCol( xFactory->createColumn( aFieldType ), UNO_SET_THROW );
918 if ( bReplace )
920 // ein paar Properties hinueberretten
921 Reference< XPropertySet > xReplaced( xCols->getByIndex( nPos ), UNO_QUERY );
923 TransferFormComponentProperties(
924 xReplaced, xNewCol, Application::GetSettings().GetUILanguageTag().getLocale() );
926 xCols->replaceByIndex( nPos, makeAny( xNewCol ) );
927 ::comphelper::disposeComponent( xReplaced );
929 eInspectorAction = eUpdateInspector;
930 xColumnToInspect = xNewCol;
932 else
934 FormControlFactory factory;
936 OUString sLabel = FormControlFactory::getDefaultUniqueName_ByComponentType(
937 Reference< XNameAccess >( xCols, UNO_QUERY_THROW ), xNewCol );
938 xNewCol->setPropertyValue( FM_PROP_LABEL, makeAny( sLabel ) );
939 xNewCol->setPropertyValue( FM_PROP_NAME, makeAny( sLabel ) );
941 factory.initializeControlModel( DocumentClassification::classifyHostDocument( xCols ), xNewCol );
943 xCols->insertByIndex( nPos, makeAny( xNewCol ) );
946 catch( const Exception& )
948 DBG_UNHANDLED_EXCEPTION();
952 SfxViewFrame* pCurrentFrame = SfxViewFrame::Current();
953 OSL_ENSURE( pCurrentFrame, "FmGridHeader::PostExecuteColumnContextMenu: no view frame -> no bindings -> no property browser!" );
954 if ( pCurrentFrame )
956 if ( eInspectorAction == eUpdateInspector )
958 if ( !pCurrentFrame->HasChildWindow( SID_FM_SHOW_PROPERTIES ) )
959 eInspectorAction = eNone;
962 if ( eInspectorAction != eNone )
964 FmInterfaceItem aIFaceItem( SID_FM_SHOW_PROPERTY_BROWSER, xColumnToInspect );
965 SfxBoolItem aShowItem( SID_FM_SHOW_PROPERTIES, eInspectorAction != eCloseInspector );
967 pCurrentFrame->GetBindings().GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SfxCallMode::ASYNCHRON,
968 &aIFaceItem, &aShowItem, 0L );
973 void FmGridHeader::triggerColumnContextMenu( const ::Point& _rPreferredPos )
975 // the affected col
976 sal_uInt16 nColId = GetItemId( _rPreferredPos );
978 // the menu
979 PopupMenu aContextMenu( SVX_RES( RID_SVXMNU_COLS ) );
981 // let derivees modify the menu
982 PreExecuteColumnContextMenu( nColId, aContextMenu );
983 aContextMenu.RemoveDisabledEntries( true, true );
985 // execute the menu
986 sal_uInt16 nResult = aContextMenu.Execute( this, _rPreferredPos );
988 // let derivees handle the result
989 PostExecuteColumnContextMenu( nColId, aContextMenu, nResult );
992 void FmGridHeader::Command(const CommandEvent& rEvt)
994 switch (rEvt.GetCommand())
996 case CommandEventId::ContextMenu:
998 if (!rEvt.IsMouseEvent())
999 return;
1001 triggerColumnContextMenu( rEvt.GetMousePosPixel() );
1003 break;
1004 default:
1005 EditBrowserHeader::Command(rEvt);
1009 FmGridControl::FmGridControl(
1010 const Reference< ::com::sun::star::uno::XComponentContext >& _rxContext,
1011 vcl::Window* pParent,
1012 FmXGridPeer* _pPeer,
1013 WinBits nBits)
1014 :DbGridControl(_rxContext, pParent, nBits)
1015 ,m_pPeer(_pPeer)
1016 ,m_nCurrentSelectedColumn(-1)
1017 ,m_nMarkedColumnId(BROWSER_INVALIDID)
1018 ,m_bSelecting(false)
1019 ,m_bInColumnMove(false)
1021 EnableInteractiveRowHeight( );
1024 void FmGridControl::Command(const CommandEvent& _rEvt)
1026 if ( CommandEventId::ContextMenu == _rEvt.GetCommand() )
1028 FmGridHeader* pMyHeader = static_cast< FmGridHeader* >( GetHeaderBar() );
1029 if ( pMyHeader && !_rEvt.IsMouseEvent() )
1030 { // context menu requested by keyboard
1031 if ( 1 == GetSelectColumnCount() || IsDesignMode() )
1033 sal_uInt16 nSelId = GetColumnId(
1034 sal::static_int_cast< sal_uInt16 >( FirstSelectedColumn() ) );
1035 ::Rectangle aColRect( GetFieldRectPixel( 0, nSelId, false ) );
1037 Point aRelativePos( pMyHeader->ScreenToOutputPixel( OutputToScreenPixel( aColRect.TopCenter() ) ) );
1038 pMyHeader->triggerColumnContextMenu( aRelativePos, FmGridHeader::AccessControl() );
1040 // handled
1041 return;
1046 DbGridControl::Command( _rEvt );
1049 // ::com::sun::star::beans::XPropertyChangeListener
1050 void FmGridControl::propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& evt)
1052 if (evt.PropertyName == FM_PROP_ROWCOUNT)
1054 // if we're not in the main thread call AdjustRows asynchronously
1055 implAdjustInSolarThread(true);
1056 return;
1059 const DbGridRowRef& xRow = GetCurrentRow();
1060 // waehrend Positionierung wird kein abgleich der Properties vorgenommen
1061 Reference<XPropertySet> xSet(evt.Source,UNO_QUERY);
1062 if (xRow.Is() && (::cppu::any2bool(xSet->getPropertyValue(FM_PROP_ISNEW))|| CompareBookmark(getDataSource()->getBookmark(), xRow->GetBookmark())))
1064 if (evt.PropertyName == FM_PROP_ISMODIFIED)
1066 // modified or clean ?
1067 GridRowStatus eStatus = ::comphelper::getBOOL(evt.NewValue) ? GRS_MODIFIED : GRS_CLEAN;
1068 if (eStatus != xRow->GetStatus())
1070 xRow->SetStatus(eStatus);
1071 SolarMutexGuard aGuard;
1072 RowModified(GetCurrentPos());
1078 void FmGridControl::SetDesignMode(bool bMode)
1080 bool bOldMode = IsDesignMode();
1081 DbGridControl::SetDesignMode(bMode);
1082 if (bOldMode != bMode)
1084 if (!bMode)
1086 // selection aufheben
1087 markColumn(USHRT_MAX);
1089 else
1091 Reference< ::com::sun::star::container::XIndexContainer > xColumns(GetPeer()->getColumns());
1092 Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
1093 if (xSelSupplier.is())
1095 Any aSelection = xSelSupplier->getSelection();
1096 Reference< ::com::sun::star::beans::XPropertySet > xColumn;
1097 if (aSelection.getValueType().getTypeClass() == TypeClass_INTERFACE)
1098 xColumn.set(aSelection, css::uno::UNO_QUERY);
1099 Reference< XInterface > xCurrent;
1100 for (sal_uInt16 i=0; i<xColumns->getCount(); ++i)
1102 xCurrent.set(xColumns->getByIndex(i), css::uno::UNO_QUERY);
1103 if (xCurrent == xColumn)
1105 markColumn(GetColumnIdFromModelPos(i));
1106 break;
1114 void FmGridControl::DeleteSelectedRows()
1116 if (!m_pSeekCursor)
1117 return;
1119 // how many rows are selected?
1120 sal_Int32 nSelectedRows = GetSelectRowCount();
1122 // the current line should be deleted but it is currently in edit mode
1123 if ( IsCurrentAppending() )
1124 return;
1125 // is the insert row selected
1126 if (GetEmptyRow().Is() && IsRowSelected(GetRowCount() - 1))
1127 nSelectedRows -= 1;
1129 // nothing to do
1130 if (nSelectedRows <= 0)
1131 return;
1133 // try to confirm the delete
1134 Reference< ::com::sun::star::frame::XDispatchProvider > xDispatcher = (::com::sun::star::frame::XDispatchProvider*)GetPeer();
1135 if (xDispatcher.is())
1137 ::com::sun::star::util::URL aUrl;
1138 aUrl.Complete = FMURL_CONFIRM_DELETION;
1139 // #100312# ------------
1140 Reference< ::com::sun::star::util::XURLTransformer > xTransformer(
1141 ::com::sun::star::util::URLTransformer::create(::comphelper::getProcessComponentContext()) );
1142 xTransformer->parseStrict( aUrl );
1144 Reference< ::com::sun::star::frame::XDispatch > xDispatch = xDispatcher->queryDispatch(aUrl, OUString(), 0);
1145 Reference< ::com::sun::star::form::XConfirmDeleteListener > xConfirm(xDispatch, UNO_QUERY);
1146 if (xConfirm.is())
1148 ::com::sun::star::sdb::RowChangeEvent aEvent;
1149 aEvent.Source = Reference< XInterface >(*getDataSource());
1150 aEvent.Rows = nSelectedRows;
1151 aEvent.Action = ::com::sun::star::sdb::RowChangeAction::DELETE;
1152 if (!xConfirm->confirmDelete(aEvent))
1153 return;
1157 const MultiSelection* pRowSelection = GetSelection();
1158 if ( pRowSelection && pRowSelection->IsAllSelected() )
1160 BeginCursorAction();
1161 CursorWrapper* pCursor = getDataSource();
1162 Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*pCursor), UNO_QUERY);
1165 pCursor->beforeFirst();
1166 while( pCursor->next() )
1167 xUpdateCursor->deleteRow();
1169 SetUpdateMode(false);
1170 SetNoSelection();
1172 xUpdateCursor->moveToInsertRow();
1174 catch(const Exception&)
1176 OSL_FAIL("Exception caught while deleting rows!");
1178 // An den DatenCursor anpassen
1179 AdjustDataSource(true);
1180 EndCursorAction();
1181 SetUpdateMode(true);
1183 else
1185 Reference< ::com::sun::star::sdbcx::XDeleteRows > xDeleteThem(Reference< XInterface >(*getDataSource()), UNO_QUERY);
1187 // collect the bookmarks of the selected rows
1188 Sequence < Any> aBookmarks = getSelectionBookmarks();
1190 // determine the next row to position after deletion
1191 Any aBookmark;
1192 bool bNewPos = false;
1193 // if the current row isn't selected we take the row as row after deletion
1194 OSL_ENSURE( GetCurrentRow().Is(), "FmGridControl::DeleteSelectedRows: no current row here?" );
1195 // crash reports suggest it can happen we don't have a current row - how?
1196 // #154303# / 2008-04-23 / frank.schoenheit@sun.com
1197 if ( !IsRowSelected( GetCurrentPos() ) && !IsCurrentAppending() && GetCurrentRow().Is() )
1199 aBookmark = GetCurrentRow()->GetBookmark();
1200 bNewPos = true;
1202 else
1204 // we look for the first row after the selected block for selection
1205 long nIdx = LastSelectedRow() + 1;
1206 if (nIdx < GetRowCount() - 1)
1208 // there is a next row to position on
1209 if (SeekCursor(nIdx))
1211 GetSeekRow()->SetState(m_pSeekCursor, true);
1213 bNewPos = true;
1214 // if it's not the row for inserting we keep the bookmark
1215 if (!IsInsertionRow(nIdx))
1216 aBookmark = m_pSeekCursor->getBookmark();
1219 else
1221 // we look for the first row before the selected block for selection after deletion
1222 nIdx = FirstSelectedRow() - 1;
1223 if (nIdx >= 0 && SeekCursor(nIdx))
1225 GetSeekRow()->SetState(m_pSeekCursor, true);
1227 bNewPos = true;
1228 aBookmark = m_pSeekCursor->getBookmark();
1233 // Sind alle Zeilen Selectiert
1234 // Zweite bedingung falls keine einguegeZeile existiert
1235 bool bAllSelected = GetTotalCount() == nSelectedRows || GetRowCount() == nSelectedRows;
1237 BeginCursorAction();
1239 // now delete the row
1240 Sequence<sal_Int32> aDeletedRows;
1241 SetUpdateMode( false );
1244 aDeletedRows = xDeleteThem->deleteRows(aBookmarks);
1246 catch(SQLException&)
1249 SetUpdateMode( true );
1251 // how many rows are deleted?
1252 sal_Int32 nDeletedRows = 0;
1253 const sal_Int32* pSuccess = aDeletedRows.getConstArray();
1254 for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++)
1256 if (pSuccess[i])
1257 ++nDeletedRows;
1260 // sind Zeilen geloescht worden?
1261 if (nDeletedRows)
1263 SetUpdateMode(false);
1264 SetNoSelection();
1267 // did we delete all the rows than try to move to the next possible row
1268 if (nDeletedRows == aDeletedRows.getLength())
1270 // there exists a new position to move on
1271 if (bNewPos)
1273 if (aBookmark.hasValue())
1274 getDataSource()->moveToBookmark(aBookmark);
1275 // no valid bookmark so move to the insert row
1276 else
1278 Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
1279 xUpdateCursor->moveToInsertRow();
1282 else
1284 Reference< ::com::sun::star::beans::XPropertySet > xSet(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
1286 sal_Int32 nRecordCount(0);
1287 xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
1288 if ( m_pDataCursor->rowDeleted() )
1289 --nRecordCount;
1291 // there are no rows left and we have an insert row
1292 if (!nRecordCount && GetEmptyRow().Is())
1294 Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
1295 xUpdateCursor->moveToInsertRow();
1297 else if (nRecordCount)
1298 // move to the first row
1299 getDataSource()->first();
1302 // not all the rows where deleted, so move to the first row which remained in the resultset
1303 else
1305 for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++)
1307 if (!pSuccess[i])
1309 getDataSource()->moveToBookmark(aBookmarks.getConstArray()[i]);
1310 break;
1315 catch(const Exception&)
1319 // positioning went wrong so try to move to the first row
1320 getDataSource()->first();
1322 catch(const Exception&)
1327 // An den DatenCursor anpassen
1328 AdjustDataSource(true);
1330 // es konnten nicht alle Zeilen geloescht werden
1331 // da nie nicht geloeschten wieder selektieren
1332 if (nDeletedRows < nSelectedRows)
1334 // waren alle selektiert
1335 if (bAllSelected)
1337 SelectAll();
1338 if (IsInsertionRow(GetRowCount() - 1)) // einfuegeZeile nicht
1339 SelectRow(GetRowCount() - 1, false);
1341 else
1343 // select the remaining rows
1344 for (sal_Int32 i = 0; i < aDeletedRows.getLength(); i++)
1348 if (!pSuccess[i])
1350 m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
1351 SetSeekPos(m_pSeekCursor->getRow() - 1);
1352 SelectRow(GetSeekPos());
1355 catch(const Exception&)
1357 // keep the seekpos in all cases
1358 SetSeekPos(m_pSeekCursor->getRow() - 1);
1364 EndCursorAction();
1365 SetUpdateMode(true);
1367 else // Zeile konnte nicht geloescht werden
1369 EndCursorAction();
1372 // currentrow is the insert row?
1373 if (!IsCurrentAppending())
1374 getDataSource()->refreshRow();
1376 catch(const Exception&)
1382 // if there is no selection anymore we can start editing
1383 if (!GetSelectRowCount())
1384 ActivateCell();
1387 // XCurrentRecordListener
1388 void FmGridControl::positioned(const ::com::sun::star::lang::EventObject& /*rEvent*/)
1390 SAL_INFO("svx.fmcomp", "FmGridControl::positioned");
1391 // position on the data source (force it to be done in the main thread)
1392 implAdjustInSolarThread(false);
1395 bool FmGridControl::commit()
1397 // Commit nur ausfuehren, wenn nicht bereits ein Update vom ::com::sun::star::form::component::GridControl ausgefuehrt
1398 // wird
1399 if (!IsUpdating())
1401 if (Controller().Is() && Controller()->IsModified())
1403 if (!SaveModified())
1404 return false;
1407 return true;
1410 void FmGridControl::inserted(const ::com::sun::star::lang::EventObject& /*rEvent*/)
1412 const DbGridRowRef& xRow = GetCurrentRow();
1413 if (!xRow.Is())
1414 return;
1416 // Zeile ist eingefuegt worden, dann den status und mode zuruecksetzen
1417 xRow->SetState(m_pDataCursor, false);
1418 xRow->SetNew(false);
1422 VclPtr<BrowserHeader> FmGridControl::imp_CreateHeaderBar(BrowseBox* pParent)
1424 DBG_ASSERT( pParent == this, "FmGridControl::imp_CreateHeaderBar: parent?" );
1425 return VclPtr<FmGridHeader>::Create( pParent );
1428 void FmGridControl::markColumn(sal_uInt16 nId)
1430 if (GetHeaderBar() && m_nMarkedColumnId != nId)
1432 // deselektieren
1433 if (m_nMarkedColumnId != BROWSER_INVALIDID)
1435 HeaderBarItemBits aBits = GetHeaderBar()->GetItemBits(m_nMarkedColumnId) & ~HeaderBarItemBits::FLAT;
1436 GetHeaderBar()->SetItemBits(m_nMarkedColumnId, aBits);
1440 if (nId != BROWSER_INVALIDID)
1442 HeaderBarItemBits aBits = GetHeaderBar()->GetItemBits(nId) | HeaderBarItemBits::FLAT;
1443 GetHeaderBar()->SetItemBits(nId, aBits);
1445 m_nMarkedColumnId = nId;
1449 bool FmGridControl::isColumnMarked(sal_uInt16 nId) const
1451 return m_nMarkedColumnId == nId;
1454 long FmGridControl::QueryMinimumRowHeight()
1456 long nMinimalLogicHeight = 20; // 0.2 cm
1457 long nMinimalPixelHeight = LogicToPixel( Point( 0, nMinimalLogicHeight ), MAP_10TH_MM ).Y();
1458 return CalcZoom( nMinimalPixelHeight );
1461 void FmGridControl::RowHeightChanged()
1463 DbGridControl::RowHeightChanged();
1465 Reference< XPropertySet > xModel( GetPeer()->getColumns(), UNO_QUERY );
1466 DBG_ASSERT( xModel.is(), "FmGridControl::RowHeightChanged: no model!" );
1467 if ( xModel.is() )
1471 sal_Int32 nUnzoomedPixelHeight = CalcReverseZoom( GetDataRowHeight() );
1472 Any aProperty = makeAny( (sal_Int32)PixelToLogic( Point( 0, nUnzoomedPixelHeight ), MAP_10TH_MM ).Y() );
1473 xModel->setPropertyValue( FM_PROP_ROWHEIGHT, aProperty );
1475 catch( const Exception& )
1477 OSL_FAIL( "FmGridControl::RowHeightChanged: caught an exception!" );
1482 void FmGridControl::ColumnResized(sal_uInt16 nId)
1484 DbGridControl::ColumnResized(nId);
1486 // Wert ans model uebergeben
1487 DbGridColumn* pCol = DbGridControl::GetColumns().at( GetModelColumnPos(nId) );
1488 Reference< ::com::sun::star::beans::XPropertySet > xColModel(pCol->getModel());
1489 if (xColModel.is())
1491 Any aWidth;
1492 sal_Int32 nColumnWidth = GetColumnWidth(nId);
1493 nColumnWidth = CalcReverseZoom(nColumnWidth);
1494 // Umrechnen in 10THMM
1495 aWidth <<= (sal_Int32)PixelToLogic(Point(nColumnWidth,0),MAP_10TH_MM).X();
1496 xColModel->setPropertyValue(FM_PROP_WIDTH, aWidth);
1500 void FmGridControl::CellModified()
1502 DbGridControl::CellModified();
1503 GetPeer()->CellModified();
1506 void FmGridControl::BeginCursorAction()
1508 DbGridControl::BeginCursorAction();
1509 m_pPeer->stopCursorListening();
1512 void FmGridControl::EndCursorAction()
1514 m_pPeer->startCursorListening();
1515 DbGridControl::EndCursorAction();
1518 void FmGridControl::ColumnMoved(sal_uInt16 nId)
1520 m_bInColumnMove = true;
1522 DbGridControl::ColumnMoved(nId);
1523 Reference< ::com::sun::star::container::XIndexContainer > xColumns(GetPeer()->getColumns());
1525 if (xColumns.is())
1527 // suchen der Spalte und verschieben im Model
1528 // ColumnPos holen
1529 DbGridColumn* pCol = DbGridControl::GetColumns().at( GetModelColumnPos(nId) );
1530 Reference< ::com::sun::star::beans::XPropertySet > xCol;
1532 // Einfuegen muss sich an den Column Positionen orientieren
1533 sal_Int32 i;
1534 Reference< XInterface > xCurrent;
1535 for (i = 0; !xCol.is() && i < xColumns->getCount(); i++)
1537 xCurrent.set(xColumns->getByIndex(i), css::uno::UNO_QUERY);
1538 if (xCurrent == pCol->getModel())
1540 xCol = pCol->getModel();
1541 break;
1545 DBG_ASSERT(i < xColumns->getCount(), "Falscher ::com::sun::star::sdbcx::Index");
1546 xColumns->removeByIndex(i);
1547 Any aElement;
1548 aElement <<= xCol;
1549 xColumns->insertByIndex(GetModelColumnPos(nId), aElement);
1550 pCol->setModel(xCol);
1551 // if the column which is shown here is selected ...
1552 if ( isColumnSelected(nId,pCol) )
1553 markColumn(nId); // ... -> mark it
1556 m_bInColumnMove = false;
1559 void FmGridControl::InitColumnsByModels(const Reference< ::com::sun::star::container::XIndexContainer >& xColumns)
1561 // Spalten wieder neu setzen
1562 // wenn es nur eine HandleColumn gibt, dann nicht
1563 if (GetModelColCount())
1565 RemoveColumns();
1566 InsertHandleColumn();
1569 if (!xColumns.is())
1570 return;
1572 SetUpdateMode(false);
1574 // Einfuegen muss sich an den Column Positionen orientieren
1575 sal_Int32 i;
1576 Any aWidth;
1577 for (i = 0; i < xColumns->getCount(); ++i)
1579 Reference< ::com::sun::star::beans::XPropertySet > xCol(
1580 xColumns->getByIndex(i), css::uno::UNO_QUERY);
1582 OUString aName(
1583 comphelper::getString(xCol->getPropertyValue(FM_PROP_LABEL)));
1585 aWidth = xCol->getPropertyValue(FM_PROP_WIDTH);
1586 sal_Int32 nWidth = 0;
1587 if (aWidth >>= nWidth)
1588 nWidth = LogicToPixel(Point(nWidth,0),MAP_10TH_MM).X();
1590 AppendColumn(aName, (sal_uInt16)nWidth);
1591 DbGridColumn* pCol = DbGridControl::GetColumns().at( i );
1592 pCol->setModel(xCol);
1595 // und jetzt noch die hidden columns rausnehmen
1596 // (wir haben das nicht gleich in der oberen Schleife gemacht, da wir dann Probleme mit den
1597 // IDs der Spalten bekommen haetten : AppendColumn vergibt die automatisch, die Spalte _nach_
1598 // einer versteckten braucht aber eine um eine erhoehte ID ....
1599 Any aHidden;
1600 for (i = 0; i < xColumns->getCount(); ++i)
1602 Reference< ::com::sun::star::beans::XPropertySet > xCol(
1603 xColumns->getByIndex(i), css::uno::UNO_QUERY);
1604 aHidden = xCol->getPropertyValue(FM_PROP_HIDDEN);
1605 if (::comphelper::getBOOL(aHidden))
1606 HideColumn(GetColumnIdFromModelPos((sal_uInt16)i));
1609 SetUpdateMode(true);
1612 void FmGridControl::InitColumnByField(
1613 DbGridColumn* _pColumn, const Reference< XPropertySet >& _rxColumnModel,
1614 const Reference< XNameAccess >& _rxFieldsByNames, const Reference< XIndexAccess >& _rxFieldsByIndex )
1616 DBG_ASSERT( _rxFieldsByNames == _rxFieldsByIndex, "FmGridControl::InitColumnByField: invalid container interfaces!" );
1618 // lookup the column which belongs to the control source
1619 OUString sFieldName;
1620 _rxColumnModel->getPropertyValue( FM_PROP_CONTROLSOURCE ) >>= sFieldName;
1621 Reference< XPropertySet > xField;
1622 _rxColumnModel->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField;
1625 if ( !xField.is() && /*sFieldName.getLength() && */_rxFieldsByNames->hasByName( sFieldName ) ) // #i93452# do not check for name length
1626 _rxFieldsByNames->getByName( sFieldName ) >>= xField;
1628 // determine the position of this column
1629 sal_Int32 nFieldPos = -1;
1630 if ( xField.is() )
1632 Reference< XPropertySet > xCheck;
1633 sal_Int32 nFieldCount = _rxFieldsByIndex->getCount();
1634 for ( sal_Int32 i = 0; i < nFieldCount; ++i)
1636 _rxFieldsByIndex->getByIndex( i ) >>= xCheck;
1637 if ( xField.get() == xCheck.get() )
1639 nFieldPos = i;
1640 break;
1645 if ( xField.is() && ( nFieldPos >= 0 ) )
1647 // some data types are not allowed
1648 sal_Int32 nDataType = DataType::OTHER;
1649 xField->getPropertyValue( FM_PROP_FIELDTYPE ) >>= nDataType;
1651 bool bIllegalType = false;
1652 switch ( nDataType )
1654 case DataType::BLOB:
1655 case DataType::LONGVARBINARY:
1656 case DataType::BINARY:
1657 case DataType::VARBINARY:
1658 case DataType::OTHER:
1659 bIllegalType = true;
1660 break;
1663 if ( bIllegalType )
1665 _pColumn->SetObject( (sal_Int16)nFieldPos );
1666 return;
1670 // the control type is determined by the ColumnServiceName
1671 static const char s_sPropColumnServiceName[] = "ColumnServiceName";
1672 if ( !::comphelper::hasProperty( s_sPropColumnServiceName, _rxColumnModel ) )
1673 return;
1675 _pColumn->setModel( _rxColumnModel );
1677 OUString sColumnServiceName;
1678 _rxColumnModel->getPropertyValue( s_sPropColumnServiceName ) >>= sColumnServiceName;
1680 sal_Int32 nTypeId = getColumnTypeByModelName( sColumnServiceName );
1681 _pColumn->CreateControl( nFieldPos, xField, nTypeId );
1684 void FmGridControl::InitColumnsByFields(const Reference< ::com::sun::star::container::XIndexAccess >& _rxFields)
1686 if ( !_rxFields.is() )
1687 return;
1689 // Spalten initialisieren
1690 Reference< XIndexContainer > xColumns( GetPeer()->getColumns() );
1691 Reference< XNameAccess > xFieldsAsNames( _rxFields, UNO_QUERY );
1693 // Einfuegen muss sich an den Column Positionen orientieren
1694 for (sal_Int32 i = 0; i < xColumns->getCount(); i++)
1696 DbGridColumn* pCol = GetColumns().at( i );
1697 OSL_ENSURE(pCol,"No grid column!");
1698 if ( pCol )
1700 Reference< XPropertySet > xColumnModel(
1701 xColumns->getByIndex( i ), css::uno::UNO_QUERY);
1703 InitColumnByField( pCol, xColumnModel, xFieldsAsNames, _rxFields );
1708 void FmGridControl::HideColumn(sal_uInt16 nId)
1710 DbGridControl::HideColumn(nId);
1712 sal_uInt16 nPos = GetModelColumnPos(nId);
1713 if (nPos == (sal_uInt16)-1)
1714 return;
1716 DbGridColumn* pColumn = GetColumns().at( nPos );
1717 if (pColumn->IsHidden())
1718 GetPeer()->columnHidden(pColumn);
1720 if (nId == m_nMarkedColumnId)
1721 m_nMarkedColumnId = (sal_uInt16)-1;
1724 bool FmGridControl::isColumnSelected(sal_uInt16 /*nId*/,DbGridColumn* _pColumn)
1726 OSL_ENSURE(_pColumn,"Column can not be null!");
1727 bool bSelected = false;
1728 // if the column which is shown here is selected ...
1729 Reference< ::com::sun::star::view::XSelectionSupplier > xSelSupplier(GetPeer()->getColumns(), UNO_QUERY);
1730 if ( xSelSupplier.is() )
1732 Reference< ::com::sun::star::beans::XPropertySet > xColumn;
1733 xSelSupplier->getSelection() >>= xColumn;
1734 bSelected = (xColumn.get() == _pColumn->getModel().get());
1736 return bSelected;
1739 void FmGridControl::ShowColumn(sal_uInt16 nId)
1741 DbGridControl::ShowColumn(nId);
1743 sal_uInt16 nPos = GetModelColumnPos(nId);
1744 if (nPos == (sal_uInt16)-1)
1745 return;
1747 DbGridColumn* pColumn = GetColumns().at( nPos );
1748 if (!pColumn->IsHidden())
1749 GetPeer()->columnVisible(pColumn);
1751 // if the column which is shown here is selected ...
1752 if ( isColumnSelected(nId,pColumn) )
1753 markColumn(nId); // ... -> mark it
1756 bool FmGridControl::selectBookmarks(const Sequence< Any >& _rBookmarks)
1758 SolarMutexGuard aGuard;
1759 // need to lock the SolarMutex so that no paint call disturbs us ...
1761 if ( !m_pSeekCursor )
1763 OSL_FAIL( "FmGridControl::selectBookmarks: no seek cursor!" );
1764 return false;
1767 const Any* pBookmark = _rBookmarks.getConstArray();
1768 const Any* pBookmarkEnd = pBookmark + _rBookmarks.getLength();
1770 SetNoSelection();
1772 bool bAllSuccessfull = true;
1775 for (; pBookmark != pBookmarkEnd; ++pBookmark)
1777 // move the seek cursor to the row given
1778 if (m_pSeekCursor->moveToBookmark(*pBookmark))
1779 SelectRow( m_pSeekCursor->getRow() - 1);
1780 else
1781 bAllSuccessfull = false;
1784 catch(Exception&)
1786 OSL_FAIL("FmGridControl::selectBookmarks: could not move to one of the bookmarks!");
1787 return false;
1790 return bAllSuccessfull;
1793 Sequence< Any> FmGridControl::getSelectionBookmarks()
1795 // lock our update so no paint-triggered seeks interfere ...
1796 SetUpdateMode(false);
1798 sal_Int32 nSelectedRows = GetSelectRowCount(), i = 0;
1799 Sequence< Any> aBookmarks(nSelectedRows);
1800 if ( nSelectedRows )
1802 Any* pBookmarks = (Any*)aBookmarks.getArray();
1804 // (I'm not sure if the problem isn't deeper : The szenario : a large table displayed by a grid with a
1805 // thread-safe cursor (dBase). On loading the sdb-cursor started a counting thread. While this counting progress
1806 // was running, I tried do delete 3 records from within the grid. Deletion caused a SeekCursor, which did a
1807 // m_pSeekCursor->moveRelative and a m_pSeekCursor->getPosition.
1808 // Unfortunally the first call caused a propertyChanged(RECORDCOUNT) which resulted in a repaint of the
1809 // navigation bar and the grid. The latter itself will result in SeekRow calls. So after (successfully) returning
1810 // from the moveRelative the getPosition returns an invalid value. And so the SeekCursor fails.
1811 // In the consequence ALL parts of code where two calls to the seek cursor are done, while the second call _relys_ on
1812 // the first one, should be secured against recursion, with a broad-minded interpretion of "recursion" : if any of these
1813 // code parts is executed, no other should be accessible. But this sounds very difficult to achieve ....
1814 // )
1816 // The next problem caused by the same behaviuor (SeekCursor causes a propertyChanged) : when adjusting rows we implicitly
1817 // change our selection. So a "FirstSelected(); SeekCursor(); NextSelected();" may produce unpredictable results.
1818 // That's why we _first_ collect the indices of the selected rows and _then_ their bookmarks.
1819 long nIdx = FirstSelectedRow();
1820 while (nIdx >= 0)
1822 // (we misuse the bookmarks array for this ...)
1823 pBookmarks[i++] <<= (sal_Int32)nIdx;
1824 nIdx = NextSelectedRow();
1826 DBG_ASSERT(i == nSelectedRows, "FmGridControl::DeleteSelectedRows : could not collect the row indices !");
1828 for (i=0; i<nSelectedRows; ++i)
1830 nIdx = ::comphelper::getINT32(pBookmarks[i]);
1831 if (IsInsertionRow(nIdx))
1833 // leerzeile nicht loeschen
1834 aBookmarks.realloc(--nSelectedRows);
1835 SelectRow(nIdx, false); // selection aufheben fuer leerzeile
1836 break;
1839 // Zunaechst den DatenCursor auf den selektierten Satz pos.
1840 if (SeekCursor(nIdx))
1842 GetSeekRow()->SetState(m_pSeekCursor, true);
1844 pBookmarks[i] = m_pSeekCursor->getBookmark();
1846 #ifdef DBG_UTIL
1847 else
1848 OSL_FAIL("FmGridControl::DeleteSelectedRows : a bookmark could not be determined !");
1849 #endif
1852 SetUpdateMode(true);
1854 // if one of the SeekCursor-calls failed ....
1855 aBookmarks.realloc(i);
1857 // (the alternative : while collecting the bookmarks lock our propertyChanged, this should resolve both our problems.
1858 // but this would be incompatible as we need a locking flag, then ...)
1860 return aBookmarks;
1863 namespace
1865 OUString getColumnPropertyFromPeer(FmXGridPeer* _pPeer,sal_Int32 _nPosition,const OUString& _sPropName)
1867 OUString sRetText;
1868 if ( _pPeer && _nPosition != -1)
1870 Reference<XIndexContainer> xIndex = _pPeer->getColumns();
1871 if ( xIndex.is() && xIndex->getCount() > _nPosition )
1873 Reference<XPropertySet> xProp;
1874 xIndex->getByIndex( _nPosition ) >>= xProp;
1875 if ( xProp.is() )
1877 try {
1878 xProp->getPropertyValue( _sPropName ) >>= sRetText;
1879 } catch (UnknownPropertyException const& e) {
1880 SAL_WARN("svx.form",
1881 "exception caught: " << e.Message);
1886 return sRetText;
1890 // Object data and state
1891 OUString FmGridControl::GetAccessibleObjectName( ::svt::AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const
1893 OUString sRetText;
1894 switch( _eObjType )
1896 case ::svt::BBTYPE_BROWSEBOX:
1897 if ( GetPeer() )
1899 Reference<XPropertySet> xProp(GetPeer()->getColumns(),UNO_QUERY);
1900 if ( xProp.is() )
1901 xProp->getPropertyValue(FM_PROP_NAME) >>= sRetText;
1903 break;
1904 case ::svt::BBTYPE_COLUMNHEADERCELL:
1905 sRetText = getColumnPropertyFromPeer(
1906 GetPeer(),
1907 GetModelColumnPos(
1908 sal::static_int_cast< sal_uInt16 >(_nPosition)),
1909 FM_PROP_LABEL);
1910 break;
1911 default:
1912 sRetText = DbGridControl::GetAccessibleObjectName(_eObjType,_nPosition);
1914 return sRetText;
1917 OUString FmGridControl::GetAccessibleObjectDescription( ::svt::AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const
1919 OUString sRetText;
1920 switch( _eObjType )
1922 case ::svt::BBTYPE_BROWSEBOX:
1923 if ( GetPeer() )
1925 Reference<XPropertySet> xProp(GetPeer()->getColumns(),UNO_QUERY);
1926 if ( xProp.is() )
1928 xProp->getPropertyValue(FM_PROP_HELPTEXT) >>= sRetText;
1929 if ( sRetText.isEmpty() )
1930 xProp->getPropertyValue(FM_PROP_DESCRIPTION) >>= sRetText;
1933 break;
1934 case ::svt::BBTYPE_COLUMNHEADERCELL:
1935 sRetText = getColumnPropertyFromPeer(
1936 GetPeer(),
1937 GetModelColumnPos(
1938 sal::static_int_cast< sal_uInt16 >(_nPosition)),
1939 FM_PROP_HELPTEXT);
1940 if ( sRetText.isEmpty() )
1941 sRetText = getColumnPropertyFromPeer(
1942 GetPeer(),
1943 GetModelColumnPos(
1944 sal::static_int_cast< sal_uInt16 >(_nPosition)),
1945 FM_PROP_DESCRIPTION);
1947 break;
1948 default:
1949 sRetText = DbGridControl::GetAccessibleObjectDescription(_eObjType,_nPosition);
1951 return sRetText;
1954 void FmGridControl::Select()
1956 DbGridControl::Select();
1957 // ... betrifft das unsere Spalten ?
1958 const MultiSelection* pColumnSelection = GetColumnSelection();
1960 sal_uInt16 nSelectedColumn =
1961 pColumnSelection && pColumnSelection->GetSelectCount()
1962 ? sal::static_int_cast< sal_uInt16 >(
1963 const_cast<MultiSelection*>(pColumnSelection)->FirstSelected())
1964 : SAL_MAX_UINT16;
1965 // die HandleColumn wird nicht selektiert
1966 switch (nSelectedColumn)
1968 case SAL_MAX_UINT16: break; // no selection
1969 case 0 : nSelectedColumn = SAL_MAX_UINT16; break;
1970 // handle col can't be seledted
1971 default :
1972 // get the model col pos instead of the view col pos
1973 nSelectedColumn = GetModelColumnPos(GetColumnIdFromViewPos(nSelectedColumn - 1));
1974 break;
1977 if (nSelectedColumn != m_nCurrentSelectedColumn)
1979 // VOR dem Aufruf des select am SelectionSupplier !
1980 m_nCurrentSelectedColumn = nSelectedColumn;
1982 if (!m_bSelecting)
1984 m_bSelecting = true;
1988 Reference< XIndexAccess > xColumns(GetPeer()->getColumns(), UNO_QUERY);
1989 Reference< XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
1990 if (xSelSupplier.is())
1992 if (nSelectedColumn != SAL_MAX_UINT16)
1994 Reference< XPropertySet > xColumn(
1995 xColumns->getByIndex(nSelectedColumn),
1996 css::uno::UNO_QUERY);
1997 xSelSupplier->select(makeAny(xColumn));
1999 else
2001 xSelSupplier->select(Any());
2005 catch(Exception&)
2010 m_bSelecting = false;
2016 void FmGridControl::KeyInput( const KeyEvent& rKEvt )
2018 bool bDone = false;
2019 const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
2020 if ( IsDesignMode()
2021 && !rKeyCode.IsShift()
2022 && !rKeyCode.IsMod1()
2023 && !rKeyCode.IsMod2()
2024 && GetParent() )
2026 switch ( rKeyCode.GetCode() )
2028 case KEY_ESCAPE:
2029 GetParent()->GrabFocus();
2030 bDone = true;
2031 break;
2032 case KEY_DELETE:
2033 if ( GetSelectColumnCount() && GetPeer() && m_nCurrentSelectedColumn >= 0 )
2035 Reference< ::com::sun::star::container::XIndexContainer > xCols(GetPeer()->getColumns());
2036 if ( xCols.is() )
2040 if ( m_nCurrentSelectedColumn < xCols->getCount() )
2042 Reference< XInterface > xCol;
2043 xCols->getByIndex(m_nCurrentSelectedColumn) >>= xCol;
2044 xCols->removeByIndex(m_nCurrentSelectedColumn);
2045 ::comphelper::disposeComponent(xCol);
2048 catch(const Exception&)
2050 OSL_FAIL("exception occurred while deleting a column");
2054 bDone = true;
2055 break;
2058 if ( !bDone )
2059 DbGridControl::KeyInput( rKEvt );
2062 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */