Bump version to 5.0-14
[LibreOffice.git] / svtools / source / brwbox / editbrowsebox.cxx
blobd0c8d530e7c7dffc76a3037107cdc2c2d73f7db7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svtools/editbrowsebox.hxx>
22 #include "editbrowsebox.hrc"
24 #include <vcl/svapp.hxx>
25 #include <tools/debug.hxx>
26 #include <vcl/window.hxx>
28 #include <vcl/edit.hxx>
29 #include <tools/resid.hxx>
30 #include <vcl/spinfld.hxx>
31 #include <vcl/settings.hxx>
32 #include <svtools/svtresid.hxx>
34 #include <svtools/svtools.hrc>
36 #include <algorithm>
37 #include <tools/multisel.hxx>
38 #include "editbrowseboximpl.hxx"
39 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
40 #include <com/sun/star/accessibility/XAccessible.hpp>
41 #include <comphelper/types.hxx>
44 namespace svt
47 namespace
50 sal_uInt16 getRealGetFocusFlags( vcl::Window* _pWindow )
52 sal_uInt16 nFlags = 0;
53 while ( _pWindow && !nFlags )
55 nFlags = _pWindow->GetGetFocusFlags( );
56 _pWindow = _pWindow->GetParent();
58 return nFlags;
62 using namespace ::com::sun::star::uno;
63 using namespace com::sun::star::accessibility::AccessibleEventId;
64 using com::sun::star::accessibility::XAccessible;
67 IEditImplementation::~IEditImplementation()
72 //= EditBrowserHeader
75 void EditBrowserHeader::DoubleClick()
77 sal_uInt16 nColId = GetCurItemId();
78 if (nColId)
80 sal_uInt32 nAutoWidth = static_cast<EditBrowseBox*>(GetParent())->GetAutoColumnWidth(nColId);
81 if (nAutoWidth != static_cast<EditBrowseBox*>(GetParent())->GetColumnWidth(nColId))
83 static_cast<EditBrowseBox*>(GetParent())->SetColumnWidth(nColId, nAutoWidth);
84 static_cast<EditBrowseBox*>(GetParent())->ColumnResized(nColId);
91 //= EditBrowseBox
94 void EditBrowseBox::BrowserMouseEventPtr::Clear()
96 DELETEZ(pEvent);
100 void EditBrowseBox::BrowserMouseEventPtr::Set(const BrowserMouseEvent* pEvt, bool bIsDown)
102 if (pEvt == pEvent)
104 bDown = bIsDown;
105 return;
107 Clear();
108 if (pEvt)
110 pEvent = new BrowserMouseEvent(pEvt->GetWindow(),
111 *pEvt,
112 pEvt->GetRow(),
113 pEvt->GetColumn(),
114 pEvt->GetColumnId(),
115 pEvt->GetRect());
116 bDown = bIsDown;
121 void EditBrowseBox::impl_construct()
123 m_aImpl.reset(new EditBrowseBoxImpl());
125 SetCompoundControl(true);
126 SetGridLineColor( Color( COL_LIGHTGRAY ) );
128 ImplInitSettings(true, true, true);
130 pCheckBoxPaint = VclPtr<CheckBoxControl>::Create(&GetDataWindow());
131 pCheckBoxPaint->SetPaintTransparent( true );
132 pCheckBoxPaint->SetBackground();
136 EditBrowseBox::EditBrowseBox(vcl::Window* pParent, const ResId& rId, EditBrowseBoxFlags nBrowserFlags, BrowserMode _nMode )
137 :BrowseBox( pParent, rId, _nMode )
138 ,nStartEvent(0)
139 ,nEndEvent(0)
140 ,nCellModifiedEvent(0)
141 ,m_pFocusWhileRequest(0)
142 ,nPaintRow(-1)
143 ,nEditRow(-1)
144 ,nOldEditRow(-1)
145 ,nEditCol(0)
146 ,nOldEditCol(0)
147 ,bHasFocus(false)
148 ,bPaintStatus(true)
149 ,bActiveBeforeTracking( false )
150 ,m_nBrowserFlags(nBrowserFlags)
151 ,pHeader(NULL)
153 impl_construct();
157 EditBrowseBox::EditBrowseBox( vcl::Window* pParent, EditBrowseBoxFlags nBrowserFlags, WinBits nBits, BrowserMode _nMode )
158 :BrowseBox( pParent, nBits, _nMode )
159 ,nStartEvent(0)
160 ,nEndEvent(0)
161 ,nCellModifiedEvent(0)
162 ,m_pFocusWhileRequest(0)
163 ,nPaintRow(-1)
164 ,nEditRow(-1)
165 ,nOldEditRow(-1)
166 ,nEditCol(0)
167 ,nOldEditCol(0)
168 ,bHasFocus(false)
169 ,bPaintStatus(true)
170 ,bActiveBeforeTracking( false )
171 ,m_nBrowserFlags(nBrowserFlags)
172 ,pHeader(NULL)
174 impl_construct();
178 void EditBrowseBox::Init()
180 // late construction
184 EditBrowseBox::~EditBrowseBox()
186 disposeOnce();
189 void EditBrowseBox::dispose()
191 if (nStartEvent)
192 Application::RemoveUserEvent(nStartEvent);
193 if (nEndEvent)
194 Application::RemoveUserEvent(nEndEvent);
195 if (nCellModifiedEvent)
196 Application::RemoveUserEvent(nCellModifiedEvent);
198 pCheckBoxPaint.disposeAndClear();
199 m_pFocusWhileRequest.clear();
200 pHeader.clear();
201 BrowseBox::dispose();
205 void EditBrowseBox::RemoveRows()
207 BrowseBox::Clear();
208 nOldEditRow = nEditRow = nPaintRow = -1;
209 nEditCol = nOldEditCol = 0;
213 VclPtr<BrowserHeader> EditBrowseBox::CreateHeaderBar(BrowseBox* pParent)
215 pHeader = imp_CreateHeaderBar(pParent);
216 if (!IsUpdateMode())
217 pHeader->SetUpdateMode(false);
218 return pHeader;
222 VclPtr<BrowserHeader> EditBrowseBox::imp_CreateHeaderBar(BrowseBox* pParent)
224 return VclPtr<EditBrowserHeader>::Create(pParent);
228 void EditBrowseBox::LoseFocus()
230 BrowseBox::LoseFocus();
231 DetermineFocus( 0 );
235 void EditBrowseBox::GetFocus()
237 BrowseBox::GetFocus();
239 // This should handle the case that the BrowseBox (or one of its children)
240 // gets the focus from outside by pressing Tab
241 if (IsEditing() && Controller()->GetWindow().IsVisible())
242 Controller()->GetWindow().GrabFocus();
244 DetermineFocus( getRealGetFocusFlags( this ) );
248 bool EditBrowseBox::SeekRow(long nRow)
250 nPaintRow = nRow;
251 return true;
255 IMPL_LINK_NOARG(EditBrowseBox, StartEditHdl)
257 nStartEvent = 0;
258 if (IsEditing())
260 EnableAndShow();
261 if (!aController->GetWindow().HasFocus() && (m_pFocusWhileRequest.get() == Application::GetFocusWindow()))
262 aController->GetWindow().GrabFocus();
264 return 0;
268 void EditBrowseBox::PaintField( OutputDevice& rDev, const Rectangle& rRect,
269 sal_uInt16 nColumnId ) const
271 if (nColumnId == HandleColumnId)
273 if (bPaintStatus)
274 PaintStatusCell(rDev, rRect);
276 else
278 // don't paint the current cell
279 if (&rDev == &GetDataWindow())
280 // but only if we're painting onto our data win (which is the usual painting)
281 if (nPaintRow == nEditRow)
283 if (IsEditing() && nEditCol == nColumnId && aController->GetWindow().IsVisible())
284 return;
286 PaintCell(rDev, rRect, nColumnId);
291 Image EditBrowseBox::GetImage(RowStatus eStatus) const
293 if ( !m_aStatusImages.GetImageCount() )
295 const_cast<EditBrowseBox*>(this)->m_aStatusImages = ImageList( SvtResId( RID_SVTOOLS_IMAGELIST_EDITBROWSEBOX ) );
298 Image aImage;
299 bool bNeedMirror = IsRTLEnabled();
300 switch (eStatus)
302 case CURRENT:
303 aImage = m_aStatusImages.GetImage(IMG_EBB_CURRENT);
304 break;
305 case CURRENTNEW:
306 aImage = m_aStatusImages.GetImage(IMG_EBB_CURRENTNEW);
307 break;
308 case MODIFIED:
309 aImage = m_aStatusImages.GetImage(IMG_EBB_MODIFIED);
310 bNeedMirror = false; // the pen is not mirrored
311 break;
312 case NEW:
313 aImage = m_aStatusImages.GetImage(IMG_EBB_NEW);
314 break;
315 case DELETED:
316 aImage = m_aStatusImages.GetImage(IMG_EBB_DELETED);
317 break;
318 case PRIMARYKEY:
319 aImage = m_aStatusImages.GetImage(IMG_EBB_PRIMARYKEY);
320 break;
321 case CURRENT_PRIMARYKEY:
322 aImage = m_aStatusImages.GetImage(IMG_EBB_CURRENT_PRIMARYKEY);
323 break;
324 case FILTER:
325 aImage = m_aStatusImages.GetImage(IMG_EBB_FILTER);
326 break;
327 case HEADERFOOTER:
328 aImage = m_aStatusImages.GetImage(IMG_EBB_HEADERFOOTER);
329 break;
330 case CLEAN:
331 break;
333 if ( bNeedMirror )
335 BitmapEx aBitmap( aImage.GetBitmapEx() );
336 aBitmap.Mirror( BmpMirrorFlags::Horizontal );
337 aImage = Image( aBitmap );
339 return aImage;
343 void EditBrowseBox::PaintStatusCell(OutputDevice& rDev, const Rectangle& rRect) const
345 if (nPaintRow < 0)
346 return;
348 RowStatus eStatus = GetRowStatus( nPaintRow );
349 EditBrowseBoxFlags nBrowserFlags = GetBrowserFlags();
351 if (nBrowserFlags & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT)
352 return;
354 // draw the text of the header column
355 if (nBrowserFlags & EditBrowseBoxFlags::HANDLE_COLUMN_TEXT )
357 rDev.DrawText( rRect, GetCellText( nPaintRow, 0 ),
358 DrawTextFlags::Center | DrawTextFlags::VCenter | DrawTextFlags::Clip );
360 // draw an image
361 else if (eStatus != CLEAN && rDev.GetOutDevType() == OUTDEV_WINDOW)
363 Image aImage(GetImage(eStatus));
364 // calc the image position
365 Size aImageSize(aImage.GetSizePixel());
366 aImageSize.Width() = CalcZoom(aImageSize.Width());
367 aImageSize.Height() = CalcZoom(aImageSize.Height());
368 Point aPos( rRect.TopLeft() );
370 if ( ( aImageSize.Width() > rRect.GetWidth() ) || ( aImageSize.Height() > rRect.GetHeight() ) )
371 rDev.SetClipRegion(vcl::Region(rRect));
373 if ( aImageSize.Width() < rRect.GetWidth() )
374 aPos.X() += ( rRect.GetWidth() - aImageSize.Width() ) / 2;
376 if ( aImageSize.Height() < rRect.GetHeight() )
377 aPos.Y() += ( rRect.GetHeight() - aImageSize.Height() ) / 2;
379 if ( IsZoom() )
380 rDev.DrawImage( aPos, aImageSize, aImage );
381 else
382 rDev.DrawImage( aPos, aImage );
384 if (rDev.IsClipRegion())
385 rDev.SetClipRegion();
390 void EditBrowseBox::ImplStartTracking()
392 bActiveBeforeTracking = IsEditing();
393 if ( bActiveBeforeTracking )
395 DeactivateCell();
396 Update();
399 BrowseBox::ImplStartTracking();
403 void EditBrowseBox::ImplTracking()
405 BrowseBox::ImplTracking();
409 void EditBrowseBox::ImplEndTracking()
411 if ( bActiveBeforeTracking )
412 ActivateCell();
413 bActiveBeforeTracking = false;
415 BrowseBox::ImplEndTracking();
419 void EditBrowseBox::RowHeightChanged()
421 if ( IsEditing() )
423 Rectangle aRect( GetCellRect( nEditRow, nEditCol, false ) );
424 CellControllerRef aCellController( Controller() );
425 ResizeController( aCellController, aRect );
426 aCellController->GetWindow().GrabFocus();
429 BrowseBox::RowHeightChanged();
433 EditBrowseBox::RowStatus EditBrowseBox::GetRowStatus(long) const
435 return CLEAN;
439 void EditBrowseBox::KeyInput( const KeyEvent& rEvt )
441 sal_uInt16 nCode = rEvt.GetKeyCode().GetCode();
442 bool bShift = rEvt.GetKeyCode().IsShift();
443 bool bCtrl = rEvt.GetKeyCode().IsMod1();
445 switch (nCode)
447 case KEY_RETURN:
448 if (!bCtrl && !bShift && IsTabAllowed(true))
450 Dispatch(BROWSER_CURSORRIGHT);
452 else
453 BrowseBox::KeyInput(rEvt);
454 return;
455 case KEY_TAB:
456 if (!bCtrl && !bShift)
458 if (IsTabAllowed(true))
459 Dispatch(BROWSER_CURSORRIGHT);
460 else
461 // do NOT call BrowseBox::KeyInput : this would handle the tab, but we already now
462 // that tab isn't allowed here. So give the Control class a chance
463 Control::KeyInput(rEvt);
464 return;
466 else if (!bCtrl && bShift)
468 if (IsTabAllowed(false))
469 Dispatch(BROWSER_CURSORLEFT);
470 else
471 // do NOT call BrowseBox::KeyInput : this would handle the tab, but we already now
472 // that tab isn't allowed here. So give the Control class a chance
473 Control::KeyInput(rEvt);
474 return;
476 // fall-through
477 default:
478 BrowseBox::KeyInput(rEvt);
483 void EditBrowseBox::MouseButtonDown(const BrowserMouseEvent& rEvt)
485 // absorb double clicks
486 if (rEvt.GetClicks() > 1 && rEvt.GetRow() >= 0)
487 return;
489 // we are about to leave the current cell. If there is a "this cell has been modified" notification
490 // pending (asynchronously), this may be deadly -> do it synchronously
491 if ( nCellModifiedEvent )
493 Application::RemoveUserEvent( nCellModifiedEvent );
494 nCellModifiedEvent = 0;
495 LINK( this, EditBrowseBox, CellModifiedHdl ).Call( NULL );
498 if (rEvt.GetColumnId() == HandleColumnId)
499 { // it was the handle column. save the current cell content if necessary
500 // (clicking on the handle column results in selecting the current row)
501 if (IsEditing() && aController->IsModified())
502 SaveModified();
505 aMouseEvent.Set(&rEvt,true);
506 BrowseBox::MouseButtonDown(rEvt);
507 aMouseEvent.Clear();
509 if (m_nBrowserFlags & EditBrowseBoxFlags::ACTIVATE_ON_BUTTONDOWN)
511 // the base class does not travel upon MouseButtonDown, but implActivateCellOnMouseEvent assumes we traveled ...
512 GoToRowColumnId( rEvt.GetRow(), rEvt.GetColumnId() );
513 if (rEvt.GetRow() >= 0)
514 implActivateCellOnMouseEvent(rEvt, false);
519 void EditBrowseBox::MouseButtonUp( const BrowserMouseEvent& rEvt )
521 // absorb double clicks
522 if (rEvt.GetClicks() > 1 && rEvt.GetRow() >= 0)
523 return;
525 aMouseEvent.Set(&rEvt,false);
526 BrowseBox::MouseButtonUp(rEvt);
527 aMouseEvent.Clear();
529 if (!(m_nBrowserFlags & EditBrowseBoxFlags::ACTIVATE_ON_BUTTONDOWN))
530 if (rEvt.GetRow() >= 0)
531 implActivateCellOnMouseEvent(rEvt, true);
535 void EditBrowseBox::implActivateCellOnMouseEvent(const BrowserMouseEvent& _rEvt, bool _bUp)
537 if (!IsEditing())
538 ActivateCell();
539 else if (IsEditing() && !aController->GetWindow().IsEnabled())
540 DeactivateCell();
541 else if (IsEditing() && !aController->GetWindow().HasChildPathFocus())
542 AsynchGetFocus();
544 if (IsEditing() && aController->GetWindow().IsEnabled() && aController->WantMouseEvent())
545 { // forwards the event to the control
547 // If the field has been moved previously, we have to adjust the position
549 aController->GetWindow().GrabFocus();
551 // the position of the event relative to the controller's window
552 Point aPos = _rEvt.GetPosPixel() - _rEvt.GetRect().TopLeft();
553 // the (child) window which should really get the event
554 vcl::Window* pRealHandler = aController->GetWindow().FindWindow(aPos);
555 if (pRealHandler)
556 // the coords relative to this real handler
557 aPos -= pRealHandler->GetPosPixel();
558 else
559 pRealHandler = &aController->GetWindow();
561 // the faked event
562 MouseEvent aEvent(aPos, _rEvt.GetClicks(), _rEvt.GetMode(),
563 _rEvt.GetButtons(),
564 _rEvt.GetModifier());
566 pRealHandler->MouseButtonDown(aEvent);
567 if (_bUp)
568 pRealHandler->MouseButtonUp(aEvent);
570 vcl::Window *pWin = &aController->GetWindow();
571 if (!pWin->IsTracking())
573 for (pWin = pWin->GetWindow(GetWindowType::FirstChild);
574 pWin && !pWin->IsTracking();
575 pWin = pWin->GetWindow(GetWindowType::Next))
579 if (pWin && pWin->IsTracking())
580 pWin->EndTracking();
585 void EditBrowseBox::Dispatch( sal_uInt16 _nId )
587 if ( _nId == BROWSER_ENHANCESELECTION )
588 { // this is a workaround for the bug in the base class:
589 // if the row selection is to be extended (which is what BROWSER_ENHANCESELECTION tells us)
590 // then the base class does not revert any column selections, while, for doing a "simple"
591 // selection (BROWSER_SELECT), it does. In fact, it does not only revert the col selection then,
592 // but also any current row selections.
593 // This clearly tells me that the both ids are for row selection only - there this behaviour does
594 // make sense.
595 // But here, where we have column selection, too, we take care of this ourself.
596 if ( GetSelectColumnCount( ) )
598 while ( GetSelectColumnCount( ) )
599 SelectColumnPos(
600 sal::static_int_cast< sal_uInt16 >(FirstSelectedColumn()),
601 false );
602 Select();
605 BrowseBox::Dispatch( _nId );
608 bool EditBrowseBox::PreNotify(NotifyEvent& rEvt)
610 if (rEvt.GetType() == MouseNotifyEvent::KEYINPUT)
612 if ( (IsEditing() && Controller()->GetWindow().HasChildPathFocus())
613 || rEvt.GetWindow() == &GetDataWindow()
614 || (!IsEditing() && HasChildPathFocus())
617 const KeyEvent* pKeyEvent = rEvt.GetKeyEvent();
618 sal_uInt16 nCode = pKeyEvent->GetKeyCode().GetCode();
619 bool bShift = pKeyEvent->GetKeyCode().IsShift();
620 bool bCtrl = pKeyEvent->GetKeyCode().IsMod1();
621 bool bAlt = pKeyEvent->GetKeyCode().IsMod2();
622 bool bLocalSelect = false;
623 bool bNonEditOnly = false;
624 sal_uInt16 nId = BROWSER_NONE;
626 if (!bAlt && !bCtrl && !bShift )
627 switch ( nCode )
629 case KEY_DOWN: nId = BROWSER_CURSORDOWN; break;
630 case KEY_UP: nId = BROWSER_CURSORUP; break;
631 case KEY_PAGEDOWN: nId = BROWSER_CURSORPAGEDOWN; break;
632 case KEY_PAGEUP: nId = BROWSER_CURSORPAGEUP; break;
633 case KEY_HOME: nId = BROWSER_CURSORHOME; break;
634 case KEY_END: nId = BROWSER_CURSOREND; break;
636 case KEY_TAB:
637 // ask if traveling to the next cell is allowed
638 if (IsTabAllowed(true))
639 nId = BROWSER_CURSORRIGHT;
640 break;
642 case KEY_RETURN:
643 // save the cell content (if necessary)
644 if (IsEditing() && aController->IsModified() && !SaveModified())
646 // maybe we're not visible ...
647 EnableAndShow();
648 aController->GetWindow().GrabFocus();
649 return true;
651 // ask if traveling to the next cell is allowed
652 if (IsTabAllowed(true))
653 nId = BROWSER_CURSORRIGHT;
655 break;
656 case KEY_RIGHT: nId = BROWSER_CURSORRIGHT; break;
657 case KEY_LEFT: nId = BROWSER_CURSORLEFT; break;
658 case KEY_SPACE: nId = BROWSER_SELECT; bNonEditOnly = bLocalSelect = true; break;
661 if ( !bAlt && !bCtrl && bShift )
662 switch ( nCode )
664 case KEY_DOWN: nId = BROWSER_SELECTDOWN; bLocalSelect = true; break;
665 case KEY_UP: nId = BROWSER_SELECTUP; bLocalSelect = true; break;
666 case KEY_HOME: nId = BROWSER_SELECTHOME; bLocalSelect = true; break;
667 case KEY_END: nId = BROWSER_SELECTEND; bLocalSelect = true; break;
668 case KEY_TAB:
669 if (IsTabAllowed(false))
670 nId = BROWSER_CURSORLEFT;
671 break;
674 if ( !bAlt && bCtrl && bShift )
675 switch ( nCode )
677 case KEY_SPACE: nId = BROWSER_SELECTCOLUMN; bLocalSelect = true; break;
681 if ( !bAlt && bCtrl && !bShift )
682 switch ( nCode )
684 case KEY_DOWN: nId = BROWSER_SCROLLUP; break;
685 case KEY_UP: nId = BROWSER_SCROLLDOWN; break;
686 case KEY_PAGEDOWN: nId = BROWSER_CURSORENDOFFILE; break;
687 case KEY_PAGEUP: nId = BROWSER_CURSORTOPOFFILE; break;
688 case KEY_HOME: nId = BROWSER_CURSORTOPOFSCREEN; break;
689 case KEY_END: nId = BROWSER_CURSORENDOFSCREEN; break;
690 case KEY_SPACE: nId = BROWSER_ENHANCESELECTION; bLocalSelect = true; break;
694 if ( ( nId != BROWSER_NONE )
695 && ( !IsEditing()
696 || ( !bNonEditOnly
697 && aController->MoveAllowed( *pKeyEvent )
702 if (nId == BROWSER_SELECT || BROWSER_SELECTCOLUMN == nId )
704 // save the cell content (if necessary)
705 if (IsEditing() && aController->IsModified() && !SaveModified())
707 // maybe we're not visible ...
708 EnableAndShow();
709 aController->GetWindow().GrabFocus();
710 return true;
714 Dispatch(nId);
716 if (bLocalSelect && (GetSelectRowCount() || GetSelection() != NULL))
717 DeactivateCell();
718 return true;
722 return BrowseBox::PreNotify(rEvt);
725 bool EditBrowseBox::IsTabAllowed(bool) const
727 return true;
731 bool EditBrowseBox::Notify(NotifyEvent& rEvt)
733 switch (rEvt.GetType())
735 case MouseNotifyEvent::GETFOCUS:
736 DetermineFocus( getRealGetFocusFlags( this ) );
737 break;
739 case MouseNotifyEvent::LOSEFOCUS:
740 DetermineFocus( 0 );
741 break;
743 default:
744 break;
746 return BrowseBox::Notify(rEvt);
750 void EditBrowseBox::StateChanged( StateChangedType nType )
752 BrowseBox::StateChanged( nType );
754 bool bNeedCellReActivation = false;
755 if ( nType == StateChangedType::Mirroring )
757 bNeedCellReActivation = true;
759 else if ( nType == StateChangedType::Zoom )
761 ImplInitSettings( true, false, false );
762 bNeedCellReActivation = true;
764 else if ( nType == StateChangedType::ControlFont )
766 ImplInitSettings( true, false, false );
767 Invalidate();
769 else if ( nType == StateChangedType::ControlForeground )
771 ImplInitSettings( false, true, false );
772 Invalidate();
774 else if ( nType == StateChangedType::ControlBackground )
776 ImplInitSettings( false, false, true );
777 Invalidate();
779 else if (nType == StateChangedType::Style)
781 WinBits nStyle = GetStyle();
782 if (!(nStyle & WB_NOTABSTOP) )
783 nStyle |= WB_TABSTOP;
785 SetStyle(nStyle);
787 if ( bNeedCellReActivation )
789 if ( IsEditing() )
791 DeactivateCell();
792 ActivateCell();
798 void EditBrowseBox::DataChanged( const DataChangedEvent& rDCEvt )
800 BrowseBox::DataChanged( rDCEvt );
802 if ((( rDCEvt.GetType() == DataChangedEventType::SETTINGS ) ||
803 ( rDCEvt.GetType() == DataChangedEventType::DISPLAY )) &&
804 ( rDCEvt.GetFlags() & AllSettingsFlags::STYLE ))
806 ImplInitSettings( true, true, true );
807 Invalidate();
811 void EditBrowseBox::ImplInitSettings( bool bFont, bool bForeground, bool bBackground )
813 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
815 if (bFont)
817 GetDataWindow().ApplyControlFont(GetDataWindow(), rStyleSettings.GetFieldFont());
820 if (bFont || bForeground)
822 GetDataWindow().ApplyControlForeground(GetDataWindow(), rStyleSettings.GetFieldTextColor());
825 if (bBackground) // FIXME: Outside of Paint Hierarchy
827 if (GetDataWindow().IsControlBackground())
829 GetDataWindow().SetControlBackground(GetControlBackground());
830 GetDataWindow().SetBackground(GetDataWindow().GetControlBackground());
831 GetDataWindow().SetFillColor(GetDataWindow().GetControlBackground());
833 else
835 GetDataWindow().SetControlBackground();
836 GetDataWindow().SetBackground(rStyleSettings.GetFieldColor());
837 GetDataWindow().SetFillColor(rStyleSettings.GetFieldColor());
843 bool EditBrowseBox::IsCursorMoveAllowed(long nNewRow, sal_uInt16 nNewColId) const
845 sal_uInt16 nInfo = 0;
847 if (GetSelectColumnCount() || (aMouseEvent.Is() && aMouseEvent->GetRow() < 0))
848 nInfo |= COLSELECT;
849 if ((GetSelection() != NULL && GetSelectRowCount()) ||
850 (aMouseEvent.Is() && aMouseEvent->GetColumnId() == HandleColumnId))
851 nInfo |= ROWSELECT;
852 if (!nInfo && nNewRow != nEditRow)
853 nInfo |= ROWCHANGE;
854 if (!nInfo && nNewColId != nEditCol)
855 nInfo |= COLCHANGE;
857 if (nInfo == 0) // nothing happened
858 return true;
860 // save the cell content
861 if (IsEditing() && aController->IsModified() && !const_cast<EditBrowseBox *>(this)->SaveModified())
863 // maybe we're not visible ...
864 EnableAndShow();
865 aController->GetWindow().GrabFocus();
866 return false;
869 EditBrowseBox * pTHIS = const_cast<EditBrowseBox *> (this);
871 // save the cell content if
872 // a) a selection is being made
873 // b) the row is changing
874 if (IsModified() && (nInfo & (ROWCHANGE | COLSELECT | ROWSELECT)) &&
875 !pTHIS->SaveRow())
877 if (nInfo & COLSELECT ||
878 nInfo & ROWSELECT)
880 // cancel selected
881 pTHIS->SetNoSelection();
884 if (IsEditing())
886 if (!Controller()->GetWindow().IsVisible())
888 EnableAndShow();
890 aController->GetWindow().GrabFocus();
892 return false;
895 if (nNewRow != nEditRow)
897 vcl::Window& rWindow = GetDataWindow();
898 if ((nEditRow >= 0) && !(GetBrowserFlags() & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT))
900 Rectangle aRect = GetFieldRectPixel(nEditRow, 0, false );
901 // status cell should be painted if and only if text is displayed
902 // note: bPaintStatus is mutable, but Solaris has problems with assigning
903 // probably because it is part of a bitfield
904 pTHIS->bPaintStatus = ( GetBrowserFlags() & EditBrowseBoxFlags::HANDLE_COLUMN_TEXT ) == EditBrowseBoxFlags::HANDLE_COLUMN_TEXT;
905 rWindow.Invalidate(aRect);
906 pTHIS->bPaintStatus = true;
909 // don't paint during row change
910 rWindow.EnablePaint(false);
912 // the last veto chance for derived classes
913 if (!pTHIS->CursorMoving(nNewRow, nNewColId))
915 pTHIS->InvalidateStatusCell(nEditRow);
916 rWindow.EnablePaint(true);
917 return false;
919 else
921 rWindow.EnablePaint(true);
922 return true;
925 else
926 return pTHIS->CursorMoving(nNewRow, nNewColId);
930 void EditBrowseBox::ColumnMoved(sal_uInt16 nId)
932 BrowseBox::ColumnMoved(nId);
933 if (IsEditing())
935 Rectangle aRect( GetCellRect(nEditRow, nEditCol, false));
936 CellControllerRef aControllerRef = Controller();
937 ResizeController(aControllerRef, aRect);
938 Controller()->GetWindow().GrabFocus();
943 bool EditBrowseBox::SaveRow()
945 return true;
949 bool EditBrowseBox::CursorMoving(long, sal_uInt16)
951 DeactivateCell(false);
952 return true;
956 void EditBrowseBox::CursorMoved()
958 long nNewRow = GetCurRow();
959 if (nEditRow != nNewRow)
961 if (!(GetBrowserFlags() & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT))
962 InvalidateStatusCell(nNewRow);
963 nEditRow = nNewRow;
965 ActivateCell();
966 GetDataWindow().EnablePaint(true);
967 // should not be called here because the descant event is not needed here
968 //BrowseBox::CursorMoved();
972 void EditBrowseBox::EndScroll()
974 if (IsEditing())
976 Rectangle aRect = GetCellRect(nEditRow, nEditCol, false);
977 ResizeController(aController,aRect);
978 AsynchGetFocus();
980 BrowseBox::EndScroll();
984 void EditBrowseBox::ActivateCell(long nRow, sal_uInt16 nCol, bool bCellFocus)
986 if (IsEditing())
987 return;
989 nEditCol = nCol;
991 if ((GetSelectRowCount() && GetSelection() != NULL) || GetSelectColumnCount() ||
992 (aMouseEvent.Is() && (aMouseEvent.IsDown() || aMouseEvent->GetClicks() > 1))) // nothing happens on MouseDown
994 return;
997 if (nEditRow >= 0 && nEditCol > HandleColumnId)
999 aController = GetController(nRow, nCol);
1000 if (aController.Is())
1002 Rectangle aRect( GetCellRect(nEditRow, nEditCol, false));
1003 ResizeController(aController, aRect);
1005 InitController(aController, nEditRow, nEditCol);
1007 aController->ClearModified();
1008 aController->SetModifyHdl(LINK(this,EditBrowseBox,ModifyHdl));
1009 EnableAndShow();
1011 if ( isAccessibleAlive() )
1012 implCreateActiveAccessible();
1014 // activate the cell only of the browser has the focus
1015 if ( bHasFocus && bCellFocus )
1016 AsynchGetFocus();
1018 else
1020 // no controller -> we have a new "active descendant"
1021 if ( isAccessibleAlive() && HasFocus() )
1023 commitTableEvent(
1024 ACTIVE_DESCENDANT_CHANGED,
1025 makeAny( CreateAccessibleCell( nRow, GetColumnPos( nCol -1) ) ),
1026 Any()
1034 void EditBrowseBox::DeactivateCell(bool bUpdate)
1036 if (IsEditing())
1038 if ( isAccessibleAlive() )
1040 commitBrowseBoxEvent( CHILD, Any(), makeAny( m_aImpl->m_xActiveCell ) );
1041 m_aImpl->clearActiveCell();
1044 aOldController = aController;
1045 aController.Clear();
1047 // reset the modify handler
1048 aOldController->SetModifyHdl(Link<>());
1050 if (bHasFocus)
1051 GrabFocus(); // ensure that we have (and keep) the focus
1053 HideAndDisable(aOldController);
1055 // update if requested
1056 if (bUpdate)
1057 Update();
1059 nOldEditCol = nEditCol;
1060 nOldEditRow = nEditRow;
1062 // release the controller (asynchronously)
1063 if (nEndEvent)
1064 Application::RemoveUserEvent(nEndEvent);
1065 nEndEvent = Application::PostUserEvent(LINK(this,EditBrowseBox,EndEditHdl), NULL, true);
1070 Rectangle EditBrowseBox::GetCellRect(long nRow, sal_uInt16 nColId, bool bRel) const
1072 Rectangle aRect( GetFieldRectPixel(nRow, nColId, bRel));
1073 if ((GetMode() & BrowserMode::CURSOR_WO_FOCUS) == BrowserMode::CURSOR_WO_FOCUS)
1075 aRect.Top() += 1;
1076 aRect.Bottom() -= 1;
1078 return aRect;
1082 IMPL_LINK_NOARG(EditBrowseBox, EndEditHdl)
1084 nEndEvent = 0;
1085 ReleaseController(aOldController, nOldEditRow, nOldEditCol);
1087 aOldController = CellControllerRef();
1088 nOldEditRow = -1;
1089 nOldEditCol = 0;
1091 return 0;
1095 IMPL_LINK_NOARG(EditBrowseBox, ModifyHdl)
1097 if (nCellModifiedEvent)
1098 Application::RemoveUserEvent(nCellModifiedEvent);
1099 nCellModifiedEvent = Application::PostUserEvent(LINK(this,EditBrowseBox,CellModifiedHdl), NULL, true);
1100 return 0;
1104 IMPL_LINK_NOARG(EditBrowseBox, CellModifiedHdl)
1106 nCellModifiedEvent = 0;
1107 CellModified();
1108 return 0;
1112 void EditBrowseBox::ColumnResized( sal_uInt16 )
1114 if (IsEditing())
1116 Rectangle aRect( GetCellRect(nEditRow, nEditCol, false));
1117 CellControllerRef aControllerRef = Controller();
1118 ResizeController(aControllerRef, aRect);
1119 Controller()->GetWindow().GrabFocus();
1124 sal_uInt16 EditBrowseBox::AppendColumn(const OUString& rName, sal_uInt16 nWidth, sal_uInt16 nPos, sal_uInt16 nId)
1126 if (nId == BROWSER_INVALIDID)
1128 // look for the next free id
1129 for (nId = ColCount(); nId > 0 && GetColumnPos(nId) != BROWSER_INVALIDID; nId--)
1132 if (!nId)
1134 // if there is no handle column
1135 // increment the id
1136 if ( ColCount() == 0 || GetColumnId(0) != HandleColumnId )
1137 nId = ColCount() + 1;
1141 DBG_ASSERT(nId, "EditBrowseBox::AppendColumn: invalid id!");
1143 long w = nWidth;
1144 if (!w)
1145 w = GetDefaultColumnWidth(rName);
1147 InsertDataColumn(nId, rName, w, (HeaderBarItemBits::CENTER | HeaderBarItemBits::VCENTER | HeaderBarItemBits::CLICKABLE), nPos);
1148 return nId;
1152 void EditBrowseBox::Resize()
1154 BrowseBox::Resize();
1156 // if the window is smaller than "title line height" + "control area",
1157 // do nothing
1158 if (GetOutputSizePixel().Height() <
1159 (GetControlArea().GetHeight() + GetDataWindow().GetPosPixel().Y()))
1160 return;
1162 // the size of the control area
1163 Point aPoint(GetControlArea().TopLeft());
1164 sal_uInt16 nX = (sal_uInt16)aPoint.X();
1166 ArrangeControls(nX, (sal_uInt16)aPoint.Y());
1168 if (!nX)
1169 nX = USHRT_MAX;
1170 ReserveControlArea((sal_uInt16)nX);
1174 void EditBrowseBox::ArrangeControls(sal_uInt16&, sal_uInt16)
1179 CellController* EditBrowseBox::GetController(long, sal_uInt16)
1181 return NULL;
1185 void EditBrowseBox::ResizeController(CellControllerRef& rController, const Rectangle& rRect)
1187 rController->GetWindow().SetPosSizePixel(rRect.TopLeft(), rRect.GetSize());
1191 void EditBrowseBox::InitController(CellControllerRef&, long, sal_uInt16)
1196 void EditBrowseBox::ReleaseController(CellControllerRef&, long, sal_uInt16)
1201 void EditBrowseBox::CellModified()
1207 bool EditBrowseBox::SaveModified()
1209 return true;
1213 void EditBrowseBox::DoubleClick(const BrowserMouseEvent& rEvt)
1215 // when double clicking on the column, the optimum size will be calculated
1216 sal_uInt16 nColId = rEvt.GetColumnId();
1217 if (nColId != HandleColumnId)
1218 SetColumnWidth(nColId, GetAutoColumnWidth(nColId));
1222 sal_uInt32 EditBrowseBox::GetAutoColumnWidth(sal_uInt16 nColId)
1224 sal_uInt32 nCurColWidth = GetColumnWidth(nColId);
1225 sal_uInt32 nMinColWidth = CalcZoom(20); // minimum
1226 sal_uInt32 nNewColWidth = nMinColWidth;
1227 long nMaxRows = std::min(long(GetVisibleRows()), GetRowCount());
1228 long nLastVisRow = GetTopRow() + nMaxRows - 1;
1230 if (GetTopRow() <= nLastVisRow) // calc the column with using the cell contents
1232 for (long i = GetTopRow(); i <= nLastVisRow; ++i)
1233 nNewColWidth = std::max(nNewColWidth,GetTotalCellWidth(i,nColId) + 12);
1235 if (nNewColWidth == nCurColWidth) // size has not changed
1236 nNewColWidth = GetDefaultColumnWidth(GetColumnTitle(nColId));
1238 else
1239 nNewColWidth = GetDefaultColumnWidth(GetColumnTitle(nColId));
1240 return nNewColWidth;
1244 sal_uInt32 EditBrowseBox::GetTotalCellWidth(long, sal_uInt16)
1246 return 0;
1250 void EditBrowseBox::InvalidateHandleColumn()
1252 Rectangle aHdlFieldRect( GetFieldRectPixel( 0, 0 ));
1253 Rectangle aInvalidRect( Point(0,0), GetOutputSizePixel() );
1254 aInvalidRect.Right() = aHdlFieldRect.Right();
1255 Invalidate( aInvalidRect );
1259 void EditBrowseBox::PaintTristate(OutputDevice&, const Rectangle& rRect, const TriState& eState, bool _bEnabled) const
1261 pCheckBoxPaint->GetBox().SetState(eState);
1262 pCheckBoxPaint->SetPosSizePixel(rRect.TopLeft(), rRect.GetSize());
1264 // First update the parent, preventing that while painting this window
1265 // an update for the parent is done (because it's in the queue already)
1266 // which may lead to hiding this window immediately
1267 // #95598# comment out OJ
1268 /* if (pCheckBoxPaint->GetParent())
1269 pCheckBoxPaint->GetParent()->Update();
1271 pCheckBoxPaint->GetBox().Enable(_bEnabled);
1272 pCheckBoxPaint->Show();
1273 pCheckBoxPaint->SetParentUpdateMode( false );
1274 pCheckBoxPaint->Update();
1275 pCheckBoxPaint->Hide();
1276 pCheckBoxPaint->SetParentUpdateMode( true );
1280 void EditBrowseBox::AsynchGetFocus()
1282 if (nStartEvent)
1283 Application::RemoveUserEvent(nStartEvent);
1285 m_pFocusWhileRequest = Application::GetFocusWindow();
1286 nStartEvent = Application::PostUserEvent(LINK(this,EditBrowseBox,StartEditHdl), NULL, true);
1290 void EditBrowseBox::SetBrowserFlags(EditBrowseBoxFlags nFlags)
1292 if (m_nBrowserFlags == nFlags)
1293 return;
1295 bool RowPicturesChanges = ((m_nBrowserFlags & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT) !=
1296 (nFlags & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT));
1297 m_nBrowserFlags = nFlags;
1299 if (RowPicturesChanges)
1300 InvalidateStatusCell(GetCurRow());
1303 inline void EditBrowseBox::HideAndDisable(CellControllerRef& rController)
1305 rController->suspend();
1308 inline void EditBrowseBox::EnableAndShow() const
1310 Controller()->resume();
1315 CellController::CellController(Control* pW)
1316 :pWindow( pW )
1317 ,bSuspended( true )
1320 DBG_ASSERT(pWindow, "CellController::CellController: missing the window!");
1321 DBG_ASSERT(!pWindow->IsVisible(), "CellController::CellController: window should not be visible!");
1325 CellController::~CellController()
1331 void CellController::suspend( )
1333 DBG_ASSERT( bSuspended == !GetWindow().IsVisible(), "CellController::suspend: inconsistence!" );
1334 if ( !isSuspended( ) )
1336 CommitModifications();
1337 GetWindow().Hide( );
1338 GetWindow().Disable( );
1339 bSuspended = true;
1344 void CellController::resume( )
1346 DBG_ASSERT( bSuspended == !GetWindow().IsVisible(), "CellController::resume: inconsistence!" );
1347 if ( isSuspended( ) )
1349 GetWindow().Enable( );
1350 GetWindow().Show( );
1351 bSuspended = false;
1356 void CellController::CommitModifications()
1358 // nothing to do in this base class
1362 bool CellController::WantMouseEvent() const
1364 return false;
1368 void CellController::SetModified()
1373 bool CellController::MoveAllowed(const KeyEvent&) const
1375 return true;
1378 } // namespace svt
1381 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */