| /************************************************************** |
| * |
| * 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 <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> |
| #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp> |
| #include <com/sun/star/ui/dialogs/ControlActions.hpp> |
| #include <com/sun/star/ui/dialogs/TemplateDescription.hpp> |
| #include <vos/mutex.hxx> |
| #include <vcl/svapp.hxx> |
| #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<NSControl *>::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<NSControl*>::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<NSControl*>::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<NSControl*>::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__); |
| } |