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