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