/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include #include #include #include #include #include #include "CFStringUtilities.hxx" #include "resourceprovider.hxx" #include "NSString_OOoAdditions.hxx" #include "ControlHelper.hxx" #pragma mark DEFINES #define CLASS_NAME "ControlHelper" #define POPUP_WIDTH_MIN 200 #define POPUP_WIDTH_MAX 350 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 ::com::sun::star::ui::dialogs::CommonFilePickerElementIds; using namespace ::rtl; #pragma mark Constructor / Destructor //------------------------------------------------------------------------------------ // Constructor / Destructor //------------------------------------------------------------------------------------ ControlHelper::ControlHelper() : m_pUserPane(NULL) , m_pFilterControl(nil) , m_bUserPaneNeeded( false ) , m_bIsUserPaneLaidOut(false) , m_bIsFilterControlNeeded(false) , m_pFilterHelper(NULL) { DBG_PRINT_ENTRY(CLASS_NAME, __func__); int i; for( i = 0; i < TOGGLE_LAST; i++ ) { m_bToggleVisibility[i] = false; } 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__); NSAutoreleasePool *pool = [NSAutoreleasePool new]; if (NULL != m_pUserPane) { [m_pUserPane release]; } for(std::list::iterator control = m_aActiveControls.begin(); control != m_aActiveControls.end(); control++) { NSControl* pControl = (*control); NSString* sLabelName = m_aMapListLabels[pControl]; if (sLabelName != nil) { [sLabelName release]; } if ([pControl class] == [NSPopUpButton class]) { NSTextField* pField = m_aMapListLabelFields[(NSPopUpButton*)pControl]; if (pField != nil) { [pField release]; } } [pControl release]; } if (m_pFilterControl != NULL) { [m_pFilterControl setTarget:nil]; } [pool release]; 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( const sal_Int16 nControlId, const sal_Bool bEnable ) const { DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "enable", bEnable); ::vos::OGuard aGuard( Application::GetSolarMutex() ); if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_PREVIEW) { OSL_TRACE(" preview checkbox cannot be changed"); DBG_PRINT_EXIT(CLASS_NAME, __func__); return; } NSControl* pControl = getControl(nControlId); if( pControl != nil ) { if( bEnable ) { OSL_TRACE( "enable" ); } else { OSL_TRACE( "disable" ); } [pControl setEnabled: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() ); NSControl* pControl = getControl( nControlId ); if( pControl == nil ) { OSL_TRACE("Get label for unknown control %d", nControlId); return OUString(); } rtl::OUString retVal; if ([pControl class] == [NSPopUpButton class]) { NSString *temp = m_aMapListLabels[pControl]; if (temp != nil) retVal = [temp OUString]; } else { NSString* sLabel = [[pControl cell] title]; retVal = [sLabel OUString]; } DBG_PRINT_EXIT(CLASS_NAME, __func__, retVal); return retVal; } void ControlHelper::setLabel( sal_Int16 nControlId, NSString* aLabel ) { DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "label", aLabel); ::vos::OGuard aGuard( Application::GetSolarMutex() ); NSAutoreleasePool *pool = [NSAutoreleasePool new]; NSControl* pControl = getControl(nControlId); if (nil != pControl) { if ([pControl class] == [NSPopUpButton class]) { NSString *sOldName = m_aMapListLabels[pControl]; if (sOldName != NULL && sOldName != aLabel) { [sOldName release]; } m_aMapListLabels[pControl] = [aLabel retain]; } else if ([pControl class] == [NSButton class]) { [[pControl cell] setTitle:aLabel]; } } else { OSL_TRACE("Control not found to set label for"); } layoutControls(); [pool release]; 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() ); if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_PREVIEW) { OSL_TRACE(" value for preview is unchangeable"); } else { NSControl* pControl = getControl( nControlId ); if( pControl == nil ) { OSL_TRACE("enable unknown control %d", nControlId); } else { if( [pControl class] == [NSPopUpButton class] ) { HandleSetListValue(pControl, nControlAction, rValue); } else if( [pControl class] == [NSButton class] ) { sal_Bool bChecked = false; rValue >>= bChecked; OSL_TRACE(" value is a bool: %d", bChecked); [(NSButton*)pControl setState:(bChecked ? NSOnState : NSOffState)]; } 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 ) const { DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "controlAction", nControlAction); ::vos::OGuard aGuard( Application::GetSolarMutex() ); uno::Any aRetval; NSControl* pControl = getControl( nControlId ); if( pControl == nil ) { OSL_TRACE("get value for unknown control %d", nControlId); aRetval <<= sal_True; } else { if( [pControl class] == [NSPopUpButton class] ) { aRetval = HandleGetListValue(pControl, nControlAction); } else if( [pControl class] == [NSButton class] ) { //NSLog(@"control: %@", [[pControl cell] title]); sal_Bool bValue = [(NSButton*)pControl state] == NSOnState ? sal_True : sal_False; aRetval <<= bValue; OSL_TRACE("value is a bool (checkbox): %d", bValue); } } DBG_PRINT_EXIT(CLASS_NAME, __func__); return aRetval; } void ControlHelper::createUserPane() { DBG_PRINT_ENTRY(CLASS_NAME, __func__); if (m_bUserPaneNeeded == false) { OSL_TRACE("no user pane needed"); DBG_PRINT_EXIT(CLASS_NAME, __func__); return; } if (nil != m_pUserPane) { OSL_TRACE("user pane already exists"); DBG_PRINT_EXIT(CLASS_NAME, __func__); return; } if (m_bIsFilterControlNeeded == true && m_pFilterControl == nil) { createFilterControl(); } NSRect minRect = NSMakeRect(0,0,300,33); m_pUserPane = [[NSView alloc] initWithFrame:minRect]; int currentHeight = kAquaSpaceBoxFrameViewDiffTop + kAquaSpaceBoxFrameViewDiffBottom; int currentWidth = 300; sal_Bool bPopupControlPresent = NO; sal_Bool bButtonControlPresent = NO; int nCheckboxMaxWidth = 0; int nPopupMaxWidth = 0; int nPopupLabelMaxWidth = 0; for (::std::list::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) { OSL_TRACE("currentHeight: %d", currentHeight); NSControl* pControl = *child; //let the control calculate its size [pControl sizeToFit]; NSRect frame = [pControl frame]; OSL_TRACE("frame for control %s is {%f, %f, %f, %f}", [[pControl description] UTF8String], frame.origin.x, frame.origin.y, frame.size.width, frame.size.height); int nControlHeight = frame.size.height; int nControlWidth = frame.size.width; // Note: controls are grouped by kind, first all popup menus, then checkboxes if ([pControl class] == [NSPopUpButton class]) { if (bPopupControlPresent == YES) { //this is not the first popup currentHeight += kAquaSpaceBetweenPopupMenus; } else if (child != m_aActiveControls.begin()){ currentHeight += kAquaSpaceBetweenControls; } bPopupControlPresent = YES; // we have to add the label text width NSString *label = m_aMapListLabels[pControl]; NSTextField *textField = createLabelWithString(label); [textField sizeToFit]; m_aMapListLabelFields[(NSPopUpButton*)pControl] = textField; [m_pUserPane addSubview:textField]; NSRect tfRect = [textField frame]; OSL_TRACE("frame for textfield %s is {%f, %f, %f, %f}", [[textField description] UTF8String], tfRect.origin.x, tfRect.origin.y, tfRect.size.width, tfRect.size.height); int tfWidth = tfRect.size.width; if (nPopupLabelMaxWidth < tfWidth) { nPopupLabelMaxWidth = tfWidth; } frame.origin.x += (kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft) + tfWidth; if (nControlWidth < POPUP_WIDTH_MIN) { nControlWidth = POPUP_WIDTH_MIN; frame.size.width = nControlWidth; [pControl setFrame:frame]; } if (nControlWidth > POPUP_WIDTH_MAX) { nControlWidth = POPUP_WIDTH_MAX; frame.size.width = nControlWidth; [pControl setFrame:frame]; } //set the max size if (nPopupMaxWidth < nControlWidth) { nPopupMaxWidth = nControlWidth; } nControlWidth += tfWidth + kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft; if (nControlHeight < kAquaPopupButtonDefaultHeight) { //maybe the popup has no menu item yet, so set a default height nControlHeight = kAquaPopupButtonDefaultHeight; } nControlHeight -= kAquaSpacePopupMenuFrameBoundsDiffV; } else if ([pControl class] == [NSButton class]) { if (child != m_aActiveControls.begin()){ currentHeight += kAquaSpaceBetweenControls; } if (nCheckboxMaxWidth < nControlWidth) { nCheckboxMaxWidth = nControlWidth; } bButtonControlPresent = YES; nControlWidth -= 2 * kAquaSpaceSwitchButtonFrameBoundsDiff; nControlHeight -= 2 * kAquaSpaceSwitchButtonFrameBoundsDiff; } // if ((nControlWidth + 2 * kAquaSpaceInsideGroupH) > currentWidth) { // currentWidth = nControlWidth + 2 * kAquaSpaceInsideGroupH; // } currentHeight += nControlHeight; [m_pUserPane addSubview:pControl]; } OSL_TRACE("height after adding all controls: %d", currentHeight); if (bPopupControlPresent && bButtonControlPresent) { //after a popup button (array) and before a different kind of control we need some extra space instead of the standard currentHeight -= kAquaSpaceBetweenControls; currentHeight += kAquaSpaceAfterPopupButtonsV; OSL_TRACE("popup extra space added, currentHeight: %d", currentHeight); } int nLongestPopupWidth = nPopupMaxWidth + nPopupLabelMaxWidth + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH; currentWidth = nLongestPopupWidth > nCheckboxMaxWidth ? nLongestPopupWidth : nCheckboxMaxWidth; OSL_TRACE("longest control width: %d", currentWidth); currentWidth += 2* kAquaSpaceInsideGroupH; if (currentWidth < minRect.size.width) currentWidth = minRect.size.width; if (currentHeight < minRect.size.height) currentHeight = minRect.size.height; NSRect upRect = NSMakeRect(0, 0, currentWidth, currentHeight ); OSL_TRACE("setting user pane rect to {%f, %f, %f, %f}",upRect.origin.x, upRect.origin.y, upRect.size.width, upRect.size.height); [m_pUserPane setFrame:upRect]; layoutControls(); DBG_PRINT_EXIT(CLASS_NAME, __func__); } #pragma mark Private / Misc //------------------------------------------------------------------------------------ // Private / Misc //------------------------------------------------------------------------------------ void ControlHelper::createControls() { DBG_PRINT_ENTRY(CLASS_NAME, __func__); CResourceProvider aResProvider; for (int i = 0; i < LIST_LAST; i++) { if (true == m_bListVisibility[i]) { m_bUserPaneNeeded = true; int elementName = getControlElementName([NSPopUpButton class], i); NSString* sLabel = aResProvider.getResString(elementName); m_pListControls[i] = [NSPopUpButton new]; #define MAP_LIST_( elem ) \ case elem: \ setLabel(ExtendedFilePickerElementIds::LISTBOX_##elem, sLabel); \ break switch(i) { MAP_LIST_(VERSION); MAP_LIST_(TEMPLATE); MAP_LIST_(IMAGE_TEMPLATE); } m_aActiveControls.push_back(m_pListControls[i]); } else { m_pListControls[i] = nil; } } for (int i = 0/*#i102102*/; i < TOGGLE_LAST; i++) { if (true == m_bToggleVisibility[i]) { m_bUserPaneNeeded = true; int elementName = getControlElementName([NSButton class], i); NSString* sLabel = aResProvider.getResString(elementName); NSButton *button = [NSButton new]; [button setTitle:sLabel]; [button setButtonType:NSSwitchButton]; [button setState:NSOffState]; if (i == AUTOEXTENSION) { [button setTarget:m_pDelegate]; [button setAction:@selector(autoextensionChanged:)]; } m_pToggles[i] = button; m_aActiveControls.push_back(m_pToggles[i]); } else { m_pToggles[i] = nil; } } //preview is always on with Mac OS X NSControl *pPreviewBox = m_pToggles[PREVIEW]; if (pPreviewBox != nil) { [pPreviewBox setEnabled:NO]; [(NSButton*)pPreviewBox setState:NSOnState]; } 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(const Class aClazz, const int nControlId) const { DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aClazz", [[aClazz description] UTF8String], "controlId", nControlId); int nReturn = -1; if (aClazz == [NSButton class]) { switch (nControlId) { TOGGLE_ELEMENT( AUTOEXTENSION ); TOGGLE_ELEMENT( PASSWORD ); TOGGLE_ELEMENT( FILTEROPTIONS ); TOGGLE_ELEMENT( READONLY ); TOGGLE_ELEMENT( LINK ); TOGGLE_ELEMENT( PREVIEW ); TOGGLE_ELEMENT( SELECTION ); } } else if (aClazz == [NSPopUpButton class]) { switch (nControlId) { LIST_ELEMENT( VERSION ); LIST_ELEMENT( TEMPLATE ); LIST_ELEMENT( IMAGE_TEMPLATE ); } } DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn); return nReturn; } void ControlHelper::HandleSetListValue(const NSControl* pControl, const sal_Int16 nControlAction, const uno::Any& rValue) { DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlAction", nControlAction); if ([pControl class] != [NSPopUpButton class]) { OSL_TRACE("not a popup menu"); DBG_PRINT_EXIT(CLASS_NAME, __func__); return; } NSPopUpButton *pButton = (NSPopUpButton*)pControl; NSMenu *rMenu = [pButton menu]; if (nil == rMenu) { OSL_TRACE("button has no menu"); DBG_PRINT_EXIT(CLASS_NAME, __func__); return; } switch (nControlAction) { case ControlActions::ADD_ITEM: { OSL_TRACE("ADD_ITEMS"); OUString sItem; rValue >>= sItem; NSString* sCFItem = [NSString stringWithOUString:sItem]; OSL_TRACE("Adding menu item: %s", OUStringToOString(sItem, RTL_TEXTENCODING_UTF8).getStr()); [pButton addItemWithTitle:sCFItem]; } 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) { NSString* sCFItem = [NSString stringWithOUString:aStringList[i]]; OSL_TRACE("Adding menu item: %s", OUStringToOString(aStringList[i], RTL_TEXTENCODING_UTF8).getStr()); [pButton addItemWithTitle:sCFItem]; } } break; case ControlActions::DELETE_ITEM: { OSL_TRACE("DELETE_ITEM"); sal_Int32 nPos = -1; rValue >>= nPos; OSL_TRACE("Deleting item at position %d", (nPos)); [rMenu removeItemAtIndex:nPos]; } break; case ControlActions::DELETE_ITEMS: { OSL_TRACE("DELETE_ITEMS"); int nItems = [rMenu numberOfItems]; if (nItems == 0) { OSL_TRACE("no menu items to delete"); DBG_PRINT_EXIT(CLASS_NAME, __func__); return; } for(sal_Int32 i = 0; i < nItems; i++) { [rMenu removeItemAtIndex:i]; } } break; case ControlActions::SET_SELECT_ITEM: { sal_Int32 nPos = -1; rValue >>= nPos; OSL_TRACE("Selecting item at position %d", nPos); [pButton selectItemAtIndex:nPos]; } break; default: OSL_TRACE("undocumented/unimplemented ControlAction for a list"); break; } layoutControls(); DBG_PRINT_EXIT(CLASS_NAME, __func__); } uno::Any ControlHelper::HandleGetListValue(const NSControl* pControl, const sal_Int16 nControlAction) const { DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlAction", nControlAction); uno::Any aAny; if ([pControl class] != [NSPopUpButton class]) { OSL_TRACE("not a popup button"); DBG_PRINT_EXIT(CLASS_NAME, __func__); return aAny; } NSPopUpButton *pButton = (NSPopUpButton*)pControl; NSMenu *rMenu = [pButton menu]; if (nil == rMenu) { OSL_TRACE("button has no menu"); DBG_PRINT_EXIT(CLASS_NAME, __func__); return aAny; } switch (nControlAction) { case ControlActions::GET_ITEMS: { OSL_TRACE("GET_ITEMS"); uno::Sequence< OUString > aItemList; int nItems = [rMenu numberOfItems]; if (nItems > 0) { aItemList.realloc(nItems); } for (int i = 0; i < nItems; i++) { NSString* sCFItem = [pButton itemTitleAtIndex:i]; if (nil != sCFItem) { aItemList[i] = [sCFItem OUString]; OSL_TRACE("Return value[%d]: %s", (i - 1), OUStringToOString(aItemList[i - 1], RTL_TEXTENCODING_UTF8).getStr()); } } aAny <<= aItemList; } break; case ControlActions::GET_SELECTED_ITEM: { OSL_TRACE("GET_SELECTED_ITEM"); NSString* sCFItem = [pButton titleOfSelectedItem]; if (nil != sCFItem) { OUString sString = [sCFItem OUString]; OSL_TRACE("Return value: %s", OUStringToOString(sString, RTL_TEXTENCODING_UTF8).getStr()); aAny <<= sString; } } break; case ControlActions::GET_SELECTED_ITEM_INDEX: { OSL_TRACE("GET_SELECTED_ITEM_INDEX"); sal_Int32 nActive = [pButton indexOfSelectedItem]; OSL_TRACE("Return value: %d", nActive); aAny <<= 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 NSControl* ControlHelper::getControl( const sal_Int16 nControlId ) const { DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId); NSControl* pWidget = nil; #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 ) { MAP_TOGGLE( AUTOEXTENSION ); 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__); ::vos::OGuard aGuard( Application::GetSolarMutex() ); if (nil == m_pUserPane) { OSL_TRACE("no user pane to layout"); DBG_PRINT_EXIT(CLASS_NAME, __func__); return; } if (m_bIsUserPaneLaidOut == true) { OSL_TRACE("user pane already laid out"); DBG_PRINT_EXIT(CLASS_NAME, __func__); return; } NSRect userPaneRect = [m_pUserPane frame]; OSL_TRACE("userPane frame: {%f, %f, %f, %f}",userPaneRect.origin.x, userPaneRect.origin.y, userPaneRect.size.width, userPaneRect.size.height); int nUsableWidth = userPaneRect.size.width; //NOTE: NSView's coordinate system starts in the lower left hand corner but we start adding controls from the top, // so we subtract from the vertical position as we make our way down the pane. int currenttop = userPaneRect.size.height; int nCheckboxMaxWidth = 0; int nPopupMaxWidth = 0; int nPopupLabelMaxWidth = 0; //first loop to determine max sizes for (::std::list::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) { NSControl* pControl = *child; NSRect controlRect = [pControl frame]; int nControlWidth = controlRect.size.width; Class aSubType = [pControl class]; if (aSubType == [NSPopUpButton class]) { if (nPopupMaxWidth < nControlWidth) { nPopupMaxWidth = nControlWidth; } NSTextField *label = m_aMapListLabelFields[(NSPopUpButton*)pControl]; NSRect labelFrame = [label frame]; int nLabelWidth = labelFrame.size.width; if (nPopupLabelMaxWidth < nLabelWidth) { nPopupLabelMaxWidth = nLabelWidth; } } else { if (nCheckboxMaxWidth < nControlWidth) { nCheckboxMaxWidth = nControlWidth; } } } int nLongestPopupWidth = nPopupMaxWidth + nPopupLabelMaxWidth + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH; OSL_TRACE("longest popup width: %d", nLongestPopupWidth); NSControl* previousControl = nil; int nDistBetweenControls = 0; for (::std::list::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) { NSControl* pControl = *child; //get the control's bounds NSRect controlRect = [pControl frame]; int nControlHeight = controlRect.size.height; int nControlWidth = controlRect.size.width; //subtract the height from the current vertical position, because the control's bounds origin rect will be its lower left hand corner currenttop -= nControlHeight; Class aSubType = [pControl class]; //add space between the previous control and this control according to Apple's HIG nDistBetweenControls = getVerticalDistance(previousControl, pControl); OSL_TRACE("vertical distance: %d", nDistBetweenControls); currenttop -= nDistBetweenControls; previousControl = pControl; if (aSubType == [NSPopUpButton class]) { //move vertically up some pixels to space the controls between their real (visual) bounds currenttop += kAquaSpacePopupMenuFrameBoundsDiffTop;//from top //get the corresponding popup label NSTextField *label = m_aMapListLabelFields[(NSPopUpButton*)pControl]; NSRect labelFrame = [label frame]; int totalWidth = nPopupMaxWidth + labelFrame.size.width + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH; OSL_TRACE("totalWidth: %d", totalWidth); //let's center popups int left = (nUsableWidth + nLongestPopupWidth) / 2 - totalWidth; OSL_TRACE("left: %d", left); labelFrame.origin.x = left; labelFrame.origin.y = currenttop + kAquaSpaceLabelPopupDiffV; OSL_TRACE("setting label at: {%f, %f, %f, %f}",labelFrame.origin.x, labelFrame.origin.y, labelFrame.size.width, labelFrame.size.height); [label setFrame:labelFrame]; controlRect.origin.x = left + labelFrame.size.width + kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft; controlRect.origin.y = currenttop; controlRect.size.width = nPopupMaxWidth; OSL_TRACE("setting popup at: {%f, %f, %f, %f}",controlRect.origin.x, controlRect.origin.y, controlRect.size.width, controlRect.size.height); [pControl setFrame:controlRect]; //add some space to place the vertical position right below the popup's visual bounds currenttop += kAquaSpacePopupMenuFrameBoundsDiffBottom; } else { currenttop += kAquaSpaceSwitchButtonFrameBoundsDiff;//from top nControlWidth = nCheckboxMaxWidth; int left = (nUsableWidth - nCheckboxMaxWidth) / 2; controlRect.origin.x = left; controlRect.origin.y = currenttop; controlRect.size.width = nPopupMaxWidth; [pControl setFrame:controlRect]; OSL_TRACE("setting checkbox at: {%f, %f, %f, %f}",controlRect.origin.x, controlRect.origin.y, controlRect.size.width, controlRect.size.height); currenttop += kAquaSpaceSwitchButtonFrameBoundsDiff; } } m_bIsUserPaneLaidOut = true; DBG_PRINT_EXIT(CLASS_NAME, __func__); } void ControlHelper::createFilterControl() { DBG_PRINT_ENTRY(CLASS_NAME, __func__); CResourceProvider aResProvider; NSString* sLabel = aResProvider.getResString(CommonFilePickerElementIds::LISTBOX_FILTER_LABEL); m_pFilterControl = [NSPopUpButton new]; [m_pFilterControl setAction:@selector(filterSelectedAtIndex:)]; [m_pFilterControl setTarget:m_pDelegate]; NSMenu *menu = [m_pFilterControl menu]; for (NSStringList::iterator iter = m_pFilterHelper->getFilterNames()->begin(); iter != m_pFilterHelper->getFilterNames()->end(); iter++) { NSString *filterName = *iter; OSL_TRACE("adding filter name: %s", [filterName UTF8String]); if ([filterName isEqualToString:@"-"]) { [menu addItem:[NSMenuItem separatorItem]]; } else { [m_pFilterControl addItemWithTitle:filterName]; } } // always add the filter as first item m_aActiveControls.push_front(m_pFilterControl); m_aMapListLabels[m_pFilterControl] = [sLabel retain]; DBG_PRINT_EXIT(CLASS_NAME, __func__); } NSTextField* ControlHelper::createLabelWithString(NSString* labelString) { DBG_PRINT_ENTRY(CLASS_NAME, __func__, "label", labelString); NSTextField *textField = [NSTextField new]; [textField setEditable:NO]; [textField setSelectable:NO]; [textField setDrawsBackground:NO]; [textField setBordered:NO]; [[textField cell] setTitle:labelString]; DBG_PRINT_EXIT(CLASS_NAME, __func__); return textField; } int ControlHelper::getVerticalDistance(const NSControl* first, const NSControl* second) { if (first == nil) { return kAquaSpaceBoxFrameViewDiffTop; } else if (second == nil) { return kAquaSpaceBoxFrameViewDiffBottom; } else { Class firstClass = [first class]; Class secondClass = [second class]; if (firstClass == [NSPopUpButton class]) { if (secondClass == [NSPopUpButton class]) { return kAquaSpaceBetweenPopupMenus; } else { return kAquaSpaceAfterPopupButtonsV; } } return kAquaSpaceBetweenControls; } } void ControlHelper::updateFilterUI() { DBG_PRINT_ENTRY(CLASS_NAME, __func__); if (m_bIsFilterControlNeeded == false || m_pFilterHelper == NULL) { OSL_TRACE("no filter control needed or no filter helper present"); DBG_PRINT_EXIT(CLASS_NAME, __func__); return; } int index = m_pFilterHelper->getCurrentFilterIndex(); if (m_pFilterControl == nil) { createFilterControl(); } [m_pFilterControl selectItemAtIndex:index]; DBG_PRINT_EXIT(CLASS_NAME, __func__); }