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