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