summaryrefslogtreecommitdiff
path: root/vcl/source/control/ctrl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/control/ctrl.cxx')
-rw-r--r--vcl/source/control/ctrl.cxx587
1 files changed, 587 insertions, 0 deletions
diff --git a/vcl/source/control/ctrl.cxx b/vcl/source/control/ctrl.cxx
new file mode 100644
index 000000000000..918675cc0783
--- /dev/null
+++ b/vcl/source/control/ctrl.cxx
@@ -0,0 +1,587 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef _SV_RC_H
+#include <tools/rc.h>
+#endif
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/event.hxx>
+#include <vcl/ctrl.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/controldata.hxx>
+#include <vcl/salnativewidgets.hxx>
+#include <vcl/textlayout.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace vcl;
+
+// =======================================================================
+
+void Control::ImplInitControlData()
+{
+ mbHasFocus = FALSE;
+ mpControlData = new ImplControlData;
+}
+
+// -----------------------------------------------------------------------
+
+Control::Control( WindowType nType ) :
+ Window( nType )
+{
+ ImplInitControlData();
+}
+
+// -----------------------------------------------------------------------
+
+Control::Control( Window* pParent, WinBits nStyle ) :
+ Window( WINDOW_CONTROL )
+{
+ ImplInitControlData();
+ Window::ImplInit( pParent, nStyle, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+Control::Control( Window* pParent, const ResId& rResId ) :
+ Window( WINDOW_CONTROL )
+{
+ ImplInitControlData();
+ rResId.SetRT( RSC_CONTROL );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle, NULL );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+Control::~Control()
+{
+ delete mpControlData, mpControlData = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void Control::GetFocus()
+{
+ Window::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void Control::LoseFocus()
+{
+ Window::LoseFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void Control::Resize()
+{
+ ImplClearLayoutData();
+ Window::Resize();
+}
+
+// -----------------------------------------------------------------------
+
+void Control::FillLayoutData() const
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Control::CreateLayoutData() const
+{
+ DBG_ASSERT( !mpControlData->mpLayoutData, "Control::CreateLayoutData: should be called with non-existent layout data only!" );
+ mpControlData->mpLayoutData = new ::vcl::ControlLayoutData();
+}
+
+// -----------------------------------------------------------------------
+
+bool Control::HasLayoutData() const
+{
+ return mpControlData->mpLayoutData != NULL;
+}
+
+// -----------------------------------------------------------------------
+
+::vcl::ControlLayoutData* Control::GetLayoutData() const
+{
+ return mpControlData->mpLayoutData;
+}
+
+// -----------------------------------------------------------------------
+
+void Control::SetText( const String& rStr )
+{
+ ImplClearLayoutData();
+ Window::SetText( rStr );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ControlLayoutData::GetCharacterBounds( long nIndex ) const
+{
+ return (nIndex >= 0 && nIndex < (long) m_aUnicodeBoundRects.size()) ? m_aUnicodeBoundRects[ nIndex ] : Rectangle();
+}
+
+
+// -----------------------------------------------------------------------
+
+Rectangle Control::GetCharacterBounds( long nIndex ) const
+{
+ if( !HasLayoutData() )
+ FillLayoutData();
+ return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetCharacterBounds( nIndex ) : Rectangle();
+}
+
+// -----------------------------------------------------------------------
+
+long ControlLayoutData::GetIndexForPoint( const Point& rPoint ) const
+{
+ long nIndex = -1;
+ for( long i = m_aUnicodeBoundRects.size()-1; i >= 0; i-- )
+ {
+ if( m_aUnicodeBoundRects[ i ].IsInside( rPoint ) )
+ {
+ nIndex = i;
+ break;
+ }
+ }
+ return nIndex;
+}
+
+// -----------------------------------------------------------------------
+
+long Control::GetIndexForPoint( const Point& rPoint ) const
+{
+ if( ! HasLayoutData() )
+ FillLayoutData();
+ return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetIndexForPoint( rPoint ) : -1;
+}
+
+// -----------------------------------------------------------------------
+
+long ControlLayoutData::GetLineCount() const
+{
+ long nLines = m_aLineIndices.size();
+ if( nLines == 0 && m_aDisplayText.Len() )
+ nLines = 1;
+ return nLines;
+}
+
+// -----------------------------------------------------------------------
+
+long Control::GetLineCount() const
+{
+ if( !HasLayoutData() )
+ FillLayoutData();
+ return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetLineCount() : 0;
+}
+
+// -----------------------------------------------------------------------
+
+Pair ControlLayoutData::GetLineStartEnd( long nLine ) const
+{
+ Pair aPair( -1, -1 );
+
+ int nDisplayLines = m_aLineIndices.size();
+ if( nLine >= 0 && nLine < nDisplayLines )
+ {
+ aPair.A() = m_aLineIndices[nLine];
+ if( nLine+1 < nDisplayLines )
+ aPair.B() = m_aLineIndices[nLine+1]-1;
+ else
+ aPair.B() = m_aDisplayText.Len()-1;
+ }
+ else if( nLine == 0 && nDisplayLines == 0 && m_aDisplayText.Len() )
+ {
+ // special case for single line controls so the implementations
+ // in that case do not have to fill in the line indices
+ aPair.A() = 0;
+ aPair.B() = m_aDisplayText.Len()-1;
+ }
+ return aPair;
+}
+
+// -----------------------------------------------------------------------
+
+Pair Control::GetLineStartEnd( long nLine ) const
+{
+ if( !HasLayoutData() )
+ FillLayoutData();
+ return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetLineStartEnd( nLine ) : Pair( -1, -1 );
+}
+
+// -----------------------------------------------------------------------
+
+long ControlLayoutData::ToRelativeLineIndex( long nIndex ) const
+{
+ // is the index sensible at all ?
+ if( nIndex >= 0 && nIndex < m_aDisplayText.Len() )
+ {
+ int nDisplayLines = m_aLineIndices.size();
+ // if only 1 line exists, then absolute and relative index are
+ // identical -> do nothing
+ if( nDisplayLines > 1 )
+ {
+ int nLine;
+ for( nLine = nDisplayLines-1; nLine >= 0; nLine-- )
+ {
+ if( m_aLineIndices[nLine] <= nIndex )
+ {
+ nIndex -= m_aLineIndices[nLine];
+ break;
+ }
+ }
+ if( nLine < 0 )
+ {
+ DBG_ASSERT( nLine >= 0, "ToRelativeLineIndex failed" );
+ nIndex = -1;
+ }
+ }
+ }
+ else
+ nIndex = -1;
+
+ return nIndex;
+}
+
+// -----------------------------------------------------------------------
+
+long Control::ToRelativeLineIndex( long nIndex ) const
+{
+ if( !HasLayoutData() )
+ FillLayoutData();
+ return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->ToRelativeLineIndex( nIndex ) : -1;
+}
+
+// -----------------------------------------------------------------------
+
+String Control::GetDisplayText() const
+{
+ if( !HasLayoutData() )
+ FillLayoutData();
+ return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->m_aDisplayText : GetText();
+}
+
+// -----------------------------------------------------------------------
+
+long Control::Notify( NotifyEvent& rNEvt )
+{
+ if ( rNEvt.GetType() == EVENT_GETFOCUS )
+ {
+ if ( !mbHasFocus )
+ {
+ mbHasFocus = TRUE;
+ if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_GETFOCUS, maGetFocusHdl, this ) )
+ // been destroyed within the handler
+ return TRUE;
+ }
+ }
+ else
+ {
+ if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ Window* pFocusWin = Application::GetFocusWindow();
+ if ( !pFocusWin || !ImplIsWindowOrChild( pFocusWin ) )
+ {
+ mbHasFocus = FALSE;
+ if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_LOSEFOCUS, maLoseFocusHdl, this ) )
+ // been destroyed within the handler
+ return TRUE;
+ }
+ }
+ }
+
+ return Window::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void Control::StateChanged( StateChangedType nStateChange )
+{
+ if( nStateChange == STATE_CHANGE_INITSHOW ||
+ nStateChange == STATE_CHANGE_VISIBLE ||
+ nStateChange == STATE_CHANGE_FORMAT ||
+ nStateChange == STATE_CHANGE_ZOOM ||
+ nStateChange == STATE_CHANGE_BORDER ||
+ nStateChange == STATE_CHANGE_CONTROLFONT
+ )
+ {
+ ImplClearLayoutData();
+ }
+ Window::StateChanged( nStateChange );
+}
+
+// -----------------------------------------------------------------------
+
+void Control::AppendLayoutData( const Control& rSubControl ) const
+{
+ if( !rSubControl.HasLayoutData() )
+ rSubControl.FillLayoutData();
+ if( !rSubControl.HasLayoutData() || !rSubControl.mpControlData->mpLayoutData->m_aDisplayText.Len() )
+ return;
+
+ long nCurrentIndex = mpControlData->mpLayoutData->m_aDisplayText.Len();
+ mpControlData->mpLayoutData->m_aDisplayText.Append( rSubControl.mpControlData->mpLayoutData->m_aDisplayText );
+ int nLines = rSubControl.mpControlData->mpLayoutData->m_aLineIndices.size();
+ int n;
+ mpControlData->mpLayoutData->m_aLineIndices.push_back( nCurrentIndex );
+ for( n = 1; n < nLines; n++ )
+ mpControlData->mpLayoutData->m_aLineIndices.push_back( rSubControl.mpControlData->mpLayoutData->m_aLineIndices[n] + nCurrentIndex );
+ int nRectangles = rSubControl.mpControlData->mpLayoutData->m_aUnicodeBoundRects.size();
+ Rectangle aRel = const_cast<Control&>(rSubControl).GetWindowExtentsRelative( const_cast<Control*>(this) );
+ for( n = 0; n < nRectangles; n++ )
+ {
+ Rectangle aRect = rSubControl.mpControlData->mpLayoutData->m_aUnicodeBoundRects[n];
+ aRect.Move( aRel.Left(), aRel.Top() );
+ mpControlData->mpLayoutData->m_aUnicodeBoundRects.push_back( aRect );
+ }
+}
+
+// -----------------------------------------------------------------
+
+BOOL Control::ImplCallEventListenersAndHandler( ULONG nEvent, const Link& rHandler, void* pCaller )
+{
+ ImplDelData aCheckDelete;
+ ImplAddDel( &aCheckDelete );
+
+ ImplCallEventListeners( nEvent );
+ if ( !aCheckDelete.IsDelete() )
+ {
+ rHandler.Call( pCaller );
+
+ if ( !aCheckDelete.IsDelete() )
+ {
+ ImplRemoveDel( &aCheckDelete );
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+// -----------------------------------------------------------------
+
+void Control::SetLayoutDataParent( const Control* pParent ) const
+{
+ if( HasLayoutData() )
+ mpControlData->mpLayoutData->m_pParent = pParent;
+}
+
+// -----------------------------------------------------------------
+
+void Control::ImplClearLayoutData() const
+{
+ delete mpControlData->mpLayoutData, mpControlData->mpLayoutData = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void Control::ImplDrawFrame( OutputDevice* pDev, Rectangle& rRect )
+{
+ // use a deco view to draw the frame
+ // However, since there happens a lot of magic there, we need to fake some (style) settings
+ // on the device
+ AllSettings aOriginalSettings( pDev->GetSettings() );
+
+ AllSettings aNewSettings( aOriginalSettings );
+ StyleSettings aStyle( aNewSettings.GetStyleSettings() );
+
+ // The *only known* clients of the Draw methods of the various VCL-controls are form controls:
+ // During print preview, and during printing, Draw is called. Thus, drawing always happens with a
+ // mono (colored) border
+ aStyle.SetOptions( aStyle.GetOptions() | STYLE_OPTION_MONO );
+ aStyle.SetMonoColor( GetSettings().GetStyleSettings().GetMonoColor() );
+
+ aNewSettings.SetStyleSettings( aStyle );
+ // #i67023# do not call data changed listeners for this fake
+ // since they may understandably invalidate on settings changed
+ pDev->OutputDevice::SetSettings( aNewSettings );
+
+ DecorationView aDecoView( pDev );
+ rRect = aDecoView.DrawFrame( rRect, FRAME_DRAW_WINDOWBORDER );
+
+ pDev->OutputDevice::SetSettings( aOriginalSettings );
+}
+
+// -----------------------------------------------------------------------
+
+void Control::DataChanged( const DataChangedEvent& rDCEvt)
+{
+ // we don't want to loose some style settings for controls created with the
+ // toolkit
+ if ( IsCreatedWithToolkit() &&
+ (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ AllSettings aSettings = GetSettings();
+ StyleSettings aStyleSettings = aSettings.GetStyleSettings();
+ ULONG nOldOptions = rDCEvt.GetOldSettings()->GetStyleSettings().GetOptions();
+ ULONG nNewOptions = aStyleSettings.GetOptions();
+
+ if ( !(nNewOptions & STYLE_OPTION_MONO) && ( nOldOptions & STYLE_OPTION_MONO ) )
+ {
+ nNewOptions |= STYLE_OPTION_MONO;
+ aStyleSettings.SetOptions( nNewOptions );
+ aStyleSettings.SetMonoColor( rDCEvt.GetOldSettings()->GetStyleSettings().GetMonoColor() );
+ aSettings.SetStyleSettings( aStyleSettings );
+ SetSettings( aSettings );
+ }
+ }
+}
+
+// -----------------------------------------------------------------
+
+ControlLayoutData::~ControlLayoutData()
+{
+ if( m_pParent )
+ m_pParent->ImplClearLayoutData();
+}
+
+// -----------------------------------------------------------------
+
+Size Control::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return Size( GetTextWidth( GetText() ) + 2 * 12,
+ GetTextHeight() + 2 * 6 );
+ case WINDOWSIZE_PREFERRED:
+ return GetOptimalSize( WINDOWSIZE_MINIMUM );
+ case WINDOWSIZE_MAXIMUM:
+ default:
+ return Size( LONG_MAX, LONG_MAX );
+ }
+}
+
+// -----------------------------------------------------------------
+
+void Control::SetReferenceDevice( OutputDevice* _referenceDevice )
+{
+ if ( mpControlData->mpReferenceDevice == _referenceDevice )
+ return;
+
+ mpControlData->mpReferenceDevice = _referenceDevice;
+ Invalidate();
+}
+
+// -----------------------------------------------------------------
+
+OutputDevice* Control::GetReferenceDevice() const
+{
+ return mpControlData->mpReferenceDevice;
+}
+
+// -----------------------------------------------------------------
+
+const Font& Control::GetCanonicalFont( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetLabelFont();
+}
+
+// -----------------------------------------------------------------
+const Color& Control::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetLabelTextColor();
+}
+
+// -----------------------------------------------------------------
+void Control::ImplInitSettings( const BOOL _bFont, const BOOL _bForeground )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ if ( _bFont )
+ {
+ Font aFont( GetCanonicalFont( rStyleSettings ) );
+ if ( IsControlFont() )
+ aFont.Merge( GetControlFont() );
+ SetZoomedPointFont( aFont );
+ }
+
+ if ( _bForeground || _bFont )
+ {
+ Color aColor;
+ if ( IsControlForeground() )
+ aColor = GetControlForeground();
+ else
+ aColor = GetCanonicalTextColor( rStyleSettings );
+ SetTextColor( aColor );
+ SetTextFillColor();
+ }
+}
+
+// -----------------------------------------------------------------
+
+void Control::DrawControlText( OutputDevice& _rTargetDevice, Rectangle& _io_rRect, const XubString& _rStr,
+ USHORT _nStyle, MetricVector* _pVector, String* _pDisplayText ) const
+{
+#ifdef FS_DEBUG
+ if ( !_pVector )
+ {
+ static MetricVector aCharRects;
+ static String sDisplayText;
+ aCharRects.clear();
+ sDisplayText = String();
+ _pVector = &aCharRects;
+ _pDisplayText = &sDisplayText;
+ }
+#endif
+
+ if ( !mpControlData->mpReferenceDevice || ( mpControlData->mpReferenceDevice == &_rTargetDevice ) )
+ {
+ _io_rRect = _rTargetDevice.GetTextRect( _io_rRect, _rStr, _nStyle );
+ _rTargetDevice.DrawText( _io_rRect, _rStr, _nStyle, _pVector, _pDisplayText );
+ }
+ else
+ {
+ ControlTextRenderer aRenderer( *this, _rTargetDevice, *mpControlData->mpReferenceDevice );
+ _io_rRect = aRenderer.DrawText( _io_rRect, _rStr, _nStyle, _pVector, _pDisplayText );
+ }
+
+#ifdef FS_DEBUG
+ _rTargetDevice.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ _rTargetDevice.SetLineColor( COL_LIGHTRED );
+ _rTargetDevice.SetFillColor();
+ for ( MetricVector::const_iterator cr = _pVector->begin();
+ cr != _pVector->end();
+ ++cr
+ )
+ {
+ _rTargetDevice.DrawRect( *cr );
+ }
+ _rTargetDevice.Pop();
+#endif
+}