diff options
Diffstat (limited to 'svtools/source/control')
38 files changed, 30732 insertions, 0 deletions
diff --git a/svtools/source/control/asynclink.cxx b/svtools/source/control/asynclink.cxx new file mode 100755 index 000000000000..d3ef0c349f08 --- /dev/null +++ b/svtools/source/control/asynclink.cxx @@ -0,0 +1,139 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#include <svtools/asynclink.hxx> +#include <vos/mutex.hxx> +#include <tools/debug.hxx> +#include <vcl/timer.hxx> +#include <vcl/svapp.hxx> + +//-------------------------------------------------------------------- +namespace svtools { + +void AsynchronLink::CreateMutex() +{ + if( !_pMutex ) _pMutex = new vos::OMutex; +} + +void AsynchronLink::Call( void* pObj, BOOL +#ifdef DBG_UTIL +bAllowDoubles +#endif +, BOOL bUseTimer ) +{ +#ifdef DBG_UTIL + if ( bUseTimer || !_bInCall ) + DBG_WARNING( "Recursives Call. Eher ueber Timer. TLX Fragen" ); +#endif + if( _aLink.IsSet() ) + { + _pArg = pObj; + DBG_ASSERT( bAllowDoubles || + ( !_nEventId && ( !_pTimer || !_pTimer->IsActive() ) ), + "Schon ein Call unterwegs" ); + if( _nEventId ) + { + if( _pMutex ) _pMutex->acquire(); + Application::RemoveUserEvent( _nEventId ); + if( _pMutex ) _pMutex->release(); + } + if( _pTimer )_pTimer->Stop(); + if( bUseTimer ) + { + if( !_pTimer ) + { + _pTimer = new Timer; + _pTimer->SetTimeout( 0 ); + _pTimer->SetTimeoutHdl( STATIC_LINK( + this, AsynchronLink, HandleCall) ); + } + _pTimer->Start(); + } + else + { + if( _pMutex ) _pMutex->acquire(); + Application::PostUserEvent( _nEventId, STATIC_LINK( this, AsynchronLink, HandleCall), 0 ); + if( _pMutex ) _pMutex->release(); + } + } +} + +AsynchronLink::~AsynchronLink() +{ + if( _nEventId ) + { + Application::RemoveUserEvent( _nEventId ); + } + delete _pTimer; + if( _pDeleted ) *_pDeleted = TRUE; + delete _pMutex; +} + +IMPL_STATIC_LINK( AsynchronLink, HandleCall, void*, EMPTYARG ) +{ + if( pThis->_pMutex ) pThis->_pMutex->acquire(); + pThis->_nEventId = 0; + if( pThis->_pMutex ) pThis->_pMutex->release(); + pThis->Call_Impl( pThis->_pArg ); + return 0; +} + +void AsynchronLink::ForcePendingCall() +{ + ClearPendingCall(); + Call_Impl( _pArg ); +} + +void AsynchronLink::ClearPendingCall() +{ + if( _pMutex ) _pMutex->acquire(); + if( _nEventId ) + { + Application::RemoveUserEvent( _nEventId ); + _nEventId = 0; + } + if( _pMutex ) _pMutex->release(); + if( _pTimer ) _pTimer->Stop(); +} + +void AsynchronLink::Call_Impl( void* pArg ) +{ + _bInCall = TRUE; + BOOL bDeleted = FALSE; + _pDeleted = &bDeleted; + _aLink.Call( pArg ); + if( !bDeleted ) + { + _bInCall = FALSE; + _pDeleted = 0; + } +} + +} diff --git a/svtools/source/control/calendar.cxx b/svtools/source/control/calendar.cxx new file mode 100755 index 000000000000..043d7023508b --- /dev/null +++ b/svtools/source/control/calendar.cxx @@ -0,0 +1,3035 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#include <vcl/svapp.hxx> +#include <tools/table.hxx> +#include <vcl/help.hxx> +#include <vcl/menu.hxx> +#include <vcl/decoview.hxx> +#include <vcl/floatwin.hxx> +#include <vcl/button.hxx> +#include <vcl/fixed.hxx> +#include <unotools/calendarwrapper.hxx> +#include <unotools/localedatawrapper.hxx> +#include <com/sun/star/i18n/Weekdays.hpp> +#include <com/sun/star/i18n/CalendarDisplayIndex.hpp> +#include <com/sun/star/i18n/CalendarFieldIndex.hpp> + +#define _SV_CALENDAR_CXX +#include <svtools/svtools.hrc> +#include <svtools/svtdata.hxx> +#include <svtools/calendar.hxx> + +// ======================================================================= + +#define DAY_OFFX 4 +#define DAY_OFFY 2 +#define MONTH_BORDERX 4 +#define MONTH_OFFY 3 +#define WEEKNUMBER_OFFX 4 +#define WEEKDAY_OFFY 3 +#define TITLE_OFFY 3 +#define TITLE_BORDERY 2 +#define SPIN_OFFX 4 +#define SPIN_OFFY TITLE_BORDERY + +#define WEEKNUMBER_HEIGHT 85 + +#define CALENDAR_HITTEST_DAY ((USHORT)0x0001) +#define CALENDAR_HITTEST_WEEK ((USHORT)0x0002) +#define CALENDAR_HITTEST_MONTHTITLE ((USHORT)0x0004) +#define CALENDAR_HITTEST_PREV ((USHORT)0x0008) +#define CALENDAR_HITTEST_NEXT ((USHORT)0x0010) +#define CALENDAR_HITTEST_OUTSIDE ((USHORT)0x1000) + +#define MENU_YEAR_COUNT 3 + +#define TABLE_DATE_SELECTED ((void*)0x00000001) + +using namespace ::com::sun::star; + +// ======================================================================= + +struct ImplDateInfo +{ + XubString maText; + Color* mpTextColor; + Color* mpFrameColor; + USHORT mnFlags; + + ImplDateInfo( const XubString& rText ) : + maText( rText ) + { mpTextColor = mpFrameColor = NULL; mnFlags = 0; } + ~ImplDateInfo() { delete mpTextColor; delete mpFrameColor; } +}; + +DECLARE_TABLE( ImplDateTable, ImplDateInfo* ) + +// ======================================================================= + +static void ImplCalendarSelectDate( Table* pTable, const Date& rDate, BOOL bSelect ) +{ + if ( bSelect ) + pTable->Insert( rDate.GetDate(), TABLE_DATE_SELECTED ); + else + pTable->Remove( rDate.GetDate() ); +} + +// ----------------------------------------------------------------------- + +static void ImplCalendarSelectDateRange( Table* pTable, + const Date& rStartDate, + const Date& rEndDate, + BOOL bSelect ) +{ + Date aStartDate = rStartDate; + Date aEndDate = rEndDate; + if ( aStartDate > aEndDate ) + { + Date aTempDate = aStartDate; + aStartDate = aEndDate; + aEndDate = aTempDate; + } + + if ( bSelect ) + { + while ( aStartDate <= aEndDate ) + { + pTable->Insert( aStartDate.GetDate(), TABLE_DATE_SELECTED ); + aStartDate++; + } + } + else + { + void* p = pTable->First(); + while ( p ) + { + Date aDate( pTable->GetCurKey() ); + if ( aDate > aEndDate ) + break; + + if ( aDate >= aStartDate ) + pTable->Remove( aDate.GetDate() ); + else + p = pTable->Next(); + } + } +} + +// ----------------------------------------------------------------------- + +static void ImplCalendarUnSelectDateRange( Table* pTable, + Table* pOldTable, + const Date& rStartDate, + const Date& rEndDate ) +{ + Date aStartDate = rStartDate; + Date aEndDate = rEndDate; + if ( aStartDate > aEndDate ) + { + Date aTempDate = aStartDate; + aStartDate = aEndDate; + aEndDate = aTempDate; + } + + void* p = pTable->First(); + while ( p ) + { + Date aDate( pTable->GetCurKey() ); + if ( aDate > aEndDate ) + break; + + if ( aDate >= aStartDate ) + pTable->Remove( aDate.GetDate() ); + else + p = pTable->Next(); + } + + p = pOldTable->First(); + while ( p ) + { + Date aDate( pOldTable->GetCurKey() ); + if ( aDate > aEndDate ) + break; + if ( aDate >= aStartDate ) + pTable->Insert( aDate.GetDate(), TABLE_DATE_SELECTED ); + + p = pOldTable->Next(); + } +} + +// ----------------------------------------------------------------------- + +inline void ImplCalendarClearSelectDate( Table* pTable ) +{ + pTable->Clear(); +} + +// ======================================================================= + +void Calendar::ImplInit( WinBits nWinStyle ) +{ + mpDateTable = NULL; + mpSelectTable = new Table; + mpOldSelectTable = NULL; + mpRestoreSelectTable = NULL; + mpStandardColor = NULL; + mpSaturdayColor = NULL; + mpSundayColor = NULL; + mnDayCount = 0; + mnWinStyle = nWinStyle; + mnFirstYear = 0; + mnLastYear = 0; + mnRequestYear = 0; + mbCalc = TRUE; + mbFormat = TRUE; + mbDrag = FALSE; + mbSelection = FALSE; + mbMultiSelection = FALSE; + mbWeekSel = FALSE; + mbUnSel = FALSE; + mbMenuDown = FALSE; + mbSpinDown = FALSE; + mbPrevIn = FALSE; + mbNextIn = FALSE; + mbDirect = FALSE; + mbInSelChange = FALSE; + mbTravelSelect = FALSE; + mbScrollDateRange = FALSE; + mbSelLeft = FALSE; + mbAllSel = FALSE; + mbDropPos = FALSE; + + ::rtl::OUString aGregorian( RTL_CONSTASCII_USTRINGPARAM( "gregorian")); + maCalendarWrapper.loadCalendar( aGregorian, + Application::GetAppLocaleDataWrapper().getLocale()); + if (maCalendarWrapper.getUniqueID() != aGregorian) + { +#ifdef DBG_UTIL + ByteString aMsg( "Calendar::ImplInit: No ``gregorian'' calendar available for locale ``"); + lang::Locale aLoc( Application::GetAppLocaleDataWrapper().getLocale()); + aMsg += ByteString( String( aLoc.Language), RTL_TEXTENCODING_UTF8); + aMsg += '-'; + aMsg += ByteString( String( aLoc.Country), RTL_TEXTENCODING_UTF8); + aMsg += "'' and other calendars aren't supported. Using en-US fallback."; + DBG_ERRORFILE( aMsg.GetBuffer()); +#endif + /* If we ever wanted to support other calendars than Gregorian a lot of + * rewrite would be necessary to internally replace use of class Date + * with proper class CalendarWrapper methods, get rid of fixed 12 + * months, fixed 7 days, ... */ + maCalendarWrapper.loadCalendar( aGregorian, lang::Locale( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "en")), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "US")), + ::rtl::OUString())); + } + + SetFirstDate( maCurDate ); + ImplCalendarSelectDate( mpSelectTable, maCurDate, TRUE ); + + // Sonstige Strings erzeugen + maDayText = XubString( SvtResId( STR_SVT_CALENDAR_DAY ) ); + maWeekText = XubString( SvtResId( STR_SVT_CALENDAR_WEEK ) ); + + // Tagestexte anlegen + for ( USHORT i = 0; i < 31; i++ ) + mpDayText[i] = new UniString( UniString::CreateFromInt32( i+1 ) ); + + maDragScrollTimer.SetTimeoutHdl( STATIC_LINK( this, Calendar, ScrollHdl ) ); + maDragScrollTimer.SetTimeout( GetSettings().GetMouseSettings().GetScrollRepeat() ); + mnDragScrollHitTest = 0; + + ImplInitSettings(); +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplInitSettings() +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + maSelColor = rStyleSettings.GetHighlightTextColor(); + SetPointFont( rStyleSettings.GetToolFont() ); + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetBackground( Wallpaper( rStyleSettings.GetFieldColor() ) ); +} + +// ----------------------------------------------------------------------- + +Calendar::Calendar( Window* pParent, WinBits nWinStyle ) : + Control( pParent, nWinStyle & (WB_TABSTOP | WB_GROUP | WB_BORDER | WB_3DLOOK | WB_RANGESELECT | WB_MULTISELECT) ), + maCalendarWrapper( Application::GetAppLocaleDataWrapper().getServiceFactory() ), + maOldFormatFirstDate( 0, 0, 1900 ), + maOldFormatLastDate( 0, 0, 1900 ), + maFirstDate( 0, 0, 1900 ), + maOldFirstDate( 0, 0, 1900 ), + maOldCurDate( 0, 0, 1900 ), + maAnchorDate( maCurDate ), + maDropDate( 0, 0, 1900 ) +{ + ImplInit( nWinStyle ); +} + +// ----------------------------------------------------------------------- + +Calendar::Calendar( Window* pParent, const ResId& rResId ) : + Control( pParent, rResId ), + maCalendarWrapper( Application::GetAppLocaleDataWrapper().getServiceFactory() ), + maOldFormatFirstDate( 0, 0, 1900 ), + maOldFormatLastDate( 0, 0, 1900 ), + maFirstDate( 0, 0, 1900 ), + maOldFirstDate( 0, 0, 1900 ), + maOldCurDate( 0, 0, 1900 ), + maAnchorDate( maCurDate ), + maDropDate( 0, 0, 1900 ) +{ + ImplInit( rResId.GetWinBits() ); +} + +// ----------------------------------------------------------------------- + +Calendar::~Calendar() +{ + delete mpStandardColor; + delete mpSaturdayColor; + delete mpSundayColor; + + if ( mpDateTable ) + { + ImplDateInfo* pDateInfo = mpDateTable->First(); + while ( pDateInfo ) + { + delete pDateInfo; + pDateInfo = mpDateTable->Next(); + } + + delete mpDateTable; + } + + delete mpSelectTable; + if ( mpOldSelectTable ) + delete mpOldSelectTable; + if ( mpRestoreSelectTable ) + delete mpRestoreSelectTable; + + for ( USHORT i = 0; i < 31; i++ ) + delete mpDayText[i]; +} + +// ----------------------------------------------------------------------- + +void Calendar::SetMinimumNumberOfDaysInWeek( sal_Int16 nDays ) +{ + ImplUpdate( TRUE ); + maCalendarWrapper.setMinimumNumberOfDaysForFirstWeek( nDays); +} + +// ----------------------------------------------------------------------- + +void Calendar::SetWeekStart( sal_Int16 nDay ) +{ + ImplUpdate( TRUE ); + switch (nDay) + { + case i18n::Weekdays::SUNDAY : + case i18n::Weekdays::MONDAY : + case i18n::Weekdays::TUESDAY : + case i18n::Weekdays::WEDNESDAY : + case i18n::Weekdays::THURSDAY : + case i18n::Weekdays::FRIDAY : + case i18n::Weekdays::SATURDAY : + ; // nothing + default: + DBG_ERRORFILE("Calendar::SetWeekStart: unknown value for setFirstDayOfWeek() of a Gregorian calendar"); + nDay = i18n::Weekdays::SUNDAY; + } + maCalendarWrapper.setFirstDayOfWeek( nDay); +} + +// ----------------------------------------------------------------------- + +DayOfWeek Calendar::ImplGetWeekStart() const +{ + // Map i18n::Weekdays to Date DayOfWeek + DayOfWeek eDay; + sal_Int16 nDay = maCalendarWrapper.getFirstDayOfWeek(); + switch (nDay) + { + case i18n::Weekdays::SUNDAY : + eDay = SUNDAY; + break; + case i18n::Weekdays::MONDAY : + eDay = MONDAY; + break; + case i18n::Weekdays::TUESDAY : + eDay = TUESDAY; + break; + case i18n::Weekdays::WEDNESDAY : + eDay = WEDNESDAY; + break; + case i18n::Weekdays::THURSDAY : + eDay = THURSDAY; + break; + case i18n::Weekdays::FRIDAY : + eDay = FRIDAY; + break; + case i18n::Weekdays::SATURDAY : + eDay = SATURDAY; + break; + default: + DBG_ERRORFILE("Calendar::ImplGetWeekStart: broken i18n Gregorian calendar (getFirstDayOfWeek())"); + eDay = SUNDAY; + } + return eDay; +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplGetWeekFont( Font& rFont ) const +{ + // Wochennummer geben wir in WEEKNUMBER_HEIGHT%-Fonthoehe aus + Size aFontSize = rFont.GetSize(); + aFontSize.Height() *= WEEKNUMBER_HEIGHT; + aFontSize.Height() /= 100; + rFont.SetSize( aFontSize ); + rFont.SetWeight( WEIGHT_NORMAL ); +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplFormat() +{ + if ( !mbFormat ) + return; + + if ( mbCalc ) + { + Size aOutSize = GetOutputSizePixel(); + + if ( (aOutSize.Width() <= 1) || (aOutSize.Height() <= 1) ) + return; + + XubString a99Text( XubString( RTL_CONSTASCII_USTRINGPARAM( "99" ) ) ); + + Font aOldFont = GetFont(); + + // Wochenanzeige beruecksichtigen + if ( mnWinStyle & WB_WEEKNUMBER ) + { + Font aTempFont = aOldFont; + ImplGetWeekFont( aTempFont ); + SetFont( aTempFont ); + mnWeekWidth = GetTextWidth( a99Text )+WEEKNUMBER_OFFX; + SetFont( aOldFont ); + } + else + mnWeekWidth = 0; + + if ( mnWinStyle & WB_BOLDTEXT ) + { + Font aFont = aOldFont; + if ( aFont.GetWeight() < WEIGHT_BOLD ) + aFont.SetWeight( WEIGHT_BOLD ); + else + aFont.SetWeight( WEIGHT_NORMAL ); + SetFont( aFont ); + } + + long n99TextWidth = GetTextWidth( a99Text ); + long nTextHeight = GetTextHeight(); + + // Breiten und X-Positionen berechnen + mnDayWidth = n99TextWidth+DAY_OFFX; + mnMonthWidth = mnDayWidth*7; + mnMonthWidth += mnWeekWidth; + mnMonthWidth += MONTH_BORDERX*2; + mnMonthPerLine = aOutSize.Width() / mnMonthWidth; + if ( !mnMonthPerLine ) + mnMonthPerLine = 1; + long nOver = ((aOutSize.Width()-(mnMonthPerLine*mnMonthWidth)) / mnMonthPerLine); + mnMonthWidth += nOver; + mnDaysOffX = MONTH_BORDERX; + mnDaysOffX += nOver/2; + mnDaysOffX += mnWeekWidth; + + // Hoehen und Y-Positionen berechnen + mnDayHeight = nTextHeight + DAY_OFFY; + mnWeekDayOffY = nTextHeight + TITLE_OFFY + (TITLE_BORDERY*2); + mnDaysOffY = mnWeekDayOffY + nTextHeight + WEEKDAY_OFFY; + mnMonthHeight = (mnDayHeight*6) + mnDaysOffY; + mnMonthHeight += MONTH_OFFY; + mnLines = aOutSize.Height() / mnMonthHeight; + if ( !mnLines ) + mnLines = 1; + mnMonthHeight += (aOutSize.Height()-(mnLines*mnMonthHeight)) / mnLines; + + // Spinfelder berechnen + long nSpinSize = nTextHeight+TITLE_BORDERY-SPIN_OFFY; + maPrevRect.Left() = SPIN_OFFX; + maPrevRect.Top() = SPIN_OFFY; + maPrevRect.Right() = maPrevRect.Left()+nSpinSize; + maPrevRect.Bottom() = maPrevRect.Top()+nSpinSize; + maNextRect.Left() = aOutSize.Width()-SPIN_OFFX-nSpinSize-1; + maNextRect.Top() = SPIN_OFFY; + maNextRect.Right() = maNextRect.Left()+nSpinSize; + maNextRect.Bottom() = maNextRect.Top()+nSpinSize; + + if ( mnWinStyle & WB_BOLDTEXT ) + SetFont( aOldFont ); + + // Calculate DayOfWeekText (gets displayed in a narrow font) + maDayOfWeekText.Erase(); + long nStartOffX = 0; + sal_Int16 nDay = maCalendarWrapper.getFirstDayOfWeek(); + for ( sal_Int16 nDayOfWeek = 0; nDayOfWeek < 7; nDayOfWeek++ ) + { + // Use first character of full name, since the abbreviated name may + // be roman digits or similar in some locales. Proper + // implementation would need narrow one letter month names defined + // in locale data. + String aDayOfWeek( maCalendarWrapper.getDisplayName( + i18n::CalendarDisplayIndex::DAY, nDay, 1).GetChar(0)); + long nOffX = (mnDayWidth-GetTextWidth( aDayOfWeek ))/2; + if ( mnWinStyle & WB_BOLDTEXT ) + nOffX++; + if ( !nDayOfWeek ) + nStartOffX = nOffX; + else + nOffX -= nStartOffX; + nOffX += nDayOfWeek * mnDayWidth; + mnDayOfWeekAry[nDayOfWeek] = nOffX; + maDayOfWeekText += aDayOfWeek; + nDay++; + nDay %= 7; + } + + mbCalc = FALSE; + } + + // Anzahl Tage berechnen + + DayOfWeek eStartDay = ImplGetWeekStart(); + + USHORT nWeekDay; + Date aTempDate = GetFirstMonth(); + maFirstDate = aTempDate; + nWeekDay = (USHORT)aTempDate.GetDayOfWeek(); + nWeekDay = (nWeekDay+(7-(USHORT)eStartDay)) % 7; + maFirstDate -= (ULONG)nWeekDay; + mnDayCount = nWeekDay; + USHORT nDaysInMonth; + USHORT nMonthCount = (USHORT)(mnMonthPerLine*mnLines); + for ( USHORT i = 0; i < nMonthCount; i++ ) + { + nDaysInMonth = aTempDate.GetDaysInMonth(); + mnDayCount += nDaysInMonth; + aTempDate += nDaysInMonth; + } + Date aTempDate2 = aTempDate; + aTempDate2--; + nDaysInMonth = aTempDate2.GetDaysInMonth(); + aTempDate2 -= nDaysInMonth-1; + nWeekDay = (USHORT)aTempDate2.GetDayOfWeek(); + nWeekDay = (nWeekDay+(7-(USHORT)eStartDay)) % 7; + mnDayCount += 42-nDaysInMonth-nWeekDay; + + // Farben festlegen + maOtherColor = Color( COL_LIGHTGRAY ); + if ( maOtherColor.IsRGBEqual( GetBackground().GetColor() ) ) + maOtherColor.SetColor( COL_GRAY ); + + Date aLastDate = GetLastDate(); + if ( (maOldFormatLastDate != aLastDate) || + (maOldFormatFirstDate != maFirstDate) ) + { + maOldFormatFirstDate = maFirstDate; + maOldFormatLastDate = aLastDate; + DateRangeChanged(); + } + + // DateInfo besorgen + USHORT nNewFirstYear = maFirstDate.GetYear(); + USHORT nNewLastYear = GetLastDate().GetYear(); + if ( mnFirstYear ) + { + if ( nNewFirstYear < mnFirstYear ) + { + for ( mnRequestYear = nNewFirstYear; mnRequestYear < mnFirstYear; mnRequestYear++ ) + RequestDateInfo(); + mnFirstYear = nNewFirstYear; + } + if ( nNewLastYear > mnLastYear ) + { + for ( mnRequestYear = mnLastYear; mnRequestYear < nNewLastYear; mnRequestYear++ ) + RequestDateInfo(); + mnLastYear = nNewLastYear; + } + } + else + { + for ( mnRequestYear = nNewFirstYear; mnRequestYear < nNewLastYear; mnRequestYear++ ) + RequestDateInfo(); + mnFirstYear = nNewFirstYear; + mnLastYear = nNewLastYear; + } + mnRequestYear = 0; + + mbFormat = FALSE; +} + +// ----------------------------------------------------------------------- + +USHORT Calendar::ImplHitTest( const Point& rPos, Date& rDate ) const +{ + if ( mbFormat ) + return 0; + + if ( maPrevRect.IsInside( rPos ) ) + return CALENDAR_HITTEST_PREV; + else if ( maNextRect.IsInside( rPos ) ) + return CALENDAR_HITTEST_NEXT; + + long nX; + long nY; + long nOffX; + long nYMonth; + USHORT nDay; + DayOfWeek eStartDay = ImplGetWeekStart(); + + rDate = GetFirstMonth(); + nY = 0; + for ( long i = 0; i < mnLines; i++ ) + { + if ( rPos.Y() < nY ) + return 0; + + nX = 0; + nYMonth = nY+mnMonthHeight; + for ( long j = 0; j < mnMonthPerLine; j++ ) + { + if ( (rPos.X() < nX) && (rPos.Y() < nYMonth) ) + return 0; + + USHORT nDaysInMonth = rDate.GetDaysInMonth(); + + // Entsprechender Monat gefunden + if ( (rPos.X() > nX) && (rPos.Y() < nYMonth) && + (rPos.X() < nX+mnMonthWidth) ) + { + if ( rPos.Y() < (nY+(TITLE_BORDERY*2)+mnDayHeight)) + return CALENDAR_HITTEST_MONTHTITLE; + else + { + long nDayX = nX+mnDaysOffX; + long nDayY = nY+mnDaysOffY; + if ( rPos.Y() < nDayY ) + return 0; + USHORT nDayIndex = (USHORT)rDate.GetDayOfWeek(); + nDayIndex = (nDayIndex+(7-(USHORT)eStartDay)) % 7; + if ( (i == 0) && (j == 0) ) + { + Date aTempDate = rDate; + aTempDate -= nDayIndex; + for ( nDay = 0; nDay < nDayIndex; nDay++ ) + { + nOffX = nDayX + (nDay*mnDayWidth); + if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) && + (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) ) + { + rDate = aTempDate; + rDate += nDay; + return CALENDAR_HITTEST_DAY; + } + } + } + for ( nDay = 1; nDay <= nDaysInMonth; nDay++ ) + { + if ( rPos.Y() < nDayY ) + { + rDate += nDayIndex; + return 0; + } + nOffX = nDayX + (nDayIndex*mnDayWidth); + if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) && + (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) ) + { + rDate += nDay-1; + return CALENDAR_HITTEST_DAY; + } + if ( nDayIndex == 6 ) + { + nDayIndex = 0; + nDayY += mnDayHeight; + } + else + nDayIndex++; + } + if ( (i == mnLines-1) && (j == mnMonthPerLine-1) ) + { + USHORT nWeekDay = (USHORT)rDate.GetDayOfWeek(); + nWeekDay = (nWeekDay+(7-(USHORT)eStartDay)) % 7; + USHORT nDayCount = 42-nDaysInMonth-nWeekDay; + Date aTempDate = rDate; + aTempDate += nDaysInMonth; + for ( nDay = 1; nDay <= nDayCount; nDay++ ) + { + if ( rPos.Y() < nDayY ) + { + rDate += nDayIndex; + return 0; + } + nOffX = nDayX + (nDayIndex*mnDayWidth); + if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) && + (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) ) + { + rDate = aTempDate; + rDate += nDay-1; + return CALENDAR_HITTEST_DAY; + } + if ( nDayIndex == 6 ) + { + nDayIndex = 0; + nDayY += mnDayHeight; + } + else + nDayIndex++; + } + } + } + } + + rDate += nDaysInMonth; + nX += mnMonthWidth; + } + + nY += mnMonthHeight; + } + + return 0; +} + +// ----------------------------------------------------------------------- + +static void ImplDrawSpinArrow( OutputDevice* pDev, const Rectangle& rRect, + BOOL bPrev ) +{ + long i; + long n; + long nLines; + long nHeight = rRect.GetHeight(); + long nWidth = rRect.GetWidth(); + if ( nWidth < nHeight ) + n = nWidth; + else + n = nHeight; + if ( !(n & 0x01) ) + n--; + nLines = n/2; + + Rectangle aRect( Point( rRect.Left()+(nWidth/2)-(nLines/2), + rRect.Top()+(nHeight/2) ), + Size( 1, 1 ) ); + if ( !bPrev ) + { + aRect.Left() += nLines; + aRect.Right() += nLines; + } + + pDev->DrawRect( aRect ); + for ( i = 0; i < nLines; i++ ) + { + if ( bPrev ) + { + aRect.Left()++; + aRect.Right()++; + } + else + { + aRect.Left()--; + aRect.Right()--; + } + aRect.Top()--; + aRect.Bottom()++; + pDev->DrawRect( aRect ); + } +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplDrawSpin( BOOL bDrawPrev, BOOL bDrawNext ) +{ + if ( !bDrawPrev && !bDrawNext ) + return; + + SetLineColor(); + SetFillColor( GetSettings().GetStyleSettings().GetButtonTextColor() ); + if ( bDrawPrev ) + { + Rectangle aOutRect = maPrevRect; + aOutRect.Left() += 3; + aOutRect.Top() += 3; + aOutRect.Right() -= 3; + aOutRect.Bottom() -= 3; + ImplDrawSpinArrow( this, aOutRect, TRUE ); + } + if ( bDrawNext ) + { + Rectangle aOutRect = maNextRect; + aOutRect.Left() += 3; + aOutRect.Top() += 3; + aOutRect.Right() -= 3; + aOutRect.Bottom() -= 3; + ImplDrawSpinArrow( this, aOutRect, FALSE ); + } +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplDrawDate( long nX, long nY, + USHORT nDay, USHORT nMonth, USHORT nYear, + DayOfWeek eDayOfWeek, + BOOL bBack, BOOL bOther, ULONG nToday ) +{ + ImplDateInfo* pDateInfo; + Color* pTextColor = NULL; + const String& rDay = *(mpDayText[nDay-1]); + Rectangle aDateRect( nX, nY, nX+mnDayWidth-1, nY+mnDayHeight-1 ); + + BOOL bSel = FALSE; + BOOL bFocus = FALSE; + // Aktueller Tag + if ( (nDay == maCurDate.GetDay()) && + (nMonth == maCurDate.GetMonth()) && + (nYear == maCurDate.GetYear()) ) + bFocus = TRUE; + if ( mpSelectTable ) + { + if ( mpSelectTable->IsKeyValid( Date( nDay, nMonth, nYear ).GetDate() ) ) + bSel = TRUE; + } + + // Dateinfo ermitteln + if ( mpDateTable ) + { + pDateInfo = mpDateTable->Get( Date( nDay, nMonth, nYear ).GetDate() ); + if ( !pDateInfo ) + pDateInfo = mpDateTable->Get( Date( nDay, nMonth, 0 ).GetDate() ); + } + else + pDateInfo = NULL; + + // Textfarbe ermitteln + if ( bSel ) + pTextColor = &maSelColor; + else if ( bOther ) + pTextColor = &maOtherColor; + else + { + if ( pDateInfo && pDateInfo->mpTextColor ) + pTextColor = pDateInfo->mpTextColor; + else + { + if ( eDayOfWeek == SATURDAY ) + pTextColor = mpSaturdayColor; + else if ( eDayOfWeek == SUNDAY ) + pTextColor = mpSundayColor; + if ( !pTextColor ) + pTextColor = mpStandardColor; + } + } + + if ( bFocus ) + HideFocus(); + + // Font ermitteln + Font aOldFont = GetFont(); + BOOL bBoldFont = FALSE; + if ( (mnWinStyle & WB_BOLDTEXT) && + pDateInfo && (pDateInfo->mnFlags & DIB_BOLD) ) + { + bBoldFont = TRUE; + Font aFont = aOldFont; + if ( aFont.GetWeight() < WEIGHT_BOLD ) + aFont.SetWeight( WEIGHT_BOLD ); + else + aFont.SetWeight( WEIGHT_NORMAL ); + SetFont( aFont ); + } + + // Hintergrund ausgeben + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + if ( bSel || bBack ) + { + if ( bSel ) + { + SetLineColor(); + SetFillColor( rStyleSettings.GetHighlightColor() ); + DrawRect( aDateRect ); + } + else + Erase( aDateRect ); + } + + // Text ausgeben + long nTextX = nX+(mnDayWidth-GetTextWidth( rDay ))-(DAY_OFFX/2); + long nTextY = nY+(mnDayHeight-GetTextHeight())/2; + if ( pTextColor ) + { + Color aOldColor = GetTextColor(); + SetTextColor( *pTextColor ); + DrawText( Point( nTextX, nTextY ), rDay ); + SetTextColor( aOldColor ); + } + else + DrawText( Point( nTextX, nTextY ), rDay ); + + // Heute + Date aTodayDate( maCurDate ); + if ( nToday ) + aTodayDate.SetDate( nToday ); + else + aTodayDate = Date(); + if ( (nDay == aTodayDate.GetDay()) && + (nMonth == aTodayDate.GetMonth()) && + (nYear == aTodayDate.GetYear()) ) + { + SetLineColor( rStyleSettings.GetWindowTextColor() ); + SetFillColor(); + DrawRect( aDateRect ); + } + + // Evt. DateInfo ausgeben + if ( (mnWinStyle & WB_FRAMEINFO) && pDateInfo && pDateInfo->mpFrameColor ) + { + SetLineColor( *(pDateInfo->mpFrameColor) ); + SetFillColor(); + Rectangle aFrameRect( aDateRect ); + aFrameRect.Left()++; + aFrameRect.Top()++; + long nFrameWidth = aFrameRect.GetWidth(); + long nFrameHeight = aFrameRect.GetHeight(); + long nFrameOff; + if ( nFrameWidth < nFrameHeight ) + { + nFrameOff = nFrameHeight-nFrameWidth; + aFrameRect.Top() += nFrameOff/2; + nFrameOff %= 2; + aFrameRect.Bottom() -= nFrameOff; + } + else if ( nFrameWidth > nFrameHeight ) + { + nFrameOff = nFrameWidth-nFrameHeight; + aFrameRect.Left() += nFrameOff/2; + nFrameOff %= 2; + aFrameRect.Right() -= nFrameOff; + } + DrawEllipse( aFrameRect ); + } + + // Evt. noch FocusRect + if ( bFocus && HasFocus() ) + ShowFocus( aDateRect ); + + if( mbDropPos && maDropDate == Date( nDay, nMonth, nYear ) ) + ImplInvertDropPos(); + + if ( bBoldFont ) + SetFont( aOldFont ); +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplDraw( BOOL bPaint ) +{ + ImplFormat(); + + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Size aOutSize = GetOutputSizePixel(); + long i; + long j; + long nX; + long nY; + long nDeltaX; + long nDeltaY; + long nDayX; + long nDayY; + ULONG nToday = Date().GetDate(); + USHORT nDay; + USHORT nMonth; + USHORT nYear; + Date aDate = GetFirstMonth(); + DayOfWeek eStartDay = ImplGetWeekStart(); + + HideFocus(); + + nY = 0; + for ( i = 0; i < mnLines; i++ ) + { + // Titleleiste ausgeben + SetLineColor(); + SetFillColor( rStyleSettings.GetFaceColor() ); + Rectangle aTitleRect( 0, nY, aOutSize.Width()-1, nY+mnDayHeight-DAY_OFFY+TITLE_BORDERY*2 ); + if ( !bPaint ) + { + Rectangle aTempRect( 1, aTitleRect.Top()+TITLE_BORDERY, + aOutSize.Width()-2, + aTitleRect.Bottom()-TITLE_BORDERY ); + if ( !i ) + { + aTempRect.Left() = maPrevRect.Right()+1; + aTempRect.Right() = maNextRect.Left()-1; + } + DrawRect( aTempRect ); + } + else + { + DrawRect( aTitleRect ); + Point aTopLeft1( aTitleRect.Left(), aTitleRect.Top() ); + Point aTopLeft2( aTitleRect.Left(), aTitleRect.Top()+1 ); + Point aBottomRight1( aTitleRect.Right(), aTitleRect.Bottom() ); + Point aBottomRight2( aTitleRect.Right(), aTitleRect.Bottom()-1 ); + SetLineColor( rStyleSettings.GetDarkShadowColor() ); + DrawLine( aTopLeft1, Point( aBottomRight1.X(), aTopLeft1.Y() ) ); + SetLineColor( rStyleSettings.GetLightColor() ); + DrawLine( aTopLeft2, Point( aBottomRight2.X(), aTopLeft2.Y() ) ); + DrawLine( aTopLeft2, Point( aTopLeft2.X(), aBottomRight2.Y() ) ); + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( Point( aTopLeft2.X(), aBottomRight2.Y() ), aBottomRight2 ); + DrawLine( Point( aBottomRight2.X(), aTopLeft2.Y() ), aBottomRight2 ); + SetLineColor( rStyleSettings.GetDarkShadowColor() ); + DrawLine( Point( aTopLeft1.X(), aBottomRight1.Y() ), aBottomRight1 ); + } + Point aSepPos1( 0, aTitleRect.Top()+TITLE_BORDERY ); + Point aSepPos2( 0, aTitleRect.Bottom()-TITLE_BORDERY ); + for ( j = 0; j < mnMonthPerLine-1; j++ ) + { + aSepPos1.X() += mnMonthWidth-1; + aSepPos2.X() = aSepPos1.X(); + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( aSepPos1, aSepPos2 ); + aSepPos1.X()++; + aSepPos2.X() = aSepPos1.X(); + SetLineColor( rStyleSettings.GetLightColor() ); + DrawLine( aSepPos1, aSepPos2 ); + } + + nX = 0; + for ( j = 0; j < mnMonthPerLine; j++ ) + { + nMonth = aDate.GetMonth(); + nYear = aDate.GetYear(); + + // Monat in der Titleleiste ausgeben + nDeltaX = nX; + nDeltaY = nY+TITLE_BORDERY; + String aMonthText( maCalendarWrapper.getDisplayName( + i18n::CalendarDisplayIndex::MONTH, nMonth-1, 1)); + aMonthText += ' '; + aMonthText += String::CreateFromInt64( nYear ); + long nMonthTextWidth = GetTextWidth( aMonthText ); + long nMonthOffX1 = 0; + long nMonthOffX2 = 0; + if ( i == 0 ) + { + if ( j == 0 ) + nMonthOffX1 = maPrevRect.Right()+1; + if ( j == mnMonthPerLine-1 ) + nMonthOffX2 = aOutSize.Width()-maNextRect.Left()+1; + } + long nMaxMonthWidth = mnMonthWidth-nMonthOffX1-nMonthOffX2-4; + if ( nMonthTextWidth > nMaxMonthWidth ) + { + // Abbreviated month name. + aMonthText = maCalendarWrapper.getDisplayName( + i18n::CalendarDisplayIndex::MONTH, nMonth-1, 0); + aMonthText += ' '; + aMonthText += String::CreateFromInt64( nYear ); + nMonthTextWidth = GetTextWidth( aMonthText ); + } + long nTempOff = (mnMonthWidth-nMonthTextWidth+1)/2; + if ( nTempOff < nMonthOffX1 ) + nDeltaX += nMonthOffX1+1; + else + { + if ( nTempOff+nMonthTextWidth > mnMonthWidth-nMonthOffX2 ) + nDeltaX += mnMonthWidth-nMonthOffX2-nMonthTextWidth; + else + nDeltaX += nTempOff; + } + SetTextColor( rStyleSettings.GetButtonTextColor() ); + DrawText( Point( nDeltaX, nDeltaY ), aMonthText ); + SetTextColor( rStyleSettings.GetWindowTextColor() ); + + // Weekleiste ausgeben + if ( bPaint ) + { + nDayX = nX+mnDaysOffX; + nDayY = nY+mnWeekDayOffY; + nDeltaY = nDayY + mnDayHeight; + SetLineColor( rStyleSettings.GetWindowTextColor() ); + Point aStartPos( nDayX, nDeltaY ); + if ( mnWinStyle & WB_WEEKNUMBER ) + aStartPos.X() -= WEEKNUMBER_OFFX-2; + DrawLine( aStartPos, Point( nDayX+(7*mnDayWidth), nDeltaY ) ); + DrawTextArray( Point( nDayX+mnDayOfWeekAry[0], nDayY ), maDayOfWeekText, &(mnDayOfWeekAry[1]) ); + } + + // Week-Numbers ausgeben + if ( mnWinStyle & WB_WEEKNUMBER ) + { + nDayX = nX+mnDaysOffX; + nDayY = nY+mnWeekDayOffY; + nDeltaY = nDayY + mnDayHeight; + long nMonthHeight = mnDayHeight*6; + if ( bPaint ) + DrawLine( Point( nDayX-WEEKNUMBER_OFFX+2, nDeltaY ), Point( nDayX-WEEKNUMBER_OFFX+2, nDeltaY+nMonthHeight ) ); + else + Erase( Rectangle( nDayX-mnWeekWidth-WEEKNUMBER_OFFX, nDeltaY, nDayX-WEEKNUMBER_OFFX-1, nDeltaY+nMonthHeight ) ); + + Font aOldFont = GetFont(); + Font aTempFont = aOldFont; + ImplGetWeekFont( aTempFont ); + SetFont( aTempFont ); + nDayX -= mnWeekWidth; + nDayY = nY+mnDaysOffY; + maCalendarWrapper.setGregorianDateTime( aDate); + for ( USHORT nWeekCount = 0; nWeekCount < 6; nWeekCount++ ) + { + sal_Int16 nWeek = maCalendarWrapper.getValue( i18n::CalendarFieldIndex::WEEK_OF_YEAR); + String aWeekText( String::CreateFromInt32( nWeek)); + long nOffX = (mnWeekWidth-WEEKNUMBER_OFFX)-GetTextWidth( aWeekText ); + long nOffY = (mnDayHeight-GetTextHeight())/2; + DrawText( Point( nDayX+nOffX, nDayY+nOffY ), aWeekText ); + nDayY += mnDayHeight; + maCalendarWrapper.addValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, 7); + } + SetFont( aOldFont ); + } + + // Tage ausgeben + USHORT nDaysInMonth = aDate.GetDaysInMonth(); + nDayX = nX+mnDaysOffX; + nDayY = nY+mnDaysOffY; + if ( !bPaint ) + { + Rectangle aClearRect( nDayX, nDayY, + nDayX+(7*mnDayWidth)-1, nDayY+(6*mnDayHeight)-1 ); + Erase( aClearRect ); + } + USHORT nDayIndex = (USHORT)aDate.GetDayOfWeek(); + nDayIndex = (nDayIndex+(7-(USHORT)eStartDay)) % 7; + if ( (i == 0) && (j == 0) ) + { + Date aTempDate = aDate; + aTempDate -= nDayIndex; + for ( nDay = 0; nDay < nDayIndex; nDay++ ) + { + nDeltaX = nDayX + (nDay*mnDayWidth); + ImplDrawDate( nDeltaX, nDayY, nDay+aTempDate.GetDay(), + aTempDate.GetMonth(), aTempDate.GetYear(), + (DayOfWeek)((nDay+(USHORT)eStartDay)%7), FALSE, TRUE, nToday ); + } + } + for ( nDay = 1; nDay <= nDaysInMonth; nDay++ ) + { + nDeltaX = nDayX + (nDayIndex*mnDayWidth); + ImplDrawDate( nDeltaX, nDayY, nDay, nMonth, nYear, + (DayOfWeek)((nDayIndex+(USHORT)eStartDay)%7), + FALSE, FALSE, nToday ); + if ( nDayIndex == 6 ) + { + nDayIndex = 0; + nDayY += mnDayHeight; + } + else + nDayIndex++; + } + if ( (i == mnLines-1) && (j == mnMonthPerLine-1) ) + { + USHORT nWeekDay = (USHORT)aDate.GetDayOfWeek(); + nWeekDay = (nWeekDay+(7-(USHORT)eStartDay)) % 7; + USHORT nDayCount = 42-nDaysInMonth-nWeekDay; + Date aTempDate = aDate; + aTempDate += nDaysInMonth; + for ( nDay = 1; nDay <= nDayCount; nDay++ ) + { + nDeltaX = nDayX + (nDayIndex*mnDayWidth); + ImplDrawDate( nDeltaX, nDayY, nDay, + aTempDate.GetMonth(), aTempDate.GetYear(), + (DayOfWeek)((nDayIndex+(USHORT)eStartDay)%7), + FALSE, TRUE, nToday ); + if ( nDayIndex == 6 ) + { + nDayIndex = 0; + nDayY += mnDayHeight; + } + else + nDayIndex++; + } + } + + aDate += nDaysInMonth; + nX += mnMonthWidth; + } + + nY += mnMonthHeight; + } + + // Spin-Buttons zeichnen + if ( bPaint ) + ImplDrawSpin(); +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplUpdateDate( const Date& rDate ) +{ + if ( IsReallyVisible() && IsUpdateMode() ) + { + Rectangle aDateRect( GetDateRect( rDate ) ); + if ( !aDateRect.IsEmpty() ) + { + BOOL bOther = (rDate < GetFirstMonth()) || (rDate > GetLastMonth()); + ImplDrawDate( aDateRect.Left(), aDateRect.Top(), + rDate.GetDay(), rDate.GetMonth(), rDate.GetYear(), + rDate.GetDayOfWeek(), TRUE, bOther ); + } + } +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplUpdateSelection( Table* pOld ) +{ + Table* pNew = mpSelectTable; + void* p; + ULONG nKey; + + p = pOld->First(); + while ( p ) + { + nKey = pOld->GetCurKey(); + if ( !pNew->Get( nKey ) ) + { + Date aTempDate( nKey ); + ImplUpdateDate( aTempDate ); + } + + p = pOld->Next(); + } + + p = pNew->First(); + while ( p ) + { + nKey = pNew->GetCurKey(); + if ( !pOld->Get( nKey ) ) + { + Date aTempDate( nKey ); + ImplUpdateDate( aTempDate ); + } + + p = pNew->Next(); + } +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplMouseSelect( const Date& rDate, USHORT nHitTest, + BOOL bMove, BOOL bExpand, BOOL bExtended ) +{ + Table* pOldSel = new Table( *mpSelectTable ); + Date aOldDate = maCurDate; + Date aTempDate = rDate; + + if ( !(nHitTest & CALENDAR_HITTEST_DAY) ) + aTempDate--; + + if ( mbMultiSelection ) + { + maCurDate = aTempDate; + mbSelLeft = aTempDate < maAnchorDate; + + if ( bMove ) + { + if ( mbSelLeft ) + { + ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, Date( 1, 1, 0 ), aTempDate ); + ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, maAnchorDate, Date( 31, 12, 9999 ) ); + } + else + { + ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, Date( 1, 1, 0 ), maAnchorDate ); + ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, aTempDate, Date( 31, 12, 9999 ) ); + } + ImplCalendarSelectDateRange( mpSelectTable, aTempDate, maAnchorDate, !mbUnSel ); + } + else + { + if ( bExpand ) + { + if ( !bExtended ) + { + if ( mbSelLeft ) + { + ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), aTempDate, FALSE ); + ImplCalendarSelectDateRange( mpSelectTable, maAnchorDate, Date( 31, 12, 9999 ), FALSE ); + } + else + { + ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), maAnchorDate, FALSE ); + ImplCalendarSelectDateRange( mpSelectTable, aTempDate, Date( 31, 12, 9999 ), FALSE ); + } + } + ImplCalendarSelectDateRange( mpSelectTable, aTempDate, maAnchorDate, TRUE ); + } + else if ( bExtended && !(mnWinStyle & WB_RANGESELECT) ) + { + maAnchorDate = aTempDate; + if ( IsDateSelected( aTempDate ) ) + { + mbUnSel = TRUE; + ImplCalendarSelectDate( mpSelectTable, aTempDate, FALSE ); + } + else + { + ImplCalendarSelectDate( mpSelectTable, aTempDate, TRUE ); + } + } + else + { + maAnchorDate = aTempDate; + ImplCalendarClearSelectDate( mpSelectTable ); + ImplCalendarSelectDate( mpSelectTable, aTempDate, TRUE ); + } + + mpRestoreSelectTable = new Table( *mpSelectTable ); + } + } + else + { + if ( aTempDate < maCurDate ) + mbSelLeft = TRUE; + else + mbSelLeft = FALSE; + if ( !(nHitTest & CALENDAR_HITTEST_DAY) ) + aTempDate = maOldCurDate; + if ( !bMove ) + maAnchorDate = aTempDate; + if ( aTempDate != maCurDate ) + { + maCurDate = aTempDate; + ImplCalendarSelectDate( mpSelectTable, aOldDate, FALSE ); + ImplCalendarSelectDate( mpSelectTable, maCurDate, TRUE ); + } + } + + BOOL bNewSel = *pOldSel != *mpSelectTable; + if ( (maCurDate != aOldDate) || bNewSel ) + { + if ( bNewSel ) + { + mbInSelChange = TRUE; + SelectionChanging(); + mbInSelChange = FALSE; + } + HideFocus(); + if ( bNewSel ) + ImplUpdateSelection( pOldSel ); + if ( !bNewSel || !pOldSel->Get( aOldDate.GetDate() ) ) + ImplUpdateDate( aOldDate ); + // Damit Focus-Rechteck auch wieder neu ausgegeben wird + if ( HasFocus() || !bNewSel || !mpSelectTable->Get( maCurDate.GetDate() ) ) + ImplUpdateDate( maCurDate ); + } + delete pOldSel; +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplUpdate( BOOL bCalcNew ) +{ + if ( IsReallyVisible() && IsUpdateMode() ) + { + if ( bCalcNew && !mbCalc ) + Invalidate(); + else if ( !mbFormat && !mbCalc ) + { + if ( mbDirect ) + { + mbFormat = TRUE; + ImplDraw( FALSE ); + return; + } + else + Invalidate(); + } + } + + if ( bCalcNew ) + mbCalc = TRUE; + mbFormat = TRUE; +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplInvertDropPos() +{ + Rectangle aRect = GetDateRect( maDropDate );//this is one Pixel to width and one to heigh + aRect.Bottom() = aRect.Top()+mnDayHeight-1; + aRect.Right() = aRect.Left()+mnDayWidth-1; + Invert( aRect ); +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplScroll( BOOL bPrev ) +{ + Date aNewFirstMonth = GetFirstMonth(); + if ( bPrev ) + { + aNewFirstMonth--; + aNewFirstMonth -= aNewFirstMonth.GetDaysInMonth()-1; + } + else + aNewFirstMonth += aNewFirstMonth.GetDaysInMonth(); + mbDirect = TRUE; + SetFirstDate( aNewFirstMonth ); + mbDirect = FALSE; +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplShowMenu( const Point& rPos, const Date& rDate ) +{ + EndSelection(); + + Date aOldFirstDate = GetFirstMonth(); + PopupMenu aPopupMenu; + PopupMenu* pYearPopupMenus[MENU_YEAR_COUNT]; + USHORT nMonthOff; + USHORT nCurItemId; + USHORT nYear = rDate.GetYear()-1; + USHORT i; + USHORT j; + USHORT nYearIdCount = 1000; + + nMonthOff = (rDate.GetYear()-aOldFirstDate.GetYear())*12; + if ( aOldFirstDate.GetMonth() < rDate.GetMonth() ) + nMonthOff += rDate.GetMonth()-aOldFirstDate.GetMonth(); + else + nMonthOff -= aOldFirstDate.GetMonth()-rDate.GetMonth(); + + // Menu aufbauen (Jahre mit verschiedenen Monaten aufnehmen) + for ( i = 0; i < MENU_YEAR_COUNT; i++ ) + { + pYearPopupMenus[i] = new PopupMenu; + for ( j = 1; j <= 12; j++ ) + pYearPopupMenus[i]->InsertItem( nYearIdCount+j, + maCalendarWrapper.getDisplayName( + i18n::CalendarDisplayIndex::MONTH, j-1, 1)); + aPopupMenu.InsertItem( 10+i, UniString::CreateFromInt32( nYear+i ) ); + aPopupMenu.SetPopupMenu( 10+i, pYearPopupMenus[i] ); + nYearIdCount += 1000; + } + + mbMenuDown = TRUE; + nCurItemId = aPopupMenu.Execute( this, rPos ); + mbMenuDown = FALSE; + + // Menu zerstoeren + aPopupMenu.SetPopupMenu( 2, NULL ); + for ( i = 0; i < MENU_YEAR_COUNT; i++ ) + { + aPopupMenu.SetPopupMenu( 10+i, NULL ); + delete pYearPopupMenus[i]; + } + + if ( nCurItemId ) + { + USHORT nTempMonthOff = nMonthOff % 12; + USHORT nTempYearOff = nMonthOff / 12; + USHORT nNewMonth = nCurItemId % 1000; + USHORT nNewYear = nYear+((nCurItemId-1000)/1000); + if ( nTempMonthOff < nNewMonth ) + nNewMonth = nNewMonth - nTempMonthOff; + else + { + nNewYear--; + nNewMonth = 12-(nTempMonthOff-nNewMonth); + } + nNewYear = nNewYear - nTempYearOff; + SetFirstDate( Date( 1, nNewMonth, nNewYear ) ); + } +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplTracking( const Point& rPos, BOOL bRepeat ) +{ + Date aTempDate = maCurDate; + USHORT nHitTest = ImplHitTest( rPos, aTempDate ); + + if ( mbSpinDown ) + { + mbPrevIn = (nHitTest & CALENDAR_HITTEST_PREV) != 0; + mbNextIn = (nHitTest & CALENDAR_HITTEST_NEXT) != 0; + + if ( bRepeat && (mbPrevIn || mbNextIn) ) + { + mbScrollDateRange = TRUE; + ImplScroll( mbPrevIn ); + mbScrollDateRange = FALSE; + } + } + else + ImplMouseSelect( aTempDate, nHitTest, TRUE, FALSE, FALSE ); +} + +// ----------------------------------------------------------------------- + +void Calendar::ImplEndTracking( BOOL bCancel ) +{ + BOOL bSelection = mbSelection; + BOOL bSpinDown = mbSpinDown; + + mbDrag = FALSE; + mbSelection = FALSE; + mbMultiSelection = FALSE; + mbUnSel = FALSE; + mbSpinDown = FALSE; + mbPrevIn = FALSE; + mbNextIn = FALSE; + + if ( bCancel ) + { + if ( maOldFirstDate != maFirstDate ) + SetFirstDate( maOldFirstDate ); + + if ( !bSpinDown ) + { + Table* pOldSel = new Table( *mpSelectTable ); + Date aOldDate = maCurDate; + maCurDate = maOldCurDate; + *mpSelectTable = *mpOldSelectTable; + HideFocus(); + ImplUpdateSelection( pOldSel ); + if ( !pOldSel->Get( aOldDate.GetDate() ) ) + ImplUpdateDate( aOldDate ); + // Damit Focus-Rechteck auch wieder neu ausgegeben wird + if ( HasFocus() || !mpSelectTable->Get( maCurDate.GetDate() ) ) + ImplUpdateDate( maCurDate ); + delete pOldSel; + } + } + + if ( !bSpinDown ) + { + if ( !bCancel ) + { + // Feststellen, ob wir sichtbaren Bereich scrollen sollen + ULONG nSelCount = mpSelectTable->Count(); + if ( nSelCount ) + { + Date aFirstSelDate( mpSelectTable->GetObjectKey( 0 ) ); + Date aLastSelDate( mpSelectTable->GetObjectKey( nSelCount-1 ) ); + if ( aLastSelDate < GetFirstMonth() ) + ImplScroll( TRUE ); + else if ( GetLastMonth() < aFirstSelDate ) + ImplScroll( FALSE ); + } + } + + if ( mbAllSel || + (!bCancel && ((maCurDate != maOldCurDate) || (*mpOldSelectTable != *mpSelectTable))) ) + Select(); + + if ( !bSelection && (mnWinStyle & WB_TABSTOP) && !bCancel ) + GrabFocus(); + + delete mpOldSelectTable; + mpOldSelectTable = NULL; + delete mpRestoreSelectTable; + mpRestoreSelectTable = NULL; + } +} + +// ----------------------------------------------------------------------- + +IMPL_STATIC_LINK( Calendar, ScrollHdl, Timer*, EMPTYARG ) +{ + BOOL bPrevIn = (pThis->mnDragScrollHitTest & CALENDAR_HITTEST_PREV) != 0; + BOOL bNextIn = (pThis->mnDragScrollHitTest & CALENDAR_HITTEST_NEXT) != 0; + if( bNextIn || bPrevIn ) + { + pThis->mbScrollDateRange = TRUE; + pThis->ImplScroll( bPrevIn ); + pThis->mbScrollDateRange = FALSE; + } + return 0; +} + +// ----------------------------------------------------------------------- + +void Calendar::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( rMEvt.IsLeft() && !mbMenuDown ) + { + Date aTempDate = maCurDate; + USHORT nHitTest = ImplHitTest( rMEvt.GetPosPixel(), aTempDate ); + if ( nHitTest ) + { + if ( nHitTest & CALENDAR_HITTEST_MONTHTITLE ) + ImplShowMenu( rMEvt.GetPosPixel(), aTempDate ); + else + { + maOldFirstDate = maFirstDate; + + mbPrevIn = (nHitTest & CALENDAR_HITTEST_PREV) != 0; + mbNextIn = (nHitTest & CALENDAR_HITTEST_NEXT) != 0; + if ( mbPrevIn || mbNextIn ) + { + mbSpinDown = TRUE; + mbScrollDateRange = TRUE; + ImplScroll( mbPrevIn ); + mbScrollDateRange = FALSE; + // Hier muss BUTTONREPEAT stehen, also nicht wieder + // auf SCROLLREPEAT aendern, sondern mit TH abklaeren, + // warum es evtl. anders sein sollte (71775) + StartTracking( STARTTRACK_BUTTONREPEAT ); + } + else + { + if ( (rMEvt.GetClicks() == 2) && (nHitTest & CALENDAR_HITTEST_DAY) ) + DoubleClick(); + else + { + if ( mpOldSelectTable ) + delete mpOldSelectTable; + maOldCurDate = maCurDate; + mpOldSelectTable = new Table( *mpSelectTable ); + + if ( !mbSelection ) + { + mbDrag = TRUE; + StartTracking(); + } + + mbMultiSelection = (mnWinStyle & (WB_MULTISELECT | WB_RANGESELECT)) != 0; + if ( (nHitTest & CALENDAR_HITTEST_DAY) && mbMultiSelection ) + mbWeekSel = TRUE; + else + mbWeekSel = FALSE; + ImplMouseSelect( aTempDate, nHitTest, FALSE, rMEvt.IsShift(), rMEvt.IsMod1() ); + } + } + } + } + + return; + } + + Control::MouseButtonDown( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void Calendar::MouseButtonUp( const MouseEvent& rMEvt ) +{ + if ( rMEvt.IsLeft() && mbSelection ) + ImplEndTracking( FALSE ); + else + Control::MouseButtonUp( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void Calendar::MouseMove( const MouseEvent& rMEvt ) +{ + if ( mbSelection && rMEvt.GetButtons() ) + ImplTracking( rMEvt.GetPosPixel(), FALSE ); + else + Control::MouseMove( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void Calendar::Tracking( const TrackingEvent& rTEvt ) +{ + Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel(); + + if ( rTEvt.IsTrackingEnded() ) + ImplEndTracking( rTEvt.IsTrackingCanceled() ); + else + ImplTracking( aMousePos, rTEvt.IsTrackingRepeat() ); +} + +// ----------------------------------------------------------------------- + +void Calendar::KeyInput( const KeyEvent& rKEvt ) +{ + Date aNewDate = maCurDate; + BOOL bMultiSel = (mnWinStyle & (WB_RANGESELECT | WB_MULTISELECT)) != 0; + BOOL bExpand = rKEvt.GetKeyCode().IsShift(); + BOOL bExtended = rKEvt.GetKeyCode().IsMod1(); + + switch ( rKEvt.GetKeyCode().GetCode() ) + { + case KEY_HOME: + aNewDate.SetDay( 1 ); + break; + + case KEY_END: + aNewDate.SetDay( aNewDate.GetDaysInMonth() ); + break; + + case KEY_LEFT: + aNewDate--; + break; + + case KEY_RIGHT: + aNewDate++; + break; + + case KEY_UP: + aNewDate -= 7; + break; + + case KEY_DOWN: + aNewDate += 7; + break; + + case KEY_PAGEUP: + { + Date aTempDate = aNewDate; + aTempDate -= aNewDate.GetDay()+1; + aNewDate -= aTempDate.GetDaysInMonth(); + } + break; + + case KEY_PAGEDOWN: + aNewDate += aNewDate.GetDaysInMonth(); + break; + + case KEY_SPACE: + if ( bMultiSel && !(mnWinStyle & WB_RANGESELECT) ) + { + if ( !bExpand ) + { + BOOL bDateSel = IsDateSelected( maCurDate ); + SelectDate( maCurDate, !bDateSel ); + mbSelLeft = FALSE; + SelectionChanging(); + mbTravelSelect = TRUE; + Select(); + mbTravelSelect = FALSE; + } + } + else + Control::KeyInput( rKEvt ); + break; + + default: + Control::KeyInput( rKEvt ); + break; + } + + if ( aNewDate != maCurDate ) + { + if ( bMultiSel && bExpand ) + { + Table* pOldSel = new Table( *mpSelectTable ); + Date aOldAnchorDate = maAnchorDate; + mbSelLeft = aNewDate < maAnchorDate; + if ( !bExtended ) + { + if ( mbSelLeft ) + { + ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), aNewDate, FALSE ); + ImplCalendarSelectDateRange( mpSelectTable, maAnchorDate, Date( 31, 12, 9999 ), FALSE ); + } + else + { + ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), maAnchorDate, FALSE ); + ImplCalendarSelectDateRange( mpSelectTable, aNewDate, Date( 31, 12, 9999 ), FALSE ); + } + } + ImplCalendarSelectDateRange( mpSelectTable, aNewDate, maAnchorDate, TRUE ); + mbDirect = TRUE; + SetCurDate( aNewDate ); + mbDirect = FALSE; + maAnchorDate = aOldAnchorDate; + mbInSelChange = TRUE; + SelectionChanging(); + mbInSelChange = FALSE; + ImplUpdateSelection( pOldSel ); + delete pOldSel; + } + else + { + if ( mnWinStyle & WB_RANGESELECT ) + { + SetNoSelection(); + SelectDate( aNewDate, TRUE ); + } + mbDirect = TRUE; + SetCurDate( aNewDate ); + mbDirect = FALSE; + } + mbTravelSelect = TRUE; + Select(); + mbTravelSelect = FALSE; + } +} + +// ----------------------------------------------------------------------- + +void Calendar::Paint( const Rectangle& ) +{ + ImplDraw( TRUE ); +} + +// ----------------------------------------------------------------------- + +void Calendar::GetFocus() +{ + ImplUpdateDate( maCurDate ); + Control::GetFocus(); +} + +// ----------------------------------------------------------------------- + +void Calendar::LoseFocus() +{ + HideFocus(); + Control::LoseFocus(); +} + +// ----------------------------------------------------------------------- + +void Calendar::Resize() +{ + ImplUpdate( TRUE ); + Control::Resize(); +} + +// ----------------------------------------------------------------------- + +void Calendar::RequestHelp( const HelpEvent& rHEvt ) +{ + if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) ) + { + Date aDate = maCurDate; + if ( GetDate( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ), aDate ) ) + { + Rectangle aDateRect = GetDateRect( aDate ); + Point aPt = OutputToScreenPixel( aDateRect.TopLeft() ); + aDateRect.Left() = aPt.X(); + aDateRect.Top() = aPt.Y(); + aPt = OutputToScreenPixel( aDateRect.BottomRight() ); + aDateRect.Right() = aPt.X(); + aDateRect.Bottom() = aPt.Y(); + + if ( (rHEvt.GetMode() & HELPMODE_BALLOON) || (mnWinStyle & WB_QUICKHELPSHOWSDATEINFO) ) + { + ImplDateInfo* pInfo; + if ( mpDateTable ) + { + pInfo = mpDateTable->Get( aDate.GetDate() ); + if ( !pInfo ) + pInfo = mpDateTable->Get( Date( aDate.GetDay(), aDate.GetMonth(), 0 ).GetDate() ); + } + else + pInfo = NULL; + if ( pInfo ) + { + XubString aStr = pInfo->maText; + if ( aStr.Len() ) + { + Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), aDateRect, aStr ); + return; + } + } + } + + if ( rHEvt.GetMode() & HELPMODE_QUICK ) + { + maCalendarWrapper.setGregorianDateTime( aDate); + USHORT nWeek = (USHORT) maCalendarWrapper.getValue( i18n::CalendarFieldIndex::WEEK_OF_YEAR); + USHORT nMonth = aDate.GetMonth(); + XubString aStr( maDayText ); + aStr.AppendAscii( ": " ); + aStr.Append( XubString::CreateFromInt32( aDate.GetDayOfYear() ) ); + aStr.AppendAscii( " / " ); + aStr.Append( maWeekText ); + aStr.AppendAscii( ": " ); + aStr.Append( XubString::CreateFromInt32( nWeek ) ); + // Evt. noch Jahr hinzufuegen, wenn es nicht das gleiche ist + if ( (nMonth == 12) && (nWeek == 1) ) + { + aStr.AppendAscii( ", " ); + aStr.Append( XubString::CreateFromInt32( aDate.GetYear()+1 ) ); + } + else if ( (nMonth == 1) && (nWeek > 50) ) + { + aStr.AppendAscii( ", " ); + aStr.Append( XubString::CreateFromInt32( aDate.GetYear()-1 ) ); + } + Help::ShowQuickHelp( this, aDateRect, aStr ); + return; + } + } + } + + Control::RequestHelp( rHEvt ); +} + +// ----------------------------------------------------------------------- + +void Calendar::Command( const CommandEvent& rCEvt ) +{ + if ( rCEvt.GetCommand() == COMMAND_CONTEXTMENU ) + { + if ( !mbSelection && rCEvt.IsMouseEvent() ) + { + Date aTempDate = maCurDate; + USHORT nHitTest = ImplHitTest( rCEvt.GetMousePosPixel(), aTempDate ); + if ( nHitTest & CALENDAR_HITTEST_MONTHTITLE ) + { + ImplShowMenu( rCEvt.GetMousePosPixel(), aTempDate ); + return; + } + } + } + else if ( rCEvt.GetCommand() == COMMAND_WHEEL ) + { + const CommandWheelData* pData = rCEvt.GetWheelData(); + if ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) + { + long nNotchDelta = pData->GetNotchDelta(); + if ( nNotchDelta < 0 ) + { + while ( nNotchDelta < 0 ) + { + ImplScroll( TRUE ); + nNotchDelta++; + } + } + else + { + while ( nNotchDelta > 0 ) + { + ImplScroll( FALSE ); + nNotchDelta--; + } + } + + return; + } + } + + Control::Command( rCEvt ); +} + +// ----------------------------------------------------------------------- + +void Calendar::StateChanged( StateChangedType nType ) +{ + Control::StateChanged( nType ); + + if ( nType == STATE_CHANGE_INITSHOW ) + ImplFormat(); +} + +// ----------------------------------------------------------------------- + +void Calendar::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Control::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + ImplInitSettings(); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void Calendar::SelectionChanging() +{ + maSelectionChangingHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Calendar::DateRangeChanged() +{ + maDateRangeChangedHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Calendar::RequestDateInfo() +{ + maRequestDateInfoHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Calendar::DoubleClick() +{ + maDoubleClickHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Calendar::Select() +{ + maSelectHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Calendar::SelectDate( const Date& rDate, BOOL bSelect ) +{ + if ( !rDate.IsValid() ) + return; + + Table* pOldSel; + + if ( !mbInSelChange ) + pOldSel = new Table( *mpSelectTable ); + else + pOldSel = NULL; + + ImplCalendarSelectDate( mpSelectTable, rDate, bSelect ); + + if ( pOldSel ) + { + ImplUpdateSelection( pOldSel ); + delete pOldSel; + } +} + +// ----------------------------------------------------------------------- + +void Calendar::SelectDateRange( const Date& rStartDate, const Date& rEndDate, + BOOL bSelect ) +{ + if ( !rStartDate.IsValid() || !rEndDate.IsValid() ) + return; + + Table* pOldSel; + + if ( !mbInSelChange ) + pOldSel = new Table( *mpSelectTable ); + else + pOldSel = NULL; + + ImplCalendarSelectDateRange( mpSelectTable, rStartDate, rEndDate, bSelect ); + + if ( pOldSel ) + { + ImplUpdateSelection( pOldSel ); + delete pOldSel; + } +} + +// ----------------------------------------------------------------------- + +void Calendar::SetNoSelection() +{ + Table* pOldSel; + + if ( !mbInSelChange ) + pOldSel = new Table( *mpSelectTable ); + else + pOldSel = NULL; + + ImplCalendarClearSelectDate( mpSelectTable ); + + if ( pOldSel ) + { + ImplUpdateSelection( pOldSel ); + delete pOldSel; + } +} + +// ----------------------------------------------------------------------- + +BOOL Calendar::IsDateSelected( const Date& rDate ) const +{ + return mpSelectTable->IsKeyValid( rDate.GetDate() ); +} + +// ----------------------------------------------------------------------- + +ULONG Calendar::GetSelectDateCount() const +{ + return mpSelectTable->Count(); +} + +// ----------------------------------------------------------------------- + +Date Calendar::GetSelectDate( ULONG nIndex ) const +{ + if ( nIndex < mpSelectTable->Count() ) + return Date( mpSelectTable->GetObjectKey( nIndex ) ); + else + { + Date aDate( 0, 0, 0 ); + return aDate; + } +} + +// ----------------------------------------------------------------------- + +void Calendar::SetCurDate( const Date& rNewDate ) +{ + if ( !rNewDate.IsValid() ) + return; + + if ( maCurDate != rNewDate ) + { + BOOL bUpdate = IsVisible() && IsUpdateMode(); + Date aOldDate = maCurDate; + maCurDate = rNewDate; + maAnchorDate = maCurDate; + + if ( !(mnWinStyle & (WB_RANGESELECT | WB_MULTISELECT)) ) + { + ImplCalendarSelectDate( mpSelectTable, aOldDate, FALSE ); + ImplCalendarSelectDate( mpSelectTable, maCurDate, TRUE ); + } + else if ( !HasFocus() ) + bUpdate = FALSE; + + // Aktuelles Datum noch in den sichtbaren Bereich verschieben + if ( mbFormat || (maCurDate < GetFirstMonth()) ) + SetFirstDate( maCurDate ); + else if ( maCurDate > GetLastMonth() ) + { + Date aTempDate = GetLastMonth(); + long nDateOff = maCurDate-aTempDate; + if ( nDateOff < 365 ) + { + Date aFirstDate = GetFirstMonth(); + aFirstDate += aFirstDate.GetDaysInMonth(); + aTempDate++; + while ( nDateOff > aTempDate.GetDaysInMonth() ) + { + aFirstDate += aFirstDate.GetDaysInMonth(); + long nDaysInMonth = aTempDate.GetDaysInMonth(); + aTempDate += nDaysInMonth; + nDateOff -= nDaysInMonth; + } + SetFirstDate( aFirstDate ); + } + else + SetFirstDate( maCurDate ); + } + else + { + if ( bUpdate ) + { + HideFocus(); + ImplUpdateDate( aOldDate ); + ImplUpdateDate( maCurDate ); + } + } + } +} + +// ----------------------------------------------------------------------- + +void Calendar::SetFirstDate( const Date& rNewFirstDate ) +{ + if ( maFirstDate != rNewFirstDate ) + { + maFirstDate = Date( 1, rNewFirstDate.GetMonth(), rNewFirstDate.GetYear() ); + mbDropPos = FALSE; + ImplUpdate(); + } +} + +// ----------------------------------------------------------------------- + +Date Calendar::GetFirstMonth() const +{ + if ( maFirstDate.GetDay() > 1 ) + { + if ( maFirstDate.GetMonth() == 12 ) + return Date( 1, 1, maFirstDate.GetYear()+1 ); + else + return Date( 1, maFirstDate.GetMonth()+1, maFirstDate.GetYear() ); + } + else + return maFirstDate; +} + +// ----------------------------------------------------------------------- + +Date Calendar::GetLastMonth() const +{ + Date aDate = GetFirstMonth(); + USHORT nMonthCount = GetMonthCount(); + for ( USHORT i = 0; i < nMonthCount; i++ ) + aDate += aDate.GetDaysInMonth(); + aDate--; + return aDate; +} + +// ----------------------------------------------------------------------- + +USHORT Calendar::GetMonthCount() const +{ + if ( mbFormat ) + return 1; + else + return (USHORT)(mnMonthPerLine*mnLines); +} + +// ----------------------------------------------------------------------- + +BOOL Calendar::GetDropDate( Date& rDate ) const +{ + if( mbDropPos ) + { + rDate = maDropDate; + return TRUE; + } + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL Calendar::GetDate( const Point& rPos, Date& rDate ) const +{ + Date aDate = maCurDate; + USHORT nHitTest = ImplHitTest( rPos, aDate ); + if ( nHitTest & CALENDAR_HITTEST_DAY ) + { + rDate = aDate; + return TRUE; + } + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +Rectangle Calendar::GetDateRect( const Date& rDate ) const +{ + Rectangle aRect; + + if ( mbFormat || (rDate < maFirstDate) || (rDate > (maFirstDate+mnDayCount)) ) + return aRect; + + long nX; + long nY; + ULONG nDaysOff; + USHORT nDayIndex; + Date aDate = GetFirstMonth(); + + if ( rDate < aDate ) + { + aRect = GetDateRect( aDate ); + nDaysOff = aDate-rDate; + nX = (long)(nDaysOff*mnDayWidth); + aRect.Left() -= nX; + aRect.Right() -= nX; + return aRect; + } + else + { + Date aLastDate = GetLastMonth(); + if ( rDate > aLastDate ) + { + USHORT nWeekDay = (USHORT)aLastDate.GetDayOfWeek(); + nWeekDay = (nWeekDay+(7-(USHORT)ImplGetWeekStart())) % 7; + aLastDate -= nWeekDay; + aRect = GetDateRect( aLastDate ); + nDaysOff = rDate-aLastDate; + nDayIndex = 0; + for ( USHORT i = 0; i <= nDaysOff; i++ ) + { + if ( aLastDate == rDate ) + { + aRect.Left() += nDayIndex*mnDayWidth; + aRect.Right() = aRect.Left()+mnDayWidth; + return aRect; + } + if ( nDayIndex == 6 ) + { + nDayIndex = 0; + aRect.Top() += mnDayHeight; + aRect.Bottom() += mnDayHeight; + } + else + nDayIndex++; + aLastDate++; + } + } + } + + nY = 0; + for ( long i = 0; i < mnLines; i++ ) + { + nX = 0; + for ( long j = 0; j < mnMonthPerLine; j++ ) + { + USHORT nDaysInMonth = aDate.GetDaysInMonth(); + + // Monat gerufen + if ( (aDate.GetMonth() == rDate.GetMonth()) && + (aDate.GetYear() == rDate.GetYear()) ) + { + long nDayX = nX+mnDaysOffX; + long nDayY = nY+mnDaysOffY; + nDayIndex = (USHORT)aDate.GetDayOfWeek(); + nDayIndex = (nDayIndex+(7-(USHORT)ImplGetWeekStart())) % 7; + for ( USHORT nDay = 1; nDay <= nDaysInMonth; nDay++ ) + { + if ( nDay == rDate.GetDay() ) + { + aRect.Left() = nDayX + (nDayIndex*mnDayWidth); + aRect.Top() = nDayY; + aRect.Right() = aRect.Left()+mnDayWidth; + aRect.Bottom() = aRect.Top()+mnDayHeight; + break; + } + if ( nDayIndex == 6 ) + { + nDayIndex = 0; + nDayY += mnDayHeight; + } + else + nDayIndex++; + } + } + + aDate += nDaysInMonth; + nX += mnMonthWidth; + } + + nY += mnMonthHeight; + } + + return aRect; +} + +// ----------------------------------------------------------------------- + +void Calendar::SetStandardColor( const Color& rColor ) +{ + if ( mpStandardColor ) + *mpStandardColor = rColor; + else + mpStandardColor = new Color( rColor ); + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void Calendar::SetSaturdayColor( const Color& rColor ) +{ + if ( mpSaturdayColor ) + *mpSaturdayColor = rColor; + else + mpSaturdayColor = new Color( rColor ); + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void Calendar::SetSundayColor( const Color& rColor ) +{ + if ( mpSundayColor ) + *mpSundayColor = rColor; + else + mpSundayColor = new Color( rColor ); + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void Calendar::AddDateInfo( const Date& rDate, const String& rText, + const Color* pTextColor, const Color* pFrameColor, + USHORT nFlags ) +{ + if ( !mpDateTable ) + mpDateTable = new ImplDateTable( 256, 256 ); + + BOOL bChanged = FALSE; + ULONG nKey = rDate.GetDate(); + ImplDateInfo* pDateInfo = mpDateTable->Get( nKey ); + if ( pDateInfo ) + pDateInfo->maText = rText; + else + { + pDateInfo = new ImplDateInfo( rText ); + mpDateTable->Insert( nKey, pDateInfo ); + } + if ( pTextColor ) + { + if ( pDateInfo->mpTextColor ) + { + if ( *(pDateInfo->mpTextColor) != *pTextColor ) + { + *(pDateInfo->mpTextColor) = *pTextColor; + bChanged = TRUE; + } + } + else + { + pDateInfo->mpTextColor = new Color( *pTextColor ); + bChanged = TRUE; + } + } + else + { + if ( pDateInfo->mpTextColor ) + { + delete pDateInfo->mpTextColor; + pDateInfo->mpTextColor = NULL; + bChanged = TRUE; + } + } + if ( pFrameColor ) + { + if ( pDateInfo->mpFrameColor ) + { + if ( *(pDateInfo->mpFrameColor) != *pFrameColor ) + { + *(pDateInfo->mpFrameColor) = *pFrameColor; + bChanged = TRUE; + } + } + else + { + pDateInfo->mpFrameColor = new Color( *pFrameColor ); + bChanged = TRUE; + } + } + else + { + if ( pDateInfo->mpFrameColor ) + { + delete pDateInfo->mpFrameColor; + pDateInfo->mpFrameColor = NULL; + bChanged = TRUE; + } + } + if ( pDateInfo->mnFlags != nFlags ) + { + pDateInfo->mnFlags = nFlags; + bChanged = TRUE; + } + + if ( bChanged ) + ImplUpdateDate( rDate ); +} + +// ----------------------------------------------------------------------- + +void Calendar::RemoveDateInfo( const Date& rDate ) +{ + if ( mpDateTable ) + { + ImplDateInfo* pDateInfo = mpDateTable->Remove( rDate.GetDate() ); + if ( pDateInfo ) + { + delete pDateInfo; + ImplUpdateDate( rDate ); + } + } +} + +// ----------------------------------------------------------------------- + +void Calendar::ClearDateInfo() +{ + if ( mpDateTable ) + { + ImplDateInfo* pDateInfo = mpDateTable->First(); + while ( pDateInfo ) + { + ULONG nKey = mpDateTable->GetCurKey(); + mpDateTable->Remove( nKey ); + Date aDate( nKey ); + ImplUpdateDate( aDate ); + delete pDateInfo; + pDateInfo = mpDateTable->First(); + } + delete mpDateTable; + mpDateTable = NULL; + } +} + +// ----------------------------------------------------------------------- + +XubString Calendar::GetDateInfoText( const Date& rDate ) +{ + XubString aRet; + if ( mpDateTable ) + { + ULONG nKey = rDate.GetDate(); + ImplDateInfo* pDateInfo = mpDateTable->Get( nKey ); + if ( pDateInfo ) + aRet = pDateInfo->maText; + } + return aRet; +} + +// ----------------------------------------------------------------------- + +BOOL Calendar::ShowDropPos( const Point& rPos, Date& rDate ) +{ + Date aTempDate = maCurDate; + mnDragScrollHitTest = ImplHitTest( rPos, aTempDate ); + + if ( mnDragScrollHitTest ) + { + if ( mnDragScrollHitTest & (CALENDAR_HITTEST_PREV | CALENDAR_HITTEST_NEXT) ) + { + if ( !maDragScrollTimer.IsActive() ) + maDragScrollTimer.Start(); + } + else + { + maDragScrollTimer.Stop(); + if ( mnDragScrollHitTest & CALENDAR_HITTEST_DAY ) + { + if ( !mbDropPos || (aTempDate != maDropDate) ) + { + if( mbDropPos ) + ImplInvertDropPos(); + maDropDate = aTempDate; + mbDropPos = TRUE; + ImplInvertDropPos(); + } + + rDate = maDropDate; + return TRUE; + } + } + } + else + maDragScrollTimer.Stop(); + + HideDropPos(); + return FALSE; +} + +// ----------------------------------------------------------------------- + +void Calendar::HideDropPos() +{ + if ( mbDropPos ) + { + ImplInvertDropPos(); + mbDropPos = FALSE; + } +} + +// ----------------------------------------------------------------------- + +void Calendar::StartSelection() +{ + if ( mpOldSelectTable ) + delete mpOldSelectTable; + maOldCurDate = maCurDate; + mpOldSelectTable = new Table( *mpSelectTable ); + + mbSelection = TRUE; +} + +// ----------------------------------------------------------------------- + +void Calendar::EndSelection() +{ + if ( mbDrag || mbSpinDown || mbSelection ) + { + if ( !mbSelection ) + ReleaseMouse(); + + mbDrag = FALSE; + mbSelection = FALSE; + mbMultiSelection = FALSE; + mbSpinDown = FALSE; + mbPrevIn = FALSE; + mbNextIn = FALSE; + } +} + +// ----------------------------------------------------------------------- + +Size Calendar::CalcWindowSizePixel( long nCalcMonthPerLine, + long nCalcLines ) const +{ + XubString a99Text( XubString( RTL_CONSTASCII_USTRINGPARAM( "99" ) ) ); + Font aOldFont = GetFont(); + + // Wochenanzeige beruecksichtigen + long nWeekWidth; + if ( mnWinStyle & WB_WEEKNUMBER ) + { + Font aTempFont = aOldFont; + ImplGetWeekFont( aTempFont ); + ((Calendar*)this)->SetFont( aTempFont ); + nWeekWidth = GetTextWidth( a99Text )+WEEKNUMBER_OFFX; + ((Calendar*)this)->SetFont( aOldFont ); + } + else + nWeekWidth = 0; + + if ( mnWinStyle & WB_BOLDTEXT ) + { + Font aFont = aOldFont; + if ( aFont.GetWeight() < WEIGHT_BOLD ) + aFont.SetWeight( WEIGHT_BOLD ); + else + aFont.SetWeight( WEIGHT_NORMAL ); + ((Calendar*)this)->SetFont( aFont ); + } + + Size aSize; + long n99TextWidth = GetTextWidth( a99Text ); + long nTextHeight = GetTextHeight(); + + if ( mnWinStyle & WB_BOLDTEXT ) + ((Calendar*)this)->SetFont( aOldFont ); + + aSize.Width() += ((n99TextWidth+DAY_OFFX)*7) + nWeekWidth; + aSize.Width() += MONTH_BORDERX*2; + aSize.Width() *= nCalcMonthPerLine; + + aSize.Height() = nTextHeight + TITLE_OFFY + (TITLE_BORDERY*2); + aSize.Height() += nTextHeight + WEEKDAY_OFFY; + aSize.Height() += ((nTextHeight+DAY_OFFY)*6); + aSize.Height() += MONTH_OFFY; + aSize.Height() *= nCalcLines; + + return aSize; +} + +// ======================================================================= + +#define CALFIELD_EXTRA_BUTTON_WIDTH 14 +#define CALFIELD_EXTRA_BUTTON_HEIGHT 8 +#define CALFIELD_SEP_X 6 +#define CALFIELD_BORDERLINE_X 5 +#define CALFIELD_BORDER_YTOP 4 +#define CALFIELD_BORDER_Y 5 + +// ======================================================================= + +class ImplCFieldFloatWin : public FloatingWindow +{ +private: + Calendar* mpCalendar; + PushButton* mpTodayBtn; + PushButton* mpNoneBtn; + FixedLine* mpFixedLine; + +public: + ImplCFieldFloatWin( Window* pParent ); + ~ImplCFieldFloatWin(); + + void SetCalendar( Calendar* pCalendar ) + { mpCalendar = pCalendar; } + + PushButton* EnableTodayBtn( BOOL bEnable ); + PushButton* EnableNoneBtn( BOOL bEnable ); + void ArrangeButtons(); + + long Notify( NotifyEvent& rNEvt ); +}; + +// ----------------------------------------------------------------------- + +ImplCFieldFloatWin::ImplCFieldFloatWin( Window* pParent ) : + FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW ) +{ + mpCalendar = NULL; + mpTodayBtn = NULL; + mpNoneBtn = NULL; + mpFixedLine = NULL; +} + +// ----------------------------------------------------------------------- + +ImplCFieldFloatWin::~ImplCFieldFloatWin() +{ + delete mpTodayBtn; + delete mpNoneBtn; + delete mpFixedLine; +} + +// ----------------------------------------------------------------------- + +PushButton* ImplCFieldFloatWin::EnableTodayBtn( BOOL bEnable ) +{ + if ( bEnable ) + { + if ( !mpTodayBtn ) + { + mpTodayBtn = new PushButton( this, WB_NOPOINTERFOCUS ); + XubString aTodayText( SvtResId( STR_SVT_CALENDAR_TODAY ) ); + mpTodayBtn->SetText( aTodayText ); + Size aSize; + aSize.Width() = mpTodayBtn->GetCtrlTextWidth( mpTodayBtn->GetText() ); + aSize.Height() = mpTodayBtn->GetTextHeight(); + aSize.Width() += CALFIELD_EXTRA_BUTTON_WIDTH; + aSize.Height() += CALFIELD_EXTRA_BUTTON_HEIGHT; + mpTodayBtn->SetSizePixel( aSize ); + mpTodayBtn->Show(); + } + } + else + { + if ( mpTodayBtn ) + { + delete mpTodayBtn; + mpTodayBtn = NULL; + } + } + + return mpTodayBtn; +} + +// ----------------------------------------------------------------------- + +PushButton* ImplCFieldFloatWin::EnableNoneBtn( BOOL bEnable ) +{ + if ( bEnable ) + { + if ( !mpNoneBtn ) + { + mpNoneBtn = new PushButton( this, WB_NOPOINTERFOCUS ); + XubString aNoneText( SvtResId( STR_SVT_CALENDAR_NONE ) ); + mpNoneBtn->SetText( aNoneText ); + Size aSize; + aSize.Width() = mpNoneBtn->GetCtrlTextWidth( mpNoneBtn->GetText() ); + aSize.Height() = mpNoneBtn->GetTextHeight(); + aSize.Width() += CALFIELD_EXTRA_BUTTON_WIDTH; + aSize.Height() += CALFIELD_EXTRA_BUTTON_HEIGHT; + mpNoneBtn->SetSizePixel( aSize ); + mpNoneBtn->Show(); + } + } + else + { + if ( mpNoneBtn ) + { + delete mpNoneBtn; + mpNoneBtn = NULL; + } + } + + return mpNoneBtn; +} + +// ----------------------------------------------------------------------- + +void ImplCFieldFloatWin::ArrangeButtons() +{ + long nBtnHeight = 0; + long nBtnWidth = 0; + Size aOutSize = GetOutputSizePixel(); + if ( mpTodayBtn && mpNoneBtn ) + { + Size aTodayBtnSize = mpTodayBtn->GetSizePixel(); + Size aNoneBtnSize = mpNoneBtn->GetSizePixel(); + if ( aTodayBtnSize.Width() < aNoneBtnSize.Width() ) + aTodayBtnSize.Width() = aNoneBtnSize.Width(); + else + aNoneBtnSize.Width() = aTodayBtnSize.Width(); + if ( aTodayBtnSize.Height() < aNoneBtnSize.Height() ) + aTodayBtnSize.Height() = aNoneBtnSize.Height(); + else + aNoneBtnSize.Height() = aTodayBtnSize.Height(); + + nBtnWidth = aTodayBtnSize.Width() + aNoneBtnSize.Width() + CALFIELD_SEP_X; + nBtnHeight = aTodayBtnSize.Height(); + long nX = (aOutSize.Width()-nBtnWidth)/2; + long nY = aOutSize.Height()+CALFIELD_BORDER_Y+CALFIELD_BORDER_YTOP; + mpTodayBtn->SetPosSizePixel( Point( nX, nY ), aTodayBtnSize ); + nX += aTodayBtnSize.Width() + CALFIELD_SEP_X; + mpNoneBtn->SetPosSizePixel( Point( nX, nY ), aNoneBtnSize ); + } + else if ( mpTodayBtn ) + { + Size aTodayBtnSize = mpTodayBtn->GetSizePixel(); + nBtnWidth = aTodayBtnSize.Width(); + nBtnHeight = aTodayBtnSize.Height(); + mpTodayBtn->SetPosPixel( Point( (aOutSize.Width()-nBtnWidth)/2, aOutSize.Height()+CALFIELD_BORDER_Y+CALFIELD_BORDER_YTOP ) ); + } + else if ( mpNoneBtn ) + { + Size aNoneBtnSize = mpNoneBtn->GetSizePixel(); + nBtnWidth = aNoneBtnSize.Width(); + nBtnHeight = aNoneBtnSize.Height(); + mpNoneBtn->SetPosPixel( Point( (aOutSize.Width()-nBtnWidth)/2, aOutSize.Height()+CALFIELD_BORDER_Y+CALFIELD_BORDER_YTOP ) ); + } + + if ( nBtnHeight ) + { + if ( !mpFixedLine ) + { + mpFixedLine = new FixedLine( this ); + mpFixedLine->Show(); + } + long nLineWidth = aOutSize.Width()-(CALFIELD_BORDERLINE_X*2); + mpFixedLine->SetPosSizePixel( (aOutSize.Width()-nLineWidth)/2, aOutSize.Height()+((CALFIELD_BORDER_YTOP-2)/2), + nLineWidth, 2, WINDOW_POSSIZE_POSSIZE ); + aOutSize.Height() += nBtnHeight + (CALFIELD_BORDER_Y*2) + CALFIELD_BORDER_YTOP; + SetOutputSizePixel( aOutSize ); + } + else + { + if ( mpFixedLine ) + { + delete mpFixedLine; + mpFixedLine = NULL; + } + } +} + +// ----------------------------------------------------------------------- + +long ImplCFieldFloatWin::Notify( NotifyEvent& rNEvt ) +{ + if ( rNEvt.GetType() == EVENT_KEYINPUT ) + { + const KeyEvent* pKEvt = rNEvt.GetKeyEvent(); + if ( pKEvt->GetKeyCode().GetCode() == KEY_RETURN ) + mpCalendar->Select(); + } + + return FloatingWindow::Notify( rNEvt ); +} + +// ======================================================================= + +CalendarField::CalendarField( Window* pParent, WinBits nWinStyle ) : + DateField( pParent, nWinStyle ), + maDefaultDate( 0, 0, 0 ) +{ + mpFloatWin = NULL; + mpCalendar = NULL; + mnCalendarStyle = 0; + mbToday = FALSE; + mbNone = FALSE; +} + +// ----------------------------------------------------------------------- + +CalendarField::CalendarField( Window* pParent, const ResId& rResId ) : + DateField( pParent, rResId ), + maDefaultDate( 0, 0, 0 ) +{ + mpFloatWin = NULL; + mpCalendar = NULL; + mnCalendarStyle = 0; + mbToday = FALSE; + mbNone = FALSE; +} + +// ----------------------------------------------------------------------- + +CalendarField::~CalendarField() +{ + if ( mpFloatWin ) + { + delete mpCalendar; + delete mpFloatWin; + } +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( CalendarField, ImplSelectHdl, Calendar*, pCalendar ) +{ + if ( !pCalendar->IsTravelSelect() ) + { + mpFloatWin->EndPopupMode(); + EndDropDown(); + GrabFocus(); + Date aNewDate = mpCalendar->GetSelectDate( 0 ); + if ( IsEmptyDate() || ( aNewDate != GetDate() ) ) + { + SetDate( aNewDate ); + SetModifyFlag(); + Modify(); + } + Select(); + } + return 0; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( CalendarField, ImplClickHdl, PushButton*, pBtn ) +{ + mpFloatWin->EndPopupMode(); + EndDropDown(); + GrabFocus(); + + if ( pBtn == mpTodayBtn ) + { + Date aToday; + if ( (aToday != GetDate()) || IsEmptyDate() ) + { + SetDate( aToday ); + SetModifyFlag(); + Modify(); + } + } + else if ( pBtn == mpNoneBtn ) + { + if ( !IsEmptyDate() ) + { + SetEmptyDate(); + SetModifyFlag(); + Modify(); + } + } + Select(); + + return 0; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( CalendarField, ImplPopupModeEndHdl, FloatingWindow*, EMPTYARG ) +{ + EndDropDown(); + GrabFocus(); + mpCalendar->EndSelection(); + return 0; +} + +// ----------------------------------------------------------------------- + +void CalendarField::Select() +{ + maSelectHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +BOOL CalendarField::ShowDropDown( BOOL bShow ) +{ + if ( bShow ) + { + Calendar* pCalendar = GetCalendar(); + + Date aDate = GetDate(); + if ( IsEmptyDate() || !aDate.IsValid() ) + { + if ( maDefaultDate.IsValid() ) + aDate = maDefaultDate; + else + aDate = Date(); + } + if ( pCalendar->GetStyle() & (WB_RANGESELECT | WB_MULTISELECT) ) + { + pCalendar->SetNoSelection(); + pCalendar->SelectDate( aDate ); + } + pCalendar->SetCurDate( aDate ); + Point aPos( GetParent()->OutputToScreenPixel( GetPosPixel() ) ); + Rectangle aRect( aPos, GetSizePixel() ); + aRect.Bottom() -= 1; + mpCalendar->SetOutputSizePixel( mpCalendar->CalcWindowSizePixel() ); + mpFloatWin->SetOutputSizePixel( mpCalendar->GetSizePixel() ); + mpFloatWin->SetCalendar( mpCalendar ); + mpTodayBtn = mpFloatWin->EnableTodayBtn( mbToday ); + mpNoneBtn = mpFloatWin->EnableNoneBtn( mbNone ); + if ( mpTodayBtn ) + mpTodayBtn->SetClickHdl( LINK( this, CalendarField, ImplClickHdl ) ); + if ( mpNoneBtn ) + mpNoneBtn->SetClickHdl( LINK( this, CalendarField, ImplClickHdl ) ); + mpFloatWin->ArrangeButtons(); + mpCalendar->EnableCallEverySelect(); + mpCalendar->StartSelection(); + mpCalendar->GrabFocus(); + mpCalendar->Show(); + mpFloatWin->StartPopupMode( aRect, FLOATWIN_POPUPMODE_NOFOCUSCLOSE|FLOATWIN_POPUPMODE_DOWN ); + } + else + { + mpFloatWin->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL ); + mpCalendar->EndSelection(); + EndDropDown(); + } + return TRUE; +} + +// ----------------------------------------------------------------------- + +Calendar* CalendarField::CreateCalendar( Window* pParent ) +{ + return new Calendar( pParent, mnCalendarStyle | WB_TABSTOP ); +} + +// ----------------------------------------------------------------------- + +Calendar* CalendarField::GetCalendar() +{ + if ( !mpFloatWin ) + { + mpFloatWin = new ImplCFieldFloatWin( this ); + mpFloatWin->SetPopupModeEndHdl( LINK( this, CalendarField, ImplPopupModeEndHdl ) ); + mpCalendar = CreateCalendar( mpFloatWin ); + mpCalendar->SetPosPixel( Point() ); + mpCalendar->SetSelectHdl( LINK( this, CalendarField, ImplSelectHdl ) ); + } + + return mpCalendar; +} + +// ----------------------------------------------------------------------- + +void CalendarField::StateChanged( StateChangedType nStateChange ) +{ + DateField::StateChanged( nStateChange ); + + if ( ( nStateChange == STATE_CHANGE_STYLE ) && GetSubEdit() ) + { + WinBits nAllAlignmentBits = ( WB_LEFT | WB_CENTER | WB_RIGHT | WB_TOP | WB_VCENTER | WB_BOTTOM ); + WinBits nMyAlignment = GetStyle() & nAllAlignmentBits; + GetSubEdit()->SetStyle( ( GetSubEdit()->GetStyle() & ~nAllAlignmentBits ) | nMyAlignment ); + } +} + diff --git a/svtools/source/control/calendar.src b/svtools/source/control/calendar.src new file mode 100755 index 000000000000..4dd31765a5c1 --- /dev/null +++ b/svtools/source/control/calendar.src @@ -0,0 +1,74 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +#include <svtools/svtools.hrc> +String STR_SVT_CALENDAR_DAY +{ + Text [ en-US ] = "Day" ; +}; +String STR_SVT_CALENDAR_WEEK +{ + Text [ en-US ] = "Week" ; +}; +String STR_SVT_CALENDAR_TODAY +{ + Text [ en-US ] = "Today" ; +}; +String STR_SVT_CALENDAR_NONE +{ + Text [ en-US ] = "None" ; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/svtools/source/control/collatorres.cxx b/svtools/source/control/collatorres.cxx new file mode 100755 index 000000000000..4514ec918b24 --- /dev/null +++ b/svtools/source/control/collatorres.cxx @@ -0,0 +1,126 @@ +/************************************************************************* + * + * 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_svtools.hxx" +#include <svtools/svtdata.hxx> +#include <svtools/svtools.hrc> +#include <svtools/collatorres.hxx> + +// ------------------------------------------------------------------------- +// +// wrapper for locale specific translations data of collator algorithm +// +// ------------------------------------------------------------------------- + +class CollatorRessourceData +{ + friend class CollatorRessource; + private: /* data */ + String ma_Name; + String ma_Translation; + private: /* member functions */ + CollatorRessourceData () {} + public: + CollatorRessourceData ( const String &r_Algorithm, const String &r_Translation) + : ma_Name (r_Algorithm), ma_Translation (r_Translation) {} + + const String& GetAlgorithm () const { return ma_Name; } + + const String& GetTranslation () const { return ma_Translation; } + + ~CollatorRessourceData () {} + + CollatorRessourceData& operator= (const CollatorRessourceData& r_From) + { + ma_Name = r_From.GetAlgorithm(); + ma_Translation = r_From.GetTranslation(); + return *this; + } +}; + +// ------------------------------------------------------------------------- +// +// implementation of the collator-algorithm-name translation +// +// ------------------------------------------------------------------------- + +#define COLLATOR_RESSOURCE_COUNT (STR_SVT_COLLATE_END - STR_SVT_COLLATE_START + 1) + +CollatorRessource::CollatorRessource() +{ + mp_Data = new CollatorRessourceData[COLLATOR_RESSOURCE_COUNT]; + + #define ASCSTR(str) String(RTL_CONSTASCII_USTRINGPARAM(str)) + #define RESSTR(rid) String(SvtResId(rid)) + + + mp_Data[0] = CollatorRessourceData (ASCSTR("alphanumeric"), RESSTR(STR_SVT_COLLATE_ALPHANUMERIC)); + mp_Data[1] = CollatorRessourceData (ASCSTR("charset"), RESSTR(STR_SVT_COLLATE_CHARSET)); + mp_Data[2] = CollatorRessourceData (ASCSTR("dict"), RESSTR(STR_SVT_COLLATE_DICTIONARY)); + mp_Data[3] = CollatorRessourceData (ASCSTR("normal"), RESSTR(STR_SVT_COLLATE_NORMAL)); + mp_Data[4] = CollatorRessourceData (ASCSTR("pinyin"), RESSTR(STR_SVT_COLLATE_PINYIN)); + mp_Data[5] = CollatorRessourceData (ASCSTR("radical"), RESSTR(STR_SVT_COLLATE_RADICAL)); + mp_Data[6] = CollatorRessourceData (ASCSTR("stroke"), RESSTR(STR_SVT_COLLATE_STROKE)); + mp_Data[7] = CollatorRessourceData (ASCSTR("unicode"), RESSTR(STR_SVT_COLLATE_UNICODE)); + mp_Data[8] = CollatorRessourceData (ASCSTR("zhuyin"), RESSTR(STR_SVT_COLLATE_ZHUYIN)); + mp_Data[9] = CollatorRessourceData (ASCSTR("phonebook"), RESSTR(STR_SVT_COLLATE_PHONEBOOK)); + mp_Data[10] = CollatorRessourceData (ASCSTR("phonetic (alphanumeric first)"), RESSTR(STR_SVT_COLLATE_PHONETIC_F)); + mp_Data[11] = CollatorRessourceData (ASCSTR("phonetic (alphanumeric last)"), RESSTR(STR_SVT_COLLATE_PHONETIC_L)); +} + +CollatorRessource::~CollatorRessource() +{ + delete[] mp_Data; +} + +const String& +CollatorRessource::GetTranslation (const String &r_Algorithm) +{ + xub_StrLen nIndex = r_Algorithm.Search('.'); + String aLocaleFreeAlgorithm; + + if (nIndex == STRING_NOTFOUND) + { + aLocaleFreeAlgorithm = r_Algorithm; + } + else + { + nIndex += 1; + aLocaleFreeAlgorithm = String(r_Algorithm, nIndex, r_Algorithm.Len() - nIndex); + } + + for (sal_uInt32 i = 0; i < COLLATOR_RESSOURCE_COUNT; i++) + { + if (aLocaleFreeAlgorithm == mp_Data[i].GetAlgorithm()) + return mp_Data[i].GetTranslation(); + } + + return r_Algorithm; +} + diff --git a/svtools/source/control/ctrlbox.cxx b/svtools/source/control/ctrlbox.cxx new file mode 100755 index 000000000000..91c446a880a9 --- /dev/null +++ b/svtools/source/control/ctrlbox.cxx @@ -0,0 +1,1505 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#define _CTRLBOX_CXX +#include <tools/debug.hxx> +#include <vcl/svapp.hxx> +#include <vcl/field.hxx> +#include <comphelper/processfactory.hxx> +#include <unotools/charclass.hxx> + +#include <svtools/svtdata.hxx> +#include <svtools/svtools.hrc> +#include <svtools/ctrlbox.hxx> +#include <svtools/ctrltool.hxx> + +#include <vcl/i18nhelp.hxx> + +#define IMGTEXTSPACE 2 +#define EXTRAFONTSIZE 5 + +static sal_Unicode aImplSymbolFontText[] = {0xF021,0xF032,0xF043,0xF054,0xF065,0xF076,0xF0B7,0xF0C8,0}; +static sal_Unicode aImplStarSymbolText[] = {0x2706,0x2704,0x270D,0xE033,0x2211,0x2288,0}; + +// ======================================================================== +// ColorListBox +// ======================================================================== + +// -------------------- +// - ImplColorListData - +// -------------------- + +struct ImplColorListData +{ + Color aColor; + BOOL bColor; + + ImplColorListData() : aColor( COL_BLACK ) { bColor = FALSE; } + ImplColorListData( const Color& rColor ) : aColor( rColor ) { bColor = TRUE; } +}; + +DECLARE_LIST( ImpColorList, ImplColorListData* ) + +// ----------------------------------------------------------------------- + +void ColorListBox::ImplInit() +{ + pColorList = new ImpColorList( 256, 64 ); + aImageSize.Width() = GetTextWidth( XubString( RTL_CONSTASCII_USTRINGPARAM( "xxx" ) ) ); + aImageSize.Height() = GetTextHeight(); + aImageSize.Height() -= 2; + + EnableUserDraw( TRUE ); + SetUserItemSize( aImageSize ); +} + +// ----------------------------------------------------------------------- + +void ColorListBox::ImplDestroyColorEntries() +{ + for ( USHORT n = (USHORT) pColorList->Count(); n; ) + { + ImplColorListData* pData = pColorList->GetObject( --n ); + delete pData; + } + pColorList->Clear(); +} + +// ----------------------------------------------------------------------- + +ColorListBox::ColorListBox( Window* pParent, WinBits nWinStyle ) : + ListBox( pParent, nWinStyle ) +{ + ImplInit(); +} + +// ----------------------------------------------------------------------- + +ColorListBox::ColorListBox( Window* pParent, const ResId& rResId ) : + ListBox( pParent, rResId ) +{ + ImplInit(); +} + +// ----------------------------------------------------------------------- + +ColorListBox::~ColorListBox() +{ + ImplDestroyColorEntries(); + delete pColorList; +} + +// ----------------------------------------------------------------------- + +USHORT ColorListBox::InsertEntry( const XubString& rStr, USHORT nPos ) +{ + nPos = ListBox::InsertEntry( rStr, nPos ); + if ( nPos != LISTBOX_ERROR ) + { + ImplColorListData* pData = new ImplColorListData; + pColorList->Insert( pData, nPos ); + } + return nPos; +} + +// ----------------------------------------------------------------------- + +USHORT ColorListBox::InsertEntry( const Color& rColor, const XubString& rStr, + USHORT nPos ) +{ + nPos = ListBox::InsertEntry( rStr, nPos ); + if ( nPos != LISTBOX_ERROR ) + { + ImplColorListData* pData = new ImplColorListData( rColor ); + pColorList->Insert( pData, nPos ); + } + return nPos; +} + +// ----------------------------------------------------------------------- + +void ColorListBox::InsertAutomaticEntry() +{ + // insert the "Automatic"-entry always on the first position + InsertEntry( Color( COL_AUTO ), SvtResId( STR_SVT_AUTOMATIC_COLOR ), 0 ); +} + +// ----------------------------------------------------------------------- + +void ColorListBox::RemoveEntry( USHORT nPos ) +{ + ListBox::RemoveEntry( nPos ); + delete pColorList->Remove( nPos ); +} + +// ----------------------------------------------------------------------- + +void ColorListBox::Clear() +{ + ImplDestroyColorEntries(); + ListBox::Clear(); +} + +// ----------------------------------------------------------------------- + +void ColorListBox::CopyEntries( const ColorListBox& rBox ) +{ + // Liste leeren + ImplDestroyColorEntries(); + + // Daten kopieren + USHORT nCount = (USHORT) rBox.pColorList->Count(); + for ( USHORT n = 0; n < nCount; n++ ) + { + ImplColorListData* pData = rBox.pColorList->GetObject( n ); + USHORT nPos = InsertEntry( rBox.GetEntry( n ), LISTBOX_APPEND ); + if ( nPos != LISTBOX_ERROR ) + pColorList->Insert( new ImplColorListData( *pData ), nPos ); + } +} + +// ----------------------------------------------------------------------- + +USHORT ColorListBox::GetEntryPos( const Color& rColor ) const +{ + for( USHORT n = (USHORT) pColorList->Count(); n; ) + { + ImplColorListData* pData = pColorList->GetObject( --n ); + if ( pData->bColor && ( pData->aColor == rColor ) ) + return n; + } + return LISTBOX_ENTRY_NOTFOUND; +} + +// ----------------------------------------------------------------------- + +Color ColorListBox::GetEntryColor( USHORT nPos ) const +{ + Color aColor; + ImplColorListData* pData = pColorList->GetObject( nPos ); + if ( pData && pData->bColor ) + aColor = pData->aColor; + return aColor; +} + +// ----------------------------------------------------------------------- + +void ColorListBox::UserDraw( const UserDrawEvent& rUDEvt ) +{ + ImplColorListData* pData = pColorList->GetObject( rUDEvt.GetItemId() ); + if ( pData ) + { + if ( pData->bColor ) + { + Point aPos( rUDEvt.GetRect().TopLeft() ); + aPos.X() += 2; + aPos.Y() += ( rUDEvt.GetRect().GetHeight() - aImageSize.Height() ) / 2; + rUDEvt.GetDevice()->Push(); + rUDEvt.GetDevice()->SetFillColor( pData->aColor ); + rUDEvt.GetDevice()->SetLineColor( rUDEvt.GetDevice()->GetTextColor() ); + rUDEvt.GetDevice()->DrawRect( Rectangle( aPos, aImageSize ) ); + rUDEvt.GetDevice()->Pop(); + ListBox::DrawEntry( rUDEvt, FALSE, TRUE, FALSE ); + } + else + ListBox::DrawEntry( rUDEvt, FALSE, TRUE, TRUE ); + } + else + ListBox::DrawEntry( rUDEvt, TRUE, TRUE, FALSE ); +} + +// ======================================================================= +// LineListBox +// ======================================================================= + +// ------------------- +// - ImpListListData - +// ------------------- + +struct ImpLineListData +{ + long nLine1; + long nLine2; + long nDistance; +}; + +DECLARE_LIST( ImpLineList, ImpLineListData* ) + +// ----------------------------------------------------------------------- + +inline const Color& LineListBox::GetPaintColor( void ) const +{ + return maPaintCol; +} + +// ----------------------------------------------------------------------- + +void LineListBox::ImpGetLine( long nLine1, long nLine2, long nDistance, + Bitmap& rBmp, XubString& rStr ) +{ + Size aSize = GetOutputSizePixel(); + aSize.Width() -= 20; + aSize.Width() -= aTxtSize.Width(); + aSize.Height() = aTxtSize.Height(); + + // SourceUnit nach Twips + if ( eSourceUnit == FUNIT_POINT ) + { + nLine1 *= 20; + nLine2 *= 20; + nDistance *= 20; + } + else if ( eSourceUnit == FUNIT_MM ) + { + nLine1 *= 14440; + nLine1 /= 254; + nLine2 *= 14440; + nLine2 /= 254; + nDistance *= 14440; + nDistance /= 254; + } + + // Linien malen + aSize = aVirDev.PixelToLogic( aSize ); + long nPix = aVirDev.PixelToLogic( Size( 0, 1 ) ).Height(); + long n1 = nLine1 / 100; + long n2 = nLine2 / 100; + long nDist = nDistance / 100; + n1 += nPix-1; + n1 -= n1%nPix; + if ( n2 ) + { + nDist += nPix-1; + nDist -= nDist%nPix; + n2 += nPix-1; + n2 -= n2%nPix; + } + long nVirHeight = n1+nDist+n2; + if ( nVirHeight > aSize.Height() ) + aSize.Height() = nVirHeight; + // negative Breiten muss und darf man nicht painten + if ( aSize.Width() > 0 ) + { + Size aVirSize = aVirDev.LogicToPixel( aSize ); + if ( aVirDev.GetOutputSizePixel() != aVirSize ) + aVirDev.SetOutputSizePixel( aVirSize ); + aVirDev.SetFillColor( GetSettings().GetStyleSettings().GetFieldColor() ); + aVirDev.DrawRect( Rectangle( Point(), aSize ) ); + + aVirDev.SetFillColor( GetPaintColor() ); + aVirDev.DrawRect( Rectangle( 0, 0, aSize.Width(), n1-nPix ) ); + if ( n2 ) + { + aVirDev.DrawRect( Rectangle( 0, n1+nDist, + aSize.Width(), n1+nDist+n2-nPix ) ); + } + rBmp = aVirDev.GetBitmap( Point(), Size( aSize.Width(), n1+nDist+n2 ) ); + } + // Twips nach Unit + if ( eUnit == FUNIT_POINT ) + { + nLine1 /= 20; + nLine2 /= 20; + nDistance /= 20; + rStr.AssignAscii( " pt" ); + } + else if ( eUnit == FUNIT_MM ) + { + nLine1 *= 254; + nLine1 /= 14400; + nLine2 *= 254; + nLine2 /= 14400; + nDistance *= 254; + nDistance /= 14400; + rStr.AssignAscii( " mm" ); + } + + String aNum( GetSettings().GetLocaleI18nHelper().GetNum( nLine1+nLine2+nDistance, 2 ) ); + rStr.Insert( aNum, 0 ); +} + +// ----------------------------------------------------------------------- + +void LineListBox::ImplInit() +{ + aTxtSize.Width() = GetTextWidth( XubString( RTL_CONSTASCII_USTRINGPARAM( "99,99 mm" ) ) ); + aTxtSize.Height() = GetTextHeight(); + pLineList = new ImpLineList; + eUnit = FUNIT_POINT; + eSourceUnit = FUNIT_POINT; + + aVirDev.SetLineColor(); + aVirDev.SetMapMode( MapMode( MAP_TWIP ) ); + + UpdatePaintLineColor(); +} + +// ----------------------------------------------------------------------- + +LineListBox::LineListBox( Window* pParent, WinBits nWinStyle ) : + ListBox( pParent, nWinStyle ), + aColor( COL_BLACK ), + maPaintCol( COL_BLACK ) +{ + ImplInit(); +} + +// ----------------------------------------------------------------------- + +LineListBox::LineListBox( Window* pParent, const ResId& rResId ) : + ListBox( pParent, rResId ), + aColor( COL_BLACK ), + maPaintCol( COL_BLACK ) +{ + ImplInit(); +} + +// ----------------------------------------------------------------------- + +LineListBox::~LineListBox() +{ + ULONG n = 0; + ULONG nCount = pLineList->Count(); + while ( n < nCount ) + { + ImpLineListData* pData = pLineList->GetObject( n ); + if ( pData ) + delete pData; + n++; + } + delete pLineList; +} + +// ----------------------------------------------------------------------- + +USHORT LineListBox::InsertEntry( const XubString& rStr, USHORT nPos ) +{ + nPos = ListBox::InsertEntry( rStr, nPos ); + if ( nPos != LISTBOX_ERROR ) + pLineList->Insert( NULL, nPos ); + return nPos; +} + +// ----------------------------------------------------------------------- + +USHORT LineListBox::InsertEntry( long nLine1, long nLine2, long nDistance, + USHORT nPos ) +{ + XubString aStr; + Bitmap aBmp; + ImpGetLine( nLine1, nLine2, nDistance, aBmp, aStr ); + nPos = ListBox::InsertEntry( aStr, aBmp, nPos ); + if ( nPos != LISTBOX_ERROR ) + { + ImpLineListData* pData = new ImpLineListData; + pData->nLine1 = nLine1; + pData->nLine2 = nLine2; + pData->nDistance = nDistance; + pLineList->Insert( pData, nPos ); + } + + return nPos; +} + +// ----------------------------------------------------------------------- + +void LineListBox::RemoveEntry( USHORT nPos ) +{ + ListBox::RemoveEntry( nPos ); + ImpLineListData* pData = pLineList->Remove( nPos ); + if ( pData ) + delete pData; +} + +// ----------------------------------------------------------------------- + +void LineListBox::Clear() +{ + ULONG n = 0; + ULONG nCount = pLineList->Count(); + while ( n < nCount ) + { + ImpLineListData* pData = pLineList->GetObject( n ); + if ( pData ) + delete pData; + n++; + } + + pLineList->Clear(); + ListBox::Clear(); +} + +// ----------------------------------------------------------------------- + +USHORT LineListBox::GetEntryPos( long nLine1, long nLine2, + long nDistance ) const +{ + ULONG n = 0; + ULONG nCount = pLineList->Count(); + while ( n < nCount ) + { + ImpLineListData* pData = pLineList->GetObject( n ); + if ( pData ) + { + if ( (pData->nLine1 == nLine1) && + (pData->nLine2 == nLine2) && + (pData->nDistance == nDistance) ) + return (USHORT)n; + } + + n++; + } + + return LISTBOX_ENTRY_NOTFOUND; +} + +// ----------------------------------------------------------------------- + +long LineListBox::GetEntryLine1( USHORT nPos ) const +{ + ImpLineListData* pData = pLineList->GetObject( nPos ); + if ( pData ) + return pData->nLine1; + else + return 0; +} + +// ----------------------------------------------------------------------- + +long LineListBox::GetEntryLine2( USHORT nPos ) const +{ + ImpLineListData* pData = pLineList->GetObject( nPos ); + if ( pData ) + return pData->nLine2; + else + return 0; +} + +// ----------------------------------------------------------------------- + +long LineListBox::GetEntryDistance( USHORT nPos ) const +{ + ImpLineListData* pData = pLineList->GetObject( nPos ); + if ( pData ) + return pData->nDistance; + else + return 0; +} + +// ----------------------------------------------------------------------- + +void LineListBox::UpdateLineColors( void ) +{ + if( UpdatePaintLineColor() ) + { + ULONG nCount = pLineList->Count(); + if( !nCount ) + return; + + XubString aStr; + Bitmap aBmp; + + // exchange entries which containing lines + SetUpdateMode( FALSE ); + + USHORT nSelEntry = GetSelectEntryPos(); + for( ULONG n = 0 ; n < nCount ; ++n ) + { + ImpLineListData* pData = pLineList->GetObject( n ); + if( pData ) + { + // exchange listbox data + ListBox::RemoveEntry( USHORT( n ) ); + ImpGetLine( pData->nLine1, pData->nLine2, pData->nDistance, aBmp, aStr ); + ListBox::InsertEntry( aStr, aBmp, USHORT( n ) ); + } + } + + if( nSelEntry != LISTBOX_ENTRY_NOTFOUND ) + SelectEntryPos( nSelEntry ); + + SetUpdateMode( TRUE ); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +BOOL LineListBox::UpdatePaintLineColor( void ) +{ + BOOL bRet = TRUE; + const StyleSettings& rSettings = GetSettings().GetStyleSettings(); + Color aNewCol( rSettings.GetWindowColor().IsDark()? rSettings.GetLabelTextColor() : aColor ); + + bRet = aNewCol != maPaintCol; + + if( bRet ) + maPaintCol = aNewCol; + + return bRet; +} + +// ----------------------------------------------------------------------- + +void LineListBox::DataChanged( const DataChangedEvent& rDCEvt ) +{ + ListBox::DataChanged( rDCEvt ); + + if( ( rDCEvt.GetType() == DATACHANGED_SETTINGS ) && ( rDCEvt.GetFlags() & SETTINGS_STYLE ) ) + UpdateLineColors(); +} + +// =================================================================== +// FontNameBox +// =================================================================== + +struct ImplFontNameListData +{ + FontInfo maInfo; + USHORT mnType; + + ImplFontNameListData( const FontInfo& rInfo, + USHORT nType ) : + maInfo( rInfo ), + mnType( nType ) + {} +}; + +DECLARE_LIST( ImplFontList, ImplFontNameListData* ) + +// ------------------------------------------------------------------- + +FontNameBox::FontNameBox( Window* pParent, WinBits nWinStyle ) : + ComboBox( pParent, nWinStyle ) +{ + InitBitmaps(); + mpFontList = NULL; + mbWYSIWYG = FALSE; + mbSymbols = FALSE; +} + +// ------------------------------------------------------------------- + +FontNameBox::FontNameBox( Window* pParent, const ResId& rResId ) : + ComboBox( pParent, rResId ) +{ + InitBitmaps(); + mpFontList = NULL; + mbWYSIWYG = FALSE; + mbSymbols = FALSE; +} + +// ------------------------------------------------------------------- + +FontNameBox::~FontNameBox() +{ + ImplDestroyFontList(); +} + +// ------------------------------------------------------------------- + +void FontNameBox::DataChanged( const DataChangedEvent& rDCEvt ) +{ + ComboBox::DataChanged( rDCEvt ); + + if( rDCEvt.GetType() == DATACHANGED_SETTINGS && ( rDCEvt.GetFlags() & SETTINGS_STYLE ) ) + InitBitmaps(); +} + +// ------------------------------------------------------------------- + +void FontNameBox::InitBitmaps( void ) +{ + BOOL bHC = GetSettings().GetStyleSettings().GetHighContrastMode(); + + maImagePrinterFont = Image( SvtResId( bHC? RID_IMG_PRINTERFONT_HC : RID_IMG_PRINTERFONT ) ); + maImageBitmapFont = Image( SvtResId( bHC? RID_IMG_BITMAPFONT_HC : RID_IMG_BITMAPFONT ) ); + maImageScalableFont = Image( SvtResId( bHC? RID_IMG_SCALABLEFONT_HC : RID_IMG_SCALABLEFONT ) ); +} + +// ------------------------------------------------------------------- + +void FontNameBox::ImplDestroyFontList() +{ + if ( mpFontList ) + { + ImplFontNameListData* pInfo = mpFontList->First(); + while ( pInfo ) + { + delete pInfo; + pInfo = mpFontList->Next(); + } + delete mpFontList; + } +} + +// ------------------------------------------------------------------- + +void FontNameBox::Fill( const FontList* pList ) +{ + // store old text and clear box + XubString aOldText = GetText(); + Clear(); + + ImplDestroyFontList(); + mpFontList = new ImplFontList; + + // insert fonts + USHORT nFontCount = pList->GetFontNameCount(); + for ( USHORT i = 0; i < nFontCount; i++ ) + { + const FontInfo& rFontInfo = pList->GetFontName( i ); + ULONG nIndex = InsertEntry( rFontInfo.GetName() ); + if ( nIndex != LISTBOX_ERROR ) + { + USHORT nType = pList->GetFontNameType( i ); + ImplFontNameListData* pData = new ImplFontNameListData( rFontInfo, nType ); + mpFontList->Insert( pData, nIndex ); + } + } + + ImplCalcUserItemSize(); + + // restore text + if ( aOldText.Len() ) + SetText( aOldText ); +} + +// ------------------------------------------------------------------- + +void FontNameBox::EnableWYSIWYG( BOOL bEnable ) +{ + if ( bEnable != mbWYSIWYG ) + { + mbWYSIWYG = bEnable; + EnableUserDraw( mbWYSIWYG | mbSymbols ); + ImplCalcUserItemSize(); + } +} + +// ------------------------------------------------------------------- + +void FontNameBox::EnableSymbols( BOOL bEnable ) +{ + if ( bEnable != mbSymbols ) + { + mbSymbols = bEnable; + EnableUserDraw( mbWYSIWYG | mbSymbols ); + ImplCalcUserItemSize(); + } +} + +// ------------------------------------------------------------------- + +void FontNameBox::ImplCalcUserItemSize() +{ + Size aUserItemSz; + if ( mbWYSIWYG && mpFontList ) + { + USHORT nMaxLen = 0; + BOOL bSymbolFont = FALSE; + BOOL bStarSymbol = FALSE; + for ( USHORT n = GetEntryCount(); n; ) + { + ImplFontNameListData* pData = mpFontList->GetObject( --n ); + XubString aFontName = pData->maInfo.GetName(); + if ( aFontName.Len() > nMaxLen ) + nMaxLen = aFontName.Len(); + if ( pData->maInfo.GetCharSet() == RTL_TEXTENCODING_SYMBOL ) + bSymbolFont = TRUE; + // starsymbol is a unicode font, but gets WYSIWIG symbols + if( aFontName.EqualsIgnoreCaseAscii( "starsymbol" ) + || aFontName.EqualsIgnoreCaseAscii( "opensymbol" ) ) + bSymbolFont = bStarSymbol = TRUE; + } + + // guess maximimum width + Size aOneCharSz( GetTextWidth( String( 'X' ) ), GetTextHeight() ); + Size aSz( aOneCharSz ); + aSz.Width() *= nMaxLen; + // only XX% of width, because ListBox calculates the normal width... + aSz.Width() *= 1; + aSz.Width() /= 10; + if ( bSymbolFont ) + { + int nLength = sizeof(aImplSymbolFontText)/sizeof(aImplSymbolFontText[0]) - 1; + int nLength2 = sizeof(aImplStarSymbolText)/sizeof(aImplStarSymbolText[0]) - 1; + if( bStarSymbol && (nLength < nLength2) ) + nLength = nLength2; + aSz.Width() += aOneCharSz.Width() * nLength; + } + aSz.Height() *= 14; + aSz.Height() /= 10; + aUserItemSz = aSz; + } + if ( mbSymbols ) + { + Size aSz = maImageScalableFont.GetSizePixel(); + aUserItemSz.Width() += aSz.Width() + IMGTEXTSPACE; + if ( aSz.Height() > aUserItemSz.Height() ) + aUserItemSz.Height() = aSz.Height(); + } + SetUserItemSize( aUserItemSz ); +} + +// ------------------------------------------------------------------- + +void FontNameBox::UserDraw( const UserDrawEvent& rUDEvt ) +{ + ImplFontNameListData* pData = mpFontList->GetObject( rUDEvt.GetItemId() ); + const FontInfo& rInfo = pData->maInfo; + USHORT nType = pData->mnType; + Point aTopLeft = rUDEvt.GetRect().TopLeft(); + long nX = aTopLeft.X(); + long nH = rUDEvt.GetRect().GetHeight(); + + if ( mbSymbols ) + { + nX += IMGTEXTSPACE; + Image* pImg = NULL; + if ( (nType & (FONTLIST_FONTNAMETYPE_PRINTER | FONTLIST_FONTNAMETYPE_SCREEN)) == FONTLIST_FONTNAMETYPE_PRINTER ) + pImg = &maImagePrinterFont; + else if ( nType & FONTLIST_FONTNAMETYPE_SCALABLE ) + pImg = &maImageScalableFont; + else + pImg = &maImageBitmapFont; + + if ( pImg ) + { + Point aPos( nX, aTopLeft.Y() + (nH-pImg->GetSizePixel().Height())/2 ); + rUDEvt.GetDevice()->DrawImage( aPos, *pImg ); + } + + // X immer um gleiche Breite aendern, auch wenn kein Image ausgegeben. + nX += maImagePrinterFont.GetSizePixel().Width(); + } + + if ( mbWYSIWYG && mpFontList ) + { + nX += IMGTEXTSPACE; + + bool bSymbolFont = (rInfo.GetCharSet() == RTL_TEXTENCODING_SYMBOL); + // starsymbol is a unicode font, but cannot display its own name + const bool bOpenSymbol = rInfo.GetName().EqualsIgnoreCaseAscii( "starsymbol" ) + || rInfo.GetName().EqualsIgnoreCaseAscii( "opensymbol" ); + bSymbolFont |= bOpenSymbol; + + if( bSymbolFont ) + { + String aText( rInfo.GetName() ); + aText.AppendAscii( " " ); + Point aPos( nX, aTopLeft.Y() + (nH-rUDEvt.GetDevice()->GetTextHeight())/2 ); + rUDEvt.GetDevice()->DrawText( aPos, aText ); + nX += rUDEvt.GetDevice()->GetTextWidth( aText ); + } + + Color aTextColor = rUDEvt.GetDevice()->GetTextColor(); + Font aOldFont( rUDEvt.GetDevice()->GetFont() ); + Size aSize( aOldFont.GetSize() ); + aSize.Height() += EXTRAFONTSIZE; + Font aFont( rInfo ); + aFont.SetSize( aSize ); + rUDEvt.GetDevice()->SetFont( aFont ); + rUDEvt.GetDevice()->SetTextColor( aTextColor ); + + FontCharMap aFontCharMap; + bool bHasCharMap = rUDEvt.GetDevice()->GetFontCharMap( aFontCharMap ); + + String aString; + if( !bSymbolFont ) + { + // preview the font name + aString = rInfo.GetName(); + + // reset font if the name cannot be display in the preview font + if( STRING_LEN != rUDEvt.GetDevice()->HasGlyphs( aFont, aString ) ) + rUDEvt.GetDevice()->SetFont( aOldFont ); + } + else if( bHasCharMap ) + { + // use some sample characters available in the font + sal_Unicode aText[8]; + + // start just above the PUA used by most symbol fonts + sal_uInt32 cNewChar = 0xFF00; +#ifdef QUARTZ + // on MacOSX there are too many non-presentable symbols above the codepoint 0x0192 + if( !bOpenSymbol ) + cNewChar = 0x0192; +#endif + const int nMaxCount = sizeof(aText)/sizeof(*aText) - 1; + int nSkip = aFontCharMap.GetCharCount() / nMaxCount; + if( nSkip > 10 ) + nSkip = 10; + else if( nSkip <= 0 ) + nSkip = 1; + for( int i = 0; i < nMaxCount; ++i ) + { + sal_uInt32 cOldChar = cNewChar; + for( int j = nSkip; --j >= 0; ) + cNewChar = aFontCharMap.GetPrevChar( cNewChar ); + if( cOldChar == cNewChar ) + break; + aText[ i ] = static_cast<sal_Unicode>(cNewChar); // TODO: support UCS4 samples + aText[ i+1 ] = 0; + } + + aString = String( aText ); + } + else + { + const sal_Unicode* pText = aImplSymbolFontText; + if( bOpenSymbol ) + pText = aImplStarSymbolText; + + aString = String( pText ); + } + + long nTextHeight = rUDEvt.GetDevice()->GetTextHeight(); + Point aPos( nX, aTopLeft.Y() + (nH-nTextHeight)/2 ); + rUDEvt.GetDevice()->DrawText( aPos, aString ); + + rUDEvt.GetDevice()->SetFont( aOldFont ); + DrawEntry( rUDEvt, FALSE, FALSE); // draw seperator + } + else + { + DrawEntry( rUDEvt, TRUE, TRUE ); + } +} + +// =================================================================== +// FontStyleBox +// =================================================================== + +FontStyleBox::FontStyleBox( Window* pParent, WinBits nWinStyle ) : + ComboBox( pParent, nWinStyle ) +{ +} + +// ------------------------------------------------------------------- + +FontStyleBox::FontStyleBox( Window* pParent, const ResId& rResId ) : + ComboBox( pParent, rResId ) +{ + aLastStyle = GetText(); +} + +// ------------------------------------------------------------------- + +FontStyleBox::~FontStyleBox() +{ +} + +// ------------------------------------------------------------------- + +void FontStyleBox::Select() +{ + // keep text over fill operation + aLastStyle = GetText(); + ComboBox::Select(); +} + +// ------------------------------------------------------------------- + +void FontStyleBox::LoseFocus() +{ + // keep text over fill operation + aLastStyle = GetText(); + ComboBox::LoseFocus(); +} + +// ------------------------------------------------------------------- + +void FontStyleBox::Modify() +{ + CharClass aChrCls( ::comphelper::getProcessServiceFactory(), + GetSettings().GetLocale() ); + XubString aStr = GetText(); + USHORT nEntryCount = GetEntryCount(); + + if ( GetEntryPos( aStr ) == COMBOBOX_ENTRY_NOTFOUND ) + { + aChrCls.toUpper( aStr ); + for ( USHORT i = 0; i < nEntryCount; i++ ) + { + XubString aEntryText = GetEntry( i ); + aChrCls.toUpper( aEntryText ); + + if ( aStr == aEntryText ) + { + SetText( GetEntry( i ) ); + break; + } + } + } + + ComboBox::Modify(); +} + +// ------------------------------------------------------------------- + +void FontStyleBox::Fill( const XubString& rName, const FontList* pList ) +{ + // note: this method must call ComboBox::SetText(), + // else aLastStyle will overwritten + // store prior selection position and clear box + XubString aOldText = GetText(); + USHORT nPos = GetEntryPos( aOldText ); + Clear(); + + // does a font with this name already exist? + sal_Handle hFontInfo = pList->GetFirstFontInfo( rName ); + if ( hFontInfo ) + { + XubString aStyleText; + FontWeight eLastWeight = WEIGHT_DONTKNOW; + FontItalic eLastItalic = ITALIC_NONE; + FontWidth eLastWidth = WIDTH_DONTKNOW; + BOOL bNormal = FALSE; + BOOL bItalic = FALSE; + BOOL bBold = FALSE; + BOOL bBoldItalic = FALSE; + BOOL bInsert = FALSE; + FontInfo aInfo; + while ( hFontInfo ) + { + aInfo = pList->GetFontInfo( hFontInfo ); + + FontWeight eWeight = aInfo.GetWeight(); + FontItalic eItalic = aInfo.GetItalic(); + FontWidth eWidth = aInfo.GetWidthType(); + // Only if the attributes are different, we insert the + // Font to avoid double Entries in different languages + if ( (eWeight != eLastWeight) || (eItalic != eLastItalic) || + (eWidth != eLastWidth) ) + { + if ( bInsert ) + InsertEntry( aStyleText ); + + if ( eWeight <= WEIGHT_NORMAL ) + { + if ( eItalic != ITALIC_NONE ) + bItalic = TRUE; + else + bNormal = TRUE; + } + else + { + if ( eItalic != ITALIC_NONE ) + bBoldItalic = TRUE; + else + bBold = TRUE; + } + + // For wrong StyleNames we replace this with the correct once + aStyleText = pList->GetStyleName( aInfo ); + bInsert = GetEntryPos( aStyleText ) == LISTBOX_ENTRY_NOTFOUND; + if ( !bInsert ) + { + aStyleText = pList->GetStyleName( eWeight, eItalic ); + bInsert = GetEntryPos( aStyleText ) == LISTBOX_ENTRY_NOTFOUND; + } + + eLastWeight = eWeight; + eLastItalic = eItalic; + eLastWidth = eWidth; + } + else + { + if ( bInsert ) + { + // If we have two names for the same attributes + // we prefer the translated standard names + const XubString& rAttrStyleText = pList->GetStyleName( eWeight, eItalic ); + if ( rAttrStyleText != aStyleText ) + { + XubString aTempStyleText = pList->GetStyleName( aInfo ); + if ( rAttrStyleText == aTempStyleText ) + aStyleText = rAttrStyleText; + bInsert = GetEntryPos( aStyleText ) == LISTBOX_ENTRY_NOTFOUND; + } + } + } + + if ( !bItalic && (aStyleText == pList->GetItalicStr()) ) + bItalic = TRUE; + else if ( !bBold && (aStyleText == pList->GetBoldStr()) ) + bBold = TRUE; + else if ( !bBoldItalic && (aStyleText == pList->GetBoldItalicStr()) ) + bBoldItalic = TRUE; + + hFontInfo = pList->GetNextFontInfo( hFontInfo ); + } + + if ( bInsert ) + InsertEntry( aStyleText ); + + // Bestimmte Styles als Nachbildung + if ( bNormal ) + { + if ( !bItalic ) + InsertEntry( pList->GetItalicStr() ); + if ( !bBold ) + InsertEntry( pList->GetBoldStr() ); + } + if ( !bBoldItalic ) + { + if ( bNormal || bItalic || bBold ) + InsertEntry( pList->GetBoldItalicStr() ); + } + if ( aOldText.Len() ) + { + if ( GetEntryPos( aLastStyle ) != LISTBOX_ENTRY_NOTFOUND ) + ComboBox::SetText( aLastStyle ); + else + { + if ( nPos >= GetEntryCount() ) + ComboBox::SetText( GetEntry( 0 ) ); + else + ComboBox::SetText( GetEntry( nPos ) ); + } + } + } + else + { + // Wenn Font nicht, dann Standard-Styles einfuegen + InsertEntry( pList->GetNormalStr() ); + InsertEntry( pList->GetItalicStr() ); + InsertEntry( pList->GetBoldStr() ); + InsertEntry( pList->GetBoldItalicStr() ); + if ( aOldText.Len() ) + { + if ( nPos > GetEntryCount() ) + ComboBox::SetText( GetEntry( 0 ) ); + else + ComboBox::SetText( GetEntry( nPos ) ); + } + } +} + +// =================================================================== +// FontSizeBox +// =================================================================== + +FontSizeBox::FontSizeBox( Window* pParent, WinBits nWinSize ) : + MetricBox( pParent, nWinSize ) +{ + ImplInit(); +} + +// ----------------------------------------------------------------------- + +FontSizeBox::FontSizeBox( Window* pParent, const ResId& rResId ) : + MetricBox( pParent, rResId ) +{ + ImplInit(); +} + +// ----------------------------------------------------------------------- + +FontSizeBox::~FontSizeBox() +{ +} + +// ----------------------------------------------------------------------- + +void FontSizeBox::ImplInit() +{ + EnableAutocomplete( FALSE ); + + bRelativeMode = FALSE; + bPtRelative = FALSE; + bRelative = FALSE; + bStdSize = FALSE; + pFontList = NULL; + + SetShowTrailingZeros( FALSE ); + SetDecimalDigits( 1 ); + SetMin( 20 ); + SetMax( 9999 ); + SetProminentEntryType( PROMINENT_MIDDLE ); +} + +// ----------------------------------------------------------------------- + +void FontSizeBox::Reformat() +{ + FontSizeNames aFontSizeNames( GetSettings().GetUILanguage() ); + if ( !bRelativeMode || !aFontSizeNames.IsEmpty() ) + { + long nNewValue = aFontSizeNames.Name2Size( GetText() ); + if ( nNewValue) + { + mnLastValue = nNewValue; + return; + } + } + + MetricBox::Reformat(); +} + +// ----------------------------------------------------------------------- + +void FontSizeBox::Modify() +{ + MetricBox::Modify(); + + if ( bRelativeMode ) + { + XubString aStr = GetText(); + aStr.EraseLeadingChars(); + + BOOL bNewMode = bRelative; + BOOL bOldPtRelMode = bPtRelative; + + if ( bRelative ) + { + bPtRelative = FALSE; + const xub_Unicode* pStr = aStr.GetBuffer(); + while ( *pStr ) + { + if ( ((*pStr < '0') || (*pStr > '9')) && (*pStr != '%') ) + { + if ( ('-' == *pStr || '+' == *pStr) && !bPtRelative ) + bPtRelative = TRUE; + else if ( bPtRelative && 'p' == *pStr && 't' == *++pStr ) + ; + else + { + bNewMode = FALSE; + break; + } + } + pStr++; + } + } + else + { + if ( STRING_NOTFOUND != aStr.Search( '%' ) ) + { + bNewMode = TRUE; + bPtRelative = FALSE; + } + + if ( '-' == aStr.GetChar( 0 ) || '+' == aStr.GetChar( 0 ) ) + { + bNewMode = TRUE; + bPtRelative = TRUE; + } + } + + if ( bNewMode != bRelative || bPtRelative != bOldPtRelMode ) + SetRelative( bNewMode ); + } +} + +// ----------------------------------------------------------------------- + +void FontSizeBox::Fill( const FontInfo* pInfo, const FontList* pList ) +{ + // remember for relative mode + pFontList = pList; + + // no font sizes need to be set for relative mode + if ( bRelative ) + return; + + // query font sizes + const long* pTempAry; + const long* pAry = 0; + + if( pInfo ) + { + aFontInfo = *pInfo; + pAry = pList->GetSizeAry( *pInfo ); + } + else + { + pAry = pList->GetStdSizeAry(); + } + + // first insert font size names (for simplified/traditional chinese) + FontSizeNames aFontSizeNames( GetSettings().GetUILanguage() ); + if ( pAry == pList->GetStdSizeAry() ) + { + // for standard sizes we don't need to bother + if ( bStdSize && GetEntryCount() && aFontSizeNames.IsEmpty() ) + return; + bStdSize = TRUE; + } + else + bStdSize = FALSE; + + Selection aSelection = GetSelection(); + XubString aStr = GetText(); + + Clear(); + USHORT nPos = 0; + + if ( !aFontSizeNames.IsEmpty() ) + { + if ( pAry == pList->GetStdSizeAry() ) + { + // for scalable fonts all font size names + ULONG nCount = aFontSizeNames.Count(); + for( ULONG i = 0; i < nCount; i++ ) + { + String aSizeName = aFontSizeNames.GetIndexName( i ); + long nSize = aFontSizeNames.GetIndexSize( i ); + ComboBox::InsertEntry( aSizeName, nPos ); + ComboBox::SetEntryData( nPos, (void*)(-nSize) ); // mark as special + nPos++; + } + } + else + { + // for fixed size fonts only selectable font size names + pTempAry = pAry; + while ( *pTempAry ) + { + String aSizeName = aFontSizeNames.Size2Name( *pTempAry ); + if ( aSizeName.Len() ) + { + ComboBox::InsertEntry( aSizeName, nPos ); + ComboBox::SetEntryData( nPos, (void*)(-(*pTempAry)) ); // mark as special + nPos++; + } + pTempAry++; + } + } + } + + // then insert numerical font size values + pTempAry = pAry; + while ( *pTempAry ) + { + InsertValue( *pTempAry, FUNIT_NONE, nPos ); + ComboBox::SetEntryData( nPos, (void*)(*pTempAry) ); + nPos++; + pTempAry++; + } + + SetText( aStr ); + SetSelection( aSelection ); +} + +// ----------------------------------------------------------------------- + +void FontSizeBox::EnableRelativeMode( USHORT nMin, USHORT nMax, USHORT nStep ) +{ + bRelativeMode = TRUE; + nRelMin = nMin; + nRelMax = nMax; + nRelStep = nStep; + SetUnit( FUNIT_POINT ); +} + +// ----------------------------------------------------------------------- + +void FontSizeBox::EnablePtRelativeMode( short nMin, short nMax, short nStep ) +{ + bRelativeMode = TRUE; + nPtRelMin = nMin; + nPtRelMax = nMax; + nPtRelStep = nStep; + SetUnit( FUNIT_POINT ); +} + +// ----------------------------------------------------------------------- + +void FontSizeBox::SetRelative( BOOL bNewRelative ) +{ + if ( bRelativeMode ) + { + Selection aSelection = GetSelection(); + XubString aStr = GetText(); + aStr.EraseLeadingChars(); + + if ( bNewRelative ) + { + bRelative = TRUE; + bStdSize = FALSE; + + if ( bPtRelative ) + { + SetDecimalDigits( 1 ); + SetMin( nPtRelMin ); + SetMax( nPtRelMax ); + SetUnit( FUNIT_POINT ); + + Clear(); + + short i = nPtRelMin, n = 0; + // JP 30.06.98: more than 100 values are not useful + while ( i <= nPtRelMax && n++ < 100 ) + { + InsertValue( i ); + i = i + nPtRelStep; + } + } + else + { + SetDecimalDigits( 0 ); + SetMin( nRelMin ); + SetMax( nRelMax ); + SetCustomUnitText( '%' ); + SetUnit( FUNIT_CUSTOM ); + + Clear(); + USHORT i = nRelMin; + while ( i <= nRelMax ) + { + InsertValue( i ); + i = i + nRelStep; + } + } + } + else + { + bRelative = bPtRelative = FALSE; + SetDecimalDigits( 1 ); + SetMin( 20 ); + SetMax( 9999 ); + SetUnit( FUNIT_POINT ); + if ( pFontList ) + Fill( &aFontInfo, pFontList ); + } + + SetText( aStr ); + SetSelection( aSelection ); + } +} + +// ----------------------------------------------------------------------- + +XubString FontSizeBox::CreateFieldText( sal_Int64 nValue ) const +{ + XubString sRet( MetricBox::CreateFieldText( nValue ) ); + if ( bRelativeMode && bPtRelative && (0 <= nValue) && sRet.Len() ) + sRet.Insert( '+', 0 ); + return sRet; +} + +// ----------------------------------------------------------------------- + +void FontSizeBox::SetValue( sal_Int64 nNewValue, FieldUnit eInUnit ) +{ + if ( !bRelative ) + { + sal_Int64 nTempValue = MetricField::ConvertValue( nNewValue, GetBaseValue(), GetDecimalDigits(), eInUnit, GetUnit() ); + FontSizeNames aFontSizeNames( GetSettings().GetUILanguage() ); + // conversion loses precision; however font sizes should + // never have a problem with that + String aName = aFontSizeNames.Size2Name( static_cast<long>(nTempValue) ); + if ( aName.Len() && (GetEntryPos( aName ) != LISTBOX_ENTRY_NOTFOUND) ) + { + mnLastValue = nTempValue; + SetText( aName ); + mnFieldValue = mnLastValue; + SetEmptyFieldValueData( FALSE ); + return; + } + } + + MetricBox::SetValue( nNewValue, eInUnit ); +} + +// ----------------------------------------------------------------------- + +void FontSizeBox::SetValue( sal_Int64 nNewValue ) +{ + SetValue( nNewValue, FUNIT_NONE ); +} + +// ----------------------------------------------------------------------- + +sal_Int64 FontSizeBox::GetValue( USHORT nPos, FieldUnit eOutUnit ) const +{ + if ( !bRelative ) + { + sal_Int64 nComboVal = static_cast<sal_Int64>(reinterpret_cast<long>(ComboBox::GetEntryData( nPos ))); + if ( nComboVal < 0 ) // marked as special? + { + return MetricField::ConvertValue( -nComboVal, mnBaseValue, GetDecimalDigits(), + meUnit, eOutUnit ); + } + } + + // do normal font size processing + sal_Int64 nRetValue = MetricBox::GetValue( nPos, eOutUnit ); + return nRetValue; +} + +// ----------------------------------------------------------------------- + +sal_Int64 FontSizeBox::GetValue( FieldUnit eOutUnit ) const +{ + if ( !bRelative ) + { + FontSizeNames aFontSizeNames( GetSettings().GetUILanguage() ); + sal_Int64 nValue = aFontSizeNames.Name2Size( GetText() ); + if ( nValue) + return MetricField::ConvertValue( nValue, GetBaseValue(), GetDecimalDigits(), GetUnit(), eOutUnit ); + } + + return MetricBox::GetValue( eOutUnit ); +} + +// ----------------------------------------------------------------------- + +sal_Int64 FontSizeBox::GetValue() const +{ + // implementation not inline, because it is a virtual function + return GetValue( FUNIT_NONE ); +} + +// ----------------------------------------------------------------------- + +void FontSizeBox::SetUserValue( sal_Int64 nNewValue, FieldUnit eInUnit ) +{ + if ( !bRelative ) + { + sal_Int64 nTempValue = MetricField::ConvertValue( nNewValue, GetBaseValue(), GetDecimalDigits(), eInUnit, GetUnit() ); + FontSizeNames aFontSizeNames( GetSettings().GetUILanguage() ); + // conversion loses precision + // however font sizes should never have a problem with that + String aName = aFontSizeNames.Size2Name( static_cast<long>(nTempValue) ); + if ( aName.Len() && (GetEntryPos( aName ) != LISTBOX_ENTRY_NOTFOUND) ) + { + mnLastValue = nTempValue; + SetText( aName ); + return; + } + } + + MetricBox::SetUserValue( nNewValue, eInUnit ); +} + diff --git a/svtools/source/control/ctrlbox.src b/svtools/source/control/ctrlbox.src new file mode 100755 index 000000000000..95440c905d89 --- /dev/null +++ b/svtools/source/control/ctrlbox.src @@ -0,0 +1,232 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ +#include <svtools/svtools.hrc> + +#ifndef IMAGE_STDBTN_COLOR +#define IMAGE_STDBTN_COLOR Color { Red = 0xFFFF; Green = 0x0000; Blue = 0xFFFF; } +#endif + + +IMAGE RID_IMG_SCALABLEFONT +{ + ImageBitmap = Bitmap { File = "scalfont.bmp" ; }; + MaskColor = IMAGE_STDBTN_COLOR ; +}; + +IMAGE RID_IMG_SCALABLEFONT_HC +{ + ImageBitmap = Bitmap { File = "scalfont_h.bmp" ; }; + MaskColor = IMAGE_STDBTN_COLOR ; +}; + +IMAGE RID_IMG_PRINTERFONT +{ + ImageBitmap = Bitmap { File = "prnfont.bmp" ; }; + MaskColor = IMAGE_STDBTN_COLOR ; +}; + +IMAGE RID_IMG_PRINTERFONT_HC +{ + ImageBitmap = Bitmap { File = "prnfont_h.bmp" ; }; + MaskColor = IMAGE_STDBTN_COLOR ; +}; + +IMAGE RID_IMG_BITMAPFONT +{ + ImageBitmap = Bitmap { File = "bmpfont.bmp" ; }; + MaskColor = IMAGE_STDBTN_COLOR ; +}; + +IMAGE RID_IMG_BITMAPFONT_HC +{ + ImageBitmap = Bitmap { File = "bmpfont_h.bmp" ; }; + MaskColor = IMAGE_STDBTN_COLOR ; +}; + +String STR_SVT_AUTOMATIC_COLOR +{ + Text [ en-US ] = "Automatic"; +}; + +/* + * ressources for CollatorRessource / CollatorRessourceData resp. + */ + +String STR_SVT_COLLATE_ALPHANUMERIC +{ + /* alphanumeric sorting algorithm */ + Text [ en-US ] = "Alphanumeric"; +}; + +String STR_SVT_COLLATE_NORMAL +{ + /* default or normal sorting algorithm */ + Text [ en-US ] = "Normal"; +}; + +String STR_SVT_COLLATE_CHARSET +{ + /* default or normal sorting algorithm */ + Text [ en-US ] = "Character set"; +}; + +String STR_SVT_COLLATE_DICTIONARY +{ + /* german dictionary word order / sorting */ + Text [ en-US ] = "Dictionary"; +}; + +String STR_SVT_COLLATE_PINYIN +{ + /* chinese sorting algorithm */ + Text [ en-US ] = "Pinyin"; +}; + +String STR_SVT_COLLATE_STROKE +{ + /* chinese sorting algorithm */ + Text [ en-US ] = "Stroke"; +}; + +String STR_SVT_COLLATE_RADICAL +{ + /* chinese sorting algorithm */ + Text [ en-US ] = "Radical"; +}; + +String STR_SVT_COLLATE_UNICODE +{ + /* sorting according to the unicode code point of the character */ + Text [ en-US ] = "Unicode"; +}; + +String STR_SVT_COLLATE_ZHUYIN +{ + /* chinese sorting algorithm */ + Text [ en-US ] = "Zhuyin"; +}; + +String STR_SVT_COLLATE_PHONEBOOK +{ + /* phone book sorting algorithm. e.g. German */ + Text [ en-US ] = "Phone book"; +}; + +String STR_SVT_COLLATE_PHONETIC_F +{ + Text [ en-US ] = "Phonetic (alphanumeric first)"; +}; + +String STR_SVT_COLLATE_PHONETIC_L +{ + Text [ en-US ] = "Phonetic (alphanumeric last)"; +}; + +String STR_SVT_INDEXENTRY_ALPHANUMERIC +{ + /* alphanumeric indexentry algorithm */ + Text [ en-US ] = "Alphanumeric"; +}; + +String STR_SVT_INDEXENTRY_DICTIONARY +{ + /* korean dictionary indexentry algorithm */ + Text [ en-US ] = "Dictionary"; +}; + +String STR_SVT_INDEXENTRY_PINYIN +{ + /* chinese sorting algorithm */ + Text [ en-US ] = "Pinyin"; +}; + +String STR_SVT_INDEXENTRY_RADICAL +{ + /* chinese indexentry algorithm */ + Text [ en-US ] = "Radical"; +}; + +String STR_SVT_INDEXENTRY_STROKE +{ + /* chinese indexentry algorithm */ + Text [ en-US ] = "Stroke"; +}; + +String STR_SVT_INDEXENTRY_ZHUYIN +{ + /* chinese indexentry algorithm */ + Text [ en-US ] = "Zhuyin"; +}; + +String STR_SVT_INDEXENTRY_PHONETIC_FS +{ + Text [ en-US ] = "Phonetic (alphanumeric first, grouped by syllables)"; +}; + +String STR_SVT_INDEXENTRY_PHONETIC_FC +{ + Text [ en-US ] = "Phonetic (alphanumeric first, grouped by consonants)"; +}; + +String STR_SVT_INDEXENTRY_PHONETIC_LS +{ + Text [ en-US ] = "Phonetic (alphanumeric last, grouped by syllables)"; +}; + +String STR_SVT_INDEXENTRY_PHONETIC_LC +{ + Text [ en-US ] = "Phonetic (alphanumeric last, grouped by consonants)"; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/svtools/source/control/ctrltool.cxx b/svtools/source/control/ctrltool.cxx new file mode 100755 index 000000000000..979a8a3a3d32 --- /dev/null +++ b/svtools/source/control/ctrltool.cxx @@ -0,0 +1,1011 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#define CTRLTOOL_CXX + +#include <string.h> + +#include <tools/debug.hxx> +#include <i18npool/mslangid.hxx> +#include <vcl/window.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <svtools/svtools.hrc> +#include <svtools/svtdata.hxx> +#include <svtools/ctrltool.hxx> + +// ======================================================================= + +// Standard Fontgroessen fuer scalierbare Fonts +static long aStdSizeAry[] = +{ + 60, + 70, + 80, + 90, + 100, + 105, + 110, + 120, + 130, + 140, + 150, + 160, + 180, + 200, + 220, + 240, + 260, + 280, + 320, + 360, + 400, + 440, + 480, + 540, + 600, + 660, + 720, + 800, + 880, + 960, + 0 +}; + +// ======================================================================= + +// ----------------------------- +// - class ImplFontListFonInfo - +// ----------------------------- + +class ImplFontListFontInfo : public FontInfo +{ + friend class FontList; + +private: + OutputDevice* mpDevice; + ImplFontListFontInfo* mpNext; + +public: + ImplFontListFontInfo( const FontInfo& rInfo, + OutputDevice* pDev ) : + FontInfo( rInfo ) + { + mpDevice = pDev; + } + + OutputDevice* GetDevice() const { return mpDevice; } +}; + +// ------------------------------ +// - class ImplFontListNameInfo - +// ------------------------------ + +class ImplFontListNameInfo +{ + friend class FontList; + +private: + XubString maSearchName; + ImplFontListFontInfo* mpFirst; + USHORT mnType; + + ImplFontListNameInfo( const XubString& rSearchName ) : + maSearchName( rSearchName ) + {} + + const XubString& GetSearchName() const { return maSearchName; } +}; + +// ======================================================================= + +static StringCompare ImplCompareFontInfo( ImplFontListFontInfo* pInfo1, + ImplFontListFontInfo* pInfo2 ) +{ + if ( pInfo1->GetWeight() < pInfo2->GetWeight() ) + return COMPARE_LESS; + else if ( pInfo1->GetWeight() > pInfo2->GetWeight() ) + return COMPARE_GREATER; + + if ( pInfo1->GetItalic() < pInfo2->GetItalic() ) + return COMPARE_LESS; + else if ( pInfo1->GetItalic() > pInfo2->GetItalic() ) + return COMPARE_GREATER; + + return pInfo1->GetStyleName().CompareTo( pInfo2->GetStyleName() ); +} + +// ======================================================================= + +static void ImplMakeSearchString( XubString& rStr ) +{ + rStr.ToLowerAscii(); +} + +// ----------------------------------------------------------------------- + +static void ImplMakeSearchStringFromName( XubString& rStr ) +{ + // check for features before alternate font separator + if (rStr.Search(':') < rStr.Search(';')) + rStr = rStr.GetToken( 0, ':' ); + else + rStr = rStr.GetToken( 0, ';' ); + ImplMakeSearchString( rStr ); +} + +// ----------------------------------------------------------------------- + +ImplFontListNameInfo* FontList::ImplFind( const XubString& rSearchName, ULONG* pIndex ) const +{ + // Wenn kein Eintrag in der Liste oder der Eintrag groesser ist als + // der Letzte, dann hinten dranhaengen. Wir vergleichen erst mit dem + // letzten Eintrag, da die Liste von VCL auch sortiert zurueckkommt + // und somit die Wahrscheinlichkeit das hinten angehaengt werden muss + // sehr gross ist. + StringCompare eComp; + ULONG nCnt = Count(); + if ( !nCnt ) + { + if ( pIndex ) + *pIndex = LIST_APPEND; + return NULL; + } + else + { + ImplFontListNameInfo* pCmpData = (ImplFontListNameInfo*)List::GetObject( nCnt-1 ); + eComp = rSearchName.CompareTo( pCmpData->maSearchName ); + if ( eComp == COMPARE_GREATER ) + { + if ( pIndex ) + *pIndex = LIST_APPEND; + return NULL; + } + else if ( eComp == COMPARE_EQUAL ) + return pCmpData; + } + + // Fonts in der Liste suchen + ImplFontListNameInfo* pCompareData; + ImplFontListNameInfo* pFoundData = NULL; + ULONG nLow = 0; + ULONG nHigh = nCnt-1; + ULONG nMid; + + do + { + nMid = (nLow + nHigh) / 2; + pCompareData = (ImplFontListNameInfo*)List::GetObject( nMid ); + eComp = rSearchName.CompareTo( pCompareData->maSearchName ); + if ( eComp == COMPARE_LESS ) + { + if ( !nMid ) + break; + nHigh = nMid-1; + } + else + { + if ( eComp == COMPARE_GREATER ) + nLow = nMid + 1; + else + { + pFoundData = pCompareData; + break; + } + } + } + while ( nLow <= nHigh ); + + if ( pIndex ) + { + eComp = rSearchName.CompareTo( pCompareData->maSearchName ); + if ( eComp == COMPARE_GREATER ) + *pIndex = (nMid+1); + else + *pIndex = nMid; + } + + return pFoundData; +} + +// ----------------------------------------------------------------------- + +ImplFontListNameInfo* FontList::ImplFindByName( const XubString& rStr ) const +{ + XubString aSearchName = rStr; + ImplMakeSearchStringFromName( aSearchName ); + return ImplFind( aSearchName, NULL ); +} + +// ----------------------------------------------------------------------- + +void FontList::ImplInsertFonts( OutputDevice* pDevice, BOOL bAll, + BOOL bInsertData ) +{ + rtl_TextEncoding eSystemEncoding = gsl_getSystemTextEncoding(); + + USHORT nType; + if ( pDevice->GetOutDevType() != OUTDEV_PRINTER ) + nType = FONTLIST_FONTNAMETYPE_SCREEN; + else + nType = FONTLIST_FONTNAMETYPE_PRINTER; + + // Alle Fonts vom Device abfragen + int n = pDevice->GetDevFontCount(); + USHORT i; + for( i = 0; i < n; i++ ) + { + FontInfo aFontInfo = pDevice->GetDevFont( i ); + + // Wenn keine Raster-Schriften angezeigt werden sollen, + // dann diese ignorieren + if ( !bAll && (aFontInfo.GetType() == TYPE_RASTER) ) + continue; + + XubString aSearchName = aFontInfo.GetName(); + ImplFontListNameInfo* pData; + ULONG nIndex; + ImplMakeSearchString( aSearchName ); + pData = ImplFind( aSearchName, &nIndex ); + + if ( !pData ) + { + if ( bInsertData ) + { + ImplFontListFontInfo* pNewInfo = new ImplFontListFontInfo( aFontInfo, pDevice ); + pData = new ImplFontListNameInfo( aSearchName ); + pData->mpFirst = pNewInfo; + pNewInfo->mpNext = NULL; + pData->mnType = 0; + Insert( (void*)pData, nIndex ); + } + } + else + { + if ( bInsertData ) + { + BOOL bInsert = TRUE; + ImplFontListFontInfo* pPrev = NULL; + ImplFontListFontInfo* pTemp = pData->mpFirst; + ImplFontListFontInfo* pNewInfo = new ImplFontListFontInfo( aFontInfo, pDevice ); + while ( pTemp ) + { + StringCompare eComp = ImplCompareFontInfo( pNewInfo, pTemp ); + if ( (eComp == COMPARE_LESS) || (eComp == COMPARE_EQUAL) ) + { + if ( eComp == COMPARE_EQUAL ) + { + // Overwrite charset, because charset should match + // with the system charset + if ( (pTemp->GetCharSet() != eSystemEncoding) && + (pNewInfo->GetCharSet() == eSystemEncoding) ) + { + ImplFontListFontInfo* pTemp2 = pTemp->mpNext; + *((FontInfo*)pTemp) = *((FontInfo*)pNewInfo); + pTemp->mpNext = pTemp2; + } + delete pNewInfo; + bInsert = FALSE; + } + + break; + } + + pPrev = pTemp; + pTemp = pTemp->mpNext; + } + + if ( bInsert ) + { + pNewInfo->mpNext = pTemp; + if ( pPrev ) + pPrev->mpNext = pNewInfo; + else + pData->mpFirst = pNewInfo; + } + } + } + + if ( pData ) + { + pData->mnType |= nType; + if ( aFontInfo.GetType() != TYPE_RASTER ) + pData->mnType |= FONTLIST_FONTNAMETYPE_SCALABLE; + } + } +} + +// ======================================================================= + +FontList::FontList( OutputDevice* pDevice, OutputDevice* pDevice2, BOOL bAll ) : + List( 4096, sal::static_int_cast< USHORT >(pDevice->GetDevFontCount()), 32 ) +{ + // Variablen initialisieren + mpDev = pDevice; + mpDev2 = pDevice2; + mpSizeAry = NULL; + + // Stylenamen festlegen + maLight = XubString( SvtResId( STR_SVT_STYLE_LIGHT ) ); + maLightItalic = XubString( SvtResId( STR_SVT_STYLE_LIGHT_ITALIC ) ); + maNormal = XubString( SvtResId( STR_SVT_STYLE_NORMAL ) ); + maNormalItalic = XubString( SvtResId( STR_SVT_STYLE_NORMAL_ITALIC ) ); + maBold = XubString( SvtResId( STR_SVT_STYLE_BOLD ) ); + maBoldItalic = XubString( SvtResId( STR_SVT_STYLE_BOLD_ITALIC ) ); + maBlack = XubString( SvtResId( STR_SVT_STYLE_BLACK ) ); + maBlackItalic = XubString( SvtResId( STR_SVT_STYLE_BLACK_ITALIC ) ); + + ImplInsertFonts( pDevice, bAll, TRUE ); + + // Gegebenenfalls muessen wir mit den Bildschirmfonts vergleichen, + // damit dort die eigentlich doppelten auf Equal mappen koennen + BOOL bCompareWindow = FALSE; + if ( !pDevice2 && (pDevice->GetOutDevType() == OUTDEV_PRINTER) ) + { + bCompareWindow = TRUE; + pDevice2 = Application::GetDefaultDevice(); + } + + if ( pDevice2 && + (pDevice2->GetOutDevType() != pDevice->GetOutDevType()) ) + ImplInsertFonts( pDevice2, bAll, !bCompareWindow ); +} + +// ----------------------------------------------------------------------- + +FontList::~FontList() +{ + // Gegebenenfalls SizeArray loeschen + if ( mpSizeAry ) + delete[] mpSizeAry; + + // FontInfos loeschen + ImplFontListNameInfo* pData = (ImplFontListNameInfo*)First(); + while ( pData ) + { + ImplFontListFontInfo* pTemp; + ImplFontListFontInfo* pInfo = pData->mpFirst; + while ( pInfo ) + { + pTemp = pInfo->mpNext; + delete pInfo; + pInfo = pTemp; + } + ImplFontListNameInfo* pNext = (ImplFontListNameInfo*)Next(); + delete pData; + pData = pNext; + } +} +// ----------------------------------------------------------------------- +FontList* FontList::Clone() const +{ + FontList* pReturn = new FontList( + mpDev, mpDev2, GetFontNameCount() == mpDev->GetDevFontCount()); + return pReturn; +} + +// ----------------------------------------------------------------------- + +const XubString& FontList::GetStyleName( FontWeight eWeight, FontItalic eItalic ) const +{ + if ( eWeight > WEIGHT_BOLD ) + { + if ( eItalic > ITALIC_NONE ) + return maBlackItalic; + else + return maBlack; + } + else if ( eWeight > WEIGHT_MEDIUM ) + { + if ( eItalic > ITALIC_NONE ) + return maBoldItalic; + else + return maBold; + } + else if ( eWeight > WEIGHT_LIGHT ) + { + if ( eItalic > ITALIC_NONE ) + return maNormalItalic; + else + return maNormal; + } + else if ( eWeight != WEIGHT_DONTKNOW ) + { + if ( eItalic > ITALIC_NONE ) + return maLightItalic; + else + return maLight; + } + else + { + if ( eItalic > ITALIC_NONE ) + return maNormalItalic; + else + return maNormal; + } +} + +// ----------------------------------------------------------------------- + +XubString FontList::GetStyleName( const FontInfo& rInfo ) const +{ + XubString aStyleName = rInfo.GetStyleName(); + FontWeight eWeight = rInfo.GetWeight(); + FontItalic eItalic = rInfo.GetItalic(); + + // Nur wenn kein StyleName gesetzt ist, geben wir einen syntetischen + // Namen zurueck + if ( !aStyleName.Len() ) + aStyleName = GetStyleName( eWeight, eItalic ); + else + { + // Translate StyleName to localized name + XubString aCompareStyleName = aStyleName; + aCompareStyleName.ToLowerAscii(); + aCompareStyleName.EraseAllChars( ' ' ); + if ( aCompareStyleName.EqualsAscii( "bold" ) ) + aStyleName = maBold; + else if ( aCompareStyleName.EqualsAscii( "bolditalic" ) ) + aStyleName = maBoldItalic; + else if ( aCompareStyleName.EqualsAscii( "italic" ) ) + aStyleName = maNormalItalic; + else if ( aCompareStyleName.EqualsAscii( "standard" ) ) + aStyleName = maNormal; + else if ( aCompareStyleName.EqualsAscii( "regular" ) ) + aStyleName = maNormal; + else if ( aCompareStyleName.EqualsAscii( "medium" ) ) + aStyleName = maNormal; + else if ( aCompareStyleName.EqualsAscii( "light" ) ) + aStyleName = maLight; + else if ( aCompareStyleName.EqualsAscii( "lightitalic" ) ) + aStyleName = maLightItalic; + else if ( aCompareStyleName.EqualsAscii( "black" ) ) + aStyleName = maBlack; + else if ( aCompareStyleName.EqualsAscii( "blackitalic" ) ) + aStyleName = maBlackItalic; + + // fix up StyleName, because the PS Printer driver from + // W2000 returns wrong StyleNames (e.g. Bold instead of Bold Italic + // for Helvetica) + if ( eItalic > ITALIC_NONE ) + { + if ( (aStyleName == maNormal) || + (aStyleName == maBold) || + (aStyleName == maLight) || + (aStyleName == maBlack) ) + aStyleName = GetStyleName( eWeight, eItalic ); + } + } + + return aStyleName; +} + +// ----------------------------------------------------------------------- + +XubString FontList::GetFontMapText( const FontInfo& rInfo ) const +{ + if ( !rInfo.GetName().Len() ) + { + XubString aEmptryStr; + return aEmptryStr; + } + + // Search Fontname + ImplFontListNameInfo* pData = ImplFindByName( rInfo.GetName() ); + if ( !pData ) + { + if ( !maMapNotAvailable.Len() ) + ((FontList*)this)->maMapNotAvailable = XubString( SvtResId( STR_SVT_FONTMAP_NOTAVAILABLE ) ); + return maMapNotAvailable; + } + + // search for synthetic style + USHORT nType = pData->mnType; + const XubString& rStyleName = rInfo.GetStyleName(); + if ( rStyleName.Len() ) + { + BOOL bNotSynthetic = FALSE; + BOOL bNoneAvailable = FALSE; + FontWeight eWeight = rInfo.GetWeight(); + FontItalic eItalic = rInfo.GetItalic(); + ImplFontListFontInfo* pFontInfo = pData->mpFirst; + while ( pFontInfo ) + { + if ( (eWeight == pFontInfo->GetWeight()) && + (eItalic == pFontInfo->GetItalic()) ) + { + bNotSynthetic = TRUE; + break; + } + + pFontInfo = pFontInfo->mpNext; + } + + if ( bNoneAvailable ) + { + XubString aEmptryStr; + return aEmptryStr; + } + else if ( !bNotSynthetic ) + { + if ( !maMapStyleNotAvailable.Len() ) + ((FontList*)this)->maMapStyleNotAvailable = XubString( SvtResId( STR_SVT_FONTMAP_STYLENOTAVAILABLE ) ); + return maMapStyleNotAvailable; + } + } + + /* Size not available not implemented yet + if ( !(nType & FONTLIST_FONTNAMETYPE_SCALABLE) ) + { + ... + { + if ( !maMapSizeNotAvailable.Len() ) + ((FontList*)this)->maMapSizeNotAvailable = XubString( SvtResId( STR_SVT_FONTMAP_SIZENOTAVAILABLE ) ); + return maMapSizeNotAvailable; + } + } + */ + + // Only Printer-Font? + if ( (nType & (FONTLIST_FONTNAMETYPE_PRINTER | FONTLIST_FONTNAMETYPE_SCREEN)) == FONTLIST_FONTNAMETYPE_PRINTER ) + { + if ( !maMapPrinterOnly.Len() ) + ((FontList*)this)->maMapPrinterOnly = XubString( SvtResId( STR_SVT_FONTMAP_PRINTERONLY ) ); + return maMapPrinterOnly; + } + // Only Screen-Font? + else if ( (nType & (FONTLIST_FONTNAMETYPE_PRINTER | FONTLIST_FONTNAMETYPE_SCREEN)) == FONTLIST_FONTNAMETYPE_SCREEN + && rInfo.GetType() == TYPE_RASTER ) + { + if ( !maMapScreenOnly.Len() ) + ((FontList*)this)->maMapScreenOnly = XubString( SvtResId( STR_SVT_FONTMAP_SCREENONLY ) ); + return maMapScreenOnly; + } + else + { + if ( !maMapBoth.Len() ) + ((FontList*)this)->maMapBoth = XubString( SvtResId( STR_SVT_FONTMAP_BOTH ) ); + return maMapBoth; + } +} + +// ----------------------------------------------------------------------- + +USHORT FontList::GetFontNameType( const XubString& rFontName ) const +{ + ImplFontListNameInfo* pData = ImplFindByName( rFontName ); + if ( pData ) + return pData->mnType; + else + return 0; +} + +// ----------------------------------------------------------------------- + +FontInfo FontList::Get( const XubString& rName, const XubString& rStyleName ) const +{ + ImplFontListNameInfo* pData = ImplFindByName( rName ); + ImplFontListFontInfo* pFontInfo = NULL; + ImplFontListFontInfo* pFontNameInfo = NULL; + if ( pData ) + { + ImplFontListFontInfo* pSearchInfo = pData->mpFirst; + pFontNameInfo = pSearchInfo; + pSearchInfo = pData->mpFirst; + while ( pSearchInfo ) + { + if ( rStyleName.EqualsIgnoreCaseAscii( GetStyleName( *pSearchInfo ) ) ) + { + pFontInfo = pSearchInfo; + break; + } + + pSearchInfo = pSearchInfo->mpNext; + } + } + + // Konnten die Daten nicht gefunden werden, dann muessen bestimmte + // Attribute nachgebildet werden + FontInfo aInfo; + if ( !pFontInfo ) + { + if ( pFontNameInfo ) + aInfo = *pFontNameInfo; + + if ( rStyleName == maNormal ) + { + aInfo.SetItalic( ITALIC_NONE ); + aInfo.SetWeight( WEIGHT_NORMAL ); + } + else if ( rStyleName == maNormalItalic ) + { + aInfo.SetItalic( ITALIC_NORMAL ); + aInfo.SetWeight( WEIGHT_NORMAL ); + } + else if ( rStyleName == maBold ) + { + aInfo.SetItalic( ITALIC_NONE ); + aInfo.SetWeight( WEIGHT_BOLD ); + } + else if ( rStyleName == maBoldItalic ) + { + aInfo.SetItalic( ITALIC_NORMAL ); + aInfo.SetWeight( WEIGHT_BOLD ); + } + else if ( rStyleName == maLight ) + { + aInfo.SetItalic( ITALIC_NONE ); + aInfo.SetWeight( WEIGHT_LIGHT ); + } + else if ( rStyleName == maLightItalic ) + { + aInfo.SetItalic( ITALIC_NORMAL ); + aInfo.SetWeight( WEIGHT_LIGHT ); + } + else if ( rStyleName == maBlack ) + { + aInfo.SetItalic( ITALIC_NONE ); + aInfo.SetWeight( WEIGHT_BLACK ); + } + else if ( rStyleName == maBlackItalic ) + { + aInfo.SetItalic( ITALIC_NORMAL ); + aInfo.SetWeight( WEIGHT_BLACK ); + } + else + { + aInfo.SetItalic( ITALIC_NONE ); + aInfo.SetWeight( WEIGHT_DONTKNOW ); + } + } + else + aInfo = *pFontInfo; + + // set Fontname to keep FontAlias + aInfo.SetName( rName ); + aInfo.SetStyleName( rStyleName ); + + return aInfo; +} + +// ----------------------------------------------------------------------- + +FontInfo FontList::Get( const XubString& rName, + FontWeight eWeight, FontItalic eItalic ) const +{ + ImplFontListNameInfo* pData = ImplFindByName( rName ); + ImplFontListFontInfo* pFontInfo = NULL; + ImplFontListFontInfo* pFontNameInfo = NULL; + if ( pData ) + { + ImplFontListFontInfo* pSearchInfo = pData->mpFirst; + pFontNameInfo = pSearchInfo; + while ( pSearchInfo ) + { + if ( (eWeight == pSearchInfo->GetWeight()) && + (eItalic == pSearchInfo->GetItalic()) ) + { + pFontInfo = pSearchInfo; + break; + } + + pSearchInfo = pSearchInfo->mpNext; + } + } + + // Konnten die Daten nicht gefunden werden, dann muessen bestimmte + // Attribute nachgebildet werden + FontInfo aInfo; + if ( !pFontInfo ) + { + // Falls der Fontname stimmt, uebernehmen wir soviel wie moeglich + if ( pFontNameInfo ) + { + aInfo = *pFontNameInfo; + aInfo.SetStyleName( XubString() ); + } + + aInfo.SetWeight( eWeight ); + aInfo.SetItalic( eItalic ); + } + else + aInfo = *pFontInfo; + + // set Fontname to keep FontAlias + aInfo.SetName( rName ); + + return aInfo; +} + +// ----------------------------------------------------------------------- + +BOOL FontList::IsAvailable( const XubString& rName ) const +{ + return (ImplFindByName( rName ) != 0); +} + +// ----------------------------------------------------------------------- + +const FontInfo& FontList::GetFontName( USHORT nFont ) const +{ + DBG_ASSERT( nFont < GetFontNameCount(), "FontList::GetFontName(): nFont >= Count" ); + + ImplFontListNameInfo* pData = (ImplFontListNameInfo*)List::GetObject( nFont ); + return *(pData->mpFirst); +} + +// ----------------------------------------------------------------------- + +USHORT FontList::GetFontNameType( USHORT nFont ) const +{ + DBG_ASSERT( nFont < GetFontNameCount(), "FontList::GetFontNameType(): nFont >= Count" ); + + ImplFontListNameInfo* pData = (ImplFontListNameInfo*)List::GetObject( nFont ); + return pData->mnType; +} + +// ----------------------------------------------------------------------- + +sal_Handle FontList::GetFirstFontInfo( const XubString& rName ) const +{ + ImplFontListNameInfo* pData = ImplFindByName( rName ); + if ( !pData ) + return (sal_Handle)NULL; + else + return (sal_Handle)pData->mpFirst; +} + +// ----------------------------------------------------------------------- + +sal_Handle FontList::GetNextFontInfo( sal_Handle hFontInfo ) const +{ + ImplFontListFontInfo* pInfo = (ImplFontListFontInfo*)(void*)hFontInfo; + return (sal_Handle)(pInfo->mpNext); +} + +// ----------------------------------------------------------------------- + +const FontInfo& FontList::GetFontInfo( sal_Handle hFontInfo ) const +{ + ImplFontListFontInfo* pInfo = (ImplFontListFontInfo*)(void*)hFontInfo; + return *pInfo; +} + +// ----------------------------------------------------------------------- + +const long* FontList::GetSizeAry( const FontInfo& rInfo ) const +{ + // Size-Array vorher loeschen + if ( mpSizeAry ) + { + delete[] ((FontList*)this)->mpSizeAry; + ((FontList*)this)->mpSizeAry = NULL; + } + + // Falls kein Name, dann Standardgroessen + if ( !rInfo.GetName().Len() ) + return aStdSizeAry; + + // Zuerst nach dem Fontnamen suchen um das Device dann von dem + // entsprechenden Font zu nehmen + OutputDevice* pDevice = mpDev; + ImplFontListNameInfo* pData = ImplFindByName( rInfo.GetName() ); + if ( pData ) + pDevice = pData->mpFirst->GetDevice(); + + int nDevSizeCount = pDevice->GetDevFontSizeCount( rInfo ); + if ( !nDevSizeCount || + (pDevice->GetDevFontSize( rInfo, 0 ).Height() == 0) ) + return aStdSizeAry; + + MapMode aOldMapMode = pDevice->GetMapMode(); + MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) ); + pDevice->SetMapMode( aMap ); + + USHORT i; + USHORT nRealCount = 0; + long nOldHeight = 0; + ((FontList*)this)->mpSizeAry = new long[nDevSizeCount+1]; + for ( i = 0; i < nDevSizeCount; i++ ) + { + Size aSize = pDevice->GetDevFontSize( rInfo, i ); + if ( aSize.Height() != nOldHeight ) + { + nOldHeight = aSize.Height(); + ((FontList*)this)->mpSizeAry[nRealCount] = nOldHeight; + nRealCount++; + } + } + ((FontList*)this)->mpSizeAry[nRealCount] = 0; + + pDevice->SetMapMode( aOldMapMode ); + return mpSizeAry; +} + +// ----------------------------------------------------------------------- + +const long* FontList::GetStdSizeAry() +{ + return aStdSizeAry; +} + +// ======================================================================= + +// --------------------------------- +// - FontSizeNames & FsizeNameItem - +// --------------------------------- + +struct ImplFSNameItem +{ + long mnSize; + const char* mszUtf8Name; +}; + +//------------------------------------------------------------------------ + +static ImplFSNameItem aImplSimplifiedChinese[] = +{ + { 50, "\xe5\x85\xab\xe5\x8f\xb7" }, + { 55, "\xe4\xb8\x83\xe5\x8f\xb7" }, + { 65, "\xe5\xb0\x8f\xe5\x85\xad" }, + { 75, "\xe5\x85\xad\xe5\x8f\xb7" }, + { 90, "\xe5\xb0\x8f\xe4\xba\x94" }, + { 105, "\xe4\xba\x94\xe5\x8f\xb7" }, + { 120, "\xe5\xb0\x8f\xe5\x9b\x9b" }, + { 140, "\xe5\x9b\x9b\xe5\x8f\xb7" }, + { 150, "\xe5\xb0\x8f\xe4\xb8\x89" }, + { 160, "\xe4\xb8\x89\xe5\x8f\xb7" }, + { 180, "\xe5\xb0\x8f\xe4\xba\x8c" }, + { 220, "\xe4\xba\x8c\xe5\x8f\xb7" }, + { 240, "\xe5\xb0\x8f\xe4\xb8\x80" }, + { 260, "\xe4\xb8\x80\xe5\x8f\xb7" }, + { 360, "\xe5\xb0\x8f\xe5\x88\x9d" }, + { 420, "\xe5\x88\x9d\xe5\x8f\xb7" } +}; + +// ----------------------------------------------------------------------- + +#if 0 // #i89077# disabled by popular request +static ImplFSNameItem aImplTraditionalChinese[] = +{ + { 50, "\xe5\x85\xab\xe8\x99\x9f" }, + { 55, "\xe4\xb8\x83\xe8\x99\x9f" }, + { 65, "\xe5\xb0\x8f\xe5\x85\xad" }, + { 75, "\xe5\x85\xad\xe8\x99\x9f" }, + { 90, "\xe5\xb0\x8f\xe4\xba\x94" }, + { 105, "\xe4\xba\x94\xe8\x99\x9f" }, + { 120, "\xe5\xb0\x8f\xe5\x9b\x9b" }, + { 140, "\xe5\x9b\x9b\xe8\x99\x9f" }, + { 150, "\xe5\xb0\x8f\xe4\xb8\x89" }, + { 160, "\xe4\xb8\x89\xe8\x99\x9f" }, + { 180, "\xe5\xb0\x8f\xe4\xba\x8c" }, + { 220, "\xe4\xba\x8c\xe8\x99\x9f" }, + { 240, "\xe5\xb0\x8f\xe4\xb8\x80" }, + { 260, "\xe4\xb8\x80\xe8\x99\x9f" }, + { 360, "\xe5\xb0\x8f\xe5\x88\x9d" }, + { 420, "\xe5\x88\x9d\xe8\x99\x9f" } +}; +#endif + +//------------------------------------------------------------------------ + +FontSizeNames::FontSizeNames( LanguageType eLanguage ) +{ + if ( eLanguage == LANGUAGE_DONTKNOW ) + eLanguage = Application::GetSettings().GetUILanguage(); + if ( eLanguage == LANGUAGE_SYSTEM ) + eLanguage = MsLangId::getSystemUILanguage(); + + switch( eLanguage ) + { + case LANGUAGE_CHINESE: + case LANGUAGE_CHINESE_SIMPLIFIED: + mpArray = aImplSimplifiedChinese; + mnElem = sizeof(aImplSimplifiedChinese) / sizeof(aImplSimplifiedChinese[0]); + break; + +#if 0 // #i89077# disabled by popular request + case LANGUAGE_CHINESE_HONGKONG: + case LANGUAGE_CHINESE_SINGAPORE: + case LANGUAGE_CHINESE_MACAU: + case LANGUAGE_CHINESE_TRADITIONAL: + mpArray = aImplTraditionalChinese; + mnElem = sizeof(aImplTraditionalChinese) / sizeof(aImplTraditionalChinese[0]); + break; +#endif + + default: + mpArray = NULL; + mnElem = 0; + break; + }; +} + +//------------------------------------------------------------------------ + +long FontSizeNames::Name2Size( const String& rName ) const +{ + if ( mnElem ) + { + ByteString aName( rName, RTL_TEXTENCODING_UTF8 ); + + // linear search is sufficient for this rare case + for( long i = mnElem; --i >= 0; ) + if ( aName == mpArray[i].mszUtf8Name ) + return mpArray[i].mnSize; + } + + return 0; +} + +//------------------------------------------------------------------------ + +String FontSizeNames::Size2Name( long nValue ) const +{ + String aStr; + + // binary search + for( long lower = 0, upper = mnElem - 1; lower <= upper; ) + { + long mid = (upper + lower) >> 1; + if ( nValue == mpArray[mid].mnSize ) + { + aStr = String( mpArray[mid].mszUtf8Name, RTL_TEXTENCODING_UTF8 ); + break; + } + else if ( nValue < mpArray[mid].mnSize ) + upper = mid - 1; + else /* ( nValue > mpArray[mid].mnSize ) */ + lower = mid + 1; + } + + return aStr; +} + +//------------------------------------------------------------------------ + +String FontSizeNames::GetIndexName( ULONG nIndex ) const +{ + String aStr; + + if ( nIndex < mnElem ) + aStr = String( mpArray[nIndex].mszUtf8Name, RTL_TEXTENCODING_UTF8 ); + + return aStr; +} + +//------------------------------------------------------------------------ + +long FontSizeNames::GetIndexSize( ULONG nIndex ) const +{ + if ( nIndex >= mnElem ) + return 0; + return mpArray[nIndex].mnSize; +} diff --git a/svtools/source/control/ctrltool.src b/svtools/source/control/ctrltool.src new file mode 100755 index 000000000000..72420af4908e --- /dev/null +++ b/svtools/source/control/ctrltool.src @@ -0,0 +1,144 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ +#include <svtools/svtools.hrc> + +String STR_SVT_STYLE_LIGHT +{ + Text [ en-US ] = "Light" ; +}; + +String STR_SVT_STYLE_LIGHT_ITALIC +{ + Text [ en-US ] = "Light Italic" ; +}; + +String STR_SVT_STYLE_NORMAL +{ + Text [ en-US ] = "Regular" ; +}; + +String STR_SVT_STYLE_NORMAL_ITALIC +{ + Text [ en-US ] = "Italic" ; +}; + +String STR_SVT_STYLE_BOLD +{ + Text [ en-US ] = "Bold" ; +}; + +String STR_SVT_STYLE_BOLD_ITALIC +{ + Text [ en-US ] = "Bold Italic" ; +}; + +String STR_SVT_STYLE_BLACK +{ + Text [ en-US ] = "Black" ; +}; + +String STR_SVT_STYLE_BLACK_ITALIC +{ + Text [ en-US ] = "Black Italic" ; +}; + +/* +Finnische Texte: + "Light", + "Light Kursivoitu", + "Normaali", + "Kursivoitu", + "Lihavoitu", + "Lihavoitu Kursivoitu", + "Black", + "Black Kursivoitu" +*/ + +String STR_SVT_FONTMAP_BOTH +{ + Text [ en-US ] = "The same font will be used on both your printer and your screen." ; +}; + +String STR_SVT_FONTMAP_PRINTERONLY +{ + Text [ en-US ] = "This is a printer font. The screen image may differ." ; +}; + +String STR_SVT_FONTMAP_SCREENONLY +{ + Text [ en-US ] = "This is a screen font. The printer image may differ." ; +}; + +String STR_SVT_FONTMAP_SIZENOTAVAILABLE +{ + Text [ en-US ] = "This font size has not been installed. The closest available size will be used."; +}; + +String STR_SVT_FONTMAP_STYLENOTAVAILABLE +{ + Text [ en-US ] = "This font style will be simulated or the closest matching style will be used."; +}; + +String STR_SVT_FONTMAP_NOTAVAILABLE +{ + Text [ en-US ] = "This font has not been installed. The closest available font will be used."; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/svtools/source/control/filectrl.cxx b/svtools/source/control/filectrl.cxx new file mode 100755 index 000000000000..3541a43effc1 --- /dev/null +++ b/svtools/source/control/filectrl.cxx @@ -0,0 +1,231 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#define _SV_FIELCTRL_CXX +#include <tools/urlobj.hxx> +#include <svtools/svtdata.hxx> +#include <svtools/filectrl.hxx> +#include <filectrl.hrc> + +// ======================================================================= + +FileControl::FileControl( Window* pParent, WinBits nStyle, FileControlMode nFlags ) : + Window( pParent, nStyle|WB_DIALOGCONTROL ), + maEdit( this, (nStyle&(~WB_BORDER))|WB_NOTABSTOP ), + maButton( this, (nStyle&(~WB_BORDER))|WB_NOLIGHTBORDER|WB_NOPOINTERFOCUS|WB_NOTABSTOP ), + maButtonText( SvtResId( STR_FILECTRL_BUTTONTEXT ) ), + mnFlags( nFlags ), + mnInternalFlags( FILECTRL_ORIGINALBUTTONTEXT ) +{ + maButton.SetClickHdl( LINK( this, FileControl, ButtonHdl ) ); + mbOpenDlg = TRUE; + + maButton.Show(); + maEdit.Show(); + + SetCompoundControl( TRUE ); + + SetStyle( ImplInitStyle( GetStyle() ) ); +} + +// ----------------------------------------------------------------------- + +WinBits FileControl::ImplInitStyle( WinBits nStyle ) +{ + if ( !( nStyle & WB_NOTABSTOP ) ) + { + maEdit.SetStyle( (maEdit.GetStyle()|WB_TABSTOP)&(~WB_NOTABSTOP) ); + maButton.SetStyle( (maButton.GetStyle()|WB_TABSTOP)&(~WB_NOTABSTOP) ); + } + else + { + maEdit.SetStyle( (maEdit.GetStyle()|WB_NOTABSTOP)&(~WB_TABSTOP) ); + maButton.SetStyle( (maButton.GetStyle()|WB_NOTABSTOP)&(~WB_TABSTOP) ); + } + + const WinBits nAlignmentStyle = ( WB_TOP | WB_VCENTER | WB_BOTTOM ); + maEdit.SetStyle( ( maEdit.GetStyle() & ~nAlignmentStyle ) | ( nStyle & nAlignmentStyle ) ); + + if ( !(nStyle & WB_NOGROUP) ) + nStyle |= WB_GROUP; + + if ( !(nStyle & WB_NOBORDER ) ) + nStyle |= WB_BORDER; + + nStyle &= ~WB_TABSTOP; + + return nStyle; +} + +// ----------------------------------------------------------------------- + +FileControl::~FileControl() +{ +} + +// ----------------------------------------------------------------------- + +void FileControl::SetText( const XubString& rStr ) +{ + maEdit.SetText( rStr ); + if ( mnFlags & FILECTRL_RESIZEBUTTONBYPATHLEN ) + Resize(); +} + +// ----------------------------------------------------------------------- + +XubString FileControl::GetText() const +{ + return maEdit.GetText(); +} + +// ----------------------------------------------------------------------- + +void FileControl::StateChanged( StateChangedType nType ) +{ + if ( nType == STATE_CHANGE_ENABLE ) + { + maEdit.Enable( IsEnabled() ); + maButton.Enable( IsEnabled() ); + } + else if ( nType == STATE_CHANGE_ZOOM ) + { + GetEdit().SetZoom( GetZoom() ); + GetButton().SetZoom( GetZoom() ); + } + else if ( nType == STATE_CHANGE_STYLE ) + { + SetStyle( ImplInitStyle( GetStyle() ) ); + } + else if ( nType == STATE_CHANGE_CONTROLFONT ) + { + GetEdit().SetControlFont( GetControlFont() ); + // Fuer den Button nur die Hoehe uebernehmen, weil in + // HTML immer Courier eingestellt wird. + Font aFont = GetButton().GetControlFont(); + aFont.SetSize( GetControlFont().GetSize() ); + GetButton().SetControlFont( aFont ); + } + else if ( nType == STATE_CHANGE_CONTROLFOREGROUND ) + { + GetEdit().SetControlForeground( GetControlForeground() ); + GetButton().SetControlForeground( GetControlForeground() ); + } + else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + GetEdit().SetControlBackground( GetControlBackground() ); + GetButton().SetControlBackground( GetControlBackground() ); + } + Window::StateChanged( nType ); +} + +// ----------------------------------------------------------------------- + +void FileControl::Resize() +{ + static long ButtonBorder = 10; + + if( mnInternalFlags & FILECTRL_INRESIZE ) + return; + mnInternalFlags |= FILECTRL_INRESIZE;//InResize = TRUE + + Size aOutSz = GetOutputSizePixel(); + long nButtonTextWidth = maButton.GetTextWidth( maButtonText ); + if ( ((mnInternalFlags & FILECTRL_ORIGINALBUTTONTEXT) == 0) || + ( nButtonTextWidth < aOutSz.Width()/3 && + ( mnFlags & FILECTRL_RESIZEBUTTONBYPATHLEN + ? ( maEdit.GetTextWidth( maEdit.GetText() ) + <= aOutSz.Width() - nButtonTextWidth - ButtonBorder ) + : TRUE ) ) + ) + { + maButton.SetText( maButtonText ); + } + else + { + XubString aSmallText( RTL_CONSTASCII_USTRINGPARAM( "..." ) ); + maButton.SetText( aSmallText ); + nButtonTextWidth = maButton.GetTextWidth( aSmallText ); + } + + long nButtonWidth = nButtonTextWidth+ButtonBorder; + maEdit.SetPosSizePixel( 0, 0, aOutSz.Width()-nButtonWidth, aOutSz.Height() ); + maButton.SetPosSizePixel( aOutSz.Width()-nButtonWidth, 0, nButtonWidth, aOutSz.Height() ); + + mnInternalFlags &= ~FILECTRL_INRESIZE; //InResize = FALSE +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( FileControl, ButtonHdl, PushButton*, EMPTYARG ) +{ + ImplBrowseFile( ); + + return 0; +} + +// ----------------------------------------------------------------------- + +void FileControl::GetFocus() +{ + maEdit.GrabFocus(); +} + +// ----------------------------------------------------------------------- + +void FileControl::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags ) +{ + WinBits nOldEditStyle = GetEdit().GetStyle(); + if ( GetStyle() & WB_BORDER ) + GetEdit().SetStyle( nOldEditStyle|WB_BORDER ); + GetEdit().Draw( pDev, rPos, rSize, nFlags ); + if ( GetStyle() & WB_BORDER ) + GetEdit().SetStyle( nOldEditStyle ); +} + +// ----------------------------------------------------------------------- + +void FileControl::SetButtonText( const XubString& rStr ) +{ + mnInternalFlags &= ~FILECTRL_ORIGINALBUTTONTEXT; + maButtonText = rStr; + Resize(); +} + +// ----------------------------------------------------------------------- + +void FileControl::ResetButtonText() +{ + mnInternalFlags |= FILECTRL_ORIGINALBUTTONTEXT; + maButtonText = XubString( SvtResId( STR_FILECTRL_BUTTONTEXT ) ); + Resize(); +} + + diff --git a/svtools/source/control/filectrl.src b/svtools/source/control/filectrl.src new file mode 100644 index 000000000000..dc8bbb5905d6 --- /dev/null +++ b/svtools/source/control/filectrl.src @@ -0,0 +1,58 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +#include "filectrl.hrc" +String STR_FILECTRL_BUTTONTEXT +{ + Text [ en-US ] = "Browse..." ; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/svtools/source/control/filectrl2.cxx b/svtools/source/control/filectrl2.cxx new file mode 100755 index 000000000000..904b643d2ae3 --- /dev/null +++ b/svtools/source/control/filectrl2.cxx @@ -0,0 +1,94 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +// this file contains code from filectrl.cxx which needs to be compiled with enabled exception hanling +#include <svtools/filectrl.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker.hpp> +#include <vcl/unohelp.hxx> +#include <tools/urlobj.hxx> +#include <osl/file.h> +#include <vcl/stdtext.hxx> +#include <tools/debug.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ui; + +void FileControl::ImplBrowseFile( ) +{ + try + { + XubString aNewText; + + const ::rtl::OUString sServiceName = ::rtl::OUString::createFromAscii( "com.sun.star.ui.dialogs.FilePicker" ); + + Reference< XMultiServiceFactory > xMSF = vcl::unohelper::GetMultiServiceFactory(); + Reference < dialogs::XFilePicker > xFilePicker( xMSF->createInstance( sServiceName ), UNO_QUERY ); + if ( xFilePicker.is() ) + { + // transform the system notation text into a file URL + ::rtl::OUString sSystemNotation = GetText(), sFileURL; + oslFileError nError = osl_getFileURLFromSystemPath( sSystemNotation.pData, &sFileURL.pData ); + if ( nError == osl_File_E_INVAL ) + sFileURL = GetText(); // #97709# Maybe URL is already a file URL... + + //#90430# Check if URL is really a file URL + ::rtl::OUString aTmp; + if ( osl_getSystemPathFromFileURL( sFileURL.pData, &aTmp.pData ) == osl_File_E_None ) + { + // initially set this directory + xFilePicker->setDisplayDirectory( sFileURL ); + } + + if ( xFilePicker.is() && xFilePicker->execute() ) + { + Sequence < rtl::OUString > aPathSeq = xFilePicker->getFiles(); + + if ( aPathSeq.getLength() ) + { + aNewText = aPathSeq[0]; + INetURLObject aObj( aNewText ); + if ( aObj.GetProtocol() == INET_PROT_FILE ) + aNewText = aObj.PathToFileName(); + SetText( aNewText ); + maEdit.GetModifyHdl().Call( &maEdit ); + } + } + } + else + ShowServiceNotAvailableError( this, sServiceName, sal_True ); + } + catch( const Exception& ) + { + DBG_ERROR( "FileControl::ImplBrowseFile: caught an exception while executing the file picker!" ); + } +} + diff --git a/svtools/source/control/fileurlbox.cxx b/svtools/source/control/fileurlbox.cxx new file mode 100644 index 000000000000..476b2864a117 --- /dev/null +++ b/svtools/source/control/fileurlbox.cxx @@ -0,0 +1,124 @@ +/************************************************************************* + * + * 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_svtools.hxx" +#include <svtools/fileurlbox.hxx> +#include <osl/file.h> +#include "svl/filenotation.hxx" + +//......................................................................... +namespace svt +{ +//......................................................................... + + //===================================================================== + //= FileURLBox + //===================================================================== + //--------------------------------------------------------------------- + FileURLBox::FileURLBox(Window* _pParent) + :SvtURLBox(_pParent, INET_PROT_FILE) + { + DisableHistory(); + } + + //--------------------------------------------------------------------- + FileURLBox::FileURLBox( Window* _pParent, WinBits _nStyle ) + :SvtURLBox( _pParent, _nStyle, INET_PROT_FILE ) + { + DisableHistory(); + } + + //--------------------------------------------------------------------- + FileURLBox::FileURLBox(Window* _pParent, const ResId& _rId) + :SvtURLBox(_pParent, _rId, INET_PROT_FILE) + { + DisableHistory(); + } + + //--------------------------------------------------------------------- + void FileURLBox::DisplayURL( const String& _rURL ) + { + String sOldText = GetText(); + + OFileNotation aTransformer( _rURL, OFileNotation::N_URL ); + String sNewText = aTransformer.get( OFileNotation::N_SYSTEM ); + SetText( sNewText ); + + if ( sOldText != sNewText ) + Modify(); + + UpdatePickList(); + } + + //--------------------------------------------------------------------- + long FileURLBox::PreNotify( NotifyEvent& _rNEvt ) + { + switch ( _rNEvt.GetType() ) + { + case EVENT_KEYINPUT: + if ( ( GetSubEdit() == _rNEvt.GetWindow() ) + && ( KEY_RETURN == _rNEvt.GetKeyEvent()->GetKeyCode().GetCode() ) + && ( IsInDropDown() ) + ) + m_sPreservedText = GetURL(); + break; + + case EVENT_LOSEFOCUS: + if ( IsWindowOrChild( _rNEvt.GetWindow() ) ) + DisplayURL( GetText() ); + break; + } + + return SvtURLBox::PreNotify(_rNEvt); + } + + //--------------------------------------------------------------------- + long FileURLBox::Notify( NotifyEvent& _rNEvt ) + { + switch ( _rNEvt.GetType() ) + { + case EVENT_KEYINPUT: + if ( ( GetSubEdit() == _rNEvt.GetWindow() ) + && ( KEY_RETURN == _rNEvt.GetKeyEvent()->GetKeyCode().GetCode() ) + && ( IsInDropDown() ) + ) + { + long nReturn = SvtURLBox::Notify(_rNEvt); + DisplayURL( m_sPreservedText ); + return nReturn; + } + break; + } + + return SvtURLBox::Notify(_rNEvt); + } + +//......................................................................... +} // namespace svt +//......................................................................... + diff --git a/svtools/source/control/fixedhyper.cxx b/svtools/source/control/fixedhyper.cxx new file mode 100644 index 000000000000..a8877d240d4e --- /dev/null +++ b/svtools/source/control/fixedhyper.cxx @@ -0,0 +1,233 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#include <svtools/fixedhyper.hxx> + +//......................................................................... +namespace svt +{ +//......................................................................... + +// class FixedHyperlink -------------------------------------------------- + +FixedHyperlink::FixedHyperlink( Window* pParent, const ResId& rResId ) : + ::toolkit::FixedHyperlinkBase( pParent, rResId ), + m_nTextLen(0) +{ + Initialize(); +} + +FixedHyperlink::FixedHyperlink( Window* pParent, WinBits nWinStyle ) : + ::toolkit::FixedHyperlinkBase( pParent, nWinStyle ), + m_nTextLen(0) +{ + Initialize(); +} + +FixedHyperlink::~FixedHyperlink() +{ +} + +void FixedHyperlink::Initialize() +{ + // saves the old pointer + m_aOldPointer = GetPointer(); + // changes the font + Font aFont = GetControlFont( ); + // to underline + aFont.SetUnderline( UNDERLINE_SINGLE ); + SetControlFont( aFont ); + // changes the color to light blue + SetTextColor( Color( COL_LIGHTBLUE ) ); + // calculates text len + m_nTextLen = GetCtrlTextWidth( GetText() ); +} + +void FixedHyperlink::MouseMove( const MouseEvent& rMEvt ) +{ + // changes the pointer if the control is enabled and the mouse is over the text. + if ( !rMEvt.IsLeaveWindow() && IsEnabled() && GetPointerPosPixel().X() < m_nTextLen ) + SetPointer( POINTER_REFHAND ); + else + SetPointer( m_aOldPointer ); +} + +void FixedHyperlink::MouseButtonUp( const MouseEvent& ) +{ + // calls the link if the control is enabled and the mouse is over the text. + if ( IsEnabled() && GetPointerPosPixel().X() < m_nTextLen ) + ImplCallEventListenersAndHandler( VCLEVENT_BUTTON_CLICK, m_aClickHdl, this ); +} + +void FixedHyperlink::RequestHelp( const HelpEvent& rHEvt ) +{ + if ( IsEnabled() && GetPointerPosPixel().X() < m_nTextLen ) + FixedText::RequestHelp( rHEvt ); +} + +void FixedHyperlink::GetFocus() +{ + SetTextColor( Color( COL_LIGHTRED ) ); + Paint( Rectangle( Point(), GetSizePixel() ) ); + ShowFocus( Rectangle( Point( 1, 1 ), Size( m_nTextLen + 4, GetSizePixel().Height() - 2 ) ) ); +} + +void FixedHyperlink::LoseFocus() +{ + SetTextColor( Color( COL_LIGHTBLUE ) ); + Paint( Rectangle( Point(), GetSizePixel() ) ); + HideFocus(); +} + +void FixedHyperlink::KeyInput( const KeyEvent& rKEvt ) +{ + switch ( rKEvt.GetKeyCode().GetCode() ) + { + case KEY_SPACE: + case KEY_RETURN: + m_aClickHdl.Call( this ); + break; + + default: + FixedText::KeyInput( rKEvt ); + } +} + +void FixedHyperlink::SetURL( const String& rNewURL ) +{ + m_sURL = rNewURL; + SetQuickHelpText( m_sURL ); +} + +String FixedHyperlink::GetURL() const +{ + return m_sURL; +} + +void FixedHyperlink::SetDescription( const String& rNewDescription ) +{ + SetText( rNewDescription ); + m_nTextLen = GetCtrlTextWidth( GetText() ); +} + +// class FixedHyperlinkImage --------------------------------------------- + +FixedHyperlinkImage::FixedHyperlinkImage( Window* pParent, const ResId& rResId ) : + FixedImage( pParent, rResId ) +{ + Initialize(); +} + +FixedHyperlinkImage::FixedHyperlinkImage( Window* pParent, WinBits nWinStyle ) : + FixedImage( pParent, nWinStyle ) +{ + Initialize(); +} + +FixedHyperlinkImage::~FixedHyperlinkImage() +{ +} + +void FixedHyperlinkImage::Initialize() +{ + // saves the old pointer + m_aOldPointer = GetPointer(); +} + +void FixedHyperlinkImage::MouseMove( const MouseEvent& rMEvt ) +{ + // changes the pointer if the control is enabled and the mouse is over the text. + if ( !rMEvt.IsLeaveWindow() && IsEnabled() ) + SetPointer( POINTER_REFHAND ); + else + SetPointer( m_aOldPointer ); +} + +void FixedHyperlinkImage::MouseButtonUp( const MouseEvent& ) +{ + // calls the link if the control is enabled and the mouse is over the text. + if ( IsEnabled() ) + ImplCallEventListenersAndHandler( VCLEVENT_BUTTON_CLICK, m_aClickHdl, this ); + + Size aSize = GetSizePixel(); + Size aImgSz = GetImage().GetSizePixel(); + if ( aSize.Width() < aImgSz.Width() ) + { + DBG_ERRORFILE("xxx"); + } +} + +void FixedHyperlinkImage::RequestHelp( const HelpEvent& rHEvt ) +{ + if ( IsEnabled() ) + FixedImage::RequestHelp( rHEvt ); +} + +void FixedHyperlinkImage::GetFocus() +{ + Paint( Rectangle( Point(), GetSizePixel() ) ); + ShowFocus( Rectangle( Point( 1, 1 ), Size( GetSizePixel().Width() - 2, GetSizePixel().Height() - 2 ) ) ); +} + +void FixedHyperlinkImage::LoseFocus() +{ + Paint( Rectangle( Point(), GetSizePixel() ) ); + HideFocus(); +} + +void FixedHyperlinkImage::KeyInput( const KeyEvent& rKEvt ) +{ + switch ( rKEvt.GetKeyCode().GetCode() ) + { + case KEY_SPACE: + case KEY_RETURN: + m_aClickHdl.Call( this ); + break; + + default: + FixedImage::KeyInput( rKEvt ); + } +} + +void FixedHyperlinkImage::SetURL( const String& rNewURL ) +{ + m_sURL = rNewURL; + SetQuickHelpText( m_sURL ); +} + +String FixedHyperlinkImage::GetURL() const +{ + return m_sURL; +} + +//......................................................................... +} // namespace svt +//......................................................................... + diff --git a/svtools/source/control/fmtfield.cxx b/svtools/source/control/fmtfield.cxx new file mode 100644 index 000000000000..5b986dc10f9d --- /dev/null +++ b/svtools/source/control/fmtfield.cxx @@ -0,0 +1,1398 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#include <stdio.h> +#include <tools/debug.hxx> +#include <comphelper/processfactory.hxx> +#include <unotools/localedatawrapper.hxx> +#include <vcl/svapp.hxx> +#include <svl/zformat.hxx> +#include <svtools/fmtfield.hxx> +#include <i18npool/mslangid.hxx> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/util/SearchOptions.hpp> +#include <com/sun/star/util/SearchAlgorithms.hpp> +#include <com/sun/star/util/SearchResult.hpp> +#include <com/sun/star/util/SearchFlags.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <unotools/syslocale.hxx> + +#ifndef REGEXP_SUPPORT +#include <map> +#endif + +#if !defined INCLUDED_RTL_MATH_HXX +#include <rtl/math.hxx> +#endif + +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; + + +#ifdef REGEXP_SUPPORT + +//============================================================================== +// regular expression to validate complete numbers, plus every fragment which can occur during the input +// of a complete number +// [+/-][{digit}*.]*{digit}*[,{digit}*][e[+/-]{digit}*] +const char __FAR_DATA szNumericInput[] = "_[-+]?([0-9]*\\,)*[0-9]*(\\.[0-9]*)?(e[-+]?[0-9]*)?_"; + // (the two _ are for normalizing it: With this, we can ensure that a to-be-checked text is always + // matched as a _whole_) +#else + +// hmm. No support for regular expression. Well, I always (not really :) wanted to write a finite automat +// so here comes a finite automat ... + +namespace validation +{ + // the states of our automat. + enum State + { + START, // at the very start of the string + NUM_START, // the very start of the number + + DIGIT_PRE_COMMA, // some pre-comma digits are read, perhaps including some thousand separators + + DIGIT_POST_COMMA, // reading digits after the comma + EXPONENT_START, // at the very start of the exponent value + // (means: not including the "e" which denotes the exponent) + EXPONENT_DIGIT, // currently reading the digits of the exponent + + END // reached the end of the string + }; + + // a row in the transition table (means the set of states to be reached from a given state) + typedef ::std::map< sal_Unicode, State > StateTransitions; + + // a single transition + typedef StateTransitions::value_type Transition; + + // the complete transition table + typedef ::std::map< State, StateTransitions > TransitionTable; + + // the validator class + class NumberValidator + { + private: + TransitionTable m_aTransitions; + const sal_Unicode m_cThSep; + const sal_Unicode m_cDecSep; + + public: + NumberValidator( const sal_Unicode _cThSep, const sal_Unicode _cDecSep ); + + sal_Bool isValidNumericFragment( const String& _rText ); + + private: + sal_Bool implValidateNormalized( const String& _rText ); + }; + + //-------------------------------------------------------------------------- + //.......................................................................... + static void lcl_insertStopTransition( StateTransitions& _rRow ) + { + _rRow.insert( Transition( '_', END ) ); + } + + //.......................................................................... + static void lcl_insertStartExponentTransition( StateTransitions& _rRow ) + { + _rRow.insert( Transition( 'e', EXPONENT_START ) ); + } + + //.......................................................................... + static void lcl_insertSignTransitions( StateTransitions& _rRow, const State eNextState ) + { + _rRow.insert( Transition( '-', eNextState ) ); + _rRow.insert( Transition( '+', eNextState ) ); + } + + //.......................................................................... + static void lcl_insertDigitTransitions( StateTransitions& _rRow, const State eNextState ) + { + for ( sal_Unicode aChar = '0'; aChar <= '9'; ++aChar ) + _rRow.insert( Transition( aChar, eNextState ) ); + } + + //.......................................................................... + static void lcl_insertCommonPreCommaTransitions( StateTransitions& _rRow, const sal_Unicode _cThSep, const sal_Unicode _cDecSep ) + { + // digits are allowed + lcl_insertDigitTransitions( _rRow, DIGIT_PRE_COMMA ); + + // the thousand separator is allowed + _rRow.insert( Transition( _cThSep, DIGIT_PRE_COMMA ) ); + + // a comma is allowed + _rRow.insert( Transition( _cDecSep, DIGIT_POST_COMMA ) ); + } + + //-------------------------------------------------------------------------- + NumberValidator::NumberValidator( const sal_Unicode _cThSep, const sal_Unicode _cDecSep ) + :m_cThSep( _cThSep ) + ,m_cDecSep( _cDecSep ) + { + // build up our transition table + + // how to procede from START + { + StateTransitions& rRow = m_aTransitions[ START ]; + rRow.insert( Transition( '_', NUM_START ) ); + // if we encounter the normalizing character, we want to procede with the number + } + + // how to procede from NUM_START + { + StateTransitions& rRow = m_aTransitions[ NUM_START ]; + + // a sign is allowed + lcl_insertSignTransitions( rRow, DIGIT_PRE_COMMA ); + + // common transitions for the two pre-comma states + lcl_insertCommonPreCommaTransitions( rRow, m_cThSep, m_cDecSep ); + + // the exponent may start here + // (this would mean string like "_+e10_", but this is a valid fragment, though no valid number) + lcl_insertStartExponentTransition( rRow ); + } + + // how to procede from DIGIT_PRE_COMMA + { + StateTransitions& rRow = m_aTransitions[ DIGIT_PRE_COMMA ]; + + // common transitions for the two pre-comma states + lcl_insertCommonPreCommaTransitions( rRow, m_cThSep, m_cDecSep ); + + // the exponent may start here + lcl_insertStartExponentTransition( rRow ); + + // the final transition indicating the end of the string + // (if there is no comma and no post-comma, then the string may end here) + lcl_insertStopTransition( rRow ); + } + + // how to procede from DIGIT_POST_COMMA + { + StateTransitions& rRow = m_aTransitions[ DIGIT_POST_COMMA ]; + + // there might be digits, which would keep the state at DIGIT_POST_COMMA + lcl_insertDigitTransitions( rRow, DIGIT_POST_COMMA ); + + // the exponent may start here + lcl_insertStartExponentTransition( rRow ); + + // the string may end here + lcl_insertStopTransition( rRow ); + } + + // how to procede from EXPONENT_START + { + StateTransitions& rRow = m_aTransitions[ EXPONENT_START ]; + + // there may be a sign + lcl_insertSignTransitions( rRow, EXPONENT_DIGIT ); + + // there may be digits + lcl_insertDigitTransitions( rRow, EXPONENT_DIGIT ); + + // the string may end here + lcl_insertStopTransition( rRow ); + } + + // how to procede from EXPONENT_DIGIT + { + StateTransitions& rRow = m_aTransitions[ EXPONENT_DIGIT ]; + + // there may be digits + lcl_insertDigitTransitions( rRow, EXPONENT_DIGIT ); + + // the string may end here + lcl_insertStopTransition( rRow ); + } + + // how to procede from END + { + /*StateTransitions& rRow =*/ m_aTransitions[ EXPONENT_DIGIT ]; + // no valid transition to leave this state + // (note that we, for consistency, nevertheless want to have a row in the table) + } + } + + //-------------------------------------------------------------------------- + sal_Bool NumberValidator::implValidateNormalized( const String& _rText ) + { + const sal_Unicode* pCheckPos = _rText.GetBuffer(); + State eCurrentState = START; + + while ( END != eCurrentState ) + { + // look up the transition row for the current state + TransitionTable::const_iterator aRow = m_aTransitions.find( eCurrentState ); + DBG_ASSERT( m_aTransitions.end() != aRow, + "NumberValidator::implValidateNormalized: invalid transition table (row not found)!" ); + + if ( m_aTransitions.end() != aRow ) + { + // look up the current character in this row + StateTransitions::const_iterator aTransition = aRow->second.find( *pCheckPos ); + if ( aRow->second.end() != aTransition ) + { + // there is a valid transition for this character + eCurrentState = aTransition->second; + ++pCheckPos; + continue; + } + } + + // if we're here, there is no valid transition + break; + } + + DBG_ASSERT( ( END != eCurrentState ) || ( 0 == *pCheckPos ), + "NumberValidator::implValidateNormalized: inconsistency!" ); + // if we're at END, then the string should be done, too - the string should be normalized, means ending + // a "_" and not containing any other "_" (except at the start), and "_" is the only possibility + // to reach the END state + + // the string is valid if and only if we reached the final state + return ( END == eCurrentState ); + } + + //-------------------------------------------------------------------------- + sal_Bool NumberValidator::isValidNumericFragment( const String& _rText ) + { + if ( !_rText.Len() ) + // empty strings are always allowed + return sal_True; + + // normalize the string + String sNormalized( RTL_CONSTASCII_STRINGPARAM( "_") ); + sNormalized.Append( _rText ); + sNormalized.AppendAscii( "_" ); + + return implValidateNormalized( sNormalized ); + } +} + +#endif + +//============================================================================== +SvNumberFormatter* FormattedField::StaticFormatter::s_cFormatter = NULL; +ULONG FormattedField::StaticFormatter::s_nReferences = 0; + +//------------------------------------------------------------------------------ +SvNumberFormatter* FormattedField::StaticFormatter::GetFormatter() +{ + if (!s_cFormatter) + { + // get the Office's locale and translate + LanguageType eSysLanguage = MsLangId::convertLocaleToLanguage( + SvtSysLocale().GetLocaleData().getLocale() ); + s_cFormatter = new SvNumberFormatter( + ::comphelper::getProcessServiceFactory(), + eSysLanguage); + } + return s_cFormatter; +} + +//------------------------------------------------------------------------------ +FormattedField::StaticFormatter::StaticFormatter() +{ + ++s_nReferences; +} + +//------------------------------------------------------------------------------ +FormattedField::StaticFormatter::~StaticFormatter() +{ + if (--s_nReferences == 0) + { + delete s_cFormatter; + s_cFormatter = NULL; + } +} + +//============================================================================== +DBG_NAME(FormattedField); + +#define INIT_MEMBERS() \ + m_aLastSelection(0,0) \ + ,m_dMinValue(0) \ + ,m_dMaxValue(0) \ + ,m_bHasMin(FALSE) \ + ,m_bHasMax(FALSE) \ + ,m_bStrictFormat(TRUE) \ + ,m_bValueDirty(TRUE) \ + ,m_bEnableEmptyField(TRUE) \ + ,m_bAutoColor(FALSE) \ + ,m_bEnableNaN(FALSE) \ + ,m_dCurrentValue(0) \ + ,m_dDefaultValue(0) \ + ,m_nFormatKey(0) \ + ,m_pFormatter(NULL) \ + ,m_dSpinSize(1) \ + ,m_dSpinFirst(-1000000) \ + ,m_dSpinLast(1000000) \ + ,m_bTreatAsNumber(TRUE) \ + ,m_pLastOutputColor(NULL) \ + ,m_bUseInputStringForFormatting(false) + +//------------------------------------------------------------------------------ +FormattedField::FormattedField(Window* pParent, WinBits nStyle, SvNumberFormatter* pInitialFormatter, INT32 nFormatKey) + :SpinField(pParent, nStyle) + ,INIT_MEMBERS() +{ + DBG_CTOR(FormattedField, NULL); + + if (pInitialFormatter) + { + m_pFormatter = pInitialFormatter; + m_nFormatKey = nFormatKey; + } +} + +//------------------------------------------------------------------------------ +FormattedField::FormattedField(Window* pParent, const ResId& rResId, SvNumberFormatter* pInitialFormatter, INT32 nFormatKey) + :SpinField(pParent, rResId) + ,INIT_MEMBERS() +{ + DBG_CTOR(FormattedField, NULL); + + if (pInitialFormatter) + { + m_pFormatter = pInitialFormatter; + m_nFormatKey = nFormatKey; + } +} + +//------------------------------------------------------------------------------ +FormattedField::~FormattedField() +{ + DBG_DTOR(FormattedField, NULL); +} + +//------------------------------------------------------------------------------ +void FormattedField::SetValidateText(const XubString& rText, const String* pErrorText) +{ + DBG_CHKTHIS(FormattedField, NULL); + + if (CheckText(rText)) + SetText(rText); + else + if (pErrorText) + ImplSetTextImpl(*pErrorText, NULL); + else + ImplSetValue(m_dDefaultValue, TRUE); +} + +//------------------------------------------------------------------------------ +void FormattedField::SetText(const XubString& rStr) +{ + DBG_CHKTHIS(FormattedField, NULL); + + SpinField::SetText(rStr); + m_bValueDirty = TRUE; +} + +//------------------------------------------------------------------------------ +void FormattedField::SetText( const XubString& rStr, const Selection& rNewSelection ) +{ + DBG_CHKTHIS(FormattedField, NULL); + + SpinField::SetText( rStr, rNewSelection ); + m_bValueDirty = TRUE; +} + +//------------------------------------------------------------------------------ +void FormattedField::SetTextFormatted(const XubString& rStr) +{ + DBG_CHKTHIS(FormattedField, NULL); + +#if defined DBG_UTIL + if (ImplGetFormatter()->IsTextFormat(m_nFormatKey)) + DBG_WARNING("FormattedField::SetTextFormatted : valid only with text formats !"); +#endif + + m_sCurrentTextValue = rStr; + + String sFormatted; + double dNumber = 0.0; + // IsNumberFormat changes the format key parameter + sal_uInt32 nTempFormatKey = static_cast< sal_uInt32 >( m_nFormatKey ); + if( IsUsingInputStringForFormatting() && + ImplGetFormatter()->IsNumberFormat(m_sCurrentTextValue, nTempFormatKey, dNumber) ) + ImplGetFormatter()->GetInputLineString(dNumber, m_nFormatKey, sFormatted); + else + ImplGetFormatter()->GetOutputString(m_sCurrentTextValue, m_nFormatKey, sFormatted, &m_pLastOutputColor); + + // calculate the new selection + Selection aSel(GetSelection()); + Selection aNewSel(aSel); + aNewSel.Justify(); + USHORT nNewLen = sFormatted.Len(); + USHORT nCurrentLen = GetText().Len(); + if ((nNewLen > nCurrentLen) && (aNewSel.Max() == nCurrentLen)) + { // the new text is longer and the cursor was behind the last char (of the old text) + if (aNewSel.Min() == 0) + { // the whole text was selected -> select the new text on the whole, too + aNewSel.Max() = nNewLen; + if (!nCurrentLen) + { // there wasn't really a previous selection (as there was no previous text), we're setting a new one -> check the selection options + ULONG nSelOptions = GetSettings().GetStyleSettings().GetSelectionOptions(); + if (nSelOptions & SELECTION_OPTION_SHOWFIRST) + { // selection should be from right to left -> swap min and max + aNewSel.Min() = aNewSel.Max(); + aNewSel.Max() = 0; + } + } + } + else if (aNewSel.Max() == aNewSel.Min()) + { // there was no selection -> set the cursor behind the new last char + aNewSel.Max() = nNewLen; + aNewSel.Min() = nNewLen; + } + } + else if (aNewSel.Max() > nNewLen) + aNewSel.Max() = nNewLen; + else + aNewSel = aSel; // don't use the justified version + SpinField::SetText(sFormatted, aNewSel); + m_bValueDirty = FALSE; +} + +//------------------------------------------------------------------------------ +String FormattedField::GetTextValue() const +{ + if (m_bValueDirty) + { + ((FormattedField*)this)->m_sCurrentTextValue = GetText(); + ((FormattedField*)this)->m_bValueDirty = FALSE; + } + return m_sCurrentTextValue; +} + +//------------------------------------------------------------------------------ +void FormattedField::EnableNotANumber( BOOL _bEnable ) +{ + if ( m_bEnableNaN == _bEnable ) + return; + + m_bEnableNaN = _bEnable; +} + +//------------------------------------------------------------------------------ +void FormattedField::SetAutoColor(BOOL _bAutomatic) +{ + if (_bAutomatic == m_bAutoColor) + return; + + m_bAutoColor = _bAutomatic; + if (m_bAutoColor) + { // if auto color is switched on, adjust the current text color, too + if (m_pLastOutputColor) + SetControlForeground(*m_pLastOutputColor); + else + SetControlForeground(); + } +} + +//------------------------------------------------------------------------------ +void FormattedField::Modify() +{ + DBG_CHKTHIS(FormattedField, NULL); + + if (!IsStrictFormat()) + { + m_bValueDirty = TRUE; + SpinField::Modify(); + return; + } + + String sCheck = GetText(); + if (CheckText(sCheck)) + { + m_sLastValidText = sCheck; + m_aLastSelection = GetSelection(); + m_bValueDirty = TRUE; + } + else + { + ImplSetTextImpl(m_sLastValidText, &m_aLastSelection); + } + + SpinField::Modify(); +} + +//------------------------------------------------------------------------------ +void FormattedField::ImplSetTextImpl(const XubString& rNew, Selection* pNewSel) +{ + DBG_CHKTHIS(FormattedField, NULL); + + if (m_bAutoColor) + { + if (m_pLastOutputColor) + SetControlForeground(*m_pLastOutputColor); + else + SetControlForeground(); + } + + if (pNewSel) + SpinField::SetText(rNew, *pNewSel); + else + { + Selection aSel(GetSelection()); + aSel.Justify(); + + USHORT nNewLen = rNew.Len(); + USHORT nCurrentLen = GetText().Len(); + + if ((nNewLen > nCurrentLen) && (aSel.Max() == nCurrentLen)) + { // new new text is longer and the cursor is behind the last char + if (aSel.Min() == 0) + { // the whole text was selected -> select the new text on the whole, too + aSel.Max() = nNewLen; + if (!nCurrentLen) + { // there wasn't really a previous selection (as there was no previous text), we're setting a new one -> check the selection options + ULONG nSelOptions = GetSettings().GetStyleSettings().GetSelectionOptions(); + if (nSelOptions & SELECTION_OPTION_SHOWFIRST) + { // selection should be from right to left -> swap min and max + aSel.Min() = aSel.Max(); + aSel.Max() = 0; + } + } + } + else if (aSel.Max() == aSel.Min()) + { // there was no selection -> set the cursor behind the new last char + aSel.Max() = nNewLen; + aSel.Min() = nNewLen; + } + } + else if (aSel.Max() > nNewLen) + aSel.Max() = nNewLen; + SpinField::SetText(rNew, aSel); + } + + m_bValueDirty = TRUE; + // muss nicht stimmen, aber sicherheitshalber ... +} + +//------------------------------------------------------------------------------ +long FormattedField::PreNotify(NotifyEvent& rNEvt) +{ + DBG_CHKTHIS(FormattedField, NULL); + if (rNEvt.GetType() == EVENT_KEYINPUT) + m_aLastSelection = GetSelection(); + return SpinField::PreNotify(rNEvt); +} + +//------------------------------------------------------------------------------ +void FormattedField::ImplSetFormatKey(ULONG nFormatKey) +{ + DBG_CHKTHIS(FormattedField, NULL); + + m_nFormatKey = nFormatKey; + BOOL bNeedFormatter = (m_pFormatter == NULL) && (nFormatKey != 0); + if (bNeedFormatter) + { + ImplGetFormatter(); // damit wird ein Standard-Formatter angelegt + + m_nFormatKey = nFormatKey; + // kann sein, dass das in dem Standard-Formatter keinen Sinn macht, aber der nimmt dann ein Default-Format an. + // Auf diese Weise kann ich einfach einen der - formatteruebergreifended gleichen - Standard-Keys setzen. + DBG_ASSERT(m_pFormatter->GetEntry(nFormatKey) != NULL, "FormattedField::ImplSetFormatKey : invalid format key !"); + // Wenn SetFormatKey aufgerufen wird, ohne dass ein Formatter existiert, muss der Key einer der Standard-Werte + // sein, der in allen Formattern (also auch in meinem neu angelegten) vorhanden ist. + } +} + +//------------------------------------------------------------------------------ +void FormattedField::SetFormatKey(ULONG nFormatKey) +{ + DBG_CHKTHIS(FormattedField, NULL); + BOOL bNoFormatter = (m_pFormatter == NULL); + ImplSetFormatKey(nFormatKey); + FormatChanged((bNoFormatter && (m_pFormatter != NULL)) ? FCT_FORMATTER : FCT_KEYONLY); +} + +//------------------------------------------------------------------------------ +void FormattedField::SetFormatter(SvNumberFormatter* pFormatter, BOOL bResetFormat) +{ + DBG_CHKTHIS(FormattedField, NULL); + + if (bResetFormat) + { + m_pFormatter = pFormatter; + + // calc the default format key from the Office's UI locale + if ( m_pFormatter ) + { + // get the Office's locale and translate + LanguageType eSysLanguage = MsLangId::convertLocaleToLanguage( + SvtSysLocale().GetLocaleData().getLocale() ); + // get the standard numeric format for this language + m_nFormatKey = m_pFormatter->GetStandardFormat( NUMBERFORMAT_NUMBER, eSysLanguage ); + } + else + m_nFormatKey = 0; + } + else + { + XubString sOldFormat; + LanguageType aOldLang; + GetFormat(sOldFormat, aOldLang); + + sal_uInt32 nDestKey = pFormatter->TestNewString(sOldFormat); + if (nDestKey == NUMBERFORMAT_ENTRY_NOT_FOUND) + { + // die Sprache des neuen Formatters + const SvNumberformat* pDefaultEntry = pFormatter->GetEntry(0); + LanguageType aNewLang = pDefaultEntry ? pDefaultEntry->GetLanguage() : LANGUAGE_DONTKNOW; + + // den alten Format-String in die neue Sprache konvertieren + USHORT nCheckPos; + short nType; + pFormatter->PutandConvertEntry(sOldFormat, nCheckPos, nType, nDestKey, aOldLang, aNewLang); + m_nFormatKey = nDestKey; + } + m_pFormatter = pFormatter; + } + + FormatChanged(FCT_FORMATTER); +} + +//------------------------------------------------------------------------------ +void FormattedField::GetFormat(XubString& rFormatString, LanguageType& eLang) const +{ + DBG_CHKTHIS(FormattedField, NULL); + const SvNumberformat* pFormatEntry = ImplGetFormatter()->GetEntry(m_nFormatKey); + DBG_ASSERT(pFormatEntry != NULL, "FormattedField::GetFormat: no number format for the given format key."); + rFormatString = pFormatEntry ? pFormatEntry->GetFormatstring() : XubString(); + eLang = pFormatEntry ? pFormatEntry->GetLanguage() : LANGUAGE_DONTKNOW; +} + +//------------------------------------------------------------------------------ +BOOL FormattedField::SetFormat(const XubString& rFormatString, LanguageType eLang) +{ + DBG_CHKTHIS(FormattedField, NULL); + sal_uInt32 nNewKey = ImplGetFormatter()->TestNewString(rFormatString, eLang); + if (nNewKey == NUMBERFORMAT_ENTRY_NOT_FOUND) + { + USHORT nCheckPos; + short nType; + XubString rFormat(rFormatString); + if (!ImplGetFormatter()->PutEntry(rFormat, nCheckPos, nType, nNewKey, eLang)) + return FALSE; + DBG_ASSERT(nNewKey != NUMBERFORMAT_ENTRY_NOT_FOUND, "FormattedField::SetFormatString : PutEntry returned an invalid key !"); + } + + if (nNewKey != m_nFormatKey) + SetFormatKey(nNewKey); + return TRUE; +} + +//------------------------------------------------------------------------------ +BOOL FormattedField::GetThousandsSep() const +{ + DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey), + "FormattedField::GetThousandsSep : your'e sure what your'e doing when setting the precision of a text format ?"); + + BOOL bThousand, IsRed; + USHORT nPrecision, nAnzLeading; + ImplGetFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nAnzLeading); + + return bThousand; +} + +//------------------------------------------------------------------------------ +void FormattedField::SetThousandsSep(BOOL _bUseSeparator) +{ + DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey), + "FormattedField::SetThousandsSep : your'e sure what your'e doing when setting the precision of a text format ?"); + + // get the current settings + BOOL bThousand, IsRed; + USHORT nPrecision, nAnzLeading; + ImplGetFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nAnzLeading); + if (bThousand == _bUseSeparator) + return; + + // we need the language for the following + LanguageType eLang; + String sFmtDescription; + GetFormat(sFmtDescription, eLang); + + // generate a new format ... + ImplGetFormatter()->GenerateFormat(sFmtDescription, m_nFormatKey, eLang, _bUseSeparator, IsRed, nPrecision, nAnzLeading); + // ... and introduce it to the formatter + USHORT nCheckPos; + sal_uInt32 nNewKey; + short nType; + ImplGetFormatter()->PutEntry(sFmtDescription, nCheckPos, nType, nNewKey, eLang); + + // set the new key + ImplSetFormatKey(nNewKey); + FormatChanged(FCT_THOUSANDSSEP); +} + +//------------------------------------------------------------------------------ +USHORT FormattedField::GetDecimalDigits() const +{ + DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey), + "FormattedField::GetDecimalDigits : your'e sure what your'e doing when setting the precision of a text format ?"); + + BOOL bThousand, IsRed; + USHORT nPrecision, nAnzLeading; + ImplGetFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nAnzLeading); + + return nPrecision; +} + +//------------------------------------------------------------------------------ +void FormattedField::SetDecimalDigits(USHORT _nPrecision) +{ + DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey), + "FormattedField::SetDecimalDigits : your'e sure what your'e doing when setting the precision of a text format ?"); + + // get the current settings + BOOL bThousand, IsRed; + USHORT nPrecision, nAnzLeading; + ImplGetFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nAnzLeading); + if (nPrecision == _nPrecision) + return; + + // we need the language for the following + LanguageType eLang; + String sFmtDescription; + GetFormat(sFmtDescription, eLang); + + // generate a new format ... + ImplGetFormatter()->GenerateFormat(sFmtDescription, m_nFormatKey, eLang, bThousand, IsRed, _nPrecision, nAnzLeading); + // ... and introduce it to the formatter + USHORT nCheckPos; + sal_uInt32 nNewKey; + short nType; + ImplGetFormatter()->PutEntry(sFmtDescription, nCheckPos, nType, nNewKey, eLang); + + // set the new key + ImplSetFormatKey(nNewKey); + FormatChanged(FCT_PRECISION); +} + +//------------------------------------------------------------------------------ +void FormattedField::FormatChanged( FORMAT_CHANGE_TYPE _nWhat ) +{ + DBG_CHKTHIS(FormattedField, NULL); + m_pLastOutputColor = NULL; + + if ( ( 0 != ( _nWhat & FCT_FORMATTER ) ) && m_pFormatter ) + m_pFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_INTL_FORMAT ); + // 95845 - 03.04.2002 - fs@openoffice.org + + ReFormat(); +} + +//------------------------------------------------------------------------------ +void FormattedField::Commit() +{ + // remember the old text + String sOld( GetText() ); + + // do the reformat + ReFormat(); + + // did the text change? + if ( GetText() != sOld ) + { // consider the field as modified + Modify(); + // but we have the most recent value now + m_bValueDirty = FALSE; + } +} + +//------------------------------------------------------------------------------ +void FormattedField::ReFormat() +{ + if (!IsEmptyFieldEnabled() || GetText().Len()) + { + if (TreatingAsNumber()) + { + double dValue = GetValue(); + if ( m_bEnableNaN && ::rtl::math::isNan( dValue ) ) + return; + ImplSetValue( dValue, TRUE ); + } + else + SetTextFormatted(GetTextValue()); + } +} + +//------------------------------------------------------------------------------ +long FormattedField::Notify(NotifyEvent& rNEvt) +{ + DBG_CHKTHIS(FormattedField, NULL); + + if ((rNEvt.GetType() == EVENT_KEYINPUT) && !IsReadOnly()) + { + const KeyEvent& rKEvt = *rNEvt.GetKeyEvent(); + USHORT nMod = rKEvt.GetKeyCode().GetModifier(); + switch ( rKEvt.GetKeyCode().GetCode() ) + { + case KEY_UP: + case KEY_DOWN: + case KEY_PAGEUP: + case KEY_PAGEDOWN: + if (!nMod && ImplGetFormatter()->IsTextFormat(m_nFormatKey)) + { + // the base class would translate this into calls to Up/Down/First/Last, + // but we don't want this if we are text-formatted + return 1; + } + } + } + + if ((rNEvt.GetType() == EVENT_COMMAND) && !IsReadOnly()) + { + const CommandEvent* pCommand = rNEvt.GetCommandEvent(); + if (pCommand->GetCommand() == COMMAND_WHEEL) + { + const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData(); + if ((pData->GetMode() == COMMAND_WHEEL_SCROLL) && ImplGetFormatter()->IsTextFormat(m_nFormatKey)) + { + // same as above : prevent the base class from doing Up/Down-calls + // (normally I should put this test into the Up/Down methods itself, shouldn't I ?) + // FS - 71553 - 19.01.00 + return 1; + } + } + } + + if (rNEvt.GetType() == EVENT_LOSEFOCUS) + { + // Sonderbehandlung fuer leere Texte + if (GetText().Len() == 0) + { + if (!IsEmptyFieldEnabled()) + { + if (TreatingAsNumber()) + { + ImplSetValue(m_dCurrentValue, TRUE); + Modify(); + } + else + { + String sNew = GetTextValue(); + if (sNew.Len()) + SetTextFormatted(sNew); + else + SetTextFormatted(m_sDefaultText); + } + m_bValueDirty = FALSE; + } + } + else + { + Commit(); + } + } + + return SpinField::Notify( rNEvt ); +} + +//------------------------------------------------------------------------------ +void FormattedField::SetMinValue(double dMin) +{ + DBG_CHKTHIS(FormattedField, NULL); + DBG_ASSERT(m_bTreatAsNumber, "FormattedField::SetMinValue : only to be used in numeric mode !"); + + m_dMinValue = dMin; + m_bHasMin = TRUE; + // fuer die Ueberpruefung des aktuellen Wertes an der neuen Grenze -> ImplSetValue + ReFormat(); +} + +//------------------------------------------------------------------------------ +void FormattedField::SetMaxValue(double dMax) +{ + DBG_CHKTHIS(FormattedField, NULL); + DBG_ASSERT(m_bTreatAsNumber, "FormattedField::SetMaxValue : only to be used in numeric mode !"); + + m_dMaxValue = dMax; + m_bHasMax = TRUE; + // fuer die Ueberpruefung des aktuellen Wertes an der neuen Grenze -> ImplSetValue + ReFormat(); +} + +//------------------------------------------------------------------------------ +void FormattedField::SetTextValue(const XubString& rText) +{ + DBG_CHKTHIS(FormattedField, NULL); + SetText(rText); + ReFormat(); +} + +//------------------------------------------------------------------------------ +void FormattedField::EnableEmptyField(BOOL bEnable) +{ + DBG_CHKTHIS(FormattedField, NULL); + if (bEnable == m_bEnableEmptyField) + return; + + m_bEnableEmptyField = bEnable; + if (!m_bEnableEmptyField && GetText().Len()==0) + ImplSetValue(m_dCurrentValue, TRUE); +} + +//------------------------------------------------------------------------------ +void FormattedField::ImplSetValue(double dVal, BOOL bForce) +{ + DBG_CHKTHIS(FormattedField, NULL); + + if (m_bHasMin && (dVal<m_dMinValue)) + dVal = m_dMinValue; + if (m_bHasMax && (dVal>m_dMaxValue)) + dVal = m_dMaxValue; + if (!bForce && (dVal == GetValue())) + return; + + DBG_ASSERT(ImplGetFormatter() != NULL, "FormattedField::ImplSetValue : can't set a value without a formatter !"); + + m_bValueDirty = FALSE; + m_dCurrentValue = dVal; + + String sNewText; + if (ImplGetFormatter()->IsTextFormat(m_nFormatKey)) + { + // zuerst die Zahl als String im Standard-Format + String sTemp; + ImplGetFormatter()->GetOutputString(dVal, 0, sTemp, &m_pLastOutputColor); + // dann den String entsprechend dem Text-Format + ImplGetFormatter()->GetOutputString(sTemp, m_nFormatKey, sNewText, &m_pLastOutputColor); + } + else + { + if( IsUsingInputStringForFormatting()) + ImplGetFormatter()->GetInputLineString(dVal, m_nFormatKey, sNewText); + else + ImplGetFormatter()->GetOutputString(dVal, m_nFormatKey, sNewText, &m_pLastOutputColor); + } + + ImplSetTextImpl(sNewText, NULL); + m_bValueDirty = FALSE; + DBG_ASSERT(CheckText(sNewText), "FormattedField::ImplSetValue : formatted string doesn't match the criteria !"); +} + +//------------------------------------------------------------------------------ +BOOL FormattedField::ImplGetValue(double& dNewVal) +{ + DBG_CHKTHIS(FormattedField, NULL); + + dNewVal = m_dCurrentValue; + if (!m_bValueDirty) + return TRUE; + + dNewVal = m_dDefaultValue; + String sText(GetText()); + if (!sText.Len()) + return TRUE; + + DBG_ASSERT(ImplGetFormatter() != NULL, "FormattedField::ImplGetValue : can't give you a current value without a formatter !"); + + sal_uInt32 nFormatKey = m_nFormatKey; // IsNumberFormat veraendert den FormatKey ... + + if (ImplGetFormatter()->IsTextFormat(nFormatKey) && m_bTreatAsNumber) + // damit wir in einem als Text formatierten Feld trotzdem eine Eingabe wie '1,1' erkennen ... + nFormatKey = 0; + + // Sonderbehandlung fuer %-Formatierung + if (ImplGetFormatter()->GetType(m_nFormatKey) == NUMBERFORMAT_PERCENT) + { + // the language of our format + LanguageType eLanguage = m_pFormatter->GetEntry(m_nFormatKey)->GetLanguage(); + // the default number format for this language + ULONG nStandardNumericFormat = m_pFormatter->GetStandardFormat(NUMBERFORMAT_NUMBER, eLanguage); + + sal_uInt32 nTempFormat = nStandardNumericFormat; + double dTemp; + if (m_pFormatter->IsNumberFormat(sText, nTempFormat, dTemp) && + NUMBERFORMAT_NUMBER == m_pFormatter->GetType(nTempFormat)) + // der String entspricht einer Number-Formatierung, hat also nur kein % + // -> append it + sText += '%'; + // (with this, a input of '3' becomes '3%', which then by the formatter is translated + // into 0.03. Without this, the formatter would give us the double 3 for an input '3', + // which equals 300 percent. + } + if (!ImplGetFormatter()->IsNumberFormat(sText, nFormatKey, dNewVal)) + return FALSE; + + + if (m_bHasMin && (dNewVal<m_dMinValue)) + dNewVal = m_dMinValue; + if (m_bHasMax && (dNewVal>m_dMaxValue)) + dNewVal = m_dMaxValue; + return TRUE; +} + +//------------------------------------------------------------------------------ +void FormattedField::SetValue(double dVal) +{ + DBG_CHKTHIS(FormattedField, NULL); + ImplSetValue(dVal, m_bValueDirty); +} + +//------------------------------------------------------------------------------ +double FormattedField::GetValue() +{ + DBG_CHKTHIS(FormattedField, NULL); + + if ( !ImplGetValue( m_dCurrentValue ) ) + { + if ( m_bEnableNaN ) + ::rtl::math::setNan( &m_dCurrentValue ); + else + m_dCurrentValue = m_dDefaultValue; + } + + m_bValueDirty = FALSE; + return m_dCurrentValue; +} + +//------------------------------------------------------------------------------ +void FormattedField::Up() +{ + DBG_CHKTHIS(FormattedField, NULL); + SetValue(GetValue() + m_dSpinSize); + // das setValue handelt Bereichsueberschreitungen (min/max) automatisch + SetModifyFlag(); + Modify(); + + SpinField::Up(); +} + +//------------------------------------------------------------------------------ +void FormattedField::Down() +{ + DBG_CHKTHIS(FormattedField, NULL); + SetValue(GetValue() - m_dSpinSize); + SetModifyFlag(); + Modify(); + + SpinField::Down(); +} + +//------------------------------------------------------------------------------ +void FormattedField::First() +{ + DBG_CHKTHIS(FormattedField, NULL); + if (m_bHasMin) + { + SetValue(m_dMinValue); + SetModifyFlag(); + Modify(); + } + + SpinField::First(); +} + +//------------------------------------------------------------------------------ +void FormattedField::Last() +{ + DBG_CHKTHIS(FormattedField, NULL); + if (m_bHasMax) + { + SetValue(m_dMaxValue); + SetModifyFlag(); + Modify(); + } + + SpinField::Last(); +} + +//------------------------------------------------------------------------------ +void FormattedField::UseInputStringForFormatting( bool bUseInputStr /* = true */ ) +{ + m_bUseInputStringForFormatting = bUseInputStr; +} + +//------------------------------------------------------------------------------ +bool FormattedField::IsUsingInputStringForFormatting() const +{ + return m_bUseInputStringForFormatting; +} + + +//============================================================================== +//------------------------------------------------------------------------------ +DoubleNumericField::~DoubleNumericField() +{ +#ifdef REGEXP_SUPPORT + delete m_pConformanceTester; +#else + delete m_pNumberValidator; +#endif +} + +//------------------------------------------------------------------------------ +void DoubleNumericField::FormatChanged(FORMAT_CHANGE_TYPE nWhat) +{ + ResetConformanceTester(); + FormattedField::FormatChanged(nWhat); +} + +//------------------------------------------------------------------------------ +BOOL DoubleNumericField::CheckText(const XubString& sText) const +{ + // We'd like to implement this using the NumberFormatter::IsNumberFormat, but unfortunately, this doesn't + // recognize fragments of numbers (like, for instance "1e", which happens during entering e.g. "1e10") + // Thus, the roundabout way via a regular expression + +#ifdef REGEXP_SUPPORT + if (!sText.Len()) + return TRUE; + + String sForceComplete = '_'; + sForceComplete += sText; + sForceComplete += '_'; + + USHORT nStart = 0, nEnd = sForceComplete.Len(); + BOOL bFound = m_pConformanceTester->SearchFrwrd(sForceComplete, &nStart, &nEnd); + + if (bFound && (nStart == 0) && (nEnd == sForceComplete.Len())) + return TRUE; + + return FALSE; +#else + return m_pNumberValidator->isValidNumericFragment( sText ); +#endif +} + +//------------------------------------------------------------------------------ +void DoubleNumericField::ResetConformanceTester() +{ + // the thousands and the decimal separator are language dependent + const SvNumberformat* pFormatEntry = ImplGetFormatter()->GetEntry(m_nFormatKey); + + sal_Unicode cSeparatorThousand = ','; + sal_Unicode cSeparatorDecimal = '.'; + if (pFormatEntry) + { + Locale aLocale; + MsLangId::convertLanguageToLocale( pFormatEntry->GetLanguage(), aLocale ); + LocaleDataWrapper aLocaleInfo(::comphelper::getProcessServiceFactory(), aLocale); + + String sSeparator = aLocaleInfo.getNumThousandSep(); + if (sSeparator.Len()) + cSeparatorThousand = sSeparator.GetBuffer()[0]; + + sSeparator = aLocaleInfo.getNumDecimalSep(); + if (sSeparator.Len()) + cSeparatorDecimal = sSeparator.GetBuffer()[0]; + } + +#ifdef REGEXP_SUPPORT + String sDescription = String::CreateFromAscii(szNumericInput); + + String sReplaceWith((sal_Unicode)'\\'); + sReplaceWith += cSeparatorThousand; + sDescription.SearchAndReplaceAscii("\\,", sReplaceWith); + + sReplaceWith = (sal_Unicode)'\\'; + sReplaceWith += cSeparatorDecimal; + sDescription.SearchAndReplaceAscii("\\.", sReplaceWith); + + delete m_pConformanceTester; + + SearchOptions aParam; + aParam.algorithmType = SearchAlgorithms_REGEXP; + aParam.searchFlag = SearchFlags::ALL_IGNORE_CASE; + aParam.searchString = sDescription; + aParam.transliterateFlags = 0; + + String sLanguage, sCountry; + ConvertLanguageToIsoNames( pFormatEntry ? pFormatEntry->GetLanguage() : LANGUAGE_ENGLISH_US, sLanguage, sCountry ); + aParam.Locale.Language = sLanguage; + aParam.Locale.Country = sCountry; + + m_pConformanceTester = new ::utl::TextSearch(aParam); +#else + delete m_pNumberValidator; + m_pNumberValidator = new validation::NumberValidator( cSeparatorThousand, cSeparatorDecimal ); +#endif +} + + +//============================================================================== + +//------------------------------------------------------------------------------ +DoubleCurrencyField::DoubleCurrencyField(Window* pParent, WinBits nStyle) + :FormattedField(pParent, nStyle) + ,m_bChangingFormat(FALSE) +{ + m_bPrependCurrSym = FALSE; + + // initialize with a system currency format + m_sCurrencySymbol = SvtSysLocale().GetLocaleData().getCurrSymbol(); + UpdateCurrencyFormat(); +} + +//------------------------------------------------------------------------------ +DoubleCurrencyField::DoubleCurrencyField(Window* pParent, const ResId& rResId) + :FormattedField(pParent, rResId) + ,m_bChangingFormat(FALSE) +{ + m_bPrependCurrSym = FALSE; + + // initialize with a system currency format + m_sCurrencySymbol = SvtSysLocale().GetLocaleData().getCurrSymbol(); + UpdateCurrencyFormat(); +} + +//------------------------------------------------------------------------------ +void DoubleCurrencyField::FormatChanged(FORMAT_CHANGE_TYPE nWhat) +{ + if (m_bChangingFormat) + { + FormattedField::FormatChanged(nWhat); + return; + } + + switch (nWhat) + { + case FCT_FORMATTER: + case FCT_PRECISION: + case FCT_THOUSANDSSEP: + // the aspects which changed don't take our currency settings into account (in fact, they most probably + // destroyed them) + UpdateCurrencyFormat(); + break; + case FCT_KEYONLY: + DBG_ERROR("DoubleCurrencyField::FormatChanged : somebody modified my key !"); + // We always build our own format from the settings we get via special methods (setCurrencySymbol etc.). + // Nobody but ourself should modifiy the format key directly ! + break; + } + + FormattedField::FormatChanged(nWhat); +} + +//------------------------------------------------------------------------------ +void DoubleCurrencyField::setCurrencySymbol(const String& _sSymbol) +{ + if (m_sCurrencySymbol == _sSymbol) + return; + + m_sCurrencySymbol = _sSymbol; + UpdateCurrencyFormat(); + FormatChanged(FCT_CURRENCY_SYMBOL); +} + +//------------------------------------------------------------------------------ +void DoubleCurrencyField::setPrependCurrSym(BOOL _bPrepend) +{ + if (m_bPrependCurrSym == _bPrepend) + return; + + m_bPrependCurrSym = _bPrepend; + UpdateCurrencyFormat(); + FormatChanged(FCT_CURRSYM_POSITION); +} + +//------------------------------------------------------------------------------ +void DoubleCurrencyField::UpdateCurrencyFormat() +{ + // the old settings + XubString sOldFormat; + LanguageType eLanguage; + GetFormat(sOldFormat, eLanguage); + BOOL bThSep = GetThousandsSep(); + USHORT nDigits = GetDecimalDigits(); + + // build a new format string with the base class' and my own settings + Locale aLocale; + MsLangId::convertLanguageToLocale( eLanguage, aLocale ); + LocaleDataWrapper aLocaleInfo(::comphelper::getProcessServiceFactory(), aLocale); + + XubString sNewFormat; + if (bThSep) + { + sNewFormat = '#'; + sNewFormat += aLocaleInfo.getNumThousandSep(); + sNewFormat.AppendAscii("##0"); + } + else + sNewFormat = '0'; + + if (nDigits) + { + sNewFormat += aLocaleInfo.getNumDecimalSep(); + + XubString sTemp; + sTemp.Fill(nDigits, '0'); + sNewFormat += sTemp; + } + + if (getPrependCurrSym()) + { + XubString sSymbol = getCurrencySymbol(); + sSymbol.EraseLeadingChars(' '); + sSymbol.EraseTrailingChars(' '); + + XubString sTemp = String::CreateFromAscii("[$"); + sTemp += sSymbol; + sTemp.AppendAscii("] "); + sTemp += sNewFormat; + + // for negative values : $ -0.00, not -$ 0.00 ... + // (the real solution would be a possibility to choose a "positive currency format" and a "negative currency format" ... + // But not now ... (and hey, you could take a formatted field for this ....)) + // FS - 31.03.00 74642 + sTemp.AppendAscii(";[$"); + sTemp += sSymbol; + sTemp.AppendAscii("] -"); + sTemp += sNewFormat; + + sNewFormat = sTemp; + } + else + { + XubString sTemp = getCurrencySymbol(); + sTemp.EraseLeadingChars(' '); + sTemp.EraseTrailingChars(' '); + + sNewFormat += String::CreateFromAscii(" [$"); + sNewFormat += sTemp; + sNewFormat += ']'; + } + + // set this new basic format + m_bChangingFormat = TRUE; + SetFormat(sNewFormat, eLanguage); + m_bChangingFormat = FALSE; +} + diff --git a/svtools/source/control/headbar.cxx b/svtools/source/control/headbar.cxx new file mode 100755 index 000000000000..7b1f2ad87108 --- /dev/null +++ b/svtools/source/control/headbar.cxx @@ -0,0 +1,1651 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#define _SV_HEADBAR_CXX +#include <svtools/headbar.hxx> +#include <tools/debug.hxx> +#ifndef _TOOLS_LIST_HXX +#include <tools/list.hxx> +#endif + +#ifndef _VCL_APP_HXX +#include <vcl/svapp.hxx> +#endif +#ifndef _VCL_HELP_HXX +#include <vcl/help.hxx> +#endif +#ifndef _VCL_IMAGE_HXX +#include <vcl/image.hxx> +#endif +#include <com/sun/star/accessibility/XAccessible.hpp> + +// ======================================================================= + +struct ImplHeadItem +{ + USHORT mnId; + HeaderBarItemBits mnBits; + long mnSize; + rtl::OString maHelpId; + Image maImage; + XubString maOutText; + XubString maText; + XubString maHelpText; + void* mpUserData; +}; + +DECLARE_LIST( ImplHeadItemList, ImplHeadItem* ) + +// ======================================================================= + +#define HEAD_ARROWSIZE1 4 +#define HEAD_ARROWSIZE2 7 + +#define HEADERBAR_TEXTOFF 2 +#define HEADERBAR_ARROWOFF 5 +#define HEADERBAR_SPLITOFF 3 + +#define HEADERBAR_DRAGOFF 4 +#define HEADERBAR_DRAGOUTOFF 15 + +#define HEAD_HITTEST_ITEM ((USHORT)0x0001) +#define HEAD_HITTEST_DIVIDER ((USHORT)0x0002) + +// ======================================================================= + +void HeaderBar::ImplInit( WinBits nWinStyle ) +{ + mpItemList = new ImplHeadItemList; + mnBorderOff1 = 0; + mnBorderOff2 = 0; + mnOffset = 0; + mnDX = 0; + mnDY = 0; + mnDragSize = 0; + mnStartPos = 0; + mnDragPos = 0; + mnMouseOff = 0; + mnCurItemId = 0; + mnItemDragPos = HEADERBAR_ITEM_NOTFOUND; + mbDrag = FALSE; + mbItemDrag = FALSE; + mbOutDrag = FALSE; + mbItemMode = FALSE; + + // StyleBits auswerten + if ( nWinStyle & WB_DRAG ) + mbDragable = TRUE; + else + mbDragable = FALSE; + if ( nWinStyle & WB_BUTTONSTYLE ) + mbButtonStyle = TRUE; + else + mbButtonStyle = FALSE; + if ( nWinStyle & WB_BORDER ) + { + mnBorderOff1 = 1; + mnBorderOff2 = 1; + } + else + { + if ( nWinStyle & WB_BOTTOMBORDER ) + mnBorderOff2 = 1; + } + + ImplInitSettings( TRUE, TRUE, TRUE ); +} + +// ----------------------------------------------------------------------- + +HeaderBar::HeaderBar( Window* pParent, WinBits nWinStyle ) : + Window( pParent, nWinStyle & WB_3DLOOK ) +{ + ImplInit( nWinStyle ); + SetSizePixel( CalcWindowSizePixel() ); +} + +// ----------------------------------------------------------------------- + +HeaderBar::HeaderBar( Window* pParent, const ResId& rResId ) : + Window( pParent, rResId ) +{ + ImplInit( rResId.GetWinBits() ); +} + +// ----------------------------------------------------------------------- + +HeaderBar::~HeaderBar() +{ + // Alle Items loeschen + ImplHeadItem* pItem = mpItemList->First(); + while ( pItem ) + { + delete pItem; + pItem = mpItemList->Next(); + } + + delete mpItemList; +} + +// ----------------------------------------------------------------------- + +void HeaderBar::ImplInitSettings( BOOL bFont, + BOOL bForeground, BOOL bBackground ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + if ( bFont ) + { + Font aFont; + aFont = rStyleSettings.GetToolFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetZoomedPointFont( aFont ); + } + + if ( bForeground || bFont ) + { + Color aColor; + if ( IsControlForeground() ) + aColor = GetControlForeground(); + else + aColor = rStyleSettings.GetButtonTextColor(); + SetTextColor( aColor ); + SetTextFillColor(); + } + + if ( bBackground ) + { + Color aColor; + if ( IsControlBackground() ) + aColor = GetControlBackground(); + else + aColor = rStyleSettings.GetFaceColor(); + SetBackground( aColor ); + } +} + +// ----------------------------------------------------------------------- + +long HeaderBar::ImplGetItemPos( USHORT nPos ) const +{ + long nX = -mnOffset; + for ( USHORT i = 0; i < nPos; i++ ) + nX += mpItemList->GetObject( i )->mnSize; + return nX; +} + +// ----------------------------------------------------------------------- + +Rectangle HeaderBar::ImplGetItemRect( USHORT nPos ) const +{ + Rectangle aRect( ImplGetItemPos( nPos ), 0, 0, mnDY-1 ); + aRect.Right() = aRect.Left() + mpItemList->GetObject( nPos )->mnSize - 1; + // Gegen Ueberlauf auf einigen Systemen testen + if ( aRect.Right() > 16000 ) + aRect.Right() = 16000; + return aRect; +} + +// ----------------------------------------------------------------------- + +USHORT HeaderBar::ImplHitTest( const Point& rPos, + long& nMouseOff, USHORT& nPos ) const +{ + ImplHeadItem* pItem; + USHORT nCount = (USHORT)mpItemList->Count(); + BOOL bLastFixed = TRUE; + long nX = -mnOffset; + + for ( USHORT i = 0; i < nCount; i++ ) + { + pItem = mpItemList->GetObject( i ); + + if ( rPos.X() < (nX+pItem->mnSize) ) + { + USHORT nMode; + + if ( !bLastFixed && (rPos.X() < (nX+HEADERBAR_SPLITOFF)) ) + { + nMode = HEAD_HITTEST_DIVIDER; + nPos = i-1; + nMouseOff = rPos.X()-nX+1; + } + else + { + nPos = i; + + if ( !(pItem->mnBits & HIB_FIXED) && (rPos.X() >= (nX+pItem->mnSize-HEADERBAR_SPLITOFF)) ) + { + nMode = HEAD_HITTEST_DIVIDER; + nMouseOff = rPos.X()-(nX+pItem->mnSize); + } + else + { + nMode = HEAD_HITTEST_ITEM; + nMouseOff = rPos.X()-nX; + } + } + + return nMode; + } + + if ( pItem->mnBits & HIB_FIXED ) + bLastFixed = TRUE; + else + bLastFixed = FALSE; + + nX += pItem->mnSize; + } + + if ( !bLastFixed ) + { + pItem = mpItemList->GetObject( nCount-1 ); + if ( (pItem->mnSize < 4) && (rPos.X() < (nX+HEADERBAR_SPLITOFF)) ) + { + nPos = nCount-1; + nMouseOff = rPos.X()-nX+1; + return HEAD_HITTEST_DIVIDER; + } + } + + return 0; +} + +// ----------------------------------------------------------------------- + +void HeaderBar::ImplInvertDrag( USHORT nStartPos, USHORT nEndPos ) +{ + Rectangle aRect1 = ImplGetItemRect( nStartPos ); + Rectangle aRect2 = ImplGetItemRect( nEndPos ); + Point aStartPos = aRect1.Center(); + Point aEndPos = aStartPos; + Rectangle aStartRect( aStartPos.X()-2, aStartPos.Y()-2, + aStartPos.X()+2, aStartPos.Y()+2 ); + + if ( nEndPos > nStartPos ) + { + aStartPos.X() += 3; + aEndPos.X() = aRect2.Right()-6; + } + else + { + aStartPos.X() -= 3; + aEndPos.X() = aRect2.Left()+6; + } + + SetRasterOp( ROP_INVERT ); + DrawRect( aStartRect ); + DrawLine( aStartPos, aEndPos ); + if ( nEndPos > nStartPos ) + { + DrawLine( Point( aEndPos.X()+1, aEndPos.Y()-3 ), + Point( aEndPos.X()+1, aEndPos.Y()+3 ) ); + DrawLine( Point( aEndPos.X()+2, aEndPos.Y()-2 ), + Point( aEndPos.X()+2, aEndPos.Y()+2 ) ); + DrawLine( Point( aEndPos.X()+3, aEndPos.Y()-1 ), + Point( aEndPos.X()+3, aEndPos.Y()+1 ) ); + DrawPixel( Point( aEndPos.X()+4, aEndPos.Y() ) ); + } + else + { + DrawLine( Point( aEndPos.X()-1, aEndPos.Y()-3 ), + Point( aEndPos.X()-1, aEndPos.Y()+3 ) ); + DrawLine( Point( aEndPos.X()-2, aEndPos.Y()-2 ), + Point( aEndPos.X()-2, aEndPos.Y()+2 ) ); + DrawLine( Point( aEndPos.X()-3, aEndPos.Y()-1 ), + Point( aEndPos.X()-3, aEndPos.Y()+1 ) ); + DrawPixel( Point( aEndPos.X()-4, aEndPos.Y() ) ); + } + SetRasterOp( ROP_OVERPAINT ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::ImplDrawItem( OutputDevice* pDev, + USHORT nPos, BOOL bHigh, BOOL bDrag, + const Rectangle& rItemRect, + const Rectangle* pRect, + ULONG ) +{ + Rectangle aRect = rItemRect; + + // Wenn kein Platz, dann brauchen wir auch nichts ausgeben + if ( aRect.GetWidth() <= 1 ) + return; + + // Feststellen, ob Rectangle ueberhaupt sichtbar + if ( pRect ) + { + if ( aRect.Right() < pRect->Left() ) + return; + else if ( aRect.Left() > pRect->Right() ) + return; + } + else + { + if ( aRect.Right() < 0 ) + return; + else if ( aRect.Left() > mnDX ) + return; + } + + ImplHeadItem* pItem = mpItemList->GetObject( nPos ); + HeaderBarItemBits nBits = pItem->mnBits; + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + // Border muss nicht gemalt werden + aRect.Top() += mnBorderOff1; + aRect.Bottom() -= mnBorderOff2; + + // Hintergrund loeschen + if ( !pRect || bDrag ) + { + if ( bDrag ) + { + pDev->SetLineColor(); + pDev->SetFillColor( rStyleSettings.GetCheckedColor() ); + pDev->DrawRect( aRect ); + } + else + pDev->DrawWallpaper( aRect, GetBackground() ); + } + + // Trennlinie malen + pDev->SetLineColor( rStyleSettings.GetDarkShadowColor() ); + pDev->DrawLine( Point( aRect.Right(), aRect.Top() ), + Point( aRect.Right(), aRect.Bottom() ) ); + + // ButtonStyle malen + // avoid 3D borders + Color aSelectionTextColor( COL_TRANSPARENT ); + if( bHigh ) + DrawSelectionBackground( aRect, 1, TRUE, FALSE, FALSE, &aSelectionTextColor ); + else if ( !mbButtonStyle || (nBits & HIB_FLAT) ) + DrawSelectionBackground( aRect, 0, TRUE, FALSE, FALSE, &aSelectionTextColor ); + + // Wenn kein Platz, dann brauchen wir auch nichts ausgeben + if ( aRect.GetWidth() < 1 ) + return; + + // Positionen und Groessen berechnen und Inhalt ausgeben + pItem->maOutText = pItem->maText; + Size aImageSize = pItem->maImage.GetSizePixel(); + Size aTxtSize( pDev->GetTextWidth( pItem->maOutText ), 0 ); + if ( pItem->maOutText.Len() ) + aTxtSize.Height() = pDev->GetTextHeight(); + long nArrowWidth = 0; + if ( nBits & (HIB_UPARROW | HIB_DOWNARROW) ) + nArrowWidth = HEAD_ARROWSIZE2+HEADERBAR_ARROWOFF; + + // Wenn kein Platz fuer Image, dann nicht ausgeben + long nTestHeight = aImageSize.Height(); + if ( !(nBits & (HIB_LEFTIMAGE | HIB_RIGHTIMAGE)) ) + nTestHeight += aTxtSize.Height(); + if ( (aImageSize.Width() > aRect.GetWidth()) || (nTestHeight > aRect.GetHeight()) ) + { + aImageSize.Width() = 0; + aImageSize.Height() = 0; + } + + // Text auf entsprechende Laenge kuerzen + BOOL bLeftText = FALSE; + long nMaxTxtWidth = aRect.GetWidth()-(HEADERBAR_TEXTOFF*2)-nArrowWidth; + if ( nBits & (HIB_LEFTIMAGE | HIB_RIGHTIMAGE) ) + nMaxTxtWidth -= aImageSize.Width(); + long nTxtWidth = aTxtSize.Width(); + if ( nTxtWidth > nMaxTxtWidth ) + { + bLeftText = TRUE; + // 3 == Len of "..." + pItem->maOutText.AppendAscii( "..." ); + do + { + pItem->maOutText.Erase( pItem->maOutText.Len()-3-1, 1 ); + nTxtWidth = pDev->GetTextWidth( pItem->maOutText ); + } + while ( (nTxtWidth > nMaxTxtWidth) && (pItem->maOutText.Len() > 3) ); + if ( pItem->maOutText.Len() == 3 ) + { + nTxtWidth = 0; + pItem->maOutText.Erase(); + } + } + + // Text/Imageposition berechnen + long nTxtPos; + if ( !bLeftText && (nBits & HIB_RIGHT) ) + { + nTxtPos = aRect.Right()-nTxtWidth-HEADERBAR_TEXTOFF; + if ( nBits & HIB_RIGHTIMAGE ) + nTxtPos -= aImageSize.Width(); + } + else if ( !bLeftText && (nBits & HIB_CENTER) ) + { + long nTempWidth = nTxtWidth; + if ( nBits & (HIB_LEFTIMAGE | HIB_RIGHTIMAGE) ) + nTempWidth += aImageSize.Width(); + nTxtPos = aRect.Left()+(aRect.GetWidth()-nTempWidth)/2; + if ( nBits & HIB_LEFTIMAGE ) + nTxtPos += aImageSize.Width(); + if ( nArrowWidth ) + { + if ( nTxtPos+nTxtWidth+nArrowWidth >= aRect.Right() ) + { + nTxtPos = aRect.Left()+HEADERBAR_TEXTOFF; + if ( nBits & HIB_LEFTIMAGE ) + nTxtPos += aImageSize.Width(); + } + } + } + else + { + nTxtPos = aRect.Left()+HEADERBAR_TEXTOFF; + if ( nBits & HIB_LEFTIMAGE ) + nTxtPos += aImageSize.Width(); + if ( nBits & HIB_RIGHT ) + nTxtPos += nArrowWidth; + } + + // TextPosition berechnen + long nTxtPosY = 0; + if ( pItem->maOutText.Len() || (nArrowWidth && aTxtSize.Height()) ) + { + if ( nBits & HIB_TOP ) + { + nTxtPosY = aRect.Top(); + if ( !(nBits & (HIB_LEFTIMAGE | HIB_RIGHTIMAGE)) ) + nTxtPosY += aImageSize.Height(); + } + else if ( nBits & HIB_BOTTOM ) + nTxtPosY = aRect.Bottom()-aTxtSize.Height(); + else + { + long nTempHeight = aTxtSize.Height(); + if ( !(nBits & (HIB_LEFTIMAGE | HIB_RIGHTIMAGE)) ) + nTempHeight += aImageSize.Height(); + nTxtPosY = aRect.Top()+((aRect.GetHeight()-nTempHeight)/2); + if ( !(nBits & (HIB_LEFTIMAGE | HIB_RIGHTIMAGE)) ) + nTxtPosY += aImageSize.Height(); + } + } + + // Text ausgebeben + if ( pItem->maOutText.Len() ) + { + if( aSelectionTextColor != Color( COL_TRANSPARENT ) ) + { + pDev->Push( PUSH_TEXTCOLOR ); + pDev->SetTextColor( aSelectionTextColor ); + } + if ( IsEnabled() ) + pDev->DrawText( Point( nTxtPos, nTxtPosY ), pItem->maOutText ); + else + pDev->DrawCtrlText( Point( nTxtPos, nTxtPosY ), pItem->maOutText, 0, STRING_LEN, TEXT_DRAW_DISABLE ); + if( aSelectionTextColor != Color( COL_TRANSPARENT ) ) + pDev->Pop(); + } + + // Wenn Image vorhanden, Position berechnen und ausgeben + long nImagePosY = 0; + if ( aImageSize.Width() && aImageSize.Height() ) + { + long nImagePos = nTxtPos; + if ( nBits & HIB_LEFTIMAGE ) + { + nImagePos -= aImageSize.Width(); + if ( nBits & HIB_RIGHT ) + nImagePos -= nArrowWidth; + } + else if ( nBits & HIB_RIGHTIMAGE ) + { + nImagePos += nTxtWidth; + if ( !(nBits & HIB_RIGHT) ) + nImagePos += nArrowWidth; + } + else + { + if ( nBits & HIB_RIGHT ) + nImagePos = aRect.Right()-aImageSize.Width(); + else if ( nBits & HIB_CENTER ) + nImagePos = aRect.Left()+(aRect.GetWidth()-aImageSize.Width())/2; + else + nImagePos = aRect.Left()+HEADERBAR_TEXTOFF; + } + + if ( nBits & HIB_TOP ) + nImagePosY = aRect.Top(); + else if ( nBits & HIB_BOTTOM ) + { + nImagePosY = aRect.Bottom()-aImageSize.Height(); + if ( !(nBits & (HIB_LEFTIMAGE | HIB_RIGHTIMAGE)) ) + nImagePosY -= aTxtSize.Height(); + } + else + { + long nTempHeight = aImageSize.Height(); + if ( !(nBits & (HIB_LEFTIMAGE | HIB_RIGHTIMAGE)) ) + nTempHeight += aTxtSize.Height(); + nImagePosY = aRect.Top()+((aRect.GetHeight()-nTempHeight)/2); + } + if ( nImagePos+aImageSize.Width() <= aRect.Right() ) + { + USHORT nStyle = 0; + if ( !IsEnabled() ) + nStyle |= IMAGE_DRAW_DISABLE; + pDev->DrawImage( Point( nImagePos, nImagePosY ), pItem->maImage, nStyle ); + } + } + + if ( nBits & (HIB_UPARROW | HIB_DOWNARROW) ) + { + long nArrowX = nTxtPos; + if ( nBits & HIB_RIGHT ) + nArrowX -= nArrowWidth; + else + nArrowX += nTxtWidth+HEADERBAR_ARROWOFF; + if ( !(nBits & (HIB_LEFTIMAGE | HIB_RIGHTIMAGE)) && !pItem->maText.Len() ) + { + if ( nBits & HIB_RIGHT ) + nArrowX -= aImageSize.Width(); + else + nArrowX += aImageSize.Width(); + } + + // Feststellen, ob Platz genug ist, das Item zu malen + BOOL bDraw = TRUE; + if ( nArrowX < aRect.Left()+HEADERBAR_TEXTOFF ) + bDraw = FALSE; + else if ( nArrowX+HEAD_ARROWSIZE2 > aRect.Right() ) + bDraw = FALSE; + + if ( bDraw ) + { + long nArrowY; + if ( aTxtSize.Height() ) + nArrowY = nTxtPosY+(aTxtSize.Height()/2); + else if ( aImageSize.Width() && aImageSize.Height() ) + nArrowY = nImagePosY+(aImageSize.Height()/2); + else + { + if ( nBits & HIB_TOP ) + nArrowY = aRect.Top()+1; + else if ( nBits & HIB_BOTTOM ) + nArrowY = aRect.Bottom()-HEAD_ARROWSIZE2-1; + else + nArrowY = aRect.Top()+((aRect.GetHeight()-HEAD_ARROWSIZE2)/2);; + } + nArrowY -= HEAD_ARROWSIZE1-1; + if ( nBits & HIB_DOWNARROW ) + { + pDev->SetLineColor( rStyleSettings.GetLightColor() ); + pDev->DrawLine( Point( nArrowX, nArrowY ), + Point( nArrowX+HEAD_ARROWSIZE2, nArrowY ) ); + pDev->DrawLine( Point( nArrowX, nArrowY ), + Point( nArrowX+HEAD_ARROWSIZE1, nArrowY+HEAD_ARROWSIZE2 ) ); + pDev->SetLineColor( rStyleSettings.GetShadowColor() ); + pDev->DrawLine( Point( nArrowX+HEAD_ARROWSIZE1, nArrowY+HEAD_ARROWSIZE2 ), + Point( nArrowX+HEAD_ARROWSIZE2, nArrowY ) ); + } + else + { + pDev->SetLineColor( rStyleSettings.GetLightColor() ); + pDev->DrawLine( Point( nArrowX, nArrowY+HEAD_ARROWSIZE2 ), + Point( nArrowX+HEAD_ARROWSIZE1, nArrowY ) ); + pDev->SetLineColor( rStyleSettings.GetShadowColor() ); + pDev->DrawLine( Point( nArrowX, nArrowY+HEAD_ARROWSIZE2 ), + Point( nArrowX+HEAD_ARROWSIZE2, nArrowY+HEAD_ARROWSIZE2 ) ); + pDev->DrawLine( Point( nArrowX+HEAD_ARROWSIZE2, nArrowY+HEAD_ARROWSIZE2 ), + Point( nArrowX+HEAD_ARROWSIZE1, nArrowY ) ); + } + } + } + + // Gegebenenfalls auch UserDraw aufrufen + if ( nBits & HIB_USERDRAW ) + { + Region aRegion( aRect ); + if ( pRect ) + aRegion.Intersect( *pRect ); + pDev->SetClipRegion( aRegion ); + UserDrawEvent aODEvt( pDev, aRect, pItem->mnId ); + UserDraw( aODEvt ); + pDev->SetClipRegion(); + } +} + +// ----------------------------------------------------------------------- + +void HeaderBar::ImplDrawItem( USHORT nPos, BOOL bHigh, BOOL bDrag, + const Rectangle* pRect ) +{ + Rectangle aRect = ImplGetItemRect( nPos ); + ImplDrawItem( this, nPos, bHigh, bDrag, aRect, pRect, 0 ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::ImplUpdate( USHORT nPos, BOOL bEnd, BOOL bDirect ) +{ + if ( IsVisible() && IsUpdateMode() ) + { + if ( !bDirect ) + { + Rectangle aRect; + USHORT nItemCount = (USHORT)(mpItemList->Count()); + if ( nPos < nItemCount ) + aRect = ImplGetItemRect( nPos ); + else + { + aRect.Bottom() = mnDY-1; + if ( nItemCount ) + aRect.Left() = ImplGetItemRect( nItemCount-1 ).Right(); + } + if ( bEnd ) + aRect.Right() = mnDX-1; + aRect.Top() += mnBorderOff1; + aRect.Bottom() -= mnBorderOff2; + Invalidate( aRect ); + } + else + { + for ( USHORT i = nPos; i < mpItemList->Count(); i++ ) + ImplDrawItem( i ); + if ( bEnd ) + { + Rectangle aRect = ImplGetItemRect( (USHORT)mpItemList->Count() ); + aRect.Left() = aRect.Right(); + aRect.Right() = mnDX-1; + if ( aRect.Left() < aRect.Right() ) + { + aRect.Top() += mnBorderOff1; + aRect.Bottom() -= mnBorderOff2; + Erase( aRect ); + } + } + } + } +} + +// ----------------------------------------------------------------------- + +void HeaderBar::ImplStartDrag( const Point& rMousePos, BOOL bCommand ) +{ + USHORT nPos; + USHORT nHitTest = ImplHitTest( rMousePos, mnMouseOff, nPos ); + if ( nHitTest ) + { + mbDrag = FALSE; + ImplHeadItem* pItem = mpItemList->GetObject( nPos ); + if ( nHitTest & HEAD_HITTEST_DIVIDER ) + mbDrag = TRUE; + else + { + if ( ((pItem->mnBits & HIB_CLICKABLE) && !(pItem->mnBits & HIB_FLAT)) || + (mbDragable && !(pItem->mnBits & HIB_FIXEDPOS)) ) + { + mbItemMode = TRUE; + mbDrag = TRUE; + if ( bCommand ) + { + if ( mbDragable ) + mbItemDrag = TRUE; + else + { + mbItemMode = FALSE; + mbDrag = FALSE; + } + } + } + else + { + if ( !bCommand ) + { + mnCurItemId = pItem->mnId; + Select(); + mnCurItemId = 0; + } + } + } + + if ( mbDrag ) + { + mbOutDrag = FALSE; + mnCurItemId = pItem->mnId; + mnItemDragPos = nPos; + StartTracking(); + mnStartPos = rMousePos.X()-mnMouseOff; + mnDragPos = mnStartPos; + StartDrag(); + if ( mbItemMode ) + ImplDrawItem( nPos, TRUE, mbItemDrag ); + else + { + Rectangle aSizeRect( mnDragPos, 0, mnDragPos, mnDragSize+mnDY ); + ShowTracking( aSizeRect, SHOWTRACK_SPLIT ); + } + } + else + mnMouseOff = 0; + } +} + +// ----------------------------------------------------------------------- + +void HeaderBar::ImplDrag( const Point& rMousePos ) +{ + BOOL bNewOutDrag; + USHORT nPos = GetItemPos( mnCurItemId ); + + mnDragPos = rMousePos.X()-mnMouseOff; + if ( mbItemMode ) + { + Rectangle aItemRect = ImplGetItemRect( nPos ); + if ( aItemRect.IsInside( rMousePos ) ) + bNewOutDrag = FALSE; + else + bNewOutDrag = TRUE; + + // Evt. ItemDrag anschalten + if ( bNewOutDrag && mbDragable && !mbItemDrag && + !(mpItemList->GetObject(nPos)->mnBits & HIB_FIXEDPOS) ) + { + if ( (rMousePos.Y() >= aItemRect.Top()) && (rMousePos.Y() <= aItemRect.Bottom()) ) + { + mbItemDrag = TRUE; + ImplDrawItem( nPos, TRUE, mbItemDrag ); + } + } + + USHORT nOldItemDragPos = mnItemDragPos; + if ( mbItemDrag ) + { + if ( (rMousePos.Y() < -HEADERBAR_DRAGOUTOFF) || (rMousePos.Y() > mnDY+HEADERBAR_DRAGOUTOFF) ) + bNewOutDrag = TRUE; + else + bNewOutDrag = FALSE; + + if ( bNewOutDrag ) + mnItemDragPos = HEADERBAR_ITEM_NOTFOUND; + else + { + USHORT nTempId = GetItemId( Point( rMousePos.X(), 2 ) ); + if ( nTempId ) + mnItemDragPos = GetItemPos( nTempId ); + else + { + if ( rMousePos.X() <= 0 ) + mnItemDragPos = 0; + else + mnItemDragPos = GetItemCount()-1; + } + + // Nicht verschiebbare Items aussparen + if ( mnItemDragPos < nPos ) + { + while ( (mpItemList->GetObject(mnItemDragPos)->mnBits & HIB_FIXEDPOS) && + (mnItemDragPos < nPos) ) + mnItemDragPos++; + } + else if ( mnItemDragPos > nPos ) + { + while ( (mpItemList->GetObject(mnItemDragPos)->mnBits & HIB_FIXEDPOS) && + (mnItemDragPos > nPos) ) + mnItemDragPos--; + } + } + + if ( (mnItemDragPos != nOldItemDragPos) && + (nOldItemDragPos != nPos) && + (nOldItemDragPos != HEADERBAR_ITEM_NOTFOUND) ) + { + ImplInvertDrag( nPos, nOldItemDragPos ); + ImplDrawItem( nOldItemDragPos ); + } + } + + if ( bNewOutDrag != mbOutDrag ) + ImplDrawItem( nPos, !bNewOutDrag, mbItemDrag ); + + if ( mbItemDrag ) + { + if ( (mnItemDragPos != nOldItemDragPos) && + (mnItemDragPos != nPos) && + (mnItemDragPos != HEADERBAR_ITEM_NOTFOUND) ) + { + ImplDrawItem( mnItemDragPos, FALSE, TRUE ); + ImplInvertDrag( nPos, mnItemDragPos ); + } + } + + mbOutDrag = bNewOutDrag; + } + else + { + Rectangle aItemRect = ImplGetItemRect( nPos ); + if ( mnDragPos < aItemRect.Left() ) + mnDragPos = aItemRect.Left(); + if ( (mnDragPos < 0) || (mnDragPos > mnDX-1) ) + HideTracking(); + else + { + Rectangle aSizeRect( mnDragPos, 0, mnDragPos, mnDragSize+mnDY ); + ShowTracking( aSizeRect, SHOWTRACK_SPLIT ); + } + } + + Drag(); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::ImplEndDrag( BOOL bCancel ) +{ + HideTracking(); + + if ( bCancel || mbOutDrag ) + { + if ( mbItemMode && (!mbOutDrag || mbItemDrag) ) + { + USHORT nPos = GetItemPos( mnCurItemId ); + ImplDrawItem( nPos ); + } + + mnCurItemId = 0; + } + else + { + USHORT nPos = GetItemPos( mnCurItemId ); + if ( mbItemMode ) + { + if ( mbItemDrag ) + { + Pointer aPointer( POINTER_ARROW ); + SetPointer( aPointer ); + if ( (mnItemDragPos != nPos) && + (mnItemDragPos != HEADERBAR_ITEM_NOTFOUND) ) + { + ImplInvertDrag( nPos, mnItemDragPos ); + MoveItem( mnCurItemId, mnItemDragPos ); + } + else + ImplDrawItem( nPos ); + } + else + { + Select(); + ImplUpdate( nPos ); + } + } + else + { + long nDelta = mnDragPos - mnStartPos; + if ( nDelta ) + { + ImplHeadItem* pItem = mpItemList->GetObject( nPos ); + pItem->mnSize += nDelta; + ImplUpdate( nPos, TRUE ); + } + } + } + + mbDrag = FALSE; + EndDrag(); + mnCurItemId = 0; + mnItemDragPos = HEADERBAR_ITEM_NOTFOUND; + mbOutDrag = FALSE; + mbItemMode = FALSE; + mbItemDrag = FALSE; +} + +// ----------------------------------------------------------------------- + +void HeaderBar::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( rMEvt.IsLeft() ) + { + if ( rMEvt.GetClicks() == 2 ) + { + long nTemp; + USHORT nPos; + USHORT nHitTest = ImplHitTest( rMEvt.GetPosPixel(), nTemp, nPos ); + if ( nHitTest ) + { + ImplHeadItem* pItem = mpItemList->GetObject( nPos ); + if ( nHitTest & HEAD_HITTEST_DIVIDER ) + mbItemMode = FALSE; + else + mbItemMode = TRUE; + mnCurItemId = pItem->mnId; + DoubleClick(); + mbItemMode = FALSE; + mnCurItemId = 0; + } + } + else + ImplStartDrag( rMEvt.GetPosPixel(), FALSE ); + } +} + +// ----------------------------------------------------------------------- + +void HeaderBar::MouseMove( const MouseEvent& rMEvt ) +{ + long nTemp1; + USHORT nTemp2; + PointerStyle eStyle = POINTER_ARROW; + USHORT nHitTest = ImplHitTest( rMEvt.GetPosPixel(), nTemp1, nTemp2 ); + + if ( nHitTest & HEAD_HITTEST_DIVIDER ) + eStyle = POINTER_HSIZEBAR; + Pointer aPtr( eStyle ); + SetPointer( aPtr ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::Tracking( const TrackingEvent& rTEvt ) +{ + Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel(); + + if ( rTEvt.IsTrackingEnded() ) + ImplEndDrag( rTEvt.IsTrackingCanceled() ); + else + ImplDrag( aMousePos ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::Paint( const Rectangle& rRect ) +{ + if ( mnBorderOff1 || mnBorderOff2 ) + { + SetLineColor( GetSettings().GetStyleSettings().GetDarkShadowColor() ); + if ( mnBorderOff1 ) + DrawLine( Point( 0, 0 ), Point( mnDX-1, 0 ) ); + if ( mnBorderOff2 ) + DrawLine( Point( 0, mnDY-1 ), Point( mnDX-1, mnDY-1 ) ); + // #i40393# draw left and right border, if WB_BORDER was set in ImplInit() + if ( mnBorderOff1 && mnBorderOff2 ) + { + DrawLine( Point( 0, 0 ), Point( 0, mnDY-1 ) ); + DrawLine( Point( mnDX-1, 0 ), Point( mnDX-1, mnDY-1 ) ); + } + } + + USHORT nCurItemPos; + if ( mbDrag ) + nCurItemPos = GetItemPos( mnCurItemId ); + else + nCurItemPos = HEADERBAR_ITEM_NOTFOUND; + USHORT nItemCount = (USHORT)mpItemList->Count(); + for ( USHORT i = 0; i < nItemCount; i++ ) + ImplDrawItem( i, (i == nCurItemPos) ? TRUE : FALSE, FALSE, &rRect ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, + ULONG nFlags ) +{ + Point aPos = pDev->LogicToPixel( rPos ); + Size aSize = pDev->LogicToPixel( rSize ); + Rectangle aRect( aPos, aSize ); + Font aFont = GetDrawPixelFont( pDev ); + + pDev->Push(); + pDev->SetMapMode(); + pDev->SetFont( aFont ); + if ( nFlags & WINDOW_DRAW_MONO ) + pDev->SetTextColor( Color( COL_BLACK ) ); + else + pDev->SetTextColor( GetTextColor() ); + pDev->SetTextFillColor(); + + if ( !(nFlags & WINDOW_DRAW_NOBACKGROUND) ) + { + pDev->DrawWallpaper( aRect, GetBackground() ); + if ( mnBorderOff1 || mnBorderOff2 ) + { + pDev->SetLineColor( GetSettings().GetStyleSettings().GetDarkShadowColor() ); + if ( mnBorderOff1 ) + pDev->DrawLine( aRect.TopLeft(), Point( aRect.Right(), aRect.Top() ) ); + if ( mnBorderOff2 ) + pDev->DrawLine( Point( aRect.Left(), aRect.Bottom() ), Point( aRect.Right(), aRect.Bottom() ) ); + // #i40393# draw left and right border, if WB_BORDER was set in ImplInit() + if ( mnBorderOff1 && mnBorderOff2 ) + { + pDev->DrawLine( aRect.TopLeft(), Point( aRect.Left(), aRect.Bottom() ) ); + pDev->DrawLine( Point( aRect.Right(), aRect.Top() ), Point( aRect.Right(), aRect.Bottom() ) ); + } + } + } + + Rectangle aItemRect( aRect ); +// aItemRect.Bottom()--; + USHORT nItemCount = (USHORT)mpItemList->Count(); + for ( USHORT i = 0; i < nItemCount; i++ ) + { + aItemRect.Left() = aRect.Left()+ImplGetItemPos( i ); + aItemRect.Right() = aItemRect.Left() + mpItemList->GetObject( i )->mnSize - 1; + // Gegen Ueberlauf auf einigen Systemen testen + if ( aItemRect.Right() > 16000 ) + aItemRect.Right() = 16000; + Region aRegion( aRect ); + pDev->SetClipRegion( aRegion ); + ImplDrawItem( pDev, i, FALSE, FALSE, aItemRect, &aRect, nFlags ); + pDev->SetClipRegion(); + } + + pDev->Pop(); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::Resize() +{ + Size aSize = GetOutputSizePixel(); + if ( IsVisible() && (mnDY != aSize.Height()) ) + Invalidate(); + mnDX = aSize.Width(); + mnDY = aSize.Height(); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::Command( const CommandEvent& rCEvt ) +{ + if ( rCEvt.IsMouseEvent() && (rCEvt.GetCommand() == COMMAND_STARTDRAG) && !mbDrag ) + { + ImplStartDrag( rCEvt.GetMousePosPixel(), TRUE ); + return; + } + + Window::Command( rCEvt ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::RequestHelp( const HelpEvent& rHEvt ) +{ + USHORT nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) ); + if ( nItemId ) + { + if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) ) + { + Rectangle aItemRect = GetItemRect( nItemId ); + Point aPt = OutputToScreenPixel( aItemRect.TopLeft() ); + aItemRect.Left() = aPt.X(); + aItemRect.Top() = aPt.Y(); + aPt = OutputToScreenPixel( aItemRect.BottomRight() ); + aItemRect.Right() = aPt.X(); + aItemRect.Bottom() = aPt.Y(); + + XubString aStr = GetHelpText( nItemId ); + if ( !aStr.Len() || !(rHEvt.GetMode() & HELPMODE_BALLOON) ) + { + ImplHeadItem* pItem = mpItemList->GetObject( GetItemPos( nItemId ) ); + // Wir zeigen die Quick-Hilfe nur an, wenn Text nicht + // vollstaendig sichtbar, ansonsten zeigen wir den Hilfetext + // an, wenn das Item keinen Text besitzt + if ( pItem->maOutText != pItem->maText ) + aStr = pItem->maText; + else if ( pItem->maText.Len() ) + aStr.Erase(); + } + + if ( aStr.Len() ) + { + if ( rHEvt.GetMode() & HELPMODE_BALLOON ) + Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr ); + else + Help::ShowQuickHelp( this, aItemRect, aStr ); + return; + } + } + else if ( rHEvt.GetMode() & HELPMODE_EXTENDED ) + { + rtl::OUString aHelpId( rtl::OStringToOUString( GetHelpId( nItemId ), RTL_TEXTENCODING_UTF8 ) ); + if ( aHelpId.getLength() ) + { + // Wenn eine Hilfe existiert, dann ausloesen + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + pHelp->Start( aHelpId, this ); + return; + } + } + } + + Window::RequestHelp( rHEvt ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::StateChanged( StateChangedType nType ) +{ + Window::StateChanged( nType ); + + if ( nType == STATE_CHANGE_ENABLE ) + Invalidate(); + else if ( (nType == STATE_CHANGE_ZOOM) || + (nType == STATE_CHANGE_CONTROLFONT) ) + { + ImplInitSettings( TRUE, FALSE, FALSE ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLFOREGROUND ) + { + ImplInitSettings( FALSE, TRUE, FALSE ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings( FALSE, FALSE, TRUE ); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void HeaderBar::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + ImplInitSettings( TRUE, TRUE, TRUE ); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void HeaderBar::UserDraw( const UserDrawEvent& ) +{ +} + +// ----------------------------------------------------------------------- + +void HeaderBar::StartDrag() +{ + maStartDragHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::Drag() +{ + maDragHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::EndDrag() +{ + maEndDragHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::Select() +{ + maSelectHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::DoubleClick() +{ + maDoubleClickHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::InsertItem( USHORT nItemId, const Image& rImage, + long nSize, HeaderBarItemBits nBits, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "HeaderBar::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == HEADERBAR_ITEM_NOTFOUND, + "HeaderBar::InsertItem(): ItemId already exists" ); + + // Item anlegen und in die Liste einfuegen + ImplHeadItem* pItem = new ImplHeadItem; + pItem->mnId = nItemId; + pItem->mnBits = nBits; + pItem->mnSize = nSize; + pItem->maImage = rImage; + pItem->mpUserData = 0; + mpItemList->Insert( pItem, nPos ); + + // Ausgabe updaten + ImplUpdate( nPos, TRUE ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::InsertItem( USHORT nItemId, const XubString& rText, + long nSize, HeaderBarItemBits nBits, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "HeaderBar::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == HEADERBAR_ITEM_NOTFOUND, + "HeaderBar::InsertItem(): ItemId already exists" ); + + // Item anlegen und in die Liste einfuegen + ImplHeadItem* pItem = new ImplHeadItem; + pItem->mnId = nItemId; + pItem->mnBits = nBits; + pItem->mnSize = nSize; + pItem->maText = rText; + pItem->mpUserData = 0; + mpItemList->Insert( pItem, nPos ); + + // Ausgabe updaten + ImplUpdate( nPos, TRUE ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::InsertItem( USHORT nItemId, + const Image& rImage, const XubString& rText, + long nSize, HeaderBarItemBits nBits, + USHORT nPos ) +{ + DBG_ASSERT( nItemId, "HeaderBar::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == HEADERBAR_ITEM_NOTFOUND, + "HeaderBar::InsertItem(): ItemId already exists" ); + + // Item anlegen und in die Liste einfuegen + ImplHeadItem* pItem = new ImplHeadItem; + pItem->mnId = nItemId; + pItem->mnBits = nBits; + pItem->mnSize = nSize; + pItem->maImage = rImage; + pItem->maText = rText; + pItem->mpUserData = 0; + mpItemList->Insert( pItem, nPos ); + + // Ausgabe updaten + ImplUpdate( nPos, TRUE ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::RemoveItem( USHORT nItemId ) +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + { + ImplHeadItem* pItem = mpItemList->Remove( nPos ); + delete pItem; + ImplUpdate( nPos, TRUE ); + } +} + +// ----------------------------------------------------------------------- + +void HeaderBar::MoveItem( USHORT nItemId, USHORT nNewPos ) +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + { + if ( nPos != nNewPos ) + { + ImplHeadItem* pItem = mpItemList->Remove( nPos ); + if ( nNewPos < nPos ) + nPos = nNewPos; + mpItemList->Insert( pItem, nNewPos ); + ImplUpdate( nPos, TRUE ); + } + } +} + +// ----------------------------------------------------------------------- + +void HeaderBar::Clear() +{ + // Alle Items loeschen + ImplHeadItem* pItem = mpItemList->First(); + while ( pItem ) + { + delete pItem; + pItem = mpItemList->Next(); + } + mpItemList->Clear(); + + ImplUpdate( 0, TRUE ); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::SetOffset( long nNewOffset ) +{ + // Hier erstmal neu zeichnen, damit mit alten Offset noch das + // richtige gemalt wird + //Update(); + + // Bereich verschieben + Rectangle aRect( 0, mnBorderOff1, mnDX-1, mnDY-mnBorderOff1-mnBorderOff2-1 ); + long nDelta = mnOffset-nNewOffset; + mnOffset = nNewOffset; + Scroll( nDelta, 0, aRect ); +} + +// ----------------------------------------------------------------------- + +USHORT HeaderBar::GetItemCount() const +{ + return (USHORT)mpItemList->Count(); +} + +// ----------------------------------------------------------------------- + +USHORT HeaderBar::GetItemPos( USHORT nItemId ) const +{ + ImplHeadItem* pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->mnId == nItemId ) + return (USHORT)mpItemList->GetCurPos(); + pItem = mpItemList->Next(); + } + + return HEADERBAR_ITEM_NOTFOUND; +} + +// ----------------------------------------------------------------------- + +USHORT HeaderBar::GetItemId( USHORT nPos ) const +{ + ImplHeadItem* pItem = mpItemList->GetObject( nPos ); + if ( pItem ) + return pItem->mnId; + else + return 0; +} + +// ----------------------------------------------------------------------- + +USHORT HeaderBar::GetItemId( const Point& rPos ) const +{ + USHORT nPos = 0; + while ( nPos < mpItemList->Count() ) + { + if ( ImplGetItemRect( nPos ).IsInside( rPos ) ) + return GetItemId( nPos ); + + nPos++; + } + + return 0; +} + +// ----------------------------------------------------------------------- + +Rectangle HeaderBar::GetItemRect( USHORT nItemId ) const +{ + Rectangle aRect; + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + aRect = ImplGetItemRect( nPos ); + return aRect; +} + +// ----------------------------------------------------------------------- + +void HeaderBar::SetItemSize( USHORT nItemId, long nNewSize ) +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + { + ImplHeadItem* pItem = mpItemList->GetObject( nPos ); + if ( pItem->mnSize != nNewSize ) + { + pItem->mnSize = nNewSize; + ImplUpdate( nPos, TRUE ); + } + } +} + +// ----------------------------------------------------------------------- + +long HeaderBar::GetItemSize( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + return mpItemList->GetObject( nPos )->mnSize; + else + return 0; +} + +// ----------------------------------------------------------------------- + +void HeaderBar::SetItemBits( USHORT nItemId, HeaderBarItemBits nNewBits ) +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + { + ImplHeadItem* pItem = mpItemList->GetObject( nPos ); + if ( pItem->mnBits != nNewBits ) + { + pItem->mnBits = nNewBits; + ImplUpdate( nPos ); + } + } +} + +// ----------------------------------------------------------------------- + +HeaderBarItemBits HeaderBar::GetItemBits( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + return mpItemList->GetObject( nPos )->mnBits; + else + return 0; +} + +// ----------------------------------------------------------------------- + +void HeaderBar::SetItemData( USHORT nItemId, void* pNewData ) +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + { + mpItemList->GetObject( nPos )->mpUserData = pNewData; + ImplUpdate( nPos ); + } +} + +// ----------------------------------------------------------------------- + +void* HeaderBar::GetItemData( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + return mpItemList->GetObject( nPos )->mpUserData; + else + return NULL; +} + +// ----------------------------------------------------------------------- + +void HeaderBar::SetItemImage( USHORT nItemId, const Image& rImage ) +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + { + mpItemList->GetObject( nPos )->maImage = rImage; + ImplUpdate( nPos ); + } +} + +// ----------------------------------------------------------------------- + +Image HeaderBar::GetItemImage( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + return mpItemList->GetObject( nPos )->maImage; + else + return Image(); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::SetItemText( USHORT nItemId, const XubString& rText ) +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + { + mpItemList->GetObject( nPos )->maText = rText; + ImplUpdate( nPos ); + } +} + +// ----------------------------------------------------------------------- + +XubString HeaderBar::GetItemText( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + return mpItemList->GetObject( nPos )->maText; + else + return String(); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::SetHelpText( USHORT nItemId, const XubString& rText ) +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + mpItemList->GetObject( nPos )->maHelpText = rText; +} + +// ----------------------------------------------------------------------- + +XubString HeaderBar::GetHelpText( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + { + ImplHeadItem* pItem = mpItemList->GetObject( nPos ); + if ( !pItem->maHelpText.Len() && pItem->maHelpId.getLength() ) + { + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + pItem->maHelpText = pHelp->GetHelpText( rtl::OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8 ), this ); + } + + return pItem->maHelpText; + } + else + return XubString(); +} + +// ----------------------------------------------------------------------- + +void HeaderBar::SetHelpId( USHORT nItemId, const rtl::OString& rHelpId ) +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + mpItemList->GetObject( nPos )->maHelpId = rHelpId; +} + +// ----------------------------------------------------------------------- + +rtl::OString HeaderBar::GetHelpId( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + rtl::OString aRet; + if ( nPos != HEADERBAR_ITEM_NOTFOUND ) + aRet = mpItemList->GetObject( nPos )->maHelpId; + return aRet; +} + +// ----------------------------------------------------------------------- + +Size HeaderBar::CalcWindowSizePixel() const +{ + long nMaxImageSize = 0; + Size aSize( 0, GetTextHeight() ); + + ImplHeadItem* pItem = mpItemList->First(); + while ( pItem ) + { + // Image-Groessen beruecksichtigen + long nImageHeight = pItem->maImage.GetSizePixel().Height(); + if ( !(pItem->mnBits & (HIB_LEFTIMAGE | HIB_RIGHTIMAGE)) && pItem->maText.Len() ) + nImageHeight += aSize.Height(); + if ( nImageHeight > nMaxImageSize ) + nMaxImageSize = nImageHeight; + + // Breite aufaddieren + aSize.Width() += pItem->mnSize; + + pItem = mpItemList->Next(); + } + + if ( nMaxImageSize > aSize.Height() ) + aSize.Height() = nMaxImageSize; + + // Border aufaddieren + if ( mbButtonStyle ) + aSize.Height() += 4; + else + aSize.Height() += 2; + aSize.Height() += mnBorderOff1+mnBorderOff2; + + return aSize; +} + +::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > HeaderBar::CreateAccessible() +{ + if ( !mxAccessible.is() ) + { + if ( maCreateAccessibleHdl.IsSet() ) + maCreateAccessibleHdl.Call( this ); + + if ( !mxAccessible.is() ) + mxAccessible = Window::CreateAccessible(); + } + + return mxAccessible; +} + +void HeaderBar::SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > _xAccessible ) +{ + mxAccessible = _xAccessible; +} + diff --git a/svtools/source/control/hyperlabel.cxx b/svtools/source/control/hyperlabel.cxx new file mode 100644 index 000000000000..10ef8cdcfadf --- /dev/null +++ b/svtools/source/control/hyperlabel.cxx @@ -0,0 +1,270 @@ +/************************************************************************* + * + * 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_svtools.hxx" +#ifndef SVTOOLS_ROADMAP_HXX +#include <svtools/hyperlabel.hxx> +#endif +#include <vcl/bitmap.hxx> +#include <tools/color.hxx> + +#ifndef _VCL_TABPAGE_HXX +#include <vcl/tabpage.hxx> +#endif + + +//......................................................................... +namespace svt +{ +//......................................................................... + + //===================================================================== + //= FontChanger + //===================================================================== + class FontChanger + { + protected: + OutputDevice* m_pDev; + + public: + FontChanger( OutputDevice* _pDev, const Font& _rNewFont ) + :m_pDev( _pDev ) + { + m_pDev->Push( PUSH_FONT ); + m_pDev->SetFont( _rNewFont ); + } + + ~FontChanger() + { + m_pDev->Pop( ); + } + }; + + class HyperLabelImpl + { + public: + sal_Int16 ID; + sal_Int32 Index; + sal_Bool bInteractive; + Size m_aMinSize; + sal_Bool m_bHyperMode; + + HyperLabelImpl(); + }; + + //--------------------------------------------------------------------- + HyperLabelImpl::HyperLabelImpl() + { + } + + HyperLabel::HyperLabel( Window* _pParent, const ResId& _rId ) + :FixedText( _pParent, _rId ) + ,m_pImpl( new HyperLabelImpl ) + { + implInit(); + } + + HyperLabel::HyperLabel( Window* _pParent, WinBits _nWinStyle ) + :FixedText( _pParent, _nWinStyle ) + ,m_pImpl( new HyperLabelImpl ) + { + implInit(); + } + + + sal_Int32 HyperLabel::GetLogicWidth() + { + Size rLogicLocSize = PixelToLogic( m_pImpl->m_aMinSize, MAP_APPFONT ); + return rLogicLocSize.Width(); + } + + + Size HyperLabel::CalcMinimumSize( long nMaxWidth ) const + { + m_pImpl->m_aMinSize = FixedText::CalcMinimumSize( nMaxWidth ); + // the MinimumSize is used to size the FocusRectangle + // and for the MouseMove method + m_pImpl->m_aMinSize.Height() += 2; + m_pImpl->m_aMinSize.Width() += 1; + return m_pImpl->m_aMinSize; + } + + void HyperLabel::implInit() + { + ToggleBackgroundColor( COL_TRANSPARENT ); + + WinBits nWinStyle = GetStyle(); + nWinStyle |= WB_EXTRAOFFSET; + SetStyle( nWinStyle ); + + Show(); + } + + void HyperLabel::ToggleBackgroundColor( const Color& _rGBColor ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + SetControlBackground( _rGBColor ); + if (_rGBColor == COL_TRANSPARENT) + SetTextColor( rStyleSettings.GetFieldTextColor( ) ); + else + SetTextColor( rStyleSettings.GetHighlightTextColor( ) ); + } + + + void HyperLabel::MouseMove( const MouseEvent& rMEvt ) + { + Font aFont = GetControlFont( ); + const Color aColor = GetTextColor(); + + if (rMEvt.IsLeaveWindow()) + { + DeactivateHyperMode(aFont, aColor); + } + else + { + Point aPoint = GetPointerPosPixel(); + if (aPoint.X() < m_pImpl->m_aMinSize.Width()) + { + if ( IsEnabled() && (m_pImpl->bInteractive) ) + { + ActivateHyperMode( aFont, aColor); + return; + } + } + DeactivateHyperMode(aFont, aColor); + } + } + + void HyperLabel::ActivateHyperMode(Font aFont, const Color aColor) + { + aFont.SetUnderline(UNDERLINE_SINGLE); + m_pImpl->m_bHyperMode = sal_True; + SetPointer( POINTER_REFHAND ); + SetControlFont( aFont); + SetTextColor( aColor); + + } + + void HyperLabel::DeactivateHyperMode(Font aFont, const Color aColor) + { + m_pImpl->m_bHyperMode = sal_False; + aFont.SetUnderline(UNDERLINE_NONE); + SetPointer( POINTER_ARROW ); + SetControlFont( aFont); + SetTextColor( aColor); + } + + void HyperLabel::MouseButtonDown( const MouseEvent& ) + { + if ( m_pImpl->m_bHyperMode && m_pImpl->bInteractive ) + { + maClickHdl.Call( this ); + } + } + + void HyperLabel::GetFocus() + { + if ( IsEnabled() && m_pImpl->bInteractive ) + { + Point aPoint(0,0); + Rectangle rRect(aPoint, Size( m_pImpl->m_aMinSize.Width(), GetSizePixel().Height() ) ); + ShowFocus( rRect ); + } + } + + void HyperLabel::LoseFocus() + { + HideFocus(); + } + + HyperLabel::~HyperLabel( ) + { + delete m_pImpl; + } + + void HyperLabel::SetInteractive( sal_Bool _bInteractive ) + { + m_pImpl->bInteractive = ( _bInteractive && IsEnabled() ); + } + + sal_Int16 HyperLabel::GetID() const + { + return m_pImpl->ID; + } + + sal_Int32 HyperLabel::GetIndex() const + { + return m_pImpl->Index; + } + + void HyperLabel::SetID( sal_Int16 _ID ) + { + m_pImpl->ID = _ID; + } + + void HyperLabel::SetIndex( sal_Int32 _Index ) + { + m_pImpl->Index = _Index; + } + + ::rtl::OUString HyperLabel::GetLabel( ) + { + return GetText(); + } + + void HyperLabel::SetLabel( const ::rtl::OUString& _rText ) + { + SetText(_rText); + } + + + //------------------------------------------------------------------------------ + void HyperLabel::DataChanged( const DataChangedEvent& rDCEvt ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + FixedText::DataChanged( rDCEvt ); + if ((( rDCEvt.GetType() == DATACHANGED_SETTINGS ) || + ( rDCEvt.GetType() == DATACHANGED_DISPLAY )) && + ( rDCEvt.GetFlags() & SETTINGS_STYLE )) + { + const Color& rGBColor = GetControlBackground(); + if (rGBColor == COL_TRANSPARENT) + SetTextColor( rStyleSettings.GetFieldTextColor( ) ); + else + { + SetControlBackground(rStyleSettings.GetHighlightColor()); + SetTextColor( rStyleSettings.GetHighlightTextColor( ) ); + } + Invalidate(); + } + } + +//......................................................................... +} // namespace svt +//......................................................................... + diff --git a/svtools/source/control/indexentryres.cxx b/svtools/source/control/indexentryres.cxx new file mode 100755 index 000000000000..23eada244a47 --- /dev/null +++ b/svtools/source/control/indexentryres.cxx @@ -0,0 +1,131 @@ +/************************************************************************* + * + * 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_svtools.hxx" +#include <svtools/svtdata.hxx> +#include <svtools/svtools.hrc> +#include <svtools/indexentryres.hxx> + +// ------------------------------------------------------------------------- +// +// wrapper for locale specific translations data of indexentry algorithm +// +// ------------------------------------------------------------------------- + +class IndexEntryRessourceData +{ + friend class IndexEntryRessource; + private: /* data */ + String ma_Name; + String ma_Translation; + private: /* member functions */ + IndexEntryRessourceData () {} + public: + IndexEntryRessourceData ( const String &r_Algorithm, const String &r_Translation) + : ma_Name (r_Algorithm), ma_Translation (r_Translation) {} + + const String& GetAlgorithm () const { return ma_Name; } + + const String& GetTranslation () const { return ma_Translation; } + + ~IndexEntryRessourceData () {} + + IndexEntryRessourceData& operator= (const IndexEntryRessourceData& r_From) + { + ma_Name = r_From.GetAlgorithm(); + ma_Translation = r_From.GetTranslation(); + return *this; + } +}; + +// ------------------------------------------------------------------------- +// +// implementation of the indexentry-algorithm-name translation +// +// ------------------------------------------------------------------------- + +#define INDEXENTRY_RESSOURCE_COUNT (STR_SVT_INDEXENTRY_END - STR_SVT_INDEXENTRY_START + 1) + +IndexEntryRessource::IndexEntryRessource() +{ + mp_Data = new IndexEntryRessourceData[INDEXENTRY_RESSOURCE_COUNT]; + + #define ASCSTR(str) String(RTL_CONSTASCII_USTRINGPARAM(str)) + #define RESSTR(rid) String(SvtResId(rid)) + + mp_Data[STR_SVT_INDEXENTRY_ALPHANUMERIC - STR_SVT_INDEXENTRY_START] = + IndexEntryRessourceData (ASCSTR("alphanumeric"), RESSTR(STR_SVT_INDEXENTRY_ALPHANUMERIC)); + mp_Data[STR_SVT_INDEXENTRY_DICTIONARY - STR_SVT_INDEXENTRY_START] = + IndexEntryRessourceData (ASCSTR("dict"), RESSTR(STR_SVT_INDEXENTRY_DICTIONARY)); + mp_Data[STR_SVT_INDEXENTRY_PINYIN - STR_SVT_INDEXENTRY_START] = + IndexEntryRessourceData (ASCSTR("pinyin"), RESSTR(STR_SVT_INDEXENTRY_PINYIN)); + mp_Data[STR_SVT_INDEXENTRY_PINYIN - STR_SVT_INDEXENTRY_START] = + IndexEntryRessourceData (ASCSTR("radical"), RESSTR(STR_SVT_INDEXENTRY_RADICAL)); + mp_Data[STR_SVT_INDEXENTRY_STROKE - STR_SVT_INDEXENTRY_START] = + IndexEntryRessourceData (ASCSTR("stroke"), RESSTR(STR_SVT_INDEXENTRY_STROKE)); + mp_Data[STR_SVT_INDEXENTRY_STROKE - STR_SVT_INDEXENTRY_START] = + IndexEntryRessourceData (ASCSTR("zhuyin"), RESSTR(STR_SVT_INDEXENTRY_ZHUYIN)); + mp_Data[STR_SVT_INDEXENTRY_ZHUYIN - STR_SVT_INDEXENTRY_START] = + IndexEntryRessourceData (ASCSTR("phonetic (alphanumeric first) (grouped by syllable)"), + RESSTR(STR_SVT_INDEXENTRY_PHONETIC_FS)); + mp_Data[STR_SVT_INDEXENTRY_PHONETIC_FS - STR_SVT_INDEXENTRY_START] = + IndexEntryRessourceData (ASCSTR("phonetic (alphanumeric first) (grouped by consonant)"), + RESSTR(STR_SVT_INDEXENTRY_PHONETIC_FC)); + mp_Data[STR_SVT_INDEXENTRY_PHONETIC_FC - STR_SVT_INDEXENTRY_START] = + IndexEntryRessourceData (ASCSTR("phonetic (alphanumeric last) (grouped by syllable)"), + RESSTR(STR_SVT_INDEXENTRY_PHONETIC_LS)); + mp_Data[STR_SVT_INDEXENTRY_PHONETIC_LS - STR_SVT_INDEXENTRY_START] = + IndexEntryRessourceData (ASCSTR("phonetic (alphanumeric last) (grouped by consonant)"), + RESSTR(STR_SVT_INDEXENTRY_PHONETIC_LC)); +} + +IndexEntryRessource::~IndexEntryRessource() +{ + delete[] mp_Data; +} + +const String& +IndexEntryRessource::GetTranslation (const String &r_Algorithm) +{ + xub_StrLen nIndex = r_Algorithm.Search('.'); + String aLocaleFreeAlgorithm; + + if (nIndex == STRING_NOTFOUND) + aLocaleFreeAlgorithm = r_Algorithm; + else { + nIndex += 1; + aLocaleFreeAlgorithm = String(r_Algorithm, nIndex, r_Algorithm.Len() - nIndex); + } + + for (sal_uInt32 i = 0; i < INDEXENTRY_RESSOURCE_COUNT; i++) + if (aLocaleFreeAlgorithm == mp_Data[i].GetAlgorithm()) + return mp_Data[i].GetTranslation(); + return r_Algorithm; +} + diff --git a/svtools/source/control/inettbc.cxx b/svtools/source/control/inettbc.cxx new file mode 100755 index 000000000000..574f2bde4e1e --- /dev/null +++ b/svtools/source/control/inettbc.cxx @@ -0,0 +1,1364 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#ifdef UNX +#include <pwd.h> +#include <sys/types.h> +#endif + +#include <svtools/inettbc.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/ucb/NumberedSortingInfo.hpp> +#include <com/sun/star/ucb/XAnyCompareFactory.hpp> +#include <com/sun/star/ucb/XProgressHandler.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/ucb/XSortedDynamicResultSetFactory.hpp> +#include <comphelper/processfactory.hxx> +#include <vcl/toolbox.hxx> +#include <vos/thread.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> +#include <unotools/historyoptions.hxx> +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <svl/itemset.hxx> +#include "svl/urihelper.hxx" +#include <unotools/pathoptions.hxx> + +#define _SVSTDARR_STRINGSDTOR +#include <svl/svstdarr.hxx> +#include <ucbhelper/commandenvironment.hxx> +#include <ucbhelper/content.hxx> +#include <unotools/localfilehelper.hxx> +#include <unotools/ucbhelper.hxx> +#include "iodlg.hrc" +#include <svtools/asynclink.hxx> +#include <svl/urlfilter.hxx> + +#include <vector> +#include <algorithm> + +// ----------------------------------------------------------------------- + +using namespace ::rtl; +using namespace ::ucbhelper; +using namespace ::utl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::uno; + +// ----------------------------------------------------------------------- +class SvtURLBox_Impl +{ +public: + SvStringsDtor* pURLs; + SvStringsDtor* pCompletions; + const IUrlFilter* pUrlFilter; + ::std::vector< WildCard > m_aFilters; + + static sal_Bool TildeParsing( String& aText, String& aBaseUrl ); + + inline SvtURLBox_Impl( ) + :pURLs( NULL ) + ,pCompletions( NULL ) + ,pUrlFilter( NULL ) + { + FilterMatch::createWildCardFilterList(String(),m_aFilters); + } +}; + +// ----------------------------------------------------------------------- +class SvtMatchContext_Impl : public ::vos::OThread +{ + static ::vos::OMutex* pDirMutex; + + SvStringsDtor aPickList; + SvStringsDtor* pCompletions; + SvStringsDtor* pURLs; + svtools::AsynchronLink aLink; + String aBaseURL; + String aText; + SvtURLBox* pBox; + BOOL bStop; + BOOL bOnlyDirectories; + BOOL bNoSelection; + + DECL_STATIC_LINK( SvtMatchContext_Impl, Select_Impl, void* ); + + virtual void SAL_CALL onTerminated( ); + virtual void SAL_CALL run(); + virtual void SAL_CALL Cancel(); + void Insert( const String& rCompletion, const String& rURL, BOOL bForce = FALSE); + void ReadFolder( const String& rURL, const String& rMatch, BOOL bSmart ); + void FillPicklist( SvStringsDtor& rPickList ); + +public: + static ::vos::OMutex* GetMutex(); + + SvtMatchContext_Impl( SvtURLBox* pBoxP, const String& rText ); + ~SvtMatchContext_Impl(); + void Stop(); +}; + +::vos::OMutex* SvtMatchContext_Impl::pDirMutex = 0; + +::vos::OMutex* SvtMatchContext_Impl::GetMutex() +{ + ::vos::OGuard aGuard( ::vos::OMutex::getGlobalMutex() ); + if( !pDirMutex ) + pDirMutex = new ::vos::OMutex; + return pDirMutex; +} + +//------------------------------------------------------------------------- +SvtMatchContext_Impl::SvtMatchContext_Impl( + SvtURLBox* pBoxP, const String& rText ) + : aLink( STATIC_LINK( this, SvtMatchContext_Impl, Select_Impl ) ) + , aBaseURL( pBoxP->aBaseURL ) + , aText( rText ) + , pBox( pBoxP ) + , bStop( FALSE ) + , bOnlyDirectories( pBoxP->bOnlyDirectories ) + , bNoSelection( pBoxP->bNoSelection ) +{ + pURLs = new SvStringsDtor; + pCompletions = new SvStringsDtor; + + aLink.CreateMutex(); + + FillPicklist( aPickList ); + + create(); +} + +//------------------------------------------------------------------------- +SvtMatchContext_Impl::~SvtMatchContext_Impl() +{ + aLink.ClearPendingCall(); + delete pURLs; + delete pCompletions; +} + +//------------------------------------------------------------------------- +void SvtMatchContext_Impl::FillPicklist( SvStringsDtor& rPickList ) +{ + // Einlesung der Historypickliste + Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( eHISTORY ); + sal_uInt32 nCount = seqPicklist.getLength(); + + for( sal_uInt32 nItem=0; nItem < nCount; nItem++ ) + { + Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ]; + + OUString sTitle; + INetURLObject aURL; + + sal_uInt32 nPropertyCount = seqPropertySet.getLength(); + + for( sal_uInt32 nProperty=0; nProperty < nPropertyCount; nProperty++ ) + { + if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_TITLE ) + { + seqPropertySet[nProperty].Value >>= sTitle; + aURL.SetURL( sTitle ); + const StringPtr pStr = new String( aURL.GetMainURL( INetURLObject::DECODE_WITH_CHARSET ) ); + rPickList.Insert( pStr, (USHORT) nItem ); + break; + } + } + } +} + +//------------------------------------------------------------------------- +void SAL_CALL SvtMatchContext_Impl::Cancel() +{ + // Cancel button pressed + terminate(); +} + +//------------------------------------------------------------------------- +void SvtMatchContext_Impl::Stop() +{ + bStop = TRUE; + + if( isRunning() ) + terminate(); +} + +//------------------------------------------------------------------------- +void SvtMatchContext_Impl::onTerminated( ) +{ + aLink.Call( this ); +} + +//------------------------------------------------------------------------- +// This method is called via AsynchronLink, so it has the SolarMutex and +// calling solar code ( VCL ... ) is safe. It is called when the thread is +// terminated ( finished work or stopped ). Cancelling the thread via +// Cancellable does not not discard the information gained so far, it +// inserts all collected completions into the listbox. + +IMPL_STATIC_LINK( SvtMatchContext_Impl, Select_Impl, void*, ) +{ + // avoid recursion through cancel button + if( pThis->bStop ) + { + // completions was stopped, no display + delete pThis; + return 0; + } + + SvtURLBox* pBox = pThis->pBox; + pBox->bAutoCompleteMode = TRUE; + + // did we filter completions which otherwise would have been valid? + // (to be filled below) + bool bValidCompletionsFiltered = false; + + // insert all completed strings into the listbox + pBox->Clear(); + + for( USHORT nPos = 0; nPos<pThis->pCompletions->Count(); nPos++ ) + { + String sCompletion( *(*pThis->pCompletions)[nPos] ); + + // convert the file into an URL + String sURL( sCompletion ); + ::utl::LocalFileHelper::ConvertPhysicalNameToURL( sCompletion, sURL ); + // note: if this doesn't work, we're not interested in: we're checking the + // untouched sCompletion then + + if ( pBox->pImp->pUrlFilter ) + { + if ( !pBox->pImp->pUrlFilter->isUrlAllowed( sURL ) ) + { // this URL is not allowed + bValidCompletionsFiltered = true; + continue; + } + } + if (( sURL.Len() > 0 ) && ( sURL.GetChar(sURL.Len()-1) != '/' )) + { + String sUpperURL( sURL ); + sUpperURL.ToUpperAscii(); + + ::std::vector< WildCard >::const_iterator aMatchingFilter = + ::std::find_if( + pBox->pImp->m_aFilters.begin(), + pBox->pImp->m_aFilters.end(), + FilterMatch( sUpperURL ) + ); + if ( aMatchingFilter == pBox->pImp->m_aFilters.end() ) + + { // this URL is not allowed + bValidCompletionsFiltered = true; + continue; + } + } + + pBox->InsertEntry( sCompletion ); + } + + if( !pThis->bNoSelection && pThis->pCompletions->Count() && !bValidCompletionsFiltered ) + { + // select the first one + String aTmp( pBox->GetEntry(0) ); + pBox->SetText( aTmp ); + pBox->SetSelection( Selection( pThis->aText.Len(), aTmp.Len() ) ); + } + + // transfer string lists to listbox and forget them + delete pBox->pImp->pURLs; + delete pBox->pImp->pCompletions; + pBox->pImp->pURLs = pThis->pURLs; + pBox->pImp->pCompletions = pThis->pCompletions; + pThis->pURLs = NULL; + pThis->pCompletions = NULL; + + // force listbox to resize ( it may be open ) + pBox->Resize(); + + // the box has this control as a member so we have to set that member + // to zero before deleting ourself. + pBox->pCtx = NULL; + delete pThis; + + return 0; +} + +//------------------------------------------------------------------------- +void SvtMatchContext_Impl::Insert( const String& rCompletion, + const String& rURL, + BOOL bForce ) +{ + if( !bForce ) + { + // avoid doubles + for( USHORT nPos = pCompletions->Count(); nPos--; ) + if( *(*pCompletions)[ nPos ] == rCompletion ) + return; + } + + const StringPtr pCompletion = new String( rCompletion ); + pCompletions->Insert( pCompletion, pCompletions->Count() ); + const StringPtr pURL = new String( rURL ); + pURLs->Insert( pURL, pURLs->Count() ); +} + +//------------------------------------------------------------------------- +void SvtMatchContext_Impl::ReadFolder( const String& rURL, + const String& rMatch, + BOOL bSmart ) +{ + // check folder to scan + if( !UCBContentHelper::IsFolder( rURL ) ) + return; + + sal_Bool bPureHomePath = sal_False; +#ifdef UNX + bPureHomePath = aText.Search( '~' ) == 0 && aText.Search( '/' ) == STRING_NOTFOUND; +#endif + + sal_Bool bExectMatch = bPureHomePath + || aText.CompareToAscii( "." ) == COMPARE_EQUAL + || (aText.Len() > 1 && aText.Copy( aText.Len() - 2, 2 ).CompareToAscii( "/." ) == COMPARE_EQUAL) + || (aText.Len() > 2 && aText.Copy( aText.Len() - 3, 3 ).CompareToAscii( "/.." ) == COMPARE_EQUAL); + + // for pure home pathes ( ~username ) the '.' at the end of rMatch + // means that it poits to root catalog + // this is done only for file contents since home pathes parsing is usefull only for them + if ( bPureHomePath && rMatch.Equals( String::CreateFromAscii( "file:///." ) ) ) + { + // a home that refers to / + + String aNewText( aText ); + aNewText += '/'; + Insert( aNewText, rURL, TRUE ); + + return; + } + + // string to match with + INetURLObject aMatchObj( rMatch ); + String aMatchName; + + if ( rURL != String(aMatchObj.GetMainURL( INetURLObject::NO_DECODE ) )) + { + aMatchName = aMatchObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + + // matching is always done case insensitive, but completion will be case sensitive and case preserving + aMatchName.ToLowerAscii(); + + // if the matchstring ends with a slash, we must search for this also + if ( rMatch.GetChar(rMatch.Len()-1) == '/' ) + aMatchName += '/'; + } + + xub_StrLen nMatchLen = aMatchName.Len(); + + INetURLObject aFolderObj( rURL ); + DBG_ASSERT( aFolderObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + + try + { + uno::Reference< XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); + + Content aCnt( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ), + new ::ucbhelper::CommandEnvironment( uno::Reference< XInteractionHandler >(), + uno::Reference< XProgressHandler >() ) ); + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(2); + OUString* pProps = aProps.getArray(); + pProps[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ); + pProps[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ); + + try + { + uno::Reference< XDynamicResultSet > xDynResultSet; + ResultSetInclude eInclude = INCLUDE_FOLDERS_AND_DOCUMENTS; + if ( bOnlyDirectories ) + eInclude = INCLUDE_FOLDERS_ONLY; + + xDynResultSet = aCnt.createDynamicCursor( aProps, eInclude ); + + uno::Reference < XAnyCompareFactory > xCompare; + uno::Reference < XSortedDynamicResultSetFactory > xSRSFac( + xFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.SortedDynamicResultSetFactory") ) ), UNO_QUERY ); + + Sequence< NumberedSortingInfo > aSortInfo( 2 ); + NumberedSortingInfo* pInfo = aSortInfo.getArray(); + pInfo[ 0 ].ColumnIndex = 2; + pInfo[ 0 ].Ascending = sal_False; + pInfo[ 1 ].ColumnIndex = 1; + pInfo[ 1 ].Ascending = sal_True; + + uno::Reference< XDynamicResultSet > xDynamicResultSet; + xDynamicResultSet = + xSRSFac->createSortedDynamicResultSet( xDynResultSet, aSortInfo, xCompare ); + + if ( xDynamicResultSet.is() ) + { + xResultSet = xDynamicResultSet->getStaticResultSet(); + } + } + catch( ::com::sun::star::uno::Exception& ) {} + + if ( xResultSet.is() ) + { + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY ); + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + + try + { + while ( schedule() && xResultSet->next() ) + { + String aURL = xContentAccess->queryContentIdentifierString(); + String aTitle = xRow->getString(1); + sal_Bool bIsFolder = xRow->getBoolean(2); + + // matching is always done case insensitive, but completion will be case sensitive and case preserving + aTitle.ToLowerAscii(); + + if ( + !nMatchLen || + (bExectMatch && aMatchName.Equals(aTitle)) || + (!bExectMatch && aMatchName.CompareTo(aTitle, nMatchLen) == COMPARE_EQUAL) + ) + { + // all names fit if matchstring is empty + INetURLObject aObj( aURL ); + sal_Unicode aDelimiter = '/'; + if ( bSmart ) + // when parsing is done "smart", the delimiter must be "guessed" + aObj.getFSysPath( (INetURLObject::FSysStyle)(INetURLObject::FSYS_DETECT & ~INetURLObject::FSYS_VOS), &aDelimiter ); + + if ( bIsFolder ) + aObj.setFinalSlash(); + + // get the last name of the URL + String aMatch = aObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + String aInput( aText ); + if ( nMatchLen ) + { + if ((aText.Len() && aText.GetChar(aText.Len() - 1) == '.') || bPureHomePath) + { + // if a "special folder" URL was typed, don't touch the user input + aMatch.Erase( 0, nMatchLen ); + } + else + { + // make the user input case preserving + DBG_ASSERT( aInput.Len() >= nMatchLen, "Suspicious Matching!" ); + aInput.Erase( aInput.Len() - nMatchLen ); + } + } + + aInput += aMatch; + + // folders should get a final slash automatically + if ( bIsFolder ) + aInput += aDelimiter; + + Insert( aInput, aObj.GetMainURL( INetURLObject::NO_DECODE ), TRUE ); + } + } + } + catch( ::com::sun::star::uno::Exception& ) + { + } + } + } + catch( ::com::sun::star::uno::Exception& ) + { + } +} + +//------------------------------------------------------------------------- +String SvtURLBox::ParseSmart( String aText, String aBaseURL, String aWorkDir ) +{ + String aMatch; + + // parse ~ for Unix systems + // does nothing for Windows + if( !SvtURLBox_Impl::TildeParsing( aText, aBaseURL ) ) + return String(); + + INetURLObject aURLObject; + if( aBaseURL.Len() ) + { + INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL ); + + // if a base URL is set the string may be parsed relative + if( aText.Search( '/' ) == 0 ) + { + // text starting with slashes means absolute file URLs + String aTemp = INetURLObject::GetScheme( eBaseProt ); + + // file URL must be correctly encoded! + String aTextURL = INetURLObject::encode( aText, INetURLObject::PART_FPATH, + '%', INetURLObject::ENCODE_ALL ); + aTemp += aTextURL; + + INetURLObject aTmp( aTemp ); + if ( !aTmp.HasError() && aTmp.GetProtocol() != INET_PROT_NOT_VALID ) + aMatch = aTmp.GetMainURL( INetURLObject::NO_DECODE ); + } + else + { + String aSmart( aText ); + INetURLObject aObj( aBaseURL ); + + // HRO: I suppose this hack should only be done for Windows !!!??? +#ifdef WNT + // HRO: INetURLObject::smatRel2Abs does not recognize '\\' as a relative path + // but in case of "\\\\" INetURLObject is right - this is an absolute path ! + + if( aText.Search( '\\' ) == 0 && (aText.Len() < 2 || aText.GetChar( 1 ) != '\\') ) + { + // cut to first segment + String aTmp = INetURLObject::GetScheme( eBaseProt ); + aTmp += '/'; + aTmp += String(aObj.getName( 0, true, INetURLObject::DECODE_WITH_CHARSET )); + aObj.SetURL( aTmp ); + + aSmart.Erase(0,1); + } +#endif + // base URL must be a directory ! + aObj.setFinalSlash(); + + // take base URL and append current input + bool bWasAbsolute = FALSE; +#ifdef UNX + // don't support FSYS_MAC under Unix, because here ':' is a valid character for a filename + INetURLObject::FSysStyle eStyle = static_cast< INetURLObject::FSysStyle >( INetURLObject::FSYS_VOS | INetURLObject::FSYS_UNX | INetURLObject::FSYS_DOS ); + // encode file URL correctly + aSmart = INetURLObject::encode( aSmart, INetURLObject::PART_FPATH, '%', INetURLObject::ENCODE_ALL ); + INetURLObject aTmp( aObj.smartRel2Abs( + aSmart, bWasAbsolute, false, INetURLObject::WAS_ENCODED, RTL_TEXTENCODING_UTF8, false, eStyle ) ); +#else + INetURLObject aTmp( aObj.smartRel2Abs( aSmart, bWasAbsolute ) ); +#endif + + if ( aText.GetChar( aText.Len() - 1 ) == '.' ) + // INetURLObject appends a final slash for the directories "." and "..", this is a bug! + // Remove it as a workaround + aTmp.removeFinalSlash(); + if ( !aTmp.HasError() && aTmp.GetProtocol() != INET_PROT_NOT_VALID ) + aMatch = aTmp.GetMainURL( INetURLObject::NO_DECODE ); + } + } + else + { + ::utl::LocalFileHelper::ConvertSystemPathToURL( aText, aWorkDir, aMatch ); + } + + return aMatch; +} + +//------------------------------------------------------------------------- +void SvtMatchContext_Impl::run() +{ + ::vos::OGuard aGuard( GetMutex() ); + if( bStop ) + // have we been stopped while we were waiting for the mutex? + return; + + // Reset match lists + pCompletions->Remove( 0, pCompletions->Count() ); + pURLs->Remove( 0, pURLs->Count() ); + + // check for input + USHORT nTextLen = aText.Len(); + if ( !nTextLen ) + return; + + if( aText.Search( '*' ) != STRING_NOTFOUND || aText.Search( '?' ) != STRING_NOTFOUND ) + // no autocompletion for wildcards + return; + + String aMatch; + String aWorkDir( SvtPathOptions().GetWorkPath() ); + INetProtocol eProt = INetURLObject::CompareProtocolScheme( aText ); + INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL ); + if ( !aBaseURL.Len() ) + eBaseProt = INetURLObject::CompareProtocolScheme( aWorkDir ); + INetProtocol eSmartProt = pBox->GetSmartProtocol(); + + // if the user input is a valid URL, go on with it + // otherwise it could be parsed smart with a predefined smart protocol + // ( or if this is not set with the protocol of a predefined base URL ) + if( eProt == INET_PROT_NOT_VALID || eProt == eSmartProt || (eSmartProt == INET_PROT_NOT_VALID && eProt == eBaseProt) ) + { + // not stopped yet ? + if( schedule() ) + { + if ( eProt == INET_PROT_NOT_VALID ) + aMatch = SvtURLBox::ParseSmart( aText, aBaseURL, aWorkDir ); + else + aMatch = aText; + if ( aMatch.Len() ) + { + INetURLObject aURLObject( aMatch ); + String aMainURL( aURLObject.GetMainURL( INetURLObject::NO_DECODE ) ); + if ( aMainURL.Len() ) + { + // if text input is a directory, it must be part of the match list! Until then it is scanned + if ( UCBContentHelper::IsFolder( aMainURL ) && aURLObject.hasFinalSlash() ) + Insert( aText, aMatch ); + else + // otherwise the parent folder will be taken + aURLObject.removeSegment(); + + // scan directory and insert all matches + ReadFolder( aURLObject.GetMainURL( INetURLObject::NO_DECODE ), aMatch, eProt == INET_PROT_NOT_VALID ); + } + } + } + } + + if ( bOnlyDirectories ) + // don't scan history picklist if only directories are allowed, picklist contains only files + return; + + BOOL bFull = FALSE; + int nCount = aPickList.Count(); + + INetURLObject aCurObj; + String aEmpty, aCurString, aCurMainURL; + INetURLObject aObj; + aObj.SetSmartProtocol( eSmartProt == INET_PROT_NOT_VALID ? INET_PROT_HTTP : eSmartProt ); + for( ;; ) + { + for( USHORT nPos = 0; schedule() && nPos < nCount; nPos++ ) + { + aCurObj.SetURL( *aPickList.GetObject( nPos ) ); + aCurObj.SetSmartURL( aCurObj.GetURLNoPass()); + aCurMainURL = aCurObj.GetMainURL( INetURLObject::NO_DECODE ); + + if( eProt != INET_PROT_NOT_VALID && aCurObj.GetProtocol() != eProt ) + continue; + + if( eSmartProt != INET_PROT_NOT_VALID && aCurObj.GetProtocol() != eSmartProt ) + continue; + + switch( aCurObj.GetProtocol() ) + { + case INET_PROT_HTTP: + case INET_PROT_HTTPS: + case INET_PROT_FTP: + { + if( eProt == INET_PROT_NOT_VALID && !bFull ) + { + aObj.SetSmartURL( aText ); + if( aObj.GetURLPath().getLength() > 1 ) + continue; + } + + aCurString = aCurMainURL; + if( eProt == INET_PROT_NOT_VALID ) + { + // try if text matches the scheme + String aScheme( INetURLObject::GetScheme( aCurObj.GetProtocol() ) ); + if ( aText.CompareIgnoreCaseToAscii( aScheme, aText.Len() ) == COMPARE_EQUAL && aText.Len() < aScheme.Len() ) + { + if( bFull ) + aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE ); + else + { + aCurObj.SetMark( aEmpty ); + aCurObj.SetParam( aEmpty ); + aCurObj.SetURLPath( aEmpty ); + aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE ); + } + + Insert( aMatch, aMatch ); + } + + // now try smart matching + aCurString.Erase( 0, aScheme.Len() ); + } + + if( aText.CompareIgnoreCaseToAscii( aCurString, aText.Len() )== COMPARE_EQUAL ) + { + if( bFull ) + aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE ); + else + { + aCurObj.SetMark( aEmpty ); + aCurObj.SetParam( aEmpty ); + aCurObj.SetURLPath( aEmpty ); + aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE ); + } + + String aURL( aMatch ); + if( eProt == INET_PROT_NOT_VALID ) + aMatch.Erase( 0, sal::static_int_cast< xub_StrLen >(INetURLObject::GetScheme( aCurObj.GetProtocol() ).getLength()) ); + + if( aText.Len() < aMatch.Len() ) + Insert( aMatch, aURL ); + + continue; + } + break; + } + default: + { + if( bFull ) + continue; + + if( aText.CompareTo( aCurMainURL, aText.Len() ) == COMPARE_EQUAL ) + { + if( aText.Len() < aCurMainURL.Len() ) + Insert( aCurMainURL, aCurMainURL ); + + continue; + } + break; + } + } + } + + if( !bFull ) + bFull = TRUE; + else + break; + } + + return; +} + +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +void SvtURLBox::TryAutoComplete( BOOL bForce ) +{ + if( Application::AnyInput( INPUT_KEYBOARD ) ) return; + + String aMatchString; + String aCurText = GetText(); + Selection aSelection( GetSelection() ); + if( aSelection.Max() != aCurText.Len() && !bForce ) + return; + USHORT nLen = (USHORT)aSelection.Min(); + aCurText.Erase( nLen ); + if( aCurText.Len() && bIsAutoCompleteEnabled ) + { + if ( pCtx ) + { + pCtx->Stop(); + pCtx = NULL; + } + pCtx = new SvtMatchContext_Impl( this, aCurText ); + } +} + +//------------------------------------------------------------------------- +SvtURLBox::SvtURLBox( Window* pParent, INetProtocol eSmart ) + : ComboBox( pParent , WB_DROPDOWN | WB_AUTOSIZE | WB_AUTOHSCROLL ), + pCtx( 0 ), + eSmartProtocol( eSmart ), + bAutoCompleteMode( FALSE ), + bOnlyDirectories( FALSE ), + bTryAutoComplete( FALSE ), + bCtrlClick( FALSE ), + bHistoryDisabled( FALSE ), + bNoSelection( FALSE ), + bIsAutoCompleteEnabled( TRUE ) +{ + ImplInit(); + + if ( GetDesktopRectPixel().GetWidth() > 800 ) + SetSizePixel( Size( 300, 240 ) ); + else + SetSizePixel( Size( 225, 240 ) ); +} + +//------------------------------------------------------------------------- +SvtURLBox::SvtURLBox( Window* pParent, WinBits _nStyle, INetProtocol eSmart ) + : ComboBox( pParent, _nStyle ), + pCtx( 0 ), + eSmartProtocol( eSmart ), + bAutoCompleteMode( FALSE ), + bOnlyDirectories( FALSE ), + bTryAutoComplete( FALSE ), + bCtrlClick( FALSE ), + bHistoryDisabled( FALSE ), + bNoSelection( FALSE ), + bIsAutoCompleteEnabled( TRUE ) +{ + ImplInit(); +} + +//------------------------------------------------------------------------- +SvtURLBox::SvtURLBox( Window* pParent, const ResId& _rResId, INetProtocol eSmart ) + : ComboBox( pParent , _rResId ), + pCtx( 0 ), + eSmartProtocol( eSmart ), + bAutoCompleteMode( FALSE ), + bOnlyDirectories( FALSE ), + bTryAutoComplete( FALSE ), + bCtrlClick( FALSE ), + bHistoryDisabled( FALSE ), + bNoSelection( FALSE ), + bIsAutoCompleteEnabled( TRUE ) +{ + ImplInit(); +} + +//------------------------------------------------------------------------- +void SvtURLBox::ImplInit() +{ + pImp = new SvtURLBox_Impl(); + + SetHelpId( ".uno:OpenURL" ); + EnableAutocomplete( FALSE ); + + SetText( String() ); + + GetSubEdit()->SetAutocompleteHdl( LINK( this, SvtURLBox, AutoCompleteHdl_Impl ) ); + UpdatePicklistForSmartProtocol_Impl(); +} + +//------------------------------------------------------------------------- +SvtURLBox::~SvtURLBox() +{ + if( pCtx ) + { + pCtx->Stop(); + pCtx = NULL; + } + + delete pImp->pURLs; + delete pImp->pCompletions; + delete pImp; +} + +//------------------------------------------------------------------------- +void SvtURLBox::UpdatePickList( ) +{ + if( pCtx ) + { + pCtx->Stop(); + pCtx = NULL; + } + + String sText = GetText(); + if ( sText.Len() && bIsAutoCompleteEnabled ) + pCtx = new SvtMatchContext_Impl( this, sText ); +} + +//------------------------------------------------------------------------- +void SvtURLBox::SetSmartProtocol( INetProtocol eProt ) +{ + if ( eSmartProtocol != eProt ) + { + eSmartProtocol = eProt; + UpdatePicklistForSmartProtocol_Impl(); + } +} + +//------------------------------------------------------------------------- +void SvtURLBox::UpdatePicklistForSmartProtocol_Impl() +{ + Clear(); + if ( !bHistoryDisabled ) + { + // read history pick list + Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( eHISTORY ); + sal_uInt32 nCount = seqPicklist.getLength(); + INetURLObject aCurObj; + + for( sal_uInt32 nItem=0; nItem < nCount; nItem++ ) + { + Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ]; + + OUString sURL; + + sal_uInt32 nPropertyCount = seqPropertySet.getLength(); + + for( sal_uInt32 nProperty=0; nProperty < nPropertyCount; nProperty++ ) + { + if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_URL ) + { + seqPropertySet[nProperty].Value >>= sURL; + aCurObj.SetURL( sURL ); + + if ( sURL.getLength() && ( eSmartProtocol != INET_PROT_NOT_VALID ) ) + { + if( aCurObj.GetProtocol() != eSmartProtocol ) + break; + } + + String aURL( aCurObj.GetMainURL( INetURLObject::DECODE_WITH_CHARSET ) ); + + if ( aURL.Len() && ( !pImp->pUrlFilter || pImp->pUrlFilter->isUrlAllowed( aURL ) ) ) + { + BOOL bFound = (aURL.GetChar(aURL.Len()-1) == '/' ); + if ( !bFound ) + { + String aUpperURL( aURL ); + aUpperURL.ToUpperAscii(); + + bFound + = (::std::find_if( + pImp->m_aFilters.begin(), + pImp->m_aFilters.end(), + FilterMatch( aUpperURL ) ) + != pImp->m_aFilters.end()); + } + if ( bFound ) + { + String aFile; + if (::utl::LocalFileHelper::ConvertURLToSystemPath(aURL,aFile)) + InsertEntry(aFile); + else + InsertEntry(aURL); + } + } + break; + } + } + } + } +} + +//------------------------------------------------------------------------- +BOOL SvtURLBox::ProcessKey( const KeyCode& rKey ) +{ + // every key input stops the current matching thread + if( pCtx ) + { + pCtx->Stop(); + pCtx = NULL; + } + + KeyCode aCode( rKey.GetCode() ); + if ( aCode == KEY_RETURN && GetText().Len() ) + { + // wait for completion of matching thread + ::vos::OGuard aGuard( SvtMatchContext_Impl::GetMutex() ); + + if ( bAutoCompleteMode ) + { + // reset picklist + bAutoCompleteMode = FALSE; + Selection aSelection( GetSelection() ); + SetSelection( Selection( aSelection.Min(), aSelection.Min() ) ); + if ( bOnlyDirectories ) + Clear(); + else + UpdatePicklistForSmartProtocol_Impl(); + Resize(); + } + + bCtrlClick = rKey.IsMod1(); + BOOL bHandled = FALSE; + if ( GetOpenHdl().IsSet() ) + { + bHandled = TRUE; + GetOpenHdl().Call(this); + } + else if ( GetSelectHdl().IsSet() ) + { + bHandled = TRUE; + GetSelectHdl().Call(this); + } + + bCtrlClick = FALSE; + + ClearModifyFlag(); + return bHandled; + } + else if ( aCode == KEY_RETURN && !GetText().Len() && GetOpenHdl().IsSet() ) + { + // for file dialog + bAutoCompleteMode = FALSE; + GetOpenHdl().Call(this); + return TRUE; + } + else if( aCode == KEY_ESCAPE ) + { + Selection aSelection( GetSelection() ); + if ( bAutoCompleteMode || aSelection.Min() != aSelection.Max() ) + { + SetSelection( Selection( aSelection.Min(), aSelection.Min() ) ); + if ( bOnlyDirectories ) + Clear(); + else + UpdatePicklistForSmartProtocol_Impl(); + Resize(); + } + else + { + return FALSE; + } + + bAutoCompleteMode = FALSE; + return TRUE; + } + else + { + return FALSE; + } +} + +//------------------------------------------------------------------------- +void SvtURLBox::Modify() +{ + ComboBox::Modify(); +} + +//------------------------------------------------------------------------- +long SvtURLBox::PreNotify( NotifyEvent& rNEvt ) +{ + if( rNEvt.GetWindow() == GetSubEdit() && rNEvt.GetType() == EVENT_KEYINPUT ) + { + + const KeyEvent& rEvent = *rNEvt.GetKeyEvent(); + const KeyCode& rKey = rEvent.GetKeyCode(); + KeyCode aCode( rKey.GetCode() ); + if( ProcessKey( rKey ) ) + { + return TRUE; + } + else if( ( aCode == KEY_UP || aCode == KEY_DOWN ) && !rKey.IsMod2() ) + { + Selection aSelection( GetSelection() ); + USHORT nLen = (USHORT)aSelection.Min(); + GetSubEdit()->KeyInput( rEvent ); + SetSelection( Selection( nLen, GetText().Len() ) ); + return TRUE; + } + + if ( MatchesPlaceHolder( GetText() ) ) + { + // set the selection so a key stroke will overwrite + // the placeholder rather than edit it + SetSelection( Selection( 0, GetText().Len() ) ); + } + } + + return ComboBox::PreNotify( rNEvt ); +} + +//------------------------------------------------------------------------- +IMPL_LINK( SvtURLBox, AutoCompleteHdl_Impl, void*, EMPTYARG ) +{ + if ( GetSubEdit()->GetAutocompleteAction() == AUTOCOMPLETE_KEYINPUT ) + { + TryAutoComplete( FALSE ); + return 1L; + } + + return 0L; +} + +//------------------------------------------------------------------------- +long SvtURLBox::Notify( NotifyEvent &rEvt ) +{ + if ( EVENT_GETFOCUS == rEvt.GetType() ) + { +#ifndef UNX + // pb: don't select automatically on unix #93251# + SetSelection( Selection( 0, GetText().Len() ) ); +#endif + } + else if ( EVENT_LOSEFOCUS == rEvt.GetType() ) + { + if( !GetText().Len() ) + ClearModifyFlag(); + if ( pCtx ) + { + pCtx->Stop(); + pCtx = NULL; + } + } + + return ComboBox::Notify( rEvt ); +} + +//------------------------------------------------------------------------- +void SvtURLBox::Select() +{ + ComboBox::Select(); + ClearModifyFlag(); +} + +//------------------------------------------------------------------------- +void SvtURLBox::SetOnlyDirectories( BOOL bDir ) +{ + bOnlyDirectories = bDir; + if ( bOnlyDirectories ) + Clear(); +} + +//------------------------------------------------------------------------- +void SvtURLBox::SetNoURLSelection( BOOL bSet ) +{ + bNoSelection = bSet; +} + +//------------------------------------------------------------------------- +String SvtURLBox::GetURL() +{ + // wait for end of autocompletion + ::vos::OGuard aGuard( SvtMatchContext_Impl::GetMutex() ); + + String aText( GetText() ); + if ( MatchesPlaceHolder( aText ) ) + return aPlaceHolder; + // try to get the right case preserving URL from the list of URLs + if ( pImp->pCompletions && pImp->pURLs ) + { + for( USHORT nPos=0; nPos<pImp->pCompletions->Count(); nPos++ ) + { +#ifdef DBG_UTIL + String aTmp( *(*pImp->pCompletions)[ nPos ] ); +#endif + if( *(*pImp->pCompletions)[ nPos ] == aText ) + return *(*pImp->pURLs)[nPos]; + } + } + +#ifdef WNT + // erase trailing spaces on Windows since thay are invalid on this OS and + // most of the time they are inserted by accident via copy / paste + aText.EraseTrailingChars(); + if ( !aText.Len() ) + return aText; + // #i9739# - 2002-12-03 - fs@openoffice.org +#endif + + INetURLObject aObj( aText ); + if( aText.Search( '*' ) != STRING_NOTFOUND || aText.Search( '?' ) != STRING_NOTFOUND ) + { + // no autocompletion for wildcards + INetURLObject aTempObj; + if ( eSmartProtocol != INET_PROT_NOT_VALID ) + aTempObj.SetSmartProtocol( eSmartProtocol ); + if ( aTempObj.SetSmartURL( aText ) ) + return aTempObj.GetMainURL( INetURLObject::NO_DECODE ); + else + return aText; + } + + if ( aObj.GetProtocol() == INET_PROT_NOT_VALID ) + { + String aName = ParseSmart( aText, aBaseURL, SvtPathOptions().GetWorkPath() ); + aObj.SetURL( aName ); + ::rtl::OUString aURL( aObj.GetMainURL( INetURLObject::NO_DECODE ) ); + if ( !aURL.getLength() ) + // aText itself is invalid, and even together with aBaseURL, it could not + // made valid -> no chance + return aText; + + bool bSlash = aObj.hasFinalSlash(); + { + static const rtl::OUString aPropName( + rtl::OUString::createFromAscii("CasePreservingURL")); + + rtl::OUString aFileURL; + + Any aAny = + UCBContentHelper::GetProperty(aURL,aPropName); + sal_Bool success = (aAny >>= aFileURL); + String aTitle; + if(success) + aTitle = String( + INetURLObject(aFileURL).getName( + INetURLObject::LAST_SEGMENT, + true, + INetURLObject::DECODE_WITH_CHARSET )); + else + success = + UCBContentHelper::GetTitle(aURL,aTitle); + + if( success && + ( aTitle.Len() > 1 || + (aTitle.CompareToAscii("/") != 0 && + aTitle.CompareToAscii(".") != 0) ) ) + { + aObj.SetName( aTitle ); + if ( bSlash ) + aObj.setFinalSlash(); + } + } + } + + return aObj.GetMainURL( INetURLObject::NO_DECODE ); +} + +//------------------------------------------------------------------------- +void SvtURLBox::DisableHistory() +{ + bHistoryDisabled = TRUE; + UpdatePicklistForSmartProtocol_Impl(); +} + +//------------------------------------------------------------------------- +void SvtURLBox::SetBaseURL( const String& rURL ) +{ + ::vos::OGuard aGuard( SvtMatchContext_Impl::GetMutex() ); + + // Reset match lists + if ( pImp->pCompletions ) + pImp->pCompletions->Remove( 0, pImp->pCompletions->Count() ); + + if ( pImp->pURLs ) + pImp->pURLs->Remove( 0, pImp->pURLs->Count() ); + + aBaseURL = rURL; +} + +//------------------------------------------------------------------------- +/** Parse leading ~ for Unix systems, + does nothing for Windows + */ +sal_Bool SvtURLBox_Impl::TildeParsing( + String& +#ifdef UNX + aText +#endif + , String& +#ifdef UNX + aBaseURL +#endif +) +{ +#ifdef UNX + if( aText.Search( '~' ) == 0 ) + { + String aParseTilde; + sal_Bool bTrailingSlash = sal_True; // use trailing slash + + if( aText.Len() == 1 || aText.GetChar( 1 ) == '/' ) + { + // covers "~" or "~/..." cases + const char* aHomeLocation = getenv( "HOME" ); + if( !aHomeLocation ) + aHomeLocation = ""; + + aParseTilde = String::CreateFromAscii( aHomeLocation ); + + // in case the whole path is just "~" then there should + // be no trailing slash at the end + if( aText.Len() == 1 ) + bTrailingSlash = sal_False; + } + else + { + // covers "~username" and "~username/..." cases + xub_StrLen nNameEnd = aText.Search( '/' ); + String aUserName = aText.Copy( 1, ( nNameEnd != STRING_NOTFOUND ) ? nNameEnd : ( aText.Len() - 1 ) ); + + struct passwd* pPasswd = NULL; +#ifdef SOLARIS + Sequence< sal_Int8 > sBuf( 1024 ); + struct passwd aTmp; + sal_Int32 nRes = getpwnam_r( OUStringToOString( OUString( aUserName ), RTL_TEXTENCODING_ASCII_US ).getStr(), + &aTmp, + (char*)sBuf.getArray(), + 1024, + &pPasswd ); + if( !nRes && pPasswd ) + aParseTilde = String::CreateFromAscii( pPasswd->pw_dir ); + else + return sal_False; // no such user +#else + pPasswd = getpwnam( OUStringToOString( OUString( aUserName ), RTL_TEXTENCODING_ASCII_US ).getStr() ); + if( pPasswd ) + aParseTilde = String::CreateFromAscii( pPasswd->pw_dir ); + else + return sal_False; // no such user +#endif + + // in case the path is "~username" then there should + // be no trailing slash at the end + if( nNameEnd == STRING_NOTFOUND ) + bTrailingSlash = sal_False; + } + + if( !bTrailingSlash ) + { + if( !aParseTilde.Len() || aParseTilde.EqualsAscii( "/" ) ) + { + // "/" path should be converted to "/." + aParseTilde = String::CreateFromAscii( "/." ); + } + else + { + // "blabla/" path should be converted to "blabla" + aParseTilde.EraseTrailingChars( '/' ); + } + } + else + { + if( aParseTilde.GetChar( aParseTilde.Len() - 1 ) != '/' ) + aParseTilde += '/'; + if( aText.Len() > 2 ) + aParseTilde += aText.Copy( 2 ); + } + + aText = aParseTilde; + aBaseURL = String(); // tilde provide absolute path + } +#endif + + return sal_True; +} + +//------------------------------------------------------------------------- +void SvtURLBox::SetUrlFilter( const IUrlFilter* _pFilter ) +{ + pImp->pUrlFilter = _pFilter; +} + +//------------------------------------------------------------------------- +const IUrlFilter* SvtURLBox::GetUrlFilter( ) const +{ + return pImp->pUrlFilter; +} +// ----------------------------------------------------------------------------- +void SvtURLBox::SetFilter(const String& _sFilter) +{ + pImp->m_aFilters.clear(); + FilterMatch::createWildCardFilterList(_sFilter,pImp->m_aFilters); +} + diff --git a/svtools/source/control/prgsbar.cxx b/svtools/source/control/prgsbar.cxx new file mode 100755 index 000000000000..bb57d043b11d --- /dev/null +++ b/svtools/source/control/prgsbar.cxx @@ -0,0 +1,258 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#define _SV_PRGSBAR_CXX + +#include <tools/debug.hxx> +#include <vcl/status.hxx> +#include <svtools/prgsbar.hxx> + +// ======================================================================= + +#define PROGRESSBAR_OFFSET 3 +#define PROGRESSBAR_WIN_OFFSET 2 + +// ======================================================================= + +void ProgressBar::ImplInit() +{ + mnPercent = 0; + mbCalcNew = TRUE; + + ImplInitSettings( TRUE, TRUE, TRUE ); +} + +static WinBits clearProgressBarBorder( Window* pParent, WinBits nOrgStyle ) +{ + WinBits nOutStyle = nOrgStyle; + if( pParent && (nOrgStyle & WB_BORDER) != 0 ) + { + if( pParent->IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) ) + nOutStyle &= WB_BORDER; + } + return nOutStyle; +} + +// ----------------------------------------------------------------------- + +ProgressBar::ProgressBar( Window* pParent, WinBits nWinStyle ) : + Window( pParent, clearProgressBarBorder( pParent, nWinStyle ) ) +{ + SetOutputSizePixel( Size( 150, 20 ) ); + ImplInit(); +} + +// ----------------------------------------------------------------------- + +ProgressBar::ProgressBar( Window* pParent, const ResId& rResId ) : + Window( pParent, rResId ) +{ + ImplInit(); +} + +// ----------------------------------------------------------------------- + +ProgressBar::~ProgressBar() +{ +} + +// ----------------------------------------------------------------------- + +void ProgressBar::ImplInitSettings( BOOL bFont, + BOOL bForeground, BOOL bBackground ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + +/* !!! Derzeit unterstuetzen wir keine Textausgaben + if ( bFont ) + { + Font aFont; + aFont = rStyleSettings.GetAppFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetZoomedPointFont( aFont ); + } +*/ + + if ( bBackground ) + { + if( !IsControlBackground() && + IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) ) + { + if( (GetStyle() & WB_BORDER) ) + SetBorderStyle( WINDOW_BORDER_REMOVEBORDER ); + EnableChildTransparentMode( TRUE ); + SetPaintTransparent( TRUE ); + SetBackground(); + SetParentClipMode( PARENTCLIPMODE_NOCLIP ); + } + else + { + Color aColor; + if ( IsControlBackground() ) + aColor = GetControlBackground(); + else + aColor = rStyleSettings.GetFaceColor(); + SetBackground( aColor ); + } + } + + if ( bForeground || bFont ) + { + Color aColor = rStyleSettings.GetHighlightColor(); + if ( IsControlForeground() ) + aColor = GetControlForeground(); + if ( aColor.IsRGBEqual( GetBackground().GetColor() ) ) + { + if ( aColor.GetLuminance() > 100 ) + aColor.DecreaseLuminance( 64 ); + else + aColor.IncreaseLuminance( 64 ); + } + SetLineColor(); + SetFillColor( aColor ); +/* !!! Derzeit unterstuetzen wir keine Textausgaben + SetTextColor( aColor ); + SetTextFillColor(); +*/ + } +} + +// ----------------------------------------------------------------------- + +void ProgressBar::ImplDrawProgress( USHORT nOldPerc, USHORT nNewPerc ) +{ + if ( mbCalcNew ) + { + mbCalcNew = FALSE; + + Size aSize = GetOutputSizePixel(); + mnPrgsHeight = aSize.Height()-(PROGRESSBAR_WIN_OFFSET*2); + mnPrgsWidth = (mnPrgsHeight*2)/3; + maPos.Y() = PROGRESSBAR_WIN_OFFSET; + long nMaxWidth = (aSize.Width()-(PROGRESSBAR_WIN_OFFSET*2)+PROGRESSBAR_OFFSET); + USHORT nMaxCount = (USHORT)(nMaxWidth / (mnPrgsWidth+PROGRESSBAR_OFFSET)); + if ( nMaxCount <= 1 ) + nMaxCount = 1; + else + { + while ( ((10000/(10000/nMaxCount))*(mnPrgsWidth+PROGRESSBAR_OFFSET)) > nMaxWidth ) + nMaxCount--; + } + mnPercentCount = 10000/nMaxCount; + nMaxWidth = ((10000/(10000/nMaxCount))*(mnPrgsWidth+PROGRESSBAR_OFFSET))-PROGRESSBAR_OFFSET; + maPos.X() = (aSize.Width()-nMaxWidth)/2; + } + + ::DrawProgress( this, maPos, PROGRESSBAR_OFFSET, mnPrgsWidth, mnPrgsHeight, + nOldPerc*100, nNewPerc*100, mnPercentCount, + Rectangle( Point(), GetSizePixel() ) ); +} + +// ----------------------------------------------------------------------- + +void ProgressBar::Paint( const Rectangle& ) +{ + ImplDrawProgress( 0, mnPercent ); +} + +// ----------------------------------------------------------------------- + +void ProgressBar::Resize() +{ + mbCalcNew = TRUE; + if ( IsReallyVisible() ) + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void ProgressBar::SetValue( USHORT nNewPercent ) +{ + DBG_ASSERTWARNING( nNewPercent <= 100, "StatusBar::SetProgressValue(): nPercent > 100" ); + + if ( nNewPercent < mnPercent ) + { + mbCalcNew = TRUE; + mnPercent = nNewPercent; + if ( IsReallyVisible() ) + { + Invalidate(); + Update(); + } + } + else + { + ImplDrawProgress( mnPercent, nNewPercent ); + mnPercent = nNewPercent; + } +} + +// ----------------------------------------------------------------------- + +void ProgressBar::StateChanged( StateChangedType nType ) +{ +/* !!! Derzeit unterstuetzen wir keine Textausgaben + if ( (nType == STATE_CHANGE_ZOOM) || + (nType == STATE_CHANGE_CONTROLFONT) ) + { + ImplInitSettings( TRUE, FALSE, FALSE ); + Invalidate(); + } + else +*/ + if ( nType == STATE_CHANGE_CONTROLFOREGROUND ) + { + ImplInitSettings( FALSE, TRUE, FALSE ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings( FALSE, FALSE, TRUE ); + Invalidate(); + } + + Window::StateChanged( nType ); +} + +// ----------------------------------------------------------------------- + +void ProgressBar::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + ImplInitSettings( TRUE, TRUE, TRUE ); + Invalidate(); + } + + Window::DataChanged( rDCEvt ); +} + diff --git a/svtools/source/control/roadmap.cxx b/svtools/source/control/roadmap.cxx new file mode 100755 index 000000000000..f4c04a7000af --- /dev/null +++ b/svtools/source/control/roadmap.cxx @@ -0,0 +1,1018 @@ +/************************************************************************* + * + * 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_svtools.hxx" +#include <svtools/roadmap.hxx> + +#ifndef _STRING_HXX +#define _STRING_HXX +#endif + +#include <vector> +#include <algorithm> +#include <vcl/bitmap.hxx> +#include <tools/color.hxx> +#include <memory> + +#define ROADMAP_INDENT_X 4 +#define ROADMAP_INDENT_Y 27 +#define ROADMAP_ITEM_DISTANCE_Y 6 +#define RMINCOMPLETE -1 +#define NADDITEM 1 +#define INCOMPLETELABEL ::String::CreateFromAscii("...") // TODO: Cast to String + +//......................................................................... +namespace svt +{ +//......................................................................... + + typedef std::vector< ::rtl::OUString > S_Vector; + typedef std::vector< RoadmapItem* > HL_Vector; + + //===================================================================== + //= ColorChanger + //===================================================================== + class IDLabel : public FixedText + { + public: + IDLabel( Window* _pParent, WinBits _nWinStyle = 0 ); + ~IDLabel( ); + virtual void DataChanged( const DataChangedEvent& rDCEvt ); + }; + + //===================================================================== + //= ColorChanger + //===================================================================== + class ColorChanger + { + protected: + OutputDevice* m_pDev; + + public: + ColorChanger( OutputDevice* _pDev, const Color& _rNewLineColor, const Color& _rNewFillColor ) + :m_pDev( _pDev ) + { + m_pDev->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); + m_pDev->SetLineColor( _rNewLineColor ); + m_pDev->SetFillColor( _rNewFillColor ); + } + + ~ColorChanger() + { + m_pDev->Pop(); + } + }; + + //===================================================================== + //= RoadmapItem + //===================================================================== + class RoadmapItem : public RoadmapTypes + { + private: + IDLabel* mpID; + HyperLabel* mpDescription; + const Size m_aItemPlayground; + + public: + RoadmapItem( ORoadmap& _rParent, const Size& _rItemPlayground ); + ~RoadmapItem( ); + + void SetID( sal_Int16 _ID ); + sal_Int16 GetID() const; + + void SetIndex( ItemIndex _Index ); + ItemIndex GetIndex() const; + + void SetLabel( const ::rtl::OUString& _rText ); + ::rtl::OUString GetLabel( ); + + void Update( ItemIndex _RMIndex, const ::rtl::OUString& _rText ); + + void SetPosition( RoadmapItem* OldHyperLabel ); + + void ToggleBackgroundColor( const Color& _rGBColor ); + void SetInteractive( sal_Bool _bInteractive ); + + void SetClickHdl( const Link& rLink ); + const Link& GetClickHdl() const; + void SetZOrder( RoadmapItem* pRefRoadmapHyperLabel, USHORT nFlags ); + void Enable( BOOL bEnable = TRUE); + BOOL IsEnabled() const; + void GrabFocus(); + + bool Contains( const Window* _pWindow ) const; + + HyperLabel* GetDescriptionHyperLabel() const { return mpDescription; } + + private: + void ImplUpdateIndex( const ItemIndex _nIndex ); + void ImplUpdatePosSize(); + }; + + //===================================================================== + //= RoadmapImpl + //===================================================================== + class RoadmapImpl : public RoadmapTypes + { + protected: + const ORoadmap& m_rAntiImpl; + Link m_aSelectHdl; + BitmapEx m_aPicture; + HL_Vector m_aRoadmapSteps; + ItemId m_iCurItemID; + sal_Bool m_bInteractive; + sal_Bool m_bComplete; + Size m_aItemSizePixel; + + public: + RoadmapImpl( const ORoadmap& _rAntiImpl ) + :m_rAntiImpl( _rAntiImpl ) + ,m_iCurItemID( -1 ) + ,m_bInteractive( sal_True ) + ,m_bComplete( sal_True ) + { + } + + RoadmapItem* InCompleteHyperLabel; + + void addHyperLabel( RoadmapItem* _rRoadmapStep ) { m_aRoadmapSteps.push_back(_rRoadmapStep); } + + HL_Vector& getHyperLabels() { return m_aRoadmapSteps; } + const HL_Vector& getHyperLabels() const { return m_aRoadmapSteps; } + + void insertHyperLabel( ItemIndex _Index, RoadmapItem* _rRoadmapStep ) { m_aRoadmapSteps.insert( m_aRoadmapSteps.begin() + _Index, _rRoadmapStep ); } + + ItemIndex getItemCount() const { return m_aRoadmapSteps.size();} + + void setCurItemID( ItemId i ) {m_iCurItemID = i; } + ItemId getCurItemID() const { return m_iCurItemID; } + + void setInteractive(const sal_Bool _bInteractive) {m_bInteractive = _bInteractive; } + sal_Bool isInteractive() const { return m_bInteractive; }; + + void setComplete(const sal_Bool _bComplete) {m_bComplete = _bComplete; } + sal_Bool isComplete() const { return m_bComplete; }; + + void setPicture( const BitmapEx& _rPic ) { m_aPicture = _rPic; } + const BitmapEx& getPicture( ) const { return m_aPicture; } + + void setSelectHdl( const Link& _rHdl ) { m_aSelectHdl = _rHdl; } + const Link& getSelectHdl( ) const { return m_aSelectHdl; } + + void initItemSize(); + const Size& getItemSize() const { return m_aItemSizePixel; } + + void removeHyperLabel( ItemIndex _Index ) + { + if ( ( _Index > -1 ) && ( _Index < getItemCount() ) ) + { + delete m_aRoadmapSteps[_Index]; + m_aRoadmapSteps.erase( m_aRoadmapSteps.begin() + _Index); + } + } + }; + + + //===================================================================== + //= Roadmap + //===================================================================== + //--------------------------------------------------------------------- + void RoadmapImpl::initItemSize() + { + Size aLabelSize( m_rAntiImpl.GetOutputSizePixel() ); + aLabelSize.Height() = m_rAntiImpl.LogicToPixel( Size( 0, LABELBASEMAPHEIGHT ), MAP_APPFONT ).Height(); + aLabelSize.Width() -= m_rAntiImpl.LogicToPixel( Size( 2 * ROADMAP_INDENT_X, 0 ), MAP_APPFONT ).Width(); + m_aItemSizePixel = aLabelSize; + } + + //===================================================================== + //= Roadmap + //===================================================================== + //--------------------------------------------------------------------- + ORoadmap::ORoadmap( Window* _pParent, const ResId& _rId ) + :Control( _pParent, _rId ) + ,m_pImpl( new RoadmapImpl( *this ) ) + { + implInit(); + } + + //--------------------------------------------------------------------- + ORoadmap::ORoadmap( Window* _pParent, WinBits _nWinStyle ) + :Control( _pParent, _nWinStyle ) + ,m_pImpl( new RoadmapImpl( *this ) ) + + { + implInit(); + } + + //--------------------------------------------------------------------- + void ORoadmap::implInit() + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Color aTextColor = rStyleSettings.GetFieldTextColor(); + Font aFont = GetFont( ); + aFont.SetColor( aTextColor ); + aFont.SetWeight( WEIGHT_BOLD ); + aFont.SetUnderline( UNDERLINE_SINGLE ); + SetFont( aFont ); + SetBackground( Wallpaper( rStyleSettings.GetFieldColor() ) ); + m_pImpl->InCompleteHyperLabel = NULL; + m_pImpl->setCurItemID(-1 ); + m_pImpl->setComplete( sal_True ); + + // Roadmap control should be reachable as one unit with a Tab key + // the next Tab key should spring out of the control. + // To reach it the control itself should get focus and set it + // on entries. The entries themself should not be reachable with + // the Tab key directly. So each entry should have WB_NOTABSTOP. + // + // In other words the creator should create the control with the following + // flags: + // SetStyle( ( GetStyle() | WB_TABSTOP ) & ~WB_DIALOGCONTROL ); + +// TODO: if somebody sets a new font from outside (OutputDevice::SetFont), we would have to react +// on this with calculating a new bold font. +// Unfortunately, the OutputDevice does not offer a notify mechanism for a changed font. +// So settings the font from outside is simply a forbidded scenario at the moment + EnableMapMode( sal_False ); + } + + //--------------------------------------------------------------------- + ORoadmap::~ORoadmap( ) + { + HL_Vector aItemsCopy = m_pImpl->getHyperLabels(); + m_pImpl->getHyperLabels().clear(); + for ( HL_Vector::iterator i = aItemsCopy.begin(); i< aItemsCopy.end(); ++i ) + { + delete *i; + } + if ( ! m_pImpl->isComplete() ) + delete m_pImpl->InCompleteHyperLabel; + delete m_pImpl; + m_pImpl = NULL; + } + + + RoadmapTypes::ItemId ORoadmap::GetCurrentRoadmapItemID() const + { + return m_pImpl->getCurItemID(); + } + + + RoadmapItem* ORoadmap::GetPreviousHyperLabel( ItemIndex _Index) + { + RoadmapItem* pOldItem = NULL; + if ( _Index > 0 ) + pOldItem = m_pImpl->getHyperLabels().at( _Index - 1 ); + return pOldItem; + } + + + //--------------------------------------------------------------------- + + RoadmapItem* ORoadmap::InsertHyperLabel( ItemIndex _Index, const ::rtl::OUString& _sLabel, ItemId _RMID, sal_Bool _bEnabled) + { + if ( m_pImpl->getItemCount() == 0 ) + m_pImpl->initItemSize(); + + RoadmapItem* pItem = NULL; + RoadmapItem* pOldItem = GetPreviousHyperLabel( _Index ); + + pItem = new RoadmapItem( *this, m_pImpl->getItemSize() ); + if ( _RMID != RMINCOMPLETE ) + { + pItem->SetInteractive( m_pImpl->isInteractive() ); + m_pImpl->insertHyperLabel( _Index, pItem ); + } + else + { + pItem->SetInteractive( sal_False ); + } + pItem->SetPosition( pOldItem ); + pItem->Update( _Index, _sLabel ); + pItem->SetClickHdl(LINK( this, ORoadmap, ImplClickHdl ) ); + pItem->SetID( _RMID ); + pItem->SetIndex( _Index ); + if (!_bEnabled) + pItem->Enable( _bEnabled ); + return pItem; + } + + //--------------------------------------------------------------------- + void ORoadmap::SetRoadmapBitmap( const BitmapEx& _rBmp, sal_Bool _bInvalidate ) + { + m_pImpl->setPicture( _rBmp ); + if ( _bInvalidate ) + Invalidate( ); + } + + //--------------------------------------------------------------------- + const BitmapEx& ORoadmap::GetRoadmapBitmap( ) const + { + return m_pImpl->getPicture( ); + } + + //--------------------------------------------------------------------- + void ORoadmap::SetRoadmapInteractive( sal_Bool _bInteractive ) + { + m_pImpl->setInteractive( _bInteractive ); + + const HL_Vector& rItems = m_pImpl->getHyperLabels(); + for ( HL_Vector::const_iterator i = rItems.begin(); + i < rItems.end(); + ++i + ) + { + (*i)->SetInteractive( _bInteractive ); + } + } + + //--------------------------------------------------------------------- + sal_Bool ORoadmap::IsRoadmapInteractive() + { + return m_pImpl->isInteractive(); + } + + //--------------------------------------------------------------------- + void ORoadmap::SetRoadmapComplete( sal_Bool _bComplete ) + { + sal_Bool bWasComplete = m_pImpl->isComplete(); + m_pImpl->setComplete( _bComplete ); + if ( _bComplete ) + { + if ( m_pImpl->InCompleteHyperLabel != NULL) + { + delete m_pImpl->InCompleteHyperLabel; + m_pImpl->InCompleteHyperLabel = NULL; + } + } + else if ( bWasComplete ) + m_pImpl->InCompleteHyperLabel = InsertHyperLabel( m_pImpl->getItemCount(), ::String::CreateFromAscii( "..." ), RMINCOMPLETE ); + } + + //--------------------------------------------------------------------- + void ORoadmap::UpdatefollowingHyperLabels( ItemIndex _nIndex ) + { + const HL_Vector& rItems = m_pImpl->getHyperLabels(); + if ( _nIndex < (ItemIndex)rItems.size() ) + { + RoadmapItem* pItem = NULL; + for ( HL_Vector::const_iterator i = rItems.begin() + _nIndex; + i< rItems.end(); + ++i, ++_nIndex + ) + { + pItem = *i; + + pItem->SetIndex( _nIndex ); + pItem->SetPosition( GetPreviousHyperLabel( _nIndex ) ); + } + } + if ( ! m_pImpl->isComplete() ) + { + RoadmapItem* pOldItem = GetPreviousHyperLabel( m_pImpl->getItemCount() ); + m_pImpl->InCompleteHyperLabel->SetPosition( pOldItem ); + m_pImpl->InCompleteHyperLabel->Update( m_pImpl->getItemCount(), ::String::CreateFromAscii("...") ); + } + } + + //--------------------------------------------------------------------- + void ORoadmap::ReplaceRoadmapItem( ItemIndex _Index, const ::rtl::OUString& _RoadmapItem, ItemId _RMID, sal_Bool _bEnabled ) + { + RoadmapItem* pItem = GetByIndex( _Index); + if ( pItem != NULL ) + { + pItem->Update( _Index, _RoadmapItem ); + pItem->SetID( _RMID ); + pItem->Enable( _bEnabled ); + } + } + + //--------------------------------------------------------------------- + RoadmapTypes::ItemIndex ORoadmap::GetItemCount() const + { + return m_pImpl->getItemCount(); + } + + //--------------------------------------------------------------------- + RoadmapTypes::ItemId ORoadmap::GetItemID( ItemIndex _nIndex ) const + { + const RoadmapItem* pHyperLabel = GetByIndex( _nIndex ); + if ( pHyperLabel ) + return pHyperLabel->GetID(); + return -1; + } + + //--------------------------------------------------------------------- + RoadmapTypes::ItemIndex ORoadmap::GetItemIndex( ItemId _nID ) const + { + ItemId nLocID = 0; + const HL_Vector& rItems = m_pImpl->getHyperLabels(); + for ( HL_Vector::const_iterator i = rItems.begin(); + i < rItems.end(); + ++i + ) + { + nLocID = (*i)->GetID(); + if ( nLocID == _nID ) + return ItemIndex( i - rItems.begin() ); + } + return -1; + } + + //--------------------------------------------------------------------- + void ORoadmap::InsertRoadmapItem( ItemIndex _Index, const ::rtl::OUString& _RoadmapItem, ItemId _nUniqueId, sal_Bool _bEnabled ) + { + InsertHyperLabel( _Index, _RoadmapItem, _nUniqueId, _bEnabled ); + // Todo: YPos is superfluous, if items are always appended + UpdatefollowingHyperLabels( _Index + 1 ); + } + + //--------------------------------------------------------------------- + void ORoadmap::DeleteRoadmapItem( ItemIndex _Index ) + { + if ( m_pImpl->getItemCount() > 0 && ( _Index > -1) && ( _Index < m_pImpl->getItemCount() ) ) + { + m_pImpl->removeHyperLabel( _Index ); + UpdatefollowingHyperLabels( _Index ); + } + } + + //--------------------------------------------------------------------- + sal_Bool ORoadmap::IsRoadmapComplete( ) const + { + return m_pImpl->isComplete(); + } + + //--------------------------------------------------------------------- + sal_Bool ORoadmap::IsRoadmapItemEnabled( ItemId _nItemId, ItemIndex _nStartIndex ) const + { + const RoadmapItem* _pLabelItem = GetByID( _nItemId, _nStartIndex ); + return _pLabelItem ? _pLabelItem->IsEnabled() : sal_False; + } + + //--------------------------------------------------------------------- + void ORoadmap::EnableRoadmapItem( ItemId _nItemId, sal_Bool _bEnable, ItemIndex _nStartIndex ) + { + RoadmapItem* pItem = GetByID( _nItemId, _nStartIndex ); + if ( pItem != NULL ) + pItem->Enable( _bEnable ); + } + + //--------------------------------------------------------------------- + void ORoadmap::ChangeRoadmapItemLabel( ItemId _nID, const ::rtl::OUString& _sLabel, ItemIndex _nStartIndex ) + { + RoadmapItem* pItem = GetByID( _nID, _nStartIndex ); + if ( pItem != NULL ) + { + pItem->Update( pItem->GetIndex(), _sLabel ); + + const HL_Vector& rItems = m_pImpl->getHyperLabels(); + for ( HL_Vector::const_iterator i = rItems.begin() + _nStartIndex; + i < rItems.end(); + ++i + ) + { + (*i)->SetPosition( GetPreviousHyperLabel( i - rItems.begin() ) ); + } + } + } + + //--------------------------------------------------------------------- + + ::rtl::OUString ORoadmap::GetRoadmapItemLabel( ItemId _nID, ItemIndex _nStartIndex ) + { + RoadmapItem* pItem = GetByID( _nID, _nStartIndex ); + if ( pItem != NULL ) + return pItem->GetLabel(); + else + return ::rtl::OUString(); + } + + //--------------------------------------------------------------------- + void ORoadmap::ChangeRoadmapItemID( ItemId _nID, ItemId _NewID, ItemIndex _nStartIndex ) + { + RoadmapItem* pItem = GetByID( _nID, _nStartIndex ); + if ( pItem != NULL ) + pItem->SetID( _NewID ); + } + + //--------------------------------------------------------------------- + RoadmapItem* ORoadmap::GetByID( ItemId _nID, ItemIndex _nStartIndex) + { + ItemId nLocID = 0; + const HL_Vector& rItems = m_pImpl->getHyperLabels(); + for ( HL_Vector::const_iterator i = rItems.begin() + _nStartIndex; + i < rItems.end(); + ++i + ) + { + nLocID = (*i)->GetID(); + if ( nLocID == _nID ) + return *i; + } + return NULL; + } + + //--------------------------------------------------------------------- + const RoadmapItem* ORoadmap::GetByID( ItemId _nID, ItemIndex _nStartIndex ) const + { + return const_cast< ORoadmap* >( this )->GetByID( _nID, _nStartIndex ); + } + + //--------------------------------------------------------------------- + RoadmapItem* ORoadmap::GetByIndex( ItemIndex _nItemIndex) + { + const HL_Vector& rItems = m_pImpl->getHyperLabels(); + if ( ( _nItemIndex > -1 ) && ( _nItemIndex < (ItemIndex)rItems.size() ) ) + { + return rItems.at( _nItemIndex ); + } + return NULL; + } + + //--------------------------------------------------------------------- + const RoadmapItem* ORoadmap::GetByIndex( ItemIndex _nItemIndex ) const + { + return const_cast< ORoadmap* >( this )->GetByIndex( _nItemIndex ); + } + + //--------------------------------------------------------------------- + RoadmapTypes::ItemId ORoadmap::GetNextAvailableItemId( ItemIndex _nNewIndex ) + { + RoadmapItem* pItem = NULL; + + ItemIndex searchIndex = ++_nNewIndex; + while ( searchIndex < m_pImpl->getItemCount() ) + { + pItem = GetByIndex( searchIndex ); + if ( pItem->IsEnabled() ) + return pItem->GetID( ); + + ++searchIndex; + } + return -1; + } + + //--------------------------------------------------------------------- + RoadmapTypes::ItemId ORoadmap::GetPreviousAvailableItemId( ItemIndex _nNewIndex ) + { + RoadmapItem* pItem = NULL; + ItemIndex searchIndex = --_nNewIndex; + while ( searchIndex > -1 ) + { + pItem = GetByIndex( searchIndex ); + if ( pItem->IsEnabled() ) + return pItem->GetID( ); + + searchIndex--; + } + return -1; + } + + //--------------------------------------------------------------------- + void ORoadmap::DeselectOldRoadmapItems() + { + const HL_Vector& rItems = m_pImpl->getHyperLabels(); + for ( HL_Vector::const_iterator i = rItems.begin(); + i < rItems.end(); + ++i + ) + { + (*i)->ToggleBackgroundColor( COL_TRANSPARENT ); + } + } + + //--------------------------------------------------------------------- + void ORoadmap::SetItemSelectHdl( const Link& _rHdl ) + { + m_pImpl->setSelectHdl( _rHdl ); + } + + //--------------------------------------------------------------------- + Link ORoadmap::GetItemSelectHdl( ) const + { + return m_pImpl->getSelectHdl(); + } + + //--------------------------------------------------------------------- + void ORoadmap::Select() + { + GetItemSelectHdl().Call( this ); + CallEventListeners( VCLEVENT_ROADMAP_ITEMSELECTED ); + } + + //--------------------------------------------------------------------- + void ORoadmap::GetFocus() + { + RoadmapItem* pCurHyperLabel = GetByID( GetCurrentRoadmapItemID() ); + if ( pCurHyperLabel != NULL ) + pCurHyperLabel->GrabFocus(); + } + + //--------------------------------------------------------------------- + sal_Bool ORoadmap::SelectRoadmapItemByID( ItemId _nNewID ) + { + DeselectOldRoadmapItems(); + RoadmapItem* pItem = GetByID( _nNewID ); + if ( pItem != NULL ) + { + if ( pItem->IsEnabled() ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + pItem->ToggleBackgroundColor( rStyleSettings.GetHighlightColor() ); //HighlightColor + + pItem->GrabFocus(); + m_pImpl->setCurItemID(_nNewID); + + Select(); + return sal_True; + } + } + return sal_False; + } + + //--------------------------------------------------------------------- + void ORoadmap::Paint( const Rectangle& _rRect ) + { + Control::Paint( _rRect ); + + + // draw the bitmap + if ( !!m_pImpl->getPicture() ) + { + Size aBitmapSize = m_pImpl->getPicture().GetSizePixel(); + Size aMySize = GetOutputSizePixel(); + + Point aBitmapPos( aMySize.Width() - aBitmapSize.Width(), aMySize.Height() - aBitmapSize.Height() ); + + // draw it + DrawBitmapEx( aBitmapPos, m_pImpl->getPicture() ); + } + + //................................................................. + // draw the headline + DrawHeadline(); + } + + //--------------------------------------------------------------------- + void ORoadmap::DrawHeadline() + { + Point aTextPos = LogicToPixel( Point( ROADMAP_INDENT_X, 8 ), MAP_APPFONT ); + + Size aOutputSize( GetOutputSizePixel() ); + + // draw it + DrawText( Rectangle( aTextPos, aOutputSize ), GetText(), TEXT_DRAW_LEFT | TEXT_DRAW_TOP | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK ); + DrawTextLine( aTextPos, aOutputSize.Width(), STRIKEOUT_NONE, UNDERLINE_SINGLE, UNDERLINE_NONE, sal_False ); + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + SetLineColor( rStyleSettings.GetFieldTextColor()); + SetTextColor(rStyleSettings.GetFieldTextColor()); + } + + //--------------------------------------------------------------------- + RoadmapItem* ORoadmap::GetByPointer(Window* pWindow) + { + const HL_Vector& rItems = m_pImpl->getHyperLabels(); + for ( HL_Vector::const_iterator i = rItems.begin(); + i < rItems.end(); + ++i + ) + { + if ( (*i)->Contains( pWindow ) ) + return *i; + } + return NULL; + } + + //--------------------------------------------------------------------- + long ORoadmap::PreNotify( NotifyEvent& _rNEvt ) + { + // capture KeyEvents for taskpane cycling + if ( _rNEvt.GetType() == EVENT_KEYINPUT ) + { + Window* pWindow = _rNEvt.GetWindow(); + RoadmapItem* pItem = GetByPointer( pWindow ); + if ( pItem != NULL ) + { + sal_Int16 nKeyCode = _rNEvt.GetKeyEvent()->GetKeyCode().GetCode(); + switch( nKeyCode ) + { + case KEY_UP: + { // Note: Performancewise this is not optimal, because we search for an ID in the labels + // and afterwards we search again for a label with the appropriate ID -> + // unnecessarily we search twice!!! + ItemId nPrevItemID = GetPreviousAvailableItemId( pItem->GetIndex() ); + if ( nPrevItemID != -1 ) + return SelectRoadmapItemByID( nPrevItemID ); + } + break; + case KEY_DOWN: + { + ItemId nNextItemID = GetNextAvailableItemId( pItem->GetIndex() ); + if ( nNextItemID != -1 ) + return SelectRoadmapItemByID( nNextItemID ); + } + break; + case KEY_SPACE: + return SelectRoadmapItemByID( pItem->GetID() ); + } + } + } + return Window::PreNotify( _rNEvt ); + } + + //--------------------------------------------------------------------- + IMPL_LINK(ORoadmap, ImplClickHdl, HyperLabel*, _CurHyperLabel) + { + return SelectRoadmapItemByID( _CurHyperLabel->GetID() ); + } + + + + //--------------------------------------------------------------------- + void ORoadmap::DataChanged( const DataChangedEvent& rDCEvt ) + { + if ((( rDCEvt.GetType() == DATACHANGED_SETTINGS ) || + ( rDCEvt.GetType() == DATACHANGED_DISPLAY )) && + ( rDCEvt.GetFlags() & SETTINGS_STYLE )) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + SetBackground( Wallpaper( rStyleSettings.GetFieldColor() ) ); + Color aTextColor = rStyleSettings.GetFieldTextColor(); + Font aFont = GetFont(); + aFont.SetColor( aTextColor ); + SetFont( aFont ); + RoadmapTypes::ItemId curItemID = GetCurrentRoadmapItemID(); + RoadmapItem* pLabelItem = GetByID( curItemID ); + pLabelItem->ToggleBackgroundColor(rStyleSettings.GetHighlightColor()); + Invalidate(); + } + } + + + //--------------------------------------------------------------------- + RoadmapItem::RoadmapItem( ORoadmap& _rParent, const Size& _rItemPlayground ) + :m_aItemPlayground( _rItemPlayground ) + { + mpID = new IDLabel( &_rParent, WB_WORDBREAK ); + mpID->SetTextColor( mpID->GetSettings().GetStyleSettings().GetFieldTextColor( ) ); + mpID->Show(); + mpDescription = new HyperLabel( &_rParent, WB_NOTABSTOP | WB_WORDBREAK ); + mpDescription->Show(); + } + + //--------------------------------------------------------------------- + bool RoadmapItem::Contains( const Window* _pWindow ) const + { + return ( mpID == _pWindow ) || ( mpDescription == _pWindow ); + } + + //--------------------------------------------------------------------- + void RoadmapItem::GrabFocus() + { + if ( mpDescription ) + mpDescription->GrabFocus(); + } + + //--------------------------------------------------------------------- + void RoadmapItem::SetInteractive( sal_Bool _bInteractive ) + { + if ( mpDescription ) + mpDescription->SetInteractive(_bInteractive); + } + + //--------------------------------------------------------------------- + void RoadmapItem::SetID( sal_Int16 _ID ) + { + if ( mpDescription ) + mpDescription->SetID(_ID); + } + + //--------------------------------------------------------------------- + sal_Int16 RoadmapItem::GetID() const + { + return mpDescription ? mpDescription->GetID() : sal_Int16(-1); + } + + //--------------------------------------------------------------------- + void RoadmapItem::ImplUpdateIndex( const ItemIndex _nIndex ) + { + if ( mpDescription ) + mpDescription->SetIndex( _nIndex ); + + if ( mpID ) + { + ::rtl::OUString aIDText = ::rtl::OUString::valueOf( (sal_Int32)( _nIndex + 1 ) ) + ::rtl::OUString::createFromAscii( "." ); + mpID->SetText( aIDText ); + } + + // update the geometry of both controls + ImplUpdatePosSize(); + } + + //--------------------------------------------------------------------- + void RoadmapItem::SetIndex( ItemIndex _Index ) + { + ImplUpdateIndex( _Index ); + } + + //--------------------------------------------------------------------- + RoadmapTypes::ItemIndex RoadmapItem::GetIndex() const + { + return mpDescription ? mpDescription->GetIndex() : ItemIndex(-1); + } + + //--------------------------------------------------------------------- + void RoadmapItem::SetLabel( const ::rtl::OUString& _rText ) + { + if ( mpDescription ) + mpDescription->SetText(_rText); + } + + //--------------------------------------------------------------------- + ::rtl::OUString RoadmapItem::GetLabel( ) + { + return mpDescription ? mpDescription->GetText() : String(); + } + + //--------------------------------------------------------------------- + void RoadmapItem::SetPosition( RoadmapItem* _pOldItem ) + { + Point aIDPos; + if ( _pOldItem == NULL ) + { + aIDPos = mpID->LogicToPixel( Point( ROADMAP_INDENT_X, ROADMAP_INDENT_Y ), MAP_APPFONT ); + } + else + { + Size aOldSize = _pOldItem->GetDescriptionHyperLabel()->GetSizePixel(); + + aIDPos = _pOldItem->mpID->GetPosPixel(); + aIDPos.Y() += aOldSize.Height(); + aIDPos.Y() += mpID->GetParent()->LogicToPixel( Size( 0, ROADMAP_ITEM_DISTANCE_Y ) ).Height(); + } + mpID->SetPosPixel( aIDPos ); + + sal_Int32 nDescPos = aIDPos.X() + mpID->GetSizePixel().Width(); + mpDescription->SetPosPixel( Point( nDescPos, aIDPos.Y() ) ); + } + + //--------------------------------------------------------------------- + void RoadmapItem::SetZOrder( RoadmapItem* pRefRoadmapHyperLabel, USHORT nFlags ) + { + if (pRefRoadmapHyperLabel == NULL) + mpDescription->SetZOrder( NULL, nFlags); //WINDOW_ZORDER_FIRST ); + else + mpDescription->SetZOrder( pRefRoadmapHyperLabel->mpDescription, nFlags); //, WINDOW_ZORDER_BEHIND ); + } + + //--------------------------------------------------------------------- + void RoadmapItem::Enable( BOOL _bEnable) + { + mpID->Enable(_bEnable); + mpDescription->Enable(_bEnable); + } + + //--------------------------------------------------------------------- + BOOL RoadmapItem::IsEnabled() const + { + return mpID->IsEnabled(); + } + + //--------------------------------------------------------------------- + void RoadmapItem::ToggleBackgroundColor( const Color& _rGBColor ) + { + if (_rGBColor == COL_TRANSPARENT) + { + mpID->SetTextColor( mpID->GetSettings().GetStyleSettings().GetFieldTextColor( ) ); + mpID->SetControlBackground( COL_TRANSPARENT ); + } + else + { + mpID->SetControlBackground( mpID->GetSettings().GetStyleSettings().GetHighlightColor() ); + mpID->SetTextColor( mpID->GetSettings().GetStyleSettings().GetHighlightTextColor( ) ); + } + mpDescription->ToggleBackgroundColor(_rGBColor); + } + + //--------------------------------------------------------------------- + void RoadmapItem::ImplUpdatePosSize() + { + // calculate widths + long nIDWidth = mpID->GetTextWidth( mpID->GetText() ); + long nMaxIDWidth = mpID->GetTextWidth( ::rtl::OUString::createFromAscii( "100." ) ); + nIDWidth = ::std::min( nIDWidth, nMaxIDWidth ); + + // check how many space the description would need + Size aDescriptionSize = mpDescription->CalcMinimumSize( m_aItemPlayground.Width() - nIDWidth ); + + // position and size both controls + Size aIDSize( nIDWidth, aDescriptionSize.Height() ); + mpID->SetSizePixel( aIDSize ); + + Point aIDPos = mpID->GetPosPixel(); + mpDescription->SetPosPixel( Point( aIDPos.X() + nIDWidth, aIDPos.Y() ) ); + mpDescription->SetSizePixel( aDescriptionSize ); + } + + //--------------------------------------------------------------------- + void RoadmapItem::Update( ItemIndex _RMIndex, const ::rtl::OUString& _rText ) + { + // update description label + mpDescription->SetLabel( _rText ); + + // update the index in both controls, which triggers updating the geometry of both + ImplUpdateIndex( _RMIndex ); + } + + //--------------------------------------------------------------------- + RoadmapItem::~RoadmapItem( ) + { + { + ::std::auto_ptr<Control> aTemp(mpID); + mpID = NULL; + } + { + ::std::auto_ptr<Control> aTemp(mpDescription); + mpDescription = NULL; + } + } + + //--------------------------------------------------------------------- + void RoadmapItem::SetClickHdl( const Link& rLink ) + { + if ( mpDescription ) + mpDescription->SetClickHdl( rLink); + } + + //--------------------------------------------------------------------- + const Link& RoadmapItem::GetClickHdl( ) const + { + return mpDescription->GetClickHdl(); + } + + //--------------------------------------------------------------------- + IDLabel::IDLabel( Window* _pParent, WinBits _nWinStyle ) + :FixedText( _pParent, _nWinStyle ) + { + + } + + //--------------------------------------------------------------------- + IDLabel::~IDLabel( ) + { + } + + //--------------------------------------------------------------------- + void IDLabel::DataChanged( const DataChangedEvent& rDCEvt ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + FixedText::DataChanged( rDCEvt ); + if ((( rDCEvt.GetType() == DATACHANGED_SETTINGS ) || + ( rDCEvt.GetType() == DATACHANGED_DISPLAY )) && + ( rDCEvt.GetFlags() & SETTINGS_STYLE )) + { + const Color& rGBColor = GetControlBackground(); + if (rGBColor == COL_TRANSPARENT) + SetTextColor( rStyleSettings.GetFieldTextColor( ) ); + else + { + SetControlBackground(rStyleSettings.GetHighlightColor()); + SetTextColor( rStyleSettings.GetHighlightTextColor( ) ); + } + Invalidate(); + } + } + + + + +//......................................................................... +} // namespace svt +//......................................................................... diff --git a/svtools/source/control/ruler.cxx b/svtools/source/control/ruler.cxx new file mode 100755 index 000000000000..bdbcd253c198 --- /dev/null +++ b/svtools/source/control/ruler.cxx @@ -0,0 +1,3184 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#include <string.h> +#include <tools/debug.hxx> +#include <vcl/svapp.hxx> +#include <tools/poly.hxx> +#include <vcl/i18nhelp.hxx> + +#define _SV_RULER_CXX +#include <svtools/ruler.hxx> + +// ======================================================================= + +#define RULER_OFF 3 +#define RULER_TEXTOFF 2 +#define RULER_RESIZE_OFF 4 +#define RULER_LINE_WIDTH 7 +#define RULER_MIN_SIZE 3 + +#define RULER_TICK1_WIDTH 1 +#define RULER_TICK2_WIDTH 3 +#define RULER_TICK3_WIDTH 5 + +#define RULER_VAR_SIZE 8 + +#define RULER_TAB_HEIGHT2 2 +#define RULER_TAB_WIDTH2 2 +#define RULER_TAB_CWIDTH 8 +#define RULER_TAB_CWIDTH2 4 +#define RULER_TAB_CWIDTH3 4 +#define RULER_TAB_CWIDTH4 2 +#define RULER_TAB_DHEIGHT 4 +#define RULER_TAB_DHEIGHT2 1 +#define RULER_TAB_DWIDTH 5 +#define RULER_TAB_DWIDTH2 3 +#define RULER_TAB_DWIDTH3 3 +#define RULER_TAB_DWIDTH4 1 + +#define RULER_UPDATE_LINES 0x01 +#define RULER_UPDATE_DRAW 0x02 + +#define RULER_CLIP 150 + +// ======================================================================= + +#define RULER_UNIT_MM 0 +#define RULER_UNIT_CM 1 +#define RULER_UNIT_M 2 +#define RULER_UNIT_KM 3 +#define RULER_UNIT_INCH 4 +#define RULER_UNIT_FOOT 5 +#define RULER_UNIT_MILE 6 +#define RULER_UNIT_POINT 7 +#define RULER_UNIT_PICA 8 +#define RULER_UNIT_COUNT 9 + +// ----------------- +// - ImplRulerData - +// ----------------- +class ImplRulerData +{ + friend class Ruler; + +private: + RulerLine* pLines; + RulerArrow* pArrows; + RulerBorder* pBorders; + RulerIndent* pIndents; + RulerTab* pTabs; + long nNullVirOff; + long nRulVirOff; + long nRulWidth; + long nPageOff; + long nPageWidth; + long nNullOff; + long nMargin1; + long nMargin2; + USHORT nLines; + USHORT nArrows; + USHORT nBorders; + USHORT nIndents; + USHORT nTabs; + USHORT nMargin1Style; + USHORT nMargin2Style; + BOOL bAutoPageWidth; + BOOL bTextRTL; + +#ifdef _SV_RULER_CXX +public: + ImplRulerData(); + ~ImplRulerData(); + ImplRulerData& operator=( const ImplRulerData& rData ); +#endif +}; + + +struct ImplRulerUnitData +{ + MapUnit eMapUnit; // MAP_UNIT zum Umrechnen + long nTickUnit; // Teiler fuer Einheit + long nTick1; // Schrittweite + long nTick2; // Tick fuer halbe Werte + long nTick3; // Tick fuer Zahlenausgabe + long n100THMM; // Teiler fuer Einheit + USHORT nUnitDigits; // Anzahl Nachkommastellen + sal_Char aUnitStr[8]; // Einheiten-String +}; + +static ImplRulerUnitData aImplRulerUnitTab[RULER_UNIT_COUNT] = +{ +{ MAP_100TH_MM, 100, 25, 50, 100, 100, 3, " mm" }, // MM +{ MAP_100TH_MM, 1000, 250, 500, 1000, 1000, 3, " cm" }, // CM +{ MAP_MM, 1000, 250, 500, 1000, 10000, 4, " m" }, // M +{ MAP_CM, 100000, 25000, 50000, 100000, 100000, 6, " km" }, // KM +{ MAP_100TH_INCH, 100, 10, 50, 100, 2540, 3, "\"" }, // INCH +{ MAP_100TH_INCH, 1200, 120, 600, 1200, 30480, 3, "'" }, // FOOT +{ MAP_10TH_INCH, 633600, 63360, 316800, 633600, 1609344, 4, " miles" }, // MILE +{ MAP_POINT, 1, 12, 12, 36, 353, 2, " pt" }, // POINT +{ MAP_100TH_MM, 423, 423, 423, 846, 423, 3, " pi" } // PICA +}; + +// ======================================================================= + +struct ImplRulerHitTest +{ + long nPos; + RulerType eType; + USHORT nAryPos; + USHORT mnDragSize; + BOOL bSize; + BOOL bSizeBar; + BOOL bExpandTest; + ImplRulerHitTest() : + bExpandTest( FALSE ) {} +}; + +// ======================================================================= + +ImplRulerData::ImplRulerData() +{ + memset( this, 0, sizeof( ImplRulerData ) ); + + // PageBreite == EditWinBreite + bAutoPageWidth = TRUE; +} + +// ----------------------------------------------------------------------- + +ImplRulerData::~ImplRulerData() +{ + delete[] pLines; + delete[] pArrows; + delete[] pBorders; + delete[] pIndents; + delete[] pTabs; +} + +// ----------------------------------------------------------------------- + +ImplRulerData& ImplRulerData::operator=( const ImplRulerData& rData ) +{ + delete[] pLines; + delete[] pArrows; + delete[] pBorders; + delete[] pIndents; + delete[] pTabs; + + memcpy( this, &rData, sizeof( ImplRulerData ) ); + + if ( rData.pLines ) + { + pLines = new RulerLine[nLines]; + memcpy( pLines, rData.pLines, nLines*sizeof( RulerLine ) ); + } + + if ( rData.pArrows ) + { + pArrows = new RulerArrow[nArrows]; + memcpy( pArrows, rData.pArrows, nArrows*sizeof( RulerArrow ) ); + } + + if ( rData.pBorders ) + { + pBorders = new RulerBorder[nBorders]; + memcpy( pBorders, rData.pBorders, nBorders*sizeof( RulerBorder ) ); + } + + if ( rData.pIndents ) + { + pIndents = new RulerIndent[nIndents]; + memcpy( pIndents, rData.pIndents, nIndents*sizeof( RulerIndent ) ); + } + + if ( rData.pTabs ) + { + pTabs = new RulerTab[nTabs]; + memcpy( pTabs, rData.pTabs, nTabs*sizeof( RulerTab ) ); + } + + return *this; +} + +// ======================================================================= + +void Ruler::ImplInit( WinBits nWinBits ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + // Default WinBits setzen + if ( !(nWinBits & WB_VERT) ) + { + nWinBits |= WB_HORZ; + + // --- RTL --- no UI mirroring for horizontal rulers, because + // the document is also not mirrored + EnableRTL( FALSE ); + } + + // Variablen initialisieren + mnWinStyle = nWinBits; // Window-Style + mnBorderOff = 0; // Border-Offset + mnWinOff = 0; // EditWinOffset + mnWinWidth = 0; // EditWinWidth + mnWidth = 0; // Fensterbreite + mnHeight = 0; // Fensterhoehe + mnVirOff = 0; // Offset des VirtualDeice vom linke/oberen Rand + mnVirWidth = 0; // Breite bzw. Hoehe vom VirtualDevice + mnVirHeight = 0; // Hoehe bzw. Breite vom VirtualDevice + mnDragPos = 0; // Drag-Position (NullPunkt) + mnUpdateEvtId = 0; // Noch kein Update-Event verschickt + mnDragAryPos = 0; // Drag-Array-Index + mnDragSize = 0; // Wird beim Draggen die Groesse geaendert + mnDragScroll = 0; // Soll beim Draggen gescrollt werden + mnDragModifier = 0; // Modifier-Tasten beim Draggen + mnExtraStyle = 0; // Style des Extra-Feldes + mnExtraClicks = 0; // Click-Anzahl fuer Extra-Feld + mnExtraModifier = 0; // Modifier-Tasten beim Click im Extrafeld + mbCalc = TRUE; // Muessen Pagebreiten neu berechnet werden + mbFormat = TRUE; // Muss neu ausgegeben werden + mbDrag = FALSE; // Sind wir im Drag-Modus + mbDragDelete = FALSE; // Wird Maus beim Draggen unten rausgezogen + mbDragCanceled = FALSE; // Wurde Dragging abgebrochen + mbAutoWinWidth = TRUE; // EditWinBreite == RulerBreite + mbActive = TRUE; // Ist Lineal aktiv + mnUpdateFlags = 0; // Was soll im Update-Handler upgedatet werden + mpData = mpSaveData; // Wir zeigen auf die normalen Daten + meExtraType = RULER_EXTRA_DONTKNOW; // Was im ExtraFeld dargestellt wird + meDragType = RULER_TYPE_DONTKNOW; // Gibt an, was gedragt wird + + // Units initialisieren + mnUnitIndex = RULER_UNIT_CM; + meUnit = FUNIT_CM; + maZoom = Fraction( 1, 1 ); + meSourceUnit = MAP_100TH_MM; + + // Border-Breiten berechnen + if ( nWinBits & WB_BORDER ) + { + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + mnBorderWidth = 2; + else + mnBorderWidth = 1; + } + else + mnBorderWidth = 0; + + // Einstellungen setzen + ImplInitSettings( TRUE, TRUE, TRUE ); + + // Default-Groesse setzen + long nDefHeight = GetTextHeight() + RULER_OFF*2 + RULER_TEXTOFF*2 + mnBorderWidth; + Size aDefSize; + if ( nWinBits & WB_HORZ ) + aDefSize.Height() = nDefHeight; + else + aDefSize.Width() = nDefHeight; + SetOutputSizePixel( aDefSize ); +} + +// ----------------------------------------------------------------------- + +Ruler::Ruler( Window* pParent, WinBits nWinStyle ) : + Window( pParent, nWinStyle & WB_3DLOOK ), + maVirDev( *this ), + maMapMode( MAP_100TH_MM ), + mpSaveData(new ImplRulerData), + mpData(0), + mpDragData(new ImplRulerData) +{ + ImplInit( nWinStyle ); +} + +// ----------------------------------------------------------------------- + +Ruler::~Ruler() +{ + if ( mnUpdateEvtId ) + Application::RemoveUserEvent( mnUpdateEvtId ); + delete mpSaveData; + delete mpDragData; +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplVDrawLine( long nX1, long nY1, long nX2, long nY2 ) +{ + if ( nX1 < -RULER_CLIP ) + { + nX1 = -RULER_CLIP; + if ( nX2 < -RULER_CLIP ) + return; + } + long nClip = mnVirWidth+RULER_CLIP; + if ( nX2 > nClip ) + { + nX2 = nClip; + if ( nX1 > nClip ) + return; + } + + if ( mnWinStyle & WB_HORZ ) + maVirDev.DrawLine( Point( nX1, nY1 ), Point( nX2, nY2 ) ); + else + maVirDev.DrawLine( Point( nY1, nX1 ), Point( nY2, nX2 ) ); +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplVDrawRect( long nX1, long nY1, long nX2, long nY2 ) +{ + if ( nX1 < -RULER_CLIP ) + { + nX1 = -RULER_CLIP; + if ( nX2 < -RULER_CLIP ) + return; + } + long nClip = mnVirWidth+RULER_CLIP; + if ( nX2 > nClip ) + { + nX2 = nClip; + if ( nX1 > nClip ) + return; + } + + if ( mnWinStyle & WB_HORZ ) + maVirDev.DrawRect( Rectangle( nX1, nY1, nX2, nY2 ) ); + else + maVirDev.DrawRect( Rectangle( nY1, nX1, nY2, nX2 ) ); +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplVDrawText( long nX, long nY, const String& rText ) +{ + if ( (nX > -RULER_CLIP) && (nX < mnVirWidth+RULER_CLIP) ) + { + if ( mnWinStyle & WB_HORZ ) + maVirDev.DrawText( Point( nX, nY ), rText ); + else + maVirDev.DrawText( Point( nY, nX ), rText ); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplInvertLines( BOOL bErase ) +{ + // Positionslinien + if ( mpData->nLines && mbActive && !mbDrag && !mbFormat && + !(mnUpdateFlags & RULER_UPDATE_LINES) ) + { + long n; + long nNullWinOff = mpData->nNullVirOff+mnVirOff; + long nRulX1 = mpData->nRulVirOff+mnVirOff; + long nRulX2 = nRulX1+mpData->nRulWidth; + long nY = (RULER_OFF*2)+mnVirHeight-1; + + // Rectangle berechnen + Rectangle aRect; + if ( mnWinStyle & WB_HORZ ) + aRect.Bottom() = nY; + else + aRect.Right() = nY; + + // Linien ausgeben + for ( USHORT i = 0; i < mpData->nLines; i++ ) + { + n = mpData->pLines[i].nPos+nNullWinOff; + if ( (n >= nRulX1) && (n < nRulX2) ) + { + if ( mnWinStyle & WB_HORZ ) + { + aRect.Left() = n; + aRect.Right() = n; + } + else + { + aRect.Top() = n; + aRect.Bottom() = n; + } + if ( bErase ) + { + Rectangle aTempRect = aRect; + if ( mnWinStyle & WB_HORZ ) + aTempRect.Bottom() = RULER_OFF-1; + else + aTempRect.Right() = RULER_OFF-1; + Erase( aTempRect ); + if ( mnWinStyle & WB_HORZ ) + { + aTempRect.Bottom() = aRect.Bottom(); + aTempRect.Top() = aTempRect.Bottom()-RULER_OFF+1; + } + else + { + aTempRect.Right() = aRect.Right(); + aTempRect.Left() = aTempRect.Right()-RULER_OFF+1; + } + Erase( aTempRect ); + } + Invert( aRect ); + } + } + } +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplDrawTicks( long nMin, long nMax, long nStart, long nCenter ) +{ + long n = 0; + long nTick = 0; + long nTick3 = aImplRulerUnitTab[mnUnitIndex].nTick3; + long nTickCount = aImplRulerUnitTab[mnUnitIndex].nTick1; + Size aPixSize = maVirDev.LogicToPixel( Size( nTick3, nTick3 ), maMapMode ); + long nTickWidth; + long nX; + long nY; + BOOL bNoTicks = FALSE; + + // Groessenvorberechnung + // Sizes calculation + BOOL bVertRight = FALSE; + if ( mnWinStyle & WB_HORZ ) + nTickWidth = aPixSize.Width(); + else + { + Font aFont = GetFont(); + if ( mnWinStyle & WB_RIGHT_ALIGNED ) + { + aFont.SetOrientation( 2700 ); + bVertRight = TRUE; + } + else + aFont.SetOrientation( 900 ); + maVirDev.SetFont( aFont ); + nTickWidth = aPixSize.Height(); + } + long nMaxWidth = maVirDev.PixelToLogic( Size( mpData->nPageWidth, 0 ), maMapMode ).Width(); + if ( nMaxWidth < 0 ) + nMaxWidth = -nMaxWidth; + nMaxWidth /= aImplRulerUnitTab[mnUnitIndex].nTickUnit; + UniString aNumStr( UniString::CreateFromInt32( nMaxWidth ) ); + long nTxtWidth = GetTextWidth( aNumStr ); + + const long nTextOff = 4; + if ( nTickWidth < nTxtWidth+nTextOff ) + { + // Calculate the scale of the ruler + long nMulti = 1; + long nOrgTick3 = nTick3; + while ( nTickWidth < nTxtWidth+nTextOff ) + { + long nOldMulti = nMulti; + if ( !nTickWidth ) //If nTickWidth equals 0 + nMulti *= 10; + else if ( nMulti < 10 ) + nMulti++; + else if ( nMulti < 100 ) + nMulti += 10; + else if ( nMulti < 1000 ) + nMulti += 100; + else + nMulti += 1000; + // Ueberlauf, dann geben wir nichts aus, da wir bei so einem + // unsinnigen Massstab sowieso nichts vernuenftiges anzeigen + // koennen + if ( nMulti < nOldMulti ) + { + bNoTicks = TRUE; + break; + } + + nTick3 = nOrgTick3 * nMulti; + aPixSize = maVirDev.LogicToPixel( Size( nTick3, nTick3 ), maMapMode ); + if ( mnWinStyle & WB_HORZ ) + nTickWidth = aPixSize.Width(); + else + nTickWidth = aPixSize.Height(); + } + nTickCount = nTick3; + } + else + maVirDev.SetLineColor( GetSettings().GetStyleSettings().GetWindowTextColor() ); + + if ( !bNoTicks ) + { + long nTxtWidth2; + long nTxtHeight2 = GetTextHeight()/2; + while ( ((nStart-n) >= nMin) || ((nStart+n) <= nMax) ) + { + // Null-Punkt + if ( !nTick ) + { + if ( nStart > nMin ) + { + // 0 is only painted when Margin1 is not equal to zero + if ( (mpData->nMargin1Style & RULER_STYLE_INVISIBLE) || (mpData->nMargin1 != 0) ) + { + aNumStr = (sal_Unicode)'0'; + nTxtWidth2 = maVirDev.GetTextWidth( aNumStr )/2; + if ( (mnWinStyle & WB_HORZ)^mpData->bTextRTL ) + nX = nStart-nTxtWidth2; + else + nX = nStart+nTxtWidth2; + long n_Y = bVertRight ? nCenter+nTxtHeight2 : nCenter-nTxtHeight2; + ImplVDrawText( nX, n_Y, aNumStr ); + } + } + } + else + { + aPixSize = maVirDev.LogicToPixel( Size( nTick, nTick ), maMapMode ); + + if ( mnWinStyle & WB_HORZ ) + n = aPixSize.Width(); + else + n = aPixSize.Height(); + + // Tick3 - Output (Text) + if ( !(nTick % nTick3) ) + { + aNumStr = UniString::CreateFromInt32( nTick / aImplRulerUnitTab[mnUnitIndex].nTickUnit ); + nTxtWidth2 = GetTextWidth( aNumStr )/2; + + nX = nStart+n; + //different orientation needs a different starting position + nY = bVertRight ? nCenter+nTxtHeight2 : nCenter-nTxtHeight2; + + // Check if we can display full number + if ( nX < (nMax-nTxtWidth2) ) + { + if ( mnWinStyle & WB_HORZ ) + nX -= nTxtWidth2; + else + nX += nTxtWidth2; + ImplVDrawText( nX, nY, aNumStr ); + } + nX = nStart-n; + if ( nX > (nMin+nTxtWidth2) ) + { + if ( mnWinStyle & WB_HORZ ) + nX -= nTxtWidth2; + else + nX += nTxtWidth2; + ImplVDrawText( nX, nY, aNumStr ); + } + } + // Tick/Tick2 - Output (Strokes) + else + { + if ( !(nTick % aImplRulerUnitTab[mnUnitIndex].nTick2) ) + nTickWidth = RULER_TICK2_WIDTH; + else + nTickWidth = RULER_TICK1_WIDTH; + long nT1 = nCenter-(nTickWidth/2); + long nT2 = nT1+nTickWidth-1; + long nT; + + nT = nStart+n; + if ( nT < nMax ) + ImplVDrawLine( nT, nT1, nT, nT2 ); + nT = nStart-n; + if ( nT > nMin ) + ImplVDrawLine( nT, nT1, nT, nT2 ); + } + } + // #i49017# with some zoom factors the value nTick can overflow + if( ((ULONG)nTick + (ULONG)nTickCount) > (ULONG)LONG_MAX) + break; + nTick += nTickCount; + } + } +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplDrawArrows( long nCenter ) +{ + USHORT i; + long n1; + long n2; + long n3; + long n4; + long nLogWidth; + String aStr; + String aStr2; + BOOL bDrawUnit; + long nTxtWidth; + long nTxtHeight2 = GetTextHeight()/2; + + const vcl::I18nHelper& rI18nHelper = GetSettings().GetLocaleI18nHelper(); + + maVirDev.SetLineColor( GetSettings().GetStyleSettings().GetWindowTextColor() ); + for ( i = 0; i < mpData->nArrows; i++ ) + { + n1 = mpData->pArrows[i].nPos+mpData->nNullVirOff+1; + n2 = n1+mpData->pArrows[i].nWidth-2; + + // Einheit umrechnen + nLogWidth = mpData->pArrows[i].nLogWidth; + if ( meSourceUnit == MAP_TWIP ) + { + if ( nLogWidth >= 100000 ) + nLogWidth = (nLogWidth*254)/144; + else + nLogWidth = (nLogWidth*2540)/1440; + } + if ( nLogWidth >= 1000000 ) + nLogWidth = (nLogWidth / aImplRulerUnitTab[mnUnitIndex].n100THMM) * 1000; + else + nLogWidth = (nLogWidth*1000) / aImplRulerUnitTab[mnUnitIndex].n100THMM; + aStr = rI18nHelper.GetNum( nLogWidth, aImplRulerUnitTab[mnUnitIndex].nUnitDigits, TRUE, FALSE ); + + // Einheit an den String haengen + aStr2 = aStr; + aStr2.AppendAscii( aImplRulerUnitTab[mnUnitIndex].aUnitStr ); + + // Textbreite ermitteln + bDrawUnit = TRUE; + nTxtWidth = GetTextWidth( aStr2 ); + if ( nTxtWidth < mpData->pArrows[i].nWidth-10 ) + aStr = aStr2; + else + { + nTxtWidth = GetTextWidth( aStr ); + if ( nTxtWidth > mpData->pArrows[i].nWidth-10 ) + bDrawUnit = FALSE; + } + + // Ist genuegen Platz fuer Einheiten-String vorhanden + if ( bDrawUnit ) + { + n3 = n1 + ((n2-n1)/2) - 1; + if ( mnWinStyle & WB_HORZ ) + n3 -= nTxtWidth/2; + else + n3 += nTxtWidth/2; + if ( mnWinStyle & WB_HORZ ) + { + n4 = n3 + nTxtWidth + 2; + ImplVDrawLine( n1, nCenter, n3, nCenter ); + ImplVDrawLine( n4, nCenter, n2, nCenter ); + } + else + { + n4 = n3 - nTxtWidth - 2; + ImplVDrawLine( n1, nCenter, n4, nCenter ); + ImplVDrawLine( n3, nCenter, n2, nCenter ); + } + ImplVDrawText( n3, nCenter-nTxtHeight2, aStr ); + } + else + ImplVDrawLine( n1, nCenter, n2, nCenter ); + ImplVDrawLine( n1+1, nCenter-1, n1+1, nCenter+1 ); + ImplVDrawLine( n1+2, nCenter-2, n1+2, nCenter+2 ); + ImplVDrawLine( n2-1, nCenter-1, n2-1, nCenter+1 ); + ImplVDrawLine( n2-2, nCenter-2, n2-2, nCenter+2 ); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplDrawBorders( long nMin, long nMax, long nVirTop, long nVirBottom ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + long n; + long n1; + long n2; + long nTemp1; + long nTemp2; + USHORT i; + + for ( i = 0; i < mpData->nBorders; i++ ) + { + if ( mpData->pBorders[i].nStyle & RULER_STYLE_INVISIBLE ) + continue; + + n1 = mpData->pBorders[i].nPos+mpData->nNullVirOff; + n2 = n1+mpData->pBorders[i].nWidth; + + if ( ((n1 >= nMin) && (n1 <= nMax)) || ((n2 >= nMin) && (n2 <= nMax)) ) + { + if ( (n2-n1) > 3 ) + { + maVirDev.SetLineColor(); + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + maVirDev.SetFillColor( rStyleSettings.GetFaceColor() ); + else + maVirDev.SetFillColor( rStyleSettings.GetWindowColor() ); + ImplVDrawRect( n1, nVirTop, n2, nVirBottom ); + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + { + maVirDev.SetLineColor( rStyleSettings.GetLightColor() ); + ImplVDrawLine( n1+1, nVirTop, n1+1, nVirBottom ); + ImplVDrawLine( n1, nVirTop, n2, nVirTop ); + maVirDev.SetLineColor( rStyleSettings.GetShadowColor() ); + ImplVDrawLine( n1, nVirTop, n1, nVirBottom ); + ImplVDrawLine( n1, nVirBottom, n2, nVirBottom ); + ImplVDrawLine( n2-1, nVirTop, n2-1, nVirBottom ); + maVirDev.SetLineColor( rStyleSettings.GetWindowTextColor() ); + ImplVDrawLine( n2, nVirTop, n2, nVirBottom ); + } + else + { + maVirDev.SetLineColor( rStyleSettings.GetWindowTextColor() ); + ImplVDrawLine( n1, nVirTop, n1, nVirBottom ); + ImplVDrawLine( n2, nVirTop, n2, nVirBottom ); + } + + if ( mpData->pBorders[i].nStyle & RULER_BORDER_VARIABLE ) + { + if ( n2-n1 > RULER_VAR_SIZE+4 ) + { + nTemp1 = n1 + (((n2-n1+1)-RULER_VAR_SIZE) / 2); + nTemp2 = nVirTop + (((nVirBottom-nVirTop+1)-RULER_VAR_SIZE) / 2); + long nTemp3 = nTemp1+RULER_VAR_SIZE-1; + long nTemp4 = nTemp2+RULER_VAR_SIZE-1; + long nTempY = nTemp2; + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + maVirDev.SetLineColor( rStyleSettings.GetLightColor() ); + else + maVirDev.SetLineColor( rStyleSettings.GetWindowTextColor() ); + while ( nTempY <= nTemp4 ) + { + ImplVDrawLine( nTemp1, nTempY, nTemp3, nTempY ); + nTempY += 2; + } + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + { + nTempY = nTemp2+1; + maVirDev.SetLineColor( rStyleSettings.GetShadowColor() ); + while ( nTempY <= nTemp4 ) + { + ImplVDrawLine( nTemp1, nTempY, nTemp3, nTempY ); + nTempY += 2; + } + } + } + } + + if ( mpData->pBorders[i].nStyle & RULER_BORDER_SIZEABLE ) + { + if ( n2-n1 > RULER_VAR_SIZE+10 ) + { + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + { + maVirDev.SetLineColor( rStyleSettings.GetShadowColor() ); + ImplVDrawLine( n1+4, nVirTop+3, n1+4, nVirBottom-3 ); + ImplVDrawLine( n2-5, nVirTop+3, n2-5, nVirBottom-3 ); + maVirDev.SetLineColor( rStyleSettings.GetLightColor() ); + ImplVDrawLine( n1+5, nVirTop+3, n1+5, nVirBottom-3 ); + ImplVDrawLine( n2-4, nVirTop+3, n2-4, nVirBottom-3 ); + } + else + { + maVirDev.SetLineColor( rStyleSettings.GetWindowTextColor() ); + ImplVDrawLine( n1+4, nVirTop+3, n1+4, nVirBottom-3 ); + ImplVDrawLine( n2-4, nVirTop+3, n2-4, nVirBottom-3 ); + } + } + } + } + else + { + n = n1+((n2-n1)/2); + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + maVirDev.SetLineColor( rStyleSettings.GetShadowColor() ); + else + maVirDev.SetLineColor( rStyleSettings.GetWindowTextColor() ); + if ( mpData->pBorders[i].nStyle & RULER_BORDER_SNAP ) + ImplVDrawLine( n, nVirTop, n, nVirBottom ); + else if ( mpData->pBorders[i].nStyle & RULER_BORDER_MARGIN ) + ImplVDrawLine( n, nVirTop, n, nVirBottom ); + else + { + ImplVDrawLine( n-1, nVirTop, n-1, nVirBottom ); + ImplVDrawLine( n+1, nVirTop, n+1, nVirBottom ); + maVirDev.SetLineColor(); + maVirDev.SetFillColor( rStyleSettings.GetWindowColor() ); + ImplVDrawRect( n, nVirTop, n, nVirBottom ); + } + } + } + } +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplDrawIndent( const Polygon& rPoly, USHORT nStyle ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Point aPos1; + Point aPos2; + USHORT nIndentStyle = nStyle & RULER_INDENT_STYLE; + + if ( nStyle & RULER_STYLE_INVISIBLE ) + return; + + if ( nStyle & RULER_STYLE_DONTKNOW ) + { + maVirDev.SetLineColor( rStyleSettings.GetShadowColor() ); + maVirDev.SetFillColor( rStyleSettings.GetFaceColor() ); + } + else + { + maVirDev.SetLineColor( rStyleSettings.GetDarkShadowColor() ); + maVirDev.SetFillColor( rStyleSettings.GetFaceColor() ); + } + + maVirDev.DrawPolygon( rPoly ); + + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) && !(nStyle & RULER_STYLE_DONTKNOW) ) + { + if ( nIndentStyle == RULER_INDENT_BOTTOM ) + { + maVirDev.SetLineColor( rStyleSettings.GetLightColor() ); + aPos1 = rPoly.GetPoint( 2 ); + aPos1.X()++; + aPos2 = rPoly.GetPoint( 1 ); + aPos2.X()++; + maVirDev.DrawLine( aPos2, aPos1 ); + aPos2.X()--; + aPos2.Y()++; + aPos1 = rPoly.GetPoint( 0 ); + aPos1.Y()++; + maVirDev.DrawLine( aPos2, aPos1 ); + maVirDev.SetLineColor( rStyleSettings.GetShadowColor() ); + aPos2 = rPoly.GetPoint( 4 ); + aPos2.Y()++; + maVirDev.DrawLine( aPos1, aPos2 ); + aPos2.X()--; + aPos1 = rPoly.GetPoint( 3 ); + aPos1.X()--; + maVirDev.DrawLine( aPos2, aPos1 ); + aPos1.Y()--; + aPos2 = rPoly.GetPoint( 2 ); + aPos2.X()++; + aPos2.Y()--; + maVirDev.DrawLine( aPos2, aPos1 ); + } + else + { + maVirDev.SetLineColor( rStyleSettings.GetLightColor() ); + aPos1 = rPoly.GetPoint( 2 ); + aPos1.X()++; + aPos1.Y()++; + aPos2 = rPoly.GetPoint( 3 ); + aPos2.Y()++; + maVirDev.DrawLine( aPos1, aPos2 ); + aPos2 = rPoly.GetPoint( 1 ); + aPos2.X()++; + maVirDev.DrawLine( aPos1, aPos2 ); + aPos2.X()--; + aPos2.Y()--; + aPos1 = rPoly.GetPoint( 0 ); + aPos1.Y()--; + maVirDev.DrawLine( aPos2, aPos1 ); + maVirDev.SetLineColor( rStyleSettings.GetShadowColor() ); + aPos2 = rPoly.GetPoint( 4 ); + aPos2.Y()--; + maVirDev.DrawLine( aPos1, aPos2 ); + aPos2.X()--; + aPos1 = rPoly.GetPoint( 3 ); + aPos1.X()--; + maVirDev.DrawLine( aPos2, aPos1 ); + } + + maVirDev.SetLineColor( rStyleSettings.GetDarkShadowColor() ); + maVirDev.SetFillColor(); + maVirDev.DrawPolygon( rPoly ); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplDrawIndents( long nMin, long nMax, long nVirTop, long nVirBottom ) +{ + USHORT j; + long n; + long nIndentHeight = (mnVirHeight/2) - 1; + long nIndentWidth2 = nIndentHeight-3; + Polygon aPoly( 5 ); + + for ( j = 0; j < mpData->nIndents; j++ ) + { + if ( mpData->pIndents[j].nStyle & RULER_STYLE_INVISIBLE ) + continue; + + USHORT nStyle = mpData->pIndents[j].nStyle; + USHORT nIndentStyle = nStyle & RULER_INDENT_STYLE; + + n = mpData->pIndents[j].nPos+mpData->nNullVirOff; + + if ( (n >= nMin) && (n <= nMax) ) + { + if(nIndentStyle == RULER_INDENT_BORDER) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + maVirDev.SetLineColor( rStyleSettings.GetShadowColor() ); + ImplVDrawLine( n, nVirTop, n, nVirBottom ); + } + else if ( nIndentStyle == RULER_INDENT_BOTTOM ) + { + aPoly.SetPoint( Point( n+0, nVirBottom-nIndentHeight ), 0 ); + aPoly.SetPoint( Point( n-nIndentWidth2, nVirBottom-3 ), 1 ); + aPoly.SetPoint( Point( n-nIndentWidth2, nVirBottom ), 2 ); + aPoly.SetPoint( Point( n+nIndentWidth2, nVirBottom ), 3 ); + aPoly.SetPoint( Point( n+nIndentWidth2, nVirBottom-3 ), 4 ); + } + else + { + aPoly.SetPoint( Point( n+0, nVirTop+nIndentHeight ), 0 ); + aPoly.SetPoint( Point( n-nIndentWidth2, nVirTop+3 ), 1 ); + aPoly.SetPoint( Point( n-nIndentWidth2, nVirTop ), 2 ); + aPoly.SetPoint( Point( n+nIndentWidth2, nVirTop ), 3 ); + aPoly.SetPoint( Point( n+nIndentWidth2, nVirTop+3 ), 4 ); + } + + if(0 == (mnWinStyle & WB_HORZ)) + { + Point aTmp; + for(USHORT i = 0; i < 5; i++) + { + aTmp = aPoly[i]; + Point aSet(nVirBottom - aTmp.Y(), aTmp.X()); + aPoly[i] = aSet; + } + } + if(RULER_INDENT_BORDER != nIndentStyle) + ImplDrawIndent( aPoly, nStyle ); + } + } +} + +// ----------------------------------------------------------------------- + +static void ImplCenterTabPos( Point& rPos, USHORT nTabStyle ) +{ + BOOL bRTL = 0 != (nTabStyle & RULER_TAB_RTL); + nTabStyle &= RULER_TAB_STYLE; + rPos.Y() += RULER_TAB_HEIGHT/2; + if ( (!bRTL && nTabStyle == RULER_TAB_LEFT) ||( bRTL && nTabStyle == RULER_TAB_RIGHT)) + rPos.X() -= RULER_TAB_WIDTH/2; + else if ( (!bRTL && nTabStyle == RULER_TAB_RIGHT) ||( bRTL && nTabStyle == RULER_TAB_LEFT)) + rPos.X() += RULER_TAB_WIDTH/2; +} + +// ----------------------------------------------------------------------- +void lcl_RotateRect_Impl(Rectangle& rRect, const long nReference, BOOL bRightAligned) +{ + if(!rRect.IsEmpty()) + { + Rectangle aTmp(rRect); + rRect.Top() = aTmp.Left(); + rRect.Bottom() = aTmp.Right(); + rRect.Left() = aTmp.Top(); + rRect.Right() = aTmp.Bottom(); + if(bRightAligned) + { + long nRef = 2 * nReference; + rRect.Left() = nRef - rRect.Left(); + rRect.Right() = nRef - rRect.Right(); + } + } +} +// ----------------------------------------------------------------------- + +static void ImplDrawRulerTab( OutputDevice* pDevice, + const Point& rPos, USHORT nStyle, WinBits nWinBits ) +{ + if ( nStyle & RULER_STYLE_INVISIBLE ) + return; + + USHORT nTabStyle = nStyle & RULER_TAB_STYLE; + BOOL bRTL = 0 != (nStyle & RULER_TAB_RTL); + Rectangle aRect1, aRect2, aRect3; + aRect3.SetEmpty(); + if ( nTabStyle == RULER_TAB_DEFAULT ) + { + aRect1.Left() = rPos.X() - RULER_TAB_DWIDTH2 + 1 ; + aRect1.Top() = rPos.Y() - RULER_TAB_DHEIGHT2 + 1 ; + aRect1.Right() = rPos.X() - RULER_TAB_DWIDTH2 + RULER_TAB_DWIDTH ; + aRect1.Bottom() = rPos.Y(); + aRect2.Left() = rPos.X() - RULER_TAB_DWIDTH2 + RULER_TAB_DWIDTH3; + aRect2.Top() = rPos.Y() - RULER_TAB_DHEIGHT + 1; + aRect2.Right() = rPos.X() - RULER_TAB_DWIDTH2 + RULER_TAB_DWIDTH3 + RULER_TAB_DWIDTH4 - 1; + aRect2.Bottom() = rPos.Y(); + + } + else if ( (!bRTL && nTabStyle == RULER_TAB_LEFT) ||( bRTL && nTabStyle == RULER_TAB_RIGHT)) + { + aRect1.Left() = rPos.X(); + aRect1.Top() = rPos.Y() - RULER_TAB_HEIGHT2 + 1; + aRect1.Right() = rPos.X() + RULER_TAB_WIDTH - 1; + aRect1.Bottom() = rPos.Y(); + aRect2.Left() = rPos.X(); + aRect2.Top() = rPos.Y() - RULER_TAB_HEIGHT + 1; + aRect2.Right() = rPos.X() + RULER_TAB_WIDTH2 - 1; + aRect2.Bottom() = rPos.Y(); + } + else if ( (!bRTL && nTabStyle == RULER_TAB_RIGHT) ||( bRTL && nTabStyle == RULER_TAB_LEFT)) + { + aRect1.Left() = rPos.X() - RULER_TAB_WIDTH + 1; + aRect1.Top() = rPos.Y() - RULER_TAB_HEIGHT2 + 1; + aRect1.Right() = rPos.X(); + aRect1.Bottom() = rPos.Y(); + aRect2.Left() = rPos.X() - RULER_TAB_WIDTH2 + 1; + aRect2.Top() = rPos.Y() - RULER_TAB_HEIGHT + 1; + aRect2.Right() = rPos.X(); + aRect2.Bottom() = rPos.Y(); + } + else + { + aRect1.Left() = rPos.X() - RULER_TAB_CWIDTH2 + 1; + aRect1.Top() = rPos.Y() - RULER_TAB_HEIGHT2 + 1; + aRect1.Right() = rPos.X() - RULER_TAB_CWIDTH2 + RULER_TAB_CWIDTH; + aRect1.Bottom() = rPos.Y(); + aRect2.Left() = rPos.X() - RULER_TAB_CWIDTH2 + RULER_TAB_CWIDTH3; + aRect2.Top() = rPos.Y() - RULER_TAB_HEIGHT + 1; + aRect2.Right() = rPos.X() - RULER_TAB_CWIDTH2 + RULER_TAB_CWIDTH3 + RULER_TAB_CWIDTH4 - 1; + aRect2.Bottom() = rPos.Y(); + + if ( nTabStyle == RULER_TAB_DECIMAL ) + { + aRect3.Left() = rPos.X() - RULER_TAB_CWIDTH2 + RULER_TAB_CWIDTH - 1; + aRect3.Top() = rPos.Y() - RULER_TAB_HEIGHT + 1 + 1; + aRect3.Right() = rPos.X() - RULER_TAB_CWIDTH2 + RULER_TAB_CWIDTH; + aRect3.Bottom()= rPos.Y() - RULER_TAB_HEIGHT + 1 + 2 ; + } + } + if( 0 == (nWinBits&WB_HORZ) ) + { + BOOL bRightAligned = 0 != (nWinBits&WB_RIGHT_ALIGNED); + lcl_RotateRect_Impl(aRect1, rPos.Y(), bRightAligned); + lcl_RotateRect_Impl(aRect2, rPos.Y(), bRightAligned); + lcl_RotateRect_Impl(aRect3, rPos.Y(), bRightAligned); + } + pDevice->DrawRect( aRect1 ); + pDevice->DrawRect( aRect2 ); + if(!aRect2.IsEmpty()) + pDevice->DrawRect( aRect3 ); + +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplDrawTab( OutputDevice* pDevice, const Point& rPos, USHORT nStyle ) +{ + if ( nStyle & RULER_STYLE_INVISIBLE ) + return; + + pDevice->SetLineColor(); + if ( nStyle & RULER_STYLE_DONTKNOW ) + pDevice->SetFillColor( GetSettings().GetStyleSettings().GetFaceColor() ); + else + pDevice->SetFillColor( GetSettings().GetStyleSettings().GetWindowTextColor() ); + + if(mpData->bTextRTL) + nStyle |= RULER_TAB_RTL; + ImplDrawRulerTab( pDevice, rPos, nStyle, GetStyle()); +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplDrawTabs( long nMin, long nMax, long nVirTop, long nVirBottom ) +{ + for ( USHORT i = 0; i < mpData->nTabs; i++ ) + { + if ( mpData->pTabs[i].nStyle & RULER_STYLE_INVISIBLE ) + continue; + + long n; + n = mpData->pTabs[i].nPos; + n += +mpData->nNullVirOff; + long nTopBottom = GetStyle() & WB_RIGHT_ALIGNED ? nVirTop : nVirBottom; + if ( (n >= nMin) && (n <= nMax) ) + ImplDrawTab( &maVirDev, Point( n, nTopBottom ), mpData->pTabs[i].nStyle ); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplInitSettings( BOOL bFont, + BOOL bForeground, BOOL bBackground ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + if ( bFont ) + { + Font aFont; + aFont = rStyleSettings.GetToolFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetZoomedPointFont( aFont ); + } + + if ( bForeground || bFont ) + { + Color aColor; + if ( IsControlForeground() ) + aColor = GetControlForeground(); + else + aColor = rStyleSettings.GetWindowTextColor(); + SetTextColor( aColor ); + SetTextFillColor(); + } + + if ( bBackground ) + { + Color aColor; + if ( IsControlBackground() ) + aColor = GetControlBackground(); + else + aColor = rStyleSettings.GetFaceColor(); + SetBackground( aColor ); + } + + maVirDev.SetSettings( GetSettings() ); + maVirDev.SetBackground( GetBackground() ); + Font aFont = GetFont(); + if ( mnWinStyle & WB_VERT ) + aFont.SetOrientation( 900 ); + maVirDev.SetFont( aFont ); + maVirDev.SetTextColor( GetTextColor() ); + maVirDev.SetTextFillColor( GetTextFillColor() ); +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplCalc() +{ + // Offset berechnen + mpData->nRulVirOff = mnWinOff + mpData->nPageOff; + if ( mpData->nRulVirOff > mnVirOff ) + mpData->nRulVirOff -= mnVirOff; + else + mpData->nRulVirOff = 0; + long nRulWinOff = mpData->nRulVirOff+mnVirOff; + + // Nicht sichtbaren Bereich der Page berechnen + long nNotVisPageWidth; + if ( mpData->nPageOff < 0 ) + { + nNotVisPageWidth = -(mpData->nPageOff); + if ( nRulWinOff < mnWinOff ) + nNotVisPageWidth -= mnWinOff-nRulWinOff; + } + else + nNotVisPageWidth = 0; + + // Breite berechnen + if ( mnWinStyle & WB_HORZ ) + { + if ( mbAutoWinWidth ) + mnWinWidth = mnWidth - mnVirOff; + if ( mpData->bAutoPageWidth ) + mpData->nPageWidth = mnWinWidth; + mpData->nRulWidth = Min( mnWinWidth, mpData->nPageWidth-nNotVisPageWidth ); + if ( nRulWinOff+mpData->nRulWidth > mnWidth ) + mpData->nRulWidth = mnWidth-nRulWinOff; + } + else + { + if ( mbAutoWinWidth ) + mnWinWidth = mnHeight - mnVirOff; + if ( mpData->bAutoPageWidth ) + mpData->nPageWidth = mnWinWidth; + mpData->nRulWidth = Min( mnWinWidth, mpData->nPageWidth-nNotVisPageWidth ); + if ( nRulWinOff+mpData->nRulWidth > mnHeight ) + mpData->nRulWidth = mnHeight-nRulWinOff; + } + + mbCalc = FALSE; +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplFormat() +{ + // Wenn schon formatiert ist, brauchen wir es nicht nochmal + if ( !mbFormat ) + return; + + // Wenn Fenster noch keine Groesse hat, brauchen wir noch nichts machen + if ( !mnVirWidth ) + return; + + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + long nP1; // Pixel-Position von Page1 + long nP2; // Pixel-Position von Page2 + long nM1; // Pixel-Position von Margin1 + long nM2; // Pixel-Position von Margin2 + long nVirTop; // Obere/Linke-Kante bei Ausgabe + long nVirBottom; // Untere/Rechte-Kante bei Ausgabe + long nVirLeft; // Linke/Obere-Kante bei Ausgabe + long nVirRight; // Rechte/Untere-Kante bei Ausgabe + long nNullVirOff; // Fuer schnellere Berechnung + + // Werte berechnen + if ( mbCalc ) + ImplCalc(); + mpData->nNullVirOff = mnWinOff+mpData->nPageOff+mpData->nNullOff-mnVirOff; + nNullVirOff = mpData->nNullVirOff; + nVirLeft = mpData->nRulVirOff; + nVirRight = nVirLeft+mpData->nRulWidth-1; + nVirTop = 0; + nVirBottom = mnVirHeight-1; + + if ( !IsReallyVisible() ) + return; + + Size aVirDevSize; + BOOL b3DLook = !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO); + + // VirtualDevice initialize + if ( mnWinStyle & WB_HORZ ) + { + aVirDevSize.Width() = mnVirWidth; + aVirDevSize.Height() = mnVirHeight; + } + else + { + aVirDevSize.Height() = mnVirWidth; + aVirDevSize.Width() = mnVirHeight; + } + if ( aVirDevSize != maVirDev.GetOutputSizePixel() ) + maVirDev.SetOutputSizePixel( aVirDevSize, TRUE ); + else + maVirDev.Erase(); + + // Raender berechnen + if ( !(mpData->nMargin1Style & RULER_STYLE_INVISIBLE) ) + { + nM1 = mpData->nMargin1+nNullVirOff; + if ( mpData->bAutoPageWidth ) + { + nP1 = nVirLeft; + if ( nM1 < nVirLeft ) + nP1--; + } + else + nP1 = nNullVirOff-mpData->nNullOff; + } + else + { + nM1 = nVirLeft-1; + nP1 = nM1; + } + if ( !(mpData->nMargin2Style & RULER_STYLE_INVISIBLE) ) + { + nM2 = mpData->nMargin2+nNullVirOff; + if ( mpData->bAutoPageWidth ) + { + nP2 = nVirRight; + if ( nM2 > nVirRight ) + nP2++; + } + else + nP2 = nNullVirOff-mpData->nNullOff+mpData->nPageWidth; + if ( nM2 > nP2 ) + nM2 = nP2; + } + else + { + nM2 = nVirRight+1; + nP2 = nM2; + } + + // Obere/untere Kante ausgeben + if ( b3DLook ) + maVirDev.SetLineColor( rStyleSettings.GetShadowColor() ); + else + maVirDev.SetLineColor( rStyleSettings.GetWindowTextColor() ); + ImplVDrawLine( nVirLeft, nVirTop, nM1 - 1, nVirTop ); //top left line + ImplVDrawLine( nM2 +1, nVirTop, nP2 -1, nVirTop ); //top right line + + // Jetzt wird zwischen dem Schatten ausgegeben + nVirTop++; + nVirBottom--; + + // Margin1, Margin2 und Zwischenraum ausgeben + maVirDev.SetLineColor(); + if ( b3DLook ) + maVirDev.SetFillColor( rStyleSettings.GetFaceColor() ); + else + maVirDev.SetFillColor( rStyleSettings.GetWindowColor() ); + if ( nM1 > nVirLeft ) + ImplVDrawRect( nP1, nVirTop, nM1-1, nVirBottom ); //left gray rectangle + if ( nM2 < nP2 ) + ImplVDrawRect( nM2+1, nVirTop, nP2, nVirBottom ); //right gray rectangle + if ( nM2-nM1 > 0 ) + { + maVirDev.SetFillColor( rStyleSettings.GetWindowColor() ); + ImplVDrawRect( nM1, nVirTop, nM2-1, nVirBottom ); //center rectangle + } + if ( b3DLook ) + { + maVirDev.SetLineColor( rStyleSettings.GetShadowColor() ); + if ( nM1 > nVirLeft ) + { + ImplVDrawLine( nM1-1, nVirTop, nM1-1, nVirBottom );//right line of the left rectangle + ImplVDrawLine( nP1, nVirBottom, nM1-1, nVirBottom );//bottom line of the left rectangle + if ( nP1 >= nVirLeft ) + { + ImplVDrawLine( nP1, nVirTop, nP1, nVirBottom );//left line of the left rectangle + ImplVDrawLine( nP1, nVirBottom, nP1+1, nVirBottom );//? + } + } + if ( nM2 < nP2 ) + { + ImplVDrawLine( nM2+1, nVirBottom, nP2-1, nVirBottom );//bottom line of the right rectangle + ImplVDrawLine( nM2+1, nVirTop, nM2+1, nVirBottom );//left line of the right rectangle + if ( nP2 <= nVirRight+1 ) + ImplVDrawLine( nP2-1, nVirTop, nP2-1, nVirBottom );//right line of the right rectangle + } + } + else + { + maVirDev.SetLineColor( rStyleSettings.GetWindowTextColor() ); + if ( nP1 >= nVirLeft ) + ImplVDrawLine( nP1, nVirTop, nP1, nVirBottom+1 ); + if ( nM1 > nP1 ) + ImplVDrawLine( nM1, nVirTop, nM1, nVirBottom ); + if ( nM2 < nP2 ) + ImplVDrawLine( nM2, nVirTop, nM2, nVirBottom ); + if ( nP2 <= nVirRight+1 ) + ImplVDrawLine( nP2, nVirTop, nP2, nVirBottom+1 ); + } + + // Lineal-Beschriftung (nur wenn keine Bemassungspfeile) + if ( !mpData->pArrows ) + { + long nMin = nVirLeft; + long nMax = nP2; + long nStart = mpData->bTextRTL ? mpData->nMargin2 + nNullVirOff : nNullVirOff; + long nCenter = nVirTop+((nVirBottom-nVirTop)/2); + + // Nicht Schatten uebermalen + if ( nP1 > nVirLeft ) + nMin++; + if ( nP2 < nVirRight ) + nMax--; + + // Draw captions + ImplDrawTicks( nMin, nMax, nStart, nCenter ); + } + + // Draw borders + if ( mpData->pBorders ) + ImplDrawBorders( nVirLeft, nP2, nVirTop, nVirBottom ); + + // Draw indents + if ( mpData->pIndents ) + ImplDrawIndents( nVirLeft, nP2, nVirTop-1, nVirBottom+1 ); + + // Tabs + if ( mpData->pTabs ) + { + ImplDrawTabs( nVirLeft, nP2, nVirTop-1, nVirBottom+1 ); + } + + // Bemassungspfeile + if ( mpData->pArrows ) + ImplDrawArrows( nVirTop+((nVirBottom-nVirTop)/2) ); + + // Wir haben formatiert + mbFormat = FALSE; +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplInitExtraField( BOOL bUpdate ) +{ + // Extra-Field beruecksichtigen + if ( mnWinStyle & WB_EXTRAFIELD ) + { + maExtraRect.Left() = RULER_OFF; + maExtraRect.Top() = RULER_OFF; + maExtraRect.Right() = RULER_OFF+mnVirHeight-1; + maExtraRect.Bottom() = RULER_OFF+mnVirHeight-1; + if(mpData->bTextRTL) + { + Size aWinSize = GetOutputSizePixel(); + if(mnWinStyle & WB_HORZ) + maExtraRect.Move(aWinSize.Width() - maExtraRect.GetWidth() - maExtraRect.Left(), 0); + else + maExtraRect.Move(0, aWinSize.Height() - maExtraRect.GetHeight() - maExtraRect.Top()); + mnVirOff = 0; + } + else + mnVirOff = maExtraRect.Right()+1; + + } + else + { + maExtraRect.SetEmpty(); + mnVirOff = 0; + } + + if ( bUpdate ) + { + mbCalc = TRUE; + mbFormat = TRUE; + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplDraw() +{ + if ( mbFormat ) + ImplFormat(); + + if ( IsReallyVisible() ) + { + // Lineal ueber das VirtualDevice ausgeben + Point aOffPos; + Size aVirDevSize = maVirDev.GetOutputSizePixel(); +// Size aVirDevSize2 = maVirDev.GetOutputSizePixel(); + if ( mnWinStyle & WB_HORZ ) + { + aOffPos.X() = mnVirOff; + if(mpData->bTextRTL) + aVirDevSize.Width() -= maExtraRect.GetWidth(); + +// else +// aVirDevSize.Width() -= mnVirOff; + aOffPos.Y() = RULER_OFF; + } + else + { + aOffPos.X() = RULER_OFF; + aOffPos.Y() = mnVirOff; +// else +// aVirDevSize.Height() -= mnVirOff; + } + DrawOutDev( aOffPos, aVirDevSize, Point(), aVirDevSize, maVirDev ); + + // Positionslinien neu malen + ImplInvertLines( TRUE ); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplDrawExtra( BOOL bPaint ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Rectangle aRect = maExtraRect; + BOOL bEraseRect = FALSE; + + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + { + aRect.Left() += 2; + aRect.Top() += 2; + aRect.Right() -= 2; + aRect.Bottom() -= 2; + } + else + { + aRect.Left() += 1; + aRect.Top() += 1; + aRect.Right() -= 1; + aRect.Bottom() -= 1; + } + + if ( !bPaint && !(mnExtraStyle & RULER_STYLE_HIGHLIGHT) ) + { + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + SetFillColor( rStyleSettings.GetFaceColor() ); + else + SetFillColor( rStyleSettings.GetWindowColor() ); + bEraseRect = TRUE; + } + else + { + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) && (mnExtraStyle & RULER_STYLE_HIGHLIGHT) ) + { + SetFillColor( rStyleSettings.GetCheckedColor() ); + bEraseRect = TRUE; + } + } + + if ( bEraseRect ) + { + SetLineColor(); + DrawRect( aRect ); + } + + // Inhalt ausgeben + if ( meExtraType == RULER_EXTRA_NULLOFFSET ) + { + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + SetLineColor( rStyleSettings.GetButtonTextColor() ); + else + SetLineColor( rStyleSettings.GetWindowTextColor() ); + DrawLine( Point( aRect.Left()+1, aRect.Top()+4 ), + Point( aRect.Right()-1, aRect.Top()+4 ) ); + DrawLine( Point( aRect.Left()+4, aRect.Top()+1 ), + Point( aRect.Left()+4, aRect.Bottom()-1 ) ); + } + else if ( meExtraType == RULER_EXTRA_TAB ) + { + USHORT nTabStyle = mnExtraStyle & RULER_TAB_STYLE; + if(mpData->bTextRTL) + nTabStyle |= RULER_TAB_RTL; + Point aCenter = aRect.Center(); + Point aDraw(aCenter); + ImplCenterTabPos( aDraw, nTabStyle ); + WinBits nWinBits = GetStyle(); + if(0 == (nWinBits&WB_HORZ) ) + { + if(0 != (nWinBits&WB_RIGHT_ALIGNED)) + aDraw.Y() = 2 * aCenter.Y() - aDraw.Y(); + if(mpData->bTextRTL) + { + long nTemp = aDraw.X(); + aDraw.X() = aDraw.Y(); + aDraw.Y() = nTemp; + } + } + ImplDrawTab( this, aDraw, nTabStyle ); + } + + if ( (rStyleSettings.GetOptions() & STYLE_OPTION_MONO) && (mnExtraStyle & RULER_STYLE_HIGHLIGHT) ) + Invert( aRect ); +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplUpdate( BOOL bMustCalc ) +{ + // Hier schon Linien loeschen, damit Sie vor dem Neuberechnen schon + // geloscht sind, da danach die alten Positionen nicht mehr bestimmt + // werden koennen + if ( !mbFormat ) + ImplInvertLines(); + + // Flags setzen + if ( bMustCalc ) + mbCalc = TRUE; + mbFormat = TRUE; + + // Wenn wir am Draggen sind, wird nach dem Drag-Handler automatisch + // das Lineal neu upgedatet + if ( mbDrag ) + return; + + // Gegebenenfalls Update ausloesen + if ( IsReallyVisible() && IsUpdateMode() ) + { + mnUpdateFlags |= RULER_UPDATE_DRAW; + if ( !mnUpdateEvtId ) + mnUpdateEvtId = Application::PostUserEvent( LINK( this, Ruler, ImplUpdateHdl ), NULL ); + } +} + +// ----------------------------------------------------------------------- + +BOOL Ruler::ImplHitTest( const Point& rPos, ImplRulerHitTest* pHitTest, + BOOL bRequireStyle, USHORT nRequiredStyle ) const +{ + USHORT i; + USHORT nStyle; + long nHitBottom; + long nX; + long nY; + long n1; + long n2; + + if ( !mbActive ) + return FALSE; + + // Position ermitteln + BOOL bIsHori = 0 != (mnWinStyle & WB_HORZ); + if ( bIsHori ) + { + nX = rPos.X(); + nY = rPos.Y(); + } + else + { + nX = rPos.Y(); + nY = rPos.X(); + } + nHitBottom = mnVirHeight+(RULER_OFF*2); + + // --> FME 2004-08-05 #i32608# + pHitTest->nAryPos = 0; + pHitTest->mnDragSize = 0; + pHitTest->bSize = FALSE; + pHitTest->bSizeBar = FALSE; + // <-- + + // Damit ueberstehende Tabs und Einzuege mit beruecksichtigt werden + long nXExtraOff; + if ( mpData->pTabs || mpData->pIndents ) + nXExtraOff = (mnVirHeight/2) - 4; + else + nXExtraOff = 0; + + // Test auf ausserhalb + nX -= mnVirOff; + long nXTemp = nX; + if ( (nX < mpData->nRulVirOff-nXExtraOff) || (nX > mpData->nRulVirOff+mpData->nRulWidth+nXExtraOff) || + (nY < 0) || (nY > nHitBottom) ) + { + pHitTest->nPos = 0; + pHitTest->eType = RULER_TYPE_OUTSIDE; + return FALSE; + } + + nX -= mpData->nNullVirOff; + pHitTest->nPos = nX; + pHitTest->eType = RULER_TYPE_DONTKNOW; + + // Zuerst die Tabs testen + Rectangle aRect; + if ( mpData->pTabs ) + { + aRect.Bottom() = nHitBottom; + aRect.Top() = aRect.Bottom()-RULER_TAB_HEIGHT-RULER_OFF; + + for ( i = mpData->nTabs; i; i-- ) + { + nStyle = mpData->pTabs[i-1].nStyle; + if ( !(nStyle & RULER_STYLE_INVISIBLE) ) + { + nStyle &= RULER_TAB_STYLE; + + // Default-Tabs werden nur angezeigt + if ( nStyle != RULER_TAB_DEFAULT ) + { + n1 = mpData->pTabs[i-1].nPos; + + if ( nStyle == RULER_TAB_LEFT ) + { + aRect.Left() = n1; + aRect.Right() = n1+RULER_TAB_WIDTH-1; + } + else if ( nStyle == RULER_TAB_RIGHT ) + { + aRect.Right() = n1; + aRect.Left() = n1-RULER_TAB_WIDTH-1; + } + else + { + aRect.Left() = n1-RULER_TAB_CWIDTH2+1; + aRect.Right() = n1-RULER_TAB_CWIDTH2+RULER_TAB_CWIDTH; + } + + if ( aRect.IsInside( Point( nX, nY ) ) ) + { + pHitTest->eType = RULER_TYPE_TAB; + pHitTest->nAryPos = i-1; + return TRUE; + } + } + } + } + } + + // Dann die Einzuege + if ( mpData->pIndents ) + { + long nIndentHeight = (mnVirHeight/2) - 1; + long nIndentWidth2 = nIndentHeight-3; + + for ( i = mpData->nIndents; i; i-- ) + { + nStyle = mpData->pIndents[i-1].nStyle; + if ( (! bRequireStyle || nStyle == nRequiredStyle) && + !(nStyle & RULER_STYLE_INVISIBLE) ) + { + nStyle &= RULER_INDENT_STYLE; + n1 = mpData->pIndents[i-1].nPos; + + if ( (nStyle == RULER_INDENT_BOTTOM) ^ (!bIsHori) ) + { + aRect.Left() = n1-nIndentWidth2; + aRect.Right() = n1+nIndentWidth2; + aRect.Top() = nHitBottom-nIndentHeight-RULER_OFF+1; + aRect.Bottom() = nHitBottom; + } + else + { + aRect.Left() = n1-nIndentWidth2; + aRect.Right() = n1+nIndentWidth2; + aRect.Top() = 0; + aRect.Bottom() = nIndentHeight+RULER_OFF-1; + } + + if ( aRect.IsInside( Point( nX, nY ) ) ) + { + pHitTest->eType = RULER_TYPE_INDENT; + pHitTest->nAryPos = i-1; + return TRUE; + } + } + } + } + + // Jetzt zaehlt nichts mehr, was links oder rechts uebersteht + if ( (nXTemp < mpData->nRulVirOff) || (nXTemp > mpData->nRulVirOff+mpData->nRulWidth) ) + { + pHitTest->nPos = 0; + pHitTest->eType = RULER_TYPE_OUTSIDE; + return FALSE; + } + + // Danach die Spalten testen + int nBorderTolerance = 1; + if(pHitTest->bExpandTest) + { + nBorderTolerance++; + } + + for ( i = mpData->nBorders; i; i-- ) + { + n1 = mpData->pBorders[i-1].nPos; + n2 = n1 + mpData->pBorders[i-1].nWidth; + + // Spalten werden mit mindestens 3 Pixel breite gezeichnet + if ( !mpData->pBorders[i-1].nWidth ) + { + n1 -= nBorderTolerance; + n2 += nBorderTolerance; + + } + + if ( (nX >= n1) && (nX <= n2) ) + { + nStyle = mpData->pBorders[i-1].nStyle; + if ( !(nStyle & RULER_STYLE_INVISIBLE) ) + { + pHitTest->eType = RULER_TYPE_BORDER; + pHitTest->nAryPos = i-1; + + if ( !(nStyle & RULER_BORDER_SIZEABLE) ) + { + if ( nStyle & RULER_BORDER_MOVEABLE ) + { + pHitTest->bSizeBar = TRUE; + pHitTest->mnDragSize = RULER_DRAGSIZE_MOVE; + } + } + else + { + long nMOff = RULER_MOUSE_BORDERWIDTH; + while ( nMOff*2 >= (n2-n1-RULER_MOUSE_BORDERMOVE) ) + { + if ( nMOff < 2 ) + { + nMOff = 0; + break; + } + else + nMOff--; + } + + if ( nX <= n1+nMOff ) + { + pHitTest->bSize = TRUE; + pHitTest->mnDragSize = RULER_DRAGSIZE_1; + } + else if ( nX >= n2-nMOff ) + { + pHitTest->bSize = TRUE; + pHitTest->mnDragSize = RULER_DRAGSIZE_2; + } + else + { + if ( nStyle & RULER_BORDER_MOVEABLE ) + { + pHitTest->bSizeBar = TRUE; + pHitTest->mnDragSize = RULER_DRAGSIZE_MOVE; + } + } + } + + return TRUE; + } + } + } + + // Und zum Schluss die Raender + int nMarginTolerance = pHitTest->bExpandTest ? nBorderTolerance : RULER_MOUSE_MARGINWIDTH; + + if ( (mpData->nMargin1Style & (RULER_MARGIN_SIZEABLE | RULER_STYLE_INVISIBLE)) == RULER_MARGIN_SIZEABLE ) + { + n1 = mpData->nMargin1; + if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) ) + { + pHitTest->eType = RULER_TYPE_MARGIN1; + pHitTest->bSize = TRUE; + return TRUE; + } + } + if ( (mpData->nMargin2Style & (RULER_MARGIN_SIZEABLE | RULER_STYLE_INVISIBLE)) == RULER_MARGIN_SIZEABLE ) + { + n1 = mpData->nMargin2; + if ( (nX >= n1 - nMarginTolerance) && (nX <= n1 + nMarginTolerance) ) + { + pHitTest->eType = RULER_TYPE_MARGIN2; + pHitTest->bSize = TRUE; + return TRUE; + } + } + + // Jetzt nocheinmal die Tabs testen, nur mit etwas mehr spielraum + if ( mpData->pTabs ) + { + aRect.Top() = RULER_OFF; + aRect.Bottom() = nHitBottom; + + for ( i = mpData->nTabs; i; i-- ) + { + nStyle = mpData->pTabs[i-1].nStyle; + if ( !(nStyle & RULER_STYLE_INVISIBLE) ) + { + nStyle &= RULER_TAB_STYLE; + + // Default-Tabs werden nur angezeigt + if ( nStyle != RULER_TAB_DEFAULT ) + { + n1 = mpData->pTabs[i-1].nPos; + + if ( nStyle == RULER_TAB_LEFT ) + { + aRect.Left() = n1; + aRect.Right() = n1+RULER_TAB_WIDTH-1; + } + else if ( nStyle == RULER_TAB_RIGHT ) + { + aRect.Right() = n1; + aRect.Left() = n1-RULER_TAB_WIDTH-1; + } + else + { + aRect.Left() = n1-RULER_TAB_CWIDTH2+1; + aRect.Right() = n1-RULER_TAB_CWIDTH2+RULER_TAB_CWIDTH; + } + + aRect.Left()--; + aRect.Right()++; + + if ( aRect.IsInside( Point( nX, nY ) ) ) + { + pHitTest->eType = RULER_TYPE_TAB; + pHitTest->nAryPos = i-1; + return TRUE; + } + } + } + } + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL Ruler::ImplDocHitTest( const Point& rPos, RulerType eDragType, + ImplRulerHitTest* pHitTest ) const +{ + Point aPos = rPos; + BOOL bRequiredStyle = FALSE; + USHORT nRequiredStyle = 0; + + if (eDragType == RULER_TYPE_INDENT) + { + bRequiredStyle = TRUE; + nRequiredStyle = RULER_INDENT_BOTTOM; + } + + if ( mnWinStyle & WB_HORZ ) + aPos.X() += mnWinOff; + else + aPos.Y() += mnWinOff; + + if ( (eDragType == RULER_TYPE_INDENT) || (eDragType == RULER_TYPE_DONTKNOW) ) + { + if ( mnWinStyle & WB_HORZ ) + aPos.Y() = RULER_OFF+1; + else + aPos.X() = RULER_OFF+1; + + // HitTest durchfuehren + if ( ImplHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle ) ) + { + if ( (pHitTest->eType == eDragType) || (eDragType == RULER_TYPE_DONTKNOW) ) + return TRUE; + } + } + + if ( (eDragType == RULER_TYPE_INDENT) || (eDragType == RULER_TYPE_TAB) || + (eDragType == RULER_TYPE_DONTKNOW) ) + { + if ( mnWinStyle & WB_HORZ ) + aPos.Y() = mnHeight-RULER_OFF-1; + else + aPos.X() = mnWidth-RULER_OFF-1; + + // HitTest durchfuehren + if ( ImplHitTest( aPos, pHitTest, bRequiredStyle, nRequiredStyle ) ) + { + if ( (pHitTest->eType == eDragType) || (eDragType == RULER_TYPE_DONTKNOW) ) + return TRUE; + } + } + + if ( (eDragType == RULER_TYPE_MARGIN1) || (eDragType == RULER_TYPE_MARGIN2) || + (eDragType == RULER_TYPE_BORDER) || (eDragType == RULER_TYPE_DONTKNOW) ) + { + if ( mnWinStyle & WB_HORZ ) + aPos.Y() = RULER_OFF + (mnVirHeight/2); + else + aPos.X() = RULER_OFF + (mnVirHeight/2); + + // HitTest durchfuehren + if ( ImplHitTest( aPos, pHitTest ) ) + { + if ( (pHitTest->eType == eDragType) || (eDragType == RULER_TYPE_DONTKNOW) ) + return TRUE; + } + } + + // Auf DontKnow setzen + pHitTest->eType = RULER_TYPE_DONTKNOW; + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL Ruler::ImplStartDrag( ImplRulerHitTest* pHitTest, USHORT nModifier ) +{ + // Wenn eine Spalte angeklick wurde, die weder verschiebar noch + // in der Groesse aenderbar ist, brauchen wir auch kein Drag ausloesen + if ( (pHitTest->eType == RULER_TYPE_BORDER) && + !pHitTest->bSize && !pHitTest->bSizeBar ) + return FALSE; + + // Dragdaten setzen + meDragType = pHitTest->eType; + mnDragPos = pHitTest->nPos; + mnDragAryPos = pHitTest->nAryPos; + mnDragSize = pHitTest->mnDragSize; + mnDragModifier = nModifier; + *mpDragData = *mpSaveData; + mpData = mpDragData; + + // Handler rufen + if ( StartDrag() ) + { + // Wenn der Handler das Draggen erlaubt, dann das Draggen + // initialisieren + ImplInvertLines(); + mbDrag = TRUE; + mnStartDragPos = mnDragPos; + StartTracking(); + return TRUE; + } + else + { + // Ansonsten muessen wir die Daten zuruecksetzen + meDragType = RULER_TYPE_DONTKNOW; + mnDragPos = 0; + mnDragAryPos = 0; + mnDragSize = 0; + mnDragModifier = 0; + mpData = mpSaveData; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplDrag( const Point& rPos ) +{ + long nX; + long nY; + long nOutHeight; + + if ( mnWinStyle & WB_HORZ ) + { + nX = rPos.X(); + nY = rPos.Y(); + nOutHeight = mnHeight; + } + else + { + nX = rPos.Y(); + nY = rPos.X(); + nOutHeight = mnWidth; + } + + // X berechnen und einpassen + nX -= mnVirOff; + if ( nX < mpData->nRulVirOff ) + { + nX = mpData->nRulVirOff; + mnDragScroll = RULER_SCROLL_1; + } + else if ( nX > mpData->nRulVirOff+mpData->nRulWidth ) + { + nX = mpData->nRulVirOff+mpData->nRulWidth; + mnDragScroll = RULER_SCROLL_2; + } + nX -= mpData->nNullVirOff; + + // Wenn oberhalb oder links vom Lineal, dann alte Werte + mbDragDelete = FALSE; + if ( nY < 0 ) + { + if ( !mbDragCanceled ) + { + // Daten wiederherstellen + mbDragCanceled = TRUE; + ImplRulerData aTempData; + aTempData = *mpDragData; + *mpDragData = *mpSaveData; + mbCalc = TRUE; + mbFormat = TRUE; + + // Handler rufen + mnDragPos = mnStartDragPos; + Drag(); + + // Und neu ausgeben (zeitverzoegert) +/* + mnUpdateFlags |= RULER_UPDATE_DRAW; + if ( mnUpdateEvtId ) + Application::RemoveUserEvent( mnUpdateEvtId ); + mnUpdateEvtId = Application::PostUserEvent( LINK( this, Ruler, ImplUpdateHdl ), NULL ); +*/ + ImplDraw(); + + // Daten wieder wie vor dem Cancel herstellen + *mpDragData = aTempData; + } + } + else + { + mbDragCanceled = FALSE; + + // +2, damit nicht so schnell die Tabs geloescht werden + if ( nY > nOutHeight+2 ) + mbDragDelete = TRUE; + + mnDragPos = nX; + + // Handler rufen + Drag(); + + // Und neu ausgeben + if ( mbFormat ) + ImplDraw(); + } + + mnDragScroll = 0; +} + +// ----------------------------------------------------------------------- + +void Ruler::ImplEndDrag() +{ + // Werte uebernehmen + if ( mbDragCanceled ) + *mpDragData = *mpSaveData; + else + *mpSaveData = *mpDragData; + mpData = mpSaveData; + mbDrag = FALSE; + + // Handler rufen + EndDrag(); + + // Drag-Werte zuruecksetzen + meDragType = RULER_TYPE_DONTKNOW; + mnDragPos = 0; + mnDragAryPos = 0; + mnDragSize = 0; + mbDragCanceled = FALSE; + mbDragDelete = FALSE; + mnDragModifier = 0; + mnDragScroll = 0; + mnStartDragPos = 0; + + // Und neu ausgeben + ImplDraw(); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( Ruler, ImplUpdateHdl, void*, EMPTYARG ) +{ + mnUpdateEvtId = 0; + + // Feststellen, was upgedatet werden muss + if ( mnUpdateFlags & RULER_UPDATE_DRAW ) + { + mnUpdateFlags = 0; + ImplDraw(); + } + else if ( mnUpdateFlags & RULER_UPDATE_LINES ) + { + mnUpdateFlags = 0; + ImplInvertLines(); + } + + return 0; +} + +// ----------------------------------------------------------------------- + +void Ruler::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( rMEvt.IsLeft() && !IsTracking() ) + { + Point aMousePos = rMEvt.GetPosPixel(); + USHORT nMouseClicks = rMEvt.GetClicks(); + USHORT nMouseModifier = rMEvt.GetModifier(); + + // Gegebenenfalls Lineal updaten (damit mit den richtigen Daten + // gearbeitet wird und die Anzeige auch zur Bearbeitung passt) + if ( mbFormat ) + { + ImplDraw(); + mnUpdateFlags &= ~RULER_UPDATE_DRAW; + } + + if ( maExtraRect.IsInside( aMousePos ) ) + { + mnExtraClicks = nMouseClicks; + mnExtraModifier = nMouseModifier; + ExtraDown(); + mnExtraClicks = 0; + mnExtraModifier = 0; + } + else + { + ImplRulerHitTest aHitTest; + + if ( nMouseClicks == 1 ) + { + if ( ImplHitTest( aMousePos, &aHitTest ) ) + ImplStartDrag( &aHitTest, nMouseModifier ); + else + { + // Position innerhalb des Lineal-Bereiches + if ( aHitTest.eType == RULER_TYPE_DONTKNOW ) + { + mnDragPos = aHitTest.nPos; + Click(); + mnDragPos = 0; + + // Nocheinmal HitTest durchfuehren, da durch den Click + // zum Beispiel ein neuer Tab gesetzt werden konnte + if ( ImplHitTest( aMousePos, &aHitTest ) ) + ImplStartDrag( &aHitTest, nMouseModifier ); + } + } + } + else + { + if ( ImplHitTest( aMousePos, &aHitTest ) ) + { + mnDragPos = aHitTest.nPos; + mnDragAryPos = aHitTest.nAryPos; + } + meDragType = aHitTest.eType; + + DoubleClick(); + + meDragType = RULER_TYPE_DONTKNOW; + mnDragPos = 0; + mnDragAryPos = 0; + } + } + } +} + +// ----------------------------------------------------------------------- + +void Ruler::MouseMove( const MouseEvent& rMEvt ) +{ + PointerStyle ePtrStyle = POINTER_ARROW; + + // Gegebenenfalls Lineal updaten (damit mit den richtigen Daten + // gearbeitet wird und die Anzeige auch zur Bearbeitung passt) + if ( mbFormat ) + { + ImplDraw(); + mnUpdateFlags &= ~RULER_UPDATE_DRAW; + } + + ImplRulerHitTest aHitTest; + if ( ImplHitTest( rMEvt.GetPosPixel(), &aHitTest ) ) + { + if ( aHitTest.bSize ) + { + if ( mnWinStyle & WB_HORZ ) + ePtrStyle = POINTER_ESIZE; + else + ePtrStyle = POINTER_SSIZE; + } + else if ( aHitTest.bSizeBar ) + { + if ( mnWinStyle & WB_HORZ ) + ePtrStyle = POINTER_HSIZEBAR; + else + ePtrStyle = POINTER_VSIZEBAR; + } + } + + SetPointer( Pointer( ePtrStyle ) ); +} + +// ----------------------------------------------------------------------- + +void Ruler::Tracking( const TrackingEvent& rTEvt ) +{ + if ( rTEvt.IsTrackingEnded() ) + { + // Bei Abbruch, den alten Status wieder herstellen + if ( rTEvt.IsTrackingCanceled() ) + { + mbDragCanceled = TRUE; + mbFormat = TRUE; + } + + ImplEndDrag(); + } + else + ImplDrag( rTEvt.GetMouseEvent().GetPosPixel() ); +} + +// ----------------------------------------------------------------------- + +void Ruler::Paint( const Rectangle& ) +{ + ImplDraw(); + + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + // Extra-Field beruecksichtigen + if ( mnWinStyle & WB_EXTRAFIELD ) + { + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + { + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( Point( maExtraRect.Left(), maExtraRect.Top() ), + Point( maExtraRect.Right()-1, maExtraRect.Top() ) ); + DrawLine( Point( maExtraRect.Left(), maExtraRect.Top() ), + Point( maExtraRect.Left(), maExtraRect.Bottom()-1 ) ); + DrawLine( Point( maExtraRect.Left(), maExtraRect.Bottom()-1 ), + Point( maExtraRect.Right()-1, maExtraRect.Bottom()-1 ) ); + DrawLine( Point( maExtraRect.Right()-1, maExtraRect.Top() ), + Point( maExtraRect.Right()-1, maExtraRect.Bottom()-1 ) ); + SetLineColor( rStyleSettings.GetLightColor() ); + DrawLine( Point( maExtraRect.Left()+1, maExtraRect.Top()+1 ), + Point( maExtraRect.Right()-2, maExtraRect.Top()+1 ) ); + DrawLine( Point( maExtraRect.Left()+1, maExtraRect.Top()+1 ), + Point( maExtraRect.Left()+1, maExtraRect.Bottom()-2 ) ); + DrawLine( Point( maExtraRect.Left(), maExtraRect.Bottom() ), + Point( maExtraRect.Right(), maExtraRect.Bottom() ) ); + DrawLine( Point( maExtraRect.Right(), maExtraRect.Top() ), + Point( maExtraRect.Right(), maExtraRect.Bottom() ) ); + } + else + { + SetLineColor( rStyleSettings.GetWindowTextColor() ); + SetFillColor( rStyleSettings.GetWindowColor() ); + DrawRect( maExtraRect ); + } + + // Imhalt vom Extrafeld ausgeben + ImplDrawExtra( TRUE ); + } + + if ( mnWinStyle & WB_BORDER ) + { + if ( mnWinStyle & WB_HORZ ) + { + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + { + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( Point( mnBorderOff, mnHeight-2 ), + Point( mnWidth, mnHeight-2 ) ); + if ( mnBorderOff ) + { + DrawLine( Point( mnBorderOff-1, mnHeight-2 ), + Point( mnBorderOff-1, mnHeight-1 ) ); + } + } + SetLineColor( rStyleSettings.GetWindowTextColor() ); + DrawLine( Point( mnBorderOff, mnHeight-1 ), + Point( mnWidth, mnHeight-1 ) ); + } + else + { + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + { + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( Point( mnWidth-2, mnBorderOff ), + Point( mnWidth-2, mnHeight ) ); + if ( mnBorderOff ) + { + DrawLine( Point( mnWidth-2, mnBorderOff-1 ), + Point( mnWidth-1, mnBorderOff-1 ) ); + } + } + SetLineColor( rStyleSettings.GetWindowTextColor() ); + DrawLine( Point( mnWidth-1, mnBorderOff ), + Point( mnWidth-1, mnHeight ) ); + } + } +} + +// ----------------------------------------------------------------------- + +void Ruler::Resize() +{ + Size aWinSize = GetOutputSizePixel(); + + long nNewHeight; + if ( mnWinStyle & WB_HORZ ) + { + if ( aWinSize.Height() != mnHeight ) + nNewHeight = aWinSize.Height(); + else + nNewHeight = 0; + } + else + { + if ( aWinSize.Width() != mnWidth ) + nNewHeight = aWinSize.Width(); + else + nNewHeight = 0; + } + + // Hier schon Linien loeschen + BOOL bVisible = IsReallyVisible(); + if ( bVisible && mpData->nLines ) + { + ImplInvertLines(); + mnUpdateFlags |= RULER_UPDATE_LINES; + if ( !mnUpdateEvtId ) + mnUpdateEvtId = Application::PostUserEvent( LINK( this, Ruler, ImplUpdateHdl ), NULL ); + } + mbFormat = TRUE; + + // Wenn sich die Hoehe bzw. Breite aendert, dann muessen besimmte Werte + // neu berechnet werden + //extra field should always be updated + ImplInitExtraField( mpData->bTextRTL ); + if ( nNewHeight ) + { + mbCalc = TRUE; + mnVirHeight = nNewHeight - mnBorderWidth - (RULER_OFF*2); + } + else + { + if ( mpData->bAutoPageWidth ) + ImplUpdate( TRUE ); + else if ( mbAutoWinWidth ) + mbCalc = TRUE; + } + + // Wenn Ruler eine Groesse hat, dann Groesse vom VirtualDevice setzen + if ( (mnVirWidth > RULER_MIN_SIZE) || + ((aWinSize.Width() > RULER_MIN_SIZE) && (aWinSize.Height() > RULER_MIN_SIZE)) ) + { + if ( mnWinStyle & WB_HORZ ) + mnVirWidth = aWinSize.Width()-mnVirOff; + else + mnVirWidth = aWinSize.Height()-mnVirOff; + if ( mnVirWidth < RULER_MIN_SIZE ) + mnVirWidth = 0; + } + + // Gegebenenfalls ein Teil vom Rand loeschen, da 3D-Effekt/Trennlinie am + // Fensterrand + if ( bVisible ) + { + if ( nNewHeight ) + Invalidate(); + else if ( mpData->bAutoPageWidth ) + { + // Nur bei AutoPageWidth haben wir rechts einen 3D-Effekt, + // der sich der Fensterbreite anpasst und deshalb neu gezeichnet + // werden muss + Rectangle aRect; + + if ( mnWinStyle & WB_HORZ ) + { + if ( mnWidth < aWinSize.Width() ) + aRect.Left() = mnWidth-RULER_RESIZE_OFF; + else + aRect.Left() = aWinSize.Width()-RULER_RESIZE_OFF; + aRect.Right() = aRect.Left()+RULER_RESIZE_OFF; + aRect.Top() = RULER_OFF; + aRect.Bottom() = RULER_OFF+mnVirHeight; + } + else + { + if ( mnHeight < aWinSize.Height() ) + aRect.Top() = mnHeight-RULER_RESIZE_OFF; + else + aRect.Top() = aWinSize.Height()-RULER_RESIZE_OFF; + aRect.Bottom() = aRect.Top()+RULER_RESIZE_OFF; + aRect.Left() = RULER_OFF; + aRect.Right() = RULER_OFF+mnVirHeight; + } + + Invalidate( aRect ); + } + } + + // Neue Groesse merken + mnWidth = aWinSize.Width(); + mnHeight = aWinSize.Height(); +} + +// ----------------------------------------------------------------------- + +void Ruler::StateChanged( StateChangedType nType ) +{ + Window::StateChanged( nType ); + + if ( nType == STATE_CHANGE_INITSHOW ) + ImplFormat(); + else if ( nType == STATE_CHANGE_UPDATEMODE ) + { + if ( IsReallyVisible() && IsUpdateMode() ) + ImplDraw(); + } + else if ( (nType == STATE_CHANGE_ZOOM) || + (nType == STATE_CHANGE_CONTROLFONT) ) + { + ImplInitSettings( TRUE, FALSE, FALSE ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLFOREGROUND ) + { + ImplInitSettings( FALSE, TRUE, FALSE ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings( FALSE, FALSE, TRUE ); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_DISPLAY) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + mbFormat = TRUE; + ImplInitSettings( TRUE, TRUE, TRUE ); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +long Ruler::StartDrag() +{ + if ( maStartDragHdl.IsSet() ) + return maStartDragHdl.Call( this ); + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void Ruler::Drag() +{ + maDragHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Ruler::EndDrag() +{ + maEndDragHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Ruler::Click() +{ + maClickHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Ruler::DoubleClick() +{ + maDoubleClickHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Ruler::ExtraDown() +{ + maExtraDownHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Ruler::Activate() +{ + mbActive = TRUE; + + // Positionslinien wieder anzeigen (erst hinter mbActive=TRUE rufen, da + // von ImplInvertLines() ausgewertet wird). Das Zeichnen der Linien + // wird verzoegert, damit im vermutlich noch nicht gepainteten Zustand + // Linien gezeichnet werden. + mnUpdateFlags |= RULER_UPDATE_LINES; + if ( !mnUpdateEvtId ) + mnUpdateEvtId = Application::PostUserEvent( LINK( this, Ruler, ImplUpdateHdl ), NULL ); +} + +// ----------------------------------------------------------------------- + +void Ruler::Deactivate() +{ + // Positionslinien loeschen (schon vor mbActive=FALSE rufen, da + // von ImplInvertLines() ausgewertet wird) + ImplInvertLines(); + + mbActive = FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL Ruler::StartDocDrag( const MouseEvent& rMEvt, RulerType eDragType ) +{ + if ( !mbDrag ) + { + Point aMousePos = rMEvt.GetPosPixel(); + USHORT nMouseClicks = rMEvt.GetClicks(); + USHORT nMouseModifier = rMEvt.GetModifier(); + ImplRulerHitTest aHitTest; + if(eDragType != RULER_TYPE_DONTKNOW) + aHitTest.bExpandTest = TRUE; + + // Gegebenenfalls Lineal updaten (damit mit den richtigen Daten + // gearbeitet wird und die Anzeige auch zur Bearbeitung passt) + if ( mbFormat ) + { + ImplDraw(); + mnUpdateFlags &= ~RULER_UPDATE_DRAW; + } + + if ( nMouseClicks == 1 ) + { + if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest ) ) + { + Pointer aPtr; + + if ( aHitTest.bSize ) + { + if ( mnWinStyle & WB_HORZ ) + aPtr = Pointer( POINTER_ESIZE ); + else + aPtr = Pointer( POINTER_SSIZE ); + } + else if ( aHitTest.bSizeBar ) + { + if ( mnWinStyle & WB_HORZ ) + aPtr = Pointer( POINTER_HSIZEBAR ); + else + aPtr = Pointer( POINTER_VSIZEBAR ); + } + SetPointer( aPtr ); + return ImplStartDrag( &aHitTest, nMouseModifier ); + } + } + else if ( nMouseClicks == 2 ) + { + if ( ImplDocHitTest( aMousePos, eDragType, &aHitTest ) ) + { + mnDragPos = aHitTest.nPos; + mnDragAryPos = aHitTest.nAryPos; + } + eDragType = aHitTest.eType; + + DoubleClick(); + + eDragType = RULER_TYPE_DONTKNOW; + mnDragPos = 0; + mnDragAryPos = 0; + + return TRUE; + } + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +RulerType Ruler::GetDocType( const Point& rPos, RulerType eDragType, + USHORT* pAryPos ) const +{ + ImplRulerHitTest aHitTest; + + // Gegebenenfalls Lineal updaten (damit mit den richtigen Daten + // gearbeitet wird und die Anzeige auch zur Bearbeitung passt) + if ( IsReallyVisible() && mbFormat ) + { + ((Ruler*)this)->ImplDraw(); + ((Ruler*)this)->mnUpdateFlags &= ~RULER_UPDATE_DRAW; + } + + // HitTest durchfuehren + ImplDocHitTest( rPos, eDragType, &aHitTest ); + + // Werte zurueckgeben + if ( pAryPos ) + *pAryPos = aHitTest.nAryPos; + return aHitTest.eType; +} + +// ----------------------------------------------------------------------- + +void Ruler::CancelDrag() +{ + if ( mbDrag ) + { + ImplDrag( Point( -1, -1 ) ); + ImplEndDrag(); + } +} + +// ----------------------------------------------------------------------- + +RulerType Ruler::GetType( const Point& rPos, USHORT* pAryPos ) const +{ + ImplRulerHitTest aHitTest; + + // Gegebenenfalls Lineal updaten (damit mit den richtigen Daten + // gearbeitet wird und die Anzeige auch zur Bearbeitung passt) + if ( IsReallyVisible() && mbFormat ) + { + ((Ruler*)this)->ImplDraw(); + ((Ruler*)this)->mnUpdateFlags &= ~RULER_UPDATE_DRAW; + } + + // HitTest durchfuehren + ImplHitTest( rPos, &aHitTest ); + + // Werte zurueckgeben + if ( pAryPos ) + *pAryPos = aHitTest.nAryPos; + return aHitTest.eType; +} + +// ----------------------------------------------------------------------- + +void Ruler::SetWinPos( long nNewOff, long nNewWidth ) +{ + // Gegebenenfalls werden die Breiten automatisch berechnet + if ( !nNewWidth ) + mbAutoWinWidth = TRUE; + else + mbAutoWinWidth = FALSE; + + // Werte setzen (werden in ImplFormat gegebenenfalls mitberechnet) + mnWinOff = nNewOff; + mnWinWidth = nNewWidth; + ImplUpdate( TRUE ); +} + +// ----------------------------------------------------------------------- + +void Ruler::SetPagePos( long nNewOff, long nNewWidth ) +{ + // Muessen wir ueberhaupt was machen + if ( (mpData->nPageOff == nNewOff) && (mpData->nPageWidth == nNewWidth) ) + return; + + // Gegebenenfalls werden die Breiten automatisch berechnet + if ( !nNewWidth ) + mpData->bAutoPageWidth = TRUE; + else + mpData->bAutoPageWidth = FALSE; + + // Werte setzen (werden in ImplFormat gegebenenfalls mitberechnet) + mpData->nPageOff = nNewOff; + mpData->nPageWidth = nNewWidth; + ImplUpdate( TRUE ); +} + +// ----------------------------------------------------------------------- + +void Ruler::SetBorderPos( long nOff ) +{ + if ( mnWinStyle & WB_BORDER ) + { + if ( mnBorderOff != nOff ) + { + mnBorderOff = nOff; + + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + } + } +} + +// ----------------------------------------------------------------------- + +void Ruler::SetUnit( FieldUnit eNewUnit ) +{ + if ( meUnit != eNewUnit ) + { + meUnit = eNewUnit; + switch ( meUnit ) + { + case FUNIT_MM: + mnUnitIndex = RULER_UNIT_MM; + break; + case FUNIT_CM: + mnUnitIndex = RULER_UNIT_CM; + break; + case FUNIT_M: + mnUnitIndex = RULER_UNIT_M; + break; + case FUNIT_KM: + mnUnitIndex = RULER_UNIT_KM; + break; + case FUNIT_INCH: + mnUnitIndex = RULER_UNIT_INCH; + break; + case FUNIT_FOOT: + mnUnitIndex = RULER_UNIT_FOOT; + break; + case FUNIT_MILE: + mnUnitIndex = RULER_UNIT_MILE; + break; + case FUNIT_POINT: + mnUnitIndex = RULER_UNIT_POINT; + break; + case FUNIT_PICA: + mnUnitIndex = RULER_UNIT_PICA; + break; + default: +#ifdef DBG_UTIL + DBG_ERRORFILE( "Ruler::SetUnit() - Wrong Unit" ); +#endif + break; + } + + maMapMode.SetMapUnit( aImplRulerUnitTab[mnUnitIndex].eMapUnit ); + ImplUpdate(); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::SetZoom( const Fraction& rNewZoom ) +{ + DBG_ASSERT( rNewZoom.GetNumerator(), "Ruler::SetZoom() with scale 0 is not allowed" ); + + if ( maZoom != rNewZoom ) + { + maZoom = rNewZoom; + maMapMode.SetScaleX( maZoom ); + maMapMode.SetScaleY( maZoom ); + ImplUpdate(); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::SetExtraType( RulerExtra eNewExtraType, USHORT nStyle ) +{ + if ( mnWinStyle & WB_EXTRAFIELD ) + { + meExtraType = eNewExtraType; + mnExtraStyle = nStyle; + if ( IsReallyVisible() && IsUpdateMode() ) + ImplDrawExtra( FALSE ); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::SetNullOffset( long nPos ) +{ + if ( mpData->nNullOff != nPos ) + { + mpData->nNullOff = nPos; + ImplUpdate(); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::SetMargin1( long nPos, USHORT nMarginStyle ) +{ + if ( (mpData->nMargin1 != nPos) || (mpData->nMargin1Style != nMarginStyle) ) + { + mpData->nMargin1 = nPos; + mpData->nMargin1Style = nMarginStyle; + ImplUpdate(); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::SetMargin2( long nPos, USHORT nMarginStyle ) +{ + DBG_ASSERT( (nPos >= mpData->nMargin1) || + (mpData->nMargin1Style & RULER_STYLE_INVISIBLE) || + (mpData->nMargin2Style & RULER_STYLE_INVISIBLE), + "Ruler::SetMargin2() - Margin2 < Margin1" ); + + if ( (mpData->nMargin2 != nPos) || (mpData->nMargin2Style != nMarginStyle) ) + { + mpData->nMargin2 = nPos; + mpData->nMargin2Style = nMarginStyle; + ImplUpdate(); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::SetLines( USHORT n, const RulerLine* pLineAry ) +{ + // To determine if what has changed + if ( mpData->nLines == n ) + { + USHORT i = n; + const RulerLine* pAry1 = mpData->pLines; + const RulerLine* pAry2 = pLineAry; + while ( i ) + { + if ( (pAry1->nPos != pAry2->nPos) || + (pAry1->nStyle != pAry2->nStyle) ) + break; + pAry1++; + pAry2++; + i--; + } + if ( !i ) + return; + } + + // New values and new share issue + BOOL bMustUpdate; + if ( IsReallyVisible() && IsUpdateMode() ) + bMustUpdate = TRUE; + else + bMustUpdate = FALSE; + + // Delete old lines + if ( bMustUpdate ) + ImplInvertLines(); + + // New data set + if ( !n || !pLineAry ) + { + if ( !mpData->pLines ) + return; + delete[] mpData->pLines; + mpData->nLines = 0; + mpData->pLines = NULL; + } + else + { + if ( mpData->nLines != n ) + { + delete[] mpData->pLines; + mpData->nLines = n; + mpData->pLines = new RulerLine[n]; + } + + memcpy( mpData->pLines, pLineAry, n*sizeof( RulerLine ) ); + + // Linien neu ausgeben + if ( bMustUpdate ) + ImplInvertLines(); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::SetArrows( USHORT n, const RulerArrow* pArrowAry ) +{ + if ( !n || !pArrowAry ) + { + if ( !mpData->pArrows ) + return; + delete[] mpData->pArrows; + mpData->nArrows = 0; + mpData->pArrows = NULL; + } + else + { + if ( mpData->nArrows != n ) + { + delete[] mpData->pArrows; + mpData->nArrows = n; + mpData->pArrows = new RulerArrow[n]; + } + else + { + USHORT i = n; + const RulerArrow* pAry1 = mpData->pArrows; + const RulerArrow* pAry2 = pArrowAry; + while ( i ) + { + if ( (pAry1->nPos != pAry2->nPos) || + (pAry1->nWidth != pAry2->nWidth) || + (pAry1->nLogWidth != pAry2->nLogWidth) || + (pAry1->nStyle != pAry2->nStyle) ) + break; + pAry1++; + pAry2++; + i--; + } + if ( !i ) + return; + } + + memcpy( mpData->pArrows, pArrowAry, n*sizeof( RulerArrow ) ); + } + + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void Ruler::SetBorders( USHORT n, const RulerBorder* pBrdAry ) +{ + if ( !n || !pBrdAry ) + { + if ( !mpData->pBorders ) + return; + delete[] mpData->pBorders; + mpData->nBorders = 0; + mpData->pBorders = NULL; + } + else + { + if ( mpData->nBorders != n ) + { + delete[] mpData->pBorders; + mpData->nBorders = n; + mpData->pBorders = new RulerBorder[n]; + } + else + { + USHORT i = n; + const RulerBorder* pAry1 = mpData->pBorders; + const RulerBorder* pAry2 = pBrdAry; + while ( i ) + { + if ( (pAry1->nPos != pAry2->nPos) || + (pAry1->nWidth != pAry2->nWidth) || + (pAry1->nStyle != pAry2->nStyle) ) + break; + pAry1++; + pAry2++; + i--; + } + if ( !i ) + return; + } + + memcpy( mpData->pBorders, pBrdAry, n*sizeof( RulerBorder ) ); + } + + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void Ruler::SetIndents( USHORT n, const RulerIndent* pIndentAry ) +{ + + if ( !n || !pIndentAry ) + { + if ( !mpData->pIndents ) + return; + delete[] mpData->pIndents; + mpData->nIndents = 0; + mpData->pIndents = NULL; + } + else + { + if ( mpData->nIndents != n ) + { + delete[] mpData->pIndents; + mpData->nIndents = n; + mpData->pIndents = new RulerIndent[n]; + } + else + { + USHORT i = n; + const RulerIndent* pAry1 = mpData->pIndents; + const RulerIndent* pAry2 = pIndentAry; + while ( i ) + { + if ( (pAry1->nPos != pAry2->nPos) || + (pAry1->nStyle != pAry2->nStyle) ) + break; + pAry1++; + pAry2++; + i--; + } + if ( !i ) + return; + } + + memcpy( mpData->pIndents, pIndentAry, n*sizeof( RulerIndent ) ); + } + + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void Ruler::SetTabs( USHORT n, const RulerTab* pTabAry ) +{ + if ( !n || !pTabAry ) + { + if ( !mpData->pTabs ) + return; + delete[] mpData->pTabs; + mpData->nTabs = 0; + mpData->pTabs = NULL; + } + else + { + if ( mpData->nTabs != n ) + { + delete[] mpData->pTabs; + mpData->nTabs = n; + mpData->pTabs = new RulerTab[n]; + } + else + { + USHORT i = n; + const RulerTab* pAry1 = mpData->pTabs; + const RulerTab* pAry2 = pTabAry; + while ( i ) + { + if ( (pAry1->nPos != pAry2->nPos) || + (pAry1->nStyle != pAry2->nStyle) ) + break; + pAry1++; + pAry2++; + i--; + } + if ( !i ) + return; + } + + memcpy( mpData->pTabs, pTabAry, n*sizeof( RulerTab ) ); + } + + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void Ruler::SetStyle( WinBits nStyle ) +{ + if ( mnWinStyle != nStyle ) + { + mnWinStyle = nStyle; + ImplInitExtraField( TRUE ); + } +} + +// ----------------------------------------------------------------------- + +void Ruler::DrawTab( OutputDevice* pDevice, const Point& rPos, USHORT nStyle ) +{ + /*const StyleSettings& rStyleSettings =*/ pDevice->GetSettings().GetStyleSettings(); + Point aPos( rPos ); + USHORT nTabStyle = nStyle & (RULER_TAB_STYLE | RULER_TAB_RTL); + + pDevice->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); + pDevice->SetLineColor(); + pDevice->SetFillColor( pDevice->GetSettings().GetStyleSettings().GetWindowTextColor() ); + ImplCenterTabPos( aPos, nTabStyle ); + ImplDrawRulerTab( pDevice, aPos, nTabStyle, nStyle ); + pDevice->Pop(); +} +/* -----------------16.10.2002 15:17----------------- + * + * --------------------------------------------------*/ +void Ruler::SetTextRTL(BOOL bRTL) +{ + if(mpData->bTextRTL != bRTL) + { + mpData->bTextRTL = bRTL; + if ( IsReallyVisible() && IsUpdateMode() ) + ImplInitExtraField( TRUE ); + } + +} +long Ruler::GetPageOffset() const { return mpData->nPageOff; } +long Ruler::GetPageWidth() const { return mpData->nPageWidth; } +long Ruler::GetNullOffset() const { return mpData->nNullOff; } +long Ruler::GetMargin1() const { return mpData->nMargin1; } +USHORT Ruler::GetMargin1Style() const { return mpData->nMargin1Style; } +long Ruler::GetMargin2() const { return mpData->nMargin2; } +USHORT Ruler::GetMargin2Style() const { return mpData->nMargin2Style; } +USHORT Ruler::GetLineCount() const { return mpData->nLines; } +const RulerLine* Ruler::GetLines() const { return mpData->pLines; } +USHORT Ruler::GetArrowCount() const { return mpData->nArrows; } +const RulerArrow* Ruler::GetArrows() const { return mpData->pArrows; } +USHORT Ruler::GetBorderCount() const { return mpData->nBorders; } +const RulerBorder* Ruler::GetBorders() const { return mpData->pBorders; } +USHORT Ruler::GetIndentCount() const { return mpData->nIndents; } +const RulerIndent* Ruler::GetIndents() const { return mpData->pIndents; } + diff --git a/svtools/source/control/scriptedtext.cxx b/svtools/source/control/scriptedtext.cxx new file mode 100755 index 000000000000..191dedfabe98 --- /dev/null +++ b/svtools/source/control/scriptedtext.cxx @@ -0,0 +1,392 @@ +/************************************************************************* + * + * 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_svtools.hxx" +#include <svtools/scriptedtext.hxx> +#include <vector> +#include <rtl/ustring.hxx> +#include <vcl/outdev.hxx> +#include <vcl/font.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/i18n/ScriptType.hpp> + + +using namespace ::std; +using namespace ::rtl; +using namespace ::com::sun::star; + + +//_____________________________________________________________________________ + +class SvtScriptedTextHelper_Impl +{ +private: + OutputDevice& mrOutDevice; /// The output device for drawing the text. + Font maLatinFont; /// The font for latin text portions. + Font maAsianFont; /// The font for asian text portions. + Font maCmplxFont; /// The font for complex text portions. + Font maDefltFont; /// The default font of the output device. + OUString maText; /// The text. + + vector< sal_Int32 > maPosVec; /// The start position of each text portion. + vector< sal_Int16 > maScriptVec; /// The script type of each text portion. + vector< sal_Int32 > maWidthVec; /// The output width of each text portion. + Size maTextSize; /// The size the text will take in the current output device. + + /** Assignment operator not implemented to prevent usage. */ + SvtScriptedTextHelper_Impl& operator=( const SvtScriptedTextHelper_Impl& ); + + /** Gets the font of the given script type. */ + const Font& GetFont( sal_uInt16 _nScript ) const; + /** Sets a font on the output device depending on the script type. */ + inline void SetOutDevFont( sal_uInt16 _nScript ) + { mrOutDevice.SetFont( GetFont( _nScript ) ); } + /** Fills maPosVec with positions of all changes of script type. + This method expects correctly initialized maPosVec and maScriptVec. */ + void CalculateSizes(); + /** Fills maPosVec with positions of all changes of script type and + maScriptVec with the script type of each portion. */ + void CalculateBreaks( + const uno::Reference< i18n::XBreakIterator >& _xBreakIter ); + +public: + /** This constructor sets an output device and fonts for all script types. */ + SvtScriptedTextHelper_Impl( + OutputDevice& _rOutDevice, + Font* _pLatinFont, + Font* _pAsianFont, + Font* _pCmplxFont ); + /** Copy constructor. */ + SvtScriptedTextHelper_Impl( + const SvtScriptedTextHelper_Impl& _rCopy ); + /** Destructor. */ + ~SvtScriptedTextHelper_Impl(); + + /** Sets new fonts and recalculates the text width. */ + void SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ); + /** Sets a new text and calculates all script breaks and the text width. */ + void SetText( + const OUString& _rText, + const uno::Reference< i18n::XBreakIterator >& _xBreakIter ); + + /** Returns the previously set text. */ + const OUString& GetText() const; + /** Returns a size struct containing the width and height of the text in the current output device. */ + const Size& GetTextSize() const; + + /** Draws the text in the current output device. */ + void DrawText( const Point& _rPos ); +}; + + +SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl( + OutputDevice& _rOutDevice, + Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) : + mrOutDevice( _rOutDevice ), + maLatinFont( _pLatinFont ? *_pLatinFont : _rOutDevice.GetFont() ), + maAsianFont( _pAsianFont ? *_pAsianFont : _rOutDevice.GetFont() ), + maCmplxFont( _pCmplxFont ? *_pCmplxFont : _rOutDevice.GetFont() ), + maDefltFont( _rOutDevice.GetFont() ) +{ +} + +SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl( const SvtScriptedTextHelper_Impl& _rCopy ) : + mrOutDevice( _rCopy.mrOutDevice ), + maLatinFont( _rCopy.maLatinFont ), + maAsianFont( _rCopy.maAsianFont ), + maCmplxFont( _rCopy.maCmplxFont ), + maDefltFont( _rCopy.maDefltFont ), + maText( _rCopy.maText ), + maPosVec( _rCopy.maPosVec ), + maScriptVec( _rCopy.maScriptVec ), + maWidthVec( _rCopy.maWidthVec ), + maTextSize( _rCopy.maTextSize ) +{ +} + +SvtScriptedTextHelper_Impl::~SvtScriptedTextHelper_Impl() +{ +} + +const Font& SvtScriptedTextHelper_Impl::GetFont( sal_uInt16 _nScript ) const +{ + switch( _nScript ) + { + case i18n::ScriptType::LATIN: return maLatinFont; + case i18n::ScriptType::ASIAN: return maAsianFont; + case i18n::ScriptType::COMPLEX: return maCmplxFont; + } + return maDefltFont; +} + +void SvtScriptedTextHelper_Impl::CalculateSizes() +{ + maTextSize.Width() = maTextSize.Height() = 0; + maDefltFont = mrOutDevice.GetFont(); + + // calculate text portion widths and total width + maWidthVec.clear(); + if( !maPosVec.empty() ) + { + DBG_ASSERT( maPosVec.size() - 1 == maScriptVec.size(), + "SvtScriptedTextHelper_Impl::CalculateWidth - invalid vectors" ); + + xub_StrLen nThisPos = static_cast< xub_StrLen >( maPosVec[ 0 ] ); + xub_StrLen nNextPos; + sal_Int32 nPosVecSize = maPosVec.size(); + sal_Int32 nPosVecIndex = 1; + + sal_Int16 nScript; + sal_Int32 nScriptVecIndex = 0; + + sal_Int32 nCurrWidth; + + while( nPosVecIndex < nPosVecSize ) + { + nNextPos = static_cast< xub_StrLen >( maPosVec[ nPosVecIndex++ ] ); + nScript = maScriptVec[ nScriptVecIndex++ ]; + + SetOutDevFont( nScript ); + nCurrWidth = mrOutDevice.GetTextWidth( maText, nThisPos, nNextPos - nThisPos ); + maWidthVec.push_back( nCurrWidth ); + maTextSize.Width() += nCurrWidth; + nThisPos = nNextPos; + } + } + + // calculate maximum font height + SetOutDevFont( i18n::ScriptType::LATIN ); + maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() ); + SetOutDevFont( i18n::ScriptType::ASIAN ); + maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() ); + SetOutDevFont( i18n::ScriptType::COMPLEX ); + maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() ); + + mrOutDevice.SetFont( maDefltFont ); +} + +void SvtScriptedTextHelper_Impl::CalculateBreaks( const uno::Reference< i18n::XBreakIterator >& _xBreakIter ) +{ + maPosVec.clear(); + maScriptVec.clear(); + + DBG_ASSERT( _xBreakIter.is(), "SvtScriptedTextHelper_Impl::CalculateBreaks - no break iterator" ); + + sal_Int32 nLen = maText.getLength(); + if( nLen ) + { + if( _xBreakIter.is() ) + { + sal_Int32 nThisPos = 0; // first position of this portion + sal_Int32 nNextPos = 0; // first position of next portion + sal_Int16 nPortScript; // script type of this portion + do + { + nPortScript = _xBreakIter->getScriptType( maText, nThisPos ); + nNextPos = _xBreakIter->endOfScript( maText, nThisPos, nPortScript ); + + switch( nPortScript ) + { + case i18n::ScriptType::LATIN: + case i18n::ScriptType::ASIAN: + case i18n::ScriptType::COMPLEX: + maPosVec.push_back( nThisPos ); + maScriptVec.push_back( nPortScript ); + break; + default: + { +/* *** handling of weak characters *** +- first portion is weak: Use OutputDevice::HasGlyphs() to find the correct font +- weak portion follows another portion: Script type of preceding portion is used */ + if( maPosVec.empty() ) + { + sal_Int32 nCharIx = 0; + sal_Int32 nNextCharIx = 0; + sal_Int16 nScript; + do + { + nScript = i18n::ScriptType::LATIN; + while( (nScript != i18n::ScriptType::WEAK) && (nCharIx == nNextCharIx) ) + { + nNextCharIx = mrOutDevice.HasGlyphs( GetFont( nScript ), maText, sal::static_int_cast< USHORT >(nCharIx), sal::static_int_cast< USHORT >(nNextPos - nCharIx) ); + if( nCharIx == nNextCharIx ) + ++nScript; + } + if( nNextCharIx == nCharIx ) + ++nNextCharIx; + + maPosVec.push_back( nCharIx ); + maScriptVec.push_back( nScript ); + nCharIx = nNextCharIx; + } + while( nCharIx < nNextPos ); + } + // nothing to do for following portions + } + } + nThisPos = nNextPos; + } + while( (0 <= nThisPos) && (nThisPos < nLen) ); + } + else // no break iterator: whole text LATIN + { + maPosVec.push_back( 0 ); + maScriptVec.push_back( i18n::ScriptType::LATIN ); + } + + // push end position of last portion + if( !maPosVec.empty() ) + maPosVec.push_back( nLen ); + } + CalculateSizes(); +} + +void SvtScriptedTextHelper_Impl::SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) +{ + maLatinFont = _pLatinFont ? *_pLatinFont : maDefltFont; + maAsianFont = _pAsianFont ? *_pAsianFont : maDefltFont; + maCmplxFont = _pCmplxFont ? *_pCmplxFont : maDefltFont; + CalculateSizes(); +} + +void SvtScriptedTextHelper_Impl::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter ) +{ + maText = _rText; + CalculateBreaks( _xBreakIter ); +} + +const OUString& SvtScriptedTextHelper_Impl::GetText() const +{ + return maText; +} + +const Size& SvtScriptedTextHelper_Impl::GetTextSize() const +{ + return maTextSize; +} + +void SvtScriptedTextHelper_Impl::DrawText( const Point& _rPos ) +{ + if( !maText.getLength() || maPosVec.empty() ) + return; + + DBG_ASSERT( maPosVec.size() - 1 == maScriptVec.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" ); + DBG_ASSERT( maScriptVec.size() == maWidthVec.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" ); + + maDefltFont = mrOutDevice.GetFont(); + Point aCurrPos( _rPos ); + xub_StrLen nThisPos = static_cast< xub_StrLen >( maPosVec[ 0 ] ); + xub_StrLen nNextPos; + sal_Int32 nPosVecSize = maPosVec.size(); + sal_Int32 nPosVecIndex = 1; + + sal_Int16 nScript; + sal_Int32 nVecIndex = 0; + + while( nPosVecIndex < nPosVecSize ) + { + nNextPos = static_cast< xub_StrLen >( maPosVec[ nPosVecIndex++ ] ); + nScript = maScriptVec[ nVecIndex ]; + + SetOutDevFont( nScript ); + mrOutDevice.DrawText( aCurrPos, maText, nThisPos, nNextPos - nThisPos ); + aCurrPos.X() += maWidthVec[ nVecIndex++ ]; + aCurrPos.X() += mrOutDevice.GetTextHeight() / 5; // add 20% of font height as portion spacing + nThisPos = nNextPos; + } + mrOutDevice.SetFont( maDefltFont ); +} + + +//_____________________________________________________________________________ + +SvtScriptedTextHelper::SvtScriptedTextHelper( OutputDevice& _rOutDevice ) : + mpImpl( new SvtScriptedTextHelper_Impl( _rOutDevice, NULL, NULL, NULL ) ) +{ +} + +SvtScriptedTextHelper::SvtScriptedTextHelper( + OutputDevice& _rOutDevice, + Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) : + mpImpl( new SvtScriptedTextHelper_Impl( _rOutDevice, _pLatinFont, _pAsianFont, _pCmplxFont ) ) +{ +} + +SvtScriptedTextHelper::SvtScriptedTextHelper( const SvtScriptedTextHelper& _rCopy ) : + mpImpl( new SvtScriptedTextHelper_Impl( *_rCopy.mpImpl ) ) +{ +} + +SvtScriptedTextHelper::~SvtScriptedTextHelper() +{ + delete mpImpl; +} + +void SvtScriptedTextHelper::SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) +{ + mpImpl->SetFonts( _pLatinFont, _pAsianFont, _pCmplxFont ); +} + +void SvtScriptedTextHelper::SetDefaultFont() +{ + mpImpl->SetFonts( NULL, NULL, NULL ); +} + +void SvtScriptedTextHelper::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter ) +{ + mpImpl->SetText( _rText, _xBreakIter ); +} + +const OUString& SvtScriptedTextHelper::GetText() const +{ + return mpImpl->GetText(); +} + +sal_Int32 SvtScriptedTextHelper::GetTextWidth() const +{ + return mpImpl->GetTextSize().Width(); +} + +sal_Int32 SvtScriptedTextHelper::GetTextHeight() const +{ + return mpImpl->GetTextSize().Height(); +} + +const Size& SvtScriptedTextHelper::GetTextSize() const +{ + return mpImpl->GetTextSize(); +} + +void SvtScriptedTextHelper::DrawText( const Point& _rPos ) +{ + mpImpl->DrawText( _rPos ); +} + + +//_____________________________________________________________________________ + diff --git a/svtools/source/control/scrwin.cxx b/svtools/source/control/scrwin.cxx new file mode 100755 index 000000000000..364c938f3f65 --- /dev/null +++ b/svtools/source/control/scrwin.cxx @@ -0,0 +1,572 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#define _SVT_SCRWIN_CXX +#include <svtools/scrwin.hxx> + +//=================================================================== + +void ScrollableWindow::ImpInitialize( ScrollableWindowFlags nFlags ) +{ + bHandleDragging = (BOOL) ( nFlags & SCRWIN_THUMBDRAGGING ); + bVCenter = (nFlags & SCRWIN_VCENTER) == SCRWIN_VCENTER; + bHCenter = (nFlags & SCRWIN_HCENTER) == SCRWIN_HCENTER; + bScrolling = FALSE; + + // set the handlers for the scrollbars + aVScroll.SetScrollHdl( LINK(this, ScrollableWindow, ScrollHdl) ); + aHScroll.SetScrollHdl( LINK(this, ScrollableWindow, ScrollHdl) ); + aVScroll.SetEndScrollHdl( LINK(this, ScrollableWindow, EndScrollHdl) ); + aHScroll.SetEndScrollHdl( LINK(this, ScrollableWindow, EndScrollHdl) ); + + nColumnPixW = nLinePixH = GetSettings().GetStyleSettings().GetScrollBarSize(); +} + +//------------------------------------------------------------------- + +ScrollableWindow::ScrollableWindow( Window* pParent, WinBits nBits, + ScrollableWindowFlags nFlags ) : + Window( pParent, WinBits(nBits|WB_CLIPCHILDREN) ), + aVScroll( this, WinBits(WB_VSCROLL | WB_DRAG) ), + aHScroll( this, WinBits(WB_HSCROLL | WB_DRAG) ), + aCornerWin( this ) +{ + ImpInitialize( nFlags ); +} + +//------------------------------------------------------------------- + +ScrollableWindow::ScrollableWindow( Window* pParent, const ResId& rId, + ScrollableWindowFlags nFlags ) : + Window( pParent, rId ), + aVScroll( this, WinBits(WB_VSCROLL | WB_DRAG) ), + aHScroll( this, WinBits(WB_HSCROLL | WB_DRAG) ), + aCornerWin( this ) +{ + ImpInitialize( nFlags ); +} + +// ----------------------------------------------------------------------- + +void ScrollableWindow::Command( const CommandEvent& rCEvt ) +{ + if ( (rCEvt.GetCommand() == COMMAND_WHEEL) || + (rCEvt.GetCommand() == COMMAND_STARTAUTOSCROLL) || + (rCEvt.GetCommand() == COMMAND_AUTOSCROLL) ) + { + ScrollBar* pHScrBar; + ScrollBar* pVScrBar; + if ( aHScroll.IsVisible() ) + pHScrBar = &aHScroll; + else + pHScrBar = NULL; + if ( aVScroll.IsVisible() ) + pVScrBar = &aVScroll; + else + pVScrBar = NULL; + if ( HandleScrollCommand( rCEvt, pHScrBar, pVScrBar ) ) + return; + } + + Window::Command( rCEvt ); +} + +//------------------------------------------------------------------- + +void ScrollableWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + Resize(); + Invalidate(); + } + + Window::DataChanged( rDCEvt ); +} + +//------------------------------------------------------------------- + +Size __EXPORT ScrollableWindow::GetOutputSizePixel() const +{ + Size aSz( Window::GetOutputSizePixel() ); + + long nTmp = GetSettings().GetStyleSettings().GetScrollBarSize(); + if ( aHScroll.IsVisible() ) + aSz.Height() -= nTmp; + if ( aVScroll.IsVisible() ) + aSz.Width() -= nTmp; + return aSz; +} + +//------------------------------------------------------------------- + +Size ScrollableWindow::GetOutputSize() const +{ + return PixelToLogic( GetOutputSizePixel() ); +} + +//------------------------------------------------------------------- + +IMPL_LINK( ScrollableWindow, EndScrollHdl, ScrollBar *, pScroll ) +{ + // notify the start of scrolling, if not already scrolling + if ( !bScrolling ) + StartScroll(), bScrolling = TRUE; + + // get the delta in logic coordinates + Size aDelta( PixelToLogic( Size( aHScroll.GetDelta(), aVScroll.GetDelta() ) ) ); + + // scroll the window, if this is not already done + if ( !bHandleDragging ) + { + if ( pScroll == &aHScroll ) + Scroll( aDelta.Width(), 0 ); + else + Scroll( 0, aDelta.Height() ); + } + + // notify the end of scrolling + bScrolling = FALSE; + EndScroll( aDelta.Width(), aDelta.Height() ); + return 0; +} + +//------------------------------------------------------------------- + +IMPL_LINK( ScrollableWindow, ScrollHdl, ScrollBar *, pScroll ) +{ + // notify the start of scrolling, if not already scrolling + if ( !bScrolling ) + StartScroll(), bScrolling = TRUE; + + if ( bHandleDragging ) + { + // get the delta in logic coordinates + Size aDelta( PixelToLogic( + Size( aHScroll.GetDelta(), aVScroll.GetDelta() ) ) ); + if ( pScroll == &aHScroll ) + Scroll( aDelta.Width(), 0 ); + else + Scroll( 0, aDelta.Height() ); + } + return 0; +} + +//------------------------------------------------------------------- + +void __EXPORT ScrollableWindow::Resize() +{ + // get the new output-size in pixel + Size aOutPixSz = Window::GetOutputSizePixel(); + + // determine the size of the output-area and if we need scrollbars + const long nScrSize = GetSettings().GetStyleSettings().GetScrollBarSize(); + BOOL bVVisible = FALSE; // by default no vertical-ScrollBar + BOOL bHVisible = FALSE; // by default no horizontal-ScrollBar + BOOL bChanged; // determines if a visiblility was changed + do + { + bChanged = FALSE; + + // does we need a vertical ScrollBar + if ( aOutPixSz.Width() < aTotPixSz.Width() && !bHVisible ) + { bHVisible = TRUE; + aOutPixSz.Height() -= nScrSize; + bChanged = TRUE; + } + + // does we need a horizontal ScrollBar + if ( aOutPixSz.Height() < aTotPixSz.Height() && !bVVisible ) + { bVVisible = TRUE; + aOutPixSz.Width() -= nScrSize; + bChanged = TRUE; + } + + } + while ( bChanged ); // until no visibility has changed + + // store the old offset and map-mode + MapMode aMap( GetMapMode() ); + Point aOldPixOffset( aPixOffset ); + + // justify (right/bottom borders should never exceed the virtual window) + Size aPixDelta; + if ( aPixOffset.X() < 0 && + aPixOffset.X() + aTotPixSz.Width() < aOutPixSz.Width() ) + aPixDelta.Width() = + aOutPixSz.Width() - ( aPixOffset.X() + aTotPixSz.Width() ); + if ( aPixOffset.Y() < 0 && + aPixOffset.Y() + aTotPixSz.Height() < aOutPixSz.Height() ) + aPixDelta.Height() = + aOutPixSz.Height() - ( aPixOffset.Y() + aTotPixSz.Height() ); + if ( aPixDelta.Width() || aPixDelta.Height() ) + { + aPixOffset.X() += aPixDelta.Width(); + aPixOffset.Y() += aPixDelta.Height(); + } + + // for axis without scrollbar restore the origin + if ( !bVVisible || !bHVisible ) + { + aPixOffset = Point( + bHVisible + ? aPixOffset.X() + : ( bHCenter + ? (aOutPixSz.Width()-aTotPixSz.Width()) / 2 + : 0 ), + bVVisible + ? aPixOffset.Y() + : ( bVCenter + ? (aOutPixSz.Height()-aTotPixSz.Height()) / 2 + : 0 ) ); + } + if ( bHVisible && !aHScroll.IsVisible() ) + aPixOffset.X() = 0; + if ( bVVisible && !aVScroll.IsVisible() ) + aPixOffset.Y() = 0; + + // select the shifted map-mode + if ( aPixOffset != aOldPixOffset ) + { + Window::SetMapMode( MapMode( MAP_PIXEL ) ); + Window::Scroll( + aPixOffset.X() - aOldPixOffset.X(), + aPixOffset.Y() - aOldPixOffset.Y() ); + SetMapMode( aMap ); + } + + // show or hide scrollbars + aVScroll.Show( bVVisible ); + aHScroll.Show( bHVisible ); + + // disable painting in the corner between the scrollbars + if ( bVVisible && bHVisible ) + { + aCornerWin.SetPosSizePixel(Point(aOutPixSz.Width(), aOutPixSz.Height()), + Size(nScrSize, nScrSize) ); + aCornerWin.Show(); + } + else + aCornerWin.Hide(); + + // resize scrollbars and set their ranges + if ( bHVisible ) + { + aHScroll.SetPosSizePixel( + Point( 0, aOutPixSz.Height() ), + Size( aOutPixSz.Width(), nScrSize ) ); + aHScroll.SetRange( Range( 0, aTotPixSz.Width() ) ); + aHScroll.SetPageSize( aOutPixSz.Width() ); + aHScroll.SetVisibleSize( aOutPixSz.Width() ); + aHScroll.SetLineSize( nColumnPixW ); + aHScroll.SetThumbPos( -aPixOffset.X() ); + } + if ( bVVisible ) + { + aVScroll.SetPosSizePixel( + Point( aOutPixSz.Width(), 0 ), + Size( nScrSize,aOutPixSz.Height() ) ); + aVScroll.SetRange( Range( 0, aTotPixSz.Height() ) ); + aVScroll.SetPageSize( aOutPixSz.Height() ); + aVScroll.SetVisibleSize( aOutPixSz.Height() ); + aVScroll.SetLineSize( nLinePixH ); + aVScroll.SetThumbPos( -aPixOffset.Y() ); + } +} + +//------------------------------------------------------------------- + +void __EXPORT ScrollableWindow::StartScroll() +{ +} + +//------------------------------------------------------------------- + +void __EXPORT ScrollableWindow::EndScroll( long, long ) +{ +} + +//------------------------------------------------------------------- + +void ScrollableWindow::SetMapMode( const MapMode& rNewMapMode ) +{ + MapMode aMap( rNewMapMode ); + aMap.SetOrigin( aMap.GetOrigin() + PixelToLogic( aPixOffset, aMap ) ); + Window::SetMapMode( aMap ); +} + +//------------------------------------------------------------------- + +MapMode ScrollableWindow::GetMapMode() const +{ + MapMode aMap( Window::GetMapMode() ); + aMap.SetOrigin( aMap.GetOrigin() - PixelToLogic( aPixOffset ) ); + return aMap; +} + +//------------------------------------------------------------------- + +void ScrollableWindow::SetTotalSize( const Size& rNewSize ) +{ + aTotPixSz = LogicToPixel( rNewSize ); + ScrollableWindow::Resize(); +} + +//------------------------------------------------------------------- + +void ScrollableWindow::SetVisibleSize( const Size& rNewSize ) +{ + // get the rectangle, we wish to view + Rectangle aWish( Point(0, 0), LogicToPixel(rNewSize) ); + + // get maximum rectangle for us from our parent-window (subst our border!) + Rectangle aMax( Point(0, 0), GetParent()->GetOutputSizePixel() ); + aMax.Left() -= ( Window::GetSizePixel().Width() - + Window::GetOutputSizePixel().Width() ); + aMax.Bottom() -= (Window::GetSizePixel().Height() - + Window::GetOutputSizePixel().Height()); + + Size aWill( aWish.GetIntersection(aMax).GetSize() ); + BOOL bHScroll = FALSE; + const long nScrSize = GetSettings().GetStyleSettings().GetScrollBarSize(); + if ( aWill.Width() < aWish.GetSize().Width() ) + { bHScroll = TRUE; + aWill.Height() = + Min( aWill.Height()+nScrSize, aMax.GetSize().Height() ); + } + if ( aWill.Height() < aWish.GetSize().Height() ) + aWill.Width() = + Min( aWill.Width()+nScrSize, aMax.GetSize().Width() ); + if ( !bHScroll && (aWill.Width() < aWish.GetSize().Width()) ) + aWill.Height() = + Min( aWill.Height()+nScrSize, aMax.GetSize().Height() ); + Window::SetOutputSizePixel( aWill ); +} + +//------------------------------------------------------------------- + +BOOL ScrollableWindow::MakeVisible( const Rectangle& rTarget, BOOL bSloppy ) +{ + Rectangle aTarget; + Rectangle aTotRect( Point(0, 0), PixelToLogic( aTotPixSz ) ); + + if ( bSloppy ) + { + aTarget = rTarget; + + // at maximum to right border + if ( aTarget.Right() > aTotRect.Right() ) + { + long nDelta = aTarget.Right() - aTotRect.Right(); + aTarget.Left() -= nDelta; + aTarget.Right() -= nDelta; + + // too wide? + if ( aTarget.Left() < aTotRect.Left() ) + aTarget.Left() = aTotRect.Left(); + } + + // at maximum to bottom border + if ( aTarget.Bottom() > aTotRect.Bottom() ) + { + long nDelta = aTarget.Bottom() - aTotRect.Bottom(); + aTarget.Top() -= nDelta; + aTarget.Bottom() -= nDelta; + + // too high? + if ( aTarget.Top() < aTotRect.Top() ) + aTarget.Top() = aTotRect.Top(); + } + + // at maximum to left border + if ( aTarget.Left() < aTotRect.Left() ) + { + long nDelta = aTarget.Left() - aTotRect.Left(); + aTarget.Right() -= nDelta; + aTarget.Left() -= nDelta; + + // too wide? + if ( aTarget.Right() > aTotRect.Right() ) + aTarget.Right() = aTotRect.Right(); + } + + // at maximum to top border + if ( aTarget.Top() < aTotRect.Top() ) + { + long nDelta = aTarget.Top() - aTotRect.Top(); + aTarget.Bottom() -= nDelta; + aTarget.Top() -= nDelta; + + // too high? + if ( aTarget.Bottom() > aTotRect.Bottom() ) + aTarget.Bottom() = aTotRect.Bottom(); + } + } + else + aTarget = rTarget.GetIntersection( aTotRect ); + + // is the area already visible? + Rectangle aVisArea( GetVisibleArea() ); + if ( aVisArea.IsInside(rTarget) ) + return TRUE; + + // is there somewhat to scroll? + if ( aVisArea.TopLeft() != aTarget.TopLeft() ) + { + Rectangle aBox( aTarget.GetUnion(aVisArea) ); + long nDeltaX = ( aBox.Right() - aVisArea.Right() ) + + ( aBox.Left() - aVisArea.Left() ); + long nDeltaY = ( aBox.Top() - aVisArea.Top() ) + + ( aBox.Bottom() - aVisArea.Bottom() ); + Scroll( nDeltaX, nDeltaY ); + } + + // determine if the target is completely visible + return aVisArea.GetWidth() >= aTarget.GetWidth() && + aVisArea.GetHeight() >= aTarget.GetHeight(); +} + +//------------------------------------------------------------------- + +Rectangle ScrollableWindow::GetVisibleArea() const +{ + Point aTopLeft( PixelToLogic( Point() ) ); + Size aSz( GetOutputSize() ); + return Rectangle( aTopLeft, aSz ); +} + +//------------------------------------------------------------------- + +void ScrollableWindow::SetLineSize( ULONG nHorz, ULONG nVert ) +{ + Size aPixSz( LogicToPixel( Size(nHorz, nVert) ) ); + nColumnPixW = aPixSz.Width(); + nLinePixH = aPixSz.Height(); + aVScroll.SetLineSize( nLinePixH ); + aHScroll.SetLineSize( nColumnPixW ); +} + +//------------------------------------------------------------------- + +void ScrollableWindow::Scroll( long nDeltaX, long nDeltaY, USHORT ) +{ + if ( !bScrolling ) + StartScroll(); + + // get the delta in pixel + Size aDeltaPix( LogicToPixel( Size(nDeltaX, nDeltaY) ) ); + Size aOutPixSz( GetOutputSizePixel() ); + MapMode aMap( GetMapMode() ); + Point aNewPixOffset( aPixOffset ); + + // scrolling horizontally? + if ( nDeltaX != 0 ) + { + aNewPixOffset.X() -= aDeltaPix.Width(); + if ( ( aOutPixSz.Width() - aNewPixOffset.X() ) > aTotPixSz.Width() ) + aNewPixOffset.X() = - ( aTotPixSz.Width() - aOutPixSz.Width() ); + else if ( aNewPixOffset.X() > 0 ) + aNewPixOffset.X() = 0; + } + + // scrolling vertically? + if ( nDeltaY != 0 ) + { + aNewPixOffset.Y() -= aDeltaPix.Height(); + if ( ( aOutPixSz.Height() - aNewPixOffset.Y() ) > aTotPixSz.Height() ) + aNewPixOffset.Y() = - ( aTotPixSz.Height() - aOutPixSz.Height() ); + else if ( aNewPixOffset.Y() > 0 ) + aNewPixOffset.Y() = 0; + } + + // recompute the logical scroll units + aDeltaPix.Width() = aPixOffset.X() - aNewPixOffset.X(); + aDeltaPix.Height() = aPixOffset.Y() - aNewPixOffset.Y(); + Size aDelta( PixelToLogic(aDeltaPix) ); + nDeltaX = aDelta.Width(); + nDeltaY = aDelta.Height(); + aPixOffset = aNewPixOffset; + + // scrolling? + if ( nDeltaX != 0 || nDeltaY != 0 ) + { + Update(); + + // does the new area overlap the old one? + if ( Abs( (int)aDeltaPix.Height() ) < aOutPixSz.Height() || + Abs( (int)aDeltaPix.Width() ) < aOutPixSz.Width() ) + { + // scroll the overlapping area + SetMapMode( aMap ); + + // never scroll the scrollbars itself! + Window::Scroll(-nDeltaX, -nDeltaY, + PixelToLogic( Rectangle( Point(0, 0), aOutPixSz ) ) ); + } + else + { + // repaint all + SetMapMode( aMap ); + Invalidate(); + } + + Update(); + } + + if ( !bScrolling ) + { + EndScroll( nDeltaX, nDeltaY ); + if ( nDeltaX ) + aHScroll.SetThumbPos( -aPixOffset.X() ); + if ( nDeltaY ) + aVScroll.SetThumbPos( -aPixOffset.Y() ); + } +} + +//------------------------------------------------------------------- + +void ScrollableWindow::ScrollLines( long nLinesX, long nLinesY ) +{ + Size aDelta( PixelToLogic( Size( nColumnPixW, nLinePixH ) ) ); + Scroll( aDelta.Width()*nLinesX, aDelta.Height()*nLinesY ); +} + +//------------------------------------------------------------------- + +void ScrollableWindow::ScrollPages( long nPagesX, ULONG nOverlapX, + long nPagesY, ULONG nOverlapY ) +{ + Size aOutSz( GetVisibleArea().GetSize() ); + Scroll( nPagesX * aOutSz.Width() + (nPagesX>0 ? 1 : -1) * nOverlapX, + nPagesY * aOutSz.Height() + (nPagesY>0 ? 1 : -1) * nOverlapY ); +} + + diff --git a/svtools/source/control/stdctrl.cxx b/svtools/source/control/stdctrl.cxx new file mode 100644 index 000000000000..14c8cade3092 --- /dev/null +++ b/svtools/source/control/stdctrl.cxx @@ -0,0 +1,96 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#include <svtools/stdctrl.hxx> + +// ======================================================================= + +FixedInfo::FixedInfo( Window* pParent, WinBits nWinStyle ) : + FixedText( pParent, nWinStyle | WB_INFO ) +{ +} + +// ----------------------------------------------------------------------- + +FixedInfo::FixedInfo( Window* pParent, const ResId& rResId ) : + FixedText( pParent, rResId ) +{ + SetStyle( GetStyle() | WB_INFO ); +} + +namespace svt +{ + // class svt::SelectableFixedText ---------------------------------------- + + SelectableFixedText::SelectableFixedText( Window* pParent, WinBits nWinStyle ) : + Edit( pParent, nWinStyle ) + { + Init(); + } + + // ----------------------------------------------------------------------- + + SelectableFixedText::SelectableFixedText( Window* pParent, const ResId& rResId ) : + Edit( pParent, rResId ) + { + Init(); + } + + // ----------------------------------------------------------------------- + + SelectableFixedText::~SelectableFixedText() + { + } + + // ----------------------------------------------------------------------- + + void SelectableFixedText::Init() + { + // no border + SetBorderStyle( WINDOW_BORDER_NOBORDER ); + // read-only + SetReadOnly(); + // make it transparent + SetControlBackground(); + SetBackground(); + SetPaintTransparent( TRUE ); + } + + // ----------------------------------------------------------------------- + + void SelectableFixedText::LoseFocus() + { + Edit::LoseFocus(); + // clear cursor + Invalidate(); + } + +} // namespace svt + diff --git a/svtools/source/control/stdmenu.cxx b/svtools/source/control/stdmenu.cxx new file mode 100755 index 000000000000..9df32d74fc59 --- /dev/null +++ b/svtools/source/control/stdmenu.cxx @@ -0,0 +1,510 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#include <string.h> +#include <vcl/svapp.hxx> +#include <vcl/i18nhelp.hxx> +#include <svtools/ctrltool.hxx> +#include <svtools/stdmenu.hxx> + +// ======================================================================== + +FontNameMenu::FontNameMenu() +{ + SetMenuFlags( GetMenuFlags() | MENU_FLAG_NOAUTOMNEMONICS ); +} + +// ----------------------------------------------------------------------- + +FontNameMenu::~FontNameMenu() +{ +} + +// ----------------------------------------------------------------------- + +void FontNameMenu::Select() +{ + maCurName = GetItemText( GetCurItemId() ); + maSelectHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void FontNameMenu::Highlight() +{ + XubString aTempName = maCurName; + maCurName = GetItemText( GetCurItemId() ); + maHighlightHdl.Call( this ); + maCurName = aTempName; +} + +// ----------------------------------------------------------------------- + +void FontNameMenu::Fill( const FontList* pList ) +{ + // clear menu + Clear(); + + // add fonts + const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper(); + // more than 100 fonts reduces the speed of opening the menu. + // So only the first 100 fonts will be displayed. + USHORT nFontCount = ::std::min( pList->GetFontNameCount(), static_cast< USHORT >(100) ); + for ( USHORT i = 0; i < nFontCount; i++ ) + { + const XubString& rName = pList->GetFontName( i ).GetName(); + + // sort with the I18nHelper + USHORT j = GetItemCount(); + while ( j ) + { + XubString aText = GetItemText( GetItemId( j-1 ) ); + if ( rI18nHelper.CompareString( rName, aText ) > 0 ) + break; + j--; + } + InsertItem( i+1, rName, MIB_RADIOCHECK | MIB_AUTOCHECK, j ); + } + + SetCurName( maCurName ); +} + +// ----------------------------------------------------------------------- + +void FontNameMenu::SetCurName( const XubString& rName ) +{ + maCurName = rName; + + // Menueintrag checken + USHORT nChecked = 0; + USHORT nItemCount = GetItemCount(); + for( USHORT i = 0; i < nItemCount; i++ ) + { + USHORT nItemId = GetItemId( i ); + + if ( IsItemChecked( nItemId ) ) + nChecked = nItemId; + + XubString aText = GetItemText( nItemId ); + if ( aText == maCurName ) + { + CheckItem( nItemId, TRUE ); + return; + } + } + + if ( nChecked ) + CheckItem( nChecked, FALSE ); +} + +// ======================================================================== + +FontStyleMenu::FontStyleMenu() +{ + SetMenuFlags( GetMenuFlags() | MENU_FLAG_NOAUTOMNEMONICS ); +} + +// ----------------------------------------------------------------------- + +FontStyleMenu::~FontStyleMenu() +{ +} + +// ----------------------------------------------------------------------- + +void FontStyleMenu::Select() +{ + USHORT nCurId = GetCurItemId(); + + if ( (nCurId >= FONTSTYLEMENU_FIRSTID) && (nCurId <= FONTSTYLEMENU_LASTID) ) + { + maCurStyle = GetItemText( nCurId ); + maSelectHdl.Call( this ); + } + else + PopupMenu::Select(); +} + +// ----------------------------------------------------------------------- + +void FontStyleMenu::Highlight() +{ + USHORT nCurId = GetCurItemId(); + + if ( (nCurId >= FONTSTYLEMENU_FIRSTID) && (nCurId <= FONTSTYLEMENU_LASTID) ) + { + XubString aTempName = maCurStyle; + maCurStyle = GetItemText( nCurId ); + maHighlightHdl.Call( this ); + maCurStyle = aTempName; + } + else + PopupMenu::Highlight(); +} + +// ----------------------------------------------------------------------- + +BOOL FontStyleMenu::ImplIsAlreadyInserted( const XubString& rStyleName, USHORT nCount ) +{ + for ( USHORT i = 0; i < nCount; i++ ) + { + if ( GetItemText( i+FONTSTYLEMENU_FIRSTID ) == rStyleName ) + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void FontStyleMenu::Fill( const XubString& rName, const FontList* pList ) +{ + USHORT nItemId = GetItemId( 0 ); + while ( (nItemId >= FONTSTYLEMENU_FIRSTID) && + (nItemId <= FONTSTYLEMENU_LASTID) ) + { + RemoveItem( 0 ); + nItemId = GetItemId( 0 ); + } + + // Existiert ein Font mit diesem Namen + sal_Handle hFontInfo = pList->GetFirstFontInfo( rName ); + if ( hFontInfo ) + { + XubString aStyleText; + USHORT nPos = 0; + USHORT nId = FONTSTYLEMENU_FIRSTID; + FontWeight eLastWeight = WEIGHT_DONTKNOW; + FontItalic eLastItalic = ITALIC_NONE; + FontWidth eLastWidth = WIDTH_DONTKNOW; + BOOL bNormal = FALSE; + BOOL bItalic = FALSE; + BOOL bBold = FALSE; + BOOL bBoldItalic = FALSE; + BOOL bInsert = FALSE; + FontInfo aInfo; + while ( hFontInfo ) + { + aInfo = pList->GetFontInfo( hFontInfo ); + + FontWeight eWeight = aInfo.GetWeight(); + FontItalic eItalic = aInfo.GetItalic(); + FontWidth eWidth = aInfo.GetWidthType(); + // Only if the attributes are different, we insert the + // Font to avoid double Entries in different languages + if ( (eWeight != eLastWeight) || (eItalic != eLastItalic) || + (eWidth != eLastWidth) ) + { + if ( bInsert ) + { + InsertItem( nId, aStyleText, + MIB_RADIOCHECK | MIB_AUTOCHECK, nPos ); + nPos++; + nId++; + } + + if ( eWeight <= WEIGHT_NORMAL ) + { + if ( eItalic != ITALIC_NONE ) + bItalic = TRUE; + else + bNormal = TRUE; + } + else + { + if ( eItalic != ITALIC_NONE ) + bBoldItalic = TRUE; + else + bBold = TRUE; + } + + // For wrong StyleNames we replace this with the correct once + aStyleText = pList->GetStyleName( aInfo ); + bInsert = !ImplIsAlreadyInserted( aStyleText, nPos ); + if ( !bInsert ) + { + aStyleText = pList->GetStyleName( eWeight, eItalic ); + bInsert = !ImplIsAlreadyInserted( aStyleText, nPos ); + } + + eLastWeight = eWeight; + eLastItalic = eItalic; + eLastWidth = eWidth; + } + else + { + if ( bInsert ) + { + // If we have two names for the same attributes + // we prefer the translated standard names + const XubString& rAttrStyleText = pList->GetStyleName( eWeight, eItalic ); + if ( rAttrStyleText != aStyleText ) + { + XubString aTempStyleText = pList->GetStyleName( aInfo ); + if ( rAttrStyleText == aTempStyleText ) + aStyleText = rAttrStyleText; + bInsert = !ImplIsAlreadyInserted( aStyleText, nPos ); + } + } + } + + if ( !bItalic && (aStyleText == pList->GetItalicStr()) ) + bItalic = TRUE; + else if ( !bBold && (aStyleText == pList->GetBoldStr()) ) + bBold = TRUE; + else if ( !bBoldItalic && (aStyleText == pList->GetBoldItalicStr()) ) + bBoldItalic = TRUE; + + hFontInfo = pList->GetNextFontInfo( hFontInfo ); + } + + if ( bInsert ) + { + InsertItem( nId, aStyleText, + MIB_RADIOCHECK | MIB_AUTOCHECK, nPos ); + nPos++; + nId++; + } + + // Bestimmte Styles als Nachbildung + if ( bNormal ) + { + if ( !bItalic ) + { + InsertItem( nId, pList->GetItalicStr(), + MIB_RADIOCHECK | MIB_AUTOCHECK, nPos ); + nPos++; + nId++; + } + if ( !bBold ) + { + InsertItem( nId, pList->GetBoldStr(), + MIB_RADIOCHECK | MIB_AUTOCHECK, nPos ); + nPos++; + nId++; + } + } + if ( !bBoldItalic ) + { + if ( bNormal || bItalic || bBold ) + { + InsertItem( nId, pList->GetBoldItalicStr(), + MIB_RADIOCHECK | MIB_AUTOCHECK, nPos ); + nPos++; + nId++; + } + } + } + else + { + // Wenn Font nicht, dann Standard-Styles einfuegen + InsertItem( FONTSTYLEMENU_FIRSTID, pList->GetNormalStr(), + MIB_RADIOCHECK | MIB_AUTOCHECK, 0 ); + InsertItem( FONTSTYLEMENU_FIRSTID+1, pList->GetItalicStr(), + MIB_RADIOCHECK | MIB_AUTOCHECK, 0 ); + InsertItem( FONTSTYLEMENU_FIRSTID+2, pList->GetBoldStr(), + MIB_RADIOCHECK | MIB_AUTOCHECK, 0 ); + InsertItem( FONTSTYLEMENU_FIRSTID+3, pList->GetBoldItalicStr(), + MIB_RADIOCHECK | MIB_AUTOCHECK, 0 ); + } + + SetCurStyle( maCurStyle ); +} + +// ----------------------------------------------------------------------- + +void FontStyleMenu::SetCurStyle( const XubString& rStyle ) +{ + maCurStyle = rStyle; + + // Menueintrag checken + USHORT nChecked = 0; + USHORT nItemCount = GetItemCount(); + for( USHORT i = 0; i < nItemCount; i++ ) + { + USHORT nItemId = GetItemId( i ); + + if ( (nItemId < FONTSTYLEMENU_FIRSTID) || + (nItemId > FONTSTYLEMENU_LASTID) ) + break; + + if ( IsItemChecked( nItemId ) ) + nChecked = nItemId; + + XubString aText = GetItemText( nItemId ); + if ( aText == maCurStyle ) + { + CheckItem( nItemId, TRUE ); + return; + } + } + + if ( nChecked ) + CheckItem( nChecked, FALSE ); +} + +// ======================================================================== + +FontSizeMenu::FontSizeMenu() +: mpHeightAry( NULL ) +, mnCurHeight( 100 ) +{ + SetMenuFlags( GetMenuFlags() | MENU_FLAG_NOAUTOMNEMONICS ); +} + +// ----------------------------------------------------------------------- + +FontSizeMenu::~FontSizeMenu() +{ + if ( mpHeightAry ) + delete[] mpHeightAry; +} + +// ----------------------------------------------------------------------- + +void FontSizeMenu::Select() +{ + const USHORT nCurItemId = GetCurItemId(); + mnCurHeight = mpHeightAry[ nCurItemId - 1 ]; + maSelectHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void FontSizeMenu::Highlight() +{ + const long nTempHeight = mnCurHeight; + const USHORT nCurItemId = GetCurItemId(); + if ( !nCurItemId ) + mnCurHeight = 0; + else + { + //sal_Int32 nValue = GetItemText( nCurItemId ).ToInt32(); + mnCurHeight = mpHeightAry[ nCurItemId - 1 ]; + } + maHighlightHdl.Call( this ); + mnCurHeight = nTempHeight; +} + +// ----------------------------------------------------------------------- + +void FontSizeMenu::Fill( const FontInfo& rInfo, const FontList* pList ) +{ + Clear(); + + // setup font size array + if ( mpHeightAry ) + delete[] mpHeightAry; + + const long* pTempAry; + const long* pAry = pList->GetSizeAry( rInfo ); + USHORT nSizeCount = 0; + while ( pAry[nSizeCount] ) + nSizeCount++; + + USHORT nPos = 0; + + // first insert font size names (for simplified/traditional chinese) + FontSizeNames aFontSizeNames( Application::GetSettings().GetUILanguage() ); + mpHeightAry = new long[nSizeCount+aFontSizeNames.Count()]; + if ( !aFontSizeNames.IsEmpty() ) + { + if ( pAry == pList->GetStdSizeAry() ) + { + // for scalable fonts all font size names + ULONG nCount = aFontSizeNames.Count(); + for( ULONG i = 0; i < nCount; i++ ) + { + String aSizeName = aFontSizeNames.GetIndexName( i ); + long nSize = aFontSizeNames.GetIndexSize( i ); + mpHeightAry[nPos] = nSize; + nPos++; // Id is nPos+1 + InsertItem( nPos, aSizeName, MIB_RADIOCHECK | MIB_AUTOCHECK ); + } + } + else + { + // for fixed size fonts only selectable font size names + pTempAry = pAry; + while ( *pTempAry ) + { + String aSizeName = aFontSizeNames.Size2Name( *pTempAry ); + if ( aSizeName.Len() ) + { + mpHeightAry[nPos] = *pTempAry; + nPos++; // Id is nPos+1 + InsertItem( nPos, aSizeName, MIB_RADIOCHECK | MIB_AUTOCHECK ); + } + pTempAry++; + } + } + } + + // then insert numerical font size values + const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper(); + pTempAry = pAry; + while ( *pTempAry ) + { + mpHeightAry[nPos] = *pTempAry; + nPos++; // Id is nPos+1 + InsertItem( nPos, rI18nHelper.GetNum( *pTempAry, 1, TRUE, FALSE ), MIB_RADIOCHECK | MIB_AUTOCHECK ); + pTempAry++; + } + + SetCurHeight( mnCurHeight ); +} + +// ----------------------------------------------------------------------- + +void FontSizeMenu::SetCurHeight( long nHeight ) +{ + mnCurHeight = nHeight; + + // check menue item + XubString aHeight = Application::GetSettings().GetUILocaleI18nHelper().GetNum( nHeight, 1, TRUE, FALSE ); + USHORT nChecked = 0; + USHORT nItemCount = GetItemCount(); + for( USHORT i = 0; i < nItemCount; i++ ) + { + USHORT nItemId = GetItemId( i ); + + if ( mpHeightAry[i] == nHeight ) + { + CheckItem( nItemId, TRUE ); + return; + } + + if ( IsItemChecked( nItemId ) ) + nChecked = nItemId; + } + + if ( nChecked ) + CheckItem( nChecked, FALSE ); +} diff --git a/svtools/source/control/svxbox.cxx b/svtools/source/control/svxbox.cxx new file mode 100644 index 000000000000..d1ea47d110cd --- /dev/null +++ b/svtools/source/control/svxbox.cxx @@ -0,0 +1,617 @@ +/************************************************************************* + * + * 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_svtools.hxx" +#include <tools/debug.hxx> +#include <vcl/svapp.hxx> +#include <svtools/svxbox.hxx> +#include <unotools/charclass.hxx> + +// ----------------------------------------------------------------------- + +SV_IMPL_PTRARR(SvxEntryLst, SvxBoxEntry*) + +/*-------------------------------------------------------------------- + Beschreibung: Ein ListboxElement + --------------------------------------------------------------------*/ + +SvxBoxEntry::SvxBoxEntry() : + nId(LISTBOX_ENTRY_NOTFOUND), + bModified(FALSE), + bNew(FALSE) +{ +} + + +SvxBoxEntry::SvxBoxEntry(const String& aNam, USHORT nIdx) : + aName(aNam), + nId(nIdx), + bModified(FALSE), + bNew(FALSE) +{ +} + + +SvxBoxEntry::SvxBoxEntry(const SvxBoxEntry& rOld) : + aName(rOld.aName), + nId(rOld.nId), + bModified(rOld.bModified), + bNew(rOld.bNew) +{ +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +SvxListBox::SvxListBox(Window* pParent, WinBits nBits) : + ListBox(pParent, nBits) +{ + InitListBox(); +} + + +SvxListBox::SvxListBox(Window* pParent, const ResId& rId): + ListBox(pParent, rId) +{ + InitListBox(); +} + +/*-------------------------------------------------------------------- + Beschreibung: Basisklasse Dtor + --------------------------------------------------------------------*/ + +__EXPORT SvxListBox::~SvxListBox() +{ + aEntryLst.DeleteAndDestroy(0, aEntryLst.Count()); + aDelEntryLst.DeleteAndDestroy(0, aDelEntryLst.Count()); +} + +/*-------------------------------------------------------------------- + Beschreibung: Evtl. Liste aus der Ressource beachten + --------------------------------------------------------------------*/ + +void SvxListBox::InitListBox() +{ + // Verwaltung fuer die Stringlist aus der Resource aufbauen + USHORT nSize = GetEntryCount(); + for(USHORT i=0; i < nSize; ++i) + { const SvxBoxEntry* pTmp = new SvxBoxEntry(ListBox::GetEntry(i), i); + const SvxBoxEntry* &rpTmp = pTmp; + aEntryLst.Insert(rpTmp, aEntryLst.Count()); + } +} + +/*-------------------------------------------------------------------- + Beschreibung: neue Eintraege verwalten + --------------------------------------------------------------------*/ + +void SvxListBox::InsertNewEntry(const SvxBoxEntry& rEntry) +{ + SvxBoxEntry* pNew = new SvxBoxEntry(rEntry); + pNew->bNew = TRUE; + InsertSorted(pNew); +} + +/*-------------------------------------------------------------------- + Beschreibung: Eintrag in die ListBox aufnehmen + --------------------------------------------------------------------*/ + +void SvxListBox::InsertEntry(const SvxBoxEntry& rEntry, USHORT nPos) +{ + if(nPos != LISTBOX_ENTRY_NOTFOUND) + { + SvxBoxEntry* pEntry = new SvxBoxEntry(rEntry); + ListBox::InsertEntry(pEntry->aName, nPos); + //const SvxBoxEntry* &rpEntry = pEntry; + aEntryLst.C40_INSERT(SvxBoxEntry, pEntry, nPos); + } + else + InsertSorted(new SvxBoxEntry(rEntry)); +} + +/*-------------------------------------------------------------------- + Beschreibung: Eintrag aus der Liste loeschen + --------------------------------------------------------------------*/ + +void SvxListBox::RemoveEntry(USHORT nPos) +{ + if(nPos >= aEntryLst.Count()) + return; + + // Altes Element austragen + SvxBoxEntry* pEntry = aEntryLst[nPos]; + aEntryLst.Remove(nPos, 1); + ListBox::RemoveEntry(nPos); + + // keine neuen Eintraege in die Liste mit aufnehmen + if(pEntry->bNew) + return; + + // in DeleteListe eintragen + aDelEntryLst.C40_INSERT(SvxBoxEntry, pEntry, aDelEntryLst.Count()); +} + +/*-------------------------------------------------------------------- + Beschreibung: Eintrag ueber konkretes Obkjekt loeschen + --------------------------------------------------------------------*/ + +void SvxListBox::RemoveEntry(const SvxBoxEntry& rEntry) +{ + USHORT nPos = ListBox::GetEntryPos(rEntry.aName); + RemoveEntry(nPos); +} + +/*-------------------------------------------------------------------- + Beschreibung: Listen loeschen und Anzeige loeschen + --------------------------------------------------------------------*/ + +void SvxListBox::Clear() +{ + ListBox::Clear(); + aEntryLst.DeleteAndDestroy(0, aEntryLst.Count()); + aDelEntryLst.DeleteAndDestroy(0, aDelEntryLst.Count()); +} + +/*-------------------------------------------------------------------- + Beschreibung: Position by Name + --------------------------------------------------------------------*/ + +USHORT SvxListBox::GetEntryPos(const SvxBoxEntry& rEntry) const +{ + return ListBox::GetEntryPos(rEntry.aName); +} + +/*-------------------------------------------------------------------- + Beschreibung: Rund um die Entries + --------------------------------------------------------------------*/ + +const SvxBoxEntry& SvxListBox::GetSvxBoxEntry(USHORT nPos) const +{ + if(nPos < aEntryLst.Count()) + return *aEntryLst[nPos]; + else + return aDefault; +} + +/*-------------------------------------------------------------------- + Beschreibung: aktullen Eintrag zurueckgeben + --------------------------------------------------------------------*/ + +const SvxBoxEntry& SvxListBox::GetSelectSvxBoxEntry(USHORT nSelId) const +{ + String aName(ListBox::GetSelectEntry(nSelId)); + + if(aName.Len() > 0) + { + for (USHORT i=0; i < aEntryLst.Count(); i++) + { + if(aEntryLst[i]->aName == aName ) + return *aEntryLst[i]; + } + } + return aDefault; +} + +/*-------------------------------------------------------------------- + Beschreibung: modifizierte Eintraege + --------------------------------------------------------------------*/ + +USHORT SvxListBox::GetModifiedCount() const +{ + USHORT nMod = 0; + USHORT nSize = aEntryLst.Count(); + for(USHORT i=0; i < nSize; ++i) + { if(aEntryLst[i]->bModified) + nMod++; + } + return nMod; +} + +/*-------------------------------------------------------------------- + Beschreibung: Modifizierte Eintraege behandeln + --------------------------------------------------------------------*/ + +void SvxListBox::ModifyEntry(USHORT nPos, const String& rName) +{ + if(nPos >= aEntryLst.Count()) + return; + + SvxBoxEntry* pEntry = aEntryLst[nPos]; + aEntryLst.Remove(nPos, 1); + aEntryLst[nPos]->aName = rName; + aEntryLst[nPos]->bModified = TRUE; + ListBox::RemoveEntry(nPos); + + InsertSorted(pEntry); +} + +/*-------------------------------------------------------------------- + Beschreibung: alle modifizierten Eintraege bahandeln + --------------------------------------------------------------------*/ + +const SvxBoxEntry& SvxListBox::GetModifiedEntry(USHORT nPos) const +{ + USHORT nSize = aEntryLst.Count(); + USHORT nMod = 0; + for(USHORT i=0; i < nSize; ++i) + { if(aEntryLst[i]->bModified) + { if(nMod == nPos) + return *aEntryLst[i]; + nMod++; + } + } + return aDefault; +} + +/*-------------------------------------------------------------------- + Beschreibung: geloeschte Eintraege + --------------------------------------------------------------------*/ + +USHORT SvxListBox::GetRemovedCount() const +{ + return aDelEntryLst.Count(); +} + + +const SvxBoxEntry& SvxListBox::GetRemovedEntry(USHORT nPos) const +{ + if(nPos < aDelEntryLst.Count()) + return *aDelEntryLst[nPos]; + + return aDefault; +} + +/*-------------------------------------------------------------------- + Beschreibung: Neue Entries begutachten + --------------------------------------------------------------------*/ + +USHORT SvxListBox::GetNewCount() const +{ + USHORT nNew = 0; + USHORT nSize = aEntryLst.Count(); + for(USHORT i=0; i < nSize; ++i) + { if(aEntryLst[i]->bNew) + nNew++; + } + return nNew; +} + +/*-------------------------------------------------------------------- + Beschreibung: Alle neuen Eintraege ueberpruefen + --------------------------------------------------------------------*/ + +const SvxBoxEntry& SvxListBox::GetNewEntry(USHORT nPos) const +{ + USHORT nSize = aEntryLst.Count(); + USHORT nNew = 0; + for(USHORT i=0; i < nSize; ++i) + { if(aEntryLst[i]->bNew) + { if(nNew == nPos) + return *aEntryLst[i]; + nNew++; + } + } + return aDefault; +} + +/*-------------------------------------------------------------------- + Beschreibung: Sortiert einfuegen + --------------------------------------------------------------------*/ + +void SvxListBox::InsertSorted(SvxBoxEntry* pEntry) +{ + ListBox::InsertEntry(pEntry->aName); + USHORT nPos = ListBox::GetEntryPos(pEntry->aName); + aEntryLst.C40_INSERT(SvxBoxEntry, pEntry, nPos); +} + +/*-------------------------------------------------------------------- + Beschreibung: ComboBoxen mit Verwaltungseinheit + --------------------------------------------------------------------*/ + +SvxComboBox::SvxComboBox(Window* pParent, WinBits nBits, USHORT nStyleBits) : + ComboBox(pParent, nBits), + nStyle(nStyleBits) +{ + InitComboBox(); +} + + +SvxComboBox::SvxComboBox(Window* pParent, const ResId& rId, USHORT nStyleBits ): + ComboBox(pParent, rId), + nStyle(nStyleBits) +{ + InitComboBox(); +} + +/*-------------------------------------------------------------------- + Beschreibung: Basisklasse Dtor + --------------------------------------------------------------------*/ + +__EXPORT SvxComboBox::~SvxComboBox() +{ + aEntryLst.DeleteAndDestroy(0, aEntryLst.Count()); + aDelEntryLst.DeleteAndDestroy(0, aDelEntryLst.Count()); +} + +/*-------------------------------------------------------------------- + Beschreibung: Evtl. Liste aus der Ressource beachten + --------------------------------------------------------------------*/ + +void SvxComboBox::InitComboBox() +{ + // Verwaltung fuer die Stringlist aus der Resource aufbauen + USHORT nSize = GetEntryCount(); + for(USHORT i=0; i < nSize; ++i) + { const SvxBoxEntry* pTmp = new SvxBoxEntry(ComboBox::GetEntry(i), i); + const SvxBoxEntry* &rpTmp = pTmp; + aEntryLst.Insert(rpTmp, aEntryLst.Count()); + } +} + +/*-------------------------------------------------------------------- + Beschreibung: neue Eintraege verwalten + --------------------------------------------------------------------*/ + +void SvxComboBox::InsertNewEntry(const SvxBoxEntry& rEntry) +{ + SvxBoxEntry* pNew = new SvxBoxEntry(rEntry); + pNew->bNew = TRUE; + InsertSorted(pNew); +} + +/*-------------------------------------------------------------------- + Beschreibung: Eintrag in die ComboBox aufnehmen + --------------------------------------------------------------------*/ + +void SvxComboBox::InsertEntry(const SvxBoxEntry& rEntry) +{ + InsertSorted(new SvxBoxEntry(rEntry)); +} + +/*-------------------------------------------------------------------- + Beschreibung: Eintrag aus der Liste loeschen + --------------------------------------------------------------------*/ + +void SvxComboBox::RemoveEntry(USHORT nPos) +{ + if(nPos >= aEntryLst.Count()) + return; + + // Altes Element austragen + SvxBoxEntry* pEntry = aEntryLst[nPos]; + aEntryLst.Remove(nPos, 1); + ComboBox::RemoveEntry(nPos); + + // keine neuen Eintraege in die Liste mit aufnehmen + if(pEntry->bNew) + return; + + // in DeleteListe eintragen + aDelEntryLst.C40_INSERT(SvxBoxEntry, pEntry, aDelEntryLst.Count()); +} + +/*-------------------------------------------------------------------- + Beschreibung: Eintrag ueber konkretes Obkjekt loeschen + --------------------------------------------------------------------*/ + +void SvxComboBox::RemoveEntry(const SvxBoxEntry& rEntry) +{ + USHORT nPos = ComboBox::GetEntryPos(rEntry.aName); + RemoveEntry(nPos); +} + +/*-------------------------------------------------------------------- + Beschreibung: Listen loeschen und Anzeige loeschen + --------------------------------------------------------------------*/ + +void SvxComboBox::Clear() +{ + ComboBox::Clear(); + aEntryLst.DeleteAndDestroy(0, aEntryLst.Count()); + aDelEntryLst.DeleteAndDestroy(0, aDelEntryLst.Count()); +} + + +/*-------------------------------------------------------------------- + Beschreibung: Position by Name + --------------------------------------------------------------------*/ + +USHORT SvxComboBox::GetEntryPos(const SvxBoxEntry& rEntry) const +{ + return ComboBox::GetEntryPos(rEntry.aName); +} + +/*-------------------------------------------------------------------- + Beschreibung: Rund um die Entries + --------------------------------------------------------------------*/ + +const SvxBoxEntry& SvxComboBox::GetEntry(USHORT nPos) const +{ + if(nPos < aEntryLst.Count()) + return *aEntryLst[nPos]; + else + return aDefault; +} + +/*-------------------------------------------------------------------- + Beschreibung: modifizierte Eintraege + --------------------------------------------------------------------*/ + +USHORT SvxComboBox::GetModifiedCount() const +{ + USHORT nMod = 0; + USHORT nSize = aEntryLst.Count(); + for(USHORT i=0; i < nSize; ++i) + { if(aEntryLst[i]->bModified) + nMod++; + } + return nMod; +} + +/*-------------------------------------------------------------------- + Beschreibung: Modifizierte Eintraege behandeln + --------------------------------------------------------------------*/ + +void SvxComboBox::ModifyEntry(USHORT nPos, const String& rName) +{ + if(nPos >= aEntryLst.Count()) + return; + + SvxBoxEntry* pEntry = aEntryLst[nPos]; + aEntryLst.Remove(nPos, 1); + aEntryLst[nPos]->aName = rName; + aEntryLst[nPos]->bModified = TRUE; + ComboBox::RemoveEntry(nPos); + + InsertSorted(pEntry); +} + +/*-------------------------------------------------------------------- + Beschreibung: alle modifizierten Eintraege bahandeln + --------------------------------------------------------------------*/ + +const SvxBoxEntry& SvxComboBox::GetModifiedEntry(USHORT nPos) const +{ + USHORT nSize = aEntryLst.Count(); + USHORT nMod = 0; + for(USHORT i=0; i < nSize; ++i) + { if(aEntryLst[i]->bModified) + { if(nMod == nPos) + return *aEntryLst[i]; + nMod++; + } + } + return aDefault; +} + +/*-------------------------------------------------------------------- + Beschreibung: geloeschte Eintraege + --------------------------------------------------------------------*/ + +USHORT SvxComboBox::GetRemovedCount() const +{ + return aDelEntryLst.Count(); +} + + +const SvxBoxEntry& SvxComboBox::GetRemovedEntry(USHORT nPos) const +{ + if(nPos < aDelEntryLst.Count()) + return *aDelEntryLst[nPos]; + + return aDefault; +} + +/*-------------------------------------------------------------------- + Beschreibung: Neue Entries begutachten + --------------------------------------------------------------------*/ + +USHORT SvxComboBox::GetNewCount() const +{ + USHORT nNew = 0; + USHORT nSize = aEntryLst.Count(); + for(USHORT i=0; i < nSize; ++i) + { if(aEntryLst[i]->bNew) + nNew++; + } + return nNew; +} + +/*-------------------------------------------------------------------- + Beschreibung: Alle neuen Eintraege ueberpruefen + --------------------------------------------------------------------*/ + +const SvxBoxEntry& SvxComboBox::GetNewEntry(USHORT nPos) const +{ + USHORT nSize = aEntryLst.Count(); + USHORT nNew = 0; + for(USHORT i=0; i < nSize; ++i) + { if(aEntryLst[i]->bNew) + { if(nNew == nPos) + return *aEntryLst[i]; + nNew++; + } + } + return aDefault; +} + +/*-------------------------------------------------------------------- + Beschreibung: Sortiert einfuegen + --------------------------------------------------------------------*/ + +void SvxComboBox::InsertSorted(SvxBoxEntry* pEntry) +{ + ComboBox::InsertEntry(pEntry->aName); + USHORT nPos = ComboBox::GetEntryPos(pEntry->aName); + aEntryLst.C40_INSERT(SvxBoxEntry, pEntry, nPos); +} + + +/*-------------------------------------------------------------------- + Beschreibung: Je nach Option bestimmte Zeichen ausblenden + --------------------------------------------------------------------*/ + +void __EXPORT SvxComboBox::KeyInput( const KeyEvent& rKEvt ) +{ + sal_Unicode cChar = rKEvt.GetCharCode(); + + if(nStyle & SVX_CBS_FILENAME) + { +#if defined UNX + if( cChar == sal_Unicode( '/' ) || cChar == sal_Unicode( ' ' ) ) + return; +#else + if( cChar == sal_Unicode( ':' ) || cChar == sal_Unicode( '\\' ) || + cChar == sal_Unicode( '.' ) || cChar == sal_Unicode( ' ' ) ) + return; +#endif + } + ComboBox::KeyInput(rKEvt); +} + +/*-------------------------------------------------------------------- + Beschreibung: Text nach Option konvertieren + --------------------------------------------------------------------*/ + +String SvxComboBox::GetText() const +{ + String aTxt(ComboBox::GetText()); + CharClass aCharClass( Application::GetSettings().GetLocale() ); + + if(nStyle & SVX_CBS_LOWER) + return aCharClass.lower(aTxt); + + if(nStyle & SVX_CBS_UPPER) + return aCharClass.upper(aTxt); + + return aTxt; +} + + diff --git a/svtools/source/control/tabbar.cxx b/svtools/source/control/tabbar.cxx new file mode 100755 index 000000000000..0c2800246061 --- /dev/null +++ b/svtools/source/control/tabbar.cxx @@ -0,0 +1,2734 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#include <svtools/tabbar.hxx> +#include <tools/time.hxx> +#include <tools/debug.hxx> +#include <tools/poly.hxx> +#include <vcl/svapp.hxx> +#include <vcl/help.hxx> +#include <vcl/decoview.hxx> +#include <vcl/button.hxx> +#include <vcl/edit.hxx> +#include "svtaccessiblefactory.hxx" + +#include <limits> + +// ======================================================================= + +#define TABBAR_OFFSET_X 7 +#define TABBAR_OFFSET_X2 2 +#define TABBAR_DRAG_SCROLLOFF 5 +#define TABBAR_MINSIZE 5 + +const USHORT ADDNEWPAGE_AREAWIDTH = 10; + +// ======================================================================= + +struct ImplTabBarItem +{ + USHORT mnId; + TabBarPageBits mnBits; + XubString maText; + XubString maHelpText; + Rectangle maRect; + long mnWidth; + rtl::OString maHelpId; + BOOL mbShort; + BOOL mbSelect; + BOOL mbEnable; + Color maTabBgColor; + bool IsDefaultTabBgColor() const { return maTabBgColor == Color(COL_AUTO) ? TRUE : FALSE; }; + Color maTabTextColor; + bool IsDefaultTabTextColor() const { return maTabTextColor == Color(COL_AUTO) ? TRUE : FALSE; }; + + ImplTabBarItem( USHORT nItemId, const XubString& rText, + TabBarPageBits nPageBits ) : + maText( rText ) + { + mnId = nItemId; + mnBits = nPageBits; + mnWidth = 0; + mbShort = FALSE; + mbSelect = FALSE; + mbEnable = TRUE; + maTabBgColor = Color( COL_AUTO ); + maTabTextColor = Color( COL_AUTO ); + } +}; + +DECLARE_LIST( ImplTabBarList, ImplTabBarItem* ) + +// ======================================================================= + +// ----------------- +// - ImplTabButton - +// ----------------- + +class ImplTabButton : public PushButton +{ +public: + ImplTabButton( TabBar* pParent, WinBits nWinStyle = 0 ) : + PushButton( pParent, nWinStyle | WB_RECTSTYLE | WB_SMALLSTYLE | WB_NOLIGHTBORDER | WB_NOPOINTERFOCUS ) {} + + TabBar* GetParent() const { return (TabBar*)Window::GetParent(); } + + virtual long PreNotify( NotifyEvent& rNEvt ); +}; + +// ======================================================================= + +long ImplTabButton::PreNotify( NotifyEvent& rNEvt ) +{ + if ( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN ) + { + if ( GetParent()->IsInEditMode() ) + { + GetParent()->EndEditMode(); + return TRUE; + } + } + + return PushButton::PreNotify( rNEvt ); +} + +// ======================================================================= + +// ---------------- +// - ImplTabSizer - +// ---------------- + +class ImplTabSizer : public Window +{ +public: + ImplTabSizer( TabBar* pParent, WinBits nWinStyle = 0 ); + + TabBar* GetParent() const { return (TabBar*)Window::GetParent(); } + +private: + void ImplTrack( const Point& rScreenPos ); + + virtual void MouseButtonDown( const MouseEvent& rMEvt ); + virtual void Tracking( const TrackingEvent& rTEvt ); + virtual void Paint( const Rectangle& rRect ); + + Point maStartPos; + long mnStartWidth; +}; + +// ----------------------------------------------------------------------- + +ImplTabSizer::ImplTabSizer( TabBar* pParent, WinBits nWinStyle ) : + Window( pParent, nWinStyle & WB_3DLOOK ) +{ + SetPointer( Pointer( POINTER_HSIZEBAR ) ); + SetSizePixel( Size( 7, 0 ) ); +} + +// ----------------------------------------------------------------------- + +void ImplTabSizer::ImplTrack( const Point& rScreenPos ) +{ + TabBar* pParent = GetParent(); + long nDiff = rScreenPos.X() - maStartPos.X(); + pParent->mnSplitSize = mnStartWidth + (pParent->IsMirrored() ? -nDiff : nDiff); + if ( pParent->mnSplitSize < TABBAR_MINSIZE ) + pParent->mnSplitSize = TABBAR_MINSIZE; + pParent->Split(); + pParent->Update(); +} + +// ----------------------------------------------------------------------- + +void ImplTabSizer::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( GetParent()->IsInEditMode() ) + { + GetParent()->EndEditMode(); + return; + } + + if ( rMEvt.IsLeft() ) + { + maStartPos = OutputToScreenPixel( rMEvt.GetPosPixel() ); + mnStartWidth = GetParent()->GetSizePixel().Width(); + StartTracking(); + } +} + +// ----------------------------------------------------------------------- + +void ImplTabSizer::Tracking( const TrackingEvent& rTEvt ) +{ + if ( rTEvt.IsTrackingEnded() ) + { + if ( rTEvt.IsTrackingCanceled() ) + ImplTrack( maStartPos ); + GetParent()->mnSplitSize = 0; + } + else + ImplTrack( OutputToScreenPixel( rTEvt.GetMouseEvent().GetPosPixel() ) ); +} + +// ----------------------------------------------------------------------- + +void ImplTabSizer::Paint( const Rectangle& ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + DecorationView aDecoView( this ); + long nOffX = 0; + Size aOutputSize = GetOutputSizePixel(); + + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + { + SetLineColor( rStyleSettings.GetDarkShadowColor() ); + DrawLine( Point( 0, 0 ), Point( 0, aOutputSize.Height()-1 ) ); + nOffX++; + aOutputSize.Width()--; + } + aDecoView.DrawButton( Rectangle( Point( nOffX, 0 ), aOutputSize ), BUTTON_DRAW_NOLIGHTBORDER ); +} + +// ======================================================================= + +// Heisst nicht Impl, da evtl. mal von aussen benutz- und ueberladbar + +// -------------- +// - TabBarEdit - +// -------------- + +class TabBarEdit : public Edit +{ +private: + Timer maLoseFocusTimer; + BOOL mbPostEvt; + + DECL_LINK( ImplEndEditHdl, void* ); + DECL_LINK( ImplEndTimerHdl, void* ); + +public: + TabBarEdit( TabBar* pParent, WinBits nWinStyle = 0 ); + + TabBar* GetParent() const { return (TabBar*)Window::GetParent(); } + + void SetPostEvent() { mbPostEvt = TRUE; } + void ResetPostEvent() { mbPostEvt = FALSE; } + + virtual long PreNotify( NotifyEvent& rNEvt ); + virtual void LoseFocus(); +}; + +// ----------------------------------------------------------------------- + +TabBarEdit::TabBarEdit( TabBar* pParent, WinBits nWinStyle ) : + Edit( pParent, nWinStyle ) +{ + mbPostEvt = FALSE; +} + +// ----------------------------------------------------------------------- + +long TabBarEdit::PreNotify( NotifyEvent& rNEvt ) +{ + if ( rNEvt.GetType() == EVENT_KEYINPUT ) + { + const KeyEvent* pKEvt = rNEvt.GetKeyEvent(); + if ( !pKEvt->GetKeyCode().GetModifier() ) + { + if ( pKEvt->GetKeyCode().GetCode() == KEY_RETURN ) + { + if ( !mbPostEvt ) + { + if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), (void*)FALSE ) ) + mbPostEvt = TRUE; + } + return TRUE; + } + else if ( pKEvt->GetKeyCode().GetCode() == KEY_ESCAPE ) + { + if ( !mbPostEvt ) + { + if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), (void*)TRUE ) ) + mbPostEvt = TRUE; + } + return TRUE; + } + } + } + + return Edit::PreNotify( rNEvt ); +} + +// ----------------------------------------------------------------------- + +void TabBarEdit::LoseFocus() +{ + if ( !mbPostEvt ) + { + if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), (void*)FALSE ) ) + mbPostEvt = TRUE; + } + + Edit::LoseFocus(); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( TabBarEdit, ImplEndEditHdl, void*, pCancel ) +{ + ResetPostEvent(); + maLoseFocusTimer.Stop(); + + // We need this query, because the edit get a losefous event, + // when it shows the context menu or the insert symbol dialog + if ( !HasFocus() && HasChildPathFocus( TRUE ) ) + { + maLoseFocusTimer.SetTimeout( 30 ); + maLoseFocusTimer.SetTimeoutHdl( LINK( this, TabBarEdit, ImplEndTimerHdl ) ); + maLoseFocusTimer.Start(); + } + else + GetParent()->EndEditMode( pCancel != 0 ); + + return 0; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( TabBarEdit, ImplEndTimerHdl, void*, EMPTYARG ) +{ + if ( HasFocus() ) + return 0; + + // We need this query, because the edit get a losefous event, + // when it shows the context menu or the insert symbol dialog + if ( HasChildPathFocus( TRUE ) ) + maLoseFocusTimer.Start(); + else + GetParent()->EndEditMode( TRUE ); + + return 0; +} + +// ======================================================================= +struct TabBar_Impl +{ + ImplTabSizer* mpSizer; + ::svt::AccessibleFactoryAccess maAccessibleFactory; + + TabBar_Impl() + :mpSizer( NULL ) + { + } + ~TabBar_Impl() + { + delete mpSizer; + } +}; + +// ======================================================================= + +const sal_uInt16 TabBar::APPEND = ::std::numeric_limits<sal_uInt16>::max(); +const sal_uInt16 TabBar::PAGE_NOT_FOUND = ::std::numeric_limits<sal_uInt16>::max(); + +void TabBar::ImplInit( WinBits nWinStyle ) +{ + mpItemList = new ImplTabBarList; + mpFirstBtn = NULL; + mpPrevBtn = NULL; + mpNextBtn = NULL; + mpLastBtn = NULL; + mpImpl = new TabBar_Impl; + mpEdit = NULL; + mnMaxPageWidth = 0; + mnCurMaxWidth = 0; + mnOffX = 0; + mnOffY = 0; + mnLastOffX = 0; + mnSplitSize = 0; + mnSwitchTime = 0; + mnWinStyle = nWinStyle; + mnCurPageId = 0; + mnFirstPos = 0; + mnDropPos = 0; + mnSwitchId = 0; + mnEditId = 0; + mbFormat = TRUE; + mbFirstFormat = TRUE; + mbSizeFormat = TRUE; + mbAutoMaxWidth = TRUE; + mbInSwitching = FALSE; + mbAutoEditMode = FALSE; + mbEditCanceled = FALSE; + mbDropPos = FALSE; + mbInSelect = FALSE; + mbSelColor = FALSE; + mbSelTextColor = FALSE; + mbMirrored = FALSE; + + if ( nWinStyle & WB_3DTAB ) + mnOffY++; + + ImplInitControls(); + SetSizePixel( Size( 100, CalcWindowSizePixel().Height() ) ); + ImplInitSettings( TRUE, TRUE ); +} + +// ----------------------------------------------------------------------- + +TabBar::TabBar( Window* pParent, WinBits nWinStyle ) : + Window( pParent, (nWinStyle & WB_3DLOOK) | WB_CLIPCHILDREN ) +{ + ImplInit( nWinStyle ); +} + +// ----------------------------------------------------------------------- + +TabBar::~TabBar() +{ + EndEditMode( TRUE ); + + // Controls loeschen + if ( mpPrevBtn ) + delete mpPrevBtn; + if ( mpNextBtn ) + delete mpNextBtn; + if ( mpFirstBtn ) + delete mpFirstBtn; + if ( mpLastBtn ) + delete mpLastBtn; + delete mpImpl; + + // Alle Items loeschen + ImplTabBarItem* pItem = mpItemList->First(); + while ( pItem ) + { + delete pItem; + pItem = mpItemList->Next(); + } + + // Itemlist loeschen + delete mpItemList; +} + +// ----------------------------------------------------------------------- + +void TabBar::ImplInitSettings( BOOL bFont, BOOL bBackground ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + if ( bFont ) + { + Font aToolFont; + aToolFont = rStyleSettings.GetToolFont(); + if ( IsControlFont() ) + aToolFont.Merge( GetControlFont() ); + aToolFont.SetWeight( WEIGHT_BOLD ); + SetZoomedPointFont( aToolFont ); + + // Font in der groesse Anpassen, wenn Fenster zu klein? + while ( GetTextHeight() > (GetOutputSizePixel().Height()-1) ) + { + Font aFont = GetFont(); + if ( aFont.GetHeight() <= 6 ) + break; + aFont.SetHeight( aFont.GetHeight()-1 ); + SetFont( aFont ); + } + } + + if ( bBackground ) + { + Color aColor; + if ( IsControlBackground() ) + aColor = GetControlBackground(); + else + aColor = rStyleSettings.GetFaceColor(); + SetBackground( aColor ); + } +} + +// ----------------------------------------------------------------------- + +void TabBar::ImplGetColors( Color& rFaceColor, Color& rFaceTextColor, + Color& rSelectColor, Color& rSelectTextColor ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + if ( IsControlBackground() ) + rFaceColor = GetControlBackground(); + else + rFaceColor = rStyleSettings.GetInactiveTabColor(); + if ( IsControlForeground() ) + rFaceTextColor = GetControlForeground(); + else + rFaceTextColor = rStyleSettings.GetButtonTextColor(); + if ( mbSelColor ) + rSelectColor = maSelColor; + else + rSelectColor = rStyleSettings.GetActiveTabColor(); + if ( mbSelTextColor ) + rSelectTextColor = maSelTextColor; + else + rSelectTextColor = rStyleSettings.GetWindowTextColor(); + + // Bei 3D-Tabs wird Selektions- und Face-Farbe umgedreht, da die + // selektierten Tabs in 3D erscheinen sollen + if ( mnWinStyle & WB_3DTAB ) + { + Color aTempColor = rFaceColor; + rFaceColor = rSelectColor; + rSelectColor = aTempColor; + aTempColor = rFaceTextColor; + rFaceTextColor = rSelectTextColor; + rSelectTextColor = rFaceTextColor; + } +} + +// ----------------------------------------------------------------------- + +BOOL TabBar::ImplCalcWidth() +{ + // Groessen muessen nur ermittelt werden, wenn sich Text aendert oder + // wenn der Font geaendert wurde + if ( !mbSizeFormat ) + return FALSE; + + // Breiten der Tabs mit dem fetten Font ermitteln + Font aFont = GetFont(); + if ( aFont.GetWeight() != WEIGHT_BOLD ) + { + aFont.SetWeight( WEIGHT_BOLD ); + SetFont( aFont ); + } + + if ( mnMaxPageWidth ) + mnCurMaxWidth = mnMaxPageWidth; + else if ( mbAutoMaxWidth ) + { + mnCurMaxWidth = mnLastOffX-mnOffX- + TABBAR_OFFSET_X-TABBAR_OFFSET_X- + TABBAR_OFFSET_X2-TABBAR_OFFSET_X2-TABBAR_OFFSET_X2; + if ( mnCurMaxWidth < 1 ) + mnCurMaxWidth = 1; + } + else + mnCurMaxWidth = 0; + + BOOL bChanged = FALSE; + ImplTabBarItem* pItem = mpItemList->First(); + while ( pItem ) + { + long nNewWidth = GetTextWidth( pItem->maText ); + if ( mnCurMaxWidth && (nNewWidth > mnCurMaxWidth) ) + { + pItem->mbShort = TRUE; + nNewWidth = mnCurMaxWidth; + } + else + pItem->mbShort = FALSE; + nNewWidth += TABBAR_OFFSET_X+TABBAR_OFFSET_X2; + if ( pItem->mnWidth != nNewWidth ) + { + pItem->mnWidth = nNewWidth; + if ( !pItem->maRect.IsEmpty() ) + bChanged = TRUE; + } + pItem = mpItemList->Next(); + } + mbSizeFormat = FALSE; + mbFormat = TRUE; + return bChanged; +} + +// ----------------------------------------------------------------------- + +void TabBar::ImplFormat() +{ + ImplCalcWidth(); + + if ( !mbFormat ) + return; + + USHORT n = 0; + long x = mnOffX; + ImplTabBarItem* pItem = mpItemList->First(); + while ( pItem ) + { + // Bei allen nicht sichtbaren Tabs, wird ein leeres Rechteck + // gesetzt + if ( (n+1 < mnFirstPos) || (x > mnLastOffX) ) + pItem->maRect.SetEmpty(); + else + { + // Etwas von der Tab vor der ersten sichtbaren Page + // muss auch zu sehen sein + if ( n+1 == mnFirstPos ) + pItem->maRect.Left() = x-pItem->mnWidth; + else + { + pItem->maRect.Left() = x; + x += pItem->mnWidth; + } + pItem->maRect.Right() = x+TABBAR_OFFSET_X+TABBAR_OFFSET_X2; + pItem->maRect.Bottom() = maWinSize.Height()-1; + + if( mbMirrored ) + { + long nTmp = mnOffX + mnLastOffX - pItem->maRect.Right(); + pItem->maRect.Right() = mnOffX + mnLastOffX - pItem->maRect.Left(); + pItem->maRect.Left() = nTmp; + } + } + + n++; + pItem = mpItemList->Next(); + } + + mbFormat = FALSE; + + // Button enablen/disablen + ImplEnableControls(); +} + +// ----------------------------------------------------------------------- + +USHORT TabBar::ImplGetLastFirstPos() +{ + USHORT nCount = (USHORT)(mpItemList->Count()); + if ( !nCount || mbSizeFormat || mbFormat ) + return 0; + + USHORT nLastFirstPos = nCount-1; + long nWinWidth = mnLastOffX-mnOffX-TABBAR_OFFSET_X-ADDNEWPAGE_AREAWIDTH; + long nWidth = mpItemList->GetObject( nLastFirstPos )->mnWidth; + while ( nLastFirstPos && (nWidth < nWinWidth) ) + { + nLastFirstPos--; + nWidth += mpItemList->GetObject( nLastFirstPos )->mnWidth; + } + if ( (nLastFirstPos != (USHORT)(mpItemList->Count()-1)) && + (nWidth > nWinWidth) ) + nLastFirstPos++; + return nLastFirstPos; +} + +// ----------------------------------------------------------------------- + +void TabBar::ImplInitControls() +{ + if ( mnWinStyle & WB_SIZEABLE ) + { + if ( !mpImpl->mpSizer ) + mpImpl->mpSizer = new ImplTabSizer( this, mnWinStyle & (WB_DRAG | WB_3DLOOK) ); + mpImpl->mpSizer->Show(); + } + else + { + DELETEZ( mpImpl->mpSizer ); + } + + Link aLink = LINK( this, TabBar, ImplClickHdl ); + + if ( mnWinStyle & (WB_MINSCROLL | WB_SCROLL) ) + { + if ( !mpPrevBtn ) + { + mpPrevBtn = new ImplTabButton( this, WB_REPEAT ); + mpPrevBtn->SetClickHdl( aLink ); + } + mpPrevBtn->SetSymbol( mbMirrored ? SYMBOL_NEXT : SYMBOL_PREV ); + mpPrevBtn->Show(); + + if ( !mpNextBtn ) + { + mpNextBtn = new ImplTabButton( this, WB_REPEAT ); + mpNextBtn->SetClickHdl( aLink ); + } + mpNextBtn->SetSymbol( mbMirrored ? SYMBOL_PREV : SYMBOL_NEXT ); + mpNextBtn->Show(); + } + else + { + DELETEZ( mpPrevBtn ); + DELETEZ( mpNextBtn ); + } + + if ( mnWinStyle & WB_SCROLL ) + { + if ( !mpFirstBtn ) + { + mpFirstBtn = new ImplTabButton( this ); + mpFirstBtn->SetClickHdl( aLink ); + } + mpFirstBtn->SetSymbol( mbMirrored ? SYMBOL_LAST : SYMBOL_FIRST ); + mpFirstBtn->Show(); + + if ( !mpLastBtn ) + { + mpLastBtn = new ImplTabButton( this ); + mpLastBtn->SetClickHdl( aLink ); + } + mpLastBtn->SetSymbol( mbMirrored ? SYMBOL_FIRST : SYMBOL_LAST ); + mpLastBtn->Show(); + } + else + { + DELETEZ( mpFirstBtn ); + DELETEZ( mpLastBtn ); + } +} + +// ----------------------------------------------------------------------- + +void TabBar::ImplEnableControls() +{ + if ( mbSizeFormat || mbFormat ) + return; + + // Buttons enablen/disblen + BOOL bEnableBtn = mnFirstPos > 0; + if ( mpFirstBtn ) + mpFirstBtn->Enable( bEnableBtn ); + if ( mpPrevBtn ) + mpPrevBtn->Enable( bEnableBtn ); + + bEnableBtn = mnFirstPos < ImplGetLastFirstPos(); + if ( mpNextBtn ) + mpNextBtn->Enable( bEnableBtn ); + if ( mpLastBtn ) + mpLastBtn->Enable( bEnableBtn ); +} + +// ----------------------------------------------------------------------- + +void TabBar::ImplShowPage( USHORT nPos ) +{ + // Breite berechnen + long nWidth = GetOutputSizePixel().Width(); + if ( nWidth >= TABBAR_OFFSET_X ) + nWidth -= TABBAR_OFFSET_X; + ImplTabBarItem* pItem = mpItemList->GetObject( nPos ); + if ( nPos < mnFirstPos ) + SetFirstPageId( pItem->mnId ); + else if ( pItem->maRect.Right() > nWidth ) + { + while ( pItem->maRect.Right() > nWidth ) + { + USHORT nNewPos = mnFirstPos+1; + SetFirstPageId( GetPageId( nNewPos ) ); + ImplFormat(); + if ( nNewPos != mnFirstPos ) + break; + } + } +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( TabBar, ImplClickHdl, ImplTabButton*, pBtn ) +{ + EndEditMode(); + + USHORT nNewPos = mnFirstPos; + + if ( pBtn == mpFirstBtn ) + nNewPos = 0; + else if ( pBtn == mpPrevBtn ) + { + if ( mnFirstPos ) + nNewPos = mnFirstPos-1; + } + else if ( pBtn == mpNextBtn ) + { + USHORT nCount = GetPageCount(); + if ( mnFirstPos < nCount ) + nNewPos = mnFirstPos+1; + } + else + { + USHORT nCount = GetPageCount(); + if ( nCount ) + nNewPos = nCount-1; + } + + if ( nNewPos != mnFirstPos ) + SetFirstPageId( GetPageId( nNewPos ) ); + return 0; +} + +// ----------------------------------------------------------------------- + +void TabBar::MouseMove( const MouseEvent& rMEvt ) +{ + if ( rMEvt.IsLeaveWindow() ) + mbInSelect = FALSE; + + Window::MouseMove( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void TabBar::MouseButtonDown( const MouseEvent& rMEvt ) +{ + // Bei Klick in unser Fenster EditModus nur beenden und Klick nicht + // ausfuehren + if ( IsInEditMode() ) + { + EndEditMode(); + return; + } + + ImplTabBarItem* pItem; + USHORT nSelId = GetPageId( rMEvt.GetPosPixel() ); + + if ( !rMEvt.IsLeft() ) + { + Window::MouseButtonDown( rMEvt ); + if ( (nSelId > 0) && (nSelId != mnCurPageId) ) + { + USHORT nPos = GetPagePos( nSelId ); + pItem = mpItemList->GetObject( nPos ); + + if ( pItem->mbEnable ) + { + if ( ImplDeactivatePage() ) + { + SetCurPageId( nSelId ); + Update(); + ImplActivatePage(); + ImplSelect(); + } + mbInSelect = TRUE; + } + } + return; + } + + if ( rMEvt.IsMod2() && mbAutoEditMode && nSelId ) + { + if ( StartEditMode( nSelId ) ) + return; + } + + if ( (rMEvt.GetMode() & (MOUSE_MULTISELECT | MOUSE_RANGESELECT)) && (rMEvt.GetClicks() == 1) ) + { + if ( nSelId ) + { + USHORT nPos = GetPagePos( nSelId ); + BOOL bSelectTab = FALSE; + pItem = mpItemList->GetObject( nPos ); + + if ( pItem->mbEnable ) + { + if ( (rMEvt.GetMode() & MOUSE_MULTISELECT) && (mnWinStyle & WB_MULTISELECT) ) + { + if ( nSelId != mnCurPageId ) + { + SelectPage( nSelId, !IsPageSelected( nSelId ) ); + bSelectTab = TRUE; + } + } + else if ( mnWinStyle & (WB_MULTISELECT | WB_RANGESELECT) ) + { + bSelectTab = TRUE; + USHORT n; + BOOL bSelect; + USHORT nCurPos = GetPagePos( mnCurPageId ); + if ( nPos <= nCurPos ) + { + // Alle Tabs bis zur angeklickten Tab deselektieren + // und alle Tabs von der angeklickten Tab bis + // zur aktuellen Position selektieren + n = 0; + while ( n < nCurPos ) + { + pItem = mpItemList->GetObject( n ); + if ( n < nPos ) + bSelect = FALSE; + else + bSelect = TRUE; + + if ( pItem->mbSelect != bSelect ) + { + pItem->mbSelect = bSelect; + if ( !pItem->maRect.IsEmpty() ) + Invalidate( pItem->maRect ); + } + + n++; + } + } + + if ( nPos >= nCurPos ) + { + // Alle Tabs von der aktuellen bis zur angeklickten + // Tab selektieren und alle Tabs von der angeklickten + // Tab bis zur letzten Tab deselektieren + USHORT nCount = (USHORT)mpItemList->Count(); + n = nCurPos; + while ( n < nCount ) + { + pItem = mpItemList->GetObject( n ); + + if ( n <= nPos ) + bSelect = TRUE; + else + bSelect = FALSE; + + if ( pItem->mbSelect != bSelect ) + { + pItem->mbSelect = bSelect; + if ( !pItem->maRect.IsEmpty() ) + Invalidate( pItem->maRect ); + } + + n++; + } + } + } + + // Gegebenenfalls muss die selektierte Tab gescrollt werden + if ( bSelectTab ) + { + ImplShowPage( nPos ); + Update(); + ImplSelect(); + } + } + else + ImplShowPage( nPos ); + mbInSelect = TRUE; + + return; + } + } + else if ( rMEvt.GetClicks() == 2 ) + { + // Gegebenenfalls den Double-Click-Handler rufen + if ( !rMEvt.GetModifier() && (!nSelId || (nSelId == mnCurPageId)) ) + { + USHORT nOldCurId = mnCurPageId; + mnCurPageId = nSelId; + DoubleClick(); + // Abfrage, da im DoubleClick-Handler die aktuelle Seite + // umgeschaltet werden konnte + if ( mnCurPageId == nSelId ) + mnCurPageId = nOldCurId; + } + + return; + } + else + { + if ( nSelId ) + { + // Nur Select ausfuehren, wenn noch nicht aktuelle Page + if ( nSelId != mnCurPageId ) + { + USHORT nPos = GetPagePos( nSelId ); + pItem = mpItemList->GetObject( nPos ); + + if ( pItem->mbEnable ) + { + if ( !pItem->mbSelect ) + { + // Muss invalidiert werden + BOOL bUpdate = FALSE; + if ( IsReallyVisible() && IsUpdateMode() ) + bUpdate = TRUE; + + // Alle selektierten Items deselektieren + pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->mbSelect || (pItem->mnId == mnCurPageId) ) + { + pItem->mbSelect = FALSE; + if ( bUpdate ) + Invalidate( pItem->maRect ); + } + + pItem = mpItemList->Next(); + } + } + + if ( ImplDeactivatePage() ) + { + SetCurPageId( nSelId ); + Update(); + ImplActivatePage(); + ImplSelect(); + } + } + else + ImplShowPage( nPos ); + mbInSelect = TRUE; + } + + return; + } + } + + Window::MouseButtonDown( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void TabBar::MouseButtonUp( const MouseEvent& rMEvt ) +{ + mbInSelect = FALSE; + Window::MouseButtonUp( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void TabBar::Paint( const Rectangle& ) +{ + // Items berechnen und ausgeben + USHORT nItemCount = (USHORT)mpItemList->Count(); + ImplTabBarItem* pItem; + + // kein Item, dann auch nichts zu tun + if ( nItemCount ) + { + // TabBar muss formatiert sein + ImplFormat(); + + // Beim ersten Format auch dafuer sorgen, das aktuelle TabPage + // sichtbar wird + if ( mbFirstFormat ) + { + mbFirstFormat = FALSE; + + if ( mnCurPageId && (mnFirstPos == 0) && !mbDropPos ) + { + pItem = mpItemList->GetObject( GetPagePos( mnCurPageId ) ); + if ( pItem->maRect.IsEmpty() ) + { + // mbDropPos setzen (bzw. misbrauchen) um Invalidate() + // zu unterbinden + mbDropPos = TRUE; + SetFirstPageId( mnCurPageId ); + mbDropPos = FALSE; + if ( mnFirstPos != 0 ) + ImplFormat(); + } + } + } + } + + // Farben ermitteln + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Color aFaceColor; + Color aSelectColor; + Color aFaceTextColor; + Color aSelectTextColor; + ImplGetColors( aFaceColor, aFaceTextColor, aSelectColor, aSelectTextColor ); + + // Font selektieren + Font aFont = GetFont(); + Font aLightFont = aFont; + //aLightFont.SetWeight( WEIGHT_LIGHT ); //TODO Make font weight light on custom color only? + aLightFont.SetWeight( WEIGHT_NORMAL ); + + // #i36013# exclude push buttons from painting area + Rectangle aClipRect( Point( mnOffX, 0 ), Point( mnLastOffX, GetOutputHeightPixel() - 1 ) ); + SetClipRegion( Region( aClipRect ) ); + + // Bei Border oben und unten einen Strich extra malen + if ( (mnWinStyle & WB_BORDER) || (mnWinStyle & WB_TOPBORDER) ) + { + Size aOutputSize = GetOutputSizePixel(); + + // Bei 3D-Tabs wird auch der Border in 3D gemalt + if ( mnWinStyle & WB_3DTAB ) + { + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( Point( mnOffX, 0 ), Point( aOutputSize.Width(), 0 ) ); + } + + // Border malen (Strich oben und Strich unten) + SetLineColor( rStyleSettings.GetDarkShadowColor() ); + DrawLine( Point( mnOffX, mnOffY ), Point( aOutputSize.Width()-1, mnOffY ) ); + } + else + SetLineColor( rStyleSettings.GetDarkShadowColor() ); + + // Items ausgeben + if ( nItemCount ) + { + // letzten sichtbaren Eintrag suchen + USHORT n = mnFirstPos+1; + if ( n >= nItemCount ) + n = nItemCount-1; + pItem = mpItemList->Seek( n ); + while ( pItem ) + { + if ( !pItem->maRect.IsEmpty() ) + { + n++; + pItem = mpItemList->Next(); + } + else + break; + } + + // Alle Tabs ausgeben (von hinten nach vorn und aktuellen zuletzt) + if ( pItem ) + n--; + else if ( n >= nItemCount ) + n = nItemCount-1; + pItem = mpItemList->Seek( n ); + ImplTabBarItem* pCurItem = NULL; + while ( pItem ) + { + // CurrentItem als letztes ausgeben, da es alle anderen ueberdeckt + if ( !pCurItem && (pItem->mnId == mnCurPageId) ) + { + pCurItem = pItem; + pItem = mpItemList->Prev(); + if ( !pItem ) + pItem = pCurItem; + continue; + } + + if ( !pItem->maRect.IsEmpty() ) + { + Rectangle aRect = pItem->maRect; + + // Aktuelle Page wird mit einem fetten Font ausgegeben + if ( pItem->mnId == mnCurPageId ) + SetFont( aFont ); + else + SetFont( aLightFont ); + + // Je nach Status die richtige FillInBrush setzen + // Set the correct FillInBrush depending upon status + if ( pItem->mbSelect || (pItem->mnId == mnCurPageId) ) + { + // Currently selected Tab + SetFillColor( aSelectColor ); + SetTextColor( aSelectTextColor ); + } + else + { + if ( !pItem->IsDefaultTabBgColor() && !rStyleSettings.GetHighContrastMode() ) + { + SetFillColor( pItem->maTabBgColor ); + SetTextColor( pItem->maTabTextColor ); + } else { + SetFillColor( aFaceColor ); + SetTextColor( aFaceTextColor ); + } + } + + // Muss Font Kursiv geschaltet werden + if ( pItem->mnBits & TPB_SPECIAL ) + { + SetTextColor( Color( COL_LIGHTBLUE ) ); + } + + // Position der Page berechnen + Point aPos0 = Point( aRect.Left(), mnOffY ); + Point aPos1 = Point( aRect.Left()+TABBAR_OFFSET_X, aRect.Bottom() ); + Point aPos2 = Point( aRect.Right()-TABBAR_OFFSET_X, aRect.Bottom() ); + Point aPos3 = Point( aRect.Right(), mnOffY ); + + // Zuerst geben wir das Polygon gefuellt aus + Polygon aPoly( 4 ); + aPoly[0] = aPos0; + aPoly[1] = aPos1; + aPoly[2] = aPos2; + aPoly[3] = aPos3; + DrawPolygon( aPoly ); + + // Danach den Text zentiert ausgeben + XubString aText = pItem->maText; + if ( pItem->mbShort ) + aText = GetEllipsisString( aText, mnCurMaxWidth, TEXT_DRAW_ENDELLIPSIS ); + Size aRectSize = aRect.GetSize(); + long nTextWidth = GetTextWidth( aText ); + long nTextHeight = GetTextHeight(); + Point aTxtPos( aRect.Left()+(aRectSize.Width()-nTextWidth)/2, + (aRectSize.Height()-nTextHeight)/2 ); + if ( pItem->IsDefaultTabBgColor() || (!pItem->mbSelect) ) + { + if ( !pItem->mbEnable ) + DrawCtrlText( aTxtPos, aText, 0, STRING_LEN, (TEXT_DRAW_DISABLE | TEXT_DRAW_MNEMONIC) ); + else + DrawText( aTxtPos, aText ); + } + // Jetzt im Inhalt den 3D-Effekt ausgeben + aPos0.X()++; + aPos1.X()++; + aPos2.X()--; + aPos3.X()--; + + // If this is the current tab, draw the left inner shadow the default color, + // otherwise make it the same as the custom background color + if ( pItem->mbSelect || (pItem->mnId == mnCurPageId) ) { + SetLineColor( rStyleSettings.GetLightColor() ); + } else { + if ( !pItem->IsDefaultTabBgColor() && ! rStyleSettings.GetHighContrastMode() ) + { + SetLineColor( pItem->maTabBgColor ); + } else { + SetLineColor( rStyleSettings.GetLightColor() ); + } + } + // Draw the left side of the tab + DrawLine( aPos0, aPos1 ); + + if ( !pItem->mbSelect && (pItem->mnId != mnCurPageId) ) + { + // Draw the top inner shadow + // ToDo: Change from this static color to tab custom bg color + DrawLine( Point( aPos0.X(), aPos0.Y()+1 ), + Point( aPos3.X(), aPos3.Y()+1 ) ); + } + + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( aPos2, aPos3 ); + aPos1.X()--; + aPos1.Y()--; + aPos2.Y()--; + if ( !pItem->IsDefaultTabBgColor() && ( pItem->mbSelect || (pItem->mnId == mnCurPageId) ) ) + { + SetLineColor( pItem->maTabBgColor ); + DrawLine( Point(aPos1.X()-1, aPos1.Y()-1), Point(aPos2.X(), aPos2.Y()-1) ); + } + DrawLine( aPos1, aPos2 ); + + // draw a small 2px sliver of the original background color at the bottom of the selected tab + + if ( !pItem->IsDefaultTabBgColor() ) + { + if ( pItem->mbSelect || (pItem->mnId == mnCurPageId) || rStyleSettings.GetHighContrastMode() ) { + SetLineColor( pItem->maTabBgColor ); + DrawLine( Point(aPos1.X()-1, aPos1.Y()-1), Point(aPos2.X(), aPos2.Y()-1) ); + if ( !pItem->mbEnable ) + DrawCtrlText( aTxtPos, aText, 0, STRING_LEN, (TEXT_DRAW_DISABLE | TEXT_DRAW_MNEMONIC) ); + else + DrawText( aTxtPos, aText ); + } + } + + // Da etwas uebermalt werden konnte, muessen wir die Polygon- + // umrandung nocheinmal ausgeben + SetLineColor( rStyleSettings.GetDarkShadowColor() ); + SetFillColor(); + DrawPolygon( aPoly ); + + // Beim dem aktuellen Tab die restlichten Ausgaben vornehmen und + // die Schleife abbrechen, da die aktuelle Tab als letztes + // ausgegeben wird + if ( pItem == pCurItem ) + { + // Beim aktuellen Item muss der oberstes Strich geloescht + // werden + SetLineColor(); + SetFillColor( aSelectColor ); + Rectangle aDelRect( aPos0, aPos3 ); + DrawRect( aDelRect ); + if ( mnWinStyle & WB_3DTAB ) + { + aDelRect.Top()--; + DrawRect( aDelRect ); + } + + break; + } + + pItem = mpItemList->Prev(); + } + else + { + if ( pItem == pCurItem ) + break; + + pItem = NULL; + } + + if ( !pItem ) + pItem = pCurItem; + } + } + + // Font wieder herstellen + SetFont( aFont ); + // remove clip region + SetClipRegion(); +} + +// ----------------------------------------------------------------------- + +void TabBar::Resize() +{ + Size aNewSize = GetOutputSizePixel(); + + long nSizerWidth = 0; + long nButtonWidth = 0; + + // Sizer anordnen + if ( mpImpl->mpSizer ) + { + Size aSizerSize = mpImpl->mpSizer->GetSizePixel(); + Point aNewSizerPos( mbMirrored ? 0 : (aNewSize.Width()-aSizerSize.Width()), 0 ); + Size aNewSizerSize( aSizerSize.Width(), aNewSize.Height() ); + mpImpl->mpSizer->SetPosSizePixel( aNewSizerPos, aNewSizerSize ); + nSizerWidth = aSizerSize.Width(); + } + + // Scroll-Buttons anordnen + long nHeight = aNewSize.Height(); + // Font in der groesse Anpassen? + ImplInitSettings( TRUE, FALSE ); + + long nX = mbMirrored ? (aNewSize.Width()-nHeight) : 0; + long nXDiff = mbMirrored ? -nHeight : nHeight; + + Size aBtnSize( nHeight, nHeight ); + if ( mpFirstBtn ) + { + mpFirstBtn->SetPosSizePixel( Point( nX, 0 ), aBtnSize ); + nX += nXDiff; + nButtonWidth += nHeight; + } + if ( mpPrevBtn ) + { + mpPrevBtn->SetPosSizePixel( Point( nX, 0 ), aBtnSize ); + nX += nXDiff; + nButtonWidth += nHeight; + } + if ( mpNextBtn ) + { + mpNextBtn->SetPosSizePixel( Point( nX, 0 ), aBtnSize ); + nX += nXDiff; + nButtonWidth += nHeight; + } + if ( mpLastBtn ) + { + mpLastBtn->SetPosSizePixel( Point( nX, 0 ), aBtnSize ); + nX += nXDiff; + nButtonWidth += nHeight; + } + + // Groesse merken + maWinSize = aNewSize; + + if( mbMirrored ) + { + mnOffX = nSizerWidth; + mnLastOffX = maWinSize.Width() - nButtonWidth - 1; + } + else + { + mnOffX = nButtonWidth; + mnLastOffX = maWinSize.Width() - nSizerWidth - 1; + } + + // Neu formatieren + mbSizeFormat = TRUE; + if ( IsReallyVisible() ) + { + if ( ImplCalcWidth() ) + Invalidate(); + ImplFormat(); + } + + // Button enablen/disablen + ImplEnableControls(); +} + +// ----------------------------------------------------------------------- + +void TabBar::RequestHelp( const HelpEvent& rHEvt ) +{ + USHORT nItemId = GetPageId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) ); + if ( nItemId ) + { + if ( rHEvt.GetMode() & HELPMODE_BALLOON ) + { + XubString aStr = GetHelpText( nItemId ); + if ( aStr.Len() ) + { + Rectangle aItemRect = GetPageRect( nItemId ); + Point aPt = OutputToScreenPixel( aItemRect.TopLeft() ); + aItemRect.Left() = aPt.X(); + aItemRect.Top() = aPt.Y(); + aPt = OutputToScreenPixel( aItemRect.BottomRight() ); + aItemRect.Right() = aPt.X(); + aItemRect.Bottom() = aPt.Y(); + Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr ); + return; + } + } + else if ( rHEvt.GetMode() & HELPMODE_EXTENDED ) + { + rtl::OUString aHelpId( rtl::OStringToOUString( GetHelpId( nItemId ), RTL_TEXTENCODING_UTF8 ) ); + if ( aHelpId.getLength() ) + { + // Wenn eine Hilfe existiert, dann ausloesen + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + pHelp->Start( aHelpId, this ); + return; + } + } + + // Bei Quick- oder Ballloon-Help zeigen wir den Text an, + // wenn dieser abgeschnitten oder nicht voll sichtbar ist + if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) ) + { + USHORT nPos = GetPagePos( nItemId ); + ImplTabBarItem* pItem = mpItemList->GetObject( nPos ); + if ( pItem->mbShort || + (pItem->maRect.Right()-TABBAR_OFFSET_X-5 > mnLastOffX) ) + { + Rectangle aItemRect = GetPageRect( nItemId ); + Point aPt = OutputToScreenPixel( aItemRect.TopLeft() ); + aItemRect.Left() = aPt.X(); + aItemRect.Top() = aPt.Y(); + aPt = OutputToScreenPixel( aItemRect.BottomRight() ); + aItemRect.Right() = aPt.X(); + aItemRect.Bottom() = aPt.Y(); + XubString aStr = mpItemList->GetObject( nPos )->maText; + if ( aStr.Len() ) + { + if ( rHEvt.GetMode() & HELPMODE_BALLOON ) + Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr ); + else + Help::ShowQuickHelp( this, aItemRect, aStr ); + return; + } + } + } + } + + Window::RequestHelp( rHEvt ); +} + +// ----------------------------------------------------------------------- + +void TabBar::StateChanged( StateChangedType nType ) +{ + Window::StateChanged( nType ); + + if ( nType == STATE_CHANGE_INITSHOW ) + { + if ( (mbSizeFormat || mbFormat) && mpItemList->Count() ) + ImplFormat(); + } + else if ( (nType == STATE_CHANGE_ZOOM) || + (nType == STATE_CHANGE_CONTROLFONT) ) + { + ImplInitSettings( TRUE, FALSE ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLFOREGROUND ) + Invalidate(); + else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings( FALSE, TRUE ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_MIRRORING ) + { + // reacts on calls of EnableRTL, have to mirror all child controls + if( mpFirstBtn ) mpFirstBtn->EnableRTL( IsRTLEnabled() ); + if( mpPrevBtn ) mpPrevBtn->EnableRTL( IsRTLEnabled() ); + if( mpNextBtn ) mpNextBtn->EnableRTL( IsRTLEnabled() ); + if( mpLastBtn ) mpLastBtn->EnableRTL( IsRTLEnabled() ); + if( mpImpl->mpSizer ) mpImpl->mpSizer->EnableRTL( IsRTLEnabled() ); + if( mpEdit ) mpEdit->EnableRTL( IsRTLEnabled() ); + } +} + +// ----------------------------------------------------------------------- + +void TabBar::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + ImplInitSettings( TRUE, TRUE ); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void TabBar::ImplSelect() +{ + Select(); + + CallEventListeners( VCLEVENT_TABBAR_PAGESELECTED, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(mnCurPageId)) ); +} + +// ----------------------------------------------------------------------- + +void TabBar::Select() +{ + maSelectHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void TabBar::DoubleClick() +{ + maDoubleClickHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void TabBar::Split() +{ + maSplitHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void TabBar::ImplActivatePage() +{ + ActivatePage(); + + CallEventListeners( VCLEVENT_TABBAR_PAGEACTIVATED, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(mnCurPageId)) ); +} + +// ----------------------------------------------------------------------- + +void TabBar::ActivatePage() +{ + maActivatePageHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +long TabBar::ImplDeactivatePage() +{ + long nRet = DeactivatePage(); + + CallEventListeners( VCLEVENT_TABBAR_PAGEDEACTIVATED, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(mnCurPageId)) ); + + return nRet; +} + +// ----------------------------------------------------------------------- + +long TabBar::DeactivatePage() +{ + if ( maDeactivatePageHdl.IsSet() ) + return maDeactivatePageHdl.Call( this ); + else + return TRUE; +} + +// ----------------------------------------------------------------------- + +long TabBar::StartRenaming() +{ + if ( maStartRenamingHdl.IsSet() ) + return maStartRenamingHdl.Call( this ); + else + return TRUE; +} + +// ----------------------------------------------------------------------- + +long TabBar::AllowRenaming() +{ + if ( maAllowRenamingHdl.IsSet() ) + return maAllowRenamingHdl.Call( this ); + else + return TRUE; +} + +// ----------------------------------------------------------------------- + +void TabBar::EndRenaming() +{ + maEndRenamingHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void TabBar::Mirror() +{ + +} + +// ----------------------------------------------------------------------- + +void TabBar::InsertPage( USHORT nPageId, const XubString& rText, + TabBarPageBits nBits, USHORT nPos ) +{ + DBG_ASSERT( nPageId, "TabBar::InsertPage(): PageId == 0" ); + DBG_ASSERT( GetPagePos( nPageId ) == PAGE_NOT_FOUND, + "TabBar::InsertPage(): PageId already exists" ); + DBG_ASSERT( nBits <= TPB_SPECIAL, "TabBar::InsertPage(): nBits is wrong" ); + + // PageItem anlegen und in die Item-Liste eintragen + ImplTabBarItem* pItem = new ImplTabBarItem( nPageId, rText, nBits ); + mpItemList->Insert( pItem, nPos ); + mbSizeFormat = TRUE; + + // CurPageId gegebenenfalls setzen + if ( !mnCurPageId ) + mnCurPageId = nPageId; + + // Leiste neu ausgeben + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + + CallEventListeners( VCLEVENT_TABBAR_PAGEINSERTED, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(nPageId)) ); +} + +// ----------------------------------------------------------------------- + +Color TabBar::GetTabBgColor( USHORT nPageId ) const +{ + USHORT nPos = GetPagePos( nPageId ); + + if ( nPos != PAGE_NOT_FOUND ) + return mpItemList->GetObject( nPos )->maTabBgColor; + else + return Color( COL_AUTO ); +} + +void TabBar::SetTabBgColor( USHORT nPageId, const Color& aTabBgColor ) +{ + USHORT nPos = GetPagePos( nPageId ); + ImplTabBarItem* pItem; + if ( nPos != PAGE_NOT_FOUND ) + { + pItem = mpItemList->GetObject( nPos ); + if ( aTabBgColor != Color( COL_AUTO ) ) + { + pItem->maTabBgColor = aTabBgColor; + if ( aTabBgColor.GetLuminance() <= 128 ) //Do not use aTabBgColor.IsDark(), because that threshold is way too low... + pItem->maTabTextColor = Color( COL_WHITE ); + else + pItem->maTabTextColor = Color( COL_BLACK ); + } + else + { + pItem->maTabBgColor = Color( COL_AUTO ); + pItem->maTabTextColor = Color( COL_AUTO ); + } + } +} + +// ----------------------------------------------------------------------- + +void TabBar::RemovePage( USHORT nPageId ) +{ + USHORT nPos = GetPagePos( nPageId ); + + // Existiert Item + if ( nPos != PAGE_NOT_FOUND ) + { + if ( mnCurPageId == nPageId ) + mnCurPageId = 0; + + // Testen, ob erste sichtbare Seite verschoben werden muss + if ( mnFirstPos > nPos ) + mnFirstPos--; + + // Item-Daten loeschen + delete mpItemList->Remove( nPos ); + mbFormat = TRUE; + + // Leiste neu ausgeben + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + + CallEventListeners( VCLEVENT_TABBAR_PAGEREMOVED, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(nPageId)) ); + } +} + +// ----------------------------------------------------------------------- + +void TabBar::MovePage( USHORT nPageId, USHORT nNewPos ) +{ + USHORT nPos = GetPagePos( nPageId ); + Pair aPair( nPos, nNewPos ); + + if ( nPos < nNewPos ) + nNewPos--; + + if ( nPos == nNewPos ) + return; + + // Existiert Item + if ( nPos != PAGE_NOT_FOUND ) + { + // TabBar-Item in der Liste verschieben + ImplTabBarItem* pItem = mpItemList->Remove( nPos ); + mpItemList->Insert( pItem, nNewPos ); + mbFormat = TRUE; + + // Leiste neu ausgeben + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + + CallEventListeners( VCLEVENT_TABBAR_PAGEMOVED, (void*) &aPair ); + } +} + +// ----------------------------------------------------------------------- + +void TabBar::Clear() +{ + // Alle Items loeschen + ImplTabBarItem* pItem = mpItemList->First(); + while ( pItem ) + { + // Item-Daten loeschen + delete pItem; + pItem = mpItemList->Next(); + } + + // Items aus der Liste loeschen + mpItemList->Clear(); + mbSizeFormat = TRUE; + mnCurPageId = 0; + mnFirstPos = 0; + + // Leiste neu ausgeben + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + + CallEventListeners( VCLEVENT_TABBAR_PAGEREMOVED, (void*) PAGE_NOT_FOUND ); +} + +// ----------------------------------------------------------------------- + +void TabBar::EnablePage( USHORT nPageId, BOOL bEnable ) +{ + USHORT nPos = GetPagePos( nPageId ); + + if ( nPos != PAGE_NOT_FOUND ) + { + ImplTabBarItem* pItem = mpItemList->GetObject( nPos ); + + if ( pItem->mbEnable != bEnable ) + { + pItem->mbEnable = bEnable; + + // Leiste neu ausgeben + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate( pItem->maRect ); + + CallEventListeners( bEnable ? VCLEVENT_TABBAR_PAGEENABLED : VCLEVENT_TABBAR_PAGEDISABLED, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(nPageId)) ); + } + } +} + +// ----------------------------------------------------------------------- + +BOOL TabBar::IsPageEnabled( USHORT nPageId ) const +{ + USHORT nPos = GetPagePos( nPageId ); + + if ( nPos != PAGE_NOT_FOUND ) + return mpItemList->GetObject( nPos )->mbEnable; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void TabBar::SetPageBits( USHORT nPageId, TabBarPageBits nBits ) +{ + USHORT nPos = GetPagePos( nPageId ); + + if ( nPos != PAGE_NOT_FOUND ) + { + ImplTabBarItem* pItem = mpItemList->GetObject( nPos ); + + if ( pItem->mnBits != nBits ) + { + pItem->mnBits = nBits; + + // Leiste neu ausgeben + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate( pItem->maRect ); + } + } +} + +// ----------------------------------------------------------------------- + +TabBarPageBits TabBar::GetPageBits( USHORT nPageId ) const +{ + USHORT nPos = GetPagePos( nPageId ); + + if ( nPos != PAGE_NOT_FOUND ) + return mpItemList->GetObject( nPos )->mnBits; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +USHORT TabBar::GetPageCount() const +{ + return (USHORT)mpItemList->Count(); +} + +// ----------------------------------------------------------------------- + +USHORT TabBar::GetPageId( USHORT nPos ) const +{ + ImplTabBarItem* pItem = mpItemList->GetObject( nPos ); + if ( pItem ) + return pItem->mnId; + else + return 0; +} + +// ----------------------------------------------------------------------- + +USHORT TabBar::GetPagePos( USHORT nPageId ) const +{ + ImplTabBarItem* pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->mnId == nPageId ) + return (USHORT)mpItemList->GetCurPos(); + + pItem = mpItemList->Next(); + } + + return PAGE_NOT_FOUND; +} + +// ----------------------------------------------------------------------- + +USHORT TabBar::GetPageId( const Point& rPos ) const +{ + ImplTabBarItem* pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->maRect.IsInside( rPos ) ) + return pItem->mnId; + + pItem = mpItemList->Next(); + } + + return 0; +} + +// ----------------------------------------------------------------------- + +Rectangle TabBar::GetPageRect( USHORT nPageId ) const +{ + USHORT nPos = GetPagePos( nPageId ); + + if ( nPos != PAGE_NOT_FOUND ) + return mpItemList->GetObject( nPos )->maRect; + else + return Rectangle(); +} + +// ----------------------------------------------------------------------- + +void TabBar::SetCurPageId( USHORT nPageId ) +{ + USHORT nPos = GetPagePos( nPageId ); + + // Wenn Item nicht existiert, dann nichts machen + if ( nPos != PAGE_NOT_FOUND ) + { + // Wenn sich aktuelle Page nicht geaendert hat, dann muessen wir + // jetzt nichts mehr machen + if ( nPageId == mnCurPageId ) + return; + + // Muss invalidiert werden + BOOL bUpdate = FALSE; + if ( IsReallyVisible() && IsUpdateMode() ) + bUpdate = TRUE; + + ImplTabBarItem* pItem = mpItemList->GetObject( nPos ); + ImplTabBarItem* pOldItem; + + if ( mnCurPageId ) + pOldItem = mpItemList->GetObject( GetPagePos( mnCurPageId ) ); + else + pOldItem = NULL; + + // Wenn Page nicht selektiert, dann vorher selektierte Seite + // deselktieren, wenn dies die einzige selektierte Seite ist + if ( !pItem->mbSelect && pOldItem ) + { + USHORT nSelPageCount = GetSelectPageCount(); + if ( nSelPageCount == 1 ) + pOldItem->mbSelect = FALSE; + pItem->mbSelect = TRUE; + } + + mnCurPageId = nPageId; + mbFormat = TRUE; + + // Dafuer sorgen, das aktuelle Page sichtbar wird + if ( IsReallyVisible() ) + { + if ( nPos < mnFirstPos ) + SetFirstPageId( nPageId ); + else + { + // sichtbare Breite berechnen + long nWidth = mnLastOffX; + if ( nWidth > TABBAR_OFFSET_X ) + nWidth -= TABBAR_OFFSET_X; + if ( nWidth > ADDNEWPAGE_AREAWIDTH ) + nWidth -= ADDNEWPAGE_AREAWIDTH; + + if ( pItem->maRect.IsEmpty() ) + ImplFormat(); + + while ( (mbMirrored ? (pItem->maRect.Left() < mnOffX) : (pItem->maRect.Right() > nWidth)) || + pItem->maRect.IsEmpty() ) + { + USHORT nNewPos = mnFirstPos+1; + // Dafuer sorgen, das min. die aktuelle TabPages als + // erste TabPage sichtbar ist + if ( nNewPos >= nPos ) + { + SetFirstPageId( nPageId ); + break; + } + else + SetFirstPageId( GetPageId( nNewPos ) ); + ImplFormat(); + // Falls erste Seite nicht weitergeschaltet wird, dann + // koennen wir abbrechen + if ( nNewPos != mnFirstPos ) + break; + } + } + } + + // Leiste neu ausgeben + if ( bUpdate ) + { + Invalidate( pItem->maRect ); + if ( pOldItem ) + Invalidate( pOldItem->maRect ); + } + } +} + +// ----------------------------------------------------------------------- + +void TabBar::MakeVisible( USHORT nPageId ) +{ + if ( !IsReallyVisible() ) + return; + + USHORT nPos = GetPagePos( nPageId ); + + // Wenn Item nicht existiert, dann nichts machen + if ( nPos != PAGE_NOT_FOUND ) + { + if ( nPos < mnFirstPos ) + SetFirstPageId( nPageId ); + else + { + ImplTabBarItem* pItem = mpItemList->GetObject( nPos ); + + // sichtbare Breite berechnen + long nWidth = mnLastOffX; + if ( nWidth > TABBAR_OFFSET_X ) + nWidth -= TABBAR_OFFSET_X; + + if ( mbFormat || pItem->maRect.IsEmpty() ) + { + mbFormat = TRUE; + ImplFormat(); + } + + while ( (pItem->maRect.Right() > nWidth) || + pItem->maRect.IsEmpty() ) + { + USHORT nNewPos = mnFirstPos+1; + // Dafuer sorgen, das min. die aktuelle TabPages als + // erste TabPage sichtbar ist + if ( nNewPos >= nPos ) + { + SetFirstPageId( nPageId ); + break; + } + else + SetFirstPageId( GetPageId( nNewPos ) ); + ImplFormat(); + // Falls erste Seite nicht weitergeschaltet wird, dann + // koennen wir abbrechen + if ( nNewPos != mnFirstPos ) + break; + } + } + } +} + +// ----------------------------------------------------------------------- + +void TabBar::SetFirstPageId( USHORT nPageId ) +{ + USHORT nPos = GetPagePos( nPageId ); + + // Wenn Item nicht existiert, dann FALSE zurueckgeben + if ( nPos != PAGE_NOT_FOUND ) + { + if ( nPos != mnFirstPos ) + { + // Dafuer sorgen, das nach Moeglichkteit soviele Pages wie + // moeglich sichtbar sind + ImplFormat(); + USHORT nLastFirstPos = ImplGetLastFirstPos(); + USHORT nNewPos; + if ( nPos > nLastFirstPos ) + nNewPos = nLastFirstPos; + else + nNewPos = nPos; + + if ( nNewPos != mnFirstPos ) + { + mnFirstPos = nNewPos; + mbFormat = TRUE; + + // Leiste neu ausgeben (Achtung: mbDropPos beachten, da wenn + // dieses Flag gesetzt ist, wird direkt gepaintet) + if ( IsReallyVisible() && IsUpdateMode() && !mbDropPos ) + Invalidate(); + } + } + } +} + +// ----------------------------------------------------------------------- + +void TabBar::SelectPage( USHORT nPageId, BOOL bSelect ) +{ + USHORT nPos = GetPagePos( nPageId ); + + if ( nPos != PAGE_NOT_FOUND ) + { + ImplTabBarItem* pItem = mpItemList->GetObject( nPos ); + + if ( pItem->mbSelect != bSelect ) + { + pItem->mbSelect = bSelect; + + // Leiste neu ausgeben + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate( pItem->maRect ); + } + } +} + +// ----------------------------------------------------------------------- + +void TabBar::SelectPageRange( BOOL bSelect, USHORT nStartPos, USHORT nEndPos ) +{ + Rectangle aPaintRect; + USHORT nPos = nStartPos; + ImplTabBarItem* pItem = mpItemList->Seek( nPos ); + while ( pItem && (nPos <= nEndPos) ) + { + if ( (pItem->mbSelect != bSelect) && (pItem->mnId != mnCurPageId) ) + { + pItem->mbSelect = bSelect; + aPaintRect.Union( pItem->maRect ); + } + + nPos++; + pItem = mpItemList->Next(); + } + + // Leiste neu ausgeben + if ( IsReallyVisible() && IsUpdateMode() && !aPaintRect.IsEmpty() ) + Invalidate( aPaintRect ); +} + +// ----------------------------------------------------------------------- + +USHORT TabBar::GetSelectPage( USHORT nSelIndex ) const +{ + USHORT nSelected = 0; + ImplTabBarItem* pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->mbSelect ) + nSelected++; + + if ( nSelected == nSelIndex ) + return pItem->mnId; + + pItem = mpItemList->Next(); + } + + return 0; +} + +// ----------------------------------------------------------------------- + +USHORT TabBar::GetSelectPageCount() const +{ + USHORT nSelected = 0; + ImplTabBarItem* pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->mbSelect ) + nSelected++; + + pItem = mpItemList->Next(); + } + + return nSelected; +} + +// ----------------------------------------------------------------------- + +BOOL TabBar::IsPageSelected( USHORT nPageId ) const +{ + USHORT nPos = GetPagePos( nPageId ); + if ( nPos != PAGE_NOT_FOUND ) + return mpItemList->GetObject( nPos )->mbSelect; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL TabBar::StartEditMode( USHORT nPageId ) +{ + USHORT nPos = GetPagePos( nPageId ); + if ( mpEdit || (nPos == PAGE_NOT_FOUND) || (mnLastOffX < 8) ) + return FALSE; + + mnEditId = nPageId; + if ( StartRenaming() ) + { + ImplShowPage( nPos ); + ImplFormat(); + Update(); + + mpEdit = new TabBarEdit( this, WB_CENTER ); + Rectangle aRect = GetPageRect( mnEditId ); + long nX = aRect.Left()+TABBAR_OFFSET_X+(TABBAR_OFFSET_X2/2); + long nWidth = aRect.GetWidth()-(TABBAR_OFFSET_X*2)-TABBAR_OFFSET_X2; + if ( mnEditId != GetCurPageId() ) + nX += 1; + if ( nX+nWidth > mnLastOffX ) + nWidth = mnLastOffX-nX; + if ( nWidth < 3 ) + { + nX = aRect.Left(); + nWidth = aRect.GetWidth(); + } + mpEdit->SetText( GetPageText( mnEditId ) ); + mpEdit->SetPosSizePixel( nX, aRect.Top()+mnOffY+1, nWidth, aRect.GetHeight()-3 ); + Font aFont = GetPointFont(); + Color aForegroundColor; + Color aBackgroundColor; + Color aFaceColor; + Color aSelectColor; + Color aFaceTextColor; + Color aSelectTextColor; + ImplGetColors( aFaceColor, aFaceTextColor, aSelectColor, aSelectTextColor ); + if ( mnEditId != GetCurPageId() ) + aFont.SetWeight( WEIGHT_LIGHT ); + if ( IsPageSelected( mnEditId ) || (mnEditId == GetCurPageId()) ) + { + aForegroundColor = aSelectTextColor; + aBackgroundColor = aSelectColor; + } + else + { + aForegroundColor = aFaceTextColor; + aBackgroundColor = aFaceColor; + } + if ( GetPageBits( mnEditId ) & TPB_SPECIAL ) + aForegroundColor = Color( COL_LIGHTBLUE ); + mpEdit->SetControlFont( aFont ); + mpEdit->SetControlForeground( aForegroundColor ); + mpEdit->SetControlBackground( aBackgroundColor ); + mpEdit->GrabFocus(); + mpEdit->SetSelection( Selection( 0, mpEdit->GetText().Len() ) ); + mpEdit->Show(); + return TRUE; + } + else + { + mnEditId = 0; + return FALSE; + } +} + +// ----------------------------------------------------------------------- + +void TabBar::EndEditMode( BOOL bCancel ) +{ + if ( mpEdit ) + { + // call hdl + BOOL bEnd = TRUE; + mbEditCanceled = bCancel; + maEditText = mpEdit->GetText(); + mpEdit->SetPostEvent(); + if ( !bCancel ) + { + long nAllowRenaming = AllowRenaming(); + if ( nAllowRenaming == TABBAR_RENAMING_YES ) + SetPageText( mnEditId, maEditText ); + else if ( nAllowRenaming == TABBAR_RENAMING_NO ) + bEnd = FALSE; + else // nAllowRenaming == TABBAR_RENAMING_CANCEL + mbEditCanceled = TRUE; + } + + // renaming not allowed, than reset edit data + if ( !bEnd ) + { + mpEdit->ResetPostEvent(); + mpEdit->GrabFocus(); + } + else + { + // close edit and call end hdl + delete mpEdit; + mpEdit = NULL; + EndRenaming(); + mnEditId = 0; + } + + // reset + maEditText.Erase(); + mbEditCanceled = FALSE; + } +} + +// ----------------------------------------------------------------------- + +void TabBar::SetMirrored( BOOL bMirrored ) +{ + if( mbMirrored != bMirrored ) + { + mbMirrored = bMirrored; + mbSizeFormat = TRUE; + ImplInitControls(); // for button images + Resize(); // recalculates control positions + Mirror(); + } +} + +void TabBar::SetEffectiveRTL( BOOL bRTL ) +{ + SetMirrored( bRTL != Application::GetSettings().GetLayoutRTL() ); +} + +BOOL TabBar::IsEffectiveRTL() const +{ + return IsMirrored() != Application::GetSettings().GetLayoutRTL(); +} + +// ----------------------------------------------------------------------- + +void TabBar::SetMaxPageWidth( long nMaxWidth ) +{ + if ( mnMaxPageWidth != nMaxWidth ) + { + mnMaxPageWidth = nMaxWidth; + mbSizeFormat = TRUE; + + // Leiste neu ausgeben + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void TabBar::SetSelectColor() +{ + if ( mbSelColor ) + { + maSelColor = Color( COL_TRANSPARENT ); + mbSelColor = FALSE; + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void TabBar::SetSelectColor( const Color& rColor ) +{ + if ( rColor.GetTransparency() ) + { + if ( mbSelColor ) + { + maSelColor = Color( COL_TRANSPARENT ); + mbSelColor = FALSE; + Invalidate(); + } + } + else + { + if ( maSelColor != rColor ) + { + maSelColor = rColor; + mbSelColor = TRUE; + Invalidate(); + } + } +} + +// ----------------------------------------------------------------------- + +void TabBar::SetSelectTextColor() +{ + if ( mbSelTextColor ) + { + maSelTextColor = Color( COL_TRANSPARENT ); + mbSelTextColor = FALSE; + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void TabBar::SetSelectTextColor( const Color& rColor ) +{ + if ( rColor.GetTransparency() ) + { + if ( mbSelTextColor ) + { + maSelTextColor = Color( COL_TRANSPARENT ); + mbSelTextColor = FALSE; + Invalidate(); + } + } + else + { + if ( maSelTextColor != rColor ) + { + maSelTextColor = rColor; + mbSelTextColor = TRUE; + Invalidate(); + } + } +} + +// ----------------------------------------------------------------------- + +void TabBar::SetPageText( USHORT nPageId, const XubString& rText ) +{ + USHORT nPos = GetPagePos( nPageId ); + if ( nPos != PAGE_NOT_FOUND ) + { + mpItemList->GetObject( nPos )->maText = rText; + mbSizeFormat = TRUE; + + // Leiste neu ausgeben + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + + CallEventListeners( VCLEVENT_TABBAR_PAGETEXTCHANGED, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(nPageId)) ); + } +} + +// ----------------------------------------------------------------------- + +XubString TabBar::GetPageText( USHORT nPageId ) const +{ + USHORT nPos = GetPagePos( nPageId ); + if ( nPos != PAGE_NOT_FOUND ) + return mpItemList->GetObject( nPos )->maText; + else + return XubString(); +} + +// ----------------------------------------------------------------------- + +void TabBar::SetHelpText( USHORT nPageId, const XubString& rText ) +{ + USHORT nPos = GetPagePos( nPageId ); + if ( nPos != PAGE_NOT_FOUND ) + mpItemList->GetObject( nPos )->maHelpText = rText; +} + +// ----------------------------------------------------------------------- + +XubString TabBar::GetHelpText( USHORT nPageId ) const +{ + USHORT nPos = GetPagePos( nPageId ); + if ( nPos != PAGE_NOT_FOUND ) + { + ImplTabBarItem* pItem = mpItemList->GetObject( nPos ); + if ( !pItem->maHelpText.Len() && pItem->maHelpId.getLength() ) + { + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + pItem->maHelpText = pHelp->GetHelpText( rtl::OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8 ), this ); + } + + return pItem->maHelpText; + } + else + return XubString(); +} + +// ----------------------------------------------------------------------- + +void TabBar::SetHelpId( USHORT nPageId, const rtl::OString& rHelpId ) +{ + USHORT nPos = GetPagePos( nPageId ); + if ( nPos != PAGE_NOT_FOUND ) + mpItemList->GetObject( nPos )->maHelpId = rHelpId; +} + +// ----------------------------------------------------------------------- + +rtl::OString TabBar::GetHelpId( USHORT nPageId ) const +{ + USHORT nPos = GetPagePos( nPageId ); + rtl::OString aRet; + if ( nPos != PAGE_NOT_FOUND ) + aRet = mpItemList->GetObject( nPos )->maHelpId; + return aRet; +} + +// ----------------------------------------------------------------------- + +long TabBar::GetMinSize() const +{ + long nMinSize = TABBAR_MINSIZE + TABBAR_OFFSET_X; + if ( mnWinStyle & WB_MINSCROLL ) + nMinSize += mpPrevBtn->GetSizePixel().Width()*2; + else if ( mnWinStyle & WB_SCROLL ) + nMinSize += mpFirstBtn->GetSizePixel().Width()*4; + return nMinSize; +} + +// ----------------------------------------------------------------------- + +BOOL TabBar::StartDrag( const CommandEvent& rCEvt, Region& rRegion ) +{ + if ( !(mnWinStyle & WB_DRAG) || (rCEvt.GetCommand() != COMMAND_STARTDRAG) ) + return FALSE; + + // Testen, ob angeklickte Seite selektiert ist. Falls dies nicht + // der Fall ist, setzen wir ihn als aktuellen Eintrag. Falls Drag and + // Drop auch mal ueber Tastatur ausgeloest werden kann, testen wir + // dies nur bei einer Mausaktion. + // Ausserdem machen wir das nur, wenn kein Select() ausgeloest wurde, + // da der Select schon den Bereich gescrollt haben kann + if ( rCEvt.IsMouseEvent() && !mbInSelect ) + { + USHORT nSelId = GetPageId( rCEvt.GetMousePosPixel() ); + + // Falls kein Eintrag angeklickt wurde, starten wir kein Dragging + if ( !nSelId ) + return FALSE; + + // Testen, ob Seite selektiertiert ist. Falls nicht, als aktuelle + // Seite setzen und Select rufen. + if ( !IsPageSelected( nSelId ) ) + { + if ( ImplDeactivatePage() ) + { + SetCurPageId( nSelId ); + Update(); + ImplActivatePage(); + ImplSelect(); + } + else + return FALSE; + } + } + mbInSelect = FALSE; + + Region aRegion; + + // Region zuweisen + rRegion = aRegion; + + return TRUE; +} + +// ----------------------------------------------------------------------- + +USHORT TabBar::ShowDropPos( const Point& rPos ) +{ + ImplTabBarItem* pItem; + USHORT nDropId; + USHORT nNewDropPos; + USHORT nItemCount = (USHORT)mpItemList->Count(); + short nScroll = 0; + + if ( rPos.X() > mnLastOffX-TABBAR_DRAG_SCROLLOFF ) + { + pItem = mpItemList->GetObject( mpItemList->Count()-1 ); + if ( !pItem->maRect.IsEmpty() && (rPos.X() > pItem->maRect.Right()) ) + nNewDropPos = (USHORT)mpItemList->Count(); + else + { + nNewDropPos = mnFirstPos+1; + nScroll = 1; + } + } + else if ( (rPos.X() <= mnOffX) || + (!mnOffX && (rPos.X() <= TABBAR_DRAG_SCROLLOFF)) ) + { + if ( mnFirstPos ) + { + nNewDropPos = mnFirstPos; + nScroll = -1; + } + else + nNewDropPos = 0; + } + else + { + nDropId = GetPageId( rPos ); + if ( nDropId ) + { + nNewDropPos = GetPagePos( nDropId ); + if ( mnFirstPos && (nNewDropPos == mnFirstPos-1) ) + nScroll = -1; + } + else + nNewDropPos = nItemCount; + } + + if ( mbDropPos && (nNewDropPos == mnDropPos) && !nScroll ) + return mnDropPos; + + if ( mbDropPos ) + HideDropPos(); + mbDropPos = TRUE; + mnDropPos = nNewDropPos; + + if ( nScroll ) + { + USHORT nOldFirstPos = mnFirstPos; + SetFirstPageId( GetPageId( mnFirstPos+nScroll ) ); + + // Direkt ausgeben, da kein Paint bei Drag and Drop moeglich + if ( nOldFirstPos != mnFirstPos ) + { + Rectangle aRect( mnOffX, 0, mnLastOffX, maWinSize.Height() ); + SetFillColor( GetBackground().GetColor() ); + DrawRect( aRect ); + Paint( aRect ); + } + } + + // Drop-Position-Pfeile ausgeben + Color aBlackColor( COL_BLACK ); + long nX; + long nY = (maWinSize.Height()/2)-1; + USHORT nCurPos = GetPagePos( mnCurPageId ); + + SetLineColor( aBlackColor ); + if ( mnDropPos < nItemCount ) + { + pItem = mpItemList->GetObject( mnDropPos ); + nX = pItem->maRect.Left()+TABBAR_OFFSET_X; + if ( mnDropPos == nCurPos ) + nX--; + else + nX++; + if ( !pItem->IsDefaultTabBgColor() && !pItem->mbSelect) + SetLineColor( pItem->maTabTextColor ); + DrawLine( Point( nX, nY ), Point( nX, nY ) ); + DrawLine( Point( nX+1, nY-1 ), Point( nX+1, nY+1 ) ); + DrawLine( Point( nX+2, nY-2 ), Point( nX+2, nY+2 ) ); + SetLineColor( aBlackColor ); + } + if ( (mnDropPos > 0) && (mnDropPos < nItemCount+1) ) + { + pItem = mpItemList->GetObject( mnDropPos-1 ); + nX = pItem->maRect.Right()-TABBAR_OFFSET_X; + if ( mnDropPos == nCurPos ) + nX++; + if ( !pItem->IsDefaultTabBgColor() && !pItem->mbSelect) + SetLineColor( pItem->maTabTextColor ); + DrawLine( Point( nX, nY ), Point( nX, nY ) ); + DrawLine( Point( nX-1, nY-1 ), Point( nX-1, nY+1 ) ); + DrawLine( Point( nX-2, nY-2 ), Point( nX-2, nY+2 ) ); + } + + return mnDropPos; +} + +// ----------------------------------------------------------------------- + +void TabBar::HideDropPos() +{ + if ( mbDropPos ) + { + ImplTabBarItem* pItem; + long nX; + long nY1 = (maWinSize.Height()/2)-3; + long nY2 = nY1 + 5; + USHORT nItemCount = (USHORT)mpItemList->Count(); + + if ( mnDropPos < nItemCount ) + { + pItem = mpItemList->GetObject( mnDropPos ); + nX = pItem->maRect.Left()+TABBAR_OFFSET_X; + // Paint direkt aufrufen, da bei Drag and Drop kein Paint + // moeglich + Rectangle aRect( nX-1, nY1, nX+3, nY2 ); + Region aRegion( aRect ); + SetClipRegion( aRegion ); + Paint( aRect ); + SetClipRegion(); + } + if ( (mnDropPos > 0) && (mnDropPos < nItemCount+1) ) + { + pItem = mpItemList->GetObject( mnDropPos-1 ); + nX = pItem->maRect.Right()-TABBAR_OFFSET_X; + // Paint direkt aufrufen, da bei Drag and Drop kein Paint + // moeglich + Rectangle aRect( nX-2, nY1, nX+1, nY2 ); + Region aRegion( aRect ); + SetClipRegion( aRegion ); + Paint( aRect ); + SetClipRegion(); + } + + mbDropPos = FALSE; + mnDropPos = 0; + } +} + +// ----------------------------------------------------------------------- + +BOOL TabBar::SwitchPage( const Point& rPos ) +{ + BOOL bSwitch = FALSE; + USHORT nSwitchId = GetPageId( rPos ); + if ( !nSwitchId ) + EndSwitchPage(); + else + { + if ( nSwitchId != mnSwitchId ) + { + mnSwitchId = nSwitchId; + mnSwitchTime = Time::GetSystemTicks(); + } + else + { + // Erst nach 500 ms umschalten + if ( mnSwitchId != GetCurPageId() ) + { + if ( Time::GetSystemTicks() > mnSwitchTime+500 ) + { + mbInSwitching = TRUE; + if ( ImplDeactivatePage() ) + { + SetCurPageId( mnSwitchId ); + Update(); + ImplActivatePage(); + ImplSelect(); + bSwitch = TRUE; + } + mbInSwitching = FALSE; + } + } + } + } + + return bSwitch; +} + +// ----------------------------------------------------------------------- + +void TabBar::EndSwitchPage() +{ + mnSwitchTime = 0; + mnSwitchId = 0; +} + +// ----------------------------------------------------------------------- + +void TabBar::SetStyle( WinBits nStyle ) +{ + mnWinStyle = nStyle; + ImplInitControls(); + // Evt. Controls neu anordnen + if ( IsReallyVisible() && IsUpdateMode() ) + Resize(); +} + +// ----------------------------------------------------------------------- + +Size TabBar::CalcWindowSizePixel() const +{ + long nWidth = 0; + + if ( mpItemList->Count() ) + { + ((TabBar*)this)->ImplCalcWidth(); + ImplTabBarItem* pItem = mpItemList->First(); + while ( pItem ) + { + nWidth += pItem->mnWidth; + pItem = mpItemList->Next(); + } + nWidth += TABBAR_OFFSET_X+TABBAR_OFFSET_X2; + } + + return Size( nWidth, GetSettings().GetStyleSettings().GetScrollBarSize() ); +} +// ----------------------------------------------------------------------- + +Rectangle TabBar::GetPageArea() const +{ + return Rectangle( Point( mnOffX, mnOffY ), Size( mnLastOffX-mnOffX+1, GetSizePixel().Height()-mnOffY ) ); +} + +// ----------------------------------------------------------------------- + +::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > TabBar::CreateAccessible() +{ + return mpImpl->maAccessibleFactory.getFactory().createAccessibleTabBar( *this ); +} + +// ----------------------------------------------------------------------- diff --git a/svtools/source/control/taskbar.cxx b/svtools/source/control/taskbar.cxx new file mode 100755 index 000000000000..232727951281 --- /dev/null +++ b/svtools/source/control/taskbar.cxx @@ -0,0 +1,589 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#define _TASKBAR_CXX + +#include <tools/list.hxx> +#include <tools/debug.hxx> +#include <vcl/floatwin.hxx> + +#include <svtools/taskbar.hxx> + +// ======================================================================= + +class ImplTaskBarFloat : public FloatingWindow +{ +public: + TaskBar* mpTaskBar; + +public: + ImplTaskBarFloat( TaskBar* pTaskBar ); +}; + +// ----------------------------------------------------------------------- + +ImplTaskBarFloat::ImplTaskBarFloat( TaskBar* pTaskBar ) : + FloatingWindow( pTaskBar, 0 ) +{ + mpTaskBar = pTaskBar; +} + +// ======================================================================= + +#define TASKBAR_BORDER 2 +#define TASKBAR_OFFSIZE 3 +#define TASKBAR_OFFX 2 +#define TASKBAR_OFFY 1 +#define TASKBAR_BUTTONOFF 5 +#define TASKBAR_AUTOHIDE_HEIGHT 2 + +// ======================================================================= + +TaskBar::TaskBar( Window* pParent, WinBits nWinStyle ) : + Window( pParent, WB_3DLOOK ) +{ + mpButtonBar = NULL; + mpTaskToolBox = NULL; + mpStatusBar = NULL; + mnStatusWidth = 0; + mnOldStatusWidth = 0; + mnLines = 1; + mnWinBits = nWinStyle; + mbStatusText = FALSE; + mbShowItems = FALSE; + mbAutoHide = FALSE; + + ImplInitSettings(); +} + +// ----------------------------------------------------------------------- + +TaskBar::~TaskBar() +{ + if ( mpButtonBar ) + delete mpButtonBar; + if ( mpTaskToolBox ) + delete mpTaskToolBox; + if ( mpStatusBar ) + delete mpStatusBar; +} + +// ----------------------------------------------------------------------- + +void TaskBar::ImplInitSettings() +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + Color aColor; + if ( IsControlBackground() ) + aColor = GetControlBackground(); + else if ( Window::GetStyle() & WB_3DLOOK ) + aColor = rStyleSettings.GetFaceColor(); + else + aColor = rStyleSettings.GetWindowColor(); + SetBackground( aColor ); +} + +// ----------------------------------------------------------------------- + +void TaskBar::ImplNewHeight( long nNewHeight ) +{ + long nOldHeight = GetSizePixel().Height(); + if ( nNewHeight != nOldHeight ) + { + long nY = GetPosPixel().Y()-(nNewHeight-nOldHeight); + SetPosSizePixel( 0, nY, 0, nNewHeight, + WINDOW_POSSIZE_Y | WINDOW_POSSIZE_HEIGHT ); + TaskResize(); + } +} + +// ----------------------------------------------------------------------- + +void TaskBar::TaskResize() +{ + maTaskResizeHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +TaskButtonBar* TaskBar::CreateButtonBar() +{ + return new TaskButtonBar( this ); +} + +// ----------------------------------------------------------------------- + +TaskToolBox* TaskBar::CreateTaskToolBox() +{ + return new TaskToolBox( this ); +} + +// ----------------------------------------------------------------------- + +TaskStatusBar* TaskBar::CreateTaskStatusBar() +{ + return new TaskStatusBar( this ); +} + +// ----------------------------------------------------------------------- + +void TaskBar::MouseMove( const MouseEvent& rMEvt ) +{ + if ( mnWinBits & WB_SIZEABLE ) + { + TaskToolBox* pTempTaskToolBox = GetTaskToolBox(); + TaskStatusBar* pTempStatusBar = GetStatusBar(); + + if ( pTempTaskToolBox && pTempStatusBar ) + { + long nStatusX = pTempStatusBar->GetPosPixel().X()-TASKBAR_OFFSIZE-2; + long nMouseX = rMEvt.GetPosPixel().X(); + PointerStyle ePtrStyle; + if ( (nMouseX >= nStatusX-1) && (nMouseX <= nStatusX+3) ) + ePtrStyle = POINTER_HSIZEBAR; + else + ePtrStyle = POINTER_ARROW; + Pointer aPtr( ePtrStyle ); + SetPointer( aPtr ); + } + } +} + +// ----------------------------------------------------------------------- + +void TaskBar::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( rMEvt.IsLeft() && (mnWinBits & WB_SIZEABLE) ) + { + TaskToolBox* pTempTaskToolBox = GetTaskToolBox(); + TaskStatusBar* pTempStatusBar = GetStatusBar(); + + if ( pTempTaskToolBox && pTempStatusBar ) + { + long nStatusX = pTempStatusBar->GetPosPixel().X()-TASKBAR_OFFSIZE-2; + long nMouseX = rMEvt.GetPosPixel().X(); + if ( (nMouseX >= nStatusX-1) && (nMouseX <= nStatusX+3) ) + { + if ( rMEvt.GetClicks() == 2 ) + { + if ( mnStatusWidth ) + { + mnStatusWidth = 0; + Resize(); + } + } + else + { + StartTracking(); + mnOldStatusWidth = mnStatusWidth; + mnMouseOff = nMouseX-nStatusX; + } + } + } + } +} + +// ----------------------------------------------------------------------- + +void TaskBar::Tracking( const TrackingEvent& rTEvt ) +{ + if ( rTEvt.IsTrackingEnded() ) + { + if ( rTEvt.IsTrackingCanceled() ) + { + mnStatusWidth = mnOldStatusWidth; + Resize(); + Update(); + } + } + else + { + Size aSize = GetOutputSizePixel(); + + long nMouseX = rTEvt.GetMouseEvent().GetPosPixel().X()-mnMouseOff; + if ( nMouseX < 0 ) + nMouseX = 0; + long nMaxX = aSize.Width()-TASKBAR_OFFX-TASKBAR_OFFSIZE-1; + if ( nMouseX > nMaxX ) + nMouseX = nMaxX; + mnStatusWidth = aSize.Width()-nMouseX-TASKBAR_OFFX-TASKBAR_OFFSIZE; + Resize(); + Update(); + } +} + +// ----------------------------------------------------------------------- + +void TaskBar::Paint( const Rectangle& rRect ) +{ + if ( mnWinBits & (WB_BORDER | WB_SIZEABLE) ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Size aSize = GetOutputSizePixel(); + long nY = 0; + + if ( mnWinBits & WB_BORDER ) + { + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( Point( 0, 0 ), Point( aSize.Width()-1, 0 ) ); + SetLineColor( rStyleSettings.GetLightColor() ); + DrawLine( Point( 0, 1 ), Point( aSize.Width()-1, 1 ) ); + nY += 2; + } + + if ( (mnWinBits & WB_SIZEABLE) ) + { + //TaskButtonBar* pTempButtonBar = GetButtonBar(); + TaskToolBox* pTempTaskToolBox = GetTaskToolBox(); + TaskStatusBar* pTempStatusBar = GetStatusBar(); + + if ( pTempTaskToolBox && pTempStatusBar ) + { + long nStatusX = pTempStatusBar->GetPosPixel().X()-TASKBAR_OFFSIZE-2; + if ( nStatusX > 0 ) + { + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( Point( nStatusX, nY ), Point( nStatusX, aSize.Height()-1 ) ); + nStatusX++; + SetLineColor( rStyleSettings.GetLightColor() ); + DrawLine( Point( nStatusX, nY ), Point( nStatusX, aSize.Height()-1 ) ); + } + } + } + } + + Window::Paint( rRect ); +} + +// ----------------------------------------------------------------------- + +void TaskBar::Resize() +{ + if ( !IsReallyShown() ) + return; + + TaskButtonBar* pTempButtonBar = GetButtonBar(); + TaskToolBox* pTempTaskToolBox = GetTaskToolBox(); + TaskStatusBar* pTempStatusBar = GetStatusBar(); + Point aToolPos( TASKBAR_OFFX, 0 ); + Size aSize = GetOutputSizePixel(); + Size aStatusSize; + Size aToolSize( aSize.Width()-(TASKBAR_OFFX*2), 0 ); + long nOldStatusX = -1; + long nNewStatusX = -1; + long nTaskHeight = aSize.Height() - (TASKBAR_OFFY*2); + + if ( mnWinBits & WB_BORDER ) + { + nTaskHeight -= TASKBAR_BORDER; + aToolPos.Y() += TASKBAR_BORDER; + } + + if ( pTempButtonBar ) + { + USHORT i = 0; + BOOL bVisibleItems = FALSE; + while ( i < pTempButtonBar->GetItemCount() ) + { + if ( pTempButtonBar->IsItemVisible( pTempButtonBar->GetItemId( i ) ) ) + { + bVisibleItems = TRUE; + break; + } + i++; + } + if ( mbStatusText || !bVisibleItems ) + pTempButtonBar->Hide(); + else + { + Size aButtonBarSize = pTempButtonBar->CalcWindowSizePixel(); + if ( pTempButtonBar->GetItemCount() ) + nTaskHeight = aButtonBarSize.Height(); + else + aButtonBarSize.Height() = nTaskHeight; + Point aTempPos = aToolPos; + aTempPos.Y() += (aSize.Height()-aButtonBarSize.Height()-aTempPos.Y())/2; + pTempButtonBar->SetPosSizePixel( aTempPos, aButtonBarSize ); + pTempButtonBar->Show(); + aToolPos.X() += aButtonBarSize.Width()+TASKBAR_BUTTONOFF; + } + } + + if ( pTempStatusBar ) + { + aStatusSize = pTempStatusBar->CalcWindowSizePixel(); + if ( mnStatusWidth ) + aStatusSize.Width() = mnStatusWidth; + if ( !pTempTaskToolBox || mbStatusText ) + aStatusSize.Width() = aSize.Width(); + long nMaxHeight = aSize.Height()-(TASKBAR_OFFY*2); + if ( mnWinBits & WB_BORDER ) + nMaxHeight -= TASKBAR_BORDER; + if ( nMaxHeight+2 > aStatusSize.Height() ) + aStatusSize.Height() = nMaxHeight; + Point aPos( aSize.Width()-aStatusSize.Width(), 0 ); + if ( pTempTaskToolBox && (mnWinBits & WB_SIZEABLE) && !mbStatusText ) + { + long nMinToolWidth = aToolPos.X()+50; + if ( aPos.X() < nMinToolWidth ) + { + aStatusSize.Width() -= nMinToolWidth-aPos.X(); + aPos.X() = nMinToolWidth; + } + } + if ( aPos.X() < 0 ) + { + aStatusSize.Width() = aSize.Width(); + aPos.X() = 0; + } + if ( mnWinBits & WB_BORDER ) + aPos.Y() += TASKBAR_BORDER; + aPos.Y() += (aSize.Height()-aStatusSize.Height()-aPos.Y())/2; + if ( mnWinBits & WB_SIZEABLE ) + { + if ( pTempTaskToolBox ) + { + nOldStatusX = pTempStatusBar->GetPosPixel().X()-TASKBAR_OFFSIZE-2; + nNewStatusX = aPos.X()-TASKBAR_OFFSIZE-2; + } + } + pTempStatusBar->SetPosSizePixel( aPos, aStatusSize ); + pTempStatusBar->Show(); + aToolSize.Width() = aPos.X()-aToolPos.X()-TASKBAR_OFFX; + if ( mnWinBits & WB_SIZEABLE ) + aToolSize.Width() -= (TASKBAR_OFFSIZE*2)-2; + } + + if ( pTempTaskToolBox ) + { + if ( aToolSize.Width() <= 24 ) + pTempTaskToolBox->Hide(); + else + { + aToolSize.Height() = pTempTaskToolBox->CalcWindowSizePixel().Height(); + if ( pTempTaskToolBox->GetItemCount() ) + nTaskHeight = aToolSize.Height(); + else + aToolSize.Height() = nTaskHeight; + aToolPos.Y() += (aSize.Height()-aToolSize.Height()-aToolPos.Y())/2; + pTempTaskToolBox->SetPosSizePixel( aToolPos, aToolSize ); + pTempTaskToolBox->Show(); + } + } + + if ( nOldStatusX != nNewStatusX ) + { + if ( nOldStatusX > 0 ) + { + Rectangle aRect( nOldStatusX, 0, nOldStatusX+2, aSize.Height()-1 ); + Invalidate( aRect ); + } + if ( nNewStatusX > 0 ) + { + Rectangle aRect( nNewStatusX, 0, nNewStatusX+2, aSize.Height()-1 ); + Invalidate( aRect ); + } + } +} + +// ----------------------------------------------------------------------- + +void TaskBar::StateChanged( StateChangedType nType ) +{ + Window::StateChanged( nType ); + + if ( nType == STATE_CHANGE_INITSHOW ) + Format(); + else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings(); + Invalidate(); + } + else if ( nType == STATE_CHANGE_FORMAT ) + { + ImplInitSettings(); + ImplNewHeight( CalcWindowSizePixel().Height() ); + Format(); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void TaskBar::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + // Asyncronen StateChanged ausloesen, damit sich die + // TaskBar an die neuen Groessen der Child-Fenster + // orientieren kann + PostStateChanged( STATE_CHANGE_FORMAT ); + } +} + +// ----------------------------------------------------------------------- + +void TaskBar::Format() +{ + ImplNewHeight( CalcWindowSizePixel().Height() ); + Resize(); +} + +// ----------------------------------------------------------------------- + +void TaskBar::SetLines( USHORT nLines ) +{ + mnLines = nLines; +} + +// ----------------------------------------------------------------------- + +void TaskBar::EnableAutoHide( BOOL bAutoHide ) +{ + mbAutoHide = bAutoHide; + + if ( mbAutoHide ) + { + ImplNewHeight( TASKBAR_AUTOHIDE_HEIGHT ); + } + else + { + ImplNewHeight( CalcWindowSizePixel().Height() ); + } +} + +// ----------------------------------------------------------------------- + +void TaskBar::ShowStatusText( const String& rText ) +{ + if ( mpStatusBar ) + { + if ( !mbStatusText ) + { + mbStatusText = TRUE; + if ( mpStatusBar->AreItemsVisible() ) + { + mbShowItems = TRUE; + mpStatusBar->HideItems(); + } + else + mbShowItems = TRUE; + maOldText = mpStatusBar->GetText(); + Resize(); + mpStatusBar->SetText( rText ); + Update(); + mpStatusBar->Update(); + } + else + mpStatusBar->SetText( rText ); + } +} + +// ----------------------------------------------------------------------- + +void TaskBar::HideStatusText() +{ + if ( mbStatusText && mpStatusBar ) + { + mbStatusText = FALSE; + mpStatusBar->SetText( maOldText ); + Resize(); + if ( mbShowItems ) + mpStatusBar->ShowItems(); + } +} + +// ----------------------------------------------------------------------- + +Size TaskBar::CalcWindowSizePixel() const +{ + TaskButtonBar* pTempButtonBar = GetButtonBar(); + TaskToolBox* pTempTaskToolBox = GetTaskToolBox(); + TaskStatusBar* pTempStatusBar = GetStatusBar(); + Size aSize; + long nTempHeight; + + if ( pTempButtonBar && pTempButtonBar->GetItemCount() ) + aSize.Height() = pTempButtonBar->CalcWindowSizePixel().Height()+(TASKBAR_OFFY*2); + if ( pTempTaskToolBox && pTempTaskToolBox->GetItemCount() ) + { + nTempHeight = pTempTaskToolBox->CalcWindowSizePixel().Height()+(TASKBAR_OFFY*2); + if ( nTempHeight > aSize.Height() ) + aSize.Height() = nTempHeight; + } + if ( pTempStatusBar ) + { + nTempHeight = pTempStatusBar->GetSizePixel().Height(); + if ( nTempHeight > aSize.Height() ) + aSize.Height() = nTempHeight; + } + + if ( mnWinBits & WB_BORDER ) + aSize.Height() += TASKBAR_BORDER; + + return aSize; +} + +// ----------------------------------------------------------------------- + +TaskButtonBar* TaskBar::GetButtonBar() const +{ + if ( !mpButtonBar ) + ((TaskBar*)this)->mpButtonBar = ((TaskBar*)this)->CreateButtonBar(); + return mpButtonBar; +} + +// ----------------------------------------------------------------------- + +TaskToolBox* TaskBar::GetTaskToolBox() const +{ + if ( !mpTaskToolBox ) + ((TaskBar*)this)->mpTaskToolBox = ((TaskBar*)this)->CreateTaskToolBox(); + return mpTaskToolBox; +} + +// ----------------------------------------------------------------------- + +TaskStatusBar* TaskBar::GetStatusBar() const +{ + if ( !mpStatusBar ) + { + ((TaskBar*)this)->mpStatusBar = ((TaskBar*)this)->CreateTaskStatusBar(); + if ( mpStatusBar ) + mpStatusBar->mpNotifyTaskBar = (TaskBar*)this; + } + return mpStatusBar; +} diff --git a/svtools/source/control/taskbox.cxx b/svtools/source/control/taskbox.cxx new file mode 100755 index 000000000000..3f05d077b7c5 --- /dev/null +++ b/svtools/source/control/taskbox.cxx @@ -0,0 +1,349 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#define _TASKBAR_CXX + +#include <tools/list.hxx> +#include <tools/debug.hxx> +#include <vcl/image.hxx> +#include <vcl/help.hxx> +#include <svtools/taskbar.hxx> + +// ======================================================================= + +#define TASKBOX_TASKOFF 3 + +// ======================================================================= + +struct ImplTaskItem +{ + Image maImage; + XubString maText; +}; + +DECLARE_LIST( ImplTaskItemList, ImplTaskItem* ) + +// ======================================================================= + +TaskToolBox::TaskToolBox( Window* pParent, WinBits nWinStyle ) : + ToolBox( pParent, nWinStyle | WB_SCROLL | WB_3DLOOK ) +{ + mpItemList = new ImplTaskItemList; + mnMaxTextWidth = 0; + mnActiveItemId = 0; + mnTaskItem = 0; + mnSmallItem = TOOLBOX_ITEM_NOTFOUND; + mbMinActivate = FALSE; + + SetAlign( WINDOWALIGN_BOTTOM ); + SetButtonType( BUTTON_SYMBOLTEXT ); +} + +// ----------------------------------------------------------------------- + +TaskToolBox::~TaskToolBox() +{ + ImplTaskItem* pItem = mpItemList->First(); + while ( pItem ) + { + delete pItem; + pItem = mpItemList->Next(); + } + + delete mpItemList; +} + +// ----------------------------------------------------------------------- + +void TaskToolBox::ActivateTaskItem( USHORT nItemId, BOOL bMinActivate ) +{ + if ( nItemId ) + { + if ( nItemId != mnActiveItemId ) + { + if ( mnActiveItemId ) + CheckItem( mnActiveItemId, FALSE ); + CheckItem( nItemId ); + mnActiveItemId = nItemId; + } + else + { + if ( !bMinActivate ) + return; + + mbMinActivate = TRUE; + } + + mnTaskItem = nItemId-1; + ActivateTask(); + mnTaskItem = 0; + mbMinActivate = FALSE; + } +} + +// ----------------------------------------------------------------------- + +void TaskToolBox::ActivateTask() +{ + maActivateTaskHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void TaskToolBox::ContextMenu() +{ + maContextMenuHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void TaskToolBox::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( !rMEvt.IsRight() ) + ToolBox::MouseButtonDown( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void TaskToolBox::Resize() +{ + mnOldItemCount = mpItemList->Count(); + mnUpdatePos = (USHORT)mnOldItemCount; + mnUpdateNewPos = TOOLBOX_ITEM_NOTFOUND; + ImplFormatTaskToolBox(); + ToolBox::Resize(); +} + +// ----------------------------------------------------------------------- + +void TaskToolBox::Command( const CommandEvent& rCEvt ) +{ + if ( rCEvt.GetCommand() == COMMAND_CONTEXTMENU ) + { + USHORT nItemId = GetItemId( rCEvt.GetMousePosPixel() ); +// Dies machen wir nicht mehr, da es von zu vielen als stoerend empfunden wurde +// ActivateTaskItem( nItemId ); + mnTaskItem = nItemId-1; + + maContextMenuPos = rCEvt.GetMousePosPixel(); + ContextMenu(); + maContextMenuPos = Point(); + mnTaskItem = 0; + } + else + ToolBox::Command( rCEvt ); +} + +// ----------------------------------------------------------------------- + +void TaskToolBox::RequestHelp( const HelpEvent& rHEvt ) +{ + if ( rHEvt.GetMode() & (HELPMODE_BALLOON | HELPMODE_QUICK) ) + { + USHORT nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) ); + + if ( nItemId ) + { + ImplTaskItem* pItem = mpItemList->GetObject( nItemId-1 ); + if ( pItem ) + { + if ( pItem->maText != GetItemText( nItemId ) ) + { + Rectangle aItemRect = GetItemRect( nItemId ); + if ( rHEvt.GetMode() & HELPMODE_QUICK ) + Help::ShowQuickHelp( this, aItemRect, pItem->maText ); + else + Help::ShowBalloon( this, aItemRect.Center(), aItemRect, pItem->maText ); + } + else + Help::ShowQuickHelp( this, Rectangle(), String() ); + return; + } + } + } + + ToolBox::RequestHelp( rHEvt ); +} + +// ----------------------------------------------------------------------- + +void TaskToolBox::Select() +{ + USHORT nItemId = GetCurItemId(); + ActivateTaskItem( nItemId, TRUE ); +} + +// ----------------------------------------------------------------------- + +void TaskToolBox::ImplFormatTaskToolBox() +{ + if ( mnUpdateNewPos == TOOLBOX_ITEM_NOTFOUND ) + { + // Eintraege aus der Liste entfernen + while ( mpItemList->Count() > mnUpdatePos ) + delete mpItemList->Remove( (ULONG)mnUpdatePos ); + mnUpdateNewPos = mnUpdatePos; + } + + // Maximale Itemgroesse berechnen + long nOldMaxTextWidth = mnMaxTextWidth; + mnMaxTextWidth = 70; + if ( mpItemList->Count() ) + { + long nWinSize = GetOutputSizePixel().Width()-8; + long nItemSize = mpItemList->GetObject(0)->maImage.GetSizePixel().Width()+7+TASKBOX_TASKOFF+2; + nWinSize -= mpItemList->Count()*nItemSize; + if ( nWinSize > 0 ) + nWinSize /= mpItemList->Count(); + else + nWinSize = 0; + if ( nWinSize < mnMaxTextWidth ) + mnMaxTextWidth = nWinSize; + if ( (mnMaxTextWidth < nOldMaxTextWidth) || + ((mnMaxTextWidth-nOldMaxTextWidth > 3) && + (mnSmallItem != TOOLBOX_ITEM_NOTFOUND)) ) + { + mnSmallItem = TOOLBOX_ITEM_NOTFOUND; + mnUpdateNewPos = 0; + } + } + + // Eintraege aus der ToolBox entfernen, die ersetzt werden + USHORT nBtnPos = (mnUpdateNewPos*2); + while ( nBtnPos < GetItemCount() ) + RemoveItem( nBtnPos ); + if ( mnUpdateNewPos <= (mnActiveItemId-1) ) + mnActiveItemId = 0; + + // Neue Eintrage einfuegen + USHORT i = mnUpdateNewPos; + while ( i < mpItemList->Count() ) + { + ImplTaskItem* pItem = mpItemList->GetObject( i ); + + // Textlaenge berechnen + XubString aText = pItem->maText; + if ( !aText.Len() ) + aText = ' '; + long nTxtWidth = GetTextWidth( aText ); + if ( nTxtWidth > mnMaxTextWidth ) + { + if ( mnSmallItem == TOOLBOX_ITEM_NOTFOUND ) + mnSmallItem = i; + // 3 == Len of "..." + aText.AppendAscii( "..." ); + do + { + aText.Erase( aText.Len()-3-1, 1 ); + nTxtWidth = GetTextWidth( aText ); + } + while ( (nTxtWidth > mnMaxTextWidth) && (aText.Len() > 3) ); + } + + USHORT nItemId = i+1; + if ( aText.EqualsAscii( "..." ) ) + InsertItem( nItemId, pItem->maImage, TIB_LEFT ); + else + InsertItem( nItemId, pItem->maImage, aText, TIB_LEFT ); + InsertSeparator( TOOLBOX_APPEND, TASKBOX_TASKOFF ); + i++; + } + + if ( mnUpdateNewPos != 0 ) + mnMaxTextWidth = nOldMaxTextWidth; + + if ( mnNewActivePos+1 != mnActiveItemId ) + { + if ( mnActiveItemId ) + CheckItem( mnActiveItemId, FALSE ); + mnActiveItemId = mnNewActivePos+1; + CheckItem( mnActiveItemId ); + } +} + +// ----------------------------------------------------------------------- + +void TaskToolBox::StartUpdateTask() +{ + mnOldItemCount = mpItemList->Count(); + mnUpdatePos = 0; + mnUpdateNewPos = TOOLBOX_ITEM_NOTFOUND; + mnNewActivePos = 0xFFFE; +} + +// ----------------------------------------------------------------------- + +void TaskToolBox::UpdateTask( const Image& rImage, const String& rText, + BOOL bActive ) +{ + ImplTaskItem* pItem = mpItemList->GetObject( mnUpdatePos ); + if ( pItem ) + { + if ( (pItem->maText != rText) || (pItem->maImage != rImage) ) + { + // Eintraege aus der Liste entfernen + while ( mpItemList->Count() > mnUpdatePos ) + delete mpItemList->Remove( (ULONG)mnUpdatePos ); + pItem = NULL; + } + } + + if ( !pItem ) + { + if ( mnUpdatePos < mnUpdateNewPos ) + mnUpdateNewPos = mnUpdatePos; + + pItem = new ImplTaskItem; + pItem->maImage = rImage; + pItem->maText = rText; + mpItemList->Insert( pItem, LIST_APPEND ); + } + + if ( bActive ) + mnNewActivePos = mnUpdatePos; + + mnUpdatePos++; +} + +// ----------------------------------------------------------------------- + +void TaskToolBox::EndUpdateTask() +{ + if ( mnUpdateNewPos == TOOLBOX_ITEM_NOTFOUND ) + { + // Eintraege aus der Liste entfernen + while ( mpItemList->Count() > mnUpdatePos ) + delete mpItemList->Remove( (ULONG)mnUpdatePos ); + mnUpdateNewPos = mnUpdatePos; + } + + ImplFormatTaskToolBox(); +} + diff --git a/svtools/source/control/taskmisc.cxx b/svtools/source/control/taskmisc.cxx new file mode 100755 index 000000000000..62eaf020c8f0 --- /dev/null +++ b/svtools/source/control/taskmisc.cxx @@ -0,0 +1,377 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#define _TASKBAR_CXX + +#include <tools/list.hxx> +#include <tools/debug.hxx> +#include <vcl/help.hxx> +#include <svtools/taskbar.hxx> + +// ======================================================================= + +TaskButtonBar::TaskButtonBar( Window* pParent, WinBits nWinStyle ) : + ToolBox( pParent, nWinStyle | WB_3DLOOK ) +{ + SetAlign( WINDOWALIGN_BOTTOM ); + SetButtonType( BUTTON_SYMBOLTEXT ); +} + +// ----------------------------------------------------------------------- + +TaskButtonBar::~TaskButtonBar() +{ +} + +// ----------------------------------------------------------------------- + +void TaskButtonBar::RequestHelp( const HelpEvent& rHEvt ) +{ + ToolBox::RequestHelp( rHEvt ); +} + +// ======================================================================= + +WindowArrange::WindowArrange() +{ + mpWinList = new List; +} + +// ----------------------------------------------------------------------- + +WindowArrange::~WindowArrange() +{ + delete mpWinList; +} + +// ----------------------------------------------------------------------- + +static USHORT ImplCeilSqareRoot( USHORT nVal ) +{ + USHORT i; + + // Ueberlauf verhindern + if ( nVal > 0xFE * 0xFE ) + return 0xFE; + + for ( i=0; i*i < nVal; i++ ) + {} + + return i; +} + +// ----------------------------------------------------------------------- + +static void ImplPosSizeWindow( Window* pWindow, + long nX, long nY, long nWidth, long nHeight ) +{ + if ( nWidth < 32 ) + nWidth = 32; + if ( nHeight < 24 ) + nHeight = 24; + pWindow->SetPosSizePixel( nX, nY, nWidth, nHeight ); +} + +// ----------------------------------------------------------------------- + +void WindowArrange::ImplTile( const Rectangle& rRect ) +{ + USHORT nCount = (USHORT)mpWinList->Count(); + if ( nCount < 3 ) + { + ImplVert( rRect ); + return; + } + + USHORT i; + USHORT j; + USHORT nCols; + USHORT nRows; + USHORT nActRows; + USHORT nOffset; + long nOverWidth; + long nOverHeight; + Window* pWindow; + long nX = rRect.Left(); + long nY = rRect.Top(); + long nWidth = rRect.GetWidth(); + long nHeight = rRect.GetHeight(); + long nRectY = nY; + long nRectWidth = nWidth; + long nRectHeight = nHeight; + long nTempWidth; + long nTempHeight; + + nCols = ImplCeilSqareRoot( nCount ); + nOffset = (nCols*nCols) - nCount; + if ( nOffset >= nCols ) + { + nRows = nCols -1; + nOffset = nOffset - nCols; + } + else + nRows = nCols; + + nWidth /= nCols; + if ( nWidth < 1 ) + nWidth = 1; + nOverWidth = nRectWidth-(nWidth*nCols); + + pWindow = (Window*)mpWinList->First(); + for ( i = 0; i < nCols; i++ ) + { + if ( i < nOffset ) + nActRows = nRows - 1; + else + nActRows = nRows; + + nTempWidth = nWidth; + if ( nOverWidth > 0 ) + { + nTempWidth++; + nOverWidth--; + } + + nHeight = nRectHeight / nActRows; + if ( nHeight < 1 ) + nHeight = 1; + nOverHeight = nRectHeight-(nHeight*nActRows); + for ( j = 0; j < nActRows; j++ ) + { + // Ueberhang verteilen + nTempHeight = nHeight; + if ( nOverHeight > 0 ) + { + nTempHeight++; + nOverHeight--; + } + ImplPosSizeWindow( pWindow, nX, nY, nTempWidth, nTempHeight ); + nY += nTempHeight; + + pWindow = (Window*)mpWinList->Next(); + if ( !pWindow ) + break; + } + + nX += nWidth; + nY = nRectY; + + if ( !pWindow ) + break; + } +} + +// ----------------------------------------------------------------------- + +void WindowArrange::ImplHorz( const Rectangle& rRect ) +{ + long nCount = (long)mpWinList->Count(); + long nX = rRect.Left(); + long nY = rRect.Top(); + long nWidth = rRect.GetWidth(); + long nHeight = rRect.GetHeight(); + long nRectHeight = nHeight; + long nOver; + long nTempHeight; + Window* pWindow; + + nHeight /= nCount; + if ( nHeight < 1 ) + nHeight = 1; + nOver = nRectHeight - (nCount*nHeight); + pWindow = (Window*)mpWinList->First(); + while ( pWindow ) + { + nTempHeight = nHeight; + if ( nOver > 0 ) + { + nTempHeight++; + nOver--; + } + ImplPosSizeWindow( pWindow, nX, nY, nWidth, nTempHeight ); + nY += nTempHeight; + + pWindow = (Window*)mpWinList->Next(); + } +} + +// ----------------------------------------------------------------------- + +void WindowArrange::ImplVert( const Rectangle& rRect ) +{ + long nCount = (long)mpWinList->Count(); + long nX = rRect.Left(); + long nY = rRect.Top(); + long nWidth = rRect.GetWidth(); + long nHeight = rRect.GetHeight(); + long nRectWidth = nWidth; + long nOver; + long nTempWidth; + Window* pWindow; + + nWidth /= nCount; + if ( nWidth < 1 ) + nWidth = 1; + nOver = nRectWidth - (nCount*nWidth); + pWindow = (Window*)mpWinList->First(); + while ( pWindow ) + { + nTempWidth = nWidth; + if ( nOver > 0 ) + { + nTempWidth++; + nOver--; + } + ImplPosSizeWindow( pWindow, nX, nY, nTempWidth, nHeight ); + nX += nTempWidth; + + pWindow = (Window*)mpWinList->Next(); + } +} + +// ----------------------------------------------------------------------- + +void WindowArrange::ImplCascade( const Rectangle& rRect ) +{ + long nX = rRect.Left(); + long nY = rRect.Top(); + long nWidth = rRect.GetWidth(); + long nHeight = rRect.GetHeight(); + long nRectWidth = nWidth; + long nRectHeight = nHeight; + long nOff; + long nCascadeWins; + sal_Int32 nLeftBorder; + sal_Int32 nTopBorder; + sal_Int32 nRightBorder; + sal_Int32 nBottomBorder; + long nStartOverWidth; + long nStartOverHeight; + long nOverWidth = 0; + long nOverHeight = 0; + long nTempX; + long nTempY; + long nTempWidth; + long nTempHeight; + long i; + Window* pWindow; + Window* pTempWindow; + + // Border-Fenster suchen um den Versatz zu ermitteln + pTempWindow = (Window*)mpWinList->First(); + pTempWindow->GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder ); + while ( !nTopBorder ) + { + Window* pBrdWin = pTempWindow->GetWindow( WINDOW_REALPARENT ); + if ( !pBrdWin || (pBrdWin->GetWindow( WINDOW_CLIENT ) != pTempWindow) ) + break; + pTempWindow = pBrdWin; + pTempWindow->GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder ); + } + if ( !nTopBorder ) + nTopBorder = 22; + nOff = nTopBorder; + + nCascadeWins = nRectHeight / 3 / nOff; + if ( !nCascadeWins ) + nCascadeWins = 1; + nWidth -= nCascadeWins*nOff; + nHeight -= nCascadeWins*nOff; + if ( nWidth < 1 ) + nWidth = 1; + if ( nHeight < 1 ) + nHeight = 1; + + nStartOverWidth = nRectWidth-(nWidth+(nCascadeWins*nOff)); + nStartOverHeight = nRectHeight-(nHeight+(nCascadeWins*nOff)); + + i = 0; + pWindow = (Window*)mpWinList->First(); + while ( pWindow ) + { + if ( !i ) + { + nOverWidth = nStartOverWidth; + nOverHeight = nStartOverHeight; + } + + // Position + nTempX = nX + (i*nOff); + nTempY = nY + (i*nOff); + + // Ueberhang verteilen + nTempWidth = nWidth; + if ( nOverWidth > 0 ) + { + nTempWidth++; + nOverWidth--; + } + nTempHeight = nHeight; + if ( nOverHeight > 0 ) + { + nTempHeight++; + nOverHeight--; + } + + ImplPosSizeWindow( pWindow, nTempX, nTempY, nTempWidth, nTempHeight ); + + if ( i < nCascadeWins ) + i++; + else + i = 0; + + pWindow = (Window*)mpWinList->Next(); + } +} + +// ----------------------------------------------------------------------- + +void WindowArrange::Arrange( USHORT nType, const Rectangle& rRect ) +{ + if ( !mpWinList->Count() ) + return; + + switch ( nType ) + { + case WINDOWARRANGE_TILE: + ImplTile( rRect ); + break; + case WINDOWARRANGE_HORZ: + ImplHorz( rRect ); + break; + case WINDOWARRANGE_VERT: + ImplVert( rRect ); + break; + case WINDOWARRANGE_CASCADE: + ImplCascade( rRect ); + break; + } +} + diff --git a/svtools/source/control/taskstat.cxx b/svtools/source/control/taskstat.cxx new file mode 100755 index 000000000000..2e1cffcaac10 --- /dev/null +++ b/svtools/source/control/taskstat.cxx @@ -0,0 +1,653 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#define _TASKBAR_CXX + +#include <tools/list.hxx> +#include <tools/debug.hxx> +#include <tools/date.hxx> +#include <vcl/image.hxx> +#include <vcl/help.hxx> +#include <vcl/svapp.hxx> +#include <unotools/calendarwrapper.hxx> +#include <unotools/syslocale.hxx> +#include <svtools/taskbar.hxx> + +// ======================================================================= + +#define TASKSTATUSBAR_CLOCXOFFX 3 +#define TASKSTATUSBAR_IMAGEOFFX 1 + +// ======================================================================= + +struct ImplTaskSBFldItem +{ + TaskStatusFieldItem maItem; + USHORT mnId; + long mnOffX; +}; + +DECLARE_LIST( ImplTaskSBItemList, ImplTaskSBFldItem* ) + +// ======================================================================= + +BOOL ITaskStatusNotify::MouseButtonDown( USHORT, const MouseEvent& ) +{ + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL ITaskStatusNotify::MouseButtonUp( USHORT, const MouseEvent& ) +{ + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL ITaskStatusNotify::MouseMove( USHORT, const MouseEvent& ) +{ + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL ITaskStatusNotify::Command( USHORT, const CommandEvent& ) +{ + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL ITaskStatusNotify::UpdateHelp( USHORT ) +{ + return FALSE; +} + +// ======================================================================= + +TaskStatusFieldItem::TaskStatusFieldItem() +{ + mpNotify = NULL; + mnFlags = 0; +} + +// ----------------------------------------------------------------------- + +TaskStatusFieldItem::TaskStatusFieldItem( const TaskStatusFieldItem& rItem ) : + mpNotify( rItem.mpNotify ), + maImage( rItem.maImage ), + maQuickHelpText( rItem.maQuickHelpText ), + maHelpText( rItem.maHelpText ), + mnFlags( rItem.mnFlags ) +{ +} + +// ----------------------------------------------------------------------- + +TaskStatusFieldItem::TaskStatusFieldItem( ITaskStatusNotify* pNotify, + const Image& rImage, + const XubString& rQuickHelpText, + const XubString& rHelpText, + USHORT nFlags ) : + mpNotify( pNotify ), + maImage( rImage ), + maQuickHelpText( rQuickHelpText ), + maHelpText( rHelpText ), + mnFlags( nFlags ) +{ +} + +// ----------------------------------------------------------------------- + +TaskStatusFieldItem::~TaskStatusFieldItem() +{ +} + +// ----------------------------------------------------------------------- + +const TaskStatusFieldItem& TaskStatusFieldItem::operator=( const TaskStatusFieldItem& rItem ) +{ + mpNotify = rItem.mpNotify; + maImage = rItem.maImage; + maQuickHelpText = rItem.maQuickHelpText; + maHelpText = rItem.maHelpText; + mnFlags = rItem.mnFlags; + return *this; +} + +// ======================================================================= + +TaskStatusBar::TaskStatusBar( Window* pParent, WinBits nWinStyle ) : + StatusBar( pParent, nWinStyle | WB_3DLOOK ), + maTime( 0, 0, 0 ) +{ + mpFieldItemList = NULL; + mpNotifyTaskBar = NULL; + mpNotify = NULL; + mnClockWidth = 0; + mnItemWidth = 0; + mnFieldWidth = 0; + mnFieldFlags = 0; + mbFlashItems = FALSE; + mbOutInterval = FALSE; + + maTimer.SetTimeoutHdl( LINK( this, TaskStatusBar, ImplTimerHdl ) ); +} + +// ----------------------------------------------------------------------- + +TaskStatusBar::~TaskStatusBar() +{ + if ( mpFieldItemList ) + { + ImplTaskSBFldItem* pItem = mpFieldItemList->First(); + while ( pItem ) + { + delete pItem; + pItem = mpFieldItemList->Next(); + } + + delete mpFieldItemList; + } +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( TaskStatusBar, ImplTimerHdl, Timer*, EMPTYARG ) +{ + BOOL bUpdate = ImplUpdateClock(); + if ( ImplUpdateFlashItems() ) + bUpdate = TRUE; + if ( bUpdate ) + SetItemData( TASKSTATUSBAR_STATUSFIELDID, NULL ); + + return 0; +} + +// ----------------------------------------------------------------------- + +ImplTaskSBFldItem* TaskStatusBar::ImplGetFieldItem( USHORT nItemId ) const +{ + if ( !mpFieldItemList ) + return NULL; + + ImplTaskSBFldItem* pItem = mpFieldItemList->First(); + while ( pItem ) + { + if ( pItem->mnId == nItemId ) + return pItem; + + pItem = mpFieldItemList->Next(); + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +ImplTaskSBFldItem* TaskStatusBar::ImplGetFieldItem( const Point& rPos, BOOL& rFieldRect ) const +{ + if ( GetItemId( rPos ) == TASKSTATUSBAR_STATUSFIELDID ) + { + rFieldRect = TRUE; + + if ( mpFieldItemList ) + { + long nX = rPos.X()-GetItemRect( TASKSTATUSBAR_STATUSFIELDID ).Left(); + ImplTaskSBFldItem* pItem = mpFieldItemList->First(); + while ( pItem ) + { + if ( nX < pItem->mnOffX+pItem->maItem.GetImage().GetSizePixel().Width() ) + return pItem; + + pItem = mpFieldItemList->Next(); + } + } + } + else + rFieldRect = FALSE; + + return NULL; +} + +// ----------------------------------------------------------------------- + +BOOL TaskStatusBar::ImplUpdateClock() +{ + if ( mnFieldFlags & TASKSTATUSFIELD_CLOCK ) + { + Time aTime; + maTimer.SetTimeout( ((long)60000)-((aTime.GetSec()*1000)+(aTime.Get100Sec()*10)) ); + if ( (aTime.GetMin() != maTime.GetMin()) || + (aTime.GetHour() != maTime.GetHour()) ) + { + maTime = aTime; + maTimeText = SvtSysLocale().GetLocaleData().getTime( aTime, FALSE, FALSE ); + return TRUE; + } + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL TaskStatusBar::ImplUpdateFlashItems() +{ + if ( mbFlashItems ) + { + if ( mbOutInterval ) + { + maTimer.SetTimeout( 900 ); + mbOutInterval = FALSE; + } + else + { + maTimer.SetTimeout( 700 ); + mbOutInterval = TRUE; + } + + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void TaskStatusBar::ImplUpdateField( BOOL bItems ) +{ + maTimer.Stop(); + + if ( bItems ) + { + ImplTaskSBFldItem* pItem = mpFieldItemList->First(); + mnItemWidth = 0; + mbFlashItems = FALSE; + mbOutInterval = FALSE; + while ( pItem ) + { + mnItemWidth += TASKSTATUSBAR_IMAGEOFFX; + pItem->mnOffX = mnItemWidth; + mnItemWidth += pItem->maItem.GetImage().GetSizePixel().Width(); + if ( pItem->maItem.GetFlags() & TASKSTATUSFIELDITEM_FLASH ) + mbFlashItems = TRUE; + + pItem = mpFieldItemList->Next(); + } + } + else + { + if ( mnFieldFlags & TASKSTATUSFIELD_CLOCK ) + { + XubString aStr = SvtSysLocale().GetLocaleData().getTime( Time( 23, 59, 59 ), FALSE, FALSE ); + mnClockWidth = GetTextWidth( aStr )+(TASKSTATUSBAR_CLOCXOFFX*2); + } + else + mnClockWidth = 0; + } + + long nNewWidth = mnItemWidth+mnClockWidth; + if ( mnItemWidth && !mnClockWidth ) + nNewWidth += TASKSTATUSBAR_IMAGEOFFX; + if ( nNewWidth != mnFieldWidth ) + { + RemoveItem( TASKSTATUSBAR_STATUSFIELDID ); + + if ( mnItemWidth || mnClockWidth ) + { + mnFieldWidth = nNewWidth; + long nOffset = GetItemOffset( TASKSTATUSBAR_STATUSFIELDID ); + USHORT nItemPos = GetItemPos( TASKSTATUSBAR_STATUSFIELDID ); + InsertItem( TASKSTATUSBAR_STATUSFIELDID, nNewWidth, SIB_RIGHT | SIB_IN | SIB_USERDRAW, nOffset, nItemPos ); + } + else + mnFieldWidth = 0; + + if ( mpNotifyTaskBar ) + mpNotifyTaskBar->Resize(); + } + else + SetItemData( TASKSTATUSBAR_STATUSFIELDID, NULL ); + + if ( mbFlashItems || (mnFieldFlags & TASKSTATUSFIELD_CLOCK) ) + { + ImplUpdateClock(); + mbOutInterval = TRUE; + ImplUpdateFlashItems(); + maTimer.Start(); + } +} + +// ----------------------------------------------------------------------- + +void TaskStatusBar::MouseButtonDown( const MouseEvent& rMEvt ) +{ + BOOL bFieldRect; + BOOL bBaseClass = FALSE; + ImplTaskSBFldItem* pItem = ImplGetFieldItem( rMEvt.GetPosPixel(), bFieldRect ); + + ITaskStatusNotify* pNotify = mpNotify; + USHORT nItemId = 0; + + if ( bFieldRect ) + nItemId = TASKSTATUSBAR_CLOCKID; + + if ( pItem ) + { + pNotify = pItem->maItem.GetNotifyObject(); + nItemId = pItem->mnId; + } + + if ( pNotify ) + bBaseClass = pNotify->MouseButtonDown( nItemId, rMEvt ); + + if ( bBaseClass ) + StatusBar::MouseButtonDown( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void TaskStatusBar::MouseButtonUp( const MouseEvent& rMEvt ) +{ + BOOL bFieldRect; + BOOL bBaseClass = FALSE; + ImplTaskSBFldItem* pItem = ImplGetFieldItem( rMEvt.GetPosPixel(), bFieldRect ); + + ITaskStatusNotify* pNotify = mpNotify; + USHORT nItemId = 0; + + if ( bFieldRect ) + nItemId = TASKSTATUSBAR_CLOCKID; + + if ( pItem ) + { + pNotify = pItem->maItem.GetNotifyObject(); + nItemId = pItem->mnId; + } + + if ( pNotify ) + bBaseClass = pNotify->MouseButtonUp( nItemId, rMEvt ); + + if ( bBaseClass ) + StatusBar::MouseButtonUp( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void TaskStatusBar::MouseMove( const MouseEvent& rMEvt ) +{ + BOOL bFieldRect; + BOOL bBaseClass = FALSE; + ImplTaskSBFldItem* pItem = ImplGetFieldItem( rMEvt.GetPosPixel(), bFieldRect ); + + ITaskStatusNotify* pNotify = mpNotify; + USHORT nItemId = 0; + + if ( bFieldRect ) + nItemId = TASKSTATUSBAR_CLOCKID; + + if ( pItem ) + { + pNotify = pItem->maItem.GetNotifyObject(); + nItemId = pItem->mnId; + } + + if ( pNotify ) + bBaseClass = pNotify->MouseMove( nItemId, rMEvt ); + + if ( bBaseClass ) + StatusBar::MouseMove( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void TaskStatusBar::Command( const CommandEvent& rCEvt ) +{ + BOOL bFieldRect; + BOOL bBaseClass = FALSE; + ImplTaskSBFldItem* pItem = ImplGetFieldItem( rCEvt.GetMousePosPixel(), bFieldRect ); + + ITaskStatusNotify* pNotify = mpNotify; + USHORT nItemId = 0; + + if ( bFieldRect ) + nItemId = TASKSTATUSBAR_CLOCKID; + + if ( pItem ) + { + pNotify = pItem->maItem.GetNotifyObject(); + nItemId = pItem->mnId; + } + + if ( pNotify ) + bBaseClass = pNotify->Command( nItemId, rCEvt ); + + if ( bBaseClass ) + StatusBar::Command( rCEvt ); +} + +// ----------------------------------------------------------------------- + +void TaskStatusBar::RequestHelp( const HelpEvent& rHEvt ) +{ + BOOL bFieldRect; + ImplTaskSBFldItem* pItem = ImplGetFieldItem( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ), bFieldRect ); + if ( bFieldRect ) + { + ITaskStatusNotify* pNotify = mpNotify; + USHORT nItemId = 0; + + if ( pItem ) + { + pNotify = pItem->maItem.GetNotifyObject(); + nItemId = pItem->mnId; + } + + if ( pNotify ) + pNotify->UpdateHelp( nItemId ); + + if ( rHEvt.GetMode() & (HELPMODE_BALLOON | HELPMODE_QUICK) ) + { + Rectangle aItemRect = GetItemRect( TASKSTATUSBAR_STATUSFIELDID ); + Point aPt = OutputToScreenPixel( aItemRect.TopLeft() ); + aItemRect.Left() = aPt.X(); + aItemRect.Top() = aPt.Y(); + aPt = OutputToScreenPixel( aItemRect.BottomRight() ); + aItemRect.Right() = aPt.X(); + aItemRect.Bottom() = aPt.Y(); + if ( pItem ) + { + if ( rHEvt.GetMode() & HELPMODE_BALLOON ) + { + XubString aStr = pItem->maItem.GetHelpText(); + if ( !aStr.Len() ) + aStr = pItem->maItem.GetQuickHelpText(); + Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr ); + } + else + Help::ShowQuickHelp( this, aItemRect, pItem->maItem.GetQuickHelpText() ); + } + else + { + SvtSysLocale aSL; + const LocaleDataWrapper& rLDW = aSL.GetLocaleData(); + CalendarWrapper aCal( rLDW.getServiceFactory()); + aCal.loadDefaultCalendar( rLDW.getLoadedLocale()); + XubString aStr = rLDW.getLongDate( Date(), aCal ); + if ( rHEvt.GetMode() & HELPMODE_BALLOON ) + Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr ); + else + Help::ShowQuickHelp( this, aItemRect, aStr ); + } + return; + } + else if ( rHEvt.GetMode() & HELPMODE_EXTENDED ) + { + if ( pItem ) + { + rtl::OUString aHelpId( rtl::OStringToOUString( pItem->maItem.GetHelpId(), RTL_TEXTENCODING_UTF8 ) ); + if ( aHelpId.getLength() ) + { + // Wenn eine Hilfe existiert, dann ausloesen + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + pHelp->Start( aHelpId, this ); + return; + } + } + } + } + + StatusBar::RequestHelp( rHEvt ); +} + +// ----------------------------------------------------------------------- + +void TaskStatusBar::UserDraw( const UserDrawEvent& rUDEvt ) +{ + if ( rUDEvt.GetItemId() == TASKSTATUSBAR_STATUSFIELDID ) + { + OutputDevice* pDev = rUDEvt.GetDevice(); + Rectangle aRect = rUDEvt.GetRect(); + + if ( mpFieldItemList ) + { + ImplTaskSBFldItem* pItem = mpFieldItemList->First(); + while ( pItem ) + { + if ( !mbOutInterval || !(pItem->maItem.GetFlags() & TASKSTATUSFIELDITEM_FLASH) ) + { + const Image& rImage = pItem->maItem.GetImage(); + Size aImgSize = rImage.GetSizePixel(); + pDev->DrawImage( Point( aRect.Left()+pItem->mnOffX, + aRect.Top()+((aRect.GetHeight()-aImgSize.Width())/2) ), + rImage ); + } + + pItem = mpFieldItemList->Next(); + } + } + + if ( mnFieldFlags & TASKSTATUSFIELD_CLOCK ) + { + long nX = mnItemWidth+TASKSTATUSBAR_CLOCXOFFX; + Point aPos = GetItemTextPos( TASKSTATUSBAR_STATUSFIELDID ); + aPos.X() = aRect.Left()+nX; + pDev->DrawText( aPos, maTimeText ); + } + } + else + StatusBar::UserDraw( rUDEvt ); +} + +// ----------------------------------------------------------------------- + +void TaskStatusBar::InsertStatusField( long, USHORT, + USHORT nFlags ) +{ + mnFieldFlags = nFlags; + ImplUpdateField( FALSE ); +} + +// ----------------------------------------------------------------------- + +void TaskStatusBar::SetFieldFlags( USHORT nFlags ) +{ + if ( mnFieldFlags != nFlags ) + { + mnFieldFlags = nFlags; + ImplUpdateField( FALSE ); + } +} + +// ----------------------------------------------------------------------- + +void TaskStatusBar::AddStatusFieldItem( USHORT nItemId, const TaskStatusFieldItem& rItem, + USHORT nPos ) +{ + DBG_ASSERT( nItemId, "TaskStatusBar::AddStatusFieldItem() - Item is 0" ); + DBG_ASSERT( !ImplGetFieldItem( nItemId ), "TaskStatusBar::AddStatusFieldItem() - Item-Id already exist" ); + + if ( !mpFieldItemList ) + mpFieldItemList = new ImplTaskSBItemList; + + ImplTaskSBFldItem* pItem = new ImplTaskSBFldItem; + pItem->maItem = rItem; + pItem->mnId = nItemId; + pItem->mnOffX = 0; + mpFieldItemList->Insert( pItem, (ULONG)nPos ); + + ImplUpdateField( TRUE ); +} + +// ----------------------------------------------------------------------- + +void TaskStatusBar::ModifyStatusFieldItem( USHORT nItemId, const TaskStatusFieldItem& rItem ) +{ + ImplTaskSBFldItem* pItem = ImplGetFieldItem( nItemId ); + if ( pItem ) + { + BOOL bUpdate = (pItem->maItem.GetImage() != rItem.GetImage()) || + (pItem->maItem.GetFlags() != rItem.GetFlags()); + pItem->maItem = rItem; + if ( bUpdate ) + ImplUpdateField( TRUE ); + } +} + +// ----------------------------------------------------------------------- + +void TaskStatusBar::RemoveStatusFieldItem( USHORT nItemId ) +{ + ImplTaskSBFldItem* pItem = ImplGetFieldItem( nItemId ); + if ( pItem ) + { + mpFieldItemList->Remove( pItem ); + delete pItem; + ImplUpdateField( TRUE ); + } +} + +// ----------------------------------------------------------------------- + +BOOL TaskStatusBar::GetStatusFieldItem( USHORT nItemId, TaskStatusFieldItem& rItem ) const +{ + ImplTaskSBFldItem* pItem = ImplGetFieldItem( nItemId ); + if ( pItem ) + { + rItem = pItem->maItem; + return TRUE; + } + + return FALSE; +} + diff --git a/svtools/source/control/toolbarmenu.cxx b/svtools/source/control/toolbarmenu.cxx new file mode 100644 index 000000000000..f0bd192fc02c --- /dev/null +++ b/svtools/source/control/toolbarmenu.cxx @@ -0,0 +1,1805 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <comphelper/processfactory.hxx> + +#include <vcl/dockwin.hxx> +#include <vcl/decoview.hxx> +#include <vcl/image.hxx> +#include <vcl/taskpanelist.hxx> +#include <vcl/toolbox.hxx> + +#include "svtools/valueset.hxx" +#include "svtools/toolbarmenu.hxx" +#include "toolbarmenuimp.hxx" + +using ::rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::accessibility; + +namespace svtools { + +// -------------------------------------------------------------------- + +static Window* GetTopMostParentSystemWindow( Window* pWindow ) +{ + OSL_ASSERT( pWindow ); + if ( pWindow ) + { + // ->manually search topmost system window + // required because their might be another system window between this and the top window + pWindow = pWindow->GetParent(); + SystemWindow* pTopMostSysWin = NULL; + while ( pWindow ) + { + if ( pWindow->IsSystemWindow() ) + pTopMostSysWin = (SystemWindow*)pWindow; + pWindow = pWindow->GetParent(); + } + pWindow = pTopMostSysWin; + OSL_ASSERT( pWindow ); + return pWindow; + } + + return NULL; +} + +// -------------------------------------------------------------------- + +void ToolbarMenuEntry::init( int nEntryId, MenuItemBits nBits ) +{ + mnEntryId = nEntryId; + mnBits = nBits; + + mbHasText = false; + mbHasImage = false; + mbChecked = false; + mbEnabled = true; + + mpControl = NULL; +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const String& rText, MenuItemBits nBits ) +: mrMenu( rMenu ) +{ + init( nEntryId, nBits ); + + maText = rText; + mbHasText = true; +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const Image& rImage, MenuItemBits nBits ) +: mrMenu( rMenu ) +{ + init( nEntryId, nBits ); + + maImage = rImage; + mbHasImage = true; +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const Image& rImage, const String& rText, MenuItemBits nBits ) +: mrMenu( rMenu ) +{ + init( nEntryId, nBits ); + + maText = rText; + mbHasText = true; + + maImage = rImage; + mbHasImage = true; +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, Control* pControl, MenuItemBits nBits ) +: mrMenu( rMenu ) +{ + init( nEntryId, nBits ); + + if( pControl ) + { + mpControl = pControl; + mpControl->Show(); + } +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry::~ToolbarMenuEntry() +{ + if( mxAccContext.is() ) + { + Reference< XComponent > xComponent( mxAccContext, UNO_QUERY ); + if( xComponent.is() ) + xComponent->dispose(); + mxAccContext.clear(); + } + delete mpControl; +} + +// -------------------------------------------------------------------- + +const Reference< XAccessibleContext >& ToolbarMenuEntry::GetAccessible( bool bCreate /* = false */ ) +{ + if( !mxAccContext.is() && bCreate ) + { + if( mpControl ) + { + mxAccContext = Reference< XAccessibleContext >( mpControl->GetAccessible( TRUE ), UNO_QUERY ); + } + else + { + mxAccContext = Reference< XAccessibleContext >( new ToolbarMenuEntryAcc( this ) ); + } + } + + return mxAccContext; +} + +// -------------------------------------------------------------------- + +sal_Int32 ToolbarMenuEntry::getAccessibleChildCount() throw (RuntimeException) +{ + if( mpControl ) + { + const Reference< XAccessibleContext >& xContext = GetAccessible( true ); + if( xContext.is() ) + { + return xContext->getAccessibleChildCount(); + } + } + return 1; +} + +// -------------------------------------------------------------------- + +Reference< XAccessible > ToolbarMenuEntry::getAccessibleChild( sal_Int32 index ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const Reference< XAccessibleContext >& xContext = GetAccessible( true ); + if( mpControl ) + { + if( xContext.is() ) + { + return xContext->getAccessibleChild(index); + } + } + else if( index == 0 ) + { + Reference< XAccessible > xRet( xContext, UNO_QUERY ); + if( xRet.is() ) + return xRet; + } + + throw IndexOutOfBoundsException(); +} + +// -------------------------------------------------------------------- + +ToolbarMenu_Impl::ToolbarMenu_Impl( ToolbarMenu& rMenu, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame ) +: mrMenu( rMenu ) +, mxFrame( xFrame ) +, mxServiceManager( ::comphelper::getProcessServiceFactory() ) +, mnCheckPos(0) +, mnImagePos(0) +, mnTextPos(0) +, mnHighlightedEntry(-1) +, mnSelectedEntry(-1) +, mnLastColumn(0) +{ +} + +// -------------------------------------------------------------------- + +ToolbarMenu_Impl::~ToolbarMenu_Impl() +{ + setAccessible( 0 ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu_Impl::setAccessible( ToolbarMenuAcc* pAccessible ) +{ + if( mxAccessible.get() != pAccessible ) + { + if( mxAccessible.is() ) + mxAccessible->dispose(); + + mxAccessible.set( pAccessible ); + } +} + +// ----------------------------------------------------------------------- + +void ToolbarMenu_Impl::fireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue ) +{ + if( mxAccessible.is() ) + mxAccessible->FireAccessibleEvent( nEventId, rOldValue, rNewValue ); +} + +// ----------------------------------------------------------------------- + +bool ToolbarMenu_Impl::hasAccessibleListeners() +{ + return( mxAccessible.is() && mxAccessible->HasAccessibleListeners() ); +} + +// -------------------------------------------------------------------- + +sal_Int32 ToolbarMenu_Impl::getAccessibleChildCount() throw (RuntimeException) +{ + sal_Int32 nCount = 0; + const int nEntryCount = maEntryVector.size(); + for( int nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = maEntryVector[nEntry]; + if( pEntry ) + { + if( pEntry->mpControl ) + { + nCount += pEntry->getAccessibleChildCount(); + } + else + { + nCount += 1; + } + } + } + + return nCount; +} + +// -------------------------------------------------------------------- + +Reference< XAccessible > ToolbarMenu_Impl::getAccessibleChild( sal_Int32 index ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const int nEntryCount = maEntryVector.size(); + for( int nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = maEntryVector[nEntry]; + if( pEntry ) + { + const sal_Int32 nCount = pEntry->getAccessibleChildCount(); + if( index < nCount ) + { + return pEntry->getAccessibleChild( index ); + } + index -= nCount; + } + } + + throw IndexOutOfBoundsException(); +} + +// -------------------------------------------------------------------- + +Reference< XAccessible > ToolbarMenu_Impl::getAccessibleChild( Control* pControl, sal_Int32 childIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const int nEntryCount = maEntryVector.size(); + for( int nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = maEntryVector[nEntry]; + if( pEntry && (pEntry->mpControl == pControl) ) + { + return pEntry->getAccessibleChild( childIndex ); + } + } + + throw IndexOutOfBoundsException(); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu_Impl::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const int nEntryCount = maEntryVector.size(); + for( int nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = maEntryVector[nEntry]; + if( pEntry ) + { + const sal_Int32 nCount = pEntry->getAccessibleChildCount(); + if( nChildIndex < nCount ) + { + if( pEntry->mpControl ) + { + Reference< XAccessibleSelection > xSel( pEntry->GetAccessible(true), UNO_QUERY_THROW ); + xSel->selectAccessibleChild(nChildIndex); + } + else if( pEntry->mnEntryId != TITLE_ID ) + { + mrMenu.implSelectEntry( nEntry ); + } + return; + } + nChildIndex -= nCount; + } + } + + throw IndexOutOfBoundsException(); +} + +// -------------------------------------------------------------------- + +sal_Bool ToolbarMenu_Impl::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const int nEntryCount = maEntryVector.size(); + for( int nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = maEntryVector[nEntry]; + if( pEntry ) + { + const sal_Int32 nCount = pEntry->getAccessibleChildCount(); + if( nChildIndex < nCount ) + { + if( mnHighlightedEntry == nEntry ) + { + if( pEntry->mpControl ) + { + Reference< XAccessibleSelection > xSel( pEntry->GetAccessible(true), UNO_QUERY_THROW ); + xSel->isAccessibleChildSelected(nChildIndex); + } + return true; + } + else + { + return false; + } + } + nChildIndex -= nCount; + } + } + + throw IndexOutOfBoundsException(); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu_Impl::clearAccessibleSelection() +{ + if( mnHighlightedEntry != -1 ) + { + mrMenu.implHighlightEntry( mnHighlightedEntry, false ); + mnHighlightedEntry = -1; + } +} + + +// -------------------------------------------------------------------- + +void ToolbarMenu_Impl::notifyHighlightedEntry() +{ + if( hasAccessibleListeners() ) + { + ToolbarMenuEntry* pEntry = implGetEntry( mnHighlightedEntry ); + if( pEntry && pEntry->mbEnabled && (pEntry->mnEntryId != TITLE_ID) ) + { + Any aNew; + Any aOld( mxOldSelection ); + if( pEntry->mpControl ) + { + sal_Int32 nChildIndex = 0; + // todo: if other controls than ValueSet are allowed, addapt this code + ValueSet* pValueSet = dynamic_cast< ValueSet* >( pEntry->mpControl ); + if( pValueSet ) + nChildIndex = static_cast< sal_Int32 >( pValueSet->GetItemPos( pValueSet->GetSelectItemId() ) ); + + if( nChildIndex >= pEntry->getAccessibleChildCount() ) + return; + + aNew <<= getAccessibleChild( pEntry->mpControl, nChildIndex ); + } + else + { + aNew <<= pEntry->GetAccessible(true); + } + + fireAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOld, aNew ); + fireAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, aOld, aNew ); + fireAccessibleEvent( AccessibleEventId::STATE_CHANGED, Any(), Any( AccessibleStateType::FOCUSED ) ); + aNew >>= mxOldSelection; + } + } +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry* ToolbarMenu_Impl::implGetEntry( int nEntry ) const +{ + if( (nEntry < 0) || (nEntry >= (int)maEntryVector.size() ) ) + return NULL; + + return maEntryVector[nEntry]; +} + + +// -------------------------------------------------------------------- + +IMPL_LINK( ToolbarMenu, HighlightHdl, Control *, pControl ) +{ + (void)pControl; + mpImpl->notifyHighlightedEntry(); + return 0; +} + +// ==================================================================== + +ToolbarMenu::ToolbarMenu( const Reference< XFrame >& rFrame, Window* pParentWindow, WinBits nBits ) +: DockingWindow(pParentWindow, nBits) +{ + implInit(rFrame); +} + +// -------------------------------------------------------------------- + +ToolbarMenu::ToolbarMenu( const Reference< XFrame >& rFrame, Window* pParentWindow, const ResId& rResId ) +: DockingWindow(pParentWindow, rResId) +{ + implInit(rFrame); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::implInit(const Reference< XFrame >& rFrame) +{ + mpImpl = new ToolbarMenu_Impl( *this, rFrame ); + + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + SetControlBackground( rStyleSettings.GetMenuColor() ); + + initWindow(); + + Window* pWindow = GetTopMostParentSystemWindow( this ); + if ( pWindow ) + ((SystemWindow *)pWindow)->GetTaskPaneList()->AddWindow( this ); +} + +// -------------------------------------------------------------------- + +ToolbarMenu::~ToolbarMenu() +{ + Window* pWindow = GetTopMostParentSystemWindow( this ); + if ( pWindow ) + ((SystemWindow *)pWindow)->GetTaskPaneList()->RemoveWindow( this ); + + if ( mpImpl->mxStatusListener.is() ) + { + mpImpl->mxStatusListener->dispose(); + mpImpl->mxStatusListener.clear(); + } + + // delete all menu entries + const int nEntryCount = mpImpl->maEntryVector.size(); + int nEntry; + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + delete mpImpl->maEntryVector[nEntry]; + } + + delete mpImpl; +} + +// -------------------------------------------------------------------- + +int ToolbarMenu::getSelectedEntryId() const +{ + ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnSelectedEntry ); + return pEntry ? pEntry->mnEntryId : -1; +} + +// -------------------------------------------------------------------- + +int ToolbarMenu::getHighlightedEntryId() const +{ + ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnHighlightedEntry ); + return pEntry ? pEntry->mnEntryId : -1; +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::checkEntry( int nEntryId, bool bChecked ) +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + if( pEntry && pEntry->mbChecked != bChecked ) + { + pEntry->mbChecked = bChecked; + Invalidate(); + } +} + +// -------------------------------------------------------------------- + +bool ToolbarMenu::isEntryChecked( int nEntryId ) const +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + return pEntry && pEntry->mbChecked; +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::enableEntry( int nEntryId, bool bEnable ) +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + if( pEntry && pEntry->mbEnabled != bEnable ) + { + pEntry->mbEnabled = bEnable; + if( pEntry->mpControl ) + { + pEntry->mpControl->Enable( bEnable ); + + // hack for the valueset to make it paint itself anew + pEntry->mpControl->Resize(); + } + Invalidate(); + } +} + +// -------------------------------------------------------------------- + +bool ToolbarMenu::isEntryEnabled( int nEntryId ) const +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + return pEntry && pEntry->mbEnabled; +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::setEntryText( int nEntryId, const String& rStr ) +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + if( pEntry && pEntry->maText != rStr ) + { + pEntry->maText = rStr; + mpImpl->maSize = implCalcSize(); + if( IsVisible() ) + Invalidate(); + } +} + +// -------------------------------------------------------------------- + +const String& ToolbarMenu::getEntryText( int nEntryId ) const +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + if( pEntry ) + return pEntry->maText; + else + { + static String aEmptyStr; + return aEmptyStr; + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::setEntryImage( int nEntryId, const Image& rImage ) +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + if( pEntry && pEntry->maImage != rImage ) + { + pEntry->maImage = rImage; + mpImpl->maSize = implCalcSize(); + if( IsVisible() ) + Invalidate(); + } +} + +// -------------------------------------------------------------------- + +const Image& ToolbarMenu::getEntryImage( int nEntryId ) const +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + if( pEntry ) + return pEntry->maImage; + else + { + static Image aEmptyImage; + return aEmptyImage; + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::initWindow() +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + SetPointFont( rStyleSettings.GetMenuFont() ); + SetBackground( Wallpaper( GetControlBackground() ) ); + SetTextColor( rStyleSettings.GetMenuTextColor() ); + SetTextFillColor(); + SetLineColor(); + + mpImpl->maSize = implCalcSize(); +} + +// -------------------------------------------------------------------- + +Size ToolbarMenu::implCalcSize() +{ + const long nFontHeight = GetTextHeight(); + long nExtra = nFontHeight/4; + + Size aSz; + Size aMaxImgSz; + long nMaxTextWidth = 0; + long nMinMenuItemHeight = nFontHeight+2; + sal_Bool bCheckable = sal_False; + + const int nEntryCount = mpImpl->maEntryVector.size(); + int nEntry; + + const StyleSettings& rSettings = GetSettings().GetStyleSettings(); + const bool bUseImages = rSettings.GetUseImagesInMenus(); + + // get maximum image size + if( bUseImages ) + { + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry]; + if( pEntry && pEntry->mbHasImage ) + { + Size aImgSz( pEntry->maImage.GetSizePixel() ); + nMinMenuItemHeight = std::max( nMinMenuItemHeight, aImgSz.Height() + 6 ); + aMaxImgSz.Width() = std::max( aMaxImgSz.Width(), aImgSz.Width() ); + } + } + } + + mpImpl->mnCheckPos = nExtra; + mpImpl->mnImagePos = nExtra; + mpImpl->mnTextPos = mpImpl->mnImagePos + aMaxImgSz.Width(); + + if ( aMaxImgSz.Width() ) + mpImpl->mnTextPos += std::max( nExtra, 7L ); + if ( bCheckable ) + mpImpl->mnTextPos += 16; + + // set heights, calc maximum width + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry]; + + if( pEntry ) + { + if ( ( pEntry->mnBits ) & ( MIB_RADIOCHECK | MIB_CHECKABLE ) ) + bCheckable = sal_True; + + // Text: + if( pEntry->mbHasText || pEntry->mbHasImage ) + { + pEntry->maSize.Height() = nMinMenuItemHeight; + + if( pEntry->mbHasText ) + { + long nTextWidth = GetCtrlTextWidth( pEntry->maText ) + mpImpl->mnTextPos + nExtra; + nMaxTextWidth = std::max( nTextWidth, nMaxTextWidth ); + } + } + // Control: + else if( pEntry->mpControl ) + { + Size aControlSize( pEntry->mpControl->GetOutputSizePixel() ); + + nMaxTextWidth = std::max( aControlSize.Width(), nMaxTextWidth ); + pEntry->maSize.Height() = aControlSize.Height() + 1; + } + + } + } + + aSz.Width() = nMaxTextWidth + (BORDER_X<<1); + + // positionate controls + int nY = BORDER_Y; + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry]; + + if( pEntry ) + { + pEntry->maSize.Width() = nMaxTextWidth; + + if( pEntry->mpControl ) + { + Size aControlSize( pEntry->mpControl->GetOutputSizePixel() ); + Point aControlPos( (aSz.Width() - aControlSize.Width())>>1, nY); + + pEntry->mpControl->SetPosPixel( aControlPos ); + + pEntry->maRect = Rectangle( aControlPos, aControlSize ); + } + else + { + pEntry->maRect = Rectangle( Point( 0, nY ), pEntry->maSize ); + } + + nY += pEntry->maSize.Height(); + } + else + { + nY += SEPARATOR_HEIGHT; + } + } + + aSz.Height() += nY + BORDER_Y; + + return aSz; +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::highlightFirstEntry() +{ + implChangeHighlightEntry( 0 ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::GetFocus() +{ + if( mpImpl->mnHighlightedEntry == -1 ) + implChangeHighlightEntry( 0 ); + + DockingWindow::GetFocus(); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::LoseFocus() +{ + if( mpImpl->mnHighlightedEntry != -1 ) + implChangeHighlightEntry( -1 ); + + DockingWindow::LoseFocus(); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::appendEntry( int nEntryId, const String& rStr, MenuItemBits nItemBits ) +{ + appendEntry( new ToolbarMenuEntry( *this, nEntryId, rStr, nItemBits ) ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::appendEntry( int nEntryId, const Image& rImage, MenuItemBits nItemBits ) +{ + appendEntry( new ToolbarMenuEntry( *this, nEntryId, rImage, nItemBits ) ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::appendEntry( int nEntryId, const String& rStr, const Image& rImage, MenuItemBits nItemBits ) +{ + appendEntry( new ToolbarMenuEntry( *this, nEntryId, rImage, rStr, nItemBits ) ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::appendEntry( int nEntryId, Control* pControl, MenuItemBits nItemBits ) +{ + appendEntry( new ToolbarMenuEntry( *this, nEntryId, pControl, nItemBits ) ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::appendEntry( ToolbarMenuEntry* pEntry ) +{ + mpImpl->maEntryVector.push_back( pEntry ); + mpImpl->maSize = implCalcSize(); + if( IsVisible() ) + Invalidate(); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::appendSeparator() +{ + appendEntry( 0 ); +} + +// -------------------------------------------------------------------- + +/** creates an empty ValueSet that is initialized and can be inserted with appendEntry. */ +ValueSet* ToolbarMenu::createEmptyValueSetControl() +{ + ValueSet* pSet = new ValueSet( this, WB_TABSTOP | WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NOBORDER | WB_NO_DIRECTSELECT ); + pSet->EnableFullItemMode( FALSE ); + pSet->SetColor( GetControlBackground() ); + pSet->SetHighlightHdl( LINK( this, ToolbarMenu, HighlightHdl ) ); + return pSet; +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry* ToolbarMenu::implGetEntry( int nEntry ) const +{ + return mpImpl->implGetEntry( nEntry ); +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry* ToolbarMenu::implSearchEntry( int nEntryId ) const +{ + const int nEntryCount = mpImpl->maEntryVector.size(); + int nEntry; + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* p = mpImpl->maEntryVector[nEntry]; + if( p && p->mnEntryId == nEntryId ) + { + return p; + } + } + + return NULL; +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::implHighlightEntry( int nHighlightEntry, bool bHighlight ) +{ + Size aSz( GetOutputSizePixel() ); + long nX = 0, nY = 0; + + const int nEntryCount = mpImpl->maEntryVector.size(); + int nEntry; + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry]; + if( pEntry && (nEntry == nHighlightEntry) ) + { + // no highlights for controls only items + if( pEntry->mpControl ) + { + if( !bHighlight ) + { + ValueSet* pValueSet = dynamic_cast< ValueSet* >( pEntry->mpControl ); + if( pValueSet ) + { + pValueSet->SetNoSelection(); + } + } + break; + } + + bool bRestoreLineColor = false; + Color oldLineColor; + bool bDrawItemRect = true; + + Rectangle aItemRect( Point( nX, nY ), Size( aSz.Width(), pEntry->maSize.Height() ) ); + if ( pEntry->mnBits & MIB_POPUPSELECT ) + { + long nFontHeight = GetTextHeight(); + aItemRect.Right() -= nFontHeight + nFontHeight/4; + } + + if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) ) + { + Size aPxSize( GetOutputSizePixel() ); + Push( PUSH_CLIPREGION ); + IntersectClipRegion( Rectangle( Point( nX, nY ), Size( aSz.Width(), pEntry->maSize.Height() ) ) ); + Rectangle aCtrlRect( Point( nX, 0 ), Size( aPxSize.Width()-nX, aPxSize.Height() ) ); + DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, + aCtrlRect, + CTRL_STATE_ENABLED, + ImplControlValue(), + OUString() ); + if( bHighlight && IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) ) + { + bDrawItemRect = false; + if( FALSE == DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM, + aItemRect, + CTRL_STATE_SELECTED | ( pEntry->mbEnabled? CTRL_STATE_ENABLED: 0 ), + ImplControlValue(), + OUString() ) ) + { + bDrawItemRect = bHighlight; + } + } + else + bDrawItemRect = bHighlight; + Pop(); + } + if( bDrawItemRect ) + { + if ( bHighlight ) + { + if( pEntry->mbEnabled ) + SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() ); + else + { + SetFillColor(); + oldLineColor = GetLineColor(); + SetLineColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() ); + bRestoreLineColor = true; + } + } + else + SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() ); + + DrawRect( aItemRect ); + } + implPaint( pEntry, bHighlight ); + if( bRestoreLineColor ) + SetLineColor( oldLineColor ); + break; + } + + nY += pEntry ? pEntry->maSize.Height() : SEPARATOR_HEIGHT; + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::implSelectEntry( int nSelectedEntry ) +{ + mpImpl->mnSelectedEntry = nSelectedEntry; + + ToolbarMenuEntry* pEntry = NULL; + if( nSelectedEntry != -1 ) + pEntry = mpImpl->maEntryVector[ nSelectedEntry ]; + + if( pEntry ) + mpImpl->maSelectHdl.Call( this ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::MouseButtonDown( const MouseEvent& rMEvt ) +{ + implHighlightEntry( rMEvt, true ); + + implSelectEntry( mpImpl->mnHighlightedEntry ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::MouseButtonUp( const MouseEvent& ) +{ +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::MouseMove( const MouseEvent& rMEvt ) +{ + if ( !IsVisible() ) + return; + + implHighlightEntry( rMEvt, false ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::implHighlightEntry( const MouseEvent& rMEvt, bool bMBDown ) +{ + long nY = 0; + long nMouseY = rMEvt.GetPosPixel().Y(); + Size aOutSz = GetOutputSizePixel(); + if ( ( nMouseY >= 0 ) && ( nMouseY < aOutSz.Height() ) ) + { + bool bHighlighted = FALSE; + + const int nEntryCount = mpImpl->maEntryVector.size(); + int nEntry; + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry]; + if( pEntry ) + { + long nOldY = nY; + nY += pEntry->maSize.Height(); + + if( pEntry->mnEntryId != TITLE_ID ) + { + if ( ( nOldY <= nMouseY ) && ( nY > nMouseY ) ) + { + if( bMBDown ) + { + if( nEntry != mpImpl->mnHighlightedEntry ) + { + implChangeHighlightEntry( nEntry ); + } + } + else + { + if ( nEntry != mpImpl->mnHighlightedEntry ) + { + implChangeHighlightEntry( nEntry ); + } + } + bHighlighted = true; + } + } + } + else + { + nY += SEPARATOR_HEIGHT; + } + } + if ( !bHighlighted ) + implChangeHighlightEntry( -1 ); + } + else + { + implChangeHighlightEntry( -1 ); + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::implChangeHighlightEntry( int nEntry ) +{ + if( mpImpl->mnHighlightedEntry != -1 ) + { + implHighlightEntry( mpImpl->mnHighlightedEntry, false ); + } + + mpImpl->mnHighlightedEntry = nEntry; + Invalidate(); + + if( mpImpl->mnHighlightedEntry != -1 ) + { + implHighlightEntry( mpImpl->mnHighlightedEntry, true ); + } + + mpImpl->notifyHighlightedEntry(); +} + +// -------------------------------------------------------------------- + +static bool implCheckSubControlCursorMove( Control* pControl, bool bUp, int& nLastColumn ) +{ + ValueSet* pValueSet = dynamic_cast< ValueSet* >( pControl ); + if( pValueSet ) + { + USHORT nItemPos = pValueSet->GetItemPos( pValueSet->GetSelectItemId() ); + if( nItemPos != VALUESET_ITEM_NOTFOUND ) + { + const USHORT nColCount = pValueSet->GetColCount(); + const USHORT nLine = nItemPos / nColCount; + + nLastColumn = nItemPos - (nLine * nColCount); + + if( bUp ) + { + return nLine > 0; + } + else + { + const USHORT nLineCount = (pValueSet->GetItemCount() + nColCount - 1) / nColCount; + return (nLine+1) < nLineCount; + } + } + } + + return false; +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry* ToolbarMenu::implCursorUpDown( bool bUp, bool bHomeEnd ) +{ + int n = 0, nLoop = 0; + if( !bHomeEnd ) + { + n = mpImpl->mnHighlightedEntry; + if( n == -1 ) + { + if( bUp ) + n = 0; + else + n = mpImpl->maEntryVector.size()-1; + } + else + { + // if we have a currently selected entry and + // cursor keys are used than check if this entry + // has a control that can use those cursor keys + ToolbarMenuEntry* pData = mpImpl->maEntryVector[n]; + if( pData && pData->mpControl && !pData->mbHasText ) + { + if( implCheckSubControlCursorMove( pData->mpControl, bUp, mpImpl->mnLastColumn ) ) + return pData; + } + } + nLoop = n; + } + else + { + // absolute positioning + if( bUp ) + { + n = mpImpl->maEntryVector.size(); + nLoop = n-1; + } + else + { + n = -1; + nLoop = mpImpl->maEntryVector.size()-1; + } + } + + do + { + if( bUp ) + { + if ( n ) + n--; + else + if( mpImpl->mnHighlightedEntry == -1 ) + n = mpImpl->maEntryVector.size()-1; + else + break; + } + else + { + if( n < ((int)mpImpl->maEntryVector.size()-1) ) + n++; + else + if( mpImpl->mnHighlightedEntry == -1 ) + n = 0; + else + break; + } + + ToolbarMenuEntry* pData = mpImpl->maEntryVector[n]; + if( pData && (pData->mnEntryId != TITLE_ID) ) + { + implChangeHighlightEntry( n ); + return pData; + } + } while ( n != nLoop ); + + return 0; +} + +// -------------------------------------------------------------------- + +void ToolbarMenu_Impl::implHighlightControl( USHORT nCode, Control* pControl ) +{ + ValueSet* pValueSet = dynamic_cast< ValueSet* >( pControl ); + if( pValueSet ) + { + const USHORT nItemCount = pValueSet->GetItemCount(); + USHORT nItemPos = VALUESET_ITEM_NOTFOUND; + switch( nCode ) + { + case KEY_UP: + { + const USHORT nColCount = pValueSet->GetColCount(); + const USHORT nLastLine = nItemCount / nColCount; + nItemPos = std::min( ((nLastLine-1) * nColCount) + mnLastColumn, nItemCount-1 ); + break; + } + case KEY_DOWN: + nItemPos = std::min( mnLastColumn, nItemCount-1 ); + break; + case KEY_END: + nItemPos = nItemCount -1; + break; + case KEY_HOME: + nItemPos = 0; + break; + } + pValueSet->SelectItem( pValueSet->GetItemId( nItemPos ) ); + notifyHighlightedEntry(); + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::KeyInput( const KeyEvent& rKEvent ) +{ + Control* pForwardControl = 0; + USHORT nCode = rKEvent.GetKeyCode().GetCode(); + switch ( nCode ) + { + case KEY_UP: + case KEY_DOWN: + { + int nOldEntry = mpImpl->mnHighlightedEntry; + ToolbarMenuEntry*p = implCursorUpDown( nCode == KEY_UP, false ); + if( p && p->mpControl ) + { + if( nOldEntry != mpImpl->mnHighlightedEntry ) + { + mpImpl->implHighlightControl( nCode, p->mpControl ); + } + else + { + // in case we are in a system floating window, GrabFocus does not work :-/ + pForwardControl = p->mpControl; + } + } + } + break; + case KEY_END: + case KEY_HOME: + { + ToolbarMenuEntry* p = implCursorUpDown( nCode == KEY_END, true ); + if( p && p->mpControl ) + { + mpImpl->implHighlightControl( nCode, p->mpControl ); + } + } + break; + case KEY_F6: + case KEY_ESCAPE: + { + // Ctrl-F6 acts like ESC here, the menu bar however will then put the focus in the document + if( nCode == KEY_F6 && !rKEvent.GetKeyCode().IsMod1() ) + break; + + implSelectEntry( -1 ); + } + break; + + case KEY_RETURN: + { + ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnHighlightedEntry ); + if ( pEntry && pEntry->mbEnabled && (pEntry->mnEntryId != TITLE_ID) ) + { + if( pEntry->mpControl ) + { + pForwardControl = pEntry->mpControl; + } + else + { + implSelectEntry( mpImpl->mnHighlightedEntry ); + } + } + } + break; + default: + { + ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnHighlightedEntry ); + if ( pEntry && pEntry->mbEnabled && pEntry->mpControl && !pEntry->mbHasText ) + { + pForwardControl = pEntry->mpControl; + } + } + + } + if( pForwardControl ) + pForwardControl->KeyInput( rKEvent ); + +} + +// -------------------------------------------------------------------- +static void ImplPaintCheckBackground( Window* i_pWindow, const Rectangle& i_rRect, bool i_bHighlight ) +{ + BOOL bNativeOk = FALSE; + if( i_pWindow->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) ) + { + ImplControlValue aControlValue; + ControlState nState = CTRL_STATE_PRESSED | CTRL_STATE_ENABLED; + + aControlValue.setTristateVal( BUTTONVALUE_ON ); + + bNativeOk = i_pWindow->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON, + i_rRect, nState, aControlValue, + rtl::OUString() ); + } + + if( ! bNativeOk ) + { + const StyleSettings& rSettings = i_pWindow->GetSettings().GetStyleSettings(); + Color aColor( i_bHighlight ? rSettings.GetMenuHighlightTextColor() : rSettings.GetHighlightColor() ); + i_pWindow->DrawSelectionBackground( i_rRect, 0, i_bHighlight, TRUE, FALSE, 2, NULL, &aColor ); + } +} + +static long ImplGetNativeCheckAndRadioSize( Window* pWin, long& rCheckHeight, long& rRadioHeight, long &rMaxWidth ) +{ + rMaxWidth = rCheckHeight = rRadioHeight = 0; + + ImplControlValue aVal; + Rectangle aNativeBounds; + Rectangle aNativeContent; + Point tmp( 0, 0 ); + Rectangle aCtrlRegion( tmp, Size( 100, 15 ) ); + if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_CHECK_MARK ) ) + { + if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP), + ControlPart(PART_MENU_ITEM_CHECK_MARK), + aCtrlRegion, + ControlState(CTRL_STATE_ENABLED), + aVal, + OUString(), + aNativeBounds, + aNativeContent ) + ) + { + rCheckHeight = aNativeBounds.GetHeight(); + rMaxWidth = aNativeContent.GetWidth(); + } + } + if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_RADIO_MARK ) ) + { + if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP), + ControlPart(PART_MENU_ITEM_RADIO_MARK), + aCtrlRegion, + ControlState(CTRL_STATE_ENABLED), + aVal, + OUString(), + aNativeBounds, + aNativeContent ) + ) + { + rRadioHeight = aNativeBounds.GetHeight(); + rMaxWidth = Max (rMaxWidth, aNativeContent.GetWidth()); + } + } + return (rCheckHeight > rRadioHeight) ? rCheckHeight : rRadioHeight; +} + +void ToolbarMenu::implPaint( ToolbarMenuEntry* pThisOnly, bool bHighlighted ) +{ + USHORT nBorder = 0; long nStartY = 0; // from Menu implementations, needed when we support native menu background & scrollable menu + + long nFontHeight = GetTextHeight(); +// long nExtra = nFontHeight/4; + + long nCheckHeight = 0, nRadioHeight = 0, nMaxCheckWidth = 0; + ImplGetNativeCheckAndRadioSize( this, nCheckHeight, nRadioHeight, nMaxCheckWidth ); + + DecorationView aDecoView( this ); + const StyleSettings& rSettings = GetSettings().GetStyleSettings(); + const bool bUseImages = rSettings.GetUseImagesInMenus(); + + int nOuterSpace = 0; // ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder; + Point aTopLeft( nOuterSpace, nOuterSpace ), aTmpPos; + + Size aOutSz( GetOutputSizePixel() ); + const int nEntryCount = mpImpl->maEntryVector.size(); + int nEntry; + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry]; + + Point aPos( aTopLeft ); + aPos.Y() += nBorder; + aPos.Y() += nStartY; + + + if( (pEntry == 0) && !pThisOnly ) + { + // Separator + aTmpPos.Y() = aPos.Y() + ((SEPARATOR_HEIGHT-2)/2); + aTmpPos.X() = aPos.X() + 2 + nOuterSpace; + SetLineColor( rSettings.GetShadowColor() ); + DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) ); + aTmpPos.Y()++; + SetLineColor( rSettings.GetLightColor() ); + DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) ); + SetLineColor(); + } + else if( !pThisOnly || ( pEntry == pThisOnly ) ) + { + const bool bTitle = pEntry->mnEntryId == TITLE_ID; + + if ( pThisOnly && bHighlighted ) + SetTextColor( rSettings.GetMenuHighlightTextColor() ); + + if( aPos.Y() >= 0 ) + { + long nTextOffsetY = ((pEntry->maSize.Height()-nFontHeight)/2); + + USHORT nTextStyle = 0; + USHORT nSymbolStyle = 0; + USHORT nImageStyle = 0; + + if( !pEntry->mbEnabled ) + { + nTextStyle |= TEXT_DRAW_DISABLE; + nSymbolStyle |= SYMBOL_DRAW_DISABLE; + nImageStyle |= IMAGE_DRAW_DISABLE; + } + + Rectangle aOuterCheckRect( Point( aPos.X()+mpImpl->mnCheckPos, aPos.Y() ), Size( pEntry->maSize.Height(), pEntry->maSize.Height() ) ); + aOuterCheckRect.Left() += 1; + aOuterCheckRect.Right() -= 1; + aOuterCheckRect.Top() += 1; + aOuterCheckRect.Bottom() -= 1; + + if( bTitle ) + { + // fill the background + Rectangle aRect( aTopLeft, Size( aOutSz.Width(), pEntry->maSize.Height() ) ); + SetFillColor(rSettings.GetDialogColor()); + SetLineColor(); + DrawRect(aRect); + SetLineColor( rSettings.GetLightColor() ); + DrawLine( aRect.TopLeft(), aRect.TopRight() ); + SetLineColor( rSettings.GetShadowColor() ); + DrawLine( aRect.BottomLeft(), aRect.BottomRight() ); + } + + // CheckMark + if ( pEntry->HasCheck() ) + { + // draw selection transparent marker if checked + // onto that either a checkmark or the item image + // will be painted + // however do not do this if native checks will be painted since + // the selection color too often does not fit the theme's check and/or radio + + if( !pEntry->mbHasImage ) + { + if( this->IsNativeControlSupported( CTRL_MENU_POPUP, + (pEntry->mnBits & MIB_RADIOCHECK) + ? PART_MENU_ITEM_CHECK_MARK + : PART_MENU_ITEM_RADIO_MARK ) ) + { + ControlPart nPart = ((pEntry->mnBits & MIB_RADIOCHECK) + ? PART_MENU_ITEM_RADIO_MARK + : PART_MENU_ITEM_CHECK_MARK); + + ControlState nState = 0; + + if ( pEntry->mbChecked ) + nState |= CTRL_STATE_PRESSED; + + if ( pEntry->mbEnabled ) + nState |= CTRL_STATE_ENABLED; + + if ( bHighlighted ) + nState |= CTRL_STATE_SELECTED; + + long nCtrlHeight = (pEntry->mnBits & MIB_RADIOCHECK) ? nCheckHeight : nRadioHeight; + aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - nCtrlHeight)/2; + aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - nCtrlHeight)/2; + + Rectangle aCheckRect( aTmpPos, Size( nCtrlHeight, nCtrlHeight ) ); + DrawNativeControl( CTRL_MENU_POPUP, nPart, aCheckRect, nState, ImplControlValue(), OUString() ); + } + else if ( pEntry->mbChecked ) // by default do nothing for unchecked items + { + ImplPaintCheckBackground( this, aOuterCheckRect, pThisOnly && bHighlighted ); + + SymbolType eSymbol; + Size aSymbolSize; + if ( pEntry->mnBits & MIB_RADIOCHECK ) + { + eSymbol = SYMBOL_RADIOCHECKMARK; + aSymbolSize = Size( nFontHeight/2, nFontHeight/2 ); + } + else + { + eSymbol = SYMBOL_CHECKMARK; + aSymbolSize = Size( (nFontHeight*25)/40, nFontHeight/2 ); + } + aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - aSymbolSize.Width())/2; + aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - aSymbolSize.Height())/2; + Rectangle aRect( aTmpPos, aSymbolSize ); + aDecoView.DrawSymbol( aRect, eSymbol, GetTextColor(), nSymbolStyle ); + } + } + } + + // Image: + if( pEntry->mbHasImage && bUseImages ) + { + // Don't render an image for a check thing + /* if((nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES) || !pEntry->HasCheck() )*/ + { + if( pEntry->mbChecked ) + ImplPaintCheckBackground( this, aOuterCheckRect, pThisOnly && bHighlighted ); + aTmpPos = aOuterCheckRect.TopLeft(); + aTmpPos.X() += (aOuterCheckRect.GetWidth()-pEntry->maImage.GetSizePixel().Width())/2; + aTmpPos.Y() += (aOuterCheckRect.GetHeight()-pEntry->maImage.GetSizePixel().Height())/2; + DrawImage( aTmpPos, pEntry->maImage, nImageStyle ); + } + } + + // Text: + if( pEntry->mbHasText ) + { + aTmpPos.X() = aPos.X() + (bTitle ? 4 : mpImpl->mnTextPos); + aTmpPos.Y() = aPos.Y(); + aTmpPos.Y() += nTextOffsetY; + USHORT nStyle = nTextStyle|TEXT_DRAW_MNEMONIC; + + DrawCtrlText( aTmpPos, pEntry->maText, 0, pEntry->maText.Len(), nStyle, NULL, NULL ); // pVector, pDisplayText ); + } + +/* + // Accel + if ( !bLayout && !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() ) + { + XubString aAccText = pData->aAccelKey.GetName(); + aTmpPos.X() = aOutSz.Width() - this->GetTextWidth( aAccText ); + aTmpPos.X() -= 4*nExtra; + + aTmpPos.X() -= nOuterSpace; + aTmpPos.Y() = aPos.Y(); + aTmpPos.Y() += nTextOffsetY; + this->DrawCtrlText( aTmpPos, aAccText, 0, aAccText.Len(), nTextStyle ); + } +*/ + +/* + // SubMenu? + if ( !bLayout && !bIsMenuBar && pData->pSubMenu ) + { + aTmpPos.X() = aOutSz.Width() - nFontHeight + nExtra - nOuterSpace; + aTmpPos.Y() = aPos.Y(); + aTmpPos.Y() += nExtra/2; + aTmpPos.Y() += ( pEntry->maSize.Height() / 2 ) - ( nFontHeight/4 ); + if ( pEntry->mnBits & MIB_POPUPSELECT ) + { + this->SetTextColor( rSettings.GetMenuTextColor() ); + Point aTmpPos2( aPos ); + aTmpPos2.X() = aOutSz.Width() - nFontHeight - nFontHeight/4; + aDecoView.DrawFrame( + Rectangle( aTmpPos2, Size( nFontHeight+nFontHeight/4, pEntry->maSize.Height() ) ), FRAME_DRAW_GROUP ); + } + aDecoView.DrawSymbol( + Rectangle( aTmpPos, Size( nFontHeight/2, nFontHeight/2 ) ), + SYMBOL_SPIN_RIGHT, this->GetTextColor(), nSymbolStyle ); +// if ( pEntry->mnBits & MIB_POPUPSELECT ) +// { +// aTmpPos.Y() += nFontHeight/2 ; +// this->SetLineColor( rSettings.GetShadowColor() ); +// this->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) ); +// this->SetLineColor( rSettings.GetLightColor() ); +// aTmpPos.Y()++; +// this->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) ); +// this->SetLineColor(); +// } + } +*/ + + if ( pThisOnly && bHighlighted ) + { + // This restores the normal menu or menu bar text + // color for when it is no longer highlighted. + SetTextColor( rSettings.GetMenuTextColor() ); + } + } + } + + aTopLeft.Y() += pEntry ? pEntry->maSize.Height() : SEPARATOR_HEIGHT; + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::Paint( const Rectangle& ) +{ + SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() ); + + implPaint(); + + if( mpImpl->mnHighlightedEntry != -1 ) + implHighlightEntry( mpImpl->mnHighlightedEntry, true ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::RequestHelp( const HelpEvent& rHEvt ) +{ + DockingWindow::RequestHelp( rHEvt ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::StateChanged( StateChangedType nType ) +{ + DockingWindow::StateChanged( nType ); + + if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || ( nType == STATE_CHANGE_CONTROLBACKGROUND ) ) + { + initWindow(); + Invalidate(); + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::DataChanged( const DataChangedEvent& rDCEvt ) +{ + DockingWindow::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + initWindow(); + Invalidate(); + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::Command( const CommandEvent& rCEvt ) +{ + if ( rCEvt.GetCommand() == COMMAND_WHEEL ) + { + const CommandWheelData* pData = rCEvt.GetWheelData(); + if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) ) + { + implCursorUpDown( pData->GetDelta() > 0L, false ); + } + } +} + +// -------------------------------------------------------------------- + +Reference< ::com::sun::star::accessibility::XAccessible > ToolbarMenu::CreateAccessible() +{ + mpImpl->setAccessible( new ToolbarMenuAcc( *mpImpl ) ); + return Reference< XAccessible >( mpImpl->mxAccessible.get() ); +} + +// -------------------------------------------------------------------- + +// todo: move to new base class that will replace SfxPopupWindo +void ToolbarMenu::AddStatusListener( const rtl::OUString& rCommandURL ) +{ + initStatusListener(); + mpImpl->mxStatusListener->addStatusListener( rCommandURL ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::RemoveStatusListener( const rtl::OUString& rCommandURL ) +{ + mpImpl->mxStatusListener->removeStatusListener( rCommandURL ); +} +// -------------------------------------------------------------------- + + +void ToolbarMenu::UpdateStatus( const rtl::OUString& rCommandURL ) +{ + mpImpl->mxStatusListener->updateStatus( rCommandURL ); +} + +// -------------------------------------------------------------------- + +// XStatusListener (subclasses must override this one to get the status updates +void SAL_CALL ToolbarMenu::statusChanged( const ::com::sun::star::frame::FeatureStateEvent& /*Event*/ ) throw ( ::com::sun::star::uno::RuntimeException ) +{ +} + +// -------------------------------------------------------------------- + +class ToolbarMenuStatusListener : public svt::FrameStatusListener +{ +public: + ToolbarMenuStatusListener( const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& xServiceManager, + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame, + ToolbarMenu& rToolbarMenu ); + + virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL statusChanged( const ::com::sun::star::frame::FeatureStateEvent& Event ) throw ( ::com::sun::star::uno::RuntimeException ); + + ToolbarMenu* mpMenu; +}; + +// -------------------------------------------------------------------- + +ToolbarMenuStatusListener::ToolbarMenuStatusListener( + const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& xServiceManager, + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame, + ToolbarMenu& rToolbarMenu ) +: svt::FrameStatusListener( xServiceManager, xFrame ) +, mpMenu( &rToolbarMenu ) +{ +} + +// -------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuStatusListener::dispose() throw (::com::sun::star::uno::RuntimeException) +{ + mpMenu = 0; + svt::FrameStatusListener::dispose(); +} + +// -------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuStatusListener::statusChanged( const ::com::sun::star::frame::FeatureStateEvent& Event ) throw ( ::com::sun::star::uno::RuntimeException ) +{ + if( mpMenu ) + mpMenu->statusChanged( Event ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::initStatusListener() +{ + if( !mpImpl->mxStatusListener.is() ) + mpImpl->mxStatusListener.set( new ToolbarMenuStatusListener( mpImpl->mxServiceManager, mpImpl->mxFrame, *this ) ); +} + +// -------------------------------------------------------------------- + +bool ToolbarMenu::IsInPopupMode() +{ + return GetDockingManager()->IsInPopupMode(this); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::EndPopupMode() +{ + GetDockingManager()->EndPopupMode(this); +} + +// -------------------------------------------------------------------- + +const Size& ToolbarMenu::getMenuSize() const +{ + return mpImpl->maSize; +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::SetSelectHdl( const Link& rLink ) +{ + mpImpl->maSelectHdl = rLink; +} + +// -------------------------------------------------------------------- + +const Link& ToolbarMenu::GetSelectHdl() const +{ + return mpImpl->maSelectHdl; +} + +// -------------------------------------------------------------------- + +Reference< XFrame > ToolbarMenu::GetFrame() const +{ + return mpImpl->mxFrame; +} + +// -------------------------------------------------------------------- + + +// -------------------------------------------------------------------- + +} + + diff --git a/svtools/source/control/toolbarmenuacc.cxx b/svtools/source/control/toolbarmenuacc.cxx new file mode 100644 index 000000000000..020467084748 --- /dev/null +++ b/svtools/source/control/toolbarmenuacc.cxx @@ -0,0 +1,1003 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +#include <unotools/accessiblestatesethelper.hxx> + +#include <vcl/svapp.hxx> + +#include "svtools/toolbarmenu.hxx" + +#include "toolbarmenuimp.hxx" + +using ::rtl::OUString; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::accessibility; + +namespace svtools { + +// ------------------ +// - ToolbarMenuAcc - +// ------------------ + +ToolbarMenuAcc::ToolbarMenuAcc( ToolbarMenu_Impl& rParent ) +: ToolbarMenuAccComponentBase(m_aMutex) +, mpParent( &rParent ) +, mbIsFocused(false) +{ + mpParent->mrMenu.AddEventListener( LINK( this, ToolbarMenuAcc, WindowEventListener ) ); +} + +// ----------------------------------------------------------------------------- + +ToolbarMenuAcc::~ToolbarMenuAcc() +{ + if( mpParent ) + mpParent->mrMenu.RemoveEventListener( LINK( this, ToolbarMenuAcc, WindowEventListener ) ); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( ToolbarMenuAcc, WindowEventListener, VclSimpleEvent*, pEvent ) +{ + DBG_ASSERT( pEvent && pEvent->ISA( VclWindowEvent ), "Unknown WindowEvent!" ); + + /* Ignore VCLEVENT_WINDOW_ENDPOPUPMODE, because the UNO accessibility wrapper + * might have been destroyed by the previous VCLEventListener (if no AT tool + * is running), e.g. sub-toolbars in impress. + */ + if ( mpParent && pEvent && pEvent->ISA( VclWindowEvent ) && (pEvent->GetId() != VCLEVENT_WINDOW_ENDPOPUPMODE) ) + { + DBG_ASSERT( ((VclWindowEvent*)pEvent)->GetWindow(), "Window???" ); + if( !((VclWindowEvent*)pEvent)->GetWindow()->IsAccessibilityEventsSuppressed() || ( pEvent->GetId() == VCLEVENT_OBJECT_DYING ) ) + { + ProcessWindowEvent( *(VclWindowEvent*)pEvent ); + } + } + return 0; +} + +// ----------------------------------------------------------------------- + +void ToolbarMenuAcc::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) +{ + Any aOldValue, aNewValue; + + switch ( rVclWindowEvent.GetId() ) + { + case VCLEVENT_OBJECT_DYING: + { + mpParent->mrMenu.RemoveEventListener( LINK( this, ToolbarMenuAcc, WindowEventListener ) ); + mpParent = 0; + } + break; + + case VCLEVENT_WINDOW_GETFOCUS: + { + if( !mbIsFocused ) + { + mpParent->notifyHighlightedEntry(); + mbIsFocused = true; + } + } + break; + case VCLEVENT_WINDOW_LOSEFOCUS: + { + if( mbIsFocused ) + { + mbIsFocused = false; + } + } + break; + default: + { + } + break; + } +} + +// ----------------------------------------------------------------------- + +void ToolbarMenuAcc::FireAccessibleEvent( short nEventId, const Any& rOldValue, const Any& rNewValue ) +{ + if( nEventId ) + { + EventListenerVector aTmpListeners( mxEventListeners ); + EventListenerVector::const_iterator aIter( aTmpListeners.begin() ); + AccessibleEventObject aEvtObject; + + aEvtObject.EventId = nEventId; + aEvtObject.Source = static_cast<XWeak*>(this); + aEvtObject.NewValue = rNewValue; + aEvtObject.OldValue = rOldValue; + + while( aIter != aTmpListeners.end() ) + { + try + { + (*aIter)->notifyEvent( aEvtObject ); + } + catch( Exception& ) + { + } + + aIter++; + } + } +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessibleContext > SAL_CALL ToolbarMenuAcc::getAccessibleContext() throw (RuntimeException) +{ + ThrowIfDisposed(); + return this; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuAcc::getAccessibleChildCount() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + + return mpParent->getAccessibleChildCount(); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuAcc::getAccessibleChild( sal_Int32 i ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + + return mpParent->getAccessibleChild(i); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuAcc::getAccessibleParent() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + + Reference< XAccessible > xRet; + + Window* pParent = mpParent->mrMenu.GetParent(); + if( pParent ) + xRet = pParent->GetAccessible(); + + return xRet; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuAcc::getAccessibleIndexInParent() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + + Window* pParent = mpParent->mrMenu.GetParent(); + if( pParent ) + { + for( USHORT i = 0, nCount = pParent->GetChildCount(); i < nCount ; i++ ) + { + if( pParent->GetChild( i ) == &mpParent->mrMenu ) + return i; + } + } + + return 0; +} + +// ----------------------------------------------------------------------------- + +sal_Int16 SAL_CALL ToolbarMenuAcc::getAccessibleRole() throw (RuntimeException) +{ + ThrowIfDisposed(); + return AccessibleRole::LIST; +} + +// ----------------------------------------------------------------------------- + +OUString SAL_CALL ToolbarMenuAcc::getAccessibleDescription() throw (RuntimeException) +{ + ThrowIfDisposed(); + return OUString( RTL_CONSTASCII_USTRINGPARAM( "ToolbarMenu" ) ); +} + +// ----------------------------------------------------------------------------- + +OUString SAL_CALL ToolbarMenuAcc::getAccessibleName() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + OUString aRet; + + if( mpParent ) + aRet = mpParent->mrMenu.GetAccessibleName(); + + if( !aRet.getLength() ) + { + Window* pLabel = mpParent->mrMenu.GetLabeledBy(); + if( pLabel && pLabel != &mpParent->mrMenu ) + aRet = OutputDevice::GetNonMnemonicString( pLabel->GetText() ); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessibleRelationSet > SAL_CALL ToolbarMenuAcc::getAccessibleRelationSet() throw (RuntimeException) +{ + ThrowIfDisposed(); + return Reference< XAccessibleRelationSet >(); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessibleStateSet > SAL_CALL ToolbarMenuAcc::getAccessibleStateSet() throw (RuntimeException) +{ + ThrowIfDisposed(); + ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper(); + + // Set some states. + pStateSet->AddState (AccessibleStateType::ENABLED); + pStateSet->AddState (AccessibleStateType::SENSITIVE); + pStateSet->AddState (AccessibleStateType::SHOWING); + pStateSet->AddState (AccessibleStateType::VISIBLE); + pStateSet->AddState (AccessibleStateType::MANAGES_DESCENDANTS); + pStateSet->AddState (AccessibleStateType::FOCUSABLE); + if (mbIsFocused) + pStateSet->AddState (AccessibleStateType::FOCUSED); + + return pStateSet; +} + +// ----------------------------------------------------------------------------- + +Locale SAL_CALL ToolbarMenuAcc::getLocale() throw (IllegalAccessibleComponentStateException, RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const ::rtl::OUString aEmptyStr; + Reference< XAccessible > xParent( getAccessibleParent() ); + Locale aRet( aEmptyStr, aEmptyStr, aEmptyStr ); + + if( xParent.is() ) + { + Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() ); + + if( xParentContext.is() ) + aRet = xParentContext->getLocale (); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::addEventListener( const Reference< XAccessibleEventListener >& rxListener ) throw (RuntimeException) +{ + ThrowIfDisposed(); + ::osl::MutexGuard aGuard(m_aMutex); + + if( rxListener.is() ) + { + EventListenerVector::const_iterator aIter = mxEventListeners.begin(); + bool bFound = false; + + while( !bFound && ( aIter != mxEventListeners.end() ) ) + { + if( *aIter == rxListener ) + bFound = true; + else + aIter++; + } + + if (!bFound) + mxEventListeners.push_back( rxListener ); + } +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::removeEventListener( const Reference< XAccessibleEventListener >& rxListener ) throw (RuntimeException) +{ + ThrowIfDisposed(); + ::osl::MutexGuard aGuard(m_aMutex); + + if( rxListener.is() ) + { + EventListenerVector::iterator aIter = mxEventListeners.begin(); + bool bFound = false; + + while( !bFound && ( aIter != mxEventListeners.end() ) ) + { + if( *aIter == rxListener ) + { + mxEventListeners.erase( aIter ); + bFound = true; + } + else + aIter++; + } + } +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL ToolbarMenuAcc::containsPoint( const awt::Point& aPoint ) throw (RuntimeException) +{ + ThrowIfDisposed(); + const awt::Rectangle aRect( getBounds() ); + const Point aSize( aRect.Width, aRect.Height ); + const Point aNullPoint, aTestPoint( aPoint.X, aPoint.Y ); + + return Rectangle( aNullPoint, aSize ).IsInside( aTestPoint ); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuAcc::getAccessibleAtPoint( const awt::Point& aPoint ) throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + + Reference< XAccessible > xRet; + + const Point aVclPoint( aPoint.X, aPoint.Y ); + + const int nEntryCount = mpParent->maEntryVector.size(); + for( int nEntry = 0; (nEntry < nEntryCount) && !xRet.is(); nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpParent->maEntryVector[nEntry]; + if( pEntry && pEntry->maRect.IsInside( aVclPoint ) ) + { + if( pEntry->mpControl ) + { + awt::Point aChildPoint( aPoint.X - pEntry->maRect.Left(), aPoint.Y - pEntry->maRect.Top() ); + Reference< XAccessibleComponent > xComp( pEntry->GetAccessible(true), UNO_QUERY_THROW ); + xRet = xComp->getAccessibleAtPoint(aChildPoint); + } + else + { + xRet = Reference< XAccessible >( pEntry->GetAccessible(true), UNO_QUERY ); + } + } + } + return xRet; +} + +// ----------------------------------------------------------------------------- + +awt::Rectangle SAL_CALL ToolbarMenuAcc::getBounds() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const Point aOutPos( mpParent->mrMenu.GetPosPixel() ); + const Size aOutSize( mpParent->mrMenu.GetOutputSizePixel() ); + awt::Rectangle aRet; + + aRet.X = aOutPos.X(); + aRet.Y = aOutPos.Y(); + aRet.Width = aOutSize.Width(); + aRet.Height = aOutSize.Height(); + + return aRet; +} + +// ----------------------------------------------------------------------------- + +awt::Point SAL_CALL ToolbarMenuAcc::getLocation() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const Point aOutPos( mpParent->mrMenu.GetPosPixel() ); + return awt::Point( aOutPos.X(), aOutPos.Y() ); +} + +// ----------------------------------------------------------------------------- + +awt::Point SAL_CALL ToolbarMenuAcc::getLocationOnScreen() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const Point aScreenPos( mpParent->mrMenu.OutputToAbsoluteScreenPixel( Point() ) ); + return awt::Point( aScreenPos.X(), aScreenPos.Y() ); +} + +// ----------------------------------------------------------------------------- + +awt::Size SAL_CALL ToolbarMenuAcc::getSize() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const Size aOutSize( mpParent->mrMenu.GetOutputSizePixel() ); + return awt::Size( aOutSize.Width(), aOutSize.Height() ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::grabFocus() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + mpParent->mrMenu.GrabFocus(); +} + +// ----------------------------------------------------------------------------- + +Any SAL_CALL ToolbarMenuAcc::getAccessibleKeyBinding() throw (RuntimeException) +{ + ThrowIfDisposed(); + return Any(); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuAcc::getForeground() throw (RuntimeException) +{ + ThrowIfDisposed(); + UINT32 nColor = Application::GetSettings().GetStyleSettings().GetMenuTextColor().GetColor(); + return static_cast<sal_Int32>(nColor); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuAcc::getBackground() throw (RuntimeException) +{ + ThrowIfDisposed(); + UINT32 nColor = Application::GetSettings().GetStyleSettings().GetMenuColor().GetColor(); + return static_cast<sal_Int32>(nColor); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + + mpParent->selectAccessibleChild( nChildIndex ); +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL ToolbarMenuAcc::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + return mpParent->isAccessibleChildSelected( nChildIndex ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::clearAccessibleSelection() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + mpParent->clearAccessibleSelection(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::selectAllAccessibleChildren() throw (RuntimeException) +{ + ThrowIfDisposed(); + // unsupported due to single selection only +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuAcc::getSelectedAccessibleChildCount() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + + return mpParent->mnHighlightedEntry != -1 ? 1 : 0; +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuAcc::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + + if( (mpParent->mnHighlightedEntry != -1) && (nSelectedChildIndex == 0) ) + { + ToolbarMenuEntry* pEntry = mpParent->maEntryVector[ mpParent->mnHighlightedEntry ]; + if( pEntry ) + { + if( pEntry->mpControl ) + { + Reference< XAccessibleSelection > xSel( pEntry->GetAccessible(true), UNO_QUERY_THROW ); + return xSel->getSelectedAccessibleChild(0); + } + else + return Reference< XAccessible >( pEntry->GetAccessible(true), UNO_QUERY ); + } + } + + throw IndexOutOfBoundsException(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::deselectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + // Because of the single selection we can reset the whole selection when + // the specified child is currently selected. + if (isAccessibleChildSelected(nChildIndex)) + mpParent->clearAccessibleSelection(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::disposing (void) +{ + EventListenerVector aListenerListCopy; + + { + // Make a copy of the list and clear the original. + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ::osl::MutexGuard aGuard (m_aMutex); + aListenerListCopy = mxEventListeners; + mxEventListeners.clear(); + + // Reset the pointer to the parent. It has to be the one who has + // disposed us because he is dying. + mpParent = NULL; + } + + // Inform all listeners that this objects is disposing. + EventListenerVector::const_iterator aListenerIterator (aListenerListCopy.begin()); + EventObject aEvent (static_cast<XAccessible*>(this)); + while(aListenerIterator != aListenerListCopy.end()) + { + try + { + (*aListenerIterator)->disposing (aEvent); + } + catch( Exception& ) + { + // Ignore exceptions. + } + + ++aListenerIterator; + } +} + +void ToolbarMenuAcc::ThrowIfDisposed (void) throw (DisposedException) +{ + if(rBHelper.bDisposed || rBHelper.bInDispose || !mpParent) + { + throw DisposedException ( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")), static_cast<XWeak*>(this)); + } +} + +// ----------------------- +// - ToolbarMenuEntryAcc - +// ----------------------- + +ToolbarMenuEntryAcc::ToolbarMenuEntryAcc( ToolbarMenuEntry* pParent ) +: ToolbarMenuEntryAccBase( m_aMutex ) +, mpParent( pParent ) +{ +} + +// ----------------------------------------------------------------------------- + +ToolbarMenuEntryAcc::~ToolbarMenuEntryAcc() +{ +} + +// ----------------------------------------------------------------------- + +void ToolbarMenuEntryAcc::FireAccessibleEvent( short nEventId, const Any& rOldValue, const Any& rNewValue ) +{ + if( nEventId ) + { + EventListenerVector aTmpListeners( mxEventListeners ); + ::std::vector< Reference< XAccessibleEventListener > >::const_iterator aIter( aTmpListeners.begin() ); + AccessibleEventObject aEvtObject; + + aEvtObject.EventId = nEventId; + aEvtObject.Source = static_cast<XWeak*>(this); + aEvtObject.NewValue = rNewValue; + aEvtObject.OldValue = rOldValue; + + while( aIter != aTmpListeners.end() ) + { + (*aIter)->notifyEvent( aEvtObject ); + aIter++; + } + } +} + + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuEntryAcc::disposing (void) +{ + EventListenerVector aListenerListCopy; + + { + // Make a copy of the list and clear the original. + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ::osl::MutexGuard aGuard (m_aMutex); + aListenerListCopy = mxEventListeners; + mxEventListeners.clear(); + + // Reset the pointer to the parent. It has to be the one who has + // disposed us because he is dying. + mpParent = NULL; + } + + // Inform all listeners that this objects is disposing. + EventListenerVector::const_iterator aListenerIterator (aListenerListCopy.begin()); + EventObject aEvent (static_cast<XAccessible*>(this)); + while(aListenerIterator != aListenerListCopy.end()) + { + try + { + (*aListenerIterator)->disposing (aEvent); + } + catch( Exception& ) + { + // Ignore exceptions. + } + + ++aListenerIterator; + } +} +// ----------------------------------------------------------------------------- + +Reference< XAccessibleContext > SAL_CALL ToolbarMenuEntryAcc::getAccessibleContext() throw (RuntimeException) +{ + return this; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuEntryAcc::getAccessibleChildCount() throw (RuntimeException) +{ + return 0; +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuEntryAcc::getAccessibleChild( sal_Int32 ) throw (IndexOutOfBoundsException, RuntimeException) +{ + throw IndexOutOfBoundsException(); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuEntryAcc::getAccessibleParent() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + Reference< XAccessible > xRet; + + if( mpParent ) + xRet = mpParent->mrMenu.GetAccessible(); + + return xRet; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuEntryAcc::getAccessibleIndexInParent() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + // The index defaults to -1 to indicate the child does not belong to its + // parent. + sal_Int32 nIndexInParent = -1; + + if( mpParent ) + { + Reference< XAccessibleContext > xParent( mpParent->mrMenu.GetAccessible(), UNO_QUERY ); + + if( xParent.is() ) + { + Reference< XAccessible > xThis( this ); + + const sal_Int32 nCount = xParent->getAccessibleChildCount(); + for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ ) + { + if( xParent->getAccessibleChild(nIndex) == xThis ) + { + nIndexInParent = nIndex; + break; + } + } + } + } + + return nIndexInParent; +} + +// ----------------------------------------------------------------------------- + +sal_Int16 SAL_CALL ToolbarMenuEntryAcc::getAccessibleRole() throw (RuntimeException) +{ + return AccessibleRole::LIST_ITEM; +} + +// ----------------------------------------------------------------------------- + +::rtl::OUString SAL_CALL ToolbarMenuEntryAcc::getAccessibleDescription() throw (RuntimeException) +{ + return ::rtl::OUString(); +} + +// ----------------------------------------------------------------------------- + +::rtl::OUString SAL_CALL ToolbarMenuEntryAcc::getAccessibleName() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + String aRet; + + if( mpParent ) + { + aRet = mpParent->maText; + + if( !aRet.Len() ) + { + aRet = String( RTL_CONSTASCII_USTRINGPARAM( "Item " ) ); + aRet += String::CreateFromInt32( mpParent->mnEntryId ); + } + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessibleRelationSet > SAL_CALL ToolbarMenuEntryAcc::getAccessibleRelationSet() throw (RuntimeException) +{ + return Reference< XAccessibleRelationSet >(); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessibleStateSet > SAL_CALL ToolbarMenuEntryAcc::getAccessibleStateSet() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper; + + if( mpParent ) + { + pStateSet->AddState (AccessibleStateType::ENABLED); + pStateSet->AddState (AccessibleStateType::SENSITIVE); + pStateSet->AddState (AccessibleStateType::SHOWING); + pStateSet->AddState (AccessibleStateType::VISIBLE); + pStateSet->AddState (AccessibleStateType::TRANSIENT); + if( mpParent->mnEntryId != TITLE_ID ) + { + pStateSet->AddState( AccessibleStateType::SELECTABLE ); + + // SELECTED + if( mpParent->mrMenu.getHighlightedEntryId() == mpParent->mnEntryId ) + pStateSet->AddState( AccessibleStateType::SELECTED ); + } + } + + return pStateSet; +} + +// ----------------------------------------------------------------------------- + +Locale SAL_CALL ToolbarMenuEntryAcc::getLocale() throw (IllegalAccessibleComponentStateException, RuntimeException) +{ + const ::rtl::OUString aEmptyStr; + Locale aRet( aEmptyStr, aEmptyStr, aEmptyStr ); + + Reference< XAccessible > xParent( getAccessibleParent() ); + if( xParent.is() ) + { + Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() ); + + if( xParentContext.is() ) + aRet = xParentContext->getLocale(); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuEntryAcc::addEventListener( const Reference< XAccessibleEventListener >& rxListener ) throw (RuntimeException) +{ + const ::vos::OGuard aGuard( maMutex ); + + if( rxListener.is() ) + { + EventListenerVector::const_iterator aIter( mxEventListeners.begin() ); + bool bFound = false; + + while( !bFound && ( aIter != mxEventListeners.end() ) ) + { + if( *aIter == rxListener ) + bFound = true; + else + aIter++; + } + + if (!bFound) + mxEventListeners.push_back( rxListener ); + } +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuEntryAcc::removeEventListener( const Reference< XAccessibleEventListener >& rxListener ) throw (RuntimeException) +{ + const ::vos::OGuard aGuard( maMutex ); + + if( rxListener.is() ) + { + EventListenerVector::iterator aIter = mxEventListeners.begin(); + bool bFound = false; + + while( !bFound && ( aIter != mxEventListeners.end() ) ) + { + if( *aIter == rxListener ) + { + mxEventListeners.erase( aIter ); + bFound = true; + } + else + aIter++; + } + } +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL ToolbarMenuEntryAcc::containsPoint( const awt::Point& aPoint ) throw (RuntimeException) +{ + const awt::Rectangle aRect( getBounds() ); + const Point aSize( aRect.Width, aRect.Height ); + const Point aNullPoint, aTestPoint( aPoint.X, aPoint.Y ); + + return Rectangle( aNullPoint, aSize ).IsInside( aTestPoint ); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuEntryAcc::getAccessibleAtPoint( const awt::Point& ) throw (RuntimeException) +{ + Reference< XAccessible > xRet; + return xRet; +} + +// ----------------------------------------------------------------------------- + +awt::Rectangle SAL_CALL ToolbarMenuEntryAcc::getBounds() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + awt::Rectangle aRet; + + if( mpParent ) + { + Rectangle aRect( mpParent->maRect ); + Point aOrigin; + Rectangle aParentRect( aOrigin, mpParent->mrMenu.GetOutputSizePixel() ); + + aRect.Intersection( aParentRect ); + + aRet.X = aRect.Left(); + aRet.Y = aRect.Top(); + aRet.Width = aRect.GetWidth(); + aRet.Height = aRect.GetHeight(); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +awt::Point SAL_CALL ToolbarMenuEntryAcc::getLocation() throw (RuntimeException) +{ + const awt::Rectangle aRect( getBounds() ); + return awt::Point( aRect.X, aRect.Y ); +} + +// ----------------------------------------------------------------------------- + +awt::Point SAL_CALL ToolbarMenuEntryAcc::getLocationOnScreen() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + awt::Point aRet; + + if( mpParent ) + { + const Point aScreenPos( mpParent->mrMenu.OutputToAbsoluteScreenPixel( mpParent->maRect.TopLeft() ) ); + + aRet.X = aScreenPos.X(); + aRet.Y = aScreenPos.Y(); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +awt::Size SAL_CALL ToolbarMenuEntryAcc::getSize() throw (RuntimeException) +{ + const awt::Rectangle aRect( getBounds() ); + awt::Size aRet; + + aRet.Width = aRect.Width; + aRet.Height = aRect.Height; + + return aRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuEntryAcc::grabFocus() throw (RuntimeException) +{ + // nothing to do +} + +// ----------------------------------------------------------------------------- + +Any SAL_CALL ToolbarMenuEntryAcc::getAccessibleKeyBinding() throw (RuntimeException) +{ + return Any(); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuEntryAcc::getForeground( ) throw (RuntimeException) +{ + return static_cast<sal_Int32>(Application::GetSettings().GetStyleSettings().GetMenuTextColor().GetColor()); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuEntryAcc::getBackground( ) throw (RuntimeException) +{ + return static_cast<sal_Int32>(Application::GetSettings().GetStyleSettings().GetMenuColor().GetColor()); +} + +} diff --git a/svtools/source/control/toolbarmenuimp.hxx b/svtools/source/control/toolbarmenuimp.hxx new file mode 100644 index 000000000000..d1de4f704b76 --- /dev/null +++ b/svtools/source/control/toolbarmenuimp.hxx @@ -0,0 +1,314 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +#include <vos/mutex.hxx> +#include <vcl/image.hxx> +#include <vcl/menu.hxx> + +#include <cppuhelper/compbase4.hxx> +#include <cppuhelper/compbase5.hxx> +#include <comphelper/broadcasthelper.hxx> + +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleSelection.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/lang/DisposedException.hpp> + +#include <rtl/ref.hxx> + +#include <vector> + +#include "framestatuslistener.hxx" + +#include "svtools/valueset.hxx" + +namespace svtools { + +struct ToolbarMenu_Impl; +class ToolbarMenu; +class ToolbarMenuEntry; + +typedef ::std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener > > EventListenerVector; +typedef std::vector< ToolbarMenuEntry * > ToolbarMenuEntryVector; + +const int EXTRAITEMHEIGHT = 0; // 4; +const int SEPARATOR_HEIGHT = 4; +const int TITLE_ID = -1; +const int BORDER_X = 0; +const int BORDER_Y = 0; + +// -------------------- +// - ToolbarMenuEntry - +// -------------------- + +class ToolbarMenuEntry +{ +public: + ToolbarMenu& mrMenu; + + int mnEntryId; + MenuItemBits mnBits; + Size maSize; + + bool mbHasText; + bool mbHasImage; + bool mbChecked; + bool mbEnabled; + + String maText; + Image maImage; + Control* mpControl; + Rectangle maRect; + + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > mxAccContext; + +public: + ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const String& rText, MenuItemBits nBits ); + ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const Image& rImage, MenuItemBits nBits ); + ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const Image& rImage, const String& rText, MenuItemBits nBits ); + ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, Control* pControl, MenuItemBits nBits ); + ~ToolbarMenuEntry(); + + void init( int nEntryId, MenuItemBits nBits ); + + const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& GetAccessible( bool bCreate = false ); + + sal_Int32 getAccessibleChildCount() throw (::com::sun::star::uno::RuntimeException); + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > getAccessibleChild( sal_Int32 index ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + void selectAccessibleChild( sal_Int32 nChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + + bool HasCheck() const + { + return mbChecked || ( mnBits & ( MIB_RADIOCHECK | MIB_CHECKABLE | MIB_AUTOCHECK ) ); + } +}; + +// --------------- +// - ToolbarMenuAcc - +// --------------- + +typedef ::cppu::WeakComponentImplHelper5< + ::com::sun::star::accessibility::XAccessible, + ::com::sun::star::accessibility::XAccessibleEventBroadcaster, + ::com::sun::star::accessibility::XAccessibleContext, + ::com::sun::star::accessibility::XAccessibleComponent, + ::com::sun::star::accessibility::XAccessibleSelection > + ToolbarMenuAccComponentBase; + +class ToolbarMenuAcc : + public ::comphelper::OBaseMutex, + public ToolbarMenuAccComponentBase +{ +public: + + ToolbarMenuAcc( ToolbarMenu_Impl& rParent ); + ~ToolbarMenuAcc(); + + void FireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue ); + bool HasAccessibleListeners() const { return( mxEventListeners.size() > 0 ); } + +public: + // XAccessible + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleEventBroadcaster + using cppu::WeakComponentImplHelper5<com::sun::star::accessibility::XAccessible, com::sun::star::accessibility::XAccessibleEventBroadcaster, com::sun::star::accessibility::XAccessibleContext, com::sun::star::accessibility::XAccessibleComponent, com::sun::star::accessibility::XAccessibleSelection>::addEventListener; + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + using cppu::WeakComponentImplHelper5<com::sun::star::accessibility::XAccessible, com::sun::star::accessibility::XAccessibleEventBroadcaster, com::sun::star::accessibility::XAccessibleContext, com::sun::star::accessibility::XAccessibleComponent, com::sun::star::accessibility::XAccessibleSelection>::removeEventListener; + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int16 SAL_CALL getAccessibleRole( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleDescription( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleName( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::lang::Locale SAL_CALL getLocale( ) throw (::com::sun::star::accessibility::IllegalAccessibleComponentStateException, ::com::sun::star::uno::RuntimeException); + + // XAccessibleComponent + virtual sal_Bool SAL_CALL containsPoint( const ::com::sun::star::awt::Point& aPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const ::com::sun::star::awt::Point& aPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Rectangle SAL_CALL getBounds( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocation( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocationOnScreen( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Size SAL_CALL getSize( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL grabFocus( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getAccessibleKeyBinding( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getForeground( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getBackground( ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleSelection + virtual void SAL_CALL selectAccessibleChild( sal_Int32 nChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL clearAccessibleSelection( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL selectAllAccessibleChildren( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getSelectedAccessibleChildCount( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + + DECL_LINK( WindowEventListener, VclSimpleEvent* ); + +private: + EventListenerVector mxEventListeners; + ToolbarMenu_Impl* mpParent; + /// The current FOCUSED state. + bool mbIsFocused; + + void ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ); + + /** Tell all listeners that the object is dying. This callback is + usually called from the WeakComponentImplHelper class. + */ + virtual void SAL_CALL disposing (void); + + /** Check whether or not the object has been disposed (or is in the + state of beeing disposed). If that is the case then + DisposedException is thrown to inform the (indirect) caller of the + foul deed. + */ + void ThrowIfDisposed (void) throw (::com::sun::star::lang::DisposedException); +}; + +// ----------------------- +// - ToolbarMenuEntryAcc - +// ----------------------- + +typedef ::cppu::WeakComponentImplHelper4< ::com::sun::star::accessibility::XAccessible, + ::com::sun::star::accessibility::XAccessibleEventBroadcaster, + ::com::sun::star::accessibility::XAccessibleContext, + ::com::sun::star::accessibility::XAccessibleComponent > ToolbarMenuEntryAccBase; + +class ToolbarMenuEntryAcc : public ::comphelper::OBaseMutex, + public ToolbarMenuEntryAccBase +{ +public: + ToolbarMenuEntryAcc( ToolbarMenuEntry* pParent ); + ~ToolbarMenuEntryAcc(); + + void FireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue ); + bool HasAccessibleListeners() const { return( mxEventListeners.size() > 0 ); } + + // XAccessible + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleEventBroadcaster + using ToolbarMenuEntryAccBase::addEventListener; + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + using ToolbarMenuEntryAccBase::removeEventListener; + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int16 SAL_CALL getAccessibleRole( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleDescription( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleName( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::lang::Locale SAL_CALL getLocale( ) throw (::com::sun::star::accessibility::IllegalAccessibleComponentStateException, ::com::sun::star::uno::RuntimeException); + + // XAccessibleComponent + virtual sal_Bool SAL_CALL containsPoint( const ::com::sun::star::awt::Point& aPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const ::com::sun::star::awt::Point& aPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Rectangle SAL_CALL getBounds( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocation( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocationOnScreen( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Size SAL_CALL getSize( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL grabFocus( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getAccessibleKeyBinding( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getForeground( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getBackground( ) throw (::com::sun::star::uno::RuntimeException); + +private: + EventListenerVector mxEventListeners; + ::vos::OMutex maMutex; + ToolbarMenuEntry* mpParent; + + /** Tell all listeners that the object is dying. This callback is + usually called from the WeakComponentImplHelper class. + */ + virtual void SAL_CALL disposing (void); +}; + +// ----------------------------------------------------------------------------- + +struct ToolbarMenu_Impl +{ + ToolbarMenu& mrMenu; + + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > mxFrame; + rtl::Reference< svt::FrameStatusListener > mxStatusListener; + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > mxServiceManager; + rtl::Reference< ToolbarMenuAcc > mxAccessible; + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > mxOldSelection; + + ToolbarMenuEntryVector maEntryVector; + + int mnCheckPos; + int mnImagePos; + int mnTextPos; + + int mnHighlightedEntry; + int mnSelectedEntry; + int mnLastColumn; + + Size maSize; + + Link maSelectHdl; + + ToolbarMenu_Impl( ToolbarMenu& rMenu, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame ); + ~ToolbarMenu_Impl(); + + void setAccessible( ToolbarMenuAcc* pAccessible ); + + void fireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue ); + bool hasAccessibleListeners(); + + sal_Int32 getAccessibleChildCount() throw (::com::sun::star::uno::RuntimeException); + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > getAccessibleChild( sal_Int32 index ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > getAccessibleChild( Control* pControl, sal_Int32 childIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + + void selectAccessibleChild( sal_Int32 nChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + sal_Bool isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + void clearAccessibleSelection(); + + ToolbarMenuEntry* implGetEntry( int nEntry ) const; + void notifyHighlightedEntry(); + + void implHighlightControl( USHORT nCode, Control* pControl ); +}; + +} diff --git a/svtools/source/control/urlcontrol.cxx b/svtools/source/control/urlcontrol.cxx new file mode 100644 index 000000000000..788948355965 --- /dev/null +++ b/svtools/source/control/urlcontrol.cxx @@ -0,0 +1,95 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#include <svtools/urlcontrol.hxx> +#include "svl/filenotation.hxx" + +//......................................................................... +namespace svt +{ +//......................................................................... + + //===================================================================== + //= OFileURLControl + //===================================================================== + //--------------------------------------------------------------------- + OFileURLControl::OFileURLControl(Window* _pParent) + :SvtURLBox(_pParent, INET_PROT_FILE) + { + DisableHistory(); + } + + //--------------------------------------------------------------------- + OFileURLControl::OFileURLControl(Window* _pParent, const ResId& _rId) + :SvtURLBox(_pParent, _rId, INET_PROT_FILE) + { + DisableHistory(); + } + + //--------------------------------------------------------------------- + long OFileURLControl::PreNotify( NotifyEvent& _rNEvt ) + { + if (GetSubEdit() == _rNEvt.GetWindow()) + if (EVENT_KEYINPUT == _rNEvt.GetType()) + if (KEY_RETURN == _rNEvt.GetKeyEvent()->GetKeyCode().GetCode()) + if (IsInDropDown()) + m_sPreservedText = GetURL(); + + return SvtURLBox::PreNotify(_rNEvt); + } + + //--------------------------------------------------------------------- + long OFileURLControl::Notify( NotifyEvent& _rNEvt ) + { + if (GetSubEdit() == _rNEvt.GetWindow()) + if (EVENT_KEYINPUT == _rNEvt.GetType()) + if (KEY_RETURN == _rNEvt.GetKeyEvent()->GetKeyCode().GetCode()) + if (IsInDropDown()) + { + long nReturn = SvtURLBox::Notify(_rNEvt); + + // build a system dependent (thus more user readable) file name + OFileNotation aTransformer(m_sPreservedText, OFileNotation::N_URL); + SetText(aTransformer.get(OFileNotation::N_SYSTEM)); + Modify(); + + // Update the pick list + UpdatePickList(); + + return nReturn; + } + + return SvtURLBox::Notify(_rNEvt); + } + +//......................................................................... +} // namespace svt +//......................................................................... + diff --git a/svtools/source/control/valueacc.cxx b/svtools/source/control/valueacc.cxx new file mode 100644 index 000000000000..66da5636d89c --- /dev/null +++ b/svtools/source/control/valueacc.cxx @@ -0,0 +1,1258 @@ +/************************************************************************* + * + * 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_svtools.hxx" + +#define _SV_VALUESET_CXX + +#include <unotools/accessiblestatesethelper.hxx> +#include <vcl/svapp.hxx> +#include <svtools/valueset.hxx> +#include "valueimp.hxx" +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +using namespace ::com::sun::star; + +// ---------------- +// - ValueSetItem - +// ---------------- + +ValueSetItem::ValueSetItem( ValueSet& rParent ) : + mrParent( rParent ), + mnId( 0 ), + mnBits( 0 ), + mpData( NULL ), + mpxAcc( NULL ) +{ +} + +// ----------------------------------------------------------------------- + +ValueSetItem::~ValueSetItem() +{ + if( mpxAcc ) + { + static_cast< ValueItemAcc* >( mpxAcc->get() )->ParentDestroyed(); + delete mpxAcc; + } +} + +// ----------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessible > ValueSetItem::GetAccessible( bool bIsTransientChildrenDisabled ) +{ + if( !mpxAcc ) + mpxAcc = new uno::Reference< accessibility::XAccessible >( new ValueItemAcc( this, bIsTransientChildrenDisabled ) ); + + return *mpxAcc; +} + +// ----------------------------------------------------------------------- + +void ValueSetItem::ClearAccessible() +{ + if( mpxAcc ) + delete mpxAcc, mpxAcc = NULL; +} + + +// --------------- +// - ValueSetAcc - +// --------------- + +ValueSetAcc::ValueSetAcc( ValueSet* pParent, bool bIsTransientChildrenDisabled ) : + ValueSetAccComponentBase (m_aMutex), + mpParent( pParent ), + mbIsTransientChildrenDisabled( bIsTransientChildrenDisabled ), + mbIsFocused(false) +{ +} + +// ----------------------------------------------------------------------------- + +ValueSetAcc::~ValueSetAcc() +{ +} + +// ----------------------------------------------------------------------- + +void ValueSetAcc::FireAccessibleEvent( short nEventId, const uno::Any& rOldValue, const uno::Any& rNewValue ) +{ + if( nEventId ) + { + ::std::vector< uno::Reference< accessibility::XAccessibleEventListener > > aTmpListeners( mxEventListeners ); + ::std::vector< uno::Reference< accessibility::XAccessibleEventListener > >::const_iterator aIter( aTmpListeners.begin() ); + accessibility::AccessibleEventObject aEvtObject; + + aEvtObject.EventId = nEventId; + aEvtObject.Source = static_cast<uno::XWeak*>(this); + aEvtObject.NewValue = rNewValue; + aEvtObject.OldValue = rOldValue; + + while( aIter != aTmpListeners.end() ) + { + try + { + (*aIter)->notifyEvent( aEvtObject ); + } + catch( uno::Exception& ) + { + } + + aIter++; + } + } +} + +// ----------------------------------------------------------------------------- + +const uno::Sequence< sal_Int8 >& ValueSetAcc::getUnoTunnelId() +{ + static uno::Sequence< sal_Int8 > aSeq; + + if( !aSeq.getLength() ) + { + static osl::Mutex aCreateMutex; + osl::Guard< osl::Mutex > aGuard( aCreateMutex ); + + aSeq.realloc( 16 ); + rtl_createUuid( reinterpret_cast< sal_uInt8* >( aSeq.getArray() ), 0, sal_True ); + } + + return aSeq; +} + +// ----------------------------------------------------------------------------- + +ValueSetAcc* ValueSetAcc::getImplementation( const uno::Reference< uno::XInterface >& rxData ) + throw() +{ + try + { + uno::Reference< lang::XUnoTunnel > xUnoTunnel( rxData, uno::UNO_QUERY ); + return( xUnoTunnel.is() ? reinterpret_cast<ValueSetAcc*>(sal::static_int_cast<sal_IntPtr>(xUnoTunnel->getSomething( ValueSetAcc::getUnoTunnelId() ))) : NULL ); + } + catch( const ::com::sun::star::uno::Exception& ) + { + return NULL; + } +} + + +// ----------------------------------------------------------------------------- + +void ValueSetAcc::GetFocus (void) +{ + mbIsFocused = true; + + // Boradcast the state change. + ::com::sun::star::uno::Any aOldState, aNewState; + aNewState <<= ::com::sun::star::accessibility::AccessibleStateType::FOCUSED; + FireAccessibleEvent( + ::com::sun::star::accessibility::AccessibleEventId::STATE_CHANGED, + aOldState, aNewState); +} + +// ----------------------------------------------------------------------------- + +void ValueSetAcc::LoseFocus (void) +{ + mbIsFocused = false; + + // Boradcast the state change. + ::com::sun::star::uno::Any aOldState, aNewState; + aOldState <<= ::com::sun::star::accessibility::AccessibleStateType::FOCUSED; + FireAccessibleEvent( + ::com::sun::star::accessibility::AccessibleEventId::STATE_CHANGED, + aOldState, aNewState); +} + +// ----------------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessibleContext > SAL_CALL ValueSetAcc::getAccessibleContext() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + return this; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ValueSetAcc::getAccessibleChildCount() + throw (uno::RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + + sal_Int32 nCount = mpParent->ImplGetVisibleItemCount(); + if (HasNoneField()) + nCount += 1; + return nCount; +} + +// ----------------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessible > SAL_CALL ValueSetAcc::getAccessibleChild( sal_Int32 i ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + uno::Reference< accessibility::XAccessible > xRet; + ValueSetItem* pItem = getItem (sal::static_int_cast< USHORT >(i)); + + if( pItem ) + xRet = pItem->GetAccessible( mbIsTransientChildrenDisabled ); + else + throw lang::IndexOutOfBoundsException(); + + return xRet; +} + +// ----------------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessible > SAL_CALL ValueSetAcc::getAccessibleParent() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + Window* pParent = mpParent->GetParent(); + uno::Reference< accessibility::XAccessible > xRet; + + if( pParent ) + xRet = pParent->GetAccessible(); + + return xRet; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ValueSetAcc::getAccessibleIndexInParent() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + Window* pParent = mpParent->GetParent(); + sal_Int32 nRet = 0; + + if( pParent ) + { + sal_Bool bFound = sal_False; + + for( USHORT i = 0, nCount = pParent->GetChildCount(); ( i < nCount ) && !bFound; i++ ) + { + if( pParent->GetChild( i ) == mpParent ) + { + nRet = i; + bFound = sal_True; + } + } + } + + return nRet; +} + +// ----------------------------------------------------------------------------- + +sal_Int16 SAL_CALL ValueSetAcc::getAccessibleRole() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + // #i73746# As the Java Access Bridge (v 2.0.1) uses "managesDescendants" + // always if the role is LIST, we need a different role in this case + return (mbIsTransientChildrenDisabled + ? accessibility::AccessibleRole::PANEL + : accessibility::AccessibleRole::LIST ); +} + +// ----------------------------------------------------------------------------- + +::rtl::OUString SAL_CALL ValueSetAcc::getAccessibleDescription() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + String aRet( RTL_CONSTASCII_USTRINGPARAM( "ValueSet" ) ); + + return aRet; +} + +// ----------------------------------------------------------------------------- + +::rtl::OUString SAL_CALL ValueSetAcc::getAccessibleName() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + String aRet; + + if ( mpParent ) + aRet = mpParent->GetAccessibleName(); + + if ( !aRet.Len() ) + { + Window* pLabel = mpParent->GetLabeledBy(); + if ( pLabel && pLabel != mpParent ) + aRet = OutputDevice::GetNonMnemonicString( pLabel->GetText() ); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessibleRelationSet > SAL_CALL ValueSetAcc::getAccessibleRelationSet() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + return uno::Reference< accessibility::XAccessibleRelationSet >(); +} + +// ----------------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessibleStateSet > SAL_CALL ValueSetAcc::getAccessibleStateSet() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper(); + + // Set some states. + pStateSet->AddState (accessibility::AccessibleStateType::ENABLED); + pStateSet->AddState (accessibility::AccessibleStateType::SENSITIVE); + pStateSet->AddState (accessibility::AccessibleStateType::SHOWING); + pStateSet->AddState (accessibility::AccessibleStateType::VISIBLE); + if ( !mbIsTransientChildrenDisabled ) + pStateSet->AddState (accessibility::AccessibleStateType::MANAGES_DESCENDANTS); + pStateSet->AddState (accessibility::AccessibleStateType::FOCUSABLE); + if (mbIsFocused) + pStateSet->AddState (accessibility::AccessibleStateType::FOCUSED); + + return pStateSet; +} + +// ----------------------------------------------------------------------------- + +lang::Locale SAL_CALL ValueSetAcc::getLocale() + throw (accessibility::IllegalAccessibleComponentStateException, uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const ::rtl::OUString aEmptyStr; + uno::Reference< accessibility::XAccessible > xParent( getAccessibleParent() ); + lang::Locale aRet( aEmptyStr, aEmptyStr, aEmptyStr ); + + if( xParent.is() ) + { + uno::Reference< accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() ); + + if( xParentContext.is() ) + aRet = xParentContext->getLocale (); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ValueSetAcc::addEventListener( const uno::Reference< accessibility::XAccessibleEventListener >& rxListener ) + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + ::osl::MutexGuard aGuard (m_aMutex); + + if( rxListener.is() ) + { + ::std::vector< uno::Reference< accessibility::XAccessibleEventListener > >::const_iterator aIter = mxEventListeners.begin(); + sal_Bool bFound = sal_False; + + while( !bFound && ( aIter != mxEventListeners.end() ) ) + { + if( *aIter == rxListener ) + bFound = sal_True; + else + aIter++; + } + + if (!bFound) + mxEventListeners.push_back( rxListener ); + } +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ValueSetAcc::removeEventListener( const uno::Reference< accessibility::XAccessibleEventListener >& rxListener ) + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + ::osl::MutexGuard aGuard (m_aMutex); + + if( rxListener.is() ) + { + ::std::vector< uno::Reference< accessibility::XAccessibleEventListener > >::iterator aIter = mxEventListeners.begin(); + sal_Bool bFound = sal_False; + + while( !bFound && ( aIter != mxEventListeners.end() ) ) + { + if( *aIter == rxListener ) + { + mxEventListeners.erase( aIter ); + bFound = sal_True; + } + else + aIter++; + } + } +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL ValueSetAcc::containsPoint( const awt::Point& aPoint ) + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + const awt::Rectangle aRect( getBounds() ); + const Point aSize( aRect.Width, aRect.Height ); + const Point aNullPoint, aTestPoint( aPoint.X, aPoint.Y ); + + return Rectangle( aNullPoint, aSize ).IsInside( aTestPoint ); +} + +// ----------------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessible > SAL_CALL ValueSetAcc::getAccessibleAtPoint( const awt::Point& aPoint ) + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const USHORT nItemId = mpParent->GetItemId( Point( aPoint.X, aPoint.Y ) ); + uno::Reference< accessibility::XAccessible > xRet; + + if( VALUESET_ITEM_NOTFOUND != nItemId ) + { + const USHORT nItemPos = mpParent->GetItemPos( nItemId ); + + if( VALUESET_ITEM_NONEITEM != nItemPos ) + { + ValueSetItem* pItem = mpParent->mpImpl->mpItemList->GetObject( nItemPos ); + + if( ( pItem->meType != VALUESETITEM_SPACE ) && !pItem->maRect.IsEmpty() ) + xRet = pItem->GetAccessible( mbIsTransientChildrenDisabled ); + } + } + + return xRet; +} + +// ----------------------------------------------------------------------------- + +awt::Rectangle SAL_CALL ValueSetAcc::getBounds() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const Point aOutPos( mpParent->GetPosPixel() ); + const Size aOutSize( mpParent->GetOutputSizePixel() ); + awt::Rectangle aRet; + + aRet.X = aOutPos.X(); + aRet.Y = aOutPos.Y(); + aRet.Width = aOutSize.Width(); + aRet.Height = aOutSize.Height(); + + return aRet; +} + +// ----------------------------------------------------------------------------- + +awt::Point SAL_CALL ValueSetAcc::getLocation() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + const awt::Rectangle aRect( getBounds() ); + awt::Point aRet; + + aRet.X = aRect.X; + aRet.Y = aRect.Y; + + return aRet; +} + +// ----------------------------------------------------------------------------- + +awt::Point SAL_CALL ValueSetAcc::getLocationOnScreen() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const Point aScreenPos( mpParent->OutputToAbsoluteScreenPixel( Point() ) ); + awt::Point aRet; + + aRet.X = aScreenPos.X(); + aRet.Y = aScreenPos.Y(); + + return aRet; +} + +// ----------------------------------------------------------------------------- + +awt::Size SAL_CALL ValueSetAcc::getSize() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + const awt::Rectangle aRect( getBounds() ); + awt::Size aRet; + + aRet.Width = aRect.Width; + aRet.Height = aRect.Height; + + return aRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ValueSetAcc::grabFocus() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + mpParent->GrabFocus(); +} + +// ----------------------------------------------------------------------------- + +uno::Any SAL_CALL ValueSetAcc::getAccessibleKeyBinding() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + return uno::Any(); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ValueSetAcc::getForeground( ) + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + UINT32 nColor = Application::GetSettings().GetStyleSettings().GetWindowTextColor().GetColor(); + return static_cast<sal_Int32>(nColor); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ValueSetAcc::getBackground( ) + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + UINT32 nColor = Application::GetSettings().GetStyleSettings().GetWindowColor().GetColor(); + return static_cast<sal_Int32>(nColor); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ValueSetAcc::selectAccessibleChild( sal_Int32 nChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ValueSetItem* pItem = getItem (sal::static_int_cast< USHORT >(nChildIndex)); + + if(pItem != NULL) + { + mpParent->SelectItem( pItem->mnId ); + mpParent->Select (); + } + else + throw lang::IndexOutOfBoundsException(); +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL ValueSetAcc::isAccessibleChildSelected( sal_Int32 nChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ValueSetItem* pItem = getItem (sal::static_int_cast< USHORT >(nChildIndex)); + sal_Bool bRet = sal_False; + + if (pItem != NULL) + bRet = mpParent->IsItemSelected( pItem->mnId ); + else + throw lang::IndexOutOfBoundsException(); + + return bRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ValueSetAcc::clearAccessibleSelection() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + mpParent->SetNoSelection(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ValueSetAcc::selectAllAccessibleChildren() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + // unsupported due to single selection only +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ValueSetAcc::getSelectedAccessibleChildCount() + throw (uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + sal_Int32 nRet = 0; + + for( USHORT i = 0, nCount = getItemCount(); i < nCount; i++ ) + { + ValueSetItem* pItem = getItem (i); + + if( pItem && mpParent->IsItemSelected( pItem->mnId ) ) + ++nRet; + } + + return nRet; +} + +// ----------------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessible > SAL_CALL ValueSetAcc::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + uno::Reference< accessibility::XAccessible > xRet; + + for( USHORT i = 0, nCount = getItemCount(), nSel = 0; ( i < nCount ) && !xRet.is(); i++ ) + { + ValueSetItem* pItem = getItem(i); + + if( pItem && mpParent->IsItemSelected( pItem->mnId ) && ( nSelectedChildIndex == static_cast< sal_Int32 >( nSel++ ) ) ) + xRet = pItem->GetAccessible( mbIsTransientChildrenDisabled ); + } + + return xRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ValueSetAcc::deselectAccessibleChild( sal_Int32 nChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + // Because of the single selection we can reset the whole selection when + // the specified child is currently selected. + if (isAccessibleChildSelected(nChildIndex)) + mpParent->SetNoSelection(); +} + +// ----------------------------------------------------------------------------- + +sal_Int64 SAL_CALL ValueSetAcc::getSomething( const uno::Sequence< sal_Int8 >& rId ) throw( uno::RuntimeException ) +{ + sal_Int64 nRet; + + if( ( rId.getLength() == 16 ) && ( 0 == rtl_compareMemory( ValueSetAcc::getUnoTunnelId().getConstArray(), rId.getConstArray(), 16 ) ) ) + nRet = reinterpret_cast< sal_Int64 >( this ); + else + nRet = 0; + + return nRet; +} + + + + +void SAL_CALL ValueSetAcc::disposing (void) +{ + ::std::vector<uno::Reference<accessibility::XAccessibleEventListener> > aListenerListCopy; + + { + // Make a copy of the list and clear the original. + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ::osl::MutexGuard aGuard (m_aMutex); + aListenerListCopy = mxEventListeners; + mxEventListeners.clear(); + + // Reset the pointer to the parent. It has to be the one who has + // disposed us because he is dying. + mpParent = NULL; + } + + // Inform all listeners that this objects is disposing. + ::std::vector<uno::Reference<accessibility::XAccessibleEventListener> >::const_iterator + aListenerIterator (aListenerListCopy.begin()); + lang::EventObject aEvent (static_cast<accessibility::XAccessible*>(this)); + while (aListenerIterator != aListenerListCopy.end()) + { + try + { + (*aListenerIterator)->disposing (aEvent); + } + catch( uno::Exception& ) + { + // Ignore exceptions. + } + + ++aListenerIterator; + } +} + + +USHORT ValueSetAcc::getItemCount (void) const +{ + USHORT nCount = mpParent->ImplGetVisibleItemCount(); + // When the None-Item is visible then increase the number of items by + // one. + if (HasNoneField()) + nCount += 1; + return nCount; +} + + +ValueSetItem* ValueSetAcc::getItem (USHORT nIndex) const +{ + ValueSetItem* pItem = NULL; + + if (HasNoneField()) + { + if (nIndex == 0) + // When present the first item is the then allways visible none field. + pItem = mpParent->ImplGetItem (VALUESET_ITEM_NONEITEM); + else + // Shift down the index to compensate for the none field. + nIndex -= 1; + } + if (pItem == NULL) + pItem = mpParent->ImplGetVisibleItem (static_cast<USHORT>(nIndex)); + + return pItem; +} + + + + +void ValueSetAcc::ThrowIfDisposed (void) + throw (::com::sun::star::lang::DisposedException) +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + OSL_TRACE ("Calling disposed object. Throwing exception:"); + throw lang::DisposedException ( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")), + static_cast<uno::XWeak*>(this)); + } + else + { + DBG_ASSERT (mpParent!=NULL, "ValueSetAcc not disposed but mpParent == NULL"); + } +} + + + +sal_Bool ValueSetAcc::IsDisposed (void) +{ + return (rBHelper.bDisposed || rBHelper.bInDispose); +} + + + + +bool ValueSetAcc::HasNoneField (void) const +{ + DBG_ASSERT (mpParent!=NULL, "ValueSetAcc::HasNoneField called with mpParent==NULL"); + return ((mpParent->GetStyle() & WB_NONEFIELD) != 0); +} + + + + +// ---------------- +// - ValueItemAcc - +// ---------------- + +ValueItemAcc::ValueItemAcc( ValueSetItem* pParent, bool bIsTransientChildrenDisabled ) : + mpParent( pParent ), + mbIsTransientChildrenDisabled( bIsTransientChildrenDisabled ) +{ +} + +// ----------------------------------------------------------------------------- + +ValueItemAcc::~ValueItemAcc() +{ +} + +// ----------------------------------------------------------------------- + +void ValueItemAcc::FireAccessibleEvent( short nEventId, const uno::Any& rOldValue, const uno::Any& rNewValue ) +{ + if( nEventId ) + { + ::std::vector< uno::Reference< accessibility::XAccessibleEventListener > > aTmpListeners( mxEventListeners ); + ::std::vector< uno::Reference< accessibility::XAccessibleEventListener > >::const_iterator aIter( aTmpListeners.begin() ); + accessibility::AccessibleEventObject aEvtObject; + + aEvtObject.EventId = nEventId; + aEvtObject.Source = static_cast<uno::XWeak*>(this); + aEvtObject.NewValue = rNewValue; + aEvtObject.OldValue = rOldValue; + + while( aIter != aTmpListeners.end() ) + { + (*aIter)->notifyEvent( aEvtObject ); + aIter++; + } + } +} + +// ----------------------------------------------------------------------------- + +void ValueItemAcc::ParentDestroyed() +{ + const ::vos::OGuard aGuard( maMutex ); + mpParent = NULL; +} + +// ----------------------------------------------------------------------------- + +const uno::Sequence< sal_Int8 >& ValueItemAcc::getUnoTunnelId() +{ + static uno::Sequence< sal_Int8 > aSeq; + + if( !aSeq.getLength() ) + { + static osl::Mutex aCreateMutex; + osl::Guard< osl::Mutex > aGuard( aCreateMutex ); + + aSeq.realloc( 16 ); + rtl_createUuid( reinterpret_cast< sal_uInt8* >( aSeq.getArray() ), 0, sal_True ); + } + + return aSeq; +} + +// ----------------------------------------------------------------------------- + +ValueItemAcc* ValueItemAcc::getImplementation( const uno::Reference< uno::XInterface >& rxData ) + throw() +{ + try + { + uno::Reference< lang::XUnoTunnel > xUnoTunnel( rxData, uno::UNO_QUERY ); + return( xUnoTunnel.is() ? reinterpret_cast<ValueItemAcc*>(sal::static_int_cast<sal_IntPtr>(xUnoTunnel->getSomething( ValueItemAcc::getUnoTunnelId() ))) : NULL ); + } + catch( const ::com::sun::star::uno::Exception& ) + { + return NULL; + } +} + +// ----------------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessibleContext > SAL_CALL ValueItemAcc::getAccessibleContext() + throw (uno::RuntimeException) +{ + return this; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ValueItemAcc::getAccessibleChildCount() + throw (uno::RuntimeException) +{ + return 0; +} + +// ----------------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessible > SAL_CALL ValueItemAcc::getAccessibleChild( sal_Int32 ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + throw lang::IndexOutOfBoundsException(); +} + +// ----------------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessible > SAL_CALL ValueItemAcc::getAccessibleParent() + throw (uno::RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + uno::Reference< accessibility::XAccessible > xRet; + + if( mpParent ) + xRet = mpParent->mrParent.GetAccessible(); + + return xRet; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ValueItemAcc::getAccessibleIndexInParent() + throw (uno::RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + // The index defaults to -1 to indicate the child does not belong to its + // parent. + sal_Int32 nIndexInParent = -1; + + if( mpParent ) + { + bool bDone = false; + + USHORT nCount = mpParent->mrParent.ImplGetVisibleItemCount(); + ValueSetItem* pItem; + for (USHORT i=0; i<nCount && !bDone; i++) + { + // Guard the retrieval of the i-th child with a try/catch block + // just in case the number of children changes in the mean time. + try + { + pItem = mpParent->mrParent.ImplGetVisibleItem (i); + } + catch (lang::IndexOutOfBoundsException aException) + { + pItem = NULL; + } + + // Do not create an accessible object for the test. + if (pItem != NULL && pItem->mpxAcc != NULL) + if (pItem->GetAccessible( mbIsTransientChildrenDisabled ).get() == this ) + { + nIndexInParent = i; + bDone = true; + } + } + } + + return nIndexInParent; +} + +// ----------------------------------------------------------------------------- + +sal_Int16 SAL_CALL ValueItemAcc::getAccessibleRole() + throw (uno::RuntimeException) +{ + return accessibility::AccessibleRole::LIST_ITEM; +} + +// ----------------------------------------------------------------------------- + +::rtl::OUString SAL_CALL ValueItemAcc::getAccessibleDescription() + throw (uno::RuntimeException) +{ + return ::rtl::OUString(); +} + +// ----------------------------------------------------------------------------- + +::rtl::OUString SAL_CALL ValueItemAcc::getAccessibleName() + throw (uno::RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + String aRet; + + if( mpParent ) + { + aRet = mpParent->maText; + + if( !aRet.Len() ) + { + aRet = String( RTL_CONSTASCII_USTRINGPARAM( "Item " ) ); + aRet += String::CreateFromInt32( mpParent->mnId ); + } + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessibleRelationSet > SAL_CALL ValueItemAcc::getAccessibleRelationSet() + throw (uno::RuntimeException) +{ + return uno::Reference< accessibility::XAccessibleRelationSet >(); +} + +// ----------------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessibleStateSet > SAL_CALL ValueItemAcc::getAccessibleStateSet() + throw (uno::RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper; + + if( mpParent ) + { + pStateSet->AddState (accessibility::AccessibleStateType::ENABLED); + pStateSet->AddState (accessibility::AccessibleStateType::SENSITIVE); + pStateSet->AddState (accessibility::AccessibleStateType::SHOWING); + pStateSet->AddState (accessibility::AccessibleStateType::VISIBLE); + if ( !mbIsTransientChildrenDisabled ) + pStateSet->AddState (accessibility::AccessibleStateType::TRANSIENT); + + // SELECTABLE + pStateSet->AddState( accessibility::AccessibleStateType::SELECTABLE ); + // pStateSet->AddState( accessibility::AccessibleStateType::FOCUSABLE ); + + // SELECTED + if( mpParent->mrParent.GetSelectItemId() == mpParent->mnId ) + { + pStateSet->AddState( accessibility::AccessibleStateType::SELECTED ); + // pStateSet->AddState( accessibility::AccessibleStateType::FOCUSED ); + } + } + + return pStateSet; +} + +// ----------------------------------------------------------------------------- + +lang::Locale SAL_CALL ValueItemAcc::getLocale() + throw (accessibility::IllegalAccessibleComponentStateException, uno::RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const ::rtl::OUString aEmptyStr; + uno::Reference< accessibility::XAccessible > xParent( getAccessibleParent() ); + lang::Locale aRet( aEmptyStr, aEmptyStr, aEmptyStr ); + + if( xParent.is() ) + { + uno::Reference< accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() ); + + if( xParentContext.is() ) + aRet = xParentContext->getLocale(); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ValueItemAcc::addEventListener( const uno::Reference< accessibility::XAccessibleEventListener >& rxListener ) + throw (uno::RuntimeException) +{ + const ::vos::OGuard aGuard( maMutex ); + + if( rxListener.is() ) + { + ::std::vector< uno::Reference< accessibility::XAccessibleEventListener > >::const_iterator aIter = mxEventListeners.begin(); + sal_Bool bFound = sal_False; + + while( !bFound && ( aIter != mxEventListeners.end() ) ) + { + if( *aIter == rxListener ) + bFound = sal_True; + else + aIter++; + } + + if (!bFound) + mxEventListeners.push_back( rxListener ); + } +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ValueItemAcc::removeEventListener( const uno::Reference< accessibility::XAccessibleEventListener >& rxListener ) + throw (uno::RuntimeException) +{ + const ::vos::OGuard aGuard( maMutex ); + + if( rxListener.is() ) + { + ::std::vector< uno::Reference< accessibility::XAccessibleEventListener > >::iterator aIter = mxEventListeners.begin(); + sal_Bool bFound = sal_False; + + while( !bFound && ( aIter != mxEventListeners.end() ) ) + { + if( *aIter == rxListener ) + { + mxEventListeners.erase( aIter ); + bFound = sal_True; + } + else + aIter++; + } + } +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL ValueItemAcc::containsPoint( const awt::Point& aPoint ) + throw (uno::RuntimeException) +{ + const awt::Rectangle aRect( getBounds() ); + const Point aSize( aRect.Width, aRect.Height ); + const Point aNullPoint, aTestPoint( aPoint.X, aPoint.Y ); + + return Rectangle( aNullPoint, aSize ).IsInside( aTestPoint ); +} + +// ----------------------------------------------------------------------------- + +uno::Reference< accessibility::XAccessible > SAL_CALL ValueItemAcc::getAccessibleAtPoint( const awt::Point& ) + throw (uno::RuntimeException) +{ + uno::Reference< accessibility::XAccessible > xRet; + return xRet; +} + +// ----------------------------------------------------------------------------- + +awt::Rectangle SAL_CALL ValueItemAcc::getBounds() + throw (uno::RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + awt::Rectangle aRet; + + if( mpParent ) + { + Rectangle aRect( mpParent->maRect ); + Point aOrigin; + Rectangle aParentRect( aOrigin, mpParent->mrParent.GetOutputSizePixel() ); + + aRect.Intersection( aParentRect ); + + aRet.X = aRect.Left(); + aRet.Y = aRect.Top(); + aRet.Width = aRect.GetWidth(); + aRet.Height = aRect.GetHeight(); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +awt::Point SAL_CALL ValueItemAcc::getLocation() + throw (uno::RuntimeException) +{ + const awt::Rectangle aRect( getBounds() ); + awt::Point aRet; + + aRet.X = aRect.X; + aRet.Y = aRect.Y; + + return aRet; +} + +// ----------------------------------------------------------------------------- + +awt::Point SAL_CALL ValueItemAcc::getLocationOnScreen() + throw (uno::RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + awt::Point aRet; + + if( mpParent ) + { + const Point aScreenPos( mpParent->mrParent.OutputToAbsoluteScreenPixel( mpParent->maRect.TopLeft() ) ); + + aRet.X = aScreenPos.X(); + aRet.Y = aScreenPos.Y(); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +awt::Size SAL_CALL ValueItemAcc::getSize() + throw (uno::RuntimeException) +{ + const awt::Rectangle aRect( getBounds() ); + awt::Size aRet; + + aRet.Width = aRect.Width; + aRet.Height = aRect.Height; + + return aRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ValueItemAcc::grabFocus() + throw (uno::RuntimeException) +{ + // nothing to do +} + +// ----------------------------------------------------------------------------- + +uno::Any SAL_CALL ValueItemAcc::getAccessibleKeyBinding() + throw (uno::RuntimeException) +{ + return uno::Any(); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ValueItemAcc::getForeground( ) + throw (uno::RuntimeException) +{ + UINT32 nColor = Application::GetSettings().GetStyleSettings().GetWindowTextColor().GetColor(); + return static_cast<sal_Int32>(nColor); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ValueItemAcc::getBackground( ) + throw (uno::RuntimeException) +{ + UINT32 nColor; + if (mpParent && mpParent->meType == VALUESETITEM_COLOR) + nColor = mpParent->maColor.GetColor(); + else + nColor = Application::GetSettings().GetStyleSettings().GetWindowColor().GetColor(); + return static_cast<sal_Int32>(nColor); +} + +// ----------------------------------------------------------------------------- + +sal_Int64 SAL_CALL ValueItemAcc::getSomething( const uno::Sequence< sal_Int8 >& rId ) throw( uno::RuntimeException ) +{ + sal_Int64 nRet; + + if( ( rId.getLength() == 16 ) && ( 0 == rtl_compareMemory( ValueItemAcc::getUnoTunnelId().getConstArray(), rId.getConstArray(), 16 ) ) ) + nRet = reinterpret_cast< sal_Int64 >( this ); + else + nRet = 0; + + return nRet; +} diff --git a/svtools/source/control/valueimp.hxx b/svtools/source/control/valueimp.hxx new file mode 100755 index 000000000000..abde4a015ab8 --- /dev/null +++ b/svtools/source/control/valueimp.hxx @@ -0,0 +1,330 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +#include <vos/mutex.hxx> +#include <tools/list.hxx> +#include <tools/color.hxx> +#include <tools/string.hxx> +#ifndef _IMAGE_HXX +#include <vcl/image.hxx> +#endif +#include <rtl/uuid.h> +#include <cppuhelper/implbase5.hxx> +#include <cppuhelper/compbase6.hxx> +#include <comphelper/broadcasthelper.hxx> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleSelection.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/lang/DisposedException.hpp> + +#include <memory> +#include <vector> + +// ----------- +// - Defines - +// ----------- + +#define ITEM_OFFSET 4 +#define ITEM_OFFSET_DOUBLE 6 +#define NAME_LINE_OFF_X 2 +#define NAME_LINE_OFF_Y 2 +#define NAME_LINE_HEIGHT 2 +#define NAME_OFFSET 2 +#define SCRBAR_OFFSET 1 +#define VALUESET_ITEM_NONEITEM 0xFFFE +#define VALUESET_SCROLL_OFFSET 4 + +// -------------------- +// - ValueSetItemType - +// -------------------- + +enum ValueSetItemType +{ + VALUESETITEM_NONE, + VALUESETITEM_IMAGE, + VALUESETITEM_COLOR, + VALUESETITEM_USERDRAW, + VALUESETITEM_SPACE +}; + +// ---------------- +// - ValueSetItem - +// ---------------- + +class ValueSet; + +struct ValueSetItem +{ + ValueSet& mrParent; + USHORT mnId; + USHORT mnBits; + ValueSetItemType meType; + Image maImage; + Color maColor; + XubString maText; + void* mpData; + Rectangle maRect; + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >* mpxAcc; + + ValueSetItem( ValueSet& rParent ); + ~ValueSetItem(); + + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + GetAccessible( bool bIsTransientChildrenDisabled ); + void ClearAccessible(); +}; + +// ----------------------------------------------------------------------------- + +DECLARE_LIST( ValueItemList, ValueSetItem* ) + +// ----------------------------------------------------------------------------- + +struct ValueSet_Impl +{ + ::std::auto_ptr< ValueItemList > mpItemList; + bool mbIsTransientChildrenDisabled; + Link maHighlightHdl; + + ValueSet_Impl() : mpItemList( ::std::auto_ptr< ValueItemList >( new ValueItemList() ) ), + mbIsTransientChildrenDisabled( false ) + { + } +}; + +// --------------- +// - ValueSetAcc - +// --------------- + +typedef ::cppu::WeakComponentImplHelper6< + ::com::sun::star::accessibility::XAccessible, + ::com::sun::star::accessibility::XAccessibleEventBroadcaster, + ::com::sun::star::accessibility::XAccessibleContext, + ::com::sun::star::accessibility::XAccessibleComponent, + ::com::sun::star::accessibility::XAccessibleSelection, + ::com::sun::star::lang::XUnoTunnel > + ValueSetAccComponentBase; + +class ValueSetAcc : + public ::comphelper::OBaseMutex, + public ValueSetAccComponentBase +{ +public: + + ValueSetAcc( ValueSet* pParent, bool bIsTransientChildrenDisabled ); + ~ValueSetAcc(); + + void FireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue ); + BOOL HasAccessibleListeners() const { return( mxEventListeners.size() > 0 ); } + + static ValueSetAcc* getImplementation( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rxData ) throw(); + +public: + + /** Called by the corresponding ValueSet when it gets the focus. + Stores the new focus state and broadcasts a state change event. + */ + void GetFocus (void); + + /** Called by the corresponding ValueSet when it loses the focus. + Stores the new focus state and broadcasts a state change event. + */ + void LoseFocus (void); + + + // XAccessible + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleEventBroadcaster + using cppu::WeakComponentImplHelper6<com::sun::star::accessibility::XAccessible, com::sun::star::accessibility::XAccessibleEventBroadcaster, com::sun::star::accessibility::XAccessibleContext, com::sun::star::accessibility::XAccessibleComponent, com::sun::star::accessibility::XAccessibleSelection, com::sun::star::lang::XUnoTunnel>::addEventListener; + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + using cppu::WeakComponentImplHelper6<com::sun::star::accessibility::XAccessible, com::sun::star::accessibility::XAccessibleEventBroadcaster, com::sun::star::accessibility::XAccessibleContext, com::sun::star::accessibility::XAccessibleComponent, com::sun::star::accessibility::XAccessibleSelection, com::sun::star::lang::XUnoTunnel>::removeEventListener; + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int16 SAL_CALL getAccessibleRole( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleDescription( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleName( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::lang::Locale SAL_CALL getLocale( ) throw (::com::sun::star::accessibility::IllegalAccessibleComponentStateException, ::com::sun::star::uno::RuntimeException); + + // XAccessibleComponent + virtual sal_Bool SAL_CALL containsPoint( const ::com::sun::star::awt::Point& aPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const ::com::sun::star::awt::Point& aPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Rectangle SAL_CALL getBounds( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocation( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocationOnScreen( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Size SAL_CALL getSize( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL grabFocus( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getAccessibleKeyBinding( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getForeground( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getBackground( ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleSelection + virtual void SAL_CALL selectAccessibleChild( sal_Int32 nChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL clearAccessibleSelection( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL selectAllAccessibleChildren( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getSelectedAccessibleChildCount( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + + // XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& rId ) throw( ::com::sun::star::uno::RuntimeException ); + +private: + // ::vos::OMutex maMutex; + ::std::vector< ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleEventListener > > mxEventListeners; + ValueSet* mpParent; + bool mbIsTransientChildrenDisabled; + /// The current FOCUSED state. + bool mbIsFocused; + + static const ::com::sun::star::uno::Sequence< sal_Int8 >& getUnoTunnelId(); + + /** Tell all listeners that the object is dying. This callback is + usually called from the WeakComponentImplHelper class. + */ + virtual void SAL_CALL disposing (void); + + /** Return the number of items. This takes the None-Item into account. + */ + USHORT getItemCount (void) const; + + /** Return the item associated with the given index. The None-Item is + taken into account which, when present, is taken to be the first + (with index 0) item. + @param nIndex + Index of the item to return. The index 0 denotes the None-Item + when present. + @return + Returns NULL when the given index is out of range. + */ + ValueSetItem* getItem (USHORT nIndex) const; + + /** Check whether or not the object has been disposed (or is in the + state of beeing disposed). If that is the case then + DisposedException is thrown to inform the (indirect) caller of the + foul deed. + */ + void ThrowIfDisposed (void) + throw (::com::sun::star::lang::DisposedException); + + /** Check whether or not the object has been disposed (or is in the + state of beeing disposed). + + @return sal_True, if the object is disposed or in the course + of being disposed. Otherwise, sal_False is returned. + */ + sal_Bool IsDisposed (void); + + /** Check whether the value set has a 'none' field, i.e. a field (button) + that deselects any items (selects none of them). + @return + Returns <true/> if there is a 'none' field and <false/> it it is + missing. + */ + bool HasNoneField (void) const; +}; + +// ---------------- +// - ValueItemAcc - +// ---------------- + +class ValueItemAcc : public ::cppu::WeakImplHelper5< ::com::sun::star::accessibility::XAccessible, + ::com::sun::star::accessibility::XAccessibleEventBroadcaster, + ::com::sun::star::accessibility::XAccessibleContext, + ::com::sun::star::accessibility::XAccessibleComponent, + ::com::sun::star::lang::XUnoTunnel > +{ +private: + + ::std::vector< ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleEventListener > > mxEventListeners; + ::vos::OMutex maMutex; + ValueSetItem* mpParent; + bool mbIsTransientChildrenDisabled; + + static const ::com::sun::star::uno::Sequence< sal_Int8 >& getUnoTunnelId(); + +public: + + ValueItemAcc( ValueSetItem* pParent, bool bIsTransientChildrenDisabled ); + ~ValueItemAcc(); + + void ParentDestroyed(); + + void FireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue ); + BOOL HasAccessibleListeners() const { return( mxEventListeners.size() > 0 ); } + + static ValueItemAcc* getImplementation( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rxData ) throw(); + +public: + + // XAccessible + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleEventBroadcaster + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int16 SAL_CALL getAccessibleRole( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleDescription( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleName( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::lang::Locale SAL_CALL getLocale( ) throw (::com::sun::star::accessibility::IllegalAccessibleComponentStateException, ::com::sun::star::uno::RuntimeException); + + // XAccessibleComponent + virtual sal_Bool SAL_CALL containsPoint( const ::com::sun::star::awt::Point& aPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const ::com::sun::star::awt::Point& aPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Rectangle SAL_CALL getBounds( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocation( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocationOnScreen( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Size SAL_CALL getSize( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL grabFocus( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getAccessibleKeyBinding( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getForeground( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getBackground( ) throw (::com::sun::star::uno::RuntimeException); + + // XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& rId ) throw( ::com::sun::star::uno::RuntimeException ); +}; diff --git a/svtools/source/control/valueset.cxx b/svtools/source/control/valueset.cxx new file mode 100644 index 000000000000..62193eadf735 --- /dev/null +++ b/svtools/source/control/valueset.cxx @@ -0,0 +1,2758 @@ +/************************************************************************* + * + * 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_svtools.hxx" +#include <tools/list.hxx> +#include <tools/debug.hxx> +#include <vcl/decoview.hxx> +#include <vcl/svapp.hxx> +#ifndef _SCRBAR_HXX +#include <vcl/scrbar.hxx> +#endif +#ifndef _HELP_HXX +#include <vcl/help.hxx> +#endif +#include <com/sun/star/accessibility/AccessibleEventObject.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <rtl/ustring.hxx> + +#include "valueimp.hxx" + +#define _SV_VALUESET_CXX +#include <svtools/valueset.hxx> + +// ------------ +// - ValueSet - +// ------------ + +void ValueSet::ImplInit() +{ + // Size aWinSize = GetSizePixel(); + mpImpl = new ValueSet_Impl; + mpNoneItem = NULL; + mpScrBar = NULL; + mnTextOffset = 0; + mnVisLines = 0; + mnLines = 0; + mnUserItemWidth = 0; + mnUserItemHeight = 0; + mnFirstLine = 0; + mnOldItemId = 0; + mnSelItemId = 0; + mnHighItemId = 0; + mnDropPos = VALUESET_ITEM_NOTFOUND; + mnCols = 0; + mnCurCol = 0; + mnUserCols = 0; + mnUserVisLines = 0; + mnSpacing = 0; + mnFrameStyle = 0; + mbFormat = TRUE; + mbHighlight = FALSE ; + mbSelection = FALSE; + mbNoSelection = TRUE; + mbDrawSelection = TRUE; + mbBlackSel = FALSE; + mbDoubleSel = FALSE; + mbScroll = FALSE; + mbDropPos = FALSE; + mbFullMode = TRUE; + + // #106446#, #106601# force mirroring of virtual device + maVirDev.EnableRTL( GetParent()->IsRTLEnabled() ); + + ImplInitSettings( TRUE, TRUE, TRUE ); +} + +// ----------------------------------------------------------------------- + +ValueSet::ValueSet( Window* pParent, WinBits nWinStyle, bool bDisableTransientChildren ) : + Control( pParent, nWinStyle ), + maVirDev( *this ), + maColor( COL_TRANSPARENT ) +{ + ImplInit(); + if( mpImpl ) + mpImpl->mbIsTransientChildrenDisabled = bDisableTransientChildren; +} + +// ----------------------------------------------------------------------- + +ValueSet::ValueSet( Window* pParent, const ResId& rResId, bool bDisableTransientChildren ) : + Control( pParent, rResId ), + maVirDev( *this ), + maColor( COL_TRANSPARENT ) +{ + ImplInit(); + if( mpImpl ) + mpImpl->mbIsTransientChildrenDisabled = bDisableTransientChildren; +} + +// ----------------------------------------------------------------------- + +ValueSet::~ValueSet() +{ + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent> + xComponent (GetAccessible(FALSE), ::com::sun::star::uno::UNO_QUERY); + if (xComponent.is()) + xComponent->dispose (); + + if ( mpScrBar ) + delete mpScrBar; + + if ( mpNoneItem ) + delete mpNoneItem; + + ImplDeleteItems(); + delete mpImpl; +} + +// ----------------------------------------------------------------------- + +void ValueSet::ImplDeleteItems() +{ + for( ValueSetItem* pItem = mpImpl->mpItemList->First(); pItem; pItem = mpImpl->mpItemList->Next() ) + { + if( !pItem->maRect.IsEmpty() && ImplHasAccessibleListeners() ) + { + ::com::sun::star::uno::Any aOldAny, aNewAny; + + aOldAny <<= pItem->GetAccessible( mpImpl->mbIsTransientChildrenDisabled ); + ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny ); + } + + delete pItem; + } + + mpImpl->mpItemList->Clear(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::ImplInitSettings( BOOL bFont, + BOOL bForeground, BOOL bBackground ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + if ( bFont ) + { + Font aFont; + aFont = rStyleSettings.GetAppFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetZoomedPointFont( aFont ); + } + + if ( bForeground || bFont ) + { + Color aColor; + if ( IsControlForeground() ) + aColor = GetControlForeground(); + else + aColor = rStyleSettings.GetButtonTextColor(); + SetTextColor( aColor ); + SetTextFillColor(); + } + + if ( bBackground ) + { + Color aColor; + if ( IsControlBackground() ) + aColor = GetControlBackground(); + else if ( GetStyle() & WB_MENUSTYLEVALUESET ) + aColor = rStyleSettings.GetMenuColor(); + else if ( IsEnabled() && (GetStyle() & WB_FLATVALUESET) ) + aColor = rStyleSettings.GetWindowColor(); + else + aColor = rStyleSettings.GetFaceColor(); + SetBackground( aColor ); + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::ImplInitScrollBar() +{ + if ( GetStyle() & WB_VSCROLL ) + { + if ( !mpScrBar ) + { + mpScrBar = new ScrollBar( this, WB_VSCROLL | WB_DRAG ); + mpScrBar->SetScrollHdl( LINK( this, ValueSet, ImplScrollHdl ) ); + } + else + { + // Wegen Einstellungsaenderungen passen wir hier die Breite an + long nScrBarWidth = GetSettings().GetStyleSettings().GetScrollBarSize(); + mpScrBar->SetPosSizePixel( 0, 0, nScrBarWidth, 0, WINDOW_POSSIZE_WIDTH ); + } + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::ImplFormatItem( ValueSetItem* pItem ) +{ + if ( pItem->meType == VALUESETITEM_SPACE ) + return; + + Rectangle aRect = pItem->maRect; + WinBits nStyle = GetStyle(); + if ( nStyle & WB_ITEMBORDER ) + { + aRect.Left()++; + aRect.Top()++; + aRect.Right()--; + aRect.Bottom()--; + if ( nStyle & WB_FLATVALUESET ) + { + if ( nStyle & WB_DOUBLEBORDER ) + { + aRect.Left() += 2; + aRect.Top() += 2; + aRect.Right() -= 2; + aRect.Bottom() -= 2; + } + else + { + aRect.Left()++; + aRect.Top()++; + aRect.Right()--; + aRect.Bottom()--; + } + } + else + { + DecorationView aView( &maVirDev ); + aRect = aView.DrawFrame( aRect, mnFrameStyle ); + } + } + + if ( pItem == mpNoneItem ) + pItem->maText = GetText(); + + if ( (aRect.GetHeight() > 0) && (aRect.GetWidth() > 0) ) + { + if ( pItem == mpNoneItem ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + maVirDev.SetFont( GetFont() ); + maVirDev.SetTextColor( ( nStyle & WB_MENUSTYLEVALUESET ) ? rStyleSettings.GetMenuTextColor() : rStyleSettings.GetWindowTextColor() ); + maVirDev.SetTextFillColor(); + maVirDev.SetFillColor( ( nStyle & WB_MENUSTYLEVALUESET ) ? rStyleSettings.GetMenuColor() : rStyleSettings.GetWindowColor() ); + maVirDev.DrawRect( aRect ); + Point aTxtPos( aRect.Left()+2, aRect.Top() ); + long nTxtWidth = GetTextWidth( pItem->maText ); + if ( nStyle & WB_RADIOSEL ) + { + aTxtPos.X() += 4; + aTxtPos.Y() += 4; + } + if ( (aTxtPos.X()+nTxtWidth) > aRect.Right() ) + { + maVirDev.SetClipRegion( Region( aRect ) ); + maVirDev.DrawText( aTxtPos, pItem->maText ); + maVirDev.SetClipRegion(); + } + else + maVirDev.DrawText( aTxtPos, pItem->maText ); + } + else if ( pItem->meType == VALUESETITEM_COLOR ) + { + maVirDev.SetFillColor( pItem->maColor ); + maVirDev.DrawRect( aRect ); + } + else + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + if ( IsColor() ) + maVirDev.SetFillColor( maColor ); + else if ( nStyle & WB_MENUSTYLEVALUESET ) + maVirDev.SetFillColor( rStyleSettings.GetMenuColor() ); + else if ( IsEnabled() ) + maVirDev.SetFillColor( rStyleSettings.GetWindowColor() ); + else + maVirDev.SetFillColor( rStyleSettings.GetFaceColor() ); + maVirDev.DrawRect( aRect ); + + if ( pItem->meType == VALUESETITEM_USERDRAW ) + { + UserDrawEvent aUDEvt( &maVirDev, aRect, pItem->mnId ); + UserDraw( aUDEvt ); + } + else + { + Size aImageSize = pItem->maImage.GetSizePixel(); + Size aRectSize = aRect.GetSize(); + Point aPos( aRect.Left(), aRect.Top() ); + aPos.X() += (aRectSize.Width()-aImageSize.Width())/2; + aPos.Y() += (aRectSize.Height()-aImageSize.Height())/2; + + USHORT nImageStyle = 0; + if( !IsEnabled() ) + nImageStyle |= IMAGE_DRAW_DISABLE; + + if ( (aImageSize.Width() > aRectSize.Width()) || + (aImageSize.Height() > aRectSize.Height()) ) + { + maVirDev.SetClipRegion( Region( aRect ) ); + maVirDev.DrawImage( aPos, pItem->maImage, nImageStyle); + maVirDev.SetClipRegion(); + } + else + maVirDev.DrawImage( aPos, pItem->maImage, nImageStyle ); + } + } + } +} + +// ----------------------------------------------------------------------- + +::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > ValueSet::CreateAccessible() +{ + return new ValueSetAcc( this, mpImpl->mbIsTransientChildrenDisabled ); +} + +// ----------------------------------------------------------------------- + +void ValueSet::Format() +{ + Size aWinSize = GetOutputSizePixel(); + ULONG nItemCount = mpImpl->mpItemList->Count(); + WinBits nStyle = GetStyle(); + long nTxtHeight = GetTextHeight(); + long nOff; + long nSpace; + long nNoneHeight; + long nNoneSpace; + ScrollBar* pDelScrBar = NULL; + + // Scrolling beruecksichtigen + if ( nStyle & WB_VSCROLL ) + ImplInitScrollBar(); + else + { + if ( mpScrBar ) + { + // ScrollBar erst spaeter zerstoeren, damit keine rekursiven + // Aufrufe entstehen koennen + pDelScrBar = mpScrBar; + mpScrBar = NULL; + } + } + + // Item-Offset berechnen + if ( nStyle & WB_ITEMBORDER ) + { + if ( nStyle & WB_DOUBLEBORDER ) + nOff = ITEM_OFFSET_DOUBLE; + else + nOff = ITEM_OFFSET; + } + else + nOff = 0; + nSpace = mnSpacing; + + // Groesse beruecksichtigen, wenn NameField vorhanden + if ( nStyle & WB_NAMEFIELD ) + { + mnTextOffset = aWinSize.Height()-nTxtHeight-NAME_OFFSET; + aWinSize.Height() -= nTxtHeight+NAME_OFFSET; + + if ( !(nStyle & WB_FLATVALUESET) ) + { + mnTextOffset -= NAME_LINE_HEIGHT+NAME_LINE_OFF_Y; + aWinSize.Height() -= NAME_LINE_HEIGHT+NAME_LINE_OFF_Y; + } + } + else + mnTextOffset = 0; + + // Offset und Groesse beruecksichtigen, wenn NoneField vorhanden + if ( nStyle & WB_NONEFIELD ) + { + nNoneHeight = nTxtHeight+nOff; + nNoneSpace = nSpace; + if ( nStyle & WB_RADIOSEL ) + nNoneHeight += 8; + } + else + { + nNoneHeight = 0; + nNoneSpace = 0; + + if ( mpNoneItem ) + { + delete mpNoneItem; + mpNoneItem = NULL; + } + } + + // Breite vom ScrollBar berechnen + long nScrBarWidth = 0; + if ( mpScrBar ) + nScrBarWidth = mpScrBar->GetSizePixel().Width()+SCRBAR_OFFSET; + + // Spaltenanzahl berechnen + if ( !mnUserCols ) + { + if ( mnUserItemWidth ) + { + mnCols = (USHORT)((aWinSize.Width()-nScrBarWidth+nSpace) / (mnUserItemWidth+nSpace)); + if ( !mnCols ) + mnCols = 1; + } + else + mnCols = 1; + } + else + mnCols = mnUserCols; + + // Zeilenanzahl berechnen + mbScroll = FALSE; + mnLines = (long)mpImpl->mpItemList->Count() / mnCols; + if ( mpImpl->mpItemList->Count() % mnCols ) + mnLines++; + else if ( !mnLines ) + mnLines = 1; + + long nCalcHeight = aWinSize.Height()-nNoneHeight; + if ( mnUserVisLines ) + mnVisLines = mnUserVisLines; + else if ( mnUserItemHeight ) + { + mnVisLines = (nCalcHeight-nNoneSpace+nSpace) / (mnUserItemHeight+nSpace); + if ( !mnVisLines ) + mnVisLines = 1; + } + else + mnVisLines = mnLines; + if ( mnLines > mnVisLines ) + mbScroll = TRUE; + if ( mnLines <= mnVisLines ) + mnFirstLine = 0; + else + { + if ( mnFirstLine > (USHORT)(mnLines-mnVisLines) ) + mnFirstLine = (USHORT)(mnLines-mnVisLines); + } + + // Itemgroessen berechnen + long nColSpace = (mnCols-1)*nSpace; + long nLineSpace = ((mnVisLines-1)*nSpace)+nNoneSpace; + long nItemWidth; + long nItemHeight; + if ( mnUserItemWidth && !mnUserCols ) + { + nItemWidth = mnUserItemWidth; + if ( nItemWidth > aWinSize.Width()-nScrBarWidth-nColSpace ) + nItemWidth = aWinSize.Width()-nScrBarWidth-nColSpace; + } + else + nItemWidth = (aWinSize.Width()-nScrBarWidth-nColSpace) / mnCols; + if ( mnUserItemHeight && !mnUserVisLines ) + { + nItemHeight = mnUserItemHeight; + if ( nItemHeight > nCalcHeight-nNoneSpace ) + nItemHeight = nCalcHeight-nNoneSpace; + } + else + { + nCalcHeight -= nLineSpace; + nItemHeight = nCalcHeight / mnVisLines; + } + + // Init VirDev + maVirDev.SetSettings( GetSettings() ); + maVirDev.SetBackground( GetBackground() ); + maVirDev.SetOutputSizePixel( aWinSize, TRUE ); + + // Bei zu kleinen Items machen wir nichts + long nMinHeight = 2; + if ( nStyle & WB_ITEMBORDER ) + nMinHeight = 4; + if ( (nItemWidth <= 0) || (nItemHeight <= nMinHeight) || !nItemCount ) + { + if ( nStyle & WB_NONEFIELD ) + { + if ( mpNoneItem ) + { + mpNoneItem->maRect.SetEmpty(); + mpNoneItem->maText = GetText(); + } + } + + for ( ULONG i = 0; i < nItemCount; i++ ) + { + ValueSetItem* pItem = mpImpl->mpItemList->GetObject( i ); + pItem->maRect.SetEmpty(); + } + + if ( mpScrBar ) + mpScrBar->Hide(); + } + else + { + // Frame-Style ermitteln + if ( nStyle & WB_DOUBLEBORDER ) + mnFrameStyle = FRAME_DRAW_DOUBLEIN; + else + mnFrameStyle = FRAME_DRAW_IN; + + // Selektionsfarben und -breiten ermitteln + // Gegebenenfalls die Farben anpassen, damit man die Selektion besser + // erkennen kann + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Color aHighColor( rStyleSettings.GetHighlightColor() ); + if ( ((aHighColor.GetRed() > 0x80) || (aHighColor.GetGreen() > 0x80) || + (aHighColor.GetBlue() > 0x80)) || + ((aHighColor.GetRed() == 0x80) && (aHighColor.GetGreen() == 0x80) && + (aHighColor.GetBlue() == 0x80)) ) + mbBlackSel = TRUE; + else + mbBlackSel = FALSE; + + // Wenn die Items groesser sind, dann die Selektion doppelt so breit + // zeichnen + if ( (nStyle & WB_DOUBLEBORDER) && + ((nItemWidth >= 25) && (nItemHeight >= 20)) ) + mbDoubleSel = TRUE; + else + mbDoubleSel = FALSE; + + // Calculate offsets + long nStartX; + long nStartY; + if ( mbFullMode ) + { + long nAllItemWidth = (nItemWidth*mnCols)+nColSpace; + long nAllItemHeight = (nItemHeight*mnVisLines)+nNoneHeight+nLineSpace; + nStartX = (aWinSize.Width()-nScrBarWidth-nAllItemWidth)/2; + nStartY = (aWinSize.Height()-nAllItemHeight)/2; + } + else + { + nStartX = 0; + nStartY = 0; + } + + // Items berechnen und zeichnen + maVirDev.SetLineColor(); + long x = nStartX; + long y = nStartY; + + // NoSelection-Field erzeugen und anzeigen + if ( nStyle & WB_NONEFIELD ) + { + if ( !mpNoneItem ) + mpNoneItem = new ValueSetItem( *this ); + + mpNoneItem->mnId = 0; + mpNoneItem->meType = VALUESETITEM_NONE; + mpNoneItem->maRect.Left() = x; + mpNoneItem->maRect.Top() = y; + mpNoneItem->maRect.Right() = mpNoneItem->maRect.Left()+aWinSize.Width()-x-1; + mpNoneItem->maRect.Bottom() = y+nNoneHeight-1; + + ImplFormatItem( mpNoneItem ); + + y += nNoneHeight+nNoneSpace; + } + + // draw items + ULONG nFirstItem = mnFirstLine * mnCols; + ULONG nLastItem = nFirstItem + (mnVisLines * mnCols); + + if ( !mbFullMode ) + { + // If want also draw parts of items in the last line, + // then we add one more line if parts of these line are + // visible + if ( y+(mnVisLines*(nItemHeight+nSpace)) < aWinSize.Height() ) + nLastItem += mnCols; + } + for ( ULONG i = 0; i < nItemCount; i++ ) + { + ValueSetItem* pItem = mpImpl->mpItemList->GetObject( i ); + + if ( (i >= nFirstItem) && (i < nLastItem) ) + { + const BOOL bWasEmpty = pItem->maRect.IsEmpty(); + + pItem->maRect.Left() = x; + pItem->maRect.Top() = y; + pItem->maRect.Right() = pItem->maRect.Left()+nItemWidth-1; + pItem->maRect.Bottom() = pItem->maRect.Top()+nItemHeight-1; + + if( bWasEmpty && ImplHasAccessibleListeners() ) + { + ::com::sun::star::uno::Any aOldAny, aNewAny; + + aNewAny <<= pItem->GetAccessible( mpImpl->mbIsTransientChildrenDisabled ); + ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny ); + } + + ImplFormatItem( pItem ); + + if ( !((i+1) % mnCols) ) + { + x = nStartX; + y += nItemHeight+nSpace; + } + else + x += nItemWidth+nSpace; + } + else + { + if( !pItem->maRect.IsEmpty() && ImplHasAccessibleListeners() ) + { + ::com::sun::star::uno::Any aOldAny, aNewAny; + + aOldAny <<= pItem->GetAccessible( mpImpl->mbIsTransientChildrenDisabled ); + ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny ); + } + + pItem->maRect.SetEmpty(); + } + } + + // ScrollBar anordnen, Werte setzen und anzeigen + if ( mpScrBar ) + { + Point aPos( aWinSize.Width()-nScrBarWidth+SCRBAR_OFFSET, 0 ); + Size aSize( nScrBarWidth-SCRBAR_OFFSET, aWinSize.Height() ); + // If a none field is visible, then we center the scrollbar + if ( nStyle & WB_NONEFIELD ) + { + aPos.Y() = nStartY+nNoneHeight+1; + aSize.Height() = ((nItemHeight+nSpace)*mnVisLines)-2-nSpace; + } + mpScrBar->SetPosSizePixel( aPos, aSize ); + mpScrBar->SetRangeMax( mnLines ); + mpScrBar->SetVisibleSize( mnVisLines ); + mpScrBar->SetThumbPos( (long)mnFirstLine ); + long nPageSize = mnVisLines; + if ( nPageSize < 1 ) + nPageSize = 1; + mpScrBar->SetPageSize( nPageSize ); + mpScrBar->Show(); + } + } + + // Jetzt haben wir formatiert und warten auf das naechste + mbFormat = FALSE; + + // ScrollBar loeschen + if ( pDelScrBar ) + delete pDelScrBar; +} + +// ----------------------------------------------------------------------- + +void ValueSet::ImplDrawItemText( const XubString& rText ) +{ + if ( !(GetStyle() & WB_NAMEFIELD) ) + return; + + Size aWinSize = GetOutputSizePixel(); + long nTxtWidth = GetTextWidth( rText ); + long nTxtOffset = mnTextOffset; + + // Rechteck loeschen und Text ausgeben + if ( GetStyle() & WB_FLATVALUESET ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + SetLineColor(); + SetFillColor( rStyleSettings.GetFaceColor() ); + DrawRect( Rectangle( Point( 0, nTxtOffset ), Point( aWinSize.Width(), aWinSize.Height() ) ) ); + SetTextColor( rStyleSettings.GetButtonTextColor() ); + } + else + { + nTxtOffset += NAME_LINE_HEIGHT+NAME_LINE_OFF_Y; + Erase( Rectangle( Point( 0, nTxtOffset ), Point( aWinSize.Width(), aWinSize.Height() ) ) ); + } + DrawText( Point( (aWinSize.Width()-nTxtWidth) / 2, nTxtOffset+(NAME_OFFSET/2) ), rText ); +} + +// ----------------------------------------------------------------------- + +void ValueSet::ImplDrawSelect() +{ + if ( !IsReallyVisible() ) + return; + + BOOL bFocus = HasFocus(); + BOOL bDrawSel; + + if ( (mbNoSelection && !mbHighlight) || (!mbDrawSelection && mbHighlight) ) + bDrawSel = FALSE; + else + bDrawSel = TRUE; + + if ( !bFocus && + ((mbNoSelection && !mbHighlight) || (!mbDrawSelection && mbHighlight)) ) + { + XubString aEmptyStr; + ImplDrawItemText( aEmptyStr ); + return; + } + + USHORT nItemId = mnSelItemId; + + for( int stage = 0; stage < 2; stage++ ) + { + if( stage == 1 ) + { + if ( mbHighlight ) + nItemId = mnHighItemId; + else + break; + } + + ValueSetItem* pItem; + if ( nItemId ) + pItem = mpImpl->mpItemList->GetObject( GetItemPos( nItemId ) ); + else + { + if ( mpNoneItem ) + pItem = mpNoneItem; + else + { + pItem = ImplGetFirstItem(); + if ( !bFocus || !pItem ) + continue; + } + } + + if ( pItem->maRect.IsEmpty() ) + continue; + + // Selection malen + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Rectangle aRect = pItem->maRect; + Control::SetFillColor(); + + Color aDoubleColor( rStyleSettings.GetHighlightColor() ); + Color aSingleColor( rStyleSettings.GetHighlightTextColor() ); + if( ! mbDoubleSel ) + { + /* + * #99777# contrast enhancement for thin mode + */ + const Wallpaper& rWall = GetDisplayBackground(); + if( ! rWall.IsBitmap() && ! rWall.IsGradient() ) + { + const Color& rBack = rWall.GetColor(); + if( rBack.IsDark() && ! aDoubleColor.IsBright() ) + { + aDoubleColor = Color( COL_WHITE ); + aSingleColor = Color( COL_BLACK ); + } + else if( rBack.IsBright() && ! aDoubleColor.IsDark() ) + { + aDoubleColor = Color( COL_BLACK ); + aSingleColor = Color( COL_WHITE ); + } + } + } + + // Selectionsausgabe festlegen + WinBits nStyle = GetStyle(); + if ( nStyle & WB_MENUSTYLEVALUESET ) + { + if ( bFocus ) + ShowFocus( aRect ); + + if ( bDrawSel ) + { + if ( mbBlackSel ) + SetLineColor( Color( COL_BLACK ) ); + else + SetLineColor( aDoubleColor ); + DrawRect( aRect ); + } + } + else if ( nStyle & WB_RADIOSEL ) + { + aRect.Left() += 3; + aRect.Top() += 3; + aRect.Right() -= 3; + aRect.Bottom() -= 3; + if ( nStyle & WB_DOUBLEBORDER ) + { + aRect.Left()++; + aRect.Top()++; + aRect.Right()--; + aRect.Bottom()--; + } + + if ( bFocus ) + ShowFocus( aRect ); + + aRect.Left()++; + aRect.Top()++; + aRect.Right()--; + aRect.Bottom()--; + + if ( bDrawSel ) + { + SetLineColor( aDoubleColor ); + aRect.Left()++; + aRect.Top()++; + aRect.Right()--; + aRect.Bottom()--; + DrawRect( aRect ); + aRect.Left()++; + aRect.Top()++; + aRect.Right()--; + aRect.Bottom()--; + DrawRect( aRect ); + } + } + else + { + if ( bDrawSel ) + { + if ( mbBlackSel ) + SetLineColor( Color( COL_BLACK ) ); + else + SetLineColor( aDoubleColor ); + DrawRect( aRect ); + } + if ( mbDoubleSel ) + { + aRect.Left()++; + aRect.Top()++; + aRect.Right()--; + aRect.Bottom()--; + if ( bDrawSel ) + DrawRect( aRect ); + } + aRect.Left()++; + aRect.Top()++; + aRect.Right()--; + aRect.Bottom()--; + Rectangle aRect2 = aRect; + aRect.Left()++; + aRect.Top()++; + aRect.Right()--; + aRect.Bottom()--; + if ( bDrawSel ) + DrawRect( aRect ); + if ( mbDoubleSel ) + { + aRect.Left()++; + aRect.Top()++; + aRect.Right()--; + aRect.Bottom()--; + if ( bDrawSel ) + DrawRect( aRect ); + } + + if ( bDrawSel ) + { + if ( mbBlackSel ) + SetLineColor( Color( COL_WHITE ) ); + else + SetLineColor( aSingleColor ); + } + else + SetLineColor( Color( COL_LIGHTGRAY ) ); + DrawRect( aRect2 ); + + if ( bFocus ) + ShowFocus( aRect2 ); + } + + ImplDrawItemText( pItem->maText ); + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::ImplHideSelect( USHORT nItemId ) +{ + Rectangle aRect; + + USHORT nItemPos = GetItemPos( nItemId ); + if ( nItemPos != sal::static_int_cast<USHORT>(LIST_ENTRY_NOTFOUND) ) + aRect = mpImpl->mpItemList->GetObject( nItemPos )->maRect; + else + { + if ( mpNoneItem ) + aRect = mpNoneItem->maRect; + } + + if ( !aRect.IsEmpty() ) + { + HideFocus(); + Point aPos = aRect.TopLeft(); + Size aSize = aRect.GetSize(); + DrawOutDev( aPos, aSize, aPos, aSize, maVirDev ); + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::ImplHighlightItem( USHORT nItemId, BOOL bIsSelection ) +{ + if ( mnHighItemId != nItemId ) + { + // Alten merken, um vorherige Selektion zu entfernen + USHORT nOldItem = mnHighItemId; + mnHighItemId = nItemId; + + // Wenn keiner selektiert ist, dann Selektion nicht malen + if ( !bIsSelection && mbNoSelection ) + mbDrawSelection = FALSE; + + // Neu ausgeben und alte Selection wegnehmen + ImplHideSelect( nOldItem ); + ImplDrawSelect(); + mbDrawSelection = TRUE; + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::ImplDrawDropPos( BOOL bShow ) +{ + if ( (mnDropPos != VALUESET_ITEM_NOTFOUND) && mpImpl->mpItemList->Count() ) + { + USHORT nItemPos = mnDropPos; + USHORT nItemId1; + USHORT nItemId2 = 0; + BOOL bRight; + if ( nItemPos >= mpImpl->mpItemList->Count() ) + { + nItemPos = (USHORT)(mpImpl->mpItemList->Count()-1); + bRight = TRUE; + } + else + bRight = FALSE; + + nItemId1 = GetItemId( nItemPos ); + if ( (nItemId1 != mnSelItemId) && (nItemId1 != mnHighItemId) ) + nItemId1 = 0; + Rectangle aRect2 = mpImpl->mpItemList->GetObject( nItemPos )->maRect; + Rectangle aRect1; + if ( bRight ) + { + aRect1 = aRect2; + aRect2.SetEmpty(); + } + else if ( nItemPos > 0 ) + { + aRect1 = mpImpl->mpItemList->GetObject( nItemPos-1 )->maRect; + nItemId2 = GetItemId( nItemPos-1 ); + if ( (nItemId2 != mnSelItemId) && (nItemId2 != mnHighItemId) ) + nItemId2 = 0; + } + + // Items ueberhaupt sichtbar (nur Erstes/Letztes) + if ( !aRect1.IsEmpty() || !aRect2.IsEmpty() ) + { + if ( nItemId1 ) + ImplHideSelect( nItemId1 ); + if ( nItemId2 ) + ImplHideSelect( nItemId2 ); + + if ( bShow ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + long nX; + long nY; + SetLineColor( rStyleSettings.GetButtonTextColor() ); + if ( !aRect1.IsEmpty() ) + { + Point aPos = aRect1.RightCenter(); + nX = aPos.X()-2; + nY = aPos.Y(); + for ( USHORT i = 0; i < 4; i++ ) + DrawLine( Point( nX-i, nY-i ), Point( nX-i, nY+i ) ); + } + if ( !aRect2.IsEmpty() ) + { + Point aPos = aRect2.LeftCenter(); + nX = aPos.X()+2; + nY = aPos.Y(); + for ( USHORT i = 0; i < 4; i++ ) + DrawLine( Point( nX+i, nY-i ), Point( nX+i, nY+i ) ); + } + } + else + { + if ( !aRect1.IsEmpty() ) + { + Point aPos = aRect1.TopLeft(); + Size aSize = aRect1.GetSize(); + DrawOutDev( aPos, aSize, aPos, aSize, maVirDev ); + } + if ( !aRect2.IsEmpty() ) + { + Point aPos = aRect2.TopLeft(); + Size aSize = aRect2.GetSize(); + DrawOutDev( aPos, aSize, aPos, aSize, maVirDev ); + } + } + + if ( nItemId1 || nItemId2 ) + ImplDrawSelect(); + } + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::ImplDraw() +{ + if ( mbFormat ) + Format(); + + HideFocus(); + + Point aDefPos; + Size aSize = maVirDev.GetOutputSizePixel(); + + if ( mpScrBar && mpScrBar->IsVisible() ) + { + Point aScrPos = mpScrBar->GetPosPixel(); + Size aScrSize = mpScrBar->GetSizePixel(); + Point aTempPos( 0, aScrPos.Y() ); + Size aTempSize( aSize.Width(), aScrPos.Y() ); + + DrawOutDev( aDefPos, aTempSize, aDefPos, aTempSize, maVirDev ); + aTempSize.Width() = aScrPos.X()-1; + aTempSize.Height() = aScrSize.Height(); + DrawOutDev( aTempPos, aTempSize, aTempPos, aTempSize, maVirDev ); + aTempPos.Y() = aScrPos.Y()+aScrSize.Height(); + aTempSize.Width() = aSize.Width(); + aTempSize.Height() = aSize.Height()-aTempPos.Y(); + DrawOutDev( aTempPos, aTempSize, aTempPos, aTempSize, maVirDev ); + } + else + DrawOutDev( aDefPos, aSize, aDefPos, aSize, maVirDev ); + + // Trennlinie zum Namefield zeichnen + if ( GetStyle() & WB_NAMEFIELD ) + { + if ( !(GetStyle() & WB_FLATVALUESET) ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Size aWinSize = GetOutputSizePixel(); + Point aPos1( NAME_LINE_OFF_X, mnTextOffset+NAME_LINE_OFF_Y ); + Point aPos2( aWinSize.Width()-(NAME_LINE_OFF_X*2), mnTextOffset+NAME_LINE_OFF_Y ); + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + { + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( aPos1, aPos2 ); + aPos1.Y()++; + aPos2.Y()++; + SetLineColor( rStyleSettings.GetLightColor() ); + } + else + SetLineColor( rStyleSettings.GetWindowTextColor() ); + DrawLine( aPos1, aPos2 ); + } + } + + ImplDrawSelect(); +} + +// ----------------------------------------------------------------------- + +BOOL ValueSet::ImplScroll( const Point& rPos ) +{ + Size aOutSize = GetOutputSizePixel(); + long nScrBarWidth; + + if ( mpScrBar ) + nScrBarWidth = mpScrBar->GetSizePixel().Width(); + else + nScrBarWidth = 0; + + if ( !mbScroll || (rPos.X() < 0) || (rPos.X() > aOutSize.Width()-nScrBarWidth) ) + return FALSE; + + long nScrollOffset; + USHORT nOldLine = mnFirstLine; + const Rectangle& rTopRect = mpImpl->mpItemList->GetObject( mnFirstLine*mnCols )->maRect; + if ( rTopRect.GetHeight() <= 16 ) + nScrollOffset = VALUESET_SCROLL_OFFSET/2; + else + nScrollOffset = VALUESET_SCROLL_OFFSET; + if ( (mnFirstLine > 0) && (rPos.Y() >= 0) ) + { + long nTopPos = rTopRect.Top(); + if ( (rPos.Y() >= nTopPos) && (rPos.Y() <= nTopPos+nScrollOffset) ) + mnFirstLine--; + } + if ( (mnFirstLine == nOldLine) && + (mnFirstLine < (USHORT)(mnLines-mnVisLines)) && (rPos.Y() < aOutSize.Height()) ) + { + long nBottomPos = mpImpl->mpItemList->GetObject( (mnFirstLine+mnVisLines-1)*mnCols )->maRect.Bottom(); + if ( (rPos.Y() >= nBottomPos-nScrollOffset) && (rPos.Y() <= nBottomPos) ) + mnFirstLine++; + } + + if ( mnFirstLine != nOldLine ) + { + mbFormat = TRUE; + ImplDraw(); + return TRUE; + } + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +USHORT ValueSet::ImplGetItem( const Point& rPos, BOOL bMove ) const +{ + if ( mpNoneItem ) + { + if ( mpNoneItem->maRect.IsInside( rPos ) ) + return VALUESET_ITEM_NONEITEM; + } + + Point aDefPos; + Rectangle aWinRect( aDefPos, maVirDev.GetOutputSizePixel() ); + + ULONG nItemCount = mpImpl->mpItemList->Count(); + for ( ULONG i = 0; i < nItemCount; i++ ) + { + ValueSetItem* pItem = mpImpl->mpItemList->GetObject( i ); + if ( pItem->maRect.IsInside( rPos ) ) + { + if ( aWinRect.IsInside( rPos ) ) + return (USHORT)i; + else + return VALUESET_ITEM_NOTFOUND; + } + } + + // Wenn Spacing gesetzt ist, wird der vorher selektierte + // Eintrag zurueckgegeben, wenn die Maus noch nicht das Fenster + // verlassen hat + if ( bMove && mnSpacing && mnHighItemId ) + { + if ( aWinRect.IsInside( rPos ) ) + return GetItemPos( mnHighItemId ); + } + + return VALUESET_ITEM_NOTFOUND; +} + +// ----------------------------------------------------------------------- + +ValueSetItem* ValueSet::ImplGetItem( USHORT nPos ) +{ + if ( nPos == VALUESET_ITEM_NONEITEM ) + return mpNoneItem; + else + return mpImpl->mpItemList->GetObject( nPos ); +} + +// ----------------------------------------------------------------------- + +ValueSetItem* ValueSet::ImplGetFirstItem() +{ + USHORT nItemCount = (USHORT)mpImpl->mpItemList->Count(); + USHORT i = 0; + + while ( i < nItemCount ) + { + ValueSetItem* pItem = mpImpl->mpItemList->GetObject( i ); + if ( pItem->meType != VALUESETITEM_SPACE ) + return pItem; + i++; + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +USHORT ValueSet::ImplGetVisibleItemCount() const +{ + USHORT nRet = 0; + + for( sal_Int32 n = 0, nItemCount = mpImpl->mpItemList->Count(); n < nItemCount; n++ ) + { + ValueSetItem* pItem = mpImpl->mpItemList->GetObject( n ); + + if( pItem->meType != VALUESETITEM_SPACE && !pItem->maRect.IsEmpty() ) + nRet++; + } + + return nRet; +} + +// ----------------------------------------------------------------------- + +ValueSetItem* ValueSet::ImplGetVisibleItem( USHORT nVisiblePos ) +{ + ValueSetItem* pRet = NULL; + USHORT nFoundPos = 0; + + for( sal_Int32 n = 0, nItemCount = mpImpl->mpItemList->Count(); ( n < nItemCount ) && !pRet; n++ ) + { + ValueSetItem* pItem = mpImpl->mpItemList->GetObject( n ); + + if( ( pItem->meType != VALUESETITEM_SPACE ) && !pItem->maRect.IsEmpty() && ( nVisiblePos == nFoundPos++ ) ) + pRet = pItem; + } + + return pRet; +} + +// ----------------------------------------------------------------------- + +void ValueSet::ImplFireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue ) +{ + ValueSetAcc* pAcc = ValueSetAcc::getImplementation( GetAccessible( FALSE ) ); + + if( pAcc ) + pAcc->FireAccessibleEvent( nEventId, rOldValue, rNewValue ); +} + +// ----------------------------------------------------------------------- + +BOOL ValueSet::ImplHasAccessibleListeners() +{ + ValueSetAcc* pAcc = ValueSetAcc::getImplementation( GetAccessible( FALSE ) ); + return( pAcc && pAcc->HasAccessibleListeners() ); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( ValueSet,ImplScrollHdl, ScrollBar*, pScrollBar ) +{ + USHORT nNewFirstLine = (USHORT)pScrollBar->GetThumbPos(); + if ( nNewFirstLine != mnFirstLine ) + { + mnFirstLine = nNewFirstLine; + mbFormat = TRUE; + ImplDraw(); + } + return 0; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( ValueSet,ImplTimerHdl, Timer*, EMPTYARG ) +{ + ImplTracking( GetPointerPosPixel(), TRUE ); + return 0; +} + +// ----------------------------------------------------------------------- + +void ValueSet::ImplTracking( const Point& rPos, BOOL bRepeat ) +{ + if ( bRepeat || mbSelection ) + { + if ( ImplScroll( rPos ) ) + { + if ( mbSelection ) + { + maTimer.SetTimeoutHdl( LINK( this, ValueSet, ImplTimerHdl ) ); + maTimer.SetTimeout( GetSettings().GetMouseSettings().GetScrollRepeat() ); + maTimer.Start(); + } + } + } + + ValueSetItem* pItem = ImplGetItem( ImplGetItem( rPos ) ); + if ( pItem && (pItem->meType != VALUESETITEM_SPACE) ) + { + if( GetStyle() & WB_MENUSTYLEVALUESET ) + mbHighlight = TRUE; + + ImplHighlightItem( pItem->mnId ); + } + else + { + if( GetStyle() & WB_MENUSTYLEVALUESET ) + mbHighlight = TRUE; + + ImplHighlightItem( mnSelItemId, FALSE ); + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::ImplEndTracking( const Point& rPos, BOOL bCancel ) +{ + ValueSetItem* pItem; + + // Bei Abbruch, den alten Status wieder herstellen + if ( bCancel ) + pItem = NULL; + else + pItem = ImplGetItem( ImplGetItem( rPos ) ); + + if ( pItem && (pItem->meType != VALUESETITEM_SPACE) ) + { + SelectItem( pItem->mnId ); + if ( !mbSelection && !(GetStyle() & WB_NOPOINTERFOCUS) ) + GrabFocus(); + mbHighlight = FALSE; + mbSelection = FALSE; + Select(); + } + else + { + ImplHighlightItem( mnSelItemId, FALSE ); + mbHighlight = FALSE; + mbSelection = FALSE; + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( rMEvt.IsLeft() ) + { + ValueSetItem* pItem = ImplGetItem( ImplGetItem( rMEvt.GetPosPixel() ) ); + if ( mbSelection ) + { + mbHighlight = TRUE; + if ( pItem && (pItem->meType != VALUESETITEM_SPACE) ) + { + mnOldItemId = mnSelItemId; + mnHighItemId = mnSelItemId; + ImplHighlightItem( pItem->mnId ); + } + + return; + } + else + { + if ( pItem && (pItem->meType != VALUESETITEM_SPACE) && !rMEvt.IsMod2() ) + { + if ( (pItem->mnBits & VIB_NODOUBLECLICK) || (rMEvt.GetClicks() == 1) ) + { + mnOldItemId = mnSelItemId; + mbHighlight = TRUE; + mnHighItemId = mnSelItemId; + ImplHighlightItem( pItem->mnId ); + StartTracking( STARTTRACK_SCROLLREPEAT ); + } + else if ( rMEvt.GetClicks() == 2 ) + DoubleClick(); + + return; + } + } + } + + Control::MouseButtonDown( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void ValueSet::MouseButtonUp( const MouseEvent& rMEvt ) +{ + // Wegen SelectionMode + if ( rMEvt.IsLeft() && mbSelection ) + ImplEndTracking( rMEvt.GetPosPixel(), FALSE ); + else + Control::MouseButtonUp( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void ValueSet::MouseMove( const MouseEvent& rMEvt ) +{ + // Wegen SelectionMode + if ( mbSelection || (GetStyle() & WB_MENUSTYLEVALUESET) ) + ImplTracking( rMEvt.GetPosPixel(), FALSE ); + Control::MouseMove( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void ValueSet::Tracking( const TrackingEvent& rTEvt ) +{ + Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel(); + + if ( rTEvt.IsTrackingEnded() ) + ImplEndTracking( aMousePos, rTEvt.IsTrackingCanceled() ); + else + ImplTracking( aMousePos, rTEvt.IsTrackingRepeat() ); +} + +// ----------------------------------------------------------------------- + +void ValueSet::KeyInput( const KeyEvent& rKEvt ) +{ + USHORT nLastItem = (USHORT)mpImpl->mpItemList->Count(); + USHORT nItemPos = VALUESET_ITEM_NOTFOUND; + USHORT nCurPos = VALUESET_ITEM_NONEITEM; + USHORT nCalcPos; + + if ( !nLastItem || !ImplGetFirstItem() ) + { + Control::KeyInput( rKEvt ); + return; + } + else + nLastItem--; + + if ( mnSelItemId ) + nCurPos = GetItemPos( mnSelItemId ); + nCalcPos = nCurPos; + + //switch off selection mode if key travelling is used + BOOL bDefault = FALSE; + switch ( rKEvt.GetKeyCode().GetCode() ) + { + case KEY_HOME: + if ( mpNoneItem ) + nItemPos = VALUESET_ITEM_NONEITEM; + else + { + nItemPos = 0; + while ( ImplGetItem( nItemPos )->meType == VALUESETITEM_SPACE ) + nItemPos++; + } + break; + + case KEY_END: + nItemPos = nLastItem; + while ( ImplGetItem( nItemPos )->meType == VALUESETITEM_SPACE ) + { + if ( nItemPos == 0 ) + nItemPos = VALUESET_ITEM_NONEITEM; + else + nItemPos--; + } + break; + + case KEY_LEFT: + case KEY_RIGHT: + if ( rKEvt.GetKeyCode().GetCode()==KEY_LEFT ) + { + do + { + if ( nCalcPos == VALUESET_ITEM_NONEITEM ) + nItemPos = nLastItem; + else if ( !nCalcPos ) + { + if ( mpNoneItem ) + nItemPos = VALUESET_ITEM_NONEITEM; + else + nItemPos = nLastItem; + } + else + nItemPos = nCalcPos-1; + nCalcPos = nItemPos; + } + while ( ImplGetItem( nItemPos )->meType == VALUESETITEM_SPACE ); + } + else + { + do + { + if ( nCalcPos == VALUESET_ITEM_NONEITEM ) + nItemPos = 0; + else if ( nCalcPos == nLastItem ) + { + if ( mpNoneItem ) + nItemPos = VALUESET_ITEM_NONEITEM; + else + nItemPos = 0; + } + else + nItemPos = nCalcPos+1; + nCalcPos = nItemPos; + } + while ( ImplGetItem( nItemPos )->meType == VALUESETITEM_SPACE ); + } + break; + + case KEY_UP: + case KEY_PAGEUP: + { + if( rKEvt.GetKeyCode().GetCode() != KEY_PAGEUP || + ( !rKEvt.GetKeyCode().IsShift() && !rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() ) ) + { + const long nLineCount = ( ( KEY_UP == rKEvt.GetKeyCode().GetCode() ) ? 1 : mnVisLines ); + do + { + if ( nCalcPos == VALUESET_ITEM_NONEITEM ) + { + if ( nLastItem+1 <= mnCols ) + nItemPos = mnCurCol; + else + { + nItemPos = ((((nLastItem+1)/mnCols)-1)*mnCols)+(mnCurCol%mnCols); + if ( nItemPos+mnCols <= nLastItem ) + nItemPos = nItemPos + mnCols; + } + } + else if ( nCalcPos >= ( nLineCount * mnCols ) ) + nItemPos = sal::static_int_cast< USHORT >( + nCalcPos - ( nLineCount * mnCols )); + else + { + if ( mpNoneItem ) + { + mnCurCol = nCalcPos%mnCols; + nItemPos = VALUESET_ITEM_NONEITEM; + } + else + { + if ( nLastItem+1 <= mnCols ) + nItemPos = nCalcPos; + else + { + nItemPos = ((((nLastItem+1)/mnCols)-1)*mnCols)+(nCalcPos%mnCols); + if ( nItemPos+mnCols <= nLastItem ) + nItemPos = nItemPos + mnCols; + } + } + } + nCalcPos = nItemPos; + } + while ( ImplGetItem( nItemPos )->meType == VALUESETITEM_SPACE ); + } + else + Control::KeyInput( rKEvt ); + } + break; + + case KEY_DOWN: + case KEY_PAGEDOWN: + { + if( rKEvt.GetKeyCode().GetCode() != KEY_PAGEDOWN || + ( !rKEvt.GetKeyCode().IsShift() && !rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() ) ) + { + const long nLineCount = ( ( KEY_DOWN == rKEvt.GetKeyCode().GetCode() ) ? 1 : mnVisLines ); + do + { + if ( nCalcPos == VALUESET_ITEM_NONEITEM ) + nItemPos = mnCurCol; + else if ( nCalcPos + ( nLineCount * mnCols ) <= nLastItem ) + nItemPos = sal::static_int_cast< USHORT >( + nCalcPos + ( nLineCount * mnCols )); + else + { +#if 0 + if( (KEY_DOWN == rKEvt.GetKeyCode().GetCode() ) && (GetStyle() & WB_MENUSTYLEVALUESET) ) + { + Window* pParent = GetParent(); + pParent->GrabFocus(); + pParent->KeyInput( rKEvt ); + break; + } + else +#endif + { + if ( mpNoneItem ) + { + mnCurCol = nCalcPos%mnCols; + nItemPos = VALUESET_ITEM_NONEITEM; + } + else + nItemPos = nCalcPos%mnCols; + } + } + nCalcPos = nItemPos; + } + while ( ImplGetItem( nItemPos )->meType == VALUESETITEM_SPACE ); + } + else + Control::KeyInput( rKEvt ); + + } + break; + case KEY_RETURN: + //enable default handling of KEY_RETURN in dialogs + if(0 != (GetStyle()&WB_NO_DIRECTSELECT)) + { + Select(); + break; + } + //no break; + default: + Control::KeyInput( rKEvt ); + bDefault = TRUE; + break; + } + if(!bDefault) + EndSelection(); + if ( nItemPos != VALUESET_ITEM_NOTFOUND ) + { + USHORT nItemId; + if ( nItemPos != VALUESET_ITEM_NONEITEM ) + nItemId = GetItemId( nItemPos ); + else + nItemId = 0; + + if ( nItemId != mnSelItemId ) + { + SelectItem( nItemId ); + //select only if WB_NO_DIRECTSELECT is not set + if(0 == (GetStyle()&WB_NO_DIRECTSELECT)) + Select(); + } + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::Command( const CommandEvent& rCEvt ) +{ + if ( (rCEvt.GetCommand() == COMMAND_WHEEL) || + (rCEvt.GetCommand() == COMMAND_STARTAUTOSCROLL) || + (rCEvt.GetCommand() == COMMAND_AUTOSCROLL) ) + { + if ( HandleScrollCommand( rCEvt, NULL, mpScrBar ) ) + return; + } + + Control::Command( rCEvt ); +} + +// ----------------------------------------------------------------------- + +void ValueSet::Paint( const Rectangle& ) +{ + if ( GetStyle() & WB_FLATVALUESET ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + SetLineColor(); + SetFillColor( rStyleSettings.GetFaceColor() ); + long nOffY = maVirDev.GetOutputSizePixel().Height(); + Size aWinSize = GetOutputSizePixel(); + DrawRect( Rectangle( Point( 0, nOffY ), Point( aWinSize.Width(), aWinSize.Height() ) ) ); + } + + ImplDraw(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::GetFocus() +{ + OSL_TRACE ("value set getting focus"); + ImplDrawSelect(); + Control::GetFocus(); + + // Tell the accessible object that we got the focus. + ValueSetAcc* pAcc = ValueSetAcc::getImplementation( GetAccessible( FALSE ) ); + if( pAcc ) + pAcc->GetFocus(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::LoseFocus() +{ + OSL_TRACE ("value set losing focus"); + if ( mbNoSelection && mnSelItemId ) + ImplHideSelect( mnSelItemId ); + else + HideFocus(); + Control::LoseFocus(); + + // Tell the accessible object that we lost the focus. + ValueSetAcc* pAcc = ValueSetAcc::getImplementation( GetAccessible( FALSE ) ); + if( pAcc ) + pAcc->LoseFocus(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::Resize() +{ + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + Control::Resize(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::RequestHelp( const HelpEvent& rHEvt ) +{ + if ( (rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON)) == HELPMODE_QUICK ) + { + Point aPos = ScreenToOutputPixel( rHEvt.GetMousePosPixel() ); + USHORT nItemPos = ImplGetItem( aPos ); + if ( nItemPos != VALUESET_ITEM_NOTFOUND ) + { + ValueSetItem* pItem = ImplGetItem( nItemPos ); + Rectangle aItemRect = pItem->maRect; + Point aPt = OutputToScreenPixel( aItemRect.TopLeft() ); + aItemRect.Left() = aPt.X(); + aItemRect.Top() = aPt.Y(); + aPt = OutputToScreenPixel( aItemRect.BottomRight() ); + aItemRect.Right() = aPt.X(); + aItemRect.Bottom() = aPt.Y(); + Help::ShowQuickHelp( this, aItemRect, GetItemText( pItem->mnId ) ); + return; + } + } + + Control::RequestHelp( rHEvt ); +} + +// ----------------------------------------------------------------------- + +void ValueSet::StateChanged( StateChangedType nType ) +{ + Control::StateChanged( nType ); + + if ( nType == STATE_CHANGE_INITSHOW ) + { + if ( mbFormat ) + Format(); + } + else if ( nType == STATE_CHANGE_UPDATEMODE ) + { + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + } + else if ( nType == STATE_CHANGE_TEXT ) + { + if ( mpNoneItem && !mbFormat && IsReallyVisible() && IsUpdateMode() ) + { + ImplFormatItem( mpNoneItem ); + Invalidate( mpNoneItem->maRect ); + } + } + else if ( (nType == STATE_CHANGE_ZOOM) || + (nType == STATE_CHANGE_CONTROLFONT) ) + { + ImplInitSettings( TRUE, FALSE, FALSE ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLFOREGROUND ) + { + ImplInitSettings( FALSE, TRUE, FALSE ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings( FALSE, FALSE, TRUE ); + Invalidate(); + } + else if ( (nType == STATE_CHANGE_STYLE) || (nType == STATE_CHANGE_ENABLE) ) + { + mbFormat = TRUE; + ImplInitSettings( FALSE, FALSE, TRUE ); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Control::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_DISPLAY) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + mbFormat = TRUE; + ImplInitSettings( TRUE, TRUE, TRUE ); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::Select() +{ + maSelectHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void ValueSet::DoubleClick() +{ + maDoubleClickHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void ValueSet::UserDraw( const UserDrawEvent& ) +{ +} + +// ----------------------------------------------------------------------- + +void ValueSet::InsertItem( USHORT nItemId, const Image& rImage, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "ValueSet::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == VALUESET_ITEM_NOTFOUND, + "ValueSet::InsertItem(): ItemId already exists" ); + + ValueSetItem* pItem = new ValueSetItem( *this ); + pItem->mnId = nItemId; + pItem->meType = VALUESETITEM_IMAGE; + pItem->maImage = rImage; + mpImpl->mpItemList->Insert( pItem, (ULONG)nPos ); + + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::InsertItem( USHORT nItemId, const Color& rColor, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "ValueSet::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == VALUESET_ITEM_NOTFOUND, + "ValueSet::InsertItem(): ItemId already exists" ); + + ValueSetItem* pItem = new ValueSetItem( *this ); + pItem->mnId = nItemId; + pItem->meType = VALUESETITEM_COLOR; + pItem->maColor = rColor; + mpImpl->mpItemList->Insert( pItem, (ULONG)nPos ); + + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::InsertItem( USHORT nItemId, const Image& rImage, + const XubString& rText, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "ValueSet::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == VALUESET_ITEM_NOTFOUND, + "ValueSet::InsertItem(): ItemId already exists" ); + + ValueSetItem* pItem = new ValueSetItem( *this ); + pItem->mnId = nItemId; + pItem->meType = VALUESETITEM_IMAGE; + pItem->maImage = rImage; + pItem->maText = rText; + mpImpl->mpItemList->Insert( pItem, (ULONG)nPos ); + + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::InsertItem( USHORT nItemId, const Color& rColor, + const XubString& rText, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "ValueSet::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == VALUESET_ITEM_NOTFOUND, + "ValueSet::InsertItem(): ItemId already exists" ); + + ValueSetItem* pItem = new ValueSetItem( *this ); + pItem->mnId = nItemId; + pItem->meType = VALUESETITEM_COLOR; + pItem->maColor = rColor; + pItem->maText = rText; + mpImpl->mpItemList->Insert( pItem, (ULONG)nPos ); + + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::InsertItem( USHORT nItemId, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "ValueSet::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == VALUESET_ITEM_NOTFOUND, + "ValueSet::InsertItem(): ItemId already exists" ); + + ValueSetItem* pItem = new ValueSetItem( *this ); + pItem->mnId = nItemId; + pItem->meType = VALUESETITEM_USERDRAW; + mpImpl->mpItemList->Insert( pItem, (ULONG)nPos ); + + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::InsertSpace( USHORT nItemId, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "ValueSet::InsertSpace(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == VALUESET_ITEM_NOTFOUND, + "ValueSet::InsertSpace(): ItemId already exists" ); + + ValueSetItem* pItem = new ValueSetItem( *this ); + pItem->mnId = nItemId; + pItem->meType = VALUESETITEM_SPACE; + mpImpl->mpItemList->Insert( pItem, (ULONG)nPos ); + + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::RemoveItem( USHORT nItemId ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos == VALUESET_ITEM_NOTFOUND ) + return; + + delete mpImpl->mpItemList->Remove( nPos ); + + // Variablen zuruecksetzen + if ( (mnHighItemId == nItemId) || (mnSelItemId == nItemId) ) + { + mnCurCol = 0; + mnOldItemId = 0; + mnHighItemId = 0; + mnSelItemId = 0; + mbNoSelection = TRUE; + } + + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::CopyItems( const ValueSet& rValueSet ) +{ + ImplDeleteItems(); + + ValueSetItem* pItem = rValueSet.mpImpl->mpItemList->First(); + while ( pItem ) + { + ValueSetItem* pNewItem = new ValueSetItem( *this ); + + pNewItem->mnId = pItem->mnId; + pNewItem->mnBits = pItem->mnBits; + pNewItem->meType = pItem->meType; + pNewItem->maImage = pItem->maImage; + pNewItem->maColor = pItem->maColor; + pNewItem->maText = pItem->maText; + pNewItem->mpData = pItem->mpData; + pNewItem->maRect = pItem->maRect; + pNewItem->mpxAcc = NULL; + + mpImpl->mpItemList->Insert( pNewItem ); + pItem = rValueSet.mpImpl->mpItemList->Next(); + } + + // Variablen zuruecksetzen + mnFirstLine = 0; + mnCurCol = 0; + mnOldItemId = 0; + mnHighItemId = 0; + mnSelItemId = 0; + mbNoSelection = TRUE; + + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::Clear() +{ + ImplDeleteItems(); + + // Variablen zuruecksetzen + mnFirstLine = 0; + mnCurCol = 0; + mnOldItemId = 0; + mnHighItemId = 0; + mnSelItemId = 0; + mbNoSelection = TRUE; + + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); +} + +// ----------------------------------------------------------------------- + +USHORT ValueSet::GetItemCount() const +{ + return (USHORT)mpImpl->mpItemList->Count(); +} + +// ----------------------------------------------------------------------- + +USHORT ValueSet::GetItemPos( USHORT nItemId ) const +{ + ValueSetItem* pItem = mpImpl->mpItemList->First(); + while ( pItem ) + { + if ( pItem->mnId == nItemId ) + return (USHORT)mpImpl->mpItemList->GetCurPos(); + pItem = mpImpl->mpItemList->Next(); + } + + return VALUESET_ITEM_NOTFOUND; +} + +// ----------------------------------------------------------------------- + +USHORT ValueSet::GetItemId( USHORT nPos ) const +{ + ValueSetItem* pItem = mpImpl->mpItemList->GetObject( nPos ); + + if ( pItem ) + return pItem->mnId; + else + return 0; +} + +// ----------------------------------------------------------------------- + +USHORT ValueSet::GetItemId( const Point& rPos ) const +{ + USHORT nItemPos = ImplGetItem( rPos ); + if ( nItemPos != VALUESET_ITEM_NOTFOUND ) + return GetItemId( nItemPos ); + + return 0; +} + +// ----------------------------------------------------------------------- + +Rectangle ValueSet::GetItemRect( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != VALUESET_ITEM_NOTFOUND ) + return mpImpl->mpItemList->GetObject( nPos )->maRect; + else + return Rectangle(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::EnableFullItemMode( BOOL bFullMode ) +{ + mbFullMode = bFullMode; +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetColCount( USHORT nNewCols ) +{ + if ( mnUserCols != nNewCols ) + { + mnUserCols = nNewCols; + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetLineCount( USHORT nNewLines ) +{ + if ( mnUserVisLines != nNewLines ) + { + mnUserVisLines = nNewLines; + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetItemWidth( long nNewItemWidth ) +{ + if ( mnUserItemWidth != nNewItemWidth ) + { + mnUserItemWidth = nNewItemWidth; + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetItemHeight( long nNewItemHeight ) +{ + if ( mnUserItemHeight != nNewItemHeight ) + { + mnUserItemHeight = nNewItemHeight; + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetFirstLine( USHORT nNewLine ) +{ + if ( mnFirstLine != nNewLine ) + { + mnFirstLine = nNewLine; + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::SelectItem( USHORT nItemId ) +{ + USHORT nItemPos = 0; + + if ( nItemId ) + { + nItemPos = GetItemPos( nItemId ); + if ( nItemPos == VALUESET_ITEM_NOTFOUND ) + return; + if ( mpImpl->mpItemList->GetObject( nItemPos )->meType == VALUESETITEM_SPACE ) + return; + } + + if ( (mnSelItemId != nItemId) || mbNoSelection ) + { + USHORT nOldItem = mnSelItemId ? mnSelItemId : 1; + mnSelItemId = nItemId; + mbNoSelection = FALSE; + + BOOL bNewOut; + BOOL bNewLine; + if ( !mbFormat && IsReallyVisible() && IsUpdateMode() ) + bNewOut = TRUE; + else + bNewOut = FALSE; + bNewLine = FALSE; + + // Gegebenenfalls in den sichtbaren Bereich scrollen + if ( mbScroll && nItemId ) + { + USHORT nNewLine = (USHORT)(nItemPos / mnCols); + if ( nNewLine < mnFirstLine ) + { + mnFirstLine = nNewLine; + bNewLine = TRUE; + } + else if ( nNewLine > (USHORT)(mnFirstLine+mnVisLines-1) ) + { + mnFirstLine = (USHORT)(nNewLine-mnVisLines+1); + bNewLine = TRUE; + } + } + + if ( bNewOut ) + { + if ( bNewLine ) + { + // Falls sich der sichtbare Bereich geaendert hat, + // alles neu ausgeben + mbFormat = TRUE; + ImplDraw(); + } + else + { + // alte Selection wegnehmen und neue ausgeben + ImplHideSelect( nOldItem ); + ImplDrawSelect(); + } + } + + if( ImplHasAccessibleListeners() ) + { + // focus event (deselect) + if( nOldItem ) + { + const USHORT nPos = GetItemPos( nItemId ); + + if( nPos != VALUESET_ITEM_NOTFOUND ) + { + ValueItemAcc* pItemAcc = ValueItemAcc::getImplementation( + mpImpl->mpItemList->GetObject( nPos )->GetAccessible( mpImpl->mbIsTransientChildrenDisabled ) ); + + if( pItemAcc ) + { + ::com::sun::star::uno::Any aOldAny, aNewAny; + if( !mpImpl->mbIsTransientChildrenDisabled) + { + aOldAny <<= ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >( + static_cast< ::cppu::OWeakObject* >( pItemAcc )); + ImplFireAccessibleEvent (::com::sun::star::accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny ); + } + else + { + aOldAny <<= ::com::sun::star::accessibility::AccessibleStateType::FOCUSED; + pItemAcc->FireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny ); + } + } + } + } + + // focus event (select) + const USHORT nPos = GetItemPos( mnSelItemId ); + + ValueSetItem* pItem; + if( nPos != VALUESET_ITEM_NOTFOUND ) + pItem = mpImpl->mpItemList->GetObject(nPos); + else + pItem = mpNoneItem; + + ValueItemAcc* pItemAcc = NULL; + if (pItem != NULL) + pItemAcc = ValueItemAcc::getImplementation(pItem->GetAccessible( mpImpl->mbIsTransientChildrenDisabled ) ); + + if( pItemAcc ) + { + ::com::sun::star::uno::Any aOldAny, aNewAny; + if( !mpImpl->mbIsTransientChildrenDisabled) + { + aNewAny <<= ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >( + static_cast< ::cppu::OWeakObject* >( pItemAcc )); + ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny ); + } + else + { + aNewAny <<= ::com::sun::star::accessibility::AccessibleStateType::FOCUSED; + pItemAcc->FireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny ); + } + } + + // selection event + ::com::sun::star::uno::Any aOldAny, aNewAny; + ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::SELECTION_CHANGED, aOldAny, aNewAny ); + } + mpImpl->maHighlightHdl.Call(this); + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetNoSelection() +{ + mbNoSelection = TRUE; + mbHighlight = FALSE; + mbSelection = FALSE; + + if ( IsReallyVisible() && IsUpdateMode() ) + ImplDraw(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetItemBits( USHORT nItemId, USHORT nItemBits ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != VALUESET_ITEM_NOTFOUND ) + mpImpl->mpItemList->GetObject( nPos )->mnBits = nItemBits; +} + +// ----------------------------------------------------------------------- + +USHORT ValueSet::GetItemBits( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != VALUESET_ITEM_NOTFOUND ) + return mpImpl->mpItemList->GetObject( nPos )->mnBits; + else + return 0; +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetItemImage( USHORT nItemId, const Image& rImage ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos == VALUESET_ITEM_NOTFOUND ) + return; + + ValueSetItem* pItem = mpImpl->mpItemList->GetObject( nPos ); + pItem->meType = VALUESETITEM_IMAGE; + pItem->maImage = rImage; + + if ( !mbFormat && IsReallyVisible() && IsUpdateMode() ) + { + ImplFormatItem( pItem ); + Invalidate( pItem->maRect ); + } + else + mbFormat = TRUE; +} + +// ----------------------------------------------------------------------- + +Image ValueSet::GetItemImage( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != VALUESET_ITEM_NOTFOUND ) + return mpImpl->mpItemList->GetObject( nPos )->maImage; + else + return Image(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetItemColor( USHORT nItemId, const Color& rColor ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos == VALUESET_ITEM_NOTFOUND ) + return; + + ValueSetItem* pItem = mpImpl->mpItemList->GetObject( nPos ); + pItem->meType = VALUESETITEM_COLOR; + pItem->maColor = rColor; + + if ( !mbFormat && IsReallyVisible() && IsUpdateMode() ) + { + ImplFormatItem( pItem ); + Invalidate( pItem->maRect ); + } + else + mbFormat = TRUE; +} + +// ----------------------------------------------------------------------- + +Color ValueSet::GetItemColor( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != VALUESET_ITEM_NOTFOUND ) + return mpImpl->mpItemList->GetObject( nPos )->maColor; + else + return Color(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetItemData( USHORT nItemId, void* pData ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos == VALUESET_ITEM_NOTFOUND ) + return; + + ValueSetItem* pItem = mpImpl->mpItemList->GetObject( nPos ); + pItem->mpData = pData; + + if ( pItem->meType == VALUESETITEM_USERDRAW ) + { + if ( !mbFormat && IsReallyVisible() && IsUpdateMode() ) + { + ImplFormatItem( pItem ); + Invalidate( pItem->maRect ); + } + else + mbFormat = TRUE; + } +} + +// ----------------------------------------------------------------------- + +void* ValueSet::GetItemData( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != VALUESET_ITEM_NOTFOUND ) + return mpImpl->mpItemList->GetObject( nPos )->mpData; + else + return NULL; +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetItemText( USHORT nItemId, const XubString& rText ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos == VALUESET_ITEM_NOTFOUND ) + return; + + + ValueSetItem* pItem = mpImpl->mpItemList->GetObject( nPos ); + + // Remember old and new name for accessibility event. + ::com::sun::star::uno::Any aOldName, aNewName; + ::rtl::OUString sString (pItem->maText); + aOldName <<= sString; + sString = rText; + aNewName <<= sString; + + pItem->maText = rText; + + if ( !mbFormat && IsReallyVisible() && IsUpdateMode() ) + { + USHORT nTempId = mnSelItemId; + + if ( mbHighlight ) + nTempId = mnHighItemId; + + if ( nTempId == nItemId ) + ImplDrawItemText( pItem->maText ); + } + + if (ImplHasAccessibleListeners()) + { + ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible> xAccessible ( + pItem->GetAccessible( mpImpl->mbIsTransientChildrenDisabled ) ); + static_cast<ValueItemAcc*>(xAccessible.get())->FireAccessibleEvent ( + ::com::sun::star::accessibility::AccessibleEventId::NAME_CHANGED, + aOldName, aNewName); + } +} + +// ----------------------------------------------------------------------- + +XubString ValueSet::GetItemText( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != VALUESET_ITEM_NOTFOUND ) + return mpImpl->mpItemList->GetObject( nPos )->maText; + else + return XubString(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetColor( const Color& rColor ) +{ + maColor = rColor; + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + ImplDraw(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetExtraSpacing( USHORT nNewSpacing ) +{ + if ( GetStyle() & WB_ITEMBORDER ) + { + mnSpacing = nNewSpacing; + + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void ValueSet::StartSelection() +{ + mnOldItemId = mnSelItemId; + mbHighlight = TRUE; + mbSelection = TRUE; + mnHighItemId = mnSelItemId; +} + +// ----------------------------------------------------------------------- + +void ValueSet::EndSelection() +{ + if ( mbHighlight ) + { + if ( IsTracking() ) + EndTracking( ENDTRACK_CANCEL ); + + ImplHighlightItem( mnSelItemId ); + mbHighlight = FALSE; + } + mbSelection = FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL ValueSet::StartDrag( const CommandEvent& rCEvt, Region& rRegion ) +{ + if ( rCEvt.GetCommand() != COMMAND_STARTDRAG ) + return FALSE; + + // Gegebenenfalls eine vorhandene Aktion abbrechen + EndSelection(); + + // Testen, ob angeklickte Seite selektiert ist. Falls dies nicht + // der Fall ist, setzen wir ihn als aktuellen Eintrag. Falls Drag and + // Drop auch mal ueber Tastatur ausgeloest werden kann, testen wir + // dies nur bei einer Mausaktion. + USHORT nSelId; + if ( rCEvt.IsMouseEvent() ) + nSelId = GetItemId( rCEvt.GetMousePosPixel() ); + else + nSelId = mnSelItemId; + + // Falls kein Eintrag angeklickt wurde, starten wir kein Dragging + if ( !nSelId ) + return FALSE; + + // Testen, ob Seite selektiertiert ist. Falls nicht, als aktuelle + // Seite setzen und Select rufen. + if ( nSelId != mnSelItemId ) + { + SelectItem( nSelId ); + Update(); + Select(); + } + + Region aRegion; + + // Region zuweisen + rRegion = aRegion; + + return TRUE; +} + +// ----------------------------------------------------------------------- + +Size ValueSet::CalcWindowSizePixel( const Size& rItemSize, USHORT nDesireCols, + USHORT nDesireLines ) +{ + long nCalcCols = (long)nDesireCols; + long nCalcLines = (long)nDesireLines; + + if ( !nCalcCols ) + { + if ( mnUserCols ) + nCalcCols = (long)mnUserCols; + else + nCalcCols = 1; + } + + if ( !nCalcLines ) + { + nCalcLines = mnVisLines; + + if ( mbFormat ) + { + if ( mnUserVisLines ) + nCalcLines = mnUserVisLines; + else + { + nCalcLines = (long)mpImpl->mpItemList->Count() / nCalcCols; + if ( mpImpl->mpItemList->Count() % nCalcCols ) + nCalcLines++; + else if ( !nCalcLines ) + nCalcLines = 1; + } + } + } + + Size aSize( rItemSize.Width()*nCalcCols, rItemSize.Height()*nCalcLines ); + WinBits nStyle = GetStyle(); + long nTxtHeight = GetTextHeight(); + long nSpace; + long n; + + if ( nStyle & WB_ITEMBORDER ) + { + if ( nStyle & WB_DOUBLEBORDER ) + n = ITEM_OFFSET_DOUBLE; + else + n = ITEM_OFFSET; + + aSize.Width() += n*nCalcCols; + aSize.Height() += n*nCalcLines; + } + else + n = 0; + + if ( mnSpacing ) + { + nSpace = mnSpacing; + aSize.Width() += mnSpacing*(nCalcCols-1); + aSize.Height() += mnSpacing*(nCalcLines-1); + } + else + nSpace = 0; + + if ( nStyle & WB_NAMEFIELD ) + { + aSize.Height() += nTxtHeight + NAME_OFFSET; + if ( !(nStyle & WB_FLATVALUESET) ) + aSize.Height() += NAME_LINE_HEIGHT+NAME_LINE_OFF_Y; + } + + if ( nStyle & WB_NONEFIELD ) + { + aSize.Height() += nTxtHeight + n + nSpace; + if ( nStyle & WB_RADIOSEL ) + aSize.Height() += 8; + } + + // Evt. ScrollBar-Breite aufaddieren + aSize.Width() += GetScrollWidth(); + + return aSize; +} + +// ----------------------------------------------------------------------- + +Size ValueSet::CalcItemSizePixel( const Size& rItemSize, BOOL bOut ) const +{ + Size aSize = rItemSize; + + WinBits nStyle = GetStyle(); + if ( nStyle & WB_ITEMBORDER ) + { + long n; + + if ( nStyle & WB_DOUBLEBORDER ) + n = ITEM_OFFSET_DOUBLE; + else + n = ITEM_OFFSET; + + if ( bOut ) + { + aSize.Width() += n; + aSize.Height() += n; + } + else + { + aSize.Width() -= n; + aSize.Height() -= n; + } + } + + return aSize; +} + +// ----------------------------------------------------------------------- + +long ValueSet::GetScrollWidth() const +{ + if ( GetStyle() & WB_VSCROLL ) + { + ((ValueSet*)this)->ImplInitScrollBar(); + return mpScrBar->GetSizePixel().Width()+SCRBAR_OFFSET; + } + else + return 0; +} + +// ----------------------------------------------------------------------- + +USHORT ValueSet::ShowDropPos( const Point& rPos ) +{ + mbDropPos = TRUE; + + // Gegebenenfalls scrollen + ImplScroll( rPos ); + + // DropPosition ermitteln + USHORT nPos = ImplGetItem( rPos, TRUE ); + if ( nPos == VALUESET_ITEM_NONEITEM ) + nPos = 0; + else if ( nPos == VALUESET_ITEM_NOTFOUND ) + { + Size aOutSize = GetOutputSizePixel(); + if ( GetStyle() & WB_NAMEFIELD ) + aOutSize.Height() = mnTextOffset; + if ( (rPos.X() >= 0) && (rPos.X() < aOutSize.Width()) && + (rPos.Y() >= 0) && (rPos.Y() < aOutSize.Height()) ) + nPos = (USHORT)mpImpl->mpItemList->Count(); + } + else + { + // Im letzten viertel, dann wird ein Item spaeter eingefuegt + Rectangle aRect = mpImpl->mpItemList->GetObject( nPos )->maRect; + if ( rPos.X() > aRect.Left()+aRect.GetWidth()-(aRect.GetWidth()/4) ) + nPos++; + } + + if ( nPos != mnDropPos ) + { + ImplDrawDropPos( FALSE ); + mnDropPos = nPos; + ImplDrawDropPos( TRUE ); + } + + return mnDropPos; +} + +// ----------------------------------------------------------------------- + +void ValueSet::HideDropPos() +{ + if ( mbDropPos ) + { + ImplDrawDropPos( FALSE ); + mbDropPos = FALSE; + } +} + +// ----------------------------------------------------------------------- + +bool ValueSet::IsRTLActive (void) +{ + return Application::GetSettings().GetLayoutRTL() && IsRTLEnabled(); +} + +// ----------------------------------------------------------------------- + +void ValueSet::SetHighlightHdl( const Link& rLink ) +{ + mpImpl->maHighlightHdl = rLink; +} + +// ----------------------------------------------------------------------- + +const Link& ValueSet::GetHighlightHdl() const +{ + return mpImpl->maHighlightHdl; +} + +// ----------------------------------------------------------------------- + |