merge the formfield patch from ooo-build
[ooovba.git] / svtools / source / brwbox / editbrowsebox.cxx
blobc721931a79fb4ef968b83f215155b932d8621aa2
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: editbrowsebox.cxx,v $
10 * $Revision: 1.33 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svtools.hxx"
33 #include <svtools/editbrowsebox.hxx>
35 #ifndef _SVTOOLS_EDITBROWSEBOX_HRC_
36 #include "editbrowsebox.hrc"
37 #endif
39 #ifndef _APP_HXX //autogen
40 #include <vcl/svapp.hxx>
41 #endif
42 #include <tools/debug.hxx>
43 #include <vcl/window.hxx>
45 #ifndef _EDIT_HXX //autogen
46 #include <vcl/edit.hxx>
47 #endif
48 #include <tools/resid.hxx>
49 #include <vcl/spinfld.hxx>
50 #include <svtools/svtdata.hxx>
52 #ifndef _SVTOOLS_HRC
53 #include <svtools/svtools.hrc>
54 #endif
56 #include <algorithm>
57 #include <tools/multisel.hxx>
58 #include "editbrowseboximpl.hxx"
59 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
60 #include <com/sun/star/accessibility/XAccessible.hpp>
61 #include <comphelper/types.hxx>
63 // .......................................................................
64 namespace svt
66 // .......................................................................
67 namespace
69 //..............................................................
70 sal_Bool isHiContrast(Window* _pWindow)
72 OSL_ENSURE(_pWindow,"Window must be not null!");
73 Window* pIter = _pWindow;
74 // while( pIter && pIter->GetBackground().GetColor().GetColor() == COL_TRANSPARENT )
75 while( pIter )
77 const Color& aColor = pIter->GetBackground().GetColor();
78 if ( aColor.GetColor() == COL_TRANSPARENT )
79 pIter = pIter->GetParent();
80 else
81 break;
83 return pIter && pIter->GetBackground().GetColor().IsDark();
86 //..............................................................
87 sal_uInt16 getRealGetFocusFlags( Window* _pWindow )
89 sal_uInt16 nFlags = 0;
90 while ( _pWindow && !nFlags )
92 nFlags = _pWindow->GetGetFocusFlags( );
93 _pWindow = _pWindow->GetParent();
95 return nFlags;
99 using namespace ::com::sun::star::uno;
100 using namespace com::sun::star::accessibility::AccessibleEventId;
101 using com::sun::star::accessibility::XAccessible;
102 //==================================================================
104 #define HANDLE_ID 0
106 //==================================================================
107 //= EditBrowserHeader
108 //==================================================================
109 //------------------------------------------------------------------------------
110 void EditBrowserHeader::DoubleClick()
112 sal_uInt16 nColId = GetCurItemId();
113 if (nColId)
115 sal_uInt32 nAutoWidth = ((EditBrowseBox*)GetParent())->GetAutoColumnWidth(nColId);
116 if (nAutoWidth != ((EditBrowseBox*)GetParent())->GetColumnWidth(nColId))
118 ((EditBrowseBox*)GetParent())->SetColumnWidth(nColId, nAutoWidth);
119 ((EditBrowseBox*)GetParent())->ColumnResized(nColId);
125 //==================================================================
126 //= EditBrowseBox
127 //==================================================================
128 //------------------------------------------------------------------------------
129 void EditBrowseBox::BrowserMouseEventPtr::Clear()
131 DELETEZ(pEvent);
134 //------------------------------------------------------------------------------
135 void EditBrowseBox::BrowserMouseEventPtr::Set(const BrowserMouseEvent* pEvt, sal_Bool bIsDown)
137 if (pEvt == pEvent)
139 bDown = bIsDown;
140 return;
142 Clear();
143 if (pEvt)
145 pEvent = new BrowserMouseEvent(pEvt->GetWindow(),
146 *pEvt,
147 pEvt->GetRow(),
148 pEvt->GetColumn(),
149 pEvt->GetColumnId(),
150 pEvt->GetRect());
151 bDown = bIsDown;
155 //------------------------------------------------------------------------------
156 DBG_NAME(EditBrowseBox);
157 void EditBrowseBox::impl_construct()
159 m_aImpl = ::std::auto_ptr<EditBrowseBoxImpl>(new EditBrowseBoxImpl());
160 m_aImpl->m_bHiContrast = isHiContrast(&GetDataWindow());
162 SetCompoundControl(sal_True);
163 SetGridLineColor( Color( COL_LIGHTGRAY ) );
165 ImplInitSettings(sal_True, sal_True, sal_True);
167 pCheckBoxPaint = new CheckBoxControl(&GetDataWindow());
168 pCheckBoxPaint->SetPaintTransparent( sal_True );
169 pCheckBoxPaint->SetBackground();
172 //------------------------------------------------------------------------------
173 EditBrowseBox::EditBrowseBox(Window* pParent, const ResId& rId, sal_Int32 nBrowserFlags, BrowserMode _nMode )
174 :BrowseBox( pParent, rId, _nMode )
175 ,nStartEvent(0)
176 ,nEndEvent(0)
177 ,nCellModifiedEvent(0)
178 ,nPaintRow(-1)
179 ,nEditRow(-1)
180 ,nOldEditRow(-1)
181 ,nEditCol(0)
182 ,nOldEditCol(0)
183 ,bHasFocus(sal_False)
184 ,bPaintStatus(sal_True)
185 ,bActiveBeforeTracking( sal_False )
186 ,m_nBrowserFlags(nBrowserFlags)
188 DBG_CTOR(EditBrowseBox,NULL);
190 impl_construct();
193 //==================================================================
194 EditBrowseBox::EditBrowseBox( Window* pParent, sal_Int32 nBrowserFlags, WinBits nBits, BrowserMode _nMode )
195 :BrowseBox( pParent, nBits, _nMode )
196 ,nStartEvent(0)
197 ,nEndEvent(0)
198 ,nCellModifiedEvent(0)
199 ,nPaintRow(-1)
200 ,nEditRow(-1)
201 ,nOldEditRow(-1)
202 ,nEditCol(0)
203 ,nOldEditCol(0)
204 ,bHasFocus(sal_False)
205 ,bPaintStatus(sal_True)
206 ,bActiveBeforeTracking( sal_False )
207 ,m_nBrowserFlags(nBrowserFlags)
208 ,pHeader(NULL)
210 DBG_CTOR(EditBrowseBox,NULL);
212 impl_construct();
215 //------------------------------------------------------------------------------
216 void EditBrowseBox::Init()
218 // spaetes Construieren,
221 //------------------------------------------------------------------------------
222 EditBrowseBox::~EditBrowseBox()
224 if (nStartEvent)
225 Application::RemoveUserEvent(nStartEvent);
226 if (nEndEvent)
227 Application::RemoveUserEvent(nEndEvent);
228 if (nCellModifiedEvent)
229 Application::RemoveUserEvent(nCellModifiedEvent);
231 delete pCheckBoxPaint;
233 DBG_DTOR(EditBrowseBox,NULL);
236 //------------------------------------------------------------------------------
237 void EditBrowseBox::RemoveRows()
239 BrowseBox::Clear();
240 nOldEditRow = nEditRow = nPaintRow = -1;
241 nEditCol = nOldEditCol = 0;
244 //------------------------------------------------------------------------------
245 BrowserHeader* EditBrowseBox::CreateHeaderBar(BrowseBox* pParent)
247 pHeader = imp_CreateHeaderBar(pParent);
248 if (!IsUpdateMode())
249 pHeader->SetUpdateMode(sal_False);
250 return pHeader;
253 //------------------------------------------------------------------------------
254 BrowserHeader* EditBrowseBox::imp_CreateHeaderBar(BrowseBox* pParent)
256 return new EditBrowserHeader(pParent);
259 //------------------------------------------------------------------------------
260 void EditBrowseBox::LoseFocus()
262 BrowseBox::LoseFocus();
263 DetermineFocus( 0 );
266 //------------------------------------------------------------------------------
267 void EditBrowseBox::GetFocus()
269 BrowseBox::GetFocus();
271 // This should handle the case that the BrowseBox (or one of it's children)
272 // gets the focus from outside by pressing Tab
273 if (IsEditing() && Controller()->GetWindow().IsVisible())
274 Controller()->GetWindow().GrabFocus();
276 DetermineFocus( getRealGetFocusFlags( this ) );
279 //------------------------------------------------------------------------------
280 sal_Bool EditBrowseBox::SeekRow(long nRow)
282 nPaintRow = nRow;
283 return sal_True;
286 //------------------------------------------------------------------------------
287 IMPL_LINK(EditBrowseBox, StartEditHdl, void*, EMPTYARG)
289 nStartEvent = 0;
290 if (IsEditing())
292 EnableAndShow();
293 if (!aController->GetWindow().HasFocus() && (m_pFocusWhileRequest == Application::GetFocusWindow()))
294 aController->GetWindow().GrabFocus();
296 return 0;
299 //------------------------------------------------------------------------------
300 void EditBrowseBox::PaintField( OutputDevice& rDev, const Rectangle& rRect,
301 sal_uInt16 nColumnId ) const
303 if (nColumnId == HANDLE_ID)
305 if (bPaintStatus)
306 PaintStatusCell(rDev, rRect);
308 else
310 // don't paint the current cell
311 if (&rDev == &GetDataWindow())
312 // but only if we're painting onto our data win (which is the usual painting)
313 if (nPaintRow == nEditRow)
315 if (IsEditing() && nEditCol == nColumnId && aController->GetWindow().IsVisible())
316 return;
318 PaintCell(rDev, rRect, nColumnId);
322 //------------------------------------------------------------------------------
323 Image EditBrowseBox::GetImage(RowStatus eStatus) const
325 sal_Bool bHiContrast = isHiContrast(&GetDataWindow());
326 if ( !m_aStatusImages.GetImageCount() || (bHiContrast != m_aImpl->m_bHiContrast) )
328 m_aImpl->m_bHiContrast = bHiContrast;
329 const_cast<EditBrowseBox*>(this)->m_aStatusImages = ImageList(SvtResId(bHiContrast ? RID_SVTOOLS_IMAGELIST_EDITBWSEBOX_H : RID_SVTOOLS_IMAGELIST_EDITBROWSEBOX));
332 Image aImage;
333 bool bNeedMirror = IsRTLEnabled();
334 switch (eStatus)
336 case CURRENT:
337 aImage = m_aStatusImages.GetImage(IMG_EBB_CURRENT);
338 break;
339 case CURRENTNEW:
340 aImage = m_aStatusImages.GetImage(IMG_EBB_CURRENTNEW);
341 break;
342 case MODIFIED:
343 aImage = m_aStatusImages.GetImage(IMG_EBB_MODIFIED);
344 bNeedMirror = false; // the pen is not mirrored
345 break;
346 case NEW:
347 aImage = m_aStatusImages.GetImage(IMG_EBB_NEW);
348 break;
349 case DELETED:
350 aImage = m_aStatusImages.GetImage(IMG_EBB_DELETED);
351 break;
352 case PRIMARYKEY:
353 aImage = m_aStatusImages.GetImage(IMG_EBB_PRIMARYKEY);
354 break;
355 case CURRENT_PRIMARYKEY:
356 aImage = m_aStatusImages.GetImage(IMG_EBB_CURRENT_PRIMARYKEY);
357 break;
358 case FILTER:
359 aImage = m_aStatusImages.GetImage(IMG_EBB_FILTER);
360 break;
361 case HEADERFOOTER:
362 aImage = m_aStatusImages.GetImage(IMG_EBB_HEADERFOOTER);
363 break;
364 case CLEAN:
365 break;
367 if ( bNeedMirror )
369 BitmapEx aBitmap( aImage.GetBitmapEx() );
370 aBitmap.Mirror( BMP_MIRROR_HORZ );
371 aImage = Image( aBitmap );
373 return aImage;
376 //------------------------------------------------------------------------------
377 void EditBrowseBox::PaintStatusCell(OutputDevice& rDev, const Rectangle& rRect) const
379 if (nPaintRow < 0)
380 return;
382 RowStatus eStatus = GetRowStatus( nPaintRow );
383 sal_Int32 nBrowserFlags = GetBrowserFlags();
385 if (nBrowserFlags & EBBF_NO_HANDLE_COLUMN_CONTENT)
386 return;
388 // draw the text of the header column
389 if (nBrowserFlags & EBBF_HANDLE_COLUMN_TEXT )
391 rDev.DrawText( rRect, GetCellText( nPaintRow, 0 ),
392 TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_CLIP );
394 // draw an image
395 else if (eStatus != CLEAN && rDev.GetOutDevType() == OUTDEV_WINDOW)
397 Image aImage(GetImage(eStatus));
398 // calc the image position
399 Size aImageSize(aImage.GetSizePixel());
400 aImageSize.Width() = CalcZoom(aImageSize.Width());
401 aImageSize.Height() = CalcZoom(aImageSize.Height());
402 Point aPos( rRect.TopLeft() );
404 if ( ( aImageSize.Width() > rRect.GetWidth() ) || ( aImageSize.Height() > rRect.GetHeight() ) )
405 rDev.SetClipRegion(rRect);
407 if ( aImageSize.Width() < rRect.GetWidth() )
408 aPos.X() += ( rRect.GetWidth() - aImageSize.Width() ) / 2;
410 if ( aImageSize.Height() < rRect.GetHeight() )
411 aPos.Y() += ( rRect.GetHeight() - aImageSize.Height() ) / 2;
413 if ( IsZoom() )
414 rDev.DrawImage( aPos, aImageSize, aImage, 0 );
415 else
416 rDev.DrawImage( aPos, aImage, 0 );
418 if (rDev.IsClipRegion())
419 rDev.SetClipRegion();
423 //------------------------------------------------------------------------------
424 void EditBrowseBox::ImplStartTracking()
426 bActiveBeforeTracking = IsEditing();
427 if ( bActiveBeforeTracking )
429 DeactivateCell();
430 Update();
433 BrowseBox::ImplStartTracking();
436 //------------------------------------------------------------------------------
437 void EditBrowseBox::ImplTracking()
439 BrowseBox::ImplTracking();
442 //------------------------------------------------------------------------------
443 void EditBrowseBox::ImplEndTracking()
445 if ( bActiveBeforeTracking )
446 ActivateCell();
447 bActiveBeforeTracking = sal_False;
449 BrowseBox::ImplEndTracking();
452 //------------------------------------------------------------------------------
453 void EditBrowseBox::RowHeightChanged()
455 if ( IsEditing() )
457 Rectangle aRect( GetCellRect( nEditRow, nEditCol, sal_False ) );
458 CellControllerRef aCellController( Controller() );
459 ResizeController( aCellController, aRect );
460 aCellController->GetWindow().GrabFocus();
463 BrowseBox::RowHeightChanged();
466 //------------------------------------------------------------------------------
467 EditBrowseBox::RowStatus EditBrowseBox::GetRowStatus(long) const
469 return CLEAN;
472 //------------------------------------------------------------------------------
473 void EditBrowseBox::KeyInput( const KeyEvent& rEvt )
475 sal_uInt16 nCode = rEvt.GetKeyCode().GetCode();
476 sal_Bool bShift = rEvt.GetKeyCode().IsShift();
477 sal_Bool bCtrl = rEvt.GetKeyCode().IsMod1();
479 switch (nCode)
481 case KEY_RETURN:
482 if (!bCtrl && !bShift && IsTabAllowed(sal_True))
484 Dispatch(BROWSER_CURSORRIGHT);
486 else
487 BrowseBox::KeyInput(rEvt);
488 return;
489 case KEY_TAB:
490 if (!bCtrl && !bShift)
492 if (IsTabAllowed(sal_True))
493 Dispatch(BROWSER_CURSORRIGHT);
494 else
495 // do NOT call BrowseBox::KeyInput : this would handle the tab, but we already now
496 // that tab isn't allowed here. So give the Control class a chance
497 Control::KeyInput(rEvt);
498 return;
500 else if (!bCtrl && bShift)
502 if (IsTabAllowed(sal_False))
503 Dispatch(BROWSER_CURSORLEFT);
504 else
505 // do NOT call BrowseBox::KeyInput : this would handle the tab, but we already now
506 // that tab isn't allowed here. So give the Control class a chance
507 Control::KeyInput(rEvt);
508 return;
510 default:
511 BrowseBox::KeyInput(rEvt);
515 //------------------------------------------------------------------------------
516 void EditBrowseBox::MouseButtonDown(const BrowserMouseEvent& rEvt)
518 sal_uInt16 nColPos = GetColumnPos( rEvt.GetColumnId() );
519 long nRow = rEvt.GetRow();
521 // absorb double clicks
522 if (rEvt.GetClicks() > 1 && rEvt.GetRow() >= 0)
523 return;
525 // change to a new position
526 if (IsEditing() && (nColPos != nEditCol || nRow != nEditRow) && (nColPos != BROWSER_INVALIDID) && (nRow < GetRowCount()))
528 CellControllerRef aCellController(Controller());
529 HideAndDisable(aCellController);
532 // we are about to leave the current cell. If there is a "this cell has been modified" notification
533 // pending (asynchronously), this may be deadly -> do it synchronously
534 // 95826 - 2002-10-14 - fs@openoffice.org
535 if ( nCellModifiedEvent )
537 Application::RemoveUserEvent( nCellModifiedEvent );
538 nCellModifiedEvent = 0;
539 LINK( this, EditBrowseBox, CellModifiedHdl ).Call( NULL );
542 if (0 == rEvt.GetColumnId())
543 { // it was the handle column. save the current cell content if necessary
544 // (clicking on the handle column results in selecting the current row)
545 // 23.01.2001 - 82797 - FS
546 if (IsEditing() && aController->IsModified())
547 SaveModified();
550 aMouseEvent.Set(&rEvt,sal_True);
551 BrowseBox::MouseButtonDown(rEvt);
552 aMouseEvent.Clear();
554 if (0 != (m_nBrowserFlags & EBBF_ACTIVATE_ON_BUTTONDOWN))
556 // the base class does not travel upon MouseButtonDown, but implActivateCellOnMouseEvent assumes we traveled ...
557 GoToRowColumnId( rEvt.GetRow(), rEvt.GetColumnId() );
558 if (rEvt.GetRow() >= 0)
559 implActivateCellOnMouseEvent(rEvt, sal_False);
563 //------------------------------------------------------------------------------
564 void EditBrowseBox::MouseButtonUp( const BrowserMouseEvent& rEvt )
566 // absorb double clicks
567 if (rEvt.GetClicks() > 1 && rEvt.GetRow() >= 0)
568 return;
570 aMouseEvent.Set(&rEvt,sal_False);
571 BrowseBox::MouseButtonUp(rEvt);
572 aMouseEvent.Clear();
574 if (0 == (m_nBrowserFlags & EBBF_ACTIVATE_ON_BUTTONDOWN))
575 if (rEvt.GetRow() >= 0)
576 implActivateCellOnMouseEvent(rEvt, sal_True);
579 //------------------------------------------------------------------------------
580 void EditBrowseBox::implActivateCellOnMouseEvent(const BrowserMouseEvent& _rEvt, sal_Bool _bUp)
582 if (!IsEditing())
583 ActivateCell();
584 else if (IsEditing() && !aController->GetWindow().IsEnabled())
585 DeactivateCell();
586 else if (IsEditing() && !aController->GetWindow().HasChildPathFocus())
587 AsynchGetFocus();
589 if (IsEditing() && aController->GetWindow().IsEnabled() && aController->WantMouseEvent())
590 { // forwards the event to the control
592 // If the field has been moved previously, we have to adjust the position
594 aController->GetWindow().GrabFocus();
596 // the position of the event relative to the controller's window
597 Point aPos = _rEvt.GetPosPixel() - _rEvt.GetRect().TopLeft();
598 // the (child) window which should really get the event
599 Window* pRealHandler = aController->GetWindow().FindWindow(aPos);
600 if (pRealHandler)
601 // the coords relative to this real handler
602 aPos -= pRealHandler->GetPosPixel();
603 else
604 pRealHandler = &aController->GetWindow();
606 // the faked event
607 MouseEvent aEvent(aPos, _rEvt.GetClicks(), _rEvt.GetMode(),
608 _rEvt.GetButtons(),
609 _rEvt.GetModifier());
611 pRealHandler->MouseButtonDown(aEvent);
612 if (_bUp)
613 pRealHandler->MouseButtonUp(aEvent);
615 Window *pWin = &aController->GetWindow();
616 if (!pWin->IsTracking())
618 for (pWin = pWin->GetWindow(WINDOW_FIRSTCHILD);
619 pWin && !pWin->IsTracking();
620 pWin = pWin->GetWindow(WINDOW_NEXT))
624 if (pWin && pWin->IsTracking())
625 pWin->EndTracking();
629 //------------------------------------------------------------------------------
630 void EditBrowseBox::Dispatch( sal_uInt16 _nId )
632 if ( _nId == BROWSER_ENHANCESELECTION )
633 { // this is a workaround for the bug in the base class:
634 // if the row selection is to be extended (which is what BROWSER_ENHANCESELECTION tells us)
635 // then the base class does not revert any column selections, while, for doing a "simple"
636 // selection (BROWSER_SELECT), it does. In fact, it does not only revert the col selection then,
637 // but also any current row selections.
638 // This clearly tells me that the both ids are for row selection only - there this behaviour does
639 // make sense.
640 // But here, where we have column selection, too, we take care of this ourself.
641 if ( GetSelectColumnCount( ) )
643 while ( GetSelectColumnCount( ) )
644 SelectColumnPos(
645 sal::static_int_cast< USHORT >(FirstSelectedColumn()),
646 sal_False );
647 Select();
650 BrowseBox::Dispatch( _nId );
653 //------------------------------------------------------------------------------
654 long EditBrowseBox::PreNotify(NotifyEvent& rEvt)
656 switch (rEvt.GetType())
658 case EVENT_KEYINPUT:
659 if ( (IsEditing() && Controller()->GetWindow().HasChildPathFocus())
660 || rEvt.GetWindow() == &GetDataWindow()
661 || (!IsEditing() && HasChildPathFocus())
664 const KeyEvent* pKeyEvent = rEvt.GetKeyEvent();
665 sal_uInt16 nCode = pKeyEvent->GetKeyCode().GetCode();
666 sal_Bool bShift = pKeyEvent->GetKeyCode().IsShift();
667 sal_Bool bCtrl = pKeyEvent->GetKeyCode().IsMod1();
668 sal_Bool bAlt = pKeyEvent->GetKeyCode().IsMod2();
669 sal_Bool bLocalSelect= sal_False;
670 sal_Bool bNonEditOnly = sal_False;
671 sal_uInt16 nId = BROWSER_NONE;
673 if (!bAlt && !bCtrl && !bShift )
674 switch ( nCode )
676 case KEY_DOWN: nId = BROWSER_CURSORDOWN; break;
677 case KEY_UP: nId = BROWSER_CURSORUP; break;
678 case KEY_PAGEDOWN: nId = BROWSER_CURSORPAGEDOWN; break;
679 case KEY_PAGEUP: nId = BROWSER_CURSORPAGEUP; break;
680 case KEY_HOME: nId = BROWSER_CURSORHOME; break;
681 case KEY_END: nId = BROWSER_CURSOREND; break;
683 case KEY_TAB:
684 // ask if traveling to the next cell is allowed
685 if (IsTabAllowed(sal_True))
686 nId = BROWSER_CURSORRIGHT;
687 break;
689 case KEY_RETURN:
690 // save the cell content (if necessary)
691 if (IsEditing() && aController->IsModified() && !((EditBrowseBox *) this)->SaveModified())
693 // maybe we're not visible ...
694 EnableAndShow();
695 aController->GetWindow().GrabFocus();
696 return 1;
698 // ask if traveling to the next cell is allowed
699 if (IsTabAllowed(sal_True))
700 nId = BROWSER_CURSORRIGHT;
702 break;
703 case KEY_RIGHT: nId = BROWSER_CURSORRIGHT; break;
704 case KEY_LEFT: nId = BROWSER_CURSORLEFT; break;
705 case KEY_SPACE: nId = BROWSER_SELECT; bNonEditOnly = bLocalSelect = sal_True;break;
708 if ( !bAlt && !bCtrl && bShift )
709 switch ( nCode )
711 case KEY_DOWN: nId = BROWSER_SELECTDOWN; bLocalSelect = sal_True;break;
712 case KEY_UP: nId = BROWSER_SELECTUP; bLocalSelect = sal_True;break;
713 case KEY_HOME: nId = BROWSER_SELECTHOME; bLocalSelect = sal_True;break;
714 case KEY_END: nId = BROWSER_SELECTEND; bLocalSelect = sal_True;break;
715 case KEY_TAB:
716 if (IsTabAllowed(sal_False))
717 nId = BROWSER_CURSORLEFT;
718 break;
721 if ( !bAlt && bCtrl && bShift )
722 switch ( nCode )
724 case KEY_SPACE: nId = BROWSER_SELECTCOLUMN; bLocalSelect = sal_True; break;
728 if ( !bAlt && bCtrl && !bShift )
729 switch ( nCode )
731 case KEY_DOWN: nId = BROWSER_SCROLLUP; break;
732 case KEY_UP: nId = BROWSER_SCROLLDOWN; break;
733 case KEY_PAGEDOWN: nId = BROWSER_CURSORENDOFFILE; break;
734 case KEY_PAGEUP: nId = BROWSER_CURSORTOPOFFILE; break;
735 case KEY_HOME: nId = BROWSER_CURSORTOPOFSCREEN; break;
736 case KEY_END: nId = BROWSER_CURSORENDOFSCREEN; break;
737 case KEY_SPACE: nId = BROWSER_ENHANCESELECTION; bLocalSelect = sal_True;break;
741 if ( ( nId != BROWSER_NONE )
742 && ( !IsEditing()
743 || ( !bNonEditOnly
744 && aController->MoveAllowed( *pKeyEvent )
749 if (nId == BROWSER_SELECT || BROWSER_SELECTCOLUMN == nId )
751 // save the cell content (if necessary)
752 if (IsEditing() && aController->IsModified() && !((EditBrowseBox *) this)->SaveModified())
754 // maybe we're not visible ...
755 EnableAndShow();
756 aController->GetWindow().GrabFocus();
757 return 1;
761 Dispatch(nId);
763 if (bLocalSelect && (GetSelectRowCount() || GetSelection() != NULL))
764 DeactivateCell();
765 return 1;
769 return BrowseBox::PreNotify(rEvt);
772 //------------------------------------------------------------------------------
773 sal_Bool EditBrowseBox::IsTabAllowed(sal_Bool) const
775 return sal_True;
778 //------------------------------------------------------------------------------
779 long EditBrowseBox::Notify(NotifyEvent& rEvt)
781 switch (rEvt.GetType())
783 case EVENT_GETFOCUS:
784 DetermineFocus( getRealGetFocusFlags( this ) );
785 break;
787 case EVENT_LOSEFOCUS:
788 DetermineFocus( 0 );
789 break;
791 return BrowseBox::Notify(rEvt);
794 //------------------------------------------------------------------------------
795 void EditBrowseBox::StateChanged( StateChangedType nType )
797 BrowseBox::StateChanged( nType );
799 bool bNeedCellReActivation = false;
800 if ( nType == STATE_CHANGE_MIRRORING )
802 bNeedCellReActivation = true;
804 else if ( nType == STATE_CHANGE_ZOOM )
806 ImplInitSettings( sal_True, sal_False, sal_False );
807 bNeedCellReActivation = true;
809 else if ( nType == STATE_CHANGE_CONTROLFONT )
811 ImplInitSettings( sal_True, sal_False, sal_False );
812 Invalidate();
814 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
816 ImplInitSettings( sal_False, sal_True, sal_False );
817 Invalidate();
819 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
821 ImplInitSettings( sal_False, sal_False, sal_True );
822 Invalidate();
824 else if (nType == STATE_CHANGE_STYLE)
826 WinBits nStyle = GetStyle();
827 if (!(nStyle & WB_NOTABSTOP) )
828 nStyle |= WB_TABSTOP;
830 SetStyle(nStyle);
832 if ( bNeedCellReActivation )
834 if ( IsEditing() )
836 DeactivateCell();
837 ActivateCell();
842 //------------------------------------------------------------------------------
843 void EditBrowseBox::DataChanged( const DataChangedEvent& rDCEvt )
845 BrowseBox::DataChanged( rDCEvt );
847 if ((( rDCEvt.GetType() == DATACHANGED_SETTINGS ) ||
848 ( rDCEvt.GetType() == DATACHANGED_DISPLAY )) &&
849 ( rDCEvt.GetFlags() & SETTINGS_STYLE ))
851 ImplInitSettings( sal_True, sal_True, sal_True );
852 Invalidate();
856 //------------------------------------------------------------------------------
857 void EditBrowseBox::ImplInitSettings( sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground )
859 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
861 if (bFont)
863 Font aFont = rStyleSettings.GetFieldFont();
864 if (IsControlFont())
866 GetDataWindow().SetControlFont(GetControlFont());
867 aFont.Merge(GetControlFont());
869 else
870 GetDataWindow().SetControlFont();
872 GetDataWindow().SetZoomedPointFont(aFont);
875 if ( bFont || bForeground )
877 Color aTextColor = rStyleSettings.GetFieldTextColor();
878 if (IsControlForeground())
880 aTextColor = GetControlForeground();
881 GetDataWindow().SetControlForeground(aTextColor);
883 else
884 GetDataWindow().SetControlForeground();
886 GetDataWindow().SetTextColor( aTextColor );
889 if ( bBackground )
891 if (GetDataWindow().IsControlBackground())
893 GetDataWindow().SetControlBackground(GetControlBackground());
894 GetDataWindow().SetBackground(GetDataWindow().GetControlBackground());
895 GetDataWindow().SetFillColor(GetDataWindow().GetControlBackground());
897 else
899 GetDataWindow().SetControlBackground();
900 GetDataWindow().SetBackground( rStyleSettings.GetFieldColor() );
901 GetDataWindow().SetFillColor( rStyleSettings.GetFieldColor() );
906 //------------------------------------------------------------------------------
907 sal_Bool EditBrowseBox::IsCursorMoveAllowed(long nNewRow, sal_uInt16 nNewColId) const
909 sal_uInt16 nInfo = 0;
911 if (GetSelectColumnCount() || (aMouseEvent.Is() && aMouseEvent->GetRow() < 0))
912 nInfo |= COLSELECT;
913 if ((GetSelection() != NULL && GetSelectRowCount()) ||
914 (aMouseEvent.Is() && aMouseEvent->GetColumnId() == HANDLE_ID))
915 nInfo |= ROWSELECT;
916 if (!nInfo && nNewRow != nEditRow)
917 nInfo |= ROWCHANGE;
918 if (!nInfo && nNewColId != nEditCol)
919 nInfo |= COLCHANGE;
921 if (nInfo == 0) // nothing happened
922 return sal_True;
924 // save the cell content
925 if (IsEditing() && aController->IsModified() && !((EditBrowseBox *) this)->SaveModified())
927 // maybe we're not visible ...
928 EnableAndShow();
929 aController->GetWindow().GrabFocus();
930 return sal_False;
933 EditBrowseBox * pTHIS = (EditBrowseBox *) this;
935 // save the cell content if
936 // a) a selection is beeing made
937 // b) the row is changing
938 if (IsModified() && (nInfo & (ROWCHANGE | COLSELECT | ROWSELECT)) &&
939 !pTHIS->SaveRow())
941 if (nInfo & COLSELECT ||
942 nInfo & ROWSELECT)
944 // cancel selected
945 pTHIS->SetNoSelection();
948 if (IsEditing())
950 if (!Controller()->GetWindow().IsVisible())
952 EnableAndShow();
954 aController->GetWindow().GrabFocus();
956 return sal_False;
959 if (nNewRow != nEditRow)
961 Window& rWindow = GetDataWindow();
962 // don't paint too much
963 // update the status immediatly if possible
964 if ((nEditRow >= 0) && (GetBrowserFlags() & EBBF_NO_HANDLE_COLUMN_CONTENT) == 0)
966 Rectangle aRect = GetFieldRectPixel(nEditRow, 0, sal_False );
967 // status cell should be painted if and only if text is displayed
968 // note: bPaintStatus is mutable, but Solaris has problems with assigning
969 // probably because it is part of a bitfield
970 pTHIS->bPaintStatus = static_cast< sal_Bool >
971 (( GetBrowserFlags() & EBBF_HANDLE_COLUMN_TEXT ) == EBBF_HANDLE_COLUMN_TEXT );
972 rWindow.Paint(aRect);
973 pTHIS->bPaintStatus = sal_True;
976 // don't paint during row change
977 rWindow.EnablePaint(sal_False);
979 // the last veto chance for derived classes
980 if (!pTHIS->CursorMoving(nNewRow, nNewColId))
982 pTHIS->InvalidateStatusCell(nEditRow);
983 rWindow.EnablePaint(sal_True);
984 return sal_False;
986 else
988 rWindow.EnablePaint(sal_True);
989 return sal_True;
992 else
993 return pTHIS->CursorMoving(nNewRow, nNewColId);
996 //------------------------------------------------------------------------------
997 void EditBrowseBox::ColumnMoved(sal_uInt16 nId)
999 BrowseBox::ColumnMoved(nId);
1000 if (IsEditing())
1002 Rectangle aRect( GetCellRect(nEditRow, nEditCol, sal_False));
1003 CellControllerRef aControllerRef = Controller();
1004 ResizeController(aControllerRef, aRect);
1005 Controller()->GetWindow().GrabFocus();
1009 //------------------------------------------------------------------------------
1010 sal_Bool EditBrowseBox::SaveRow()
1012 return sal_True;
1015 //------------------------------------------------------------------------------
1016 sal_Bool EditBrowseBox::CursorMoving(long, sal_uInt16)
1018 ((EditBrowseBox *) this)->DeactivateCell(sal_False);
1019 return sal_True;
1022 //------------------------------------------------------------------------------
1023 void EditBrowseBox::CursorMoved()
1025 long nNewRow = GetCurRow();
1026 if (nEditRow != nNewRow)
1028 if ((GetBrowserFlags() & EBBF_NO_HANDLE_COLUMN_CONTENT) == 0)
1029 InvalidateStatusCell(nNewRow);
1030 nEditRow = nNewRow;
1032 ActivateCell();
1033 GetDataWindow().EnablePaint(sal_True);
1034 // should not be called here because the descant event is not needed here
1035 //BrowseBox::CursorMoved();
1038 //------------------------------------------------------------------------------
1039 void EditBrowseBox::EndScroll()
1041 if (IsEditing())
1043 Rectangle aRect = GetCellRect(nEditRow, nEditCol, sal_False);
1044 ResizeController(aController,aRect);
1045 AsynchGetFocus();
1047 BrowseBox::EndScroll();
1050 //------------------------------------------------------------------------------
1051 void EditBrowseBox::ActivateCell(long nRow, sal_uInt16 nCol, sal_Bool bCellFocus)
1053 if (IsEditing())
1054 return;
1056 nEditCol = nCol;
1058 if ((GetSelectRowCount() && GetSelection() != NULL) || GetSelectColumnCount() ||
1059 (aMouseEvent.Is() && (aMouseEvent.IsDown() || aMouseEvent->GetClicks() > 1))) // bei MouseDown passiert noch nichts
1061 return;
1064 if (nEditRow >= 0 && nEditCol > HANDLE_ID)
1066 aController = GetController(nRow, nCol);
1067 if (aController.Is())
1069 Rectangle aRect( GetCellRect(nEditRow, nEditCol, sal_False));
1070 ResizeController(aController, aRect);
1072 InitController(aController, nEditRow, nEditCol);
1074 aController->ClearModified();
1075 aController->SetModifyHdl(LINK(this,EditBrowseBox,ModifyHdl));
1076 EnableAndShow();
1078 if ( isAccessibleAlive() )
1079 implCreateActiveAccessible();
1081 // activate the cell only of the browser has the focus
1082 if ( bHasFocus && bCellFocus )
1083 AsynchGetFocus();
1085 else
1087 // no controller -> we have a new "active descendant"
1088 if ( isAccessibleAlive() && HasFocus() )
1090 commitTableEvent(
1091 ACTIVE_DESCENDANT_CHANGED,
1092 makeAny( CreateAccessibleCell( nRow, GetColumnPos( nCol ) ) ),
1093 Any()
1100 //------------------------------------------------------------------------------
1101 void EditBrowseBox::DeactivateCell(sal_Bool bUpdate)
1103 if (IsEditing())
1105 if ( isAccessibleAlive() )
1107 commitBrowseBoxEvent( CHILD, Any(), makeAny( m_aImpl->m_xActiveCell ) );
1108 m_aImpl->clearActiveCell();
1111 aOldController = aController;
1112 aController.Clear();
1114 // reset the modify handler
1115 aOldController->SetModifyHdl(Link());
1117 if (bHasFocus)
1118 GrabFocus(); // ensure that we have (and keep) the focus
1120 HideAndDisable(aOldController);
1122 // update if requested
1123 if (bUpdate)
1124 Update();
1126 nOldEditCol = nEditCol;
1127 nOldEditRow = nEditRow;
1129 // release the controller (asynchronously)
1130 if (nEndEvent)
1131 Application::RemoveUserEvent(nEndEvent);
1132 nEndEvent = Application::PostUserEvent(LINK(this,EditBrowseBox,EndEditHdl));
1136 //------------------------------------------------------------------------------
1137 Rectangle EditBrowseBox::GetCellRect(long nRow, sal_uInt16 nColId, sal_Bool bRel) const
1139 Rectangle aRect( GetFieldRectPixel(nRow, nColId, bRel));
1140 if ((GetMode() & BROWSER_CURSOR_WO_FOCUS) == BROWSER_CURSOR_WO_FOCUS)
1142 aRect.Top() += 1;
1143 aRect.Bottom() -= 1;
1145 return aRect;
1148 //------------------------------------------------------------------------------
1149 IMPL_LINK(EditBrowseBox, EndEditHdl, void*, EMPTYARG)
1151 nEndEvent = 0;
1152 ReleaseController(aOldController, nOldEditRow, nOldEditCol);
1154 aOldController = CellControllerRef();
1155 nOldEditRow = -1;
1156 nOldEditCol = 0;
1158 return 0;
1161 //------------------------------------------------------------------------------
1162 IMPL_LINK(EditBrowseBox, ModifyHdl, void*, EMPTYARG)
1164 if (nCellModifiedEvent)
1165 Application::RemoveUserEvent(nCellModifiedEvent);
1166 nCellModifiedEvent = Application::PostUserEvent(LINK(this,EditBrowseBox,CellModifiedHdl));
1167 return 0;
1170 //------------------------------------------------------------------------------
1171 IMPL_LINK(EditBrowseBox, CellModifiedHdl, void*, EMPTYARG)
1173 nCellModifiedEvent = 0;
1174 CellModified();
1175 return 0;
1178 //------------------------------------------------------------------------------
1179 void EditBrowseBox::ColumnResized( sal_uInt16 )
1181 if (IsEditing())
1183 Rectangle aRect( GetCellRect(nEditRow, nEditCol, sal_False));
1184 CellControllerRef aControllerRef = Controller();
1185 ResizeController(aControllerRef, aRect);
1186 Controller()->GetWindow().GrabFocus();
1190 //------------------------------------------------------------------------------
1191 sal_uInt16 EditBrowseBox::AppendColumn(const String& rName, sal_uInt16 nWidth, sal_uInt16 nPos, sal_uInt16 nId)
1193 if (nId == (sal_uInt16)-1)
1195 // look for the next free id
1196 for (nId = ColCount(); nId > 0 && GetColumnPos(nId) != BROWSER_INVALIDID; nId--)
1199 if (!nId)
1201 // if there is no handle column
1202 // increment the id
1203 if (!ColCount() || GetColumnId(0))
1204 nId = ColCount() + 1;
1208 DBG_ASSERT(nId, "EditBrowseBox::AppendColumn: invalid id!");
1210 long w = nWidth;
1211 if (!w)
1212 w = GetDefaultColumnWidth(rName);
1214 InsertDataColumn(nId, rName, w, (HIB_CENTER | HIB_VCENTER | HIB_CLICKABLE), nPos);
1215 return nId;
1218 //------------------------------------------------------------------------------
1219 void EditBrowseBox::Resize()
1221 BrowseBox::Resize();
1223 // if the window is smaller than "title line height" + "control area",
1224 // do nothing
1225 if (GetOutputSizePixel().Height() <
1226 (GetControlArea().GetHeight() + GetDataWindow().GetPosPixel().Y()))
1227 return;
1229 // the size of the control area
1230 Point aPoint(GetControlArea().TopLeft());
1231 sal_uInt16 nX = (sal_uInt16)aPoint.X();
1233 ArrangeControls(nX, (sal_uInt16)aPoint.Y());
1235 if (!nX)
1236 nX = USHRT_MAX;
1237 ReserveControlArea((sal_uInt16)nX);
1240 //------------------------------------------------------------------------------
1241 void EditBrowseBox::ArrangeControls(sal_uInt16&, sal_uInt16)
1245 //------------------------------------------------------------------------------
1246 CellController* EditBrowseBox::GetController(long, sal_uInt16)
1248 return NULL;
1251 //-----------------------------------------------------------------------------
1252 void EditBrowseBox::ResizeController(CellControllerRef& rController, const Rectangle& rRect)
1254 rController->GetWindow().SetPosSizePixel(rRect.TopLeft(), rRect.GetSize());
1257 //------------------------------------------------------------------------------
1258 void EditBrowseBox::InitController(CellControllerRef&, long, sal_uInt16)
1262 //------------------------------------------------------------------------------
1263 void EditBrowseBox::ReleaseController(CellControllerRef&, long, sal_uInt16)
1267 //------------------------------------------------------------------------------
1268 void EditBrowseBox::CellModified()
1273 //------------------------------------------------------------------------------
1274 sal_Bool EditBrowseBox::SaveModified()
1276 return sal_True;
1279 //------------------------------------------------------------------------------
1280 void EditBrowseBox::DoubleClick(const BrowserMouseEvent& rEvt)
1282 // when double clicking on the column, the optimum size will be calculated
1283 sal_uInt16 nColId = rEvt.GetColumnId();
1284 if (nColId != HANDLE_ID)
1285 SetColumnWidth(nColId, GetAutoColumnWidth(nColId));
1288 //------------------------------------------------------------------------------
1289 sal_uInt32 EditBrowseBox::GetAutoColumnWidth(sal_uInt16 nColId)
1291 sal_uInt32 nCurColWidth = GetColumnWidth(nColId);
1292 sal_uInt32 nMinColWidth = CalcZoom(20); // minimum
1293 sal_uInt32 nNewColWidth = nMinColWidth;
1294 long nMaxRows = Min(long(GetVisibleRows()), GetRowCount());
1295 long nLastVisRow = GetTopRow() + nMaxRows - 1;
1297 if (GetTopRow() <= nLastVisRow) // calc the column with using the cell contents
1299 for (long i = GetTopRow(); i <= nLastVisRow; ++i)
1300 nNewColWidth = std::max(nNewColWidth,GetTotalCellWidth(i,nColId) + 12);
1302 if (nNewColWidth == nCurColWidth) // size has not changed
1303 nNewColWidth = GetDefaultColumnWidth(GetColumnTitle(nColId));
1305 else
1306 nNewColWidth = GetDefaultColumnWidth(GetColumnTitle(nColId));
1307 return nNewColWidth;
1310 //------------------------------------------------------------------------------
1311 sal_uInt32 EditBrowseBox::GetTotalCellWidth(long, sal_uInt16)
1313 return 0;
1316 //------------------------------------------------------------------------------
1317 void EditBrowseBox::InvalidateHandleColumn()
1319 Rectangle aHdlFieldRect( GetFieldRectPixel( 0, 0 ));
1320 Rectangle aInvalidRect( Point(0,0), GetOutputSizePixel() );
1321 aInvalidRect.Right() = aHdlFieldRect.Right();
1322 Invalidate( aInvalidRect );
1325 //------------------------------------------------------------------------------
1326 void EditBrowseBox::PaintTristate(OutputDevice&, const Rectangle& rRect,const TriState& eState,sal_Bool _bEnabled) const
1328 pCheckBoxPaint->GetBox().SetState(eState);
1329 pCheckBoxPaint->SetPosSizePixel(rRect.TopLeft(), rRect.GetSize());
1331 // First update the parent, preventing that while painting this window
1332 // an update for the parent is done (because it's in the queue already)
1333 // which may lead to hiding this window immediately
1334 // #95598# comment out OJ
1335 /* if (pCheckBoxPaint->GetParent())
1336 pCheckBoxPaint->GetParent()->Update();
1338 pCheckBoxPaint->GetBox().Enable(_bEnabled);
1339 pCheckBoxPaint->Show();
1340 pCheckBoxPaint->SetParentUpdateMode( sal_False );
1341 pCheckBoxPaint->Update();
1342 pCheckBoxPaint->Hide();
1343 pCheckBoxPaint->SetParentUpdateMode( sal_True );
1346 //------------------------------------------------------------------------------
1347 void EditBrowseBox::AsynchGetFocus()
1349 if (nStartEvent)
1350 Application::RemoveUserEvent(nStartEvent);
1352 m_pFocusWhileRequest = Application::GetFocusWindow();
1353 nStartEvent = Application::PostUserEvent(LINK(this,EditBrowseBox,StartEditHdl));
1356 //------------------------------------------------------------------------------
1357 void EditBrowseBox::SetBrowserFlags(sal_Int32 nFlags)
1359 if (m_nBrowserFlags == nFlags)
1360 return;
1362 sal_Bool RowPicturesChanges = ((m_nBrowserFlags & EBBF_NO_HANDLE_COLUMN_CONTENT) !=
1363 (nFlags & EBBF_NO_HANDLE_COLUMN_CONTENT));
1364 m_nBrowserFlags = nFlags;
1366 if (RowPicturesChanges)
1367 InvalidateStatusCell(GetCurRow());
1369 //------------------------------------------------------------------------------
1370 inline void EditBrowseBox::HideAndDisable(CellControllerRef& rController)
1372 rController->suspend();
1374 //------------------------------------------------------------------------------
1375 inline void EditBrowseBox::EnableAndShow() const
1377 Controller()->resume();
1379 //===============================================================================
1381 DBG_NAME(CellController);
1382 //------------------------------------------------------------------------------
1383 CellController::CellController(Control* pW)
1384 :pWindow( pW )
1385 ,bSuspended( sal_True )
1387 DBG_CTOR(CellController,NULL);
1389 DBG_ASSERT(pWindow, "CellController::CellController: missing the window!");
1390 DBG_ASSERT(!pWindow->IsVisible(), "CellController::CellController: window should not be visible!");
1393 //-----------------------------------------------------------------------------
1394 CellController::~CellController()
1397 DBG_DTOR(CellController,NULL);
1400 //-----------------------------------------------------------------------------
1401 void CellController::suspend( )
1403 DBG_ASSERT( bSuspended == !GetWindow().IsVisible(), "CellController::suspend: inconsistence!" );
1404 if ( !isSuspended( ) )
1406 CommitModifications();
1407 GetWindow().Hide( );
1408 GetWindow().Disable( );
1409 bSuspended = sal_True;
1413 //-----------------------------------------------------------------------------
1414 void CellController::resume( )
1416 DBG_ASSERT( bSuspended == !GetWindow().IsVisible(), "CellController::resume: inconsistence!" );
1417 if ( isSuspended( ) )
1419 GetWindow().Enable( );
1420 GetWindow().Show( );
1421 bSuspended = sal_False;
1425 //-----------------------------------------------------------------------------
1426 void CellController::CommitModifications()
1428 // nothing to do in this base class
1431 //-----------------------------------------------------------------------------
1432 sal_Bool CellController::WantMouseEvent() const
1434 return sal_False;
1437 //-----------------------------------------------------------------------------
1438 void CellController::SetModified()
1442 //-----------------------------------------------------------------------------
1443 sal_Bool CellController::MoveAllowed(const KeyEvent&) const
1445 return sal_True;
1447 // .......................................................................
1448 } // namespace svt
1449 // .......................................................................