diff options
author | Ivo Hinkelmann <ihi@openoffice.org> | 2007-07-11 09:57:43 +0000 |
---|---|---|
committer | Ivo Hinkelmann <ihi@openoffice.org> | 2007-07-11 09:57:43 +0000 |
commit | 66d6cbcbf652f1873368faa7e03a119ff939b1c5 (patch) | |
tree | 370062964c61c04ee7587ce09848bcdd56c8171d /fpicker | |
parent | 7da0ebe121b5b07dfd3f020b23e9622628f12a82 (diff) |
INTEGRATION: CWS aquafilepicker01 (1.1.2); FILE ADDED
2007/06/16 11:41:05 pjanik 1.1.2.5: #i74798#: Add license header, whitespace cleanup.
2007/06/15 21:25:25 fheckl 1.1.2.4: cleanup changes
2007/05/09 06:12:05 fheckl 1.1.2.3: some cleanup and last changes
2007/04/28 14:03:53 fheckl 1.1.2.2: Several debug logging changes
2007/04/13 18:25:59 fheckl 1.1.2.1: Adding new files and general update
Diffstat (limited to 'fpicker')
-rw-r--r-- | fpicker/source/aqua/ControlHelper.cxx | 1061 |
1 files changed, 1061 insertions, 0 deletions
diff --git a/fpicker/source/aqua/ControlHelper.cxx b/fpicker/source/aqua/ControlHelper.cxx new file mode 100644 index 000000000000..446ee152ac76 --- /dev/null +++ b/fpicker/source/aqua/ControlHelper.cxx @@ -0,0 +1,1061 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ControlHelper.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: ihi $ $Date: 2007-07-11 10:57:43 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#ifndef _COM_SUN_STAR_UI_DIALOGS_EXTENDEDFILEPICKERELEMENTIDS_HPP_ +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> +#endif +#ifndef _COM_SUN_STAR_UI_DIALOGS_CONTROLACTIONS_HPP_ +#include <com/sun/star/ui/dialogs/ControlActions.hpp> +#endif +#ifndef _COM_SUN_STAR_UI_DIALOGS_TEMPLATEDESCRIPTION_HPP_ +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#endif +#ifndef _VOS_MUTEX_HXX_ +#include <vos/mutex.hxx> +#endif +#ifndef _SV_SVAPP_HXX +#include <vcl/svapp.hxx> +#endif +#ifndef _OSL_DIAGNOSE_H_ +#include <osl/diagnose.h> +#endif +#ifndef _CONTROLHELPER_HXX_ +#include "ControlHelper.hxx" +#endif +#ifndef _RESOURCEPROVIDER_HXX_ +#include "resourceprovider.hxx" +#endif + +#pragma mark DEFINES +#define CLASS_NAME "ControlHelper" + +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::ui::dialogs::TemplateDescription; +using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds; +using namespace ::rtl; + +#pragma mark Constructor / Destructor +//------------------------------------------------------------------------------------ +// Constructor / Destructor +//------------------------------------------------------------------------------------ +ControlHelper::ControlHelper() +: m_nLastCustomizeTryWidth(0) +, m_nLastCustomizeTryHeight(0) +, m_bUserPaneNeeded( false ) +, m_bIsFilterPopupPresent(false) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__); + + int i; + + for( i = 0; i < TOGGLE_LAST; i++ ) { + m_bToggleVisibility[i] = false; + } + + // for( i = 0; i < BUTTON_LAST; i++ ) + // m_pButtons[i] = NULL; + + for( i = 0; i < LIST_LAST; i++ ) { + m_bListVisibility[i] = false; + } + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + +ControlHelper::~ControlHelper() +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__); + + if (NULL != m_pUserPane) { + DisposeControl(m_pUserPane); + } + + for(std::list<ControlRef>::iterator control = m_aActiveControls.begin(); control != m_aActiveControls.end(); control++) { + ControlRef pControl = (*control); + ControlActionUPP pAction = GetControlAction(pControl); + if (NULL != pAction) { + DisposeControlActionUPP(pAction); + } + DisposeControl(*control); + } + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + +#pragma mark XInitialization delegate +//------------------------------------------------ +// XInitialization delegate +//------------------------------------------------ +void ControlHelper::initialize(sal_Int16 nTemplateId) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__, "templateId", nTemplateId); + + switch( nTemplateId ) + { + case FILESAVE_AUTOEXTENSION_PASSWORD: + m_bToggleVisibility[AUTOEXTENSION] = true; + m_bToggleVisibility[PASSWORD] = true; + break; + case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS: + m_bToggleVisibility[AUTOEXTENSION] = true; + m_bToggleVisibility[PASSWORD] = true; + m_bToggleVisibility[FILTEROPTIONS] = true; + break; + case FILESAVE_AUTOEXTENSION_SELECTION: + m_bToggleVisibility[AUTOEXTENSION] = true; + m_bToggleVisibility[SELECTION] = true; + break; + case FILESAVE_AUTOEXTENSION_TEMPLATE: + m_bToggleVisibility[AUTOEXTENSION] = true; + m_bListVisibility[TEMPLATE] = true; + break; + case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE: + m_bToggleVisibility[LINK] = true; + m_bToggleVisibility[PREVIEW] = true; + m_bListVisibility[IMAGE_TEMPLATE] = true; + break; + case FILEOPEN_READONLY_VERSION: + m_bToggleVisibility[READONLY] = true; + m_bListVisibility[VERSION] = true; + break; + case FILEOPEN_LINK_PREVIEW: + m_bToggleVisibility[LINK] = true; + m_bToggleVisibility[PREVIEW] = true; + break; + case FILESAVE_AUTOEXTENSION: + m_bToggleVisibility[AUTOEXTENSION] = true; + break; + } + + createControls(); + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + +#pragma mark XFilePickerControlAccess delegates +//------------------------------------------------------------------------------------ +// XFilePickerControlAccess functions +//------------------------------------------------------------------------------------ + +void ControlHelper::enableControl(sal_Int16 nControlId, sal_Bool bEnable) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "enable", bEnable); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + ControlRef pControl; + + if( ( pControl = getControl(nControlId)) ) { + if( bEnable ) { + OSL_TRACE( "enable" ); + } else { + OSL_TRACE( "disable" ); + } + HIViewSetEnabled(pControl, bEnable); + } else { + OSL_TRACE("enable unknown control %d", nControlId ); + } + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + +OUString ControlHelper::getLabel(sal_Int16 nControlId) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + ControlRef pControl; + + if( !( pControl = getControl( nControlId ) ) ) { + OSL_TRACE("Get label on unknown control %d", nControlId); + return OUString(); + } + + CFStringRef sLabel; + CopyControlTitleAsCFString(pControl, &sLabel); + rtl::OUString retVal = CFStringToOUString(sLabel); + CFRelease(sLabel); + + DBG_PRINT_EXIT(CLASS_NAME, __func__, retVal); + + return retVal; +} + +void ControlHelper::setLabel( sal_Int16 nControlId, const CFStringRef aLabel ) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "label", aLabel); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + ControlRef pControl = getControl(nControlId); + if (NULL != pControl) { + ControlType aSubType; + GetControlProperty(pControl,kAppFourCharCode,kControlPropertySubType,sizeof(aSubType),NULL,&aSubType); + if (aSubType == POPUPMENU) { + MenuRef rMenu = GetControlPopupMenuHandle(pControl); + //for the sizes to be calculated correctly, a menu item must be present in the menu + CFStringRef dummy = CFSTR("hi"); + AppendMenuItemTextWithCFString(rMenu, dummy, 0, 0, 0); + //dummy is no longer needed + CFRelease(dummy); + + SetControlTitleWithCFString(pControl, NULL); + + Rect sizeWoTitle; + GetBestControlRect(pControl,&sizeWoTitle,NULL); + //...and set the title here + SetControlTitleWithCFString(pControl,aLabel); + Rect sizeWithTitle; + GetBestControlRect(pControl,&sizeWithTitle,NULL); + + //now we no longer need the dummy menu item + DeleteMenuItem(rMenu, 1); + + //get the title's size + int nTitleWidth = sizeWithTitle.right - sizeWoTitle.right; + SetControlProperty(pControl,kAppFourCharCode,kPopupControlPropertyTitleWidth,sizeof(nTitleWidth),&nTitleWidth); + + } else if (aSubType == CHECKBOX) { + SetControlTitleWithCFString(pControl,aLabel); + } + } else { + OSL_TRACE("Control not found to set label for"); + } + + layoutControls(); + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + +void ControlHelper::setValue( sal_Int16 nControlId, sal_Int16 nControlAction, const uno::Any& rValue ) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "controlAction", nControlAction); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + ControlRef pControl; + + if( !( pControl = getControl( nControlId ) ) ) { + OSL_TRACE("enable unknown control %d", nControlId); + } else { + ControlType aSubType; + GetControlProperty(pControl,kAppFourCharCode,kControlPropertySubType,sizeof(aSubType),NULL,&aSubType); + if( aSubType == CHECKBOX ) { + sal_Bool bChecked = false; + rValue >>= bChecked; + OSL_TRACE(" value is a bool: %d", bChecked); + SetControlValue(pControl, bChecked); + } else if( aSubType == POPUPMENU ) { + HandleSetListValue(pControl, nControlAction, rValue); + } else + { + OSL_TRACE("Can't set value on button / list %d %d", + nControlId, nControlAction); + } + } + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + +uno::Any ControlHelper::getValue(sal_Int16 nControlId, sal_Int16 nControlAction) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "controlAction", nControlAction); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + uno::Any aRetval; + + ControlRef pControl; + + if( !( pControl = getControl( nControlId ) ) ) { + OSL_TRACE("get value for unknown control %d", nControlId); + } else { + ControlType aSubType; + GetControlProperty(pControl,kAppFourCharCode,kControlPropertySubType,sizeof(aSubType),NULL,&aSubType); + if( aSubType == CHECKBOX ) { + sal_Bool bValue = (sal_Bool)GetControlValue(pControl); + aRetval <<= bValue; + OSL_TRACE("value is a bool: %d", bValue); + } else if( aSubType == POPUPMENU ) { + aRetval = HandleGetListValue(pControl, nControlAction); + } + } + + DBG_PRINT_EXIT(CLASS_NAME, __func__); + + return aRetval; +} + +#pragma mark NavigationServices callback delegates +//------------------------------------------------------------------------------------ +// NavigationServices callback delegates +//------------------------------------------------------------------------------------ +void ControlHelper::handleStart(NavCBRecPtr callBackParms) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__); + + ::vos::OGuard aGuard(Application::GetSolarMutex()); + + OSStatus status = noErr; + + if (NULL != m_pUserPane) { + layoutControls(); + for (::std::list<ControlRef>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) { + ControlRef pControl = *child; + EmbedControl(pControl, m_pUserPane); + } + + status = NavCustomControl(callBackParms->context,kNavCtlAddControl,&m_pUserPane); + if (status != noErr) { + OSL_TRACE("NavigationServices refused to add the user pane"); + } + } + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + +void ControlHelper::handleCustomize(NavCBRecPtr callBackParms) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__); + + ::vos::OGuard aGuard(Application::GetSolarMutex()); + + if (true == m_bUserPaneNeeded && NULL == m_pUserPane) { + createUserPane(callBackParms->window); + } + + if (NULL == m_pUserPane) { + //nothing to do + return; + } + + if (callBackParms->customRect.right == 0 && callBackParms->customRect.bottom == 0) { + //this is the first try, let's try normal sized controls + Rect normalSize;// = m_pUserPane->getSize(SalAquaControlRefWrapper::NORMAL_SIZE); + GetBestControlRect(m_pUserPane,&normalSize,NULL); + m_nLastCustomizeTryWidth = normalSize.right - normalSize.left; + m_nLastCustomizeTryHeight = normalSize.bottom - normalSize.top; + callBackParms->customRect.right = callBackParms->customRect.left + m_nLastCustomizeTryWidth; + callBackParms->customRect.bottom = callBackParms->customRect.top + m_nLastCustomizeTryHeight; + } else { + int nSuggestedWidth = callBackParms->customRect.right - callBackParms->customRect.left; + int nSuggestedHeight = callBackParms->customRect.bottom - callBackParms->customRect.top; + if (nSuggestedWidth >= m_nLastCustomizeTryWidth && nSuggestedHeight >= m_nLastCustomizeTryHeight) { + //everything was accepted + return; + } else { + //TODO implement small and mini behavior + //this can be done in a separate child workspace sometime + } + } + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + +void ControlHelper::handleEvent(NavCBRecPtr callBackParms, NavEventCallbackMessage aLatestEvent) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__, "latestEvent", aLatestEvent); + + ::vos::OGuard aGuard(Application::GetSolarMutex()); + + NavEventData data = callBackParms->eventData; + NavEventDataInfo info = data.eventDataParms; + EventRecord *event = info.event; + EventKind aEventKind = event->what; + EventModifiers modifiers = event->modifiers; + + if (aEventKind == updateEvt) { + OSL_TRACE("UPDATE event"); + // the following is a little hacky because normally Apple says in her + // docs that we don't have to care about drawing our custom controls + // once they are added to the dialog. But this is definitely not true + // because without this hack controls would suddenly disappear if one + // control in the user pane area gets clicked. + bool display; + ControlRef pControl = NULL; + + for (::std::list<ControlRef>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) { + pControl = *child; + if (NULL == pControl) + continue; + display = HIViewGetNeedsDisplay(pControl) || (aLatestEvent == kNavCBAdjustRect); + if (!display) { + OSL_TRACE("REFRESHING CONTROL MYSELF"); + Draw1Control(pControl); + } + } + + return; + } + + if (aEventKind != mouseDown) { + return; + } + + Rect globWinBounds; + GetWindowBounds(callBackParms->window,kWindowContentRgn,&globWinBounds); + + MacOSPoint mousePt; + GetMouse(&mousePt); + SInt16 partResult; + ControlRef pControl = FindControlUnderMouse(mousePt,callBackParms->window,&partResult); + + if (!IsControlEnabled(pControl)) + return; + // OSL_TRACE("partResult: %d", partResult); + // + ControlType nSubType = NONE; + GetControlProperty(pControl,kAppFourCharCode,kControlPropertySubType,sizeof(ControlType),NULL,&nSubType); + + if (NONE == nSubType) { + //do nothing + return; + } + + if (nSubType == CHECKBOX) { + SInt16 oldValue = GetControlValue(pControl); + bool tracking = true; + SetControlProperty(pControl,kAppFourCharCode,kControlPropertyTracking, sizeof(bool),&tracking); + ControlPartCode lastCode = -1; + SetControlProperty(pControl, kAppFourCharCode,kControlPropertyLastPartCode, sizeof(ControlPartCode), &lastCode); + //ControlPartCode part = TrackControl(pControl,mousePt,(ControlActionUPP)-1); + ControlPartCode part = HandleControlClick(pControl,mousePt,modifiers,(ControlActionUPP)-1); + SetControlProperty(pControl, kAppFourCharCode,kControlPropertyLastPartCode, sizeof(ControlPartCode), &lastCode); + tracking = false; + SetControlProperty(pControl,kAppFourCharCode,kControlPropertyTracking, sizeof(bool),&tracking); + if (part == 0) { + SInt16 newValue = GetControlValue(pControl); + if (newValue == oldValue) { + //hit control handler was not called + MacOSPoint mouseUpPt; + GetMouse(&mouseUpPt); + if (mouseUpPt.h == mousePt.h && mouseUpPt.v == mousePt.v) { + SetControlValue(pControl,!newValue); + } + } + } else { + SetControlValue(pControl,1 - GetControlValue(pControl)); + } + } else if (nSubType == POPUPMENU) { + Rect localBounds; + GetControlBounds(pControl,&localBounds); + Rect upBounds; + GetControlBounds(m_pUserPane,&upBounds); + localBounds.left += upBounds.left; + localBounds.top += upBounds.top; + OSL_TRACE(" localBounds t:%d l:%d b:%d r:%d", localBounds.top, localBounds.left, localBounds.bottom, localBounds.right); + + int nTitleWidth; + GetControlProperty(pControl, kAppFourCharCode, kPopupControlPropertyTitleWidth,sizeof(nTitleWidth),NULL,&nTitleWidth); + //if we are hit in the popup's title, then do nothing + if (localBounds.left + nTitleWidth > mousePt.h) { + return; + } + + //we are hit in the menu, so display the menu + MenuRef pMenu = GetControlPopupMenuHandle(pControl); + SInt16 nSelectedItem = GetControlValue(pControl); + CheckMenuItem(pMenu,nSelectedItem,TRUE); + + int menuLeftPoint = globWinBounds.left + localBounds.left + nTitleWidth - 22 + 9; + int menuTopPoint = localBounds.top + globWinBounds.top + 1; + + OSL_TRACE(" menuLeft: %d", menuLeftPoint); + + long index = PopUpMenuSelect(pMenu, menuTopPoint, menuLeftPoint, GetControlValue(pControl)); + short high = (index & 0xFF00) >> 16; + short low = (index & 0x00FF); + OSL_TRACE(" item selected: %d %d", high, low); + if (low != 0) { + if (low != nSelectedItem) + CheckMenuItem(pMenu,nSelectedItem,FALSE); + SetControlValue(pControl,low); + OSL_TRACE(" popup menu value: %d", GetControlValue(pControl)); + } + } + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + +void ControlHelper::handleAdjustRect(NavCBRecPtr callBackParms) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__); + + if (NULL != m_pUserPane) { + SetControlBounds(m_pUserPane,&(callBackParms->customRect)); + } + layoutControls(); + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + +void ControlHelper::createUserPane(WindowRef parent) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__); + + if (NULL != m_pUserPane) { + return; + } + + OSStatus status = noErr; + + int currenttop = 0; + //NavServices will never be smaller + int maxWidth = kAquaNavigationServicesMinWidth; + + for (::std::list<ControlRef>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) { + ControlRef pControl = *child; + + Rect bestSize; + status = GetBestControlRect(pControl,&bestSize,NULL); + int nControlHeight = bestSize.bottom - bestSize.top; + int nControlWidth = bestSize.right - bestSize.left; + if ((nControlWidth + 2 * kAquaSpaceInsideGroup) > maxWidth) { + maxWidth = nControlWidth; + } + + if (pControl == *(m_aActiveControls.begin())) { + //first control + if (true == m_bIsFilterPopupPresent) { + //in this case we already have a control in the user pane: the file formats popup control + // and the user pane is already spaced correctly + //currenttop += kAquaSpaceBetweenControls; + } else { + currenttop += kAquaSpaceInsideGroup;//from top + } + } + else { + //we already have a control + currenttop += kAquaSpaceBetweenControls;//in-between space before + } + + //set the top value + bestSize.top = currenttop; + bestSize.bottom = currenttop + nControlHeight; + bestSize.left = kAquaSpaceInsideGroup; + bestSize.right = kAquaSpaceInsideGroup + nControlWidth; + + currenttop += nControlHeight; + } + //from bottom + currenttop += kAquaSpaceInsideGroup; + + //ok, we have all controls + Rect upRect = { 0, 0, currenttop, maxWidth }; + status = CreateUserPaneControl(parent,&upRect,0x16,&m_pUserPane); + + layoutControls(); + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + +#pragma mark Private / Misc +//------------------------------------------------------------------------------------ +// Private / Misc +//------------------------------------------------------------------------------------ +void SalAquaCheckboxAction(ControlRef pControl, ControlPartCode partCode) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__, "partCode", partCode); + + ControlPartCode lastCode; + GetControlProperty(pControl,kAppFourCharCode,kControlPropertyLastPartCode,sizeof(ControlPartCode),NULL,&lastCode); + + bool tracking; + GetControlProperty(pControl,kAppFourCharCode,kControlPropertyTracking,sizeof(bool),NULL, &tracking); + if (true == tracking) { + if (lastCode == -1) { + //first run + HiliteControl(pControl, kControlCheckBoxPart); + } + lastCode = partCode; + SetControlProperty(pControl,kAppFourCharCode,kControlPropertyLastPartCode,sizeof(ControlPartCode),&lastCode); + } else { + //keep initial state + if (partCode != 0) + SetControlValue(pControl, !GetControlValue(pControl)); + lastCode = -1; + SetControlProperty(pControl, kAppFourCharCode, kControlPropertyLastPartCode, sizeof(ControlPartCode), &lastCode); + } + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + +void ControlHelper::createControls() +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__); + + OSStatus status = noErr; + CResourceProvider aResProvider; + Rect dummyRect = { 0, 0, 0, 0 }; + +#define MENUOFFSET 1024 + for (int i = 0; i < LIST_LAST; i++) { + if (true == m_bListVisibility[i]) { + m_bUserPaneNeeded = true; + + int elementName = getControlElementName(POPUPMENU, i); + CFStringRef sLabel = aResProvider.getResString(elementName); + + MenuRef rMenu; + int menuId = MENUOFFSET + i; + status = CreateNewMenu(menuId, 0, &rMenu); + InsertMenu(rMenu, -1); + + //we create the popup menu control without title + status = CreatePopupButtonControl(NULL,&dummyRect,NULL, menuId, TRUE, -1,teFlushDefault,0,&m_pListControls[i]); + + ControlType aSubType = POPUPMENU; + SetControlProperty(m_pListControls[i],kAppFourCharCode,kControlPropertySubType,sizeof(aSubType),&aSubType); + +#define MAP_LIST_( elem ) \ +case elem: \ + setLabel(ExtendedFilePickerElementIds::LISTBOX_##elem, sLabel); \ + break + + switch(i) { + MAP_LIST_(VERSION); + MAP_LIST_(TEMPLATE); + MAP_LIST_(IMAGE_TEMPLATE); + } + CFRelease(sLabel); + + m_aActiveControls.push_back(m_pListControls[i]); + + Rect size; + GetBestControlRect(m_pListControls[i],&size,NULL); + if (size.right < kAquaNavigationServicesPopupControlWidth) { + size.right = kAquaNavigationServicesPopupControlWidth; + SetControlBounds(m_pListControls[i], &size); + } + //we don't have any menu items in the beginning, so let's disable the control + //HIViewSetEnabled(m_pListControls[i],false); + } else { + m_pListControls[i] = NULL; + } + } + + for (int i = 1; i < TOGGLE_LAST; i++) { + if (true == m_bToggleVisibility[i]) { + m_bUserPaneNeeded = true; + + int elementName = getControlElementName(CHECKBOX, i); + CFStringRef sLabel = aResProvider.getResString(elementName); + + status = CreateCheckBoxControl(NULL, &dummyRect, sLabel, FALSE, FALSE, &m_pToggles[i]); + CFRelease(sLabel); + m_aActiveControls.push_back(m_pToggles[i]); + + ControlType aSubType = CHECKBOX; + SetControlProperty(m_pToggles[i],kAppFourCharCode,kControlPropertySubType,sizeof(aSubType),&aSubType); + + ControlActionUPP pControlAction = NewControlActionUPP(SalAquaCheckboxAction); + SetControlAction(m_pToggles[i], pControlAction); + } else { + m_pToggles[i] = NULL; + } + } + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + +#define TOGGLE_ELEMENT( elem ) \ +case elem: \ + nReturn = CHECKBOX_##elem; \ + DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn); \ + return nReturn +#define LIST_ELEMENT( elem ) \ +case elem: \ + nReturn = LISTBOX_##elem##_LABEL; \ + DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn); \ + return nReturn + +int ControlHelper::getControlElementName(ControlType type, int nControlId) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__, "type", type, "controlId", nControlId); + + int nReturn = -1; + switch (type) { + case CHECKBOX: + { + switch (nControlId) { + TOGGLE_ELEMENT( AUTOEXTENSION ); + TOGGLE_ELEMENT( PASSWORD ); + TOGGLE_ELEMENT( FILTEROPTIONS ); + TOGGLE_ELEMENT( READONLY ); + TOGGLE_ELEMENT( LINK ); + TOGGLE_ELEMENT( PREVIEW ); + TOGGLE_ELEMENT( SELECTION ); + } + break; + } + case POPUPMENU: + { + switch (nControlId) { + LIST_ELEMENT( VERSION ); + LIST_ELEMENT( TEMPLATE ); + LIST_ELEMENT( IMAGE_TEMPLATE ); + } + break; + } + case NONE: + break; + default: + break; + } + + DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn); + + return nReturn; +} + +void ControlHelper::HandleSetListValue(const ControlRef pControl, const sal_Int16 nControlAction, const uno::Any& rValue) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlAction", nControlAction); + + MenuRef rMenu = GetControlPopupMenuHandle(pControl); + if (NULL == rMenu) { + return; + } + + switch (nControlAction) + { + case ControlActions::ADD_ITEM: + { + OSL_TRACE("ADD_ITEMS"); + OUString sItem; + rValue >>= sItem; + + int nMenuItems = CountMenuItems(rMenu); + if (nMenuItems == 0) { + //HIViewSetEnabled(pControl, true); + } + + CFStringRef sCFItem = CFStringCreateWithOUString(sItem); + OSL_TRACE("Adding menu item: %s", OUStringToOString(sItem, RTL_TEXTENCODING_UTF8).getStr()); + AppendMenuItemTextWithCFString(rMenu,sCFItem,0,0,NULL); + SetControlMaximum(pControl,CountMenuItems(rMenu)); + CFRelease(sCFItem); + //gtk_combo_box_append_text(pWidget, rtl::OUStringToOString(sItem, RTL_TEXTENCODING_UTF8).getStr()); + // if (!bVersionWidthUnset) + // { + // // HackWidthToFirst(pWidget); + // bVersionWidthUnset = true; + // } + } + break; + case ControlActions::ADD_ITEMS: + { + OSL_TRACE("ADD_ITEMS"); + uno::Sequence< OUString > aStringList; + rValue >>= aStringList; + sal_Int32 nItemCount = aStringList.getLength(); + for (sal_Int32 i = 0; i < nItemCount; ++i) + { + int nMenuItems = CountMenuItems(rMenu); + if (nMenuItems == 0) { + //HIViewSetEnabled(pControl, true); + } + CFStringRef sCFItem = CFStringCreateWithOUString(aStringList[i]); + OSL_TRACE("Adding menu item: %s", OUStringToOString(aStringList[i], RTL_TEXTENCODING_UTF8).getStr()); + AppendMenuItemTextWithCFString(rMenu,sCFItem,0,0,NULL); + CFRelease(sCFItem); + } + SetControlMaximum(pControl,CountMenuItems(rMenu)); + } + break; + case ControlActions::DELETE_ITEM: + { + OSL_TRACE("DELETE_ITEM"); + sal_Int32 nPos = -1; + rValue >>= nPos; + //in a MenuRef the first element has position 1 + OSL_TRACE("Deleteing item at position %d", (nPos + 1)); + DeleteMenuItem(rMenu,nPos + 1); + int nMenuItems = CountMenuItems(rMenu); + SetControlMaximum(pControl, nMenuItems); + if (nMenuItems == 0) { + //HIViewSetEnabled(pControl, false); + } + } + break; + case ControlActions::DELETE_ITEMS: + { + OSL_TRACE("DELETE_ITEMS"); + int nItems = CountMenuItems(rMenu); + if (nItems == 0) + return; + DeleteMenuItems(rMenu,1, nItems); + int nMenuItems = CountMenuItems(rMenu); + SetControlMaximum(pControl, nMenuItems); + if (nMenuItems == 0) { + //HIViewSetEnabled(pControl, false); + } + } + break; + case ControlActions::SET_SELECT_ITEM: + { + sal_Int32 nPos = -1; + rValue >>= nPos; + OSL_TRACE("Selecting item at position %d", (nPos + 1)); + //in a MenuRef the first element has position 1 + SetControlValue(pControl, nPos + 1); + } + break; + default: + OSL_TRACE("undocumented/unimplemented ControlAction for a list"); + break; + } + + layoutControls(); + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} + + +uno::Any ControlHelper::HandleGetListValue(const ControlRef pControl, const sal_Int16 nControlAction) const +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlAction", nControlAction); + + uno::Any aAny; + + MenuRef rMenu = GetControlPopupMenuHandle(pControl); + if (NULL == rMenu) { + return aAny; + } + + switch (nControlAction) + { + case ControlActions::GET_ITEMS: + { + OSL_TRACE("GET_ITEMS"); + uno::Sequence< OUString > aItemList; + + int nItems = CountMenuItems(rMenu); + if (nItems > 0) { + aItemList.realloc(nItems); + } + for (int i = 1; i <= nItems; i++) { + CFStringRef sCFItem; + CopyMenuItemTextAsCFString(rMenu, i, &sCFItem); + if (NULL != sCFItem) { + aItemList[i - 1] = CFStringToOUString(sCFItem); + OSL_TRACE("Return value[%d]: %s", (i - 1), OUStringToOString(aItemList[i - 1], RTL_TEXTENCODING_UTF8).getStr()); + CFRelease(sCFItem); + } + } + + aAny <<= aItemList; + } + break; + case ControlActions::GET_SELECTED_ITEM: + { + OSL_TRACE("GET_SELECTED_ITEM"); + int nIndex = GetControlValue(pControl); + CFStringRef sCFItem; + CopyMenuItemTextAsCFString(rMenu, nIndex, &sCFItem); + if (NULL != sCFItem) { + OUString sString = CFStringToOUString(sCFItem); + OSL_TRACE("Return value: %s", OUStringToOString(sString, RTL_TEXTENCODING_UTF8).getStr()); + aAny <<= sString; + CFRelease(sCFItem); + } + } + break; + case ControlActions::GET_SELECTED_ITEM_INDEX: + { + OSL_TRACE("GET_SELECTED_ITEM_INDEX"); + //menu indexes start at 1, so we have to subtract 1 + int nActive = GetControlValue(pControl) - 1; + OSL_TRACE("Return value: %d", nActive); + aAny <<= static_cast< sal_Int32 >(nActive); + } + break; + default: + OSL_TRACE("undocumented/unimplemented ControlAction for a list"); + break; + } + + DBG_PRINT_EXIT(CLASS_NAME, __func__); + + return aAny; +} + + +// cf. offapi/com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.idl +ControlRef ControlHelper::getControl( const sal_Int16 nControlId) +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId); + + ControlRef pWidget = NULL; + +#define MAP_TOGGLE( elem ) \ +case ExtendedFilePickerElementIds::CHECKBOX_##elem: \ + pWidget = m_pToggles[elem]; \ + break + +#define MAP_BUTTON( elem ) \ +case ExtendedFilePickerElementIds::PUSHBUTTON_##elem: \ + pWidget = m_pButtons[elem]; \ + break + +#define MAP_LIST( elem ) \ +case ExtendedFilePickerElementIds::LISTBOX_##elem: \ + pWidget = m_pListControls[elem]; \ + break + +#define MAP_LIST_LABEL( elem ) \ +case ExtendedFilePickerElementIds::LISTBOX_##elem##_LABEL: \ + pWidget = m_pListControls[elem]; \ + break + + switch( nControlId ) + { + case AUTOEXTENSION: + { + //handle differently on MacOSX + break; + } + MAP_TOGGLE( PASSWORD ); + MAP_TOGGLE( FILTEROPTIONS ); + MAP_TOGGLE( READONLY ); + MAP_TOGGLE( LINK ); + MAP_TOGGLE( PREVIEW ); + MAP_TOGGLE( SELECTION ); + //MAP_BUTTON( PLAY ); + MAP_LIST( VERSION ); + MAP_LIST( TEMPLATE ); + MAP_LIST( IMAGE_TEMPLATE ); + MAP_LIST_LABEL( VERSION ); + MAP_LIST_LABEL( TEMPLATE ); + MAP_LIST_LABEL( IMAGE_TEMPLATE ); + default: + OSL_TRACE("Handle unknown control %d", nControlId); + break; + } +#undef MAP + + DBG_PRINT_EXIT(CLASS_NAME, __func__); + + return pWidget; +} + +void ControlHelper::layoutControls() +{ + DBG_PRINT_ENTRY(CLASS_NAME, __func__); + + if (NULL == m_pUserPane) { + DBG_PRINT_EXIT(CLASS_NAME, __func__); + return; + } + + OSStatus status = noErr; + Rect userPaneRect; + GetControlBounds(m_pUserPane,&userPaneRect); + int nUsableWidth = userPaneRect.right - userPaneRect.left - 2 * kAquaSpaceInsideGroup; + + int currenttop = 0; + int nCheckboxMaxWidth = 0; + + for (::std::list<ControlRef>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) { + ControlRef pControl = *child; + + Rect bestSize; + status = GetBestControlRect(pControl,&bestSize,NULL); + int nControlHeight = bestSize.bottom - bestSize.top; + int nControlWidth = bestSize.right - bestSize.left; + + if (pControl == *(m_aActiveControls.begin())) { + //first control + if (true == m_bIsFilterPopupPresent) { + //in this case we already have a control in the user pane: the file formats popup control + // and the user pane is already spaced correctly + //currenttop += kAquaSpaceBetweenControls; + } else { + currenttop += kAquaSpaceInsideGroup;//from top + } + } + else { + //we already have a control + currenttop += kAquaSpaceBetweenControls;//in-between space before + } + + ControlType aSubType; + GetControlProperty(pControl,kAppFourCharCode,kControlPropertySubType,sizeof(aSubType),NULL,&aSubType); + if (aSubType == POPUPMENU) { + int nTitleWidth; + GetControlProperty(pControl,kAppFourCharCode,kPopupControlPropertyTitleWidth,sizeof(nTitleWidth),NULL,&nTitleWidth); + if (nControlWidth < kAquaNavigationServicesPopupControlWidth + nTitleWidth) + nControlWidth = kAquaNavigationServicesPopupControlWidth + nTitleWidth; + //let's center popups + bestSize.left = kAquaSpaceInsideGroup + (nUsableWidth - nControlWidth) / 2; + bestSize.right = bestSize.left + nControlWidth; + } else { + //for checkboxes first determine max. width + if (nCheckboxMaxWidth < nControlWidth) { + nCheckboxMaxWidth = nControlWidth; + } + } + + //set the top value + bestSize.top = currenttop; + bestSize.bottom = currenttop + nControlHeight; + SetControlBounds(pControl, &bestSize); + + currenttop += nControlHeight; + } + + int nCheckboxLeft = kAquaSpaceInsideGroup + (nUsableWidth - nCheckboxMaxWidth) / 2; + //second run to set checkbox dimensions + for (::std::list<ControlRef>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) { + ControlRef pControl = *child; + + ControlType aSubType; + GetControlProperty(pControl,kAppFourCharCode,kControlPropertySubType,sizeof(aSubType),NULL,&aSubType); + if (aSubType != CHECKBOX) { + //nothing to do for other types + continue; + } + + Rect bestSize; + status = GetBestControlRect(pControl,&bestSize,NULL); + int nControlWidth = bestSize.right - bestSize.left; + + bestSize.left = nCheckboxLeft; + bestSize.right = bestSize.left + nControlWidth; + SetControlBounds(pControl, &bestSize); + } + + DBG_PRINT_EXIT(CLASS_NAME, __func__); +} |