Line data Source code
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 <sal/macros.h>
21 : #include "fmhelp.hrc"
22 : #include <svx/gridctrl.hxx>
23 : #include "gridcell.hxx"
24 : #include "svx/dbtoolsclient.hxx"
25 : #include "svx/fmtools.hxx"
26 : #include <svtools/stringtransfer.hxx>
27 : #include <connectivity/dbtools.hxx>
28 : #include <connectivity/dbconversion.hxx>
29 :
30 : #include "fmprop.hrc"
31 : #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
32 : #include <com/sun/star/accessibility/XAccessible.hpp>
33 : #include <com/sun/star/sdb/XResultSetAccess.hpp>
34 : #include <com/sun/star/sdb/RowChangeAction.hpp>
35 : #include <com/sun/star/sdb/XRowsChangeBroadcaster.hpp>
36 : #include <com/sun/star/sdbc/XResultSetUpdate.hpp>
37 : #include <com/sun/star/sdbcx/Privilege.hpp>
38 : #include <com/sun/star/container/XChild.hpp>
39 : #include <com/sun/star/util/NumberFormatter.hpp>
40 : #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
41 : #include <com/sun/star/util/XCloneable.hpp>
42 : #include <com/sun/star/beans/XPropertySet.hpp>
43 : #include <com/sun/star/beans/PropertyChangeEvent.hpp>
44 : #include <comphelper/processfactory.hxx>
45 : #include <tools/resid.hxx>
46 : #include <tools/diagnose_ex.h>
47 : #include <vcl/menu.hxx>
48 : #include <vcl/settings.hxx>
49 :
50 : #include "svx/fmresids.hrc"
51 :
52 : #include <svx/svxids.hrc>
53 : #include <svx/dialmgr.hxx>
54 : #include "fmservs.hxx"
55 : #include "sdbdatacolumn.hxx"
56 :
57 : #include <comphelper/property.hxx>
58 :
59 : #include <algorithm>
60 : #include <cstdlib>
61 : #include <map>
62 :
63 : using namespace ::dbtools;
64 : using namespace ::dbtools::DBTypeConversion;
65 : using namespace ::svxform;
66 : using namespace ::svt;
67 : using namespace ::com::sun::star::beans;
68 : using namespace ::com::sun::star::lang;
69 : using namespace ::com::sun::star::uno;
70 : using namespace ::com::sun::star::sdbc;
71 : using namespace ::com::sun::star::sdbcx;
72 : using namespace ::com::sun::star::sdb;
73 : using namespace ::com::sun::star::datatransfer;
74 : using namespace ::com::sun::star::container;
75 : using namespace com::sun::star::accessibility;
76 :
77 : #define ROWSTATUS(row) (!row.Is() ? "NULL" : row->GetStatus() == GRS_CLEAN ? "CLEAN" : row->GetStatus() == GRS_MODIFIED ? "MODIFIED" : row->GetStatus() == GRS_DELETED ? "DELETED" : "INVALID")
78 :
79 : #define DEFAULT_BROWSE_MODE \
80 : BROWSER_COLUMNSELECTION \
81 : | BROWSER_MULTISELECTION \
82 : | BROWSER_KEEPSELECTION \
83 : | BROWSER_TRACKING_TIPS \
84 : | BROWSER_HLINESFULL \
85 : | BROWSER_VLINESFULL \
86 : | BROWSER_HEADERBAR_NEW \
87 :
88 4 : class RowSetEventListener : public ::cppu::WeakImplHelper1<XRowsChangeListener>
89 : {
90 : DbGridControl* m_pControl;
91 : public:
92 2 : RowSetEventListener(DbGridControl* i_pControl) : m_pControl(i_pControl)
93 : {
94 2 : }
95 :
96 : private:
97 : // XEventListener
98 2 : virtual void SAL_CALL disposing(const ::com::sun::star::lang::EventObject& /*i_aEvt*/) throw ( RuntimeException, std::exception ) SAL_OVERRIDE
99 : {
100 2 : }
101 0 : virtual void SAL_CALL rowsChanged(const ::com::sun::star::sdb::RowsChangeEvent& i_aEvt) throw ( RuntimeException, std::exception ) SAL_OVERRIDE
102 : {
103 0 : if ( i_aEvt.Action == RowChangeAction::UPDATE )
104 : {
105 0 : ::DbGridControl::GrantControlAccess aAccess;
106 0 : CursorWrapper* pSeek = m_pControl->GetSeekCursor(aAccess);
107 0 : const DbGridRowRef& rSeekRow = m_pControl->GetSeekRow(aAccess);
108 0 : const Any* pIter = i_aEvt.Bookmarks.getConstArray();
109 0 : const Any* pEnd = pIter + i_aEvt.Bookmarks.getLength();
110 0 : for(;pIter != pEnd;++pIter)
111 : {
112 0 : pSeek->moveToBookmark(*pIter);
113 : // get the data
114 0 : rSeekRow->SetState(pSeek, true);
115 0 : sal_Int32 nSeekPos = pSeek->getRow() - 1;
116 0 : m_pControl->SetSeekPos(nSeekPos,aAccess);
117 0 : m_pControl->RowModified(nSeekPos);
118 : }
119 : }
120 0 : }
121 : };
122 :
123 : class GridFieldValueListener;
124 : typedef std::map<sal_uInt16, GridFieldValueListener*> ColumnFieldValueListeners;
125 :
126 : class GridFieldValueListener : protected ::comphelper::OPropertyChangeListener
127 : {
128 : osl::Mutex m_aMutex;
129 : DbGridControl& m_rParent;
130 : ::comphelper::OPropertyChangeMultiplexer* m_pRealListener;
131 : sal_uInt16 m_nId;
132 : sal_Int16 m_nSuspended;
133 : bool m_bDisposed : 1;
134 :
135 : public:
136 : GridFieldValueListener(DbGridControl& _rParent, const Reference< XPropertySet >& xField, sal_uInt16 _nId);
137 : virtual ~GridFieldValueListener();
138 :
139 : virtual void _propertyChanged(const PropertyChangeEvent& evt) throw( RuntimeException ) SAL_OVERRIDE;
140 :
141 62 : void suspend() { ++m_nSuspended; }
142 62 : void resume() { --m_nSuspended; }
143 :
144 : void dispose();
145 : };
146 :
147 62 : GridFieldValueListener::GridFieldValueListener(DbGridControl& _rParent, const Reference< XPropertySet >& _rField, sal_uInt16 _nId)
148 : :OPropertyChangeListener(m_aMutex)
149 : ,m_rParent(_rParent)
150 : ,m_pRealListener(NULL)
151 : ,m_nId(_nId)
152 : ,m_nSuspended(0)
153 62 : ,m_bDisposed(false)
154 : {
155 62 : if (_rField.is())
156 : {
157 62 : m_pRealListener = new ::comphelper::OPropertyChangeMultiplexer(this, _rField);
158 62 : m_pRealListener->addProperty(FM_PROP_VALUE);
159 62 : m_pRealListener->acquire();
160 : }
161 62 : }
162 :
163 186 : GridFieldValueListener::~GridFieldValueListener()
164 : {
165 62 : dispose();
166 124 : }
167 :
168 0 : void GridFieldValueListener::_propertyChanged(const PropertyChangeEvent& _evt) throw( RuntimeException )
169 : {
170 : DBG_ASSERT(m_nSuspended>=0, "GridFieldValueListener::_propertyChanged : resume > suspend !");
171 0 : if (m_nSuspended <= 0)
172 0 : m_rParent.FieldValueChanged(m_nId, _evt);
173 0 : }
174 :
175 124 : void GridFieldValueListener::dispose()
176 : {
177 124 : if (m_bDisposed)
178 : {
179 : DBG_ASSERT(m_pRealListener == NULL, "GridFieldValueListener::dispose : inconsistent !");
180 186 : return;
181 : }
182 :
183 62 : if (m_pRealListener)
184 : {
185 62 : m_pRealListener->dispose();
186 62 : m_pRealListener->release();
187 62 : m_pRealListener = NULL;
188 : }
189 :
190 62 : m_bDisposed = true;
191 62 : m_rParent.FieldListenerDisposing(m_nId);
192 : }
193 :
194 : class DisposeListenerGridBridge : public FmXDisposeListener
195 : {
196 : osl::Mutex m_aMutex;
197 : DbGridControl& m_rParent;
198 : FmXDisposeMultiplexer* m_pRealListener;
199 :
200 : public:
201 : DisposeListenerGridBridge( DbGridControl& _rParent, const Reference< XComponent >& _rxObject, sal_Int16 _rId = -1);
202 : virtual ~DisposeListenerGridBridge();
203 :
204 2 : virtual void disposing(const EventObject& _rEvent, sal_Int16 _nId) throw( RuntimeException ) SAL_OVERRIDE { m_rParent.disposing(_nId, _rEvent); }
205 : };
206 :
207 2 : DisposeListenerGridBridge::DisposeListenerGridBridge(DbGridControl& _rParent, const Reference< XComponent >& _rxObject, sal_Int16 _rId)
208 : :FmXDisposeListener(m_aMutex)
209 : ,m_rParent(_rParent)
210 2 : ,m_pRealListener(NULL)
211 : {
212 :
213 2 : if (_rxObject.is())
214 : {
215 2 : m_pRealListener = new FmXDisposeMultiplexer(this, _rxObject, _rId);
216 2 : m_pRealListener->acquire();
217 : }
218 2 : }
219 :
220 6 : DisposeListenerGridBridge::~DisposeListenerGridBridge()
221 : {
222 2 : if (m_pRealListener)
223 : {
224 2 : m_pRealListener->dispose();
225 2 : m_pRealListener->release();
226 2 : m_pRealListener = NULL;
227 : }
228 :
229 4 : }
230 :
231 : static const sal_uInt16 ControlMap[] =
232 : {
233 : DbGridControl::NavigationBar::RECORD_TEXT,
234 : DbGridControl::NavigationBar::RECORD_ABSOLUTE,
235 : DbGridControl::NavigationBar::RECORD_OF,
236 : DbGridControl::NavigationBar::RECORD_COUNT,
237 : DbGridControl::NavigationBar::RECORD_FIRST,
238 : DbGridControl::NavigationBar::RECORD_NEXT,
239 : DbGridControl::NavigationBar::RECORD_PREV,
240 : DbGridControl::NavigationBar::RECORD_LAST,
241 : DbGridControl::NavigationBar::RECORD_NEW,
242 : 0
243 : };
244 :
245 0 : bool CompareBookmark(const Any& aLeft, const Any& aRight)
246 : {
247 0 : return ::comphelper::compare(aLeft, aRight);
248 : }
249 :
250 4 : class FmXGridSourcePropListener : public ::comphelper::OPropertyChangeListener
251 : {
252 : DbGridControl* m_pParent;
253 :
254 : // a DbGridControl has no mutex, so we use our own as the base class expects one
255 : osl::Mutex m_aMutex;
256 : sal_Int16 m_nSuspended;
257 :
258 : public:
259 : FmXGridSourcePropListener(DbGridControl* _pParent);
260 :
261 2 : void suspend() { ++m_nSuspended; }
262 2 : void resume() { --m_nSuspended; }
263 :
264 : virtual void _propertyChanged(const PropertyChangeEvent& evt) throw( RuntimeException ) SAL_OVERRIDE;
265 : };
266 :
267 2 : FmXGridSourcePropListener::FmXGridSourcePropListener(DbGridControl* _pParent)
268 : :OPropertyChangeListener(m_aMutex)
269 : ,m_pParent(_pParent)
270 2 : ,m_nSuspended(0)
271 : {
272 : DBG_ASSERT(m_pParent, "FmXGridSourcePropListener::FmXGridSourcePropListener : invalid parent !");
273 2 : }
274 :
275 0 : void FmXGridSourcePropListener::_propertyChanged(const PropertyChangeEvent& evt) throw( RuntimeException )
276 : {
277 : DBG_ASSERT(m_nSuspended>=0, "FmXGridSourcePropListener::_propertyChanged : resume > suspend !");
278 0 : if (m_nSuspended <= 0)
279 0 : m_pParent->DataSourcePropertyChanged(evt);
280 0 : }
281 :
282 41 : DbGridControl::NavigationBar::AbsolutePos::AbsolutePos(vcl::Window* pParent, WinBits nStyle)
283 41 : :NumericField(pParent, nStyle)
284 : {
285 41 : SetMin(1);
286 41 : SetFirst(1);
287 41 : SetSpinSize(1);
288 :
289 41 : SetDecimalDigits(0);
290 41 : SetStrictFormat(true);
291 41 : }
292 :
293 0 : void DbGridControl::NavigationBar::AbsolutePos::KeyInput(const KeyEvent& rEvt)
294 : {
295 0 : if (rEvt.GetKeyCode() == KEY_RETURN && !GetText().isEmpty())
296 : {
297 0 : sal_Int64 nRecord = GetValue();
298 0 : if (nRecord < GetMin() || nRecord > GetMax())
299 0 : return;
300 : else
301 0 : static_cast<NavigationBar*>(GetParent())->PositionDataSource(static_cast<sal_Int32>(nRecord));
302 : }
303 0 : else if (rEvt.GetKeyCode() == KEY_TAB)
304 0 : GetParent()->GetParent()->GrabFocus();
305 : else
306 0 : NumericField::KeyInput(rEvt);
307 : }
308 :
309 0 : void DbGridControl::NavigationBar::AbsolutePos::LoseFocus()
310 : {
311 0 : NumericField::LoseFocus();
312 0 : sal_Int64 nRecord = GetValue();
313 0 : if (nRecord < GetMin() || nRecord > GetMax())
314 0 : return;
315 : else
316 : {
317 0 : static_cast<NavigationBar*>(GetParent())->PositionDataSource(static_cast<sal_Int32>(nRecord));
318 0 : static_cast<NavigationBar*>(GetParent())->InvalidateState(NavigationBar::RECORD_ABSOLUTE);
319 : }
320 : }
321 :
322 0 : void DbGridControl::NavigationBar::PositionDataSource(sal_Int32 nRecord)
323 : {
324 0 : if (m_bPositioning)
325 0 : return;
326 : // the MoveToPosition may cause a LoseFocus which would lead to a second MoveToPosition,
327 : // so protect against this recursion
328 0 : m_bPositioning = true;
329 0 : static_cast<DbGridControl*>(GetParent())->MoveToPosition(nRecord - 1);
330 0 : m_bPositioning = false;
331 : }
332 :
333 41 : DbGridControl::NavigationBar::NavigationBar(vcl::Window* pParent, WinBits nStyle)
334 : :Control(pParent, nStyle)
335 : ,m_aRecordText(this, WB_VCENTER)
336 : ,m_aAbsolute(this, WB_CENTER | WB_VCENTER)
337 : ,m_aRecordOf(this, WB_VCENTER)
338 : ,m_aRecordCount(this, WB_VCENTER)
339 : ,m_aFirstBtn(this, WB_RECTSTYLE|WB_NOPOINTERFOCUS)
340 : ,m_aPrevBtn(this, WB_REPEAT|WB_RECTSTYLE|WB_NOPOINTERFOCUS)
341 : ,m_aNextBtn(this, WB_REPEAT|WB_RECTSTYLE|WB_NOPOINTERFOCUS)
342 : ,m_aLastBtn(this, WB_RECTSTYLE|WB_NOPOINTERFOCUS)
343 : ,m_aNewBtn(this, WB_RECTSTYLE|WB_NOPOINTERFOCUS)
344 : ,m_nDefaultWidth(0)
345 : ,m_nCurrentPos(-1)
346 41 : ,m_bPositioning(false)
347 : {
348 41 : m_aFirstBtn.SetSymbol(SymbolType::FIRST);
349 41 : m_aPrevBtn.SetSymbol(SymbolType::PREV);
350 41 : m_aNextBtn.SetSymbol(SymbolType::NEXT);
351 41 : m_aLastBtn.SetSymbol(SymbolType::LAST);
352 41 : m_aNewBtn.SetModeImage(static_cast<DbGridControl*>(pParent)->GetImage(DbGridControl_Base::NEW));
353 :
354 41 : m_aFirstBtn.SetHelpId(HID_GRID_TRAVEL_FIRST);
355 41 : m_aPrevBtn.SetHelpId(HID_GRID_TRAVEL_PREV);
356 41 : m_aNextBtn.SetHelpId(HID_GRID_TRAVEL_NEXT);
357 41 : m_aLastBtn.SetHelpId(HID_GRID_TRAVEL_LAST);
358 41 : m_aNewBtn.SetHelpId(HID_GRID_TRAVEL_NEW);
359 41 : m_aAbsolute.SetHelpId(HID_GRID_TRAVEL_ABSOLUTE);
360 41 : m_aRecordCount.SetHelpId(HID_GRID_NUMBEROFRECORDS);
361 :
362 : // Handler fuer Buttons einrichten
363 41 : m_aFirstBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
364 41 : m_aPrevBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
365 41 : m_aNextBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
366 41 : m_aLastBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
367 41 : m_aNewBtn.SetClickHdl(LINK(this,NavigationBar,OnClick));
368 :
369 41 : m_aRecordText.SetText(SVX_RESSTR(RID_STR_REC_TEXT));
370 41 : m_aRecordOf.SetText(SVX_RESSTR(RID_STR_REC_FROM_TEXT));
371 41 : m_aRecordCount.SetText(OUString('?'));
372 :
373 41 : m_nDefaultWidth = ArrangeControls();
374 :
375 41 : m_aFirstBtn.Disable();
376 41 : m_aPrevBtn.Disable();
377 41 : m_aNextBtn.Disable();
378 41 : m_aLastBtn.Disable();
379 41 : m_aNewBtn.Disable();
380 41 : m_aRecordText.Disable();
381 41 : m_aRecordOf.Disable();
382 41 : m_aRecordCount.Disable();
383 41 : m_aAbsolute.Disable();
384 :
385 41 : AllSettings aSettings = m_aNextBtn.GetSettings();
386 82 : MouseSettings aMouseSettings = aSettings.GetMouseSettings();
387 41 : aMouseSettings.SetButtonRepeat(aMouseSettings.GetButtonRepeat() / 4);
388 41 : aSettings.SetMouseSettings(aMouseSettings);
389 41 : m_aNextBtn.SetSettings(aSettings, true);
390 41 : m_aPrevBtn.SetSettings(aSettings, true);
391 :
392 41 : m_aFirstBtn.Show();
393 41 : m_aPrevBtn.Show();
394 41 : m_aNextBtn.Show();
395 41 : m_aLastBtn.Show();
396 41 : m_aNewBtn.Show();
397 41 : m_aRecordText.Show();
398 41 : m_aRecordOf.Show();
399 41 : m_aRecordCount.Show();
400 82 : m_aAbsolute.Show();
401 41 : }
402 :
403 : namespace
404 : {
405 600 : void SetPosAndSize(Button& _rButton,Point& _rPos,const Size& _rSize)
406 : {
407 600 : _rButton.SetPosPixel( _rPos );
408 600 : _rButton.SetSizePixel( _rSize );
409 600 : _rPos.X() += (sal_uInt16)_rSize.Width();
410 600 : }
411 : }
412 :
413 120 : sal_uInt16 DbGridControl::NavigationBar::ArrangeControls()
414 : {
415 : // positioning of the controls
416 : // calculate base size
417 120 : Rectangle aRect(static_cast<DbGridControl*>(GetParent())->GetControlArea());
418 120 : const long nH = aRect.GetSize().Height();
419 120 : Size aBorder = LogicToPixel(Size(2, 2),MAP_APPFONT);
420 120 : aBorder = Size(CalcZoom(aBorder.Width()), CalcZoom(aBorder.Height()));
421 120 : sal_uInt16 nX = 1;
422 120 : sal_uInt16 nY = 0;
423 :
424 : // Is the font of this edit larger than the field?
425 120 : if (m_aAbsolute.GetTextHeight() > nH)
426 : {
427 0 : vcl::Font aApplFont (m_aAbsolute.GetFont());
428 0 : const Size pointAbsoluteSize(m_aAbsolute.PixelToLogic( Size( 0, nH - 2 ), MapMode(MAP_POINT) ));
429 0 : aApplFont.SetSize( pointAbsoluteSize );
430 0 : m_aAbsolute.SetControlFont( aApplFont );
431 :
432 0 : aApplFont.SetTransparent( true );
433 0 : m_aRecordText.SetControlFont( aApplFont );
434 0 : m_aRecordOf.SetControlFont( aApplFont );
435 0 : m_aRecordCount.SetControlFont( aApplFont );
436 : }
437 :
438 : // set size and position of the control
439 120 : OUString aText = m_aRecordText.GetText();
440 120 : long nTextWidth = m_aRecordText.GetTextWidth(aText);
441 120 : m_aRecordText.SetPosPixel(Point(nX,nY));
442 120 : m_aRecordText.SetSizePixel(Size(nTextWidth,nH));
443 120 : nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
444 :
445 : // count an extra hairspace (U+200A) left and right
446 240 : const OUString sevenDigits(m_aAbsolute.CreateFieldText(6000000));
447 240 : const OUString hairSpace(static_cast<sal_Unicode>(0x200A));
448 240 : OUString textPattern(hairSpace);
449 120 : textPattern += sevenDigits;
450 120 : textPattern += hairSpace;
451 120 : nTextWidth = m_aAbsolute.GetTextWidth( textPattern );
452 120 : m_aAbsolute.SetPosPixel(Point(nX,nY));
453 120 : m_aAbsolute.SetSizePixel(Size(nTextWidth, nH));
454 120 : nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
455 :
456 120 : aText = m_aRecordOf.GetText();
457 120 : nTextWidth = m_aRecordOf.GetTextWidth(aText);
458 120 : m_aRecordOf.SetPosPixel(Point(nX,nY));
459 120 : m_aRecordOf.SetSizePixel(Size(nTextWidth,nH));
460 120 : nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
461 :
462 120 : textPattern = sevenDigits + " * (" + sevenDigits + ")";
463 120 : nTextWidth = m_aRecordCount.GetTextWidth( textPattern );
464 120 : m_aRecordCount.SetPosPixel(Point(nX,nY));
465 120 : m_aRecordCount.SetSizePixel(Size(nTextWidth,nH));
466 120 : nX = sal::static_int_cast< sal_uInt16 >(nX + nTextWidth + aBorder.Width());
467 :
468 120 : Point aButtonPos(nX,nY);
469 120 : const Size aButtonSize(nH,nH);
470 120 : SetPosAndSize(m_aFirstBtn, aButtonPos, aButtonSize);
471 120 : SetPosAndSize(m_aPrevBtn, aButtonPos, aButtonSize);
472 120 : SetPosAndSize(m_aNextBtn, aButtonPos, aButtonSize);
473 120 : SetPosAndSize(m_aLastBtn, aButtonPos, aButtonSize);
474 120 : SetPosAndSize(m_aNewBtn, aButtonPos, aButtonSize);
475 :
476 120 : nX = sal::static_int_cast< sal_uInt16 >(aButtonPos.X() + 1);
477 :
478 240 : return nX;
479 : }
480 :
481 0 : IMPL_LINK(DbGridControl::NavigationBar, OnClick, Button *, pButton )
482 : {
483 0 : DbGridControl* pParent = static_cast<DbGridControl*>(GetParent());
484 :
485 0 : if (pParent->m_aMasterSlotExecutor.IsSet())
486 : {
487 0 : long lResult = 0;
488 0 : if (pButton == &m_aFirstBtn)
489 0 : lResult = pParent->m_aMasterSlotExecutor.Call(reinterpret_cast<void*>(RECORD_FIRST));
490 0 : else if( pButton == &m_aPrevBtn )
491 0 : lResult = pParent->m_aMasterSlotExecutor.Call(reinterpret_cast<void*>(RECORD_PREV));
492 0 : else if( pButton == &m_aNextBtn )
493 0 : lResult = pParent->m_aMasterSlotExecutor.Call(reinterpret_cast<void*>(RECORD_NEXT));
494 0 : else if( pButton == &m_aLastBtn )
495 0 : lResult = pParent->m_aMasterSlotExecutor.Call(reinterpret_cast<void*>(RECORD_LAST));
496 0 : else if( pButton == &m_aNewBtn )
497 0 : lResult = pParent->m_aMasterSlotExecutor.Call(reinterpret_cast<void*>(RECORD_NEW));
498 :
499 0 : if (lResult)
500 : // the link already handled it
501 0 : return 0;
502 : }
503 :
504 0 : if (pButton == &m_aFirstBtn)
505 0 : pParent->MoveToFirst();
506 0 : else if( pButton == &m_aPrevBtn )
507 0 : pParent->MoveToPrev();
508 0 : else if( pButton == &m_aNextBtn )
509 0 : pParent->MoveToNext();
510 0 : else if( pButton == &m_aLastBtn )
511 0 : pParent->MoveToLast();
512 0 : else if( pButton == &m_aNewBtn )
513 0 : pParent->AppendNew();
514 0 : return 0;
515 : }
516 :
517 130 : void DbGridControl::NavigationBar::InvalidateAll(sal_Int32 nCurrentPos, bool bAll)
518 : {
519 130 : if (m_nCurrentPos != nCurrentPos || nCurrentPos < 0 || bAll)
520 : {
521 124 : DbGridControl* pParent = static_cast<DbGridControl*>(GetParent());
522 :
523 124 : sal_Int32 nAdjustedRowCount = pParent->GetRowCount() - ((pParent->GetOptions() & DbGridControl::OPT_INSERT) ? 2 : 1);
524 :
525 : // check if everything needs to be invalidated
526 124 : bAll = bAll || m_nCurrentPos <= 0;
527 124 : bAll = bAll || nCurrentPos <= 0;
528 124 : bAll = bAll || m_nCurrentPos >= nAdjustedRowCount;
529 124 : bAll = bAll || nCurrentPos >= nAdjustedRowCount;
530 :
531 124 : if ( bAll )
532 : {
533 124 : m_nCurrentPos = nCurrentPos;
534 124 : int i = 0;
535 1364 : while (ControlMap[i])
536 1116 : SetState(ControlMap[i++]);
537 : }
538 : else // is in the center
539 : {
540 0 : m_nCurrentPos = nCurrentPos;
541 0 : SetState(NavigationBar::RECORD_COUNT);
542 0 : SetState(NavigationBar::RECORD_ABSOLUTE);
543 : }
544 : }
545 130 : }
546 :
547 1120 : bool DbGridControl::NavigationBar::GetState(sal_uInt16 nWhich) const
548 : {
549 1120 : DbGridControl* pParent = static_cast<DbGridControl*>(GetParent());
550 :
551 2298 : if (!pParent->IsOpen() || pParent->IsDesignMode() || !pParent->IsEnabled()
552 1138 : || pParent->IsFilterMode() )
553 1102 : return false;
554 : else
555 : {
556 : // check if we have a master state provider
557 18 : if (pParent->m_aMasterStateProvider.IsSet())
558 : {
559 18 : long nState = pParent->m_aMasterStateProvider.Call(reinterpret_cast< void* >( nWhich ) );
560 18 : if (nState>=0)
561 0 : return (nState>0);
562 : }
563 :
564 18 : bool bAvailable = true;
565 :
566 18 : switch (nWhich)
567 : {
568 : case NavigationBar::RECORD_FIRST:
569 : case NavigationBar::RECORD_PREV:
570 4 : bAvailable = m_nCurrentPos > 0;
571 4 : break;
572 : case NavigationBar::RECORD_NEXT:
573 2 : if(pParent->m_bRecordCountFinal)
574 : {
575 2 : bAvailable = m_nCurrentPos < pParent->GetRowCount() - 1;
576 2 : if (!bAvailable && pParent->GetOptions() & DbGridControl::OPT_INSERT)
577 0 : bAvailable = (m_nCurrentPos == pParent->GetRowCount() - 2) && pParent->IsModified();
578 : }
579 2 : break;
580 : case NavigationBar::RECORD_LAST:
581 2 : if(pParent->m_bRecordCountFinal)
582 : {
583 2 : if (pParent->GetOptions() & DbGridControl::OPT_INSERT)
584 2 : bAvailable = pParent->IsCurrentAppending() ? pParent->GetRowCount() > 1 :
585 2 : m_nCurrentPos != pParent->GetRowCount() - 2;
586 : else
587 0 : bAvailable = m_nCurrentPos != pParent->GetRowCount() - 1;
588 : }
589 2 : break;
590 : case NavigationBar::RECORD_NEW:
591 2 : bAvailable = (pParent->GetOptions() & DbGridControl::OPT_INSERT) && pParent->GetRowCount() && m_nCurrentPos < pParent->GetRowCount() - 1;
592 2 : break;
593 : case NavigationBar::RECORD_ABSOLUTE:
594 2 : bAvailable = pParent->GetRowCount() > 0;
595 2 : break;
596 : }
597 18 : return bAvailable;
598 : }
599 : }
600 :
601 1120 : void DbGridControl::NavigationBar::SetState(sal_uInt16 nWhich)
602 : {
603 1120 : bool bAvailable = GetState(nWhich);
604 1120 : DbGridControl* pParent = static_cast<DbGridControl*>(GetParent());
605 1120 : vcl::Window* pWnd = NULL;
606 1120 : switch (nWhich)
607 : {
608 : case NavigationBar::RECORD_FIRST:
609 124 : pWnd = &m_aFirstBtn;
610 124 : break;
611 : case NavigationBar::RECORD_PREV:
612 124 : pWnd = &m_aPrevBtn;
613 124 : break;
614 : case NavigationBar::RECORD_NEXT:
615 124 : pWnd = &m_aNextBtn;
616 124 : break;
617 : case NavigationBar::RECORD_LAST:
618 124 : pWnd = &m_aLastBtn;
619 124 : break;
620 : case NavigationBar::RECORD_NEW:
621 124 : pWnd = &m_aNewBtn;
622 124 : break;
623 : case NavigationBar::RECORD_ABSOLUTE:
624 124 : pWnd = &m_aAbsolute;
625 124 : if (bAvailable)
626 : {
627 2 : if (pParent->m_nTotalCount >= 0)
628 : {
629 2 : if (pParent->IsCurrentAppending())
630 0 : m_aAbsolute.SetMax(pParent->m_nTotalCount + 1);
631 : else
632 2 : m_aAbsolute.SetMax(pParent->m_nTotalCount);
633 : }
634 : else
635 0 : m_aAbsolute.SetMax(LONG_MAX);
636 :
637 2 : m_aAbsolute.SetValue(m_nCurrentPos + 1);
638 : }
639 : else
640 122 : m_aAbsolute.SetText(OUString());
641 124 : break;
642 : case NavigationBar::RECORD_TEXT:
643 124 : pWnd = &m_aRecordText;
644 124 : break;
645 : case NavigationBar::RECORD_OF:
646 124 : pWnd = &m_aRecordOf;
647 124 : break;
648 : case NavigationBar::RECORD_COUNT:
649 : {
650 128 : pWnd = &m_aRecordCount;
651 128 : OUString aText;
652 128 : if (bAvailable)
653 : {
654 2 : if (pParent->GetOptions() & DbGridControl::OPT_INSERT)
655 : {
656 2 : if (pParent->IsCurrentAppending() && !pParent->IsModified())
657 0 : aText = m_aAbsolute.CreateFieldText(pParent->GetRowCount());
658 : else
659 2 : aText = m_aAbsolute.CreateFieldText(pParent->GetRowCount() - 1);
660 : }
661 : else
662 0 : aText = m_aAbsolute.CreateFieldText(pParent->GetRowCount());
663 2 : if(!pParent->m_bRecordCountFinal)
664 0 : aText += " *";
665 : }
666 : else
667 126 : aText = "";
668 :
669 : // add the number of selected rows, if applicable
670 128 : if (pParent->GetSelectRowCount())
671 : {
672 0 : OUString aExtendedInfo(aText);
673 0 : aExtendedInfo += " (";
674 0 : aExtendedInfo += m_aAbsolute.CreateFieldText(pParent->GetSelectRowCount());
675 0 : aExtendedInfo += ")";
676 0 : pWnd->SetText(aExtendedInfo);
677 : }
678 : else
679 128 : pWnd->SetText(aText);
680 :
681 128 : pParent->SetRealRowCount(aText);
682 128 : } break;
683 : }
684 : DBG_ASSERT(pWnd, "kein Fenster");
685 1120 : if (pWnd && (pWnd->IsEnabled() != bAvailable))
686 : // this "pWnd->IsEnabled() != bAvailable" is a little hack : Window::Enable always generates a user
687 : // event (ImplGenerateMouseMove) even if nothing happened. This may lead to some unwanted effects, so we
688 : // do this check.
689 : // For further explanation see Bug 69900.
690 424 : pWnd->Enable(bAvailable);
691 1120 : }
692 :
693 79 : void DbGridControl::NavigationBar::Resize()
694 : {
695 79 : Control::Resize();
696 79 : ArrangeControls();
697 79 : }
698 :
699 9 : void DbGridControl::NavigationBar::Paint(const Rectangle& rRect)
700 : {
701 9 : Control::Paint(rRect);
702 9 : Point aAbsolutePos = m_aAbsolute.GetPosPixel();
703 9 : Size aAbsoluteSize = m_aAbsolute.GetSizePixel();
704 :
705 9 : DrawLine(Point(aAbsolutePos.X() - 1, 0 ),
706 18 : Point(aAbsolutePos.X() - 1, aAbsolutePos.Y() + aAbsoluteSize.Height()));
707 :
708 9 : DrawLine(Point(aAbsolutePos.X() + aAbsoluteSize.Width() + 1, 0 ),
709 18 : Point(aAbsolutePos.X() + aAbsoluteSize.Width() + 1, aAbsolutePos.Y() + aAbsoluteSize.Height()));
710 9 : }
711 :
712 311 : void DbGridControl::NavigationBar::StateChanged( StateChangedType nType )
713 : {
714 311 : Control::StateChanged( nType );
715 :
716 : vcl::Window* pWindows[] = { &m_aRecordText,
717 : &m_aAbsolute,
718 : &m_aRecordOf,
719 : &m_aRecordCount,
720 : &m_aFirstBtn,
721 : &m_aPrevBtn,
722 : &m_aNextBtn,
723 : &m_aLastBtn,
724 : &m_aNewBtn
725 311 : };
726 :
727 311 : switch ( nType )
728 : {
729 : case StateChangedType::MIRRORING:
730 : {
731 134 : bool bIsRTLEnabled = IsRTLEnabled();
732 1340 : for ( size_t i=0; i < (sizeof (pWindows) / sizeof(pWindows[0])); ++i )
733 1206 : pWindows[i]->EnableRTL( bIsRTLEnabled );
734 : }
735 134 : break;
736 :
737 : case StateChangedType::ZOOM:
738 : {
739 0 : Fraction aZoom = GetZoom();
740 :
741 : // not all of these controls need to know the new zoom, but to be sure ...
742 0 : vcl::Font aFont( GetSettings().GetStyleSettings().GetFieldFont() );
743 0 : if ( IsControlFont() )
744 0 : aFont.Merge( GetControlFont() );
745 :
746 0 : for (size_t i=0; i < sizeof(pWindows)/sizeof(pWindows[0]); ++i)
747 : {
748 0 : pWindows[i]->SetZoom(aZoom);
749 0 : pWindows[i]->SetZoomedPointFont(aFont);
750 : }
751 :
752 0 : SetZoomedPointFont( aFont );
753 :
754 : // rearrange the controls
755 0 : m_nDefaultWidth = ArrangeControls();
756 : }
757 0 : break;
758 : default:;
759 : }
760 311 : }
761 :
762 4 : DbGridRow::DbGridRow(CursorWrapper* pCur, bool bPaintCursor)
763 4 : :m_bIsNew(false)
764 : {
765 :
766 4 : if (pCur && pCur->Is())
767 : {
768 4 : Reference< XIndexAccess > xColumns(pCur->getColumns(), UNO_QUERY);
769 : DataColumn* pColumn;
770 128 : for (sal_Int32 i = 0; i < xColumns->getCount(); ++i)
771 : {
772 : Reference< XPropertySet > xColSet(
773 124 : xColumns->getByIndex(i), css::uno::UNO_QUERY);
774 124 : pColumn = new DataColumn(xColSet);
775 124 : m_aVariants.push_back( pColumn );
776 124 : }
777 :
778 4 : if (pCur->rowDeleted())
779 0 : m_eStatus = GRS_DELETED;
780 : else
781 : {
782 4 : if (bPaintCursor)
783 2 : m_eStatus = (pCur->isAfterLast() || pCur->isBeforeFirst()) ? GRS_INVALID : GRS_CLEAN;
784 : else
785 : {
786 2 : Reference< XPropertySet > xSet = pCur->getPropertySet();
787 2 : if (xSet.is())
788 : {
789 2 : m_bIsNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
790 2 : if (!m_bIsNew && (pCur->isAfterLast() || pCur->isBeforeFirst()))
791 0 : m_eStatus = GRS_INVALID;
792 2 : else if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED)))
793 0 : m_eStatus = GRS_MODIFIED;
794 : else
795 2 : m_eStatus = GRS_CLEAN;
796 : }
797 : else
798 0 : m_eStatus = GRS_INVALID;
799 : }
800 : }
801 4 : if (!m_bIsNew && IsValid())
802 4 : m_aBookmark = pCur->getBookmark();
803 : else
804 0 : m_aBookmark = Any();
805 : }
806 : else
807 0 : m_eStatus = GRS_INVALID;
808 4 : }
809 :
810 18 : DbGridRow::~DbGridRow()
811 : {
812 130 : for ( size_t i = 0, n = m_aVariants.size(); i < n; ++i )
813 124 : delete m_aVariants[ i ];
814 6 : m_aVariants.clear();
815 12 : }
816 :
817 16 : void DbGridRow::SetState(CursorWrapper* pCur, bool bPaintCursor)
818 : {
819 16 : if (pCur && pCur->Is())
820 : {
821 16 : if (pCur->rowDeleted())
822 : {
823 0 : m_eStatus = GRS_DELETED;
824 0 : m_bIsNew = false;
825 : }
826 : else
827 : {
828 16 : m_eStatus = GRS_CLEAN;
829 16 : if (!bPaintCursor)
830 : {
831 2 : Reference< XPropertySet > xSet = pCur->getPropertySet();
832 : DBG_ASSERT(xSet.is(), "DbGridRow::SetState : invalid cursor !");
833 :
834 2 : if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED)))
835 0 : m_eStatus = GRS_MODIFIED;
836 2 : m_bIsNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
837 : }
838 : else
839 14 : m_bIsNew = false;
840 : }
841 :
842 : try
843 : {
844 16 : if (!m_bIsNew && IsValid())
845 16 : m_aBookmark = pCur->getBookmark();
846 : else
847 0 : m_aBookmark = Any();
848 : }
849 0 : catch(SQLException&)
850 : {
851 : DBG_UNHANDLED_EXCEPTION();
852 0 : m_aBookmark = Any();
853 0 : m_eStatus = GRS_INVALID;
854 0 : m_bIsNew = false;
855 : }
856 : }
857 : else
858 : {
859 0 : m_aBookmark = Any();
860 0 : m_eStatus = GRS_INVALID;
861 0 : m_bIsNew = false;
862 : }
863 16 : }
864 :
865 41 : DbGridControl::DbGridControl(
866 : Reference< XComponentContext > _rxContext,
867 : vcl::Window* pParent,
868 : WinBits nBits)
869 : :DbGridControl_Base(pParent, EBBF_NONE, nBits, DEFAULT_BROWSE_MODE )
870 : ,m_xContext(_rxContext)
871 : ,m_aBar(this)
872 : ,m_nAsynAdjustEvent(0)
873 : ,m_pDataSourcePropMultiplexer(NULL)
874 : ,m_pDataSourcePropListener(NULL)
875 : ,m_pFieldListeners(NULL)
876 : ,m_pCursorDisposeListener(NULL)
877 : ,m_pGridListener(NULL)
878 : ,m_pDataCursor(NULL)
879 : ,m_pSeekCursor(NULL)
880 : ,m_nSeekPos(-1)
881 : ,m_nTotalCount(-1)
882 : ,m_aNullDate(::dbtools::DBTypeConversion::getStandardDate())
883 : ,m_nMode(DEFAULT_BROWSE_MODE)
884 : ,m_nCurrentPos(-1)
885 : ,m_nDeleteEvent(0)
886 : ,m_nOptions(OPT_READONLY)
887 : ,m_nOptionMask(OPT_INSERT | OPT_UPDATE | OPT_DELETE)
888 : ,m_nLastColId((sal_uInt16)-1)
889 : ,m_nLastRowId(-1)
890 : ,m_bDesignMode(false)
891 : ,m_bRecordCountFinal(false)
892 : ,m_bMultiSelection(true)
893 : ,m_bNavigationBar(true)
894 : ,m_bSynchDisplay(true)
895 : ,m_bForceROController(false)
896 : ,m_bHandle(true)
897 : ,m_bFilterMode(false)
898 : ,m_bWantDestruction(false)
899 : ,m_bInAdjustDataSource(false)
900 : ,m_bPendingAdjustRows(false)
901 : ,m_bHideScrollbars( false )
902 41 : ,m_bUpdating(false)
903 : {
904 :
905 41 : OUString sName(SVX_RESSTR(RID_STR_NAVIGATIONBAR));
906 41 : m_aBar.SetAccessibleName(sName);
907 41 : m_aBar.Show();
908 41 : ImplInitWindow( InitAll );
909 41 : }
910 :
911 68 : void DbGridControl::InsertHandleColumn()
912 : {
913 : // BrowseBox has problems when painting without a handleColumn (hide it here)
914 68 : if (HasHandle())
915 51 : BrowseBox::InsertHandleColumn(GetDefaultColumnWidth(OUString()));
916 : else
917 17 : BrowseBox::InsertHandleColumn(0);
918 68 : }
919 :
920 41 : void DbGridControl::Init()
921 : {
922 41 : BrowserHeader* pNewHeader = CreateHeaderBar(this);
923 41 : pHeader->SetMouseTransparent(false);
924 :
925 41 : SetHeaderBar(pNewHeader);
926 41 : SetMode(m_nMode);
927 41 : SetCursorColor(Color(0xFF, 0, 0));
928 :
929 41 : InsertHandleColumn();
930 41 : }
931 :
932 82 : DbGridControl::~DbGridControl()
933 : {
934 41 : RemoveColumns();
935 :
936 : {
937 41 : m_bWantDestruction = true;
938 41 : osl::MutexGuard aGuard(m_aDestructionSafety);
939 41 : if (m_pFieldListeners)
940 2 : DisconnectFromFields();
941 41 : if (m_pCursorDisposeListener)
942 : {
943 2 : delete m_pCursorDisposeListener;
944 2 : m_pCursorDisposeListener = NULL;
945 41 : }
946 : }
947 :
948 41 : if (m_nDeleteEvent)
949 0 : Application::RemoveUserEvent(m_nDeleteEvent);
950 :
951 41 : if (m_pDataSourcePropMultiplexer)
952 : {
953 0 : m_pDataSourcePropMultiplexer->dispose();
954 0 : m_pDataSourcePropMultiplexer->release(); // this should delete the multiplexer
955 0 : delete m_pDataSourcePropListener;
956 0 : m_pDataSourcePropMultiplexer = NULL;
957 0 : m_pDataSourcePropListener = NULL;
958 : }
959 41 : m_xRowSetListener.clear();
960 :
961 41 : delete m_pDataCursor;
962 41 : delete m_pSeekCursor;
963 :
964 41 : }
965 :
966 501 : void DbGridControl::StateChanged( StateChangedType nType )
967 : {
968 501 : DbGridControl_Base::StateChanged( nType );
969 :
970 501 : switch (nType)
971 : {
972 : case StateChangedType::MIRRORING:
973 100 : ImplInitWindow( InitWritingMode );
974 100 : Invalidate();
975 100 : break;
976 :
977 : case StateChangedType::ZOOM:
978 : {
979 0 : ImplInitWindow( InitFontFacet );
980 :
981 : // and give it a chance to rearrange
982 0 : Point aPoint = GetControlArea().TopLeft();
983 0 : sal_uInt16 nX = (sal_uInt16)aPoint.X();
984 0 : ArrangeControls(nX, (sal_uInt16)aPoint.Y());
985 0 : ReserveControlArea((sal_uInt16)nX);
986 : }
987 0 : break;
988 : case StateChangedType::CONTROLFONT:
989 77 : ImplInitWindow( InitFontFacet );
990 77 : Invalidate();
991 77 : break;
992 : case StateChangedType::CONTROLFOREGROUND:
993 0 : ImplInitWindow( InitForeground );
994 0 : Invalidate();
995 0 : break;
996 : case StateChangedType::CONTROLBACKGROUND:
997 0 : ImplInitWindow( InitBackground );
998 0 : Invalidate();
999 0 : break;
1000 : default:;
1001 : }
1002 501 : }
1003 :
1004 42 : void DbGridControl::DataChanged( const DataChangedEvent& rDCEvt )
1005 : {
1006 42 : DbGridControl_Base::DataChanged( rDCEvt );
1007 84 : if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS ) &&
1008 42 : (rDCEvt.GetFlags() & SETTINGS_STYLE) )
1009 : {
1010 42 : ImplInitWindow( InitAll );
1011 42 : Invalidate();
1012 : }
1013 42 : }
1014 :
1015 0 : void DbGridControl::Select()
1016 : {
1017 0 : DbGridControl_Base::Select();
1018 :
1019 : // as the selected rows may have changed, udate the according display in our navigation bar
1020 0 : m_aBar.InvalidateState(NavigationBar::RECORD_COUNT);
1021 :
1022 0 : if (m_pGridListener)
1023 0 : m_pGridListener->selectionChanged();
1024 0 : }
1025 :
1026 260 : void DbGridControl::ImplInitWindow( const InitWindowFacet _eInitWhat )
1027 : {
1028 492 : for ( size_t i = 0; i < m_aColumns.size(); ++i )
1029 : {
1030 232 : DbGridColumn* pCol = m_aColumns[ i ];
1031 232 : if (pCol)
1032 232 : pCol->ImplInitWindow( GetDataWindow(), _eInitWhat );
1033 : }
1034 :
1035 260 : if ( ( _eInitWhat & InitWritingMode ) != 0 )
1036 : {
1037 183 : if ( m_bNavigationBar )
1038 : {
1039 134 : m_aBar.EnableRTL( IsRTLEnabled() );
1040 : }
1041 : }
1042 :
1043 260 : if ( ( _eInitWhat & InitFontFacet ) != 0 )
1044 : {
1045 160 : if ( m_bNavigationBar )
1046 : {
1047 98 : vcl::Font aFont = m_aBar.GetSettings().GetStyleSettings().GetFieldFont();
1048 98 : if ( IsControlFont() )
1049 57 : m_aBar.SetControlFont( GetControlFont() );
1050 : else
1051 41 : m_aBar.SetControlFont();
1052 :
1053 98 : m_aBar.SetZoom( GetZoom() );
1054 : }
1055 : }
1056 :
1057 260 : if ( ( _eInitWhat & InitBackground ) != 0 )
1058 : {
1059 83 : if (IsControlBackground())
1060 : {
1061 0 : GetDataWindow().SetBackground(GetControlBackground());
1062 0 : GetDataWindow().SetControlBackground(GetControlBackground());
1063 0 : GetDataWindow().SetFillColor(GetControlBackground());
1064 : }
1065 : else
1066 : {
1067 83 : GetDataWindow().SetControlBackground();
1068 83 : GetDataWindow().SetFillColor(GetFillColor());
1069 : }
1070 : }
1071 260 : }
1072 :
1073 0 : void DbGridControl::RemoveRows(bool bNewCursor)
1074 : {
1075 : // Did the data cursor change?
1076 0 : if (!bNewCursor)
1077 : {
1078 0 : DELETEZ(m_pSeekCursor);
1079 0 : m_xPaintRow = m_xDataRow = m_xEmptyRow = m_xCurrentRow = m_xSeekRow = NULL;
1080 0 : m_nCurrentPos = m_nSeekPos = -1;
1081 0 : m_nOptions = OPT_READONLY;
1082 :
1083 0 : RowRemoved(0, GetRowCount(), false);
1084 0 : m_nTotalCount = -1;
1085 : }
1086 : else
1087 : {
1088 0 : RemoveRows();
1089 : }
1090 0 : }
1091 :
1092 4 : void DbGridControl::RemoveRows()
1093 : {
1094 : // we're going to remove all columns and all row, so deactivate the current cell
1095 4 : if (IsEditing())
1096 2 : DeactivateCell();
1097 :
1098 : // de-initialize all columns
1099 : // if there are columns, free all controllers
1100 128 : for (size_t i = 0; i < m_aColumns.size(); i++)
1101 124 : m_aColumns[ i ]->Clear();
1102 :
1103 4 : DELETEZ(m_pSeekCursor);
1104 4 : DELETEZ(m_pDataCursor);
1105 :
1106 4 : m_xPaintRow = m_xDataRow = m_xEmptyRow = m_xCurrentRow = m_xSeekRow = NULL;
1107 4 : m_nCurrentPos = m_nSeekPos = m_nTotalCount = -1;
1108 4 : m_nOptions = OPT_READONLY;
1109 :
1110 : // reset number of sentences to zero in the browser
1111 4 : DbGridControl_Base::RemoveRows();
1112 4 : m_aBar.InvalidateAll(m_nCurrentPos, true);
1113 4 : }
1114 :
1115 271 : void DbGridControl::ArrangeControls(sal_uInt16& nX, sal_uInt16 nY)
1116 : {
1117 : // positioning of the controls
1118 271 : if (m_bNavigationBar)
1119 : {
1120 150 : nX = m_aBar.GetDefaultWidth();
1121 150 : Rectangle aRect(GetControlArea());
1122 150 : m_aBar.SetPosSizePixel(Point(0,nY + 1), Size(nX, aRect.GetSize().Height() - 1));
1123 : }
1124 271 : }
1125 :
1126 55 : void DbGridControl::EnableHandle(bool bEnable)
1127 : {
1128 55 : if (m_bHandle == bEnable)
1129 85 : return;
1130 :
1131 : // HandleColumn is only hidden because there are a lot of problems while painting otherwise
1132 25 : RemoveColumn( HandleColumnId );
1133 25 : m_bHandle = bEnable;
1134 25 : InsertHandleColumn();
1135 : }
1136 :
1137 : namespace
1138 : {
1139 27 : bool adjustModeForScrollbars( BrowserMode& _rMode, bool _bNavigationBar, bool _bHideScrollbars )
1140 : {
1141 27 : BrowserMode nOldMode = _rMode;
1142 :
1143 27 : if ( !_bNavigationBar )
1144 : {
1145 17 : _rMode &= ~BROWSER_AUTO_HSCROLL;
1146 : }
1147 :
1148 27 : if ( _bHideScrollbars )
1149 : {
1150 0 : _rMode |= ( BROWSER_NO_HSCROLL | BROWSER_NO_VSCROLL );
1151 0 : _rMode &= ~( BROWSER_AUTO_HSCROLL | BROWSER_AUTO_VSCROLL );
1152 : }
1153 : else
1154 : {
1155 27 : _rMode |= ( BROWSER_AUTO_HSCROLL | BROWSER_AUTO_VSCROLL );
1156 27 : _rMode &= ~( BROWSER_NO_HSCROLL | BROWSER_NO_VSCROLL );
1157 : }
1158 :
1159 : // note: if we have a navigation bar, we always have a AUTO_HSCROLL. In particular,
1160 : // _bHideScrollbars is ignored then
1161 27 : if ( _bNavigationBar )
1162 : {
1163 10 : _rMode |= BROWSER_AUTO_HSCROLL;
1164 10 : _rMode &= ~BROWSER_NO_HSCROLL;
1165 : }
1166 :
1167 27 : return nOldMode != _rMode;
1168 : }
1169 : }
1170 :
1171 55 : void DbGridControl::EnableNavigationBar(bool bEnable)
1172 : {
1173 55 : if (m_bNavigationBar == bEnable)
1174 85 : return;
1175 :
1176 25 : m_bNavigationBar = bEnable;
1177 :
1178 25 : if (bEnable)
1179 : {
1180 8 : m_aBar.Show();
1181 8 : m_aBar.Enable();
1182 8 : m_aBar.InvalidateAll(m_nCurrentPos, true);
1183 :
1184 8 : if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
1185 0 : SetMode( m_nMode );
1186 :
1187 : // get size of the reserved ControlArea
1188 8 : Point aPoint = GetControlArea().TopLeft();
1189 8 : sal_uInt16 nX = (sal_uInt16)aPoint.X();
1190 :
1191 8 : ArrangeControls(nX, (sal_uInt16)aPoint.Y());
1192 8 : ReserveControlArea((sal_uInt16)nX);
1193 : }
1194 : else
1195 : {
1196 17 : m_aBar.Hide();
1197 17 : m_aBar.Disable();
1198 :
1199 17 : if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
1200 17 : SetMode( m_nMode );
1201 :
1202 17 : ReserveControlArea();
1203 : }
1204 : }
1205 :
1206 0 : sal_uInt16 DbGridControl::SetOptions(sal_uInt16 nOpt)
1207 : {
1208 : DBG_ASSERT(!m_xCurrentRow || !m_xCurrentRow->IsModified(),
1209 : "DbGridControl::SetOptions : please do not call when editing a record (things are much easier this way ;) !");
1210 :
1211 : // for the next setDataSource (which is triggered by a refresh, for instance)
1212 0 : m_nOptionMask = nOpt;
1213 :
1214 : // normalize the new options
1215 0 : Reference< XPropertySet > xDataSourceSet = m_pDataCursor->getPropertySet();
1216 0 : if (xDataSourceSet.is())
1217 : {
1218 : // check what kind of options are available
1219 0 : sal_Int32 nPrivileges = 0;
1220 0 : xDataSourceSet->getPropertyValue(FM_PROP_PRIVILEGES) >>= nPrivileges;
1221 0 : if ((nPrivileges & Privilege::INSERT) == 0)
1222 0 : nOpt &= ~OPT_INSERT;
1223 0 : if ((nPrivileges & Privilege::UPDATE) == 0)
1224 0 : nOpt &= ~OPT_UPDATE;
1225 0 : if ((nPrivileges & Privilege::DELETE) == 0)
1226 0 : nOpt &= ~OPT_DELETE;
1227 : }
1228 : else
1229 0 : nOpt = OPT_READONLY;
1230 :
1231 : // need to do something after that ?
1232 0 : if (nOpt == m_nOptions)
1233 0 : return m_nOptions;
1234 :
1235 : // the 'update' option only affects our BrowserMode (with or w/o focus rect)
1236 0 : BrowserMode nNewMode = m_nMode;
1237 0 : if ((m_nMode & BROWSER_CURSOR_WO_FOCUS) == 0)
1238 : {
1239 0 : if (nOpt & OPT_UPDATE)
1240 0 : nNewMode |= BROWSER_HIDECURSOR;
1241 : else
1242 0 : nNewMode &= ~BROWSER_HIDECURSOR;
1243 : }
1244 : else
1245 0 : nNewMode &= ~BROWSER_HIDECURSOR;
1246 : // should not be necessary if EnablePermanentCursor is used to change the cursor behaviour, but to be sure ...
1247 :
1248 0 : if (nNewMode != m_nMode)
1249 : {
1250 0 : SetMode(nNewMode);
1251 0 : m_nMode = nNewMode;
1252 : }
1253 :
1254 : // _after_ setting the mode because this results in an ActivateCell
1255 0 : DeactivateCell();
1256 :
1257 0 : bool bInsertChanged = (nOpt & OPT_INSERT) != (m_nOptions & OPT_INSERT);
1258 0 : m_nOptions = nOpt;
1259 : // we need to set this before the code below because it indirectly uses m_nOptions
1260 :
1261 : // the 'insert' option affects our empty row
1262 0 : if (bInsertChanged)
1263 : {
1264 0 : if (m_nOptions & OPT_INSERT)
1265 : { // the insert option is to be set
1266 0 : m_xEmptyRow = new DbGridRow();
1267 0 : RowInserted(GetRowCount(), 1, true);
1268 : }
1269 : else
1270 : { // the insert option is to be reset
1271 0 : m_xEmptyRow = NULL;
1272 0 : if ((GetCurRow() == GetRowCount() - 1) && (GetCurRow() > 0))
1273 0 : GoToRowColumnId(GetCurRow() - 1, GetCurColumnId());
1274 0 : RowRemoved(GetRowCount(), 1, true);
1275 : }
1276 : }
1277 :
1278 : // the 'delete' options has no immediate consequences
1279 :
1280 0 : ActivateCell();
1281 0 : Invalidate();
1282 0 : return m_nOptions;
1283 : }
1284 :
1285 0 : void DbGridControl::ForceHideScrollbars( bool _bForce )
1286 : {
1287 0 : if ( m_bHideScrollbars == _bForce )
1288 0 : return;
1289 :
1290 0 : m_bHideScrollbars = _bForce;
1291 :
1292 0 : if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
1293 0 : SetMode( m_nMode );
1294 : }
1295 :
1296 55 : void DbGridControl::EnablePermanentCursor(bool bEnable)
1297 : {
1298 55 : if (IsPermanentCursorEnabled() == bEnable)
1299 87 : return;
1300 :
1301 23 : if (bEnable)
1302 : {
1303 15 : m_nMode &= ~BROWSER_HIDECURSOR; // without this BROWSER_CURSOR_WO_FOCUS won't have any affect
1304 15 : m_nMode |= BROWSER_CURSOR_WO_FOCUS;
1305 : }
1306 : else
1307 : {
1308 8 : if (m_nOptions & OPT_UPDATE)
1309 0 : m_nMode |= BROWSER_HIDECURSOR; // no cursor at all
1310 : else
1311 8 : m_nMode &= ~BROWSER_HIDECURSOR; // at least the "non-permanent" cursor
1312 :
1313 8 : m_nMode &= ~BROWSER_CURSOR_WO_FOCUS;
1314 : }
1315 23 : SetMode(m_nMode);
1316 :
1317 23 : bool bWasEditing = IsEditing();
1318 23 : DeactivateCell();
1319 23 : if (bWasEditing)
1320 0 : ActivateCell();
1321 : }
1322 :
1323 57 : bool DbGridControl::IsPermanentCursorEnabled() const
1324 : {
1325 57 : return ((m_nMode & BROWSER_CURSOR_WO_FOCUS) != 0) && ((m_nMode & BROWSER_HIDECURSOR) == 0);
1326 : }
1327 :
1328 0 : void DbGridControl::refreshController(sal_uInt16 _nColId, GrantControlAccess /*_aAccess*/)
1329 : {
1330 0 : if ((GetCurColumnId() == _nColId) && IsEditing())
1331 : { // the controller which is currently active needs to be refreshed
1332 0 : DeactivateCell();
1333 0 : ActivateCell();
1334 : }
1335 0 : }
1336 :
1337 8 : void DbGridControl::setDataSource(const Reference< XRowSet >& _xCursor, sal_uInt16 nOpts)
1338 : {
1339 8 : if (!_xCursor.is() && !m_pDataCursor)
1340 10 : return;
1341 :
1342 4 : if (m_pDataSourcePropMultiplexer)
1343 : {
1344 2 : m_pDataSourcePropMultiplexer->dispose();
1345 2 : m_pDataSourcePropMultiplexer->release(); // this should delete the multiplexer
1346 2 : delete m_pDataSourcePropListener;
1347 2 : m_pDataSourcePropMultiplexer = NULL;
1348 2 : m_pDataSourcePropListener = NULL;
1349 : }
1350 4 : m_xRowSetListener.clear();
1351 :
1352 : // is the new cursor valid ?
1353 : // the cursor is only valid if it contains some columns
1354 : // if there is no cursor or the cursor is not valid we have to clean up an leave
1355 4 : if (!_xCursor.is() || !Reference< XColumnsSupplier > (_xCursor, UNO_QUERY)->getColumns()->hasElements())
1356 : {
1357 2 : RemoveRows();
1358 2 : return;
1359 : }
1360 :
1361 : // did the data cursor change?
1362 2 : sal_uInt16 nCurPos = GetColumnPos(GetCurColumnId());
1363 :
1364 2 : SetUpdateMode(false);
1365 2 : RemoveRows();
1366 2 : DisconnectFromFields();
1367 :
1368 2 : DELETEZ(m_pCursorDisposeListener);
1369 :
1370 : {
1371 2 : ::osl::MutexGuard aGuard(m_aAdjustSafety);
1372 2 : if (m_nAsynAdjustEvent)
1373 : {
1374 : // the adjust was thought to work with the old cursor which we don't have anymore
1375 0 : RemoveUserEvent(m_nAsynAdjustEvent);
1376 0 : m_nAsynAdjustEvent = 0;
1377 2 : }
1378 : }
1379 :
1380 : // get a new formatter and data cursor
1381 2 : m_xFormatter = NULL;
1382 2 : Reference< ::com::sun::star::util::XNumberFormatsSupplier > xSupplier = getNumberFormats(getConnection(_xCursor), true);
1383 2 : if (xSupplier.is())
1384 : {
1385 4 : m_xFormatter = Reference< ::com::sun::star::util::XNumberFormatter >(
1386 : ::com::sun::star::util::NumberFormatter::create(m_xContext),
1387 2 : UNO_QUERY);
1388 2 : m_xFormatter->attachNumberFormatsSupplier(xSupplier);
1389 :
1390 : // retrieve the datebase of the Numberformatter
1391 : try
1392 : {
1393 2 : xSupplier->getNumberFormatSettings()->getPropertyValue("NullDate") >>= m_aNullDate;
1394 : }
1395 0 : catch(Exception&)
1396 : {
1397 : }
1398 : }
1399 :
1400 2 : m_pDataCursor = new CursorWrapper(_xCursor);
1401 :
1402 : // now create a cursor for painting rows
1403 : // we need that cursor only if we are not in insert only mode
1404 4 : Reference< XResultSet > xClone;
1405 4 : Reference< XResultSetAccess > xAccess( _xCursor, UNO_QUERY );
1406 : try
1407 : {
1408 2 : xClone = xAccess.is() ? xAccess->createResultSet() : Reference< XResultSet > ();
1409 : }
1410 0 : catch(Exception&)
1411 : {
1412 : }
1413 2 : if (xClone.is())
1414 2 : m_pSeekCursor = new CursorWrapper(xClone);
1415 :
1416 : // property listening on the data source
1417 : // (Normally one class would be sufficient : the multiplexer which could forward the property change to us.
1418 : // But for that we would have been derived from ::comphelper::OPropertyChangeListener, which isn't exported.
1419 : // So we introduce a second class, which is a ::comphelper::OPropertyChangeListener (in the implementation file we know this class)
1420 : // and forwards the property changes to a our special method "DataSourcePropertyChanged".)
1421 2 : if (m_pDataCursor)
1422 : {
1423 2 : m_pDataSourcePropListener = new FmXGridSourcePropListener(this);
1424 2 : m_pDataSourcePropMultiplexer = new ::comphelper::OPropertyChangeMultiplexer(m_pDataSourcePropListener, m_pDataCursor->getPropertySet() );
1425 2 : m_pDataSourcePropMultiplexer->acquire();
1426 2 : m_pDataSourcePropMultiplexer->addProperty(FM_PROP_ISMODIFIED);
1427 2 : m_pDataSourcePropMultiplexer->addProperty(FM_PROP_ISNEW);
1428 : }
1429 :
1430 2 : BrowserMode nOldMode = m_nMode;
1431 2 : if (m_pSeekCursor)
1432 : {
1433 : try
1434 : {
1435 2 : Reference< XPropertySet > xSet(_xCursor, UNO_QUERY);
1436 2 : if (xSet.is())
1437 : {
1438 : // check what kind of options are available
1439 2 : sal_Int32 nConcurrency = ResultSetConcurrency::READ_ONLY;
1440 2 : xSet->getPropertyValue(FM_PROP_RESULTSET_CONCURRENCY) >>= nConcurrency;
1441 :
1442 2 : if ( ResultSetConcurrency::UPDATABLE == nConcurrency )
1443 : {
1444 2 : sal_Int32 nPrivileges = 0;
1445 2 : xSet->getPropertyValue(FM_PROP_PRIVILEGES) >>= nPrivileges;
1446 :
1447 : // Insert Option should be set if insert only otherwise you won't see any rows
1448 : // and no insertion is possible
1449 2 : if ((m_nOptionMask & OPT_INSERT) && ((nPrivileges & Privilege::INSERT) == Privilege::INSERT) && (nOpts & OPT_INSERT))
1450 2 : m_nOptions |= OPT_INSERT;
1451 2 : if ((m_nOptionMask & OPT_UPDATE) && ((nPrivileges & Privilege::UPDATE) == Privilege::UPDATE) && (nOpts & OPT_UPDATE))
1452 2 : m_nOptions |= OPT_UPDATE;
1453 2 : if ((m_nOptionMask & OPT_DELETE) && ((nPrivileges & Privilege::DELETE) == Privilege::DELETE) && (nOpts & OPT_DELETE))
1454 2 : m_nOptions |= OPT_DELETE;
1455 : }
1456 2 : }
1457 : }
1458 0 : catch( const Exception& )
1459 : {
1460 : DBG_UNHANDLED_EXCEPTION();
1461 : }
1462 :
1463 2 : bool bPermanentCursor = IsPermanentCursorEnabled();
1464 2 : m_nMode = DEFAULT_BROWSE_MODE;
1465 :
1466 2 : if ( bPermanentCursor )
1467 : {
1468 0 : m_nMode |= BROWSER_CURSOR_WO_FOCUS;
1469 0 : m_nMode &= ~BROWSER_HIDECURSOR;
1470 : }
1471 : else
1472 : {
1473 : // updates are allowed -> no focus rectangle
1474 2 : if ( m_nOptions & OPT_UPDATE )
1475 2 : m_nMode |= BROWSER_HIDECURSOR;
1476 : }
1477 :
1478 2 : if ( m_bMultiSelection )
1479 2 : m_nMode |= BROWSER_MULTISELECTION;
1480 : else
1481 0 : m_nMode &= ~BROWSER_MULTISELECTION;
1482 :
1483 2 : adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars );
1484 :
1485 2 : Reference< XColumnsSupplier > xSupplyColumns(_xCursor, UNO_QUERY);
1486 2 : if (xSupplyColumns.is())
1487 2 : InitColumnsByFields(Reference< XIndexAccess > (xSupplyColumns->getColumns(), UNO_QUERY));
1488 :
1489 2 : ConnectToFields();
1490 : }
1491 :
1492 2 : sal_uInt32 nRecordCount(0);
1493 :
1494 2 : if (m_pSeekCursor)
1495 : {
1496 2 : Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
1497 2 : xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
1498 2 : m_bRecordCountFinal = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ROWCOUNTFINAL));
1499 :
1500 2 : m_xRowSetListener = new RowSetEventListener(this);
1501 4 : Reference< XRowsChangeBroadcaster> xChangeBroad(xSet,UNO_QUERY);
1502 2 : if ( xChangeBroad.is( ) )
1503 2 : xChangeBroad->addRowsChangeListener(m_xRowSetListener);
1504 :
1505 :
1506 : // insert the currently known rows
1507 : // and one row if we are able to insert rows
1508 2 : if (m_nOptions & OPT_INSERT)
1509 : {
1510 : // insert the empty row for insertion
1511 2 : m_xEmptyRow = new DbGridRow();
1512 2 : ++nRecordCount;
1513 : }
1514 2 : if (nRecordCount)
1515 : {
1516 2 : m_xPaintRow = m_xSeekRow = new DbGridRow(m_pSeekCursor, true);
1517 2 : m_xDataRow = new DbGridRow(m_pDataCursor, false);
1518 2 : RowInserted(0, nRecordCount, false);
1519 :
1520 2 : if (m_xSeekRow->IsValid())
1521 : try
1522 : {
1523 2 : m_nSeekPos = m_pSeekCursor->getRow() - 1;
1524 : }
1525 0 : catch( const Exception& )
1526 : {
1527 : DBG_UNHANDLED_EXCEPTION();
1528 0 : m_nSeekPos = -1;
1529 : }
1530 : }
1531 : else
1532 : {
1533 : // no rows so we don't need a seekcursor
1534 0 : DELETEZ(m_pSeekCursor);
1535 2 : }
1536 : }
1537 :
1538 : // go to the old column
1539 2 : if (nCurPos == BROWSER_INVALIDID || nCurPos >= ColCount())
1540 2 : nCurPos = 0;
1541 :
1542 : // Column zero is a valid choice and guaranteed to exist,
1543 : // but invisible to the user; if we have at least one
1544 : // user-visible column, go to that one.
1545 2 : if (nCurPos == 0 && ColCount() > 1)
1546 2 : nCurPos = 1;
1547 :
1548 : // there are rows so go to the selected current column
1549 2 : if (nRecordCount)
1550 2 : GoToRowColumnId(0, GetColumnId(nCurPos));
1551 : // else stop the editing if necessary
1552 0 : else if (IsEditing())
1553 0 : DeactivateCell();
1554 :
1555 : // now reset the mode
1556 2 : if (m_nMode != nOldMode)
1557 2 : SetMode(m_nMode);
1558 :
1559 : // RecalcRows was already called while resizing
1560 2 : if (!IsResizing() && GetRowCount())
1561 2 : RecalcRows(GetTopRow(), GetVisibleRows(), true);
1562 :
1563 2 : m_aBar.InvalidateAll(m_nCurrentPos, true);
1564 2 : SetUpdateMode(true);
1565 :
1566 : // start listening on the seek cursor
1567 2 : if (m_pSeekCursor)
1568 4 : m_pCursorDisposeListener = new DisposeListenerGridBridge(*this, Reference< XComponent > (Reference< XInterface >(*m_pSeekCursor), UNO_QUERY), 0);
1569 : }
1570 :
1571 43 : void DbGridControl::RemoveColumns()
1572 : {
1573 43 : if ( IsEditing() )
1574 0 : DeactivateCell();
1575 :
1576 163 : for (size_t i = 0, n = m_aColumns.size(); i < n; i++)
1577 120 : delete m_aColumns[ i ];
1578 43 : m_aColumns.clear();
1579 :
1580 43 : DbGridControl_Base::RemoveColumns();
1581 43 : }
1582 :
1583 140 : DbGridColumn* DbGridControl::CreateColumn(sal_uInt16 nId) const
1584 : {
1585 140 : return new DbGridColumn(nId, *(DbGridControl*)this);
1586 : }
1587 :
1588 140 : sal_uInt16 DbGridControl::AppendColumn(const OUString& rName, sal_uInt16 nWidth, sal_uInt16 nModelPos, sal_uInt16 nId)
1589 : {
1590 : DBG_ASSERT(nId == BROWSER_INVALIDID, "DbGridControl::AppendColumn : I want to set the ID myself ...");
1591 140 : sal_uInt16 nRealPos = nModelPos;
1592 140 : if (nModelPos != HEADERBAR_APPEND)
1593 : {
1594 : // calc the view pos. we can't use our converting functions because the new column
1595 : // has no VCL-representation, yet.
1596 102 : sal_Int16 nViewPos = nModelPos;
1597 1170 : while (nModelPos--)
1598 : {
1599 966 : if ( m_aColumns[ nModelPos ]->IsHidden() )
1600 0 : --nViewPos;
1601 : }
1602 : // restore nModelPos, we need it later
1603 102 : nModelPos = nRealPos;
1604 : // the position the base class gets is the view pos + 1 (because of the handle column)
1605 102 : nRealPos = nViewPos + 1;
1606 : }
1607 :
1608 : // calculate the new id
1609 140 : for (nId=1; (GetModelColumnPos(nId) != GRID_COLUMN_NOT_FOUND) && (nId <= m_aColumns.size()); ++nId)
1610 : ;
1611 : DBG_ASSERT(GetViewColumnPos(nId) == GRID_COLUMN_NOT_FOUND, "DbGridControl::AppendColumn : inconsistent internal state !");
1612 : // my column's models say "there is no column with id nId", but the view (the base class) says "there is a column ..."
1613 :
1614 140 : DbGridControl_Base::AppendColumn(rName, nWidth, nRealPos, nId);
1615 140 : if (nModelPos == HEADERBAR_APPEND)
1616 38 : m_aColumns.push_back( CreateColumn(nId) );
1617 : else
1618 : {
1619 102 : DbGridColumns::iterator it = m_aColumns.begin();
1620 102 : ::std::advance( it, nModelPos );
1621 102 : m_aColumns.insert( it, CreateColumn(nId) );
1622 : }
1623 :
1624 140 : return nId;
1625 : }
1626 :
1627 45 : void DbGridControl::RemoveColumn(sal_uInt16 nId)
1628 : {
1629 45 : DbGridControl_Base::RemoveColumn(nId);
1630 :
1631 45 : const sal_uInt16 nIndex = GetModelColumnPos(nId);
1632 45 : if(nIndex != GRID_COLUMN_NOT_FOUND)
1633 : {
1634 20 : delete m_aColumns[nIndex];
1635 20 : m_aColumns.erase( m_aColumns.begin()+nIndex );
1636 : }
1637 45 : }
1638 :
1639 0 : void DbGridControl::ColumnMoved(sal_uInt16 nId)
1640 : {
1641 0 : DbGridControl_Base::ColumnMoved(nId);
1642 :
1643 : // remove the col from the model
1644 0 : sal_uInt16 nOldModelPos = GetModelColumnPos(nId);
1645 : #ifdef DBG_UTIL
1646 : DbGridColumn* pCol = m_aColumns[ (sal_uInt32)nOldModelPos ];
1647 : DBG_ASSERT(!pCol->IsHidden(), "DbGridControl::ColumnMoved : moved a hidden col ? how this ?");
1648 : #endif
1649 :
1650 : // for the new model pos we can't use GetModelColumnPos because we are altering the model at the moment
1651 : // so the method won't work (in fact it would return the old model pos)
1652 :
1653 : // the new view pos is calculated easily
1654 0 : sal_uInt16 nNewViewPos = GetViewColumnPos(nId);
1655 :
1656 : // from that we can compute the new model pos
1657 : sal_uInt16 nNewModelPos;
1658 0 : for (nNewModelPos = 0; nNewModelPos < m_aColumns.size(); ++nNewModelPos)
1659 : {
1660 0 : if (!m_aColumns[ nNewModelPos ]->IsHidden())
1661 : {
1662 0 : if (!nNewViewPos)
1663 0 : break;
1664 : else
1665 0 : --nNewViewPos;
1666 : }
1667 : }
1668 : DBG_ASSERT( nNewModelPos < m_aColumns.size(), "DbGridControl::ColumnMoved : could not find the new model position !");
1669 :
1670 : // this will work. of course the model isn't fully consistent with our view right now, but let's
1671 : // look at the situation : a column has been moved with in the VIEW from pos m to n, say m<n (in the
1672 : // other case we can use analogue arguments).
1673 : // All cols k with m<k<=n have been shifted left on pos, the former col m now has pos n.
1674 : // In the model this affects a range of cols x to y, where x<=m and y<=n. And the number of hidden cols
1675 : // within this range is constant, so we may calculate the view pos from the model pos in the above way.
1676 :
1677 : // for instance, let's look at a grid with six columns where the third one is hidden. this will
1678 : // initially look like this :
1679 :
1680 : // +---+---+---+---+---+---+
1681 : // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
1682 : // +---+---+---+---+---+---+
1683 : // ID | 1 | 2 | 3 | 4 | 5 | 6 |
1684 : // +---+---+---+---+---+---+
1685 : // view pos | 0 | 1 | - | 2 | 3 | 4 |
1686 : // +---+---+---+---+---+---+
1687 :
1688 : // if we move the column at (view) pos 1 to (view) pos 3 we have :
1689 :
1690 : // +---+---+---+---+---+---+
1691 : // model pos | 0 | 3 |*2*| 4 | 1 | 5 | // not reflecting the changes, yet
1692 : // +---+---+---+---+---+---+
1693 : // ID | 1 | 4 | 3 | 5 | 2 | 6 | // already reflecting the changes
1694 : // +---+---+---+---+---+---+
1695 : // view pos | 0 | 1 | - | 2 | 3 | 4 |
1696 : // +---+---+---+---+---+---+
1697 :
1698 : // or, sorted by the out-of-date model positions :
1699 :
1700 : // +---+---+---+---+---+---+
1701 : // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
1702 : // +---+---+---+---+---+---+
1703 : // ID | 1 | 2 | 3 | 4 | 5 | 6 |
1704 : // +---+---+---+---+---+---+
1705 : // view pos | 0 | 3 | - | 1 | 2 | 4 |
1706 : // +---+---+---+---+---+---+
1707 :
1708 : // We know the new view pos (3) of the moved column because our base class tells us. So we look at our
1709 : // model for the 4th (the pos is zero-based) visible column, it is at (model) position 4. And this is
1710 : // exactly the pos where we have to re-insert our column's model, so it looks ike this :
1711 :
1712 : // +---+---+---+---+---+---+
1713 : // model pos | 0 |*1*| 2 | 3 | 4 | 5 |
1714 : // +---+---+---+---+---+---+
1715 : // ID | 1 | 3 | 4 | 5 | 2 | 6 |
1716 : // +---+---+---+---+---+---+
1717 : // view pos | 0 | - | 1 | 2 | 3 | 4 |
1718 : // +---+---+---+---+---+---+
1719 :
1720 : // Now, all is consistent again.
1721 : // (except of the hidden column : The cycling of the cols occurred on the model, not on the view. maybe
1722 : // the user expected the latter but there really is no good argument against our method ;) ...)
1723 :
1724 : // And no, this large explanation isn't just because I wanted to play a board game or something like
1725 : // that. It's because it took me a while to see it myself, and the whole theme (hidden cols, model col
1726 : // positions, view col positions) is really painful (at least for me) so the above pictures helped me a lot ;)
1727 :
1728 0 : DbGridColumn* temp = m_aColumns[ nOldModelPos ];
1729 :
1730 0 : DbGridColumns::iterator it = m_aColumns.begin();
1731 0 : ::std::advance( it, nOldModelPos );
1732 0 : m_aColumns.erase( it );
1733 :
1734 0 : it = m_aColumns.begin();
1735 0 : ::std::advance( it, nNewModelPos );
1736 0 : m_aColumns.insert( it, temp );
1737 0 : }
1738 :
1739 16 : bool DbGridControl::SeekRow(long nRow)
1740 : {
1741 : // in filter mode or in insert only mode we don't have any cursor!
1742 16 : if ( !SeekCursor( nRow ) )
1743 0 : return false;
1744 :
1745 16 : if ( IsFilterMode() )
1746 : {
1747 : DBG_ASSERT( IsFilterRow( nRow ), "DbGridControl::SeekRow(): No filter row, wrong mode" );
1748 0 : m_xPaintRow = m_xEmptyRow;
1749 : }
1750 : else
1751 : {
1752 : // on the current position we have to take the current row for display as we want
1753 : // to have the most recent values for display
1754 16 : if ( ( nRow == m_nCurrentPos ) && getDisplaySynchron() )
1755 2 : m_xPaintRow = m_xCurrentRow;
1756 : // seek to the empty insert row
1757 14 : else if ( IsInsertionRow( nRow ) )
1758 0 : m_xPaintRow = m_xEmptyRow;
1759 : else
1760 : {
1761 14 : m_xSeekRow->SetState( m_pSeekCursor, true );
1762 14 : m_xPaintRow = m_xSeekRow;
1763 : }
1764 : }
1765 :
1766 16 : DbGridControl_Base::SeekRow(nRow);
1767 :
1768 16 : return m_nSeekPos >= 0;
1769 : }
1770 :
1771 : // Is called whenever the visible amount of data changes
1772 105 : void DbGridControl::VisibleRowsChanged( long nNewTopRow, sal_uInt16 nLinesOnScreen )
1773 : {
1774 105 : RecalcRows(nNewTopRow, nLinesOnScreen, false);
1775 105 : }
1776 :
1777 107 : void DbGridControl::RecalcRows(long nNewTopRow, sal_uInt16 nLinesOnScreen, bool bUpdateCursor)
1778 : {
1779 : // Wenn kein Cursor -> keine Rows im Browser.
1780 107 : if (!m_pSeekCursor)
1781 : {
1782 : DBG_ASSERT(GetRowCount() == 0,"DbGridControl: ohne Cursor darf es keine Rows geben");
1783 212 : return;
1784 : }
1785 :
1786 : // ignore any implicitly made updates
1787 2 : bool bDisablePaint = !bUpdateCursor && IsPaintEnabled();
1788 2 : if (bDisablePaint)
1789 0 : EnablePaint(false);
1790 :
1791 : // adjust cache to the visible area
1792 2 : Reference< XPropertySet > xSet = m_pSeekCursor->getPropertySet();
1793 2 : sal_Int32 nCacheSize = 0;
1794 2 : xSet->getPropertyValue(FM_PROP_FETCHSIZE) >>= nCacheSize;
1795 2 : bool bCacheAligned = false;
1796 : // no further cursor movements after initializing (m_nSeekPos < 0) because it is already
1797 : // positioned on the first sentence
1798 2 : long nDelta = nNewTopRow - GetTopRow();
1799 : // limit for relative positioning
1800 2 : long nLimit = (nCacheSize) ? nCacheSize / 2 : 0;
1801 :
1802 : // more lines on screen than in cache
1803 2 : if (nLimit < nLinesOnScreen)
1804 : {
1805 0 : Any aCacheSize;
1806 0 : aCacheSize <<= sal_Int32(nLinesOnScreen*2);
1807 0 : xSet->setPropertyValue(FM_PROP_FETCHSIZE, aCacheSize);
1808 : // here we need to update the cursor for sure
1809 0 : bUpdateCursor = true;
1810 0 : bCacheAligned = true;
1811 0 : nLimit = nLinesOnScreen;
1812 : }
1813 :
1814 : // In the following, all positionings are done as it is
1815 : // ensured that there are enough lines in the data cache
1816 :
1817 : // window goes downwards with less than two windows difference or
1818 : // the cache was updated and no rowcount yet
1819 2 : if (nDelta < nLimit && (nDelta > 0
1820 2 : || (bCacheAligned && m_nTotalCount < 0)) )
1821 0 : SeekCursor(nNewTopRow + nLinesOnScreen - 1, false);
1822 2 : else if (nDelta < 0 && std::abs(nDelta) < nLimit)
1823 0 : SeekCursor(nNewTopRow, false);
1824 2 : else if (nDelta != 0 || bUpdateCursor)
1825 2 : SeekCursor(nNewTopRow, true);
1826 :
1827 2 : AdjustRows();
1828 :
1829 : // ignore any updates implicit made
1830 2 : EnablePaint(true);
1831 : }
1832 :
1833 2 : void DbGridControl::RowInserted(long nRow, long nNumRows, bool bDoPaint, bool bKeepSelection)
1834 : {
1835 2 : if (nNumRows)
1836 : {
1837 2 : if (m_bRecordCountFinal && m_nTotalCount < 0)
1838 : {
1839 : // if we have an insert row we have to reduce to count by 1
1840 : // as the total count reflects only the existing rows in database
1841 2 : m_nTotalCount = GetRowCount() + nNumRows;
1842 4 : if (m_xEmptyRow.Is())
1843 2 : --m_nTotalCount;
1844 : }
1845 0 : else if (m_nTotalCount >= 0)
1846 0 : m_nTotalCount += nNumRows;
1847 :
1848 2 : DbGridControl_Base::RowInserted(nRow, nNumRows, bDoPaint, bKeepSelection);
1849 2 : m_aBar.InvalidateState(NavigationBar::RECORD_COUNT);
1850 : }
1851 2 : }
1852 :
1853 0 : void DbGridControl::RowRemoved(long nRow, long nNumRows, bool bDoPaint)
1854 : {
1855 0 : if (nNumRows)
1856 : {
1857 0 : if (m_bRecordCountFinal && m_nTotalCount < 0)
1858 : {
1859 0 : m_nTotalCount = GetRowCount() - nNumRows;
1860 : // if we have an insert row reduce by 1
1861 0 : if (m_xEmptyRow.Is())
1862 0 : --m_nTotalCount;
1863 : }
1864 0 : else if (m_nTotalCount >= 0)
1865 0 : m_nTotalCount -= nNumRows;
1866 :
1867 0 : DbGridControl_Base::RowRemoved(nRow, nNumRows, bDoPaint);
1868 0 : m_aBar.InvalidateState(NavigationBar::RECORD_COUNT);
1869 : }
1870 0 : }
1871 :
1872 10 : void DbGridControl::AdjustRows()
1873 : {
1874 10 : if (!m_pSeekCursor)
1875 18 : return;
1876 :
1877 2 : Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
1878 :
1879 : // refresh RecordCount
1880 2 : sal_Int32 nRecordCount = 0;
1881 2 : xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
1882 2 : if (!m_bRecordCountFinal)
1883 0 : m_bRecordCountFinal = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ROWCOUNTFINAL));
1884 :
1885 : // Did the number of rows change?
1886 : // Here we need to consider that there might be an additional row for adding new data sets
1887 :
1888 : // add additional AppendRow for insertion
1889 2 : if (m_nOptions & OPT_INSERT)
1890 2 : ++nRecordCount;
1891 :
1892 : // If there is currently an insertion, so do not consider this added row in RecordCount or Appendrow
1893 2 : if (!IsUpdating() && m_bRecordCountFinal && IsModified() && m_xCurrentRow != m_xEmptyRow &&
1894 0 : m_xCurrentRow->IsNew())
1895 0 : ++nRecordCount;
1896 : // ensured with !m_bUpdating: otherwise the edited data set (that SaveRow added and why this
1897 : // method was called) would be called twice (if m_bUpdating == sal_True): once in RecordCount
1898 : // and a second time here (60787 - FS)
1899 :
1900 2 : if (nRecordCount != GetRowCount())
1901 : {
1902 0 : long nDelta = GetRowCount() - (long)nRecordCount;
1903 0 : if (nDelta > 0) // too many
1904 : {
1905 0 : RowRemoved(GetRowCount() - nDelta, nDelta, false);
1906 : // some rows are gone, thus, repaint starting at the current position
1907 0 : Invalidate();
1908 :
1909 0 : sal_Int32 nNewPos = AlignSeekCursor();
1910 0 : if (m_bSynchDisplay)
1911 0 : DbGridControl_Base::GoToRow(nNewPos);
1912 :
1913 0 : SetCurrent(nNewPos);
1914 : // there are rows so go to the selected current column
1915 0 : if (nRecordCount)
1916 0 : GoToRowColumnId(nNewPos, GetColumnId(GetCurColumnId()));
1917 0 : if (!IsResizing() && GetRowCount())
1918 0 : RecalcRows(GetTopRow(), GetVisibleRows(), true);
1919 0 : m_aBar.InvalidateAll(m_nCurrentPos, true);
1920 : }
1921 : else // too few
1922 0 : RowInserted(GetRowCount(), -nDelta, true);
1923 : }
1924 :
1925 2 : if (m_bRecordCountFinal && m_nTotalCount < 0)
1926 : {
1927 0 : if (m_nOptions & OPT_INSERT)
1928 0 : m_nTotalCount = GetRowCount() - 1;
1929 : else
1930 0 : m_nTotalCount = GetRowCount();
1931 : }
1932 2 : m_aBar.InvalidateState(NavigationBar::RECORD_COUNT);
1933 : }
1934 :
1935 16 : DbGridControl_Base::RowStatus DbGridControl::GetRowStatus(long nRow) const
1936 : {
1937 16 : if (IsFilterRow(nRow))
1938 0 : return DbGridControl_Base::FILTER;
1939 16 : else if (m_nCurrentPos >= 0 && nRow == m_nCurrentPos)
1940 : {
1941 : // neue Zeile
1942 2 : if (!IsValid(m_xCurrentRow))
1943 0 : return DbGridControl_Base::DELETED;
1944 2 : else if (IsModified())
1945 0 : return DbGridControl_Base::MODIFIED;
1946 2 : else if (m_xCurrentRow->IsNew())
1947 0 : return DbGridControl_Base::CURRENTNEW;
1948 : else
1949 2 : return DbGridControl_Base::CURRENT;
1950 : }
1951 14 : else if (IsInsertionRow(nRow))
1952 0 : return DbGridControl_Base::NEW;
1953 14 : else if (!IsValid(m_xSeekRow))
1954 0 : return DbGridControl_Base::DELETED;
1955 : else
1956 14 : return DbGridControl_Base::CLEAN;
1957 : }
1958 :
1959 16 : void DbGridControl::PaintStatusCell(OutputDevice& rDev, const Rectangle& rRect) const
1960 : {
1961 16 : DbGridControl_Base::PaintStatusCell(rDev, rRect);
1962 16 : }
1963 :
1964 78 : void DbGridControl::PaintCell(OutputDevice& rDev, const Rectangle& rRect, sal_uInt16 nColumnId) const
1965 : {
1966 78 : if (!IsValid(m_xPaintRow))
1967 78 : return;
1968 :
1969 78 : size_t Location = GetModelColumnPos(nColumnId);
1970 78 : DbGridColumn* pColumn = (Location < m_aColumns.size() ) ? m_aColumns[ Location ] : NULL;
1971 78 : if (pColumn)
1972 : {
1973 78 : Rectangle aArea(rRect);
1974 78 : if ((GetMode() & BROWSER_CURSOR_WO_FOCUS) == BROWSER_CURSOR_WO_FOCUS)
1975 : {
1976 0 : aArea.Top() += 1;
1977 0 : aArea.Bottom() -= 1;
1978 : }
1979 78 : pColumn->Paint(rDev, aArea, m_xPaintRow, getNumberFormatter());
1980 : }
1981 : }
1982 :
1983 4 : bool DbGridControl::CursorMoving(long nNewRow, sal_uInt16 nNewCol)
1984 : {
1985 :
1986 4 : DeactivateCell( false );
1987 :
1988 4 : if ( m_pDataCursor
1989 4 : && ( m_nCurrentPos != nNewRow )
1990 6 : && !SetCurrent( nNewRow )
1991 : )
1992 : {
1993 0 : ActivateCell();
1994 0 : return false;
1995 : }
1996 :
1997 4 : if ( !DbGridControl_Base::CursorMoving( nNewRow, nNewCol ) )
1998 0 : return false;
1999 :
2000 4 : return true;
2001 : }
2002 :
2003 2 : bool DbGridControl::SetCurrent(long nNewRow)
2004 : {
2005 : // Each movement of the datacursor must start with BeginCursorAction and end with
2006 : // EndCursorAction to block all notifications during the movement
2007 2 : BeginCursorAction();
2008 :
2009 : try
2010 : {
2011 : // compare positions
2012 2 : if (SeekCursor(nNewRow))
2013 : {
2014 2 : if (IsFilterRow(nNewRow)) // special mode for filtering
2015 : {
2016 0 : m_xCurrentRow = m_xDataRow = m_xPaintRow = m_xEmptyRow;
2017 0 : m_nCurrentPos = nNewRow;
2018 : }
2019 : else
2020 : {
2021 2 : bool bNewRowInserted = false;
2022 : // Should we go to the insertrow ?
2023 2 : if (IsInsertionRow(nNewRow))
2024 : {
2025 : // to we need to move the cursor to the insert row?
2026 : // we need to insert the if the current row isn't the insert row or if the
2027 : // cursor triggered the move by itselt and we need a reinitialization of the row
2028 0 : Reference< XPropertySet > xCursorProps = m_pDataCursor->getPropertySet();
2029 0 : if ( !::comphelper::getBOOL(xCursorProps->getPropertyValue(FM_PROP_ISNEW)) )
2030 : {
2031 0 : Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
2032 0 : xUpdateCursor->moveToInsertRow();
2033 : }
2034 0 : bNewRowInserted = true;
2035 : }
2036 : else
2037 : {
2038 :
2039 2 : if ( !m_pSeekCursor->isBeforeFirst() && !m_pSeekCursor->isAfterLast() )
2040 : {
2041 2 : Any aBookmark = m_pSeekCursor->getBookmark();
2042 2 : if (!m_xCurrentRow || m_xCurrentRow->IsNew() || !CompareBookmark(aBookmark, m_pDataCursor->getBookmark()))
2043 : {
2044 : // adjust the cursor to the new desired row
2045 2 : if (!m_pDataCursor->moveToBookmark(aBookmark))
2046 : {
2047 0 : EndCursorAction();
2048 0 : return false;
2049 : }
2050 2 : }
2051 : }
2052 : }
2053 2 : m_xDataRow->SetState(m_pDataCursor, false);
2054 2 : m_xCurrentRow = m_xDataRow;
2055 :
2056 2 : long nPaintPos = -1;
2057 : // do we have to repaint the last regular row in case of setting defaults or autovalues
2058 2 : if (m_nCurrentPos >= 0 && m_nCurrentPos >= (GetRowCount() - 2))
2059 0 : nPaintPos = m_nCurrentPos;
2060 :
2061 2 : m_nCurrentPos = nNewRow;
2062 :
2063 : // repaint the new row to display all defaults
2064 2 : if (bNewRowInserted)
2065 0 : RowModified(m_nCurrentPos);
2066 2 : if (nPaintPos >= 0)
2067 0 : RowModified(nPaintPos);
2068 : }
2069 : }
2070 : else
2071 : {
2072 : OSL_FAIL("DbGridControl::SetCurrent : SeekRow failed !");
2073 0 : EndCursorAction();
2074 0 : return false;
2075 : }
2076 : }
2077 0 : catch ( const Exception& )
2078 : {
2079 : DBG_UNHANDLED_EXCEPTION();
2080 0 : EndCursorAction();
2081 0 : return false;
2082 : }
2083 :
2084 2 : EndCursorAction();
2085 2 : return true;
2086 : }
2087 :
2088 73 : void DbGridControl::CursorMoved()
2089 : {
2090 :
2091 : // cursor movement due to deletion or insertion of rows
2092 73 : if (m_pDataCursor && m_nCurrentPos != GetCurRow())
2093 : {
2094 0 : DeactivateCell(true);
2095 0 : SetCurrent(GetCurRow());
2096 : }
2097 :
2098 73 : DbGridControl_Base::CursorMoved();
2099 73 : m_aBar.InvalidateAll(m_nCurrentPos);
2100 :
2101 : // select the new column when they moved
2102 73 : if ( IsDesignMode() && GetSelectedColumnCount() > 0 && GetCurColumnId() )
2103 : {
2104 0 : SelectColumnId( GetCurColumnId() );
2105 : }
2106 :
2107 73 : if ( m_nLastColId != GetCurColumnId() )
2108 6 : onColumnChange();
2109 73 : m_nLastColId = GetCurColumnId();
2110 :
2111 73 : if ( m_nLastRowId != GetCurRow() )
2112 4 : onRowChange();
2113 73 : m_nLastRowId = GetCurRow();
2114 73 : }
2115 :
2116 0 : void DbGridControl::onRowChange()
2117 : {
2118 : // not interested in
2119 0 : }
2120 :
2121 0 : void DbGridControl::onColumnChange()
2122 : {
2123 0 : if ( m_pGridListener )
2124 0 : m_pGridListener->columnChanged();
2125 0 : }
2126 :
2127 55 : void DbGridControl::setDisplaySynchron(bool bSync)
2128 : {
2129 55 : if (bSync != m_bSynchDisplay)
2130 : {
2131 25 : m_bSynchDisplay = bSync;
2132 25 : if (m_bSynchDisplay)
2133 8 : AdjustDataSource(false);
2134 : }
2135 55 : }
2136 :
2137 8 : void DbGridControl::AdjustDataSource(bool bFull)
2138 : {
2139 : SAL_INFO("svx.fmcomp", "DbGridControl::AdjustDataSource");
2140 8 : SolarMutexGuard aGuard;
2141 : // If the current row is recalculated at the moment, do not adjust
2142 :
2143 8 : if (bFull)
2144 0 : m_xCurrentRow = NULL;
2145 : // if we are on the same row only repaint
2146 : // but this is only possible for rows which are not inserted, in that case the comparison result
2147 : // may not be correct
2148 : else
2149 16 : if ( m_xCurrentRow.Is()
2150 0 : && !m_xCurrentRow->IsNew()
2151 0 : && !m_pDataCursor->isBeforeFirst()
2152 0 : && !m_pDataCursor->isAfterLast()
2153 8 : && !m_pDataCursor->rowDeleted()
2154 : )
2155 : {
2156 0 : bool bEqualBookmarks = CompareBookmark( m_xCurrentRow->GetBookmark(), m_pDataCursor->getBookmark() );
2157 :
2158 0 : bool bDataCursorIsOnNew = false;
2159 0 : m_pDataCursor->getPropertySet()->getPropertyValue( FM_PROP_ISNEW ) >>= bDataCursorIsOnNew;
2160 :
2161 0 : if ( bEqualBookmarks && !bDataCursorIsOnNew )
2162 : {
2163 : // position of my data cursor is the same as the position our current row points tpo
2164 : // sync the status, repaint, done
2165 : DBG_ASSERT(m_xDataRow == m_xCurrentRow, "Fehler in den Datenzeilen");
2166 : SAL_INFO("svx.fmcomp", "same position, new state: " << ROWSTATUS(m_xCurrentRow));
2167 0 : RowModified(m_nCurrentPos);
2168 0 : return;
2169 : }
2170 : }
2171 :
2172 : // away from the data cursor's row
2173 8 : if (m_xPaintRow == m_xCurrentRow)
2174 8 : m_xPaintRow = m_xSeekRow;
2175 :
2176 : // not up-to-date row, thus, adjust completely
2177 8 : if (!m_xCurrentRow)
2178 8 : AdjustRows();
2179 :
2180 8 : sal_Int32 nNewPos = AlignSeekCursor();
2181 8 : if (nNewPos < 0)// could not find any position
2182 8 : return;
2183 :
2184 0 : m_bInAdjustDataSource = true;
2185 0 : if (nNewPos != m_nCurrentPos)
2186 : {
2187 0 : if (m_bSynchDisplay)
2188 0 : DbGridControl_Base::GoToRow(nNewPos);
2189 :
2190 0 : if (!m_xCurrentRow.Is())
2191 : // Happens e.g. when deleting the n last datasets (n>1) while the cursor was positioned
2192 : // on the last one. In this case, AdjustRows deletes two rows from BrowseBox, by what
2193 : // CurrentRow is corrected to point two rows down, so that GoToRow will point into
2194 : // emptiness (since we are - purportedly - at the correct position)
2195 0 : SetCurrent(nNewPos);
2196 : }
2197 : else
2198 : {
2199 0 : SetCurrent(nNewPos);
2200 0 : RowModified(nNewPos);
2201 : }
2202 0 : m_bInAdjustDataSource = false;
2203 :
2204 : // if the data cursor was moved from outside, this section is voided
2205 0 : SetNoSelection();
2206 0 : m_aBar.InvalidateAll(m_nCurrentPos, m_xCurrentRow.Is());
2207 : }
2208 :
2209 8 : sal_Int32 DbGridControl::AlignSeekCursor()
2210 : {
2211 : // position SeekCursor onto the data cursor, no data transmission
2212 :
2213 8 : if (!m_pSeekCursor)
2214 8 : return -1;
2215 :
2216 0 : Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
2217 :
2218 : // now align the seek cursor and the data cursor
2219 0 : if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW)))
2220 0 : m_nSeekPos = GetRowCount() - 1;
2221 : else
2222 : {
2223 : try
2224 : {
2225 0 : if ( m_pDataCursor->isBeforeFirst() )
2226 : {
2227 : // this is somewhat strange, but can nevertheless happen
2228 : DBG_WARNING( "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (before first)!" );
2229 0 : m_pSeekCursor->first();
2230 0 : m_pSeekCursor->previous();
2231 0 : m_nSeekPos = -1;
2232 : }
2233 0 : else if ( m_pDataCursor->isAfterLast() )
2234 : {
2235 : DBG_WARNING( "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (after last)!" );
2236 0 : m_pSeekCursor->last();
2237 0 : m_pSeekCursor->next();
2238 0 : m_nSeekPos = -1;
2239 : }
2240 : else
2241 : {
2242 0 : m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
2243 0 : if (!CompareBookmark(m_pDataCursor->getBookmark(), m_pSeekCursor->getBookmark()))
2244 : // unfortunately, moveToBookmark might lead to a re-positioning of the seek
2245 : // cursor (if the complex moveToBookmark with all its events fires an update
2246 : // somewhere) -> retry
2247 0 : m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
2248 : // Now there is still the chance of a failure but it is less likely.
2249 : // The alternative would be an loop until everything is fine - no good solution...
2250 0 : m_nSeekPos = m_pSeekCursor->getRow() - 1;
2251 : }
2252 : }
2253 0 : catch(Exception&)
2254 : {
2255 : }
2256 : }
2257 0 : return m_nSeekPos;
2258 : }
2259 :
2260 20 : bool DbGridControl::SeekCursor(long nRow, bool bAbsolute)
2261 : {
2262 : // position SeekCursor onto the data cursor, no data transmission
2263 :
2264 : // additions for the filtermode
2265 20 : if (IsFilterRow(nRow))
2266 : {
2267 0 : m_nSeekPos = 0;
2268 0 : return true;
2269 : }
2270 :
2271 20 : if (!m_pSeekCursor)
2272 0 : return false;
2273 :
2274 : // is this an insertion?
2275 20 : if (IsValid(m_xCurrentRow) && m_xCurrentRow->IsNew() &&
2276 0 : nRow >= m_nCurrentPos)
2277 : {
2278 : // if so, scrolling down must be prevented as this is already the last data set!
2279 0 : if (nRow == m_nCurrentPos)
2280 : {
2281 : // no adjustment necessary
2282 0 : m_nSeekPos = nRow;
2283 : }
2284 0 : else if (IsInsertionRow(nRow)) // blank row for data insertion
2285 0 : m_nSeekPos = nRow;
2286 : }
2287 20 : else if (IsInsertionRow(nRow)) // blank row for data insertion
2288 0 : m_nSeekPos = nRow;
2289 20 : else if ((-1 == nRow) && (GetRowCount() == ((m_nOptions & OPT_INSERT) ? 1 : 0)) && m_pSeekCursor->isAfterLast())
2290 0 : m_nSeekPos = nRow;
2291 : else
2292 : {
2293 20 : bool bSuccess = false;
2294 20 : long nSteps = 0;
2295 : try
2296 : {
2297 20 : if ( m_pSeekCursor->rowDeleted() )
2298 : {
2299 : // somebody deleted the current row of the seek cursor. Move it away from this row.
2300 0 : m_pSeekCursor->next();
2301 0 : if ( m_pSeekCursor->isAfterLast() || m_pSeekCursor->isBeforeFirst() )
2302 0 : bAbsolute = true;
2303 : }
2304 :
2305 20 : if ( !bAbsolute )
2306 : {
2307 : DBG_ASSERT( !m_pSeekCursor->isAfterLast() && !m_pSeekCursor->isBeforeFirst(),
2308 : "DbGridControl::SeekCursor: how did the seek cursor get to this position?!" );
2309 18 : nSteps = nRow - (m_pSeekCursor->getRow() - 1);
2310 18 : bAbsolute = bAbsolute || (std::abs(nSteps) > 100);
2311 : }
2312 :
2313 20 : if ( bAbsolute )
2314 : {
2315 2 : bSuccess = m_pSeekCursor->absolute(nRow + 1);
2316 2 : if (bSuccess)
2317 2 : m_nSeekPos = nRow;
2318 : }
2319 : else
2320 : {
2321 18 : if (nSteps > 0) // position onto the last needed data set
2322 : {
2323 14 : if (m_pSeekCursor->isAfterLast())
2324 0 : bSuccess = false;
2325 14 : else if (m_pSeekCursor->isBeforeFirst())
2326 0 : bSuccess = m_pSeekCursor->absolute(nSteps);
2327 : else
2328 14 : bSuccess = m_pSeekCursor->relative(nSteps);
2329 : }
2330 4 : else if (nSteps < 0)
2331 : {
2332 0 : if (m_pSeekCursor->isBeforeFirst())
2333 0 : bSuccess = false;
2334 0 : else if (m_pSeekCursor->isAfterLast())
2335 0 : bSuccess = m_pSeekCursor->absolute(nSteps);
2336 : else
2337 0 : bSuccess = m_pSeekCursor->relative(nSteps);
2338 : }
2339 : else
2340 : {
2341 4 : m_nSeekPos = nRow;
2342 4 : return true;
2343 : }
2344 : }
2345 : }
2346 0 : catch(Exception&)
2347 : {
2348 : OSL_FAIL("DbGridControl::SeekCursor : failed ...");
2349 : }
2350 :
2351 : try
2352 : {
2353 16 : if (!bSuccess)
2354 : {
2355 0 : if (bAbsolute || nSteps > 0)
2356 : {
2357 0 : if (m_pSeekCursor->isLast())
2358 0 : bSuccess = true;
2359 : else
2360 0 : bSuccess = m_pSeekCursor->last();
2361 : }
2362 : else
2363 : {
2364 0 : if (m_pSeekCursor->isFirst())
2365 0 : bSuccess = true;
2366 : else
2367 0 : bSuccess = m_pSeekCursor->first();
2368 : }
2369 : }
2370 :
2371 16 : if (bSuccess)
2372 16 : m_nSeekPos = m_pSeekCursor->getRow() - 1;
2373 : else
2374 0 : m_nSeekPos = -1;
2375 : }
2376 0 : catch(Exception&)
2377 : {
2378 : OSL_FAIL("DbGridControl::SeekCursor : failed ...");
2379 : DBG_UNHANDLED_EXCEPTION();
2380 0 : m_nSeekPos = -1; // no further data set available
2381 : }
2382 : }
2383 16 : return m_nSeekPos == nRow;
2384 : }
2385 :
2386 0 : void DbGridControl::MoveToFirst()
2387 : {
2388 0 : if (m_pSeekCursor && (GetCurRow() != 0))
2389 0 : MoveToPosition(0);
2390 0 : }
2391 :
2392 0 : void DbGridControl::MoveToLast()
2393 : {
2394 0 : if (!m_pSeekCursor)
2395 0 : return;
2396 :
2397 0 : if (m_nTotalCount < 0) // no RecordCount, yet
2398 : {
2399 : try
2400 : {
2401 0 : bool bRes = m_pSeekCursor->last();
2402 :
2403 0 : if (bRes)
2404 : {
2405 0 : m_nSeekPos = m_pSeekCursor->getRow() - 1;
2406 0 : AdjustRows();
2407 : }
2408 : }
2409 0 : catch(Exception&)
2410 : {
2411 : }
2412 : }
2413 :
2414 : // position onto the last data set not on a blank row
2415 0 : if (m_nOptions & OPT_INSERT)
2416 : {
2417 0 : if ((GetRowCount() - 1) > 0)
2418 0 : MoveToPosition(GetRowCount() - 2);
2419 : }
2420 0 : else if (GetRowCount())
2421 0 : MoveToPosition(GetRowCount() - 1);
2422 : }
2423 :
2424 0 : void DbGridControl::MoveToPrev()
2425 : {
2426 0 : long nNewRow = std::max(GetCurRow() - 1L, 0L);
2427 0 : if (GetCurRow() != nNewRow)
2428 0 : MoveToPosition(nNewRow);
2429 0 : }
2430 :
2431 0 : void DbGridControl::MoveToNext()
2432 : {
2433 0 : if (!m_pSeekCursor)
2434 0 : return;
2435 :
2436 0 : if (m_nTotalCount > 0)
2437 : {
2438 : // move the data cursor to the right position
2439 0 : long nNewRow = std::min(GetRowCount() - 1, GetCurRow() + 1);
2440 0 : if (GetCurRow() != nNewRow)
2441 0 : MoveToPosition(nNewRow);
2442 : }
2443 : else
2444 : {
2445 0 : bool bOk = false;
2446 : try
2447 : {
2448 : // try to move to next row
2449 : // when not possible our paint cursor is already on the last row
2450 : // then we must be sure that the data cursor is on the position
2451 : // we call ourself again
2452 0 : bOk = m_pSeekCursor->next();
2453 0 : if (bOk)
2454 : {
2455 0 : m_nSeekPos = m_pSeekCursor->getRow() - 1;
2456 0 : MoveToPosition(GetCurRow() + 1);
2457 : }
2458 : }
2459 0 : catch(SQLException &)
2460 : {
2461 : DBG_UNHANDLED_EXCEPTION();
2462 : }
2463 :
2464 0 : if(!bOk)
2465 : {
2466 0 : AdjustRows();
2467 0 : if (m_nTotalCount > 0) // only to avoid infinte recursion
2468 0 : MoveToNext();
2469 : }
2470 : }
2471 : }
2472 :
2473 0 : void DbGridControl::MoveToPosition(sal_uInt32 nPos)
2474 : {
2475 0 : if (!m_pSeekCursor)
2476 0 : return;
2477 :
2478 0 : if (m_nTotalCount < 0 && (long)nPos >= GetRowCount())
2479 : {
2480 : try
2481 : {
2482 0 : if (!m_pSeekCursor->absolute(nPos + 1))
2483 : {
2484 0 : AdjustRows();
2485 0 : return;
2486 : }
2487 : else
2488 : {
2489 0 : m_nSeekPos = m_pSeekCursor->getRow() - 1;
2490 0 : AdjustRows();
2491 : }
2492 : }
2493 0 : catch(Exception&)
2494 : {
2495 0 : return;
2496 : }
2497 : }
2498 0 : DbGridControl_Base::GoToRow(nPos);
2499 0 : m_aBar.InvalidateAll(m_nCurrentPos);
2500 : }
2501 :
2502 0 : void DbGridControl::AppendNew()
2503 : {
2504 0 : if (!m_pSeekCursor || !(m_nOptions & OPT_INSERT))
2505 0 : return;
2506 :
2507 0 : if (m_nTotalCount < 0) // no RecordCount, yet
2508 : {
2509 : try
2510 : {
2511 0 : bool bRes = m_pSeekCursor->last();
2512 :
2513 0 : if (bRes)
2514 : {
2515 0 : m_nSeekPos = m_pSeekCursor->getRow() - 1;
2516 0 : AdjustRows();
2517 : }
2518 : }
2519 0 : catch(Exception&)
2520 : {
2521 0 : return;
2522 : }
2523 : }
2524 :
2525 0 : long nNewRow = m_nTotalCount + 1;
2526 0 : if (nNewRow > 0 && GetCurRow() != nNewRow)
2527 0 : MoveToPosition(nNewRow - 1);
2528 : }
2529 :
2530 43 : void DbGridControl::SetDesignMode(bool bMode)
2531 : {
2532 43 : if ((bool) IsDesignMode() != bMode)
2533 : {
2534 : // adjust Enable/Disable for design mode so that the headerbar remains configurable
2535 43 : if (bMode)
2536 : {
2537 41 : if (!IsEnabled())
2538 : {
2539 6 : Enable();
2540 6 : GetDataWindow().Disable();
2541 : }
2542 : }
2543 : else
2544 : {
2545 : // disable completely
2546 2 : if (!GetDataWindow().IsEnabled())
2547 0 : Disable();
2548 : }
2549 :
2550 43 : m_bDesignMode = bMode;
2551 43 : GetDataWindow().SetMouseTransparent(bMode);
2552 43 : SetMouseTransparent(bMode);
2553 :
2554 43 : m_aBar.InvalidateAll(m_nCurrentPos, true);
2555 : }
2556 43 : }
2557 :
2558 0 : void DbGridControl::SetFilterMode(bool bMode)
2559 : {
2560 0 : if (IsFilterMode() != bMode)
2561 : {
2562 0 : m_bFilterMode = bMode;
2563 :
2564 0 : if (bMode)
2565 : {
2566 0 : SetUpdateMode(false);
2567 :
2568 : // there is no cursor anymore
2569 0 : if (IsEditing())
2570 0 : DeactivateCell();
2571 0 : RemoveRows(false);
2572 :
2573 0 : m_xEmptyRow = new DbGridRow();
2574 :
2575 : // setting the new filter controls
2576 0 : for ( size_t i = 0; i < m_aColumns.size(); ++i )
2577 : {
2578 0 : DbGridColumn* pCurCol = m_aColumns[ i ];
2579 0 : if (!pCurCol->IsHidden())
2580 0 : pCurCol->UpdateControl();
2581 : }
2582 :
2583 : // one row for filtering
2584 0 : RowInserted(0, 1, true);
2585 0 : SetUpdateMode(true);
2586 : }
2587 : else
2588 0 : setDataSource(Reference< XRowSet > ());
2589 : }
2590 0 : }
2591 :
2592 0 : OUString DbGridControl::GetCellText(long _nRow, sal_uInt16 _nColId) const
2593 : {
2594 0 : size_t Location = GetModelColumnPos( _nColId );
2595 0 : DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ] : NULL;
2596 0 : OUString sRet;
2597 0 : if ( const_cast<DbGridControl*>(this)->SeekRow(_nRow) )
2598 0 : sRet = GetCurrentRowCellText(pColumn, m_xPaintRow);
2599 0 : return sRet;
2600 : }
2601 :
2602 0 : OUString DbGridControl::GetCurrentRowCellText(DbGridColumn* pColumn,const DbGridRowRef& _rRow) const
2603 : {
2604 : // text output for a single row
2605 0 : OUString aText;
2606 0 : if ( pColumn && IsValid(_rRow) )
2607 0 : aText = pColumn->GetCellText(_rRow, m_xFormatter);
2608 0 : return aText;
2609 : }
2610 :
2611 0 : sal_uInt32 DbGridControl::GetTotalCellWidth(long nRow, sal_uInt16 nColId)
2612 : {
2613 0 : if (SeekRow(nRow))
2614 : {
2615 0 : size_t Location = GetModelColumnPos( nColId );
2616 0 : DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ] : NULL;
2617 0 : return GetDataWindow().GetTextWidth(GetCurrentRowCellText(pColumn,m_xPaintRow));
2618 : }
2619 : else
2620 0 : return 30; // FIXME magic number for defaul cell width
2621 : }
2622 :
2623 0 : void DbGridControl::PreExecuteRowContextMenu(sal_uInt16 /*nRow*/, PopupMenu& rMenu)
2624 : {
2625 0 : bool bDelete = (m_nOptions & OPT_DELETE) && GetSelectRowCount() && !IsCurrentAppending();
2626 : // if only a blank row is selected than do not delete
2627 0 : bDelete = bDelete && !((m_nOptions & OPT_INSERT) && GetSelectRowCount() == 1 && IsRowSelected(GetRowCount() - 1));
2628 :
2629 0 : rMenu.EnableItem(SID_FM_DELETEROWS, bDelete);
2630 0 : rMenu.EnableItem(SID_FM_RECORD_SAVE, IsModified());
2631 :
2632 : // the undo is more difficult
2633 0 : bool bCanUndo = IsModified();
2634 0 : long nState = -1;
2635 0 : if (m_aMasterStateProvider.IsSet())
2636 0 : nState = m_aMasterStateProvider.Call(reinterpret_cast<void*>(SID_FM_RECORD_UNDO));
2637 0 : bCanUndo &= ( 0 != nState );
2638 :
2639 0 : rMenu.EnableItem(SID_FM_RECORD_UNDO, bCanUndo);
2640 0 : }
2641 :
2642 0 : void DbGridControl::PostExecuteRowContextMenu(sal_uInt16 /*nRow*/, const PopupMenu& /*rMenu*/, sal_uInt16 nExecutionResult)
2643 : {
2644 0 : switch (nExecutionResult)
2645 : {
2646 : case SID_FM_DELETEROWS:
2647 : // delete asynchronously
2648 0 : if (m_nDeleteEvent)
2649 0 : Application::RemoveUserEvent(m_nDeleteEvent);
2650 0 : m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete));
2651 0 : break;
2652 : case SID_FM_RECORD_UNDO:
2653 0 : Undo();
2654 0 : break;
2655 : case SID_FM_RECORD_SAVE:
2656 0 : SaveRow();
2657 0 : break;
2658 : default:
2659 0 : break;
2660 : }
2661 0 : }
2662 :
2663 0 : void DbGridControl::DataSourcePropertyChanged(const PropertyChangeEvent& evt) throw( RuntimeException )
2664 : {
2665 : SAL_INFO("svx.fmcomp", "DbGridControl::DataSourcePropertyChanged");
2666 0 : SolarMutexGuard aGuard;
2667 : // prop "IsModified" changed ?
2668 : // during update don't care about the modified state
2669 0 : if (!IsUpdating() && evt.PropertyName == FM_PROP_ISMODIFIED )
2670 : {
2671 0 : Reference< XPropertySet > xSource(evt.Source, UNO_QUERY);
2672 : DBG_ASSERT( xSource.is(), "DbGridControl::DataSourcePropertyChanged: invalid event source!" );
2673 0 : bool bIsNew = false;
2674 0 : if (xSource.is())
2675 0 : bIsNew = ::comphelper::getBOOL(xSource->getPropertyValue(FM_PROP_ISNEW));
2676 :
2677 0 : if (bIsNew && m_xCurrentRow.Is())
2678 : {
2679 : DBG_ASSERT(::comphelper::getBOOL(xSource->getPropertyValue(FM_PROP_ROWCOUNTFINAL)), "DbGridControl::DataSourcePropertyChanged : somebody moved the form to a new record before the row count was final !");
2680 0 : sal_Int32 nRecordCount = 0;
2681 0 : xSource->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
2682 0 : if (::comphelper::getBOOL(evt.NewValue))
2683 : { // modified state changed from sal_False to sal_True and we're on a insert row
2684 : // -> we've to add a new grid row
2685 0 : if ((nRecordCount == GetRowCount() - 1) && m_xCurrentRow->IsNew())
2686 : {
2687 0 : RowInserted(GetRowCount(), 1, true);
2688 0 : InvalidateStatusCell(m_nCurrentPos);
2689 0 : m_aBar.InvalidateAll(m_nCurrentPos);
2690 : }
2691 : }
2692 : else
2693 : { // modified state changed from sal_True to sal_False and we're on a insert row
2694 : // we have two "new row"s at the moment : the one we're editing currently (where the current
2695 : // column is the only dirty element) and a "new new" row which is completely clean. As the first
2696 : // one is about to be cleaned, too, the second one is obsolete now.
2697 0 : if (m_xCurrentRow->IsNew() && nRecordCount == (GetRowCount() - 2))
2698 : {
2699 0 : RowRemoved(GetRowCount() - 1, 1, true);
2700 0 : InvalidateStatusCell(m_nCurrentPos);
2701 0 : m_aBar.InvalidateAll(m_nCurrentPos);
2702 : }
2703 : }
2704 : }
2705 0 : if (m_xCurrentRow.Is())
2706 : {
2707 0 : m_xCurrentRow->SetStatus(::comphelper::getBOOL(evt.NewValue) ? GRS_MODIFIED : GRS_CLEAN);
2708 0 : m_xCurrentRow->SetNew( bIsNew );
2709 0 : InvalidateStatusCell(m_nCurrentPos);
2710 : SAL_INFO("svx.fmcomp", "modified flag changed, new state: " << ROWSTATUS(m_xCurrentRow));
2711 0 : }
2712 0 : }
2713 0 : }
2714 :
2715 0 : void DbGridControl::StartDrag( sal_Int8 /*nAction*/, const Point& rPosPixel )
2716 : {
2717 0 : if (!m_pSeekCursor || IsResizing())
2718 0 : return;
2719 :
2720 0 : sal_uInt16 nColId = GetColumnAtXPosPixel(rPosPixel.X());
2721 0 : long nRow = GetRowAtYPosPixel(rPosPixel.Y());
2722 0 : if (nColId != HandleColumnId && nRow >= 0)
2723 : {
2724 0 : if (GetDataWindow().IsMouseCaptured())
2725 0 : GetDataWindow().ReleaseMouse();
2726 :
2727 0 : size_t Location = GetModelColumnPos( nColId );
2728 0 : DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ] : NULL;
2729 0 : OStringTransferable* pTransferable = new OStringTransferable(GetCurrentRowCellText(pColumn,m_xPaintRow));
2730 0 : Reference< XTransferable > xEnsureDelete(pTransferable);
2731 0 : pTransferable->StartDrag(this, DND_ACTION_COPY);
2732 : }
2733 : }
2734 :
2735 0 : bool DbGridControl::canCopyCellText(sal_Int32 _nRow, sal_Int16 _nColId)
2736 : {
2737 : return (_nRow >= 0)
2738 0 : && (_nRow < GetRowCount())
2739 0 : && (_nColId != HandleColumnId)
2740 0 : && (_nColId <= ColCount());
2741 : }
2742 :
2743 0 : void DbGridControl::copyCellText(sal_Int32 _nRow, sal_Int16 _nColId)
2744 : {
2745 : DBG_ASSERT(canCopyCellText(_nRow, _nColId), "DbGridControl::copyCellText: invalid call!");
2746 0 : DbGridColumn* pColumn = m_aColumns[ GetModelColumnPos(_nColId) ];
2747 0 : SeekRow(_nRow);
2748 0 : OStringTransfer::CopyString( GetCurrentRowCellText( pColumn,m_xPaintRow ), this );
2749 0 : }
2750 :
2751 0 : void DbGridControl::executeRowContextMenu( long _nRow, const Point& _rPreferredPos )
2752 : {
2753 0 : PopupMenu aContextMenu( SVX_RES( RID_SVXMNU_ROWS ) );
2754 :
2755 0 : PreExecuteRowContextMenu( (sal_uInt16)_nRow, aContextMenu );
2756 0 : aContextMenu.RemoveDisabledEntries( true, true );
2757 0 : PostExecuteRowContextMenu( (sal_uInt16)_nRow, aContextMenu, aContextMenu.Execute( this, _rPreferredPos ) );
2758 :
2759 : // TODO: why this weird cast to sal_uInt16? What if we really have more than 65535 lines?
2760 : // -> change this to sal_uInt32
2761 0 : }
2762 :
2763 0 : void DbGridControl::Command(const CommandEvent& rEvt)
2764 : {
2765 0 : switch (rEvt.GetCommand())
2766 : {
2767 : case COMMAND_CONTEXTMENU:
2768 : {
2769 0 : if ( !m_pSeekCursor )
2770 : {
2771 0 : DbGridControl_Base::Command(rEvt);
2772 0 : return;
2773 : }
2774 :
2775 0 : if ( !rEvt.IsMouseEvent() )
2776 : { // context menu requested by keyboard
2777 0 : if ( GetSelectRowCount() )
2778 : {
2779 0 : long nRow = FirstSelectedRow( );
2780 :
2781 0 : ::Rectangle aRowRect( GetRowRectPixel( nRow, true ) );
2782 0 : executeRowContextMenu( nRow, aRowRect.LeftCenter() );
2783 :
2784 : // handled
2785 0 : return;
2786 : }
2787 : }
2788 :
2789 0 : sal_uInt16 nColId = GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X());
2790 0 : long nRow = GetRowAtYPosPixel(rEvt.GetMousePosPixel().Y());
2791 :
2792 0 : if (nColId == HandleColumnId)
2793 : {
2794 0 : executeRowContextMenu( nRow, rEvt.GetMousePosPixel() );
2795 : }
2796 0 : else if (canCopyCellText(nRow, nColId))
2797 : {
2798 0 : PopupMenu aContextMenu(SVX_RES(RID_SVXMNU_CELL));
2799 0 : aContextMenu.RemoveDisabledEntries(true, true);
2800 0 : switch (aContextMenu.Execute(this, rEvt.GetMousePosPixel()))
2801 : {
2802 : case SID_COPY:
2803 0 : copyCellText(nRow, nColId);
2804 0 : break;
2805 0 : }
2806 : }
2807 : else
2808 : {
2809 0 : DbGridControl_Base::Command(rEvt);
2810 0 : return;
2811 : }
2812 : }
2813 : //fall-through
2814 : default:
2815 0 : DbGridControl_Base::Command(rEvt);
2816 : }
2817 : }
2818 :
2819 0 : IMPL_LINK(DbGridControl, OnDelete, void*, /*EMPTYTAG*/ )
2820 : {
2821 0 : m_nDeleteEvent = 0;
2822 0 : DeleteSelectedRows();
2823 0 : return 0;
2824 : }
2825 :
2826 0 : void DbGridControl::DeleteSelectedRows()
2827 : {
2828 : DBG_ASSERT(GetSelection(), "keine selection!!!");
2829 :
2830 0 : if (!m_pSeekCursor)
2831 0 : return;
2832 : }
2833 :
2834 2 : CellController* DbGridControl::GetController(long /*nRow*/, sal_uInt16 nColumnId)
2835 : {
2836 2 : if (!IsValid(m_xCurrentRow) || !IsEnabled())
2837 0 : return NULL;
2838 :
2839 2 : size_t Location = GetModelColumnPos(nColumnId);
2840 2 : DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ] : NULL;
2841 2 : if (!pColumn)
2842 0 : return NULL;
2843 :
2844 2 : CellController* pReturn = NULL;
2845 2 : if (IsFilterMode())
2846 0 : pReturn = &pColumn->GetController();
2847 : else
2848 : {
2849 2 : if (::comphelper::hasProperty(FM_PROP_ENABLED, pColumn->getModel()))
2850 : {
2851 2 : if (!::comphelper::getBOOL(pColumn->getModel()->getPropertyValue(FM_PROP_ENABLED)))
2852 0 : return NULL;
2853 : }
2854 :
2855 2 : bool bInsert = (m_xCurrentRow->IsNew() && (m_nOptions & OPT_INSERT));
2856 2 : bool bUpdate = (!m_xCurrentRow->IsNew() && (m_nOptions & OPT_UPDATE));
2857 :
2858 2 : if ((bInsert && !pColumn->IsAutoValue()) || bUpdate || m_bForceROController)
2859 : {
2860 2 : pReturn = &pColumn->GetController();
2861 2 : if (pReturn)
2862 : {
2863 : // if it is an edit row, it is possible to give it a forced read-only property
2864 2 : if (!pReturn->ISA(EditCellController) && !pReturn->ISA(SpinCellController))
2865 : // controller could not be set to read-only in forceROController
2866 0 : if (!bInsert && !bUpdate)
2867 : // better use no controller than one without read-only
2868 0 : pReturn = NULL;
2869 : }
2870 : }
2871 : }
2872 2 : return pReturn;
2873 : }
2874 :
2875 2 : void DbGridControl::InitController(CellControllerRef& /*rController*/, long /*nRow*/, sal_uInt16 nColumnId)
2876 : {
2877 2 : size_t Location = GetModelColumnPos(nColumnId);
2878 2 : DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ] : NULL;
2879 2 : if (pColumn)
2880 2 : pColumn->UpdateFromField(m_xCurrentRow, m_xFormatter);
2881 2 : }
2882 :
2883 0 : void DbGridControl::CellModified()
2884 : {
2885 : SAL_INFO("svx.fmcomp", "DbGridControl::CellModified");
2886 :
2887 : {
2888 0 : ::osl::MutexGuard aGuard(m_aAdjustSafety);
2889 0 : if (m_nAsynAdjustEvent)
2890 : {
2891 : SAL_INFO("svx.fmcomp", "forcing a synchron call to " << (m_bPendingAdjustRows ? "AdjustRows" : "AdustDataSource"));
2892 0 : RemoveUserEvent(m_nAsynAdjustEvent);
2893 0 : m_nAsynAdjustEvent = 0;
2894 :
2895 : // force the call : this should be no problem as we're probably running in the solar thread here
2896 : // (cell modified is triggered by user actions)
2897 0 : if (m_bPendingAdjustRows)
2898 0 : AdjustRows();
2899 : else
2900 0 : AdjustDataSource();
2901 0 : }
2902 : }
2903 :
2904 0 : if (!IsFilterMode() && IsValid(m_xCurrentRow) && !m_xCurrentRow->IsModified())
2905 : {
2906 : // enable edit mode
2907 : // a data set should be inserted
2908 0 : if (m_xCurrentRow->IsNew())
2909 : {
2910 0 : m_xCurrentRow->SetStatus(GRS_MODIFIED);
2911 : SAL_INFO("svx.fmcomp", "current row is new, new state: MODIFIED");
2912 : // if no row was added yet, do it now
2913 0 : if (m_nCurrentPos == GetRowCount() - 1)
2914 : {
2915 : // increment RowCount
2916 0 : RowInserted(GetRowCount(), 1, true);
2917 0 : InvalidateStatusCell(m_nCurrentPos);
2918 0 : m_aBar.InvalidateAll(m_nCurrentPos);
2919 : }
2920 : }
2921 0 : else if (m_xCurrentRow->GetStatus() != GRS_MODIFIED)
2922 : {
2923 0 : m_xCurrentRow->SetState(m_pDataCursor, false);
2924 : SAL_INFO("svx.fmcomp", "current row is not new, after SetState, new state: " << ROWSTATUS(m_xCurrentRow));
2925 0 : m_xCurrentRow->SetStatus(GRS_MODIFIED);
2926 : SAL_INFO("svx.fmcomp", "current row is not new, new state: MODIFIED");
2927 0 : InvalidateStatusCell(m_nCurrentPos);
2928 : }
2929 : }
2930 0 : }
2931 :
2932 0 : void DbGridControl::Dispatch(sal_uInt16 nId)
2933 : {
2934 0 : if (nId == BROWSER_CURSORENDOFFILE)
2935 : {
2936 0 : if (m_nOptions & OPT_INSERT)
2937 0 : AppendNew();
2938 : else
2939 0 : MoveToLast();
2940 : }
2941 : else
2942 0 : DbGridControl_Base::Dispatch(nId);
2943 0 : }
2944 :
2945 0 : void DbGridControl::Undo()
2946 : {
2947 0 : if (!IsFilterMode() && IsValid(m_xCurrentRow) && IsModified())
2948 : {
2949 : // check if we have somebody doin' the UNDO for us
2950 0 : long nState = -1;
2951 0 : if (m_aMasterStateProvider.IsSet())
2952 0 : nState = m_aMasterStateProvider.Call(reinterpret_cast<void*>(SID_FM_RECORD_UNDO));
2953 0 : if (nState>0)
2954 : { // yes, we have, and the slot is enabled
2955 : DBG_ASSERT(m_aMasterSlotExecutor.IsSet(), "DbGridControl::Undo : a state, but no execute link ?");
2956 0 : long lResult = m_aMasterSlotExecutor.Call(reinterpret_cast<void*>(SID_FM_RECORD_UNDO));
2957 0 : if (lResult)
2958 : // handled
2959 0 : return;
2960 : }
2961 0 : else if (nState == 0)
2962 : // yes, we have, and the slot is disabled
2963 0 : return;
2964 :
2965 0 : BeginCursorAction();
2966 :
2967 0 : bool bAppending = m_xCurrentRow->IsNew();
2968 0 : bool bDirty = m_xCurrentRow->IsModified();
2969 :
2970 : try
2971 : {
2972 : // cancel editing
2973 0 : Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
2974 : // no effects if we're not updating currently
2975 0 : if (bAppending)
2976 : // just refresh the row
2977 0 : xUpdateCursor->moveToInsertRow();
2978 : else
2979 0 : xUpdateCursor->cancelRowUpdates();
2980 :
2981 : }
2982 0 : catch(Exception&)
2983 : {
2984 : DBG_UNHANDLED_EXCEPTION();
2985 : }
2986 :
2987 0 : EndCursorAction();
2988 :
2989 0 : m_xDataRow->SetState(m_pDataCursor, false);
2990 0 : if (&m_xPaintRow == &m_xCurrentRow)
2991 0 : m_xPaintRow = m_xCurrentRow = m_xDataRow;
2992 : else
2993 0 : m_xCurrentRow = m_xDataRow;
2994 :
2995 0 : if (bAppending && (DbGridControl_Base::IsModified() || bDirty))
2996 : // remove the row
2997 0 : if (m_nCurrentPos == GetRowCount() - 2)
2998 : { // maybe we already removed it (in resetCurrentRow, called if the above moveToInsertRow
2999 : // caused our data source form to be reset - which should be the usual case ....)
3000 0 : RowRemoved(GetRowCount() - 1, 1, true);
3001 0 : m_aBar.InvalidateAll(m_nCurrentPos);
3002 : }
3003 :
3004 0 : RowModified(m_nCurrentPos);
3005 : }
3006 : }
3007 :
3008 4 : void DbGridControl::resetCurrentRow()
3009 : {
3010 4 : if (IsModified())
3011 : {
3012 : // scenario : we're on the insert row, the row is dirty, and thus there exists a "second" insert row (which
3013 : // is clean). Normally in DataSourcePropertyChanged we would remove this second row if the modified state of
3014 : // the insert row changes from sal_True to sal_False. But if our current cell is the only modified element (means the
3015 : // data source isn't modified) and we're reset this DataSourcePropertyChanged would never be called, so we
3016 : // would never delete the obsolete "second insert row". Thus in this special case this method here
3017 : // is the only possibility to determine the redundance of the row (resetCurrentRow is called when the
3018 : // "first insert row" is about to be cleaned, so of course the "second insert row" is redundant now)
3019 0 : Reference< XPropertySet > xDataSource = getDataSource()->getPropertySet();
3020 0 : if (xDataSource.is() && !::comphelper::getBOOL(xDataSource->getPropertyValue(FM_PROP_ISMODIFIED)))
3021 : {
3022 : // are we on a new row currently ?
3023 0 : if (m_xCurrentRow->IsNew())
3024 : {
3025 0 : if (m_nCurrentPos == GetRowCount() - 2)
3026 : {
3027 0 : RowRemoved(GetRowCount() - 1, 1, true);
3028 0 : m_aBar.InvalidateAll(m_nCurrentPos);
3029 : }
3030 : }
3031 : }
3032 :
3033 : // update the rows
3034 0 : m_xDataRow->SetState(m_pDataCursor, false);
3035 0 : if (&m_xPaintRow == &m_xCurrentRow)
3036 0 : m_xPaintRow = m_xCurrentRow = m_xDataRow;
3037 : else
3038 0 : m_xCurrentRow = m_xDataRow;
3039 : }
3040 :
3041 4 : RowModified(GetCurRow()); // will update the current controller if affected
3042 4 : }
3043 :
3044 4 : void DbGridControl::RowModified( long nRow, sal_uInt16 /*nColId*/ )
3045 : {
3046 4 : if (nRow == m_nCurrentPos && IsEditing())
3047 : {
3048 0 : CellControllerRef aTmpRef = Controller();
3049 0 : aTmpRef->ClearModified();
3050 0 : InitController(aTmpRef, m_nCurrentPos, GetCurColumnId());
3051 : }
3052 4 : DbGridControl_Base::RowModified(nRow);
3053 4 : }
3054 :
3055 12 : bool DbGridControl::IsModified() const
3056 : {
3057 12 : return !IsFilterMode() && IsValid(m_xCurrentRow) && (m_xCurrentRow->IsModified() || DbGridControl_Base::IsModified());
3058 : }
3059 :
3060 6 : bool DbGridControl::IsCurrentAppending() const
3061 : {
3062 6 : return m_xCurrentRow.Is() && m_xCurrentRow->IsNew();
3063 : }
3064 :
3065 50 : bool DbGridControl::IsInsertionRow(long nRow) const
3066 : {
3067 50 : return (m_nOptions & OPT_INSERT) && m_nTotalCount >= 0 && (nRow == GetRowCount() - 1);
3068 : }
3069 :
3070 0 : bool DbGridControl::SaveModified()
3071 : {
3072 : SAL_INFO("svx.fmcomp", "DbGridControl::SaveModified");
3073 : DBG_ASSERT(IsValid(m_xCurrentRow), "GridControl:: Invalid row");
3074 0 : if (!IsValid(m_xCurrentRow))
3075 0 : return true;
3076 :
3077 : // accept input for this field
3078 : // Where there changes at the current input field?
3079 0 : if (!DbGridControl_Base::IsModified())
3080 0 : return true;
3081 :
3082 0 : size_t Location = GetModelColumnPos( GetCurColumnId() );
3083 0 : DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ] : NULL;
3084 0 : bool bOK = pColumn && pColumn->Commit();
3085 : DBG_ASSERT( Controller().Is(), "DbGridControl::SaveModified: was modified, by have no controller?!" );
3086 0 : if ( !Controller().Is() )
3087 : // this might happen if the callbacks implicitly triggered by Commit
3088 : // fiddled with the form or the control ...
3089 : // (Note that this here is a workaround, at most. We need a general concept how
3090 : // to treat this, you can imagine an arbitrary number of scenarios where a callback
3091 : // triggers something which leaves us in an expected state.)
3092 : // #i67147# / 2006-07-17 / frank.schoenheit@sun.com
3093 0 : return bOK;
3094 :
3095 0 : if (bOK)
3096 : {
3097 0 : Controller()->ClearModified();
3098 :
3099 0 : if ( IsValid(m_xCurrentRow) )
3100 : {
3101 0 : m_xCurrentRow->SetState(m_pDataCursor, false);
3102 : SAL_INFO("svx.fmcomp", "explicit SetState, new state: " << ROWSTATUS(m_xCurrentRow));
3103 0 : InvalidateStatusCell( m_nCurrentPos );
3104 : }
3105 : else
3106 : {
3107 : SAL_INFO("svx.fmcomp", "no SetState, new state: " << ROWSTATUS(m_xCurrentRow));
3108 : }
3109 : }
3110 : else
3111 : {
3112 : // reset the modified flag ....
3113 0 : Controller()->SetModified();
3114 : }
3115 :
3116 0 : return bOK;
3117 : }
3118 :
3119 0 : bool DbGridControl::SaveRow()
3120 : {
3121 : SAL_INFO("svx.fmcomp", "DbGridControl::SaveRow");
3122 : // valid row
3123 0 : if (!IsValid(m_xCurrentRow) || !IsModified())
3124 0 : return true;
3125 : // value of the controller was not saved, yet
3126 0 : else if (Controller().Is() && Controller()->IsModified())
3127 : {
3128 0 : if (!SaveModified())
3129 0 : return false;
3130 : }
3131 0 : m_bUpdating = true;
3132 :
3133 0 : BeginCursorAction();
3134 0 : bool bAppending = m_xCurrentRow->IsNew();
3135 0 : bool bSuccess = false;
3136 : try
3137 : {
3138 0 : Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
3139 0 : if (bAppending)
3140 0 : xUpdateCursor->insertRow();
3141 : else
3142 0 : xUpdateCursor->updateRow();
3143 0 : bSuccess = true;
3144 : }
3145 0 : catch(SQLException&)
3146 : {
3147 0 : EndCursorAction();
3148 0 : m_bUpdating = false;
3149 0 : return false;
3150 : }
3151 :
3152 : try
3153 : {
3154 0 : if (bSuccess)
3155 : {
3156 : // if we are appending we still sit on the insert row
3157 : // we don't move just clear the flags not to move on the current row
3158 0 : m_xCurrentRow->SetState(m_pDataCursor, false);
3159 : SAL_INFO("svx.fmcomp", "explicit SetState after a successful update, new state: " << ROWSTATUS(m_xCurrentRow));
3160 0 : m_xCurrentRow->SetNew(false);
3161 :
3162 : // adjust the seekcursor if it is on the same position as the datacursor
3163 0 : if (m_nSeekPos == m_nCurrentPos || bAppending)
3164 : {
3165 : // get the bookmark to refetch the data
3166 : // in insert mode we take the new bookmark of the data cursor
3167 0 : Any aBookmark = bAppending ? m_pDataCursor->getBookmark() : m_pSeekCursor->getBookmark();
3168 0 : m_pSeekCursor->moveToBookmark(aBookmark);
3169 : // get the data
3170 0 : m_xSeekRow->SetState(m_pSeekCursor, true);
3171 0 : m_nSeekPos = m_pSeekCursor->getRow() - 1;
3172 : }
3173 : }
3174 : // and repaint the row
3175 0 : RowModified(m_nCurrentPos);
3176 : }
3177 0 : catch(Exception&)
3178 : {
3179 : }
3180 :
3181 0 : m_bUpdating = false;
3182 0 : EndCursorAction();
3183 :
3184 : // The old code returned (nRecords != 0) here.
3185 : // Me thinks this is wrong : If something goes wrong while update the record, an exception will be thrown,
3186 : // which results in a "return sal_False" (see above). If no exception is thrown, everything is fine. If nRecords
3187 : // is zero, this simply means all fields had their original values.
3188 : // FS - 06.12.99 - 70502
3189 0 : return true;
3190 : }
3191 :
3192 0 : bool DbGridControl::PreNotify(NotifyEvent& rEvt)
3193 : {
3194 : // do not handle events of the Navbar
3195 0 : if (m_aBar.IsWindowOrChild(rEvt.GetWindow()))
3196 0 : return BrowseBox::PreNotify(rEvt);
3197 :
3198 0 : switch (rEvt.GetType())
3199 : {
3200 : case EVENT_KEYINPUT:
3201 : {
3202 0 : const KeyEvent* pKeyEvent = rEvt.GetKeyEvent();
3203 :
3204 0 : sal_uInt16 nCode = pKeyEvent->GetKeyCode().GetCode();
3205 0 : bool bShift = pKeyEvent->GetKeyCode().IsShift();
3206 0 : bool bCtrl = pKeyEvent->GetKeyCode().IsMod1();
3207 0 : bool bAlt = pKeyEvent->GetKeyCode().IsMod2();
3208 0 : if ( ( KEY_TAB == nCode ) && bCtrl && !bAlt )
3209 : {
3210 : // Ctrl-Tab is used to step out of the control, without traveling to the
3211 : // remaining cells first
3212 : // -> build a new key event without the Ctrl-key, and let the very base class handle it
3213 0 : vcl::KeyCode aNewCode( KEY_TAB, bShift, false, false, false );
3214 0 : KeyEvent aNewEvent( pKeyEvent->GetCharCode(), aNewCode );
3215 :
3216 : // call the Control - our direct base class will interpret this in a way we do not want (and do
3217 : // a cell traveling)
3218 0 : Control::KeyInput( aNewEvent );
3219 0 : return true;
3220 : }
3221 :
3222 0 : if ( !bShift && !bCtrl && ( KEY_ESCAPE == nCode ) )
3223 : {
3224 0 : if (IsModified())
3225 : {
3226 0 : Undo();
3227 0 : return true;
3228 : }
3229 : }
3230 0 : else if ( ( KEY_DELETE == nCode ) && !bShift && !bCtrl ) // delete rows
3231 : {
3232 0 : if ((m_nOptions & OPT_DELETE) && GetSelectRowCount())
3233 : {
3234 : // delete asynchronously
3235 0 : if (m_nDeleteEvent)
3236 0 : Application::RemoveUserEvent(m_nDeleteEvent);
3237 0 : m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete));
3238 0 : return true;
3239 : }
3240 : }
3241 : } // no break!
3242 : default:
3243 0 : return DbGridControl_Base::PreNotify(rEvt);
3244 : }
3245 : }
3246 :
3247 0 : bool DbGridControl::IsTabAllowed(bool bRight) const
3248 : {
3249 0 : if (bRight)
3250 : // Tab only if not on the _last_ row
3251 0 : return GetCurRow() < (GetRowCount() - 1) || !m_bRecordCountFinal ||
3252 0 : GetViewColumnPos(GetCurColumnId()) < (GetViewColCount() - 1);
3253 : else
3254 : {
3255 : // Tab only if not on the _first_ row
3256 0 : return GetCurRow() > 0 || (GetCurColumnId() && GetViewColumnPos(GetCurColumnId()) > 0);
3257 : }
3258 : }
3259 :
3260 0 : void DbGridControl::KeyInput( const KeyEvent& rEvt )
3261 : {
3262 0 : if (rEvt.GetKeyCode().GetFunction() == KeyFuncType::COPY)
3263 : {
3264 0 : long nRow = GetCurRow();
3265 0 : sal_uInt16 nColId = GetCurColumnId();
3266 0 : if (nRow >= 0 && nRow < GetRowCount() && nColId < ColCount())
3267 : {
3268 0 : size_t Location = GetModelColumnPos( nColId );
3269 0 : DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ] : NULL;
3270 0 : OStringTransfer::CopyString( GetCurrentRowCellText( pColumn, m_xCurrentRow ), this );
3271 0 : return;
3272 : }
3273 : }
3274 0 : DbGridControl_Base::KeyInput(rEvt);
3275 : }
3276 :
3277 0 : void DbGridControl::HideColumn(sal_uInt16 nId)
3278 : {
3279 0 : DeactivateCell();
3280 :
3281 : // determine the col for the focus to set to after removal
3282 0 : sal_uInt16 nPos = GetViewColumnPos(nId);
3283 0 : sal_uInt16 nNewColId = nPos == (ColCount()-1)
3284 0 : ? GetColumnIdFromViewPos(nPos-1) // last col is to be removed -> take the previous
3285 0 : : GetColumnIdFromViewPos(nPos+1); // take the next
3286 :
3287 0 : long lCurrentWidth = GetColumnWidth(nId);
3288 0 : DbGridControl_Base::RemoveColumn(nId);
3289 : // don't use my own RemoveColumn, this would remove it from m_aColumns, too
3290 :
3291 : // update my model
3292 0 : size_t Location = GetModelColumnPos( nId );
3293 0 : DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ] : NULL;
3294 : DBG_ASSERT(pColumn, "DbGridControl::HideColumn : somebody did hide a nonexistent column !");
3295 0 : if (pColumn)
3296 : {
3297 0 : pColumn->m_bHidden = true;
3298 0 : pColumn->m_nLastVisibleWidth = CalcReverseZoom(lCurrentWidth);
3299 : }
3300 :
3301 : // and reset the focus
3302 0 : if ( nId == GetCurColumnId() )
3303 0 : GoToColumnId( nNewColId );
3304 0 : }
3305 :
3306 0 : void DbGridControl::ShowColumn(sal_uInt16 nId)
3307 : {
3308 0 : sal_uInt16 nPos = GetModelColumnPos(nId);
3309 : DBG_ASSERT(nPos != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : invalid argument !");
3310 0 : if (nPos == GRID_COLUMN_NOT_FOUND)
3311 0 : return;
3312 :
3313 0 : DbGridColumn* pColumn = m_aColumns[ nPos ];
3314 0 : if (!pColumn->IsHidden())
3315 : {
3316 : DBG_ASSERT(GetViewColumnPos(nId) != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
3317 : // if the column isn't marked as hidden, it should be visible, shouldn't it ?
3318 0 : return;
3319 : }
3320 : DBG_ASSERT(GetViewColumnPos(nId) == GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
3321 : // the opposite situation ...
3322 :
3323 : // to determine the new view position we need an adjacent non-hidden column
3324 0 : sal_uInt16 nNextNonHidden = BROWSER_INVALIDID;
3325 : // first search the cols to the right
3326 0 : for ( size_t i = nPos + 1; i < m_aColumns.size(); ++i )
3327 : {
3328 0 : DbGridColumn* pCurCol = m_aColumns[ i ];
3329 0 : if (!pCurCol->IsHidden())
3330 : {
3331 0 : nNextNonHidden = i;
3332 0 : break;
3333 : }
3334 : }
3335 0 : if ((nNextNonHidden == BROWSER_INVALIDID) && (nPos > 0))
3336 : {
3337 : // then to the left
3338 0 : for ( size_t i = nPos; i > 0; --i )
3339 : {
3340 0 : DbGridColumn* pCurCol = m_aColumns[ i-1 ];
3341 0 : if (!pCurCol->IsHidden())
3342 : {
3343 0 : nNextNonHidden = i-1;
3344 0 : break;
3345 : }
3346 : }
3347 : }
3348 : sal_uInt16 nNewViewPos = (nNextNonHidden == BROWSER_INVALIDID)
3349 : ? 1 // there is no visible column -> insert behinde the handle col
3350 0 : : GetViewColumnPos( m_aColumns[ nNextNonHidden ]->GetId() ) + 1;
3351 : // the first non-handle col has "view pos" 0, but the pos arg for InsertDataColumn expects
3352 : // a position 1 for the first non-handle col -> +1
3353 : DBG_ASSERT(nNewViewPos != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
3354 : // we found a col marked as visible but got no view pos for it ...
3355 :
3356 0 : if ((nNextNonHidden<nPos) && (nNextNonHidden != BROWSER_INVALIDID))
3357 : // nNextNonHidden is a column to the left, so we want to insert the new col _right_ beside it's pos
3358 0 : ++nNewViewPos;
3359 :
3360 0 : DeactivateCell();
3361 :
3362 0 : OUString aName;
3363 0 : pColumn->getModel()->getPropertyValue(FM_PROP_LABEL) >>= aName;
3364 0 : InsertDataColumn(nId, aName, CalcZoom(pColumn->m_nLastVisibleWidth), HIB_CENTER | HIB_VCENTER | HIB_CLICKABLE, nNewViewPos);
3365 0 : pColumn->m_bHidden = false;
3366 :
3367 0 : ActivateCell();
3368 0 : Invalidate();
3369 : }
3370 :
3371 20 : sal_uInt16 DbGridControl::GetColumnIdFromModelPos( sal_uInt16 nPos ) const
3372 : {
3373 20 : if (nPos >= m_aColumns.size())
3374 : {
3375 : OSL_FAIL("DbGridControl::GetColumnIdFromModelPos : invalid argument !");
3376 0 : return GRID_COLUMN_NOT_FOUND;
3377 : }
3378 :
3379 20 : DbGridColumn* pCol = m_aColumns[ nPos ];
3380 : #if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
3381 : // in der Debug-Version rechnen wir die ModelPos in eine ViewPos um und vergleichen das mit dem Wert,
3382 : // den wir zurueckliefern werden (nId an der entsprechenden Col in m_aColumns)
3383 :
3384 : if (!pCol->IsHidden())
3385 : { // macht nur Sinn, wenn die Spalte sichtbar ist
3386 : sal_uInt16 nViewPos = nPos;
3387 : for ( size_t i = 0; i < m_aColumns.size() && i < nPos; ++i)
3388 : if ( m_aColumns[ i ]->IsHidden())
3389 : --nViewPos;
3390 :
3391 : DBG_ASSERT(pCol && GetColumnIdFromViewPos(nViewPos) == pCol->GetId(),
3392 : "DbGridControl::GetColumnIdFromModelPos : this isn't consistent .... did I misunderstand something ?");
3393 : }
3394 : #endif
3395 20 : return pCol->GetId();
3396 : }
3397 :
3398 1299 : sal_uInt16 DbGridControl::GetModelColumnPos( sal_uInt16 nId ) const
3399 : {
3400 11518 : for ( size_t i = 0; i < m_aColumns.size(); ++i )
3401 11353 : if ( m_aColumns[ i ]->GetId() == nId )
3402 1134 : return i;
3403 :
3404 165 : return GRID_COLUMN_NOT_FOUND;
3405 : }
3406 :
3407 0 : void DbGridControl::implAdjustInSolarThread(bool _bRows)
3408 : {
3409 : SAL_INFO("svx.fmcomp", "DbGridControl::implAdjustInSolarThread");
3410 0 : ::osl::MutexGuard aGuard(m_aAdjustSafety);
3411 0 : if (::osl::Thread::getCurrentIdentifier() != Application::GetMainThreadIdentifier())
3412 : {
3413 0 : m_nAsynAdjustEvent = PostUserEvent(LINK(this, DbGridControl, OnAsyncAdjust), reinterpret_cast< void* >( _bRows ));
3414 0 : m_bPendingAdjustRows = _bRows;
3415 0 : if (_bRows)
3416 : SAL_INFO("svx.fmcomp", "posting an AdjustRows");
3417 : else
3418 : SAL_INFO("svx.fmcomp", "posting an AdjustDataSource");
3419 : }
3420 : else
3421 : {
3422 0 : if (_bRows)
3423 : SAL_INFO("svx.fmcomp", "doing an AdjustRows");
3424 : else
3425 : SAL_INFO("svx.fmcomp", "doing an AdjustDataSource");
3426 : // always adjust the rows before adjusting the data source
3427 : // If this is not necessary (because the row count did not change), nothing is done
3428 : // The problem is that we can't rely on the order of which the calls come in: If the cursor was moved
3429 : // to a position behind row count know 'til now, the cursorMoved notification may come before the
3430 : // RowCountChanged notification
3431 : // 94093 - 02.11.2001 - frank.schoenheit@sun.com
3432 0 : AdjustRows();
3433 :
3434 0 : if ( !_bRows )
3435 0 : AdjustDataSource();
3436 0 : }
3437 0 : }
3438 :
3439 0 : IMPL_LINK(DbGridControl, OnAsyncAdjust, void*, pAdjustWhat)
3440 : {
3441 0 : m_nAsynAdjustEvent = 0;
3442 :
3443 0 : AdjustRows();
3444 : // see implAdjustInSolarThread for a comment why we do this every time
3445 :
3446 0 : if ( !pAdjustWhat )
3447 0 : AdjustDataSource();
3448 :
3449 0 : return 0L;
3450 : }
3451 :
3452 2 : void DbGridControl::BeginCursorAction()
3453 : {
3454 2 : if (m_pFieldListeners)
3455 : {
3456 2 : ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
3457 2 : ColumnFieldValueListeners::const_iterator aIter = pListeners->begin();
3458 66 : while (aIter != pListeners->end())
3459 : {
3460 62 : GridFieldValueListener* pCurrent = (*aIter).second;
3461 62 : if (pCurrent)
3462 62 : pCurrent->suspend();
3463 62 : ++aIter;
3464 : }
3465 : }
3466 :
3467 2 : if (m_pDataSourcePropListener)
3468 2 : m_pDataSourcePropListener->suspend();
3469 2 : }
3470 :
3471 2 : void DbGridControl::EndCursorAction()
3472 : {
3473 2 : if (m_pFieldListeners)
3474 : {
3475 2 : ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
3476 2 : ColumnFieldValueListeners::const_iterator aIter = pListeners->begin();
3477 66 : while (aIter != pListeners->end())
3478 : {
3479 62 : GridFieldValueListener* pCurrent = (*aIter).second;
3480 62 : if (pCurrent)
3481 62 : pCurrent->resume();
3482 62 : ++aIter;
3483 : }
3484 : }
3485 :
3486 2 : if (m_pDataSourcePropListener)
3487 2 : m_pDataSourcePropListener->resume();
3488 2 : }
3489 :
3490 2 : void DbGridControl::ConnectToFields()
3491 : {
3492 2 : ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
3493 : DBG_ASSERT(!pListeners || pListeners->empty(), "DbGridControl::ConnectToFields : please call DisconnectFromFields first !");
3494 :
3495 2 : if (!pListeners)
3496 : {
3497 2 : pListeners = new ColumnFieldValueListeners;
3498 2 : m_pFieldListeners = pListeners;
3499 : }
3500 :
3501 64 : for ( size_t i = 0; i < m_aColumns.size(); ++i )
3502 : {
3503 62 : DbGridColumn* pCurrent = m_aColumns[ i ];
3504 62 : sal_uInt16 nViewPos = pCurrent ? GetViewColumnPos(pCurrent->GetId()) : GRID_COLUMN_NOT_FOUND;
3505 62 : if (GRID_COLUMN_NOT_FOUND == nViewPos)
3506 0 : continue;
3507 :
3508 62 : Reference< XPropertySet > xField = pCurrent->GetField();
3509 62 : if (!xField.is())
3510 0 : continue;
3511 :
3512 : // column is visible and bound here
3513 62 : GridFieldValueListener*& rpListener = (*pListeners)[pCurrent->GetId()];
3514 : DBG_ASSERT(!rpListener, "DbGridControl::ConnectToFields : already a listener for this column ?!");
3515 62 : rpListener = new GridFieldValueListener(*this, xField, pCurrent->GetId());
3516 62 : }
3517 2 : }
3518 :
3519 4 : void DbGridControl::DisconnectFromFields()
3520 : {
3521 4 : if (!m_pFieldListeners)
3522 6 : return;
3523 :
3524 2 : ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
3525 66 : while (!pListeners->empty())
3526 : {
3527 : #ifdef DBG_UTIL
3528 : sal_Int32 nOldSize = pListeners->size();
3529 : #endif
3530 62 : pListeners->begin()->second->dispose();
3531 : DBG_ASSERT(nOldSize > (sal_Int32)pListeners->size(), "DbGridControl::DisconnectFromFields : dispose on a listener should result in a removal from my list !");
3532 : }
3533 :
3534 2 : delete pListeners;
3535 2 : m_pFieldListeners = NULL;
3536 : }
3537 :
3538 0 : void DbGridControl::FieldValueChanged(sal_uInt16 _nId, const PropertyChangeEvent& /*_evt*/)
3539 : {
3540 0 : osl::MutexGuard aPreventDestruction(m_aDestructionSafety);
3541 : // needed as this may run in a thread other than the main one
3542 0 : if (GetRowStatus(GetCurRow()) != DbGridControl_Base::MODIFIED)
3543 : // all other cases are handled elsewhere
3544 0 : return;
3545 :
3546 0 : size_t Location = GetModelColumnPos( _nId );
3547 0 : DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ] : NULL;
3548 0 : if (pColumn)
3549 : {
3550 0 : boost::scoped_ptr<vcl::SolarMutexTryAndBuyGuard> pGuard;
3551 0 : while (!m_bWantDestruction && (!pGuard || !pGuard->isAcquired()))
3552 0 : pGuard.reset(new vcl::SolarMutexTryAndBuyGuard);
3553 :
3554 0 : if (m_bWantDestruction)
3555 : { // at this moment, within another thread, our destructor tries to destroy the listener which called this method
3556 : // => don't do anything
3557 : // 73365 - 23.02.00 - FS
3558 0 : return;
3559 : }
3560 :
3561 : // and finally do the update ...
3562 0 : pColumn->UpdateFromField(m_xCurrentRow, m_xFormatter);
3563 0 : RowModified(GetCurRow(), _nId);
3564 0 : }
3565 : }
3566 :
3567 62 : void DbGridControl::FieldListenerDisposing(sal_uInt16 _nId)
3568 : {
3569 62 : ColumnFieldValueListeners* pListeners = (ColumnFieldValueListeners*)m_pFieldListeners;
3570 62 : if (!pListeners)
3571 : {
3572 : OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (have no listener array) !");
3573 0 : return;
3574 : }
3575 :
3576 62 : ColumnFieldValueListeners::iterator aPos = pListeners->find(_nId);
3577 62 : if (aPos == pListeners->end())
3578 : {
3579 : OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (did not find the listener) !");
3580 0 : return;
3581 : }
3582 :
3583 62 : delete aPos->second;
3584 :
3585 62 : pListeners->erase(aPos);
3586 : }
3587 :
3588 2 : void DbGridControl::disposing(sal_uInt16 _nId, const EventObject& /*_rEvt*/)
3589 : {
3590 2 : if (_nId == 0)
3591 : { // the seek cursor is being disposed
3592 2 : ::osl::MutexGuard aGuard(m_aAdjustSafety);
3593 2 : setDataSource(NULL,0); // our clone was disposed so we set our datasource to null to avoid later acces to it
3594 2 : if (m_nAsynAdjustEvent)
3595 : {
3596 0 : RemoveUserEvent(m_nAsynAdjustEvent);
3597 0 : m_nAsynAdjustEvent = 0;
3598 2 : }
3599 : }
3600 2 : }
3601 :
3602 0 : sal_Int32 DbGridControl::GetAccessibleControlCount() const
3603 : {
3604 0 : return DbGridControl_Base::GetAccessibleControlCount() + 1; // the navigation control
3605 : }
3606 :
3607 0 : Reference<XAccessible > DbGridControl::CreateAccessibleControl( sal_Int32 _nIndex )
3608 : {
3609 0 : Reference<XAccessible > xRet;
3610 0 : if ( _nIndex == DbGridControl_Base::GetAccessibleControlCount() )
3611 : {
3612 0 : xRet = m_aBar.GetAccessible();
3613 : }
3614 : else
3615 0 : xRet = DbGridControl_Base::CreateAccessibleControl( _nIndex );
3616 0 : return xRet;
3617 : }
3618 :
3619 0 : Reference< XAccessible > DbGridControl::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos )
3620 : {
3621 0 : sal_uInt16 nColumnId = GetColumnId( _nColumnPos );
3622 0 : size_t Location = GetModelColumnPos(nColumnId);
3623 0 : DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ] : NULL;
3624 0 : if ( pColumn )
3625 : {
3626 0 : Reference< ::com::sun::star::awt::XControl> xInt(pColumn->GetCell());
3627 0 : Reference< ::com::sun::star::awt::XCheckBox> xBox(xInt,UNO_QUERY);
3628 0 : if ( xBox.is() )
3629 : {
3630 0 : TriState eValue = TRISTATE_FALSE;
3631 0 : switch( xBox->getState() )
3632 : {
3633 : case 0:
3634 0 : eValue = TRISTATE_FALSE;
3635 0 : break;
3636 : case 1:
3637 0 : eValue = TRISTATE_TRUE;
3638 0 : break;
3639 : case 2:
3640 0 : eValue = TRISTATE_INDET;
3641 0 : break;
3642 : }
3643 0 : return DbGridControl_Base::CreateAccessibleCheckBoxCell( _nRow, _nColumnPos,eValue );
3644 0 : }
3645 : }
3646 0 : return DbGridControl_Base::CreateAccessibleCell( _nRow, _nColumnPos );
3647 651 : }
3648 :
3649 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|