merge the formfield patch from ooo-build
[ooovba.git] / fpicker / source / aqua / ControlHelper.cxx
blobd28960863162d26251087469136b701cdddffcda
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ControlHelper.cxx,v $
10 * $Revision: 1.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
32 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
33 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
34 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
35 #include <vos/mutex.hxx>
36 #include <vcl/svapp.hxx>
37 #include "CFStringUtilities.hxx"
38 #include "resourceprovider.hxx"
39 #include "NSString_OOoAdditions.hxx"
41 #include "ControlHelper.hxx"
43 #pragma mark DEFINES
44 #define CLASS_NAME "ControlHelper"
45 #define POPUP_WIDTH_MIN 200
46 #define POPUP_WIDTH_MAX 350
48 using namespace ::com::sun::star::ui::dialogs;
49 using namespace ::com::sun::star::ui::dialogs::TemplateDescription;
50 using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds;
51 using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds;
52 using namespace ::rtl;
54 #pragma mark Constructor / Destructor
55 //------------------------------------------------------------------------------------
56 // Constructor / Destructor
57 //------------------------------------------------------------------------------------
58 ControlHelper::ControlHelper()
59 : m_pUserPane(NULL)
60 , m_pFilterControl(nil)
61 , m_bUserPaneNeeded( false )
62 , m_bIsUserPaneLaidOut(false)
63 , m_bIsFilterControlNeeded(false)
64 , m_pFilterHelper(NULL)
66 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
68 int i;
70 for( i = 0; i < TOGGLE_LAST; i++ ) {
71 m_bToggleVisibility[i] = false;
74 for( i = 0; i < LIST_LAST; i++ ) {
75 m_bListVisibility[i] = false;
78 DBG_PRINT_EXIT(CLASS_NAME, __func__);
81 ControlHelper::~ControlHelper()
83 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
85 NSAutoreleasePool *pool = [NSAutoreleasePool new];
87 if (NULL != m_pUserPane) {
88 [m_pUserPane release];
91 for(std::list<NSControl *>::iterator control = m_aActiveControls.begin(); control != m_aActiveControls.end(); control++) {
92 NSControl* pControl = (*control);
93 NSString* sLabelName = m_aMapListLabels[pControl];
94 if (sLabelName != nil) {
95 [sLabelName release];
97 if ([pControl class] == [NSPopUpButton class]) {
98 NSTextField* pField = m_aMapListLabelFields[(NSPopUpButton*)pControl];
99 if (pField != nil) {
100 [pField release];
103 [pControl release];
106 if (m_pFilterControl != NULL) {
107 [m_pFilterControl setTarget:nil];
110 [pool release];
112 DBG_PRINT_EXIT(CLASS_NAME, __func__);
115 #pragma mark XInitialization delegate
116 //------------------------------------------------
117 // XInitialization delegate
118 //------------------------------------------------
119 void ControlHelper::initialize( sal_Int16 nTemplateId )
121 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "templateId", nTemplateId);
123 switch( nTemplateId )
125 case FILESAVE_AUTOEXTENSION_PASSWORD:
126 m_bToggleVisibility[AUTOEXTENSION] = true;
127 m_bToggleVisibility[PASSWORD] = true;
128 break;
129 case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
130 m_bToggleVisibility[AUTOEXTENSION] = true;
131 m_bToggleVisibility[PASSWORD] = true;
132 m_bToggleVisibility[FILTEROPTIONS] = true;
133 break;
134 case FILESAVE_AUTOEXTENSION_SELECTION:
135 m_bToggleVisibility[AUTOEXTENSION] = true;
136 m_bToggleVisibility[SELECTION] = true;
137 break;
138 case FILESAVE_AUTOEXTENSION_TEMPLATE:
139 m_bToggleVisibility[AUTOEXTENSION] = true;
140 m_bListVisibility[TEMPLATE] = true;
141 break;
142 case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
143 m_bToggleVisibility[LINK] = true;
144 m_bToggleVisibility[PREVIEW] = true;
145 m_bListVisibility[IMAGE_TEMPLATE] = true;
146 break;
147 case FILEOPEN_READONLY_VERSION:
148 m_bToggleVisibility[READONLY] = true;
149 m_bListVisibility[VERSION] = true;
150 break;
151 case FILEOPEN_LINK_PREVIEW:
152 m_bToggleVisibility[LINK] = true;
153 m_bToggleVisibility[PREVIEW] = true;
154 break;
155 case FILESAVE_AUTOEXTENSION:
156 m_bToggleVisibility[AUTOEXTENSION] = true;
157 break;
160 createControls();
162 DBG_PRINT_EXIT(CLASS_NAME, __func__);
165 #pragma mark XFilePickerControlAccess delegates
166 //------------------------------------------------------------------------------------
167 // XFilePickerControlAccess functions
168 //------------------------------------------------------------------------------------
170 void ControlHelper::enableControl( const sal_Int16 nControlId, const sal_Bool bEnable ) const
172 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "enable", bEnable);
174 ::vos::OGuard aGuard( Application::GetSolarMutex() );
176 if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_PREVIEW) {
177 OSL_TRACE(" preview checkbox cannot be changed");
178 DBG_PRINT_EXIT(CLASS_NAME, __func__);
179 return;
182 NSControl* pControl = getControl(nControlId);
184 if( pControl != nil ) {
185 if( bEnable ) {
186 OSL_TRACE( "enable" );
187 } else {
188 OSL_TRACE( "disable" );
190 [pControl setEnabled:bEnable];
191 } else {
192 OSL_TRACE("enable unknown control %d", nControlId );
195 DBG_PRINT_EXIT(CLASS_NAME, __func__);
198 OUString ControlHelper::getLabel( sal_Int16 nControlId )
200 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId);
202 ::vos::OGuard aGuard( Application::GetSolarMutex() );
204 NSControl* pControl = getControl( nControlId );
206 if( pControl == nil ) {
207 OSL_TRACE("Get label for unknown control %d", nControlId);
208 return OUString();
211 rtl::OUString retVal;
212 if ([pControl class] == [NSPopUpButton class]) {
213 NSString *temp = m_aMapListLabels[pControl];
214 if (temp != nil)
215 retVal = [temp OUString];
217 else {
218 NSString* sLabel = [[pControl cell] title];
219 retVal = [sLabel OUString];
222 DBG_PRINT_EXIT(CLASS_NAME, __func__, retVal);
224 return retVal;
227 void ControlHelper::setLabel( sal_Int16 nControlId, const NSString* aLabel )
229 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "label", aLabel);
231 ::vos::OGuard aGuard( Application::GetSolarMutex() );
233 NSAutoreleasePool *pool = [NSAutoreleasePool new];
235 NSControl* pControl = getControl(nControlId);
237 if (nil != pControl) {
238 if ([pControl class] == [NSPopUpButton class]) {
239 NSString *sOldName = m_aMapListLabels[pControl];
240 if (sOldName != NULL && sOldName != aLabel) {
241 [sOldName release];
244 m_aMapListLabels[pControl] = [aLabel retain];
245 } else if ([pControl class] == [NSButton class]) {
246 [[pControl cell] setTitle:aLabel];
248 } else {
249 OSL_TRACE("Control not found to set label for");
252 layoutControls();
254 [pool release];
256 DBG_PRINT_EXIT(CLASS_NAME, __func__);
259 void ControlHelper::setValue( sal_Int16 nControlId, sal_Int16 nControlAction, const uno::Any& rValue )
261 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "controlAction", nControlAction);
263 ::vos::OGuard aGuard( Application::GetSolarMutex() );
265 if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_PREVIEW) {
266 OSL_TRACE(" value for preview is unchangeable");
268 else {
269 NSControl* pControl = getControl( nControlId );
271 if( pControl == nil ) {
272 OSL_TRACE("enable unknown control %d", nControlId);
273 } else {
274 if( [pControl class] == [NSPopUpButton class] ) {
275 HandleSetListValue(pControl, nControlAction, rValue);
276 } else if( [pControl class] == [NSButton class] ) {
277 sal_Bool bChecked = false;
278 rValue >>= bChecked;
279 OSL_TRACE(" value is a bool: %d", bChecked);
280 [(NSButton*)pControl setState:(bChecked ? NSOnState : NSOffState)];
281 } else
283 OSL_TRACE("Can't set value on button / list %d %d",
284 nControlId, nControlAction);
289 DBG_PRINT_EXIT(CLASS_NAME, __func__);
292 uno::Any ControlHelper::getValue( sal_Int16 nControlId, sal_Int16 nControlAction ) const
294 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "controlAction", nControlAction);
296 ::vos::OGuard aGuard( Application::GetSolarMutex() );
297 uno::Any aRetval;
299 NSControl* pControl = getControl( nControlId );
301 if( pControl == nil ) {
302 OSL_TRACE("get value for unknown control %d", nControlId);
303 aRetval <<= sal_True;
304 } else {
305 if( [pControl class] == [NSPopUpButton class] ) {
306 aRetval = HandleGetListValue(pControl, nControlAction);
307 } else if( [pControl class] == [NSButton class] ) {
308 //NSLog(@"control: %@", [[pControl cell] title]);
309 sal_Bool bValue = [(NSButton*)pControl state] == NSOnState ? sal_True : sal_False;
310 aRetval <<= bValue;
311 OSL_TRACE("value is a bool (checkbox): %d", bValue);
315 DBG_PRINT_EXIT(CLASS_NAME, __func__);
317 return aRetval;
320 void ControlHelper::createUserPane()
322 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
324 if (m_bUserPaneNeeded == false) {
325 OSL_TRACE("no user pane needed");
326 DBG_PRINT_EXIT(CLASS_NAME, __func__);
327 return;
330 if (nil != m_pUserPane) {
331 OSL_TRACE("user pane already exists");
332 DBG_PRINT_EXIT(CLASS_NAME, __func__);
333 return;
336 if (m_bIsFilterControlNeeded == true && m_pFilterControl == nil) {
337 createFilterControl();
340 NSRect minRect = NSMakeRect(0,0,300,33);
341 m_pUserPane = [[NSView alloc] initWithFrame:minRect];
343 int currentHeight = kAquaSpaceBoxFrameViewDiffTop + kAquaSpaceBoxFrameViewDiffBottom;
344 int currentWidth = 300;
346 BOOL bPopupControlPresent = NO;
347 BOOL bButtonControlPresent = NO;
349 int nCheckboxMaxWidth = 0;
350 int nPopupMaxWidth = 0;
351 int nPopupLabelMaxWidth = 0;
353 for (::std::list<NSControl*>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) {
354 OSL_TRACE("currentHeight: %d", currentHeight);
356 NSControl* pControl = *child;
358 //let the control calculate its size
359 [pControl sizeToFit];
361 NSRect frame = [pControl frame];
362 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);
364 int nControlHeight = frame.size.height;
365 int nControlWidth = frame.size.width;
367 // Note: controls are grouped by kind, first all popup menus, then checkboxes
368 if ([pControl class] == [NSPopUpButton class]) {
369 if (bPopupControlPresent == YES) {
370 //this is not the first popup
371 currentHeight += kAquaSpaceBetweenPopupMenus;
373 else if (child != m_aActiveControls.begin()){
374 currentHeight += kAquaSpaceBetweenControls;
377 bPopupControlPresent = YES;
379 // we have to add the label text width
380 NSString *label = m_aMapListLabels[pControl];
382 NSTextField *textField = createLabelWithString(label);
383 [textField sizeToFit];
384 m_aMapListLabelFields[(NSPopUpButton*)pControl] = textField;
385 [m_pUserPane addSubview:textField];
387 NSRect tfRect = [textField frame];
388 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);
390 int tfWidth = tfRect.size.width;
392 if (nPopupLabelMaxWidth < tfWidth) {
393 nPopupLabelMaxWidth = tfWidth;
396 frame.origin.x += (kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft) + tfWidth;
398 if (nControlWidth < POPUP_WIDTH_MIN) {
399 nControlWidth = POPUP_WIDTH_MIN;
400 frame.size.width = nControlWidth;
401 [pControl setFrame:frame];
404 if (nControlWidth > POPUP_WIDTH_MAX) {
405 nControlWidth = POPUP_WIDTH_MAX;
406 frame.size.width = nControlWidth;
407 [pControl setFrame:frame];
410 //set the max size
411 if (nPopupMaxWidth < nControlWidth) {
412 nPopupMaxWidth = nControlWidth;
415 nControlWidth += tfWidth + kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft;
416 if (nControlHeight < kAquaPopupButtonDefaultHeight) {
417 //maybe the popup has no menu item yet, so set a default height
418 nControlHeight = kAquaPopupButtonDefaultHeight;
421 nControlHeight -= kAquaSpacePopupMenuFrameBoundsDiffV;
423 else if ([pControl class] == [NSButton class]) {
424 if (child != m_aActiveControls.begin()){
425 currentHeight += kAquaSpaceBetweenControls;
428 if (nCheckboxMaxWidth < nControlWidth) {
429 nCheckboxMaxWidth = nControlWidth;
432 bButtonControlPresent = YES;
433 nControlWidth -= 2 * kAquaSpaceSwitchButtonFrameBoundsDiff;
434 nControlHeight -= 2 * kAquaSpaceSwitchButtonFrameBoundsDiff;
437 // if ((nControlWidth + 2 * kAquaSpaceInsideGroupH) > currentWidth) {
438 // currentWidth = nControlWidth + 2 * kAquaSpaceInsideGroupH;
439 // }
441 currentHeight += nControlHeight;
443 [m_pUserPane addSubview:pControl];
446 OSL_TRACE("height after adding all controls: %d", currentHeight);
448 if (bPopupControlPresent && bButtonControlPresent)
450 //after a popup button (array) and before a different kind of control we need some extra space instead of the standard
451 currentHeight -= kAquaSpaceBetweenControls;
452 currentHeight += kAquaSpaceAfterPopupButtonsV;
453 OSL_TRACE("popup extra space added, currentHeight: %d", currentHeight);
456 int nLongestPopupWidth = nPopupMaxWidth + nPopupLabelMaxWidth + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
458 currentWidth = nLongestPopupWidth > nCheckboxMaxWidth ? nLongestPopupWidth : nCheckboxMaxWidth;
459 OSL_TRACE("longest control width: %d", currentWidth);
461 currentWidth += 2* kAquaSpaceInsideGroupH;
463 if (currentWidth < minRect.size.width)
464 currentWidth = minRect.size.width;
466 if (currentHeight < minRect.size.height)
467 currentHeight = minRect.size.height;
469 NSRect upRect = NSMakeRect(0, 0, currentWidth, currentHeight );
470 OSL_TRACE("setting user pane rect to {%f, %f, %f, %f}",upRect.origin.x, upRect.origin.y, upRect.size.width, upRect.size.height);
472 [m_pUserPane setFrame:upRect];
474 layoutControls();
476 DBG_PRINT_EXIT(CLASS_NAME, __func__);
479 #pragma mark Private / Misc
480 //------------------------------------------------------------------------------------
481 // Private / Misc
482 //------------------------------------------------------------------------------------
483 void ControlHelper::createControls()
485 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
487 CResourceProvider aResProvider;
488 for (int i = 0; i < LIST_LAST; i++) {
489 if (true == m_bListVisibility[i]) {
490 m_bUserPaneNeeded = true;
492 int elementName = getControlElementName([NSPopUpButton class], i);
493 NSString* sLabel = aResProvider.getResString(elementName);
495 m_pListControls[i] = [NSPopUpButton new];
497 #define MAP_LIST_( elem ) \
498 case elem: \
499 setLabel(ExtendedFilePickerElementIds::LISTBOX_##elem, sLabel); \
500 break
502 switch(i) {
503 MAP_LIST_(VERSION);
504 MAP_LIST_(TEMPLATE);
505 MAP_LIST_(IMAGE_TEMPLATE);
508 m_aActiveControls.push_back(m_pListControls[i]);
509 } else {
510 m_pListControls[i] = nil;
514 for (int i = 0/*#i102102*/; i < TOGGLE_LAST; i++) {
515 if (true == m_bToggleVisibility[i]) {
516 m_bUserPaneNeeded = true;
518 int elementName = getControlElementName([NSButton class], i);
519 NSString* sLabel = aResProvider.getResString(elementName);
521 NSButton *button = [NSButton new];
522 [button setTitle:sLabel];
524 [button setButtonType:NSSwitchButton];
526 [button setState:NSOffState];
528 if (i == AUTOEXTENSION) {
529 [button setTarget:m_pDelegate];
530 [button setAction:@selector(autoextensionChanged:)];
533 m_pToggles[i] = button;
535 m_aActiveControls.push_back(m_pToggles[i]);
536 } else {
537 m_pToggles[i] = nil;
541 //preview is always on with Mac OS X
542 NSControl *pPreviewBox = m_pToggles[PREVIEW];
543 if (pPreviewBox != nil) {
544 [pPreviewBox setEnabled:NO];
545 [(NSButton*)pPreviewBox setState:NSOnState];
548 DBG_PRINT_EXIT(CLASS_NAME, __func__);
551 #define TOGGLE_ELEMENT( elem ) \
552 case elem: \
553 nReturn = CHECKBOX_##elem; \
554 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn); \
555 return nReturn
556 #define LIST_ELEMENT( elem ) \
557 case elem: \
558 nReturn = LISTBOX_##elem##_LABEL; \
559 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn); \
560 return nReturn
562 int ControlHelper::getControlElementName(const Class aClazz, const int nControlId) const
564 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aClazz", [[aClazz description] UTF8String], "controlId", nControlId);
566 int nReturn = -1;
567 if (aClazz == [NSButton class])
569 switch (nControlId) {
570 TOGGLE_ELEMENT( AUTOEXTENSION );
571 TOGGLE_ELEMENT( PASSWORD );
572 TOGGLE_ELEMENT( FILTEROPTIONS );
573 TOGGLE_ELEMENT( READONLY );
574 TOGGLE_ELEMENT( LINK );
575 TOGGLE_ELEMENT( PREVIEW );
576 TOGGLE_ELEMENT( SELECTION );
579 else if (aClazz == [NSPopUpButton class])
581 switch (nControlId) {
582 LIST_ELEMENT( VERSION );
583 LIST_ELEMENT( TEMPLATE );
584 LIST_ELEMENT( IMAGE_TEMPLATE );
588 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn);
590 return nReturn;
593 void ControlHelper::HandleSetListValue(const NSControl* pControl, const sal_Int16 nControlAction, const uno::Any& rValue)
595 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlAction", nControlAction);
597 if ([pControl class] != [NSPopUpButton class]) {
598 OSL_TRACE("not a popup menu");
599 DBG_PRINT_EXIT(CLASS_NAME, __func__);
600 return;
603 NSPopUpButton *pButton = (NSPopUpButton*)pControl;
604 NSMenu *rMenu = [pButton menu];
605 if (nil == rMenu) {
606 OSL_TRACE("button has no menu");
607 DBG_PRINT_EXIT(CLASS_NAME, __func__);
608 return;
611 switch (nControlAction)
613 case ControlActions::ADD_ITEM:
615 OSL_TRACE("ADD_ITEMS");
616 OUString sItem;
617 rValue >>= sItem;
619 NSString* sCFItem = [NSString stringWithOUString:sItem];
620 OSL_TRACE("Adding menu item: %s", OUStringToOString(sItem, RTL_TEXTENCODING_UTF8).getStr());
621 [pButton addItemWithTitle:sCFItem];
623 break;
624 case ControlActions::ADD_ITEMS:
626 OSL_TRACE("ADD_ITEMS");
627 uno::Sequence< OUString > aStringList;
628 rValue >>= aStringList;
629 sal_Int32 nItemCount = aStringList.getLength();
630 for (sal_Int32 i = 0; i < nItemCount; ++i)
632 NSString* sCFItem = [NSString stringWithOUString:aStringList[i]];
633 OSL_TRACE("Adding menu item: %s", OUStringToOString(aStringList[i], RTL_TEXTENCODING_UTF8).getStr());
634 [pButton addItemWithTitle:sCFItem];
637 break;
638 case ControlActions::DELETE_ITEM:
640 OSL_TRACE("DELETE_ITEM");
641 sal_Int32 nPos = -1;
642 rValue >>= nPos;
643 OSL_TRACE("Deleting item at position %d", (nPos));
644 [rMenu removeItemAtIndex:nPos];
646 break;
647 case ControlActions::DELETE_ITEMS:
649 OSL_TRACE("DELETE_ITEMS");
650 int nItems = [rMenu numberOfItems];
651 if (nItems == 0) {
652 OSL_TRACE("no menu items to delete");
653 DBG_PRINT_EXIT(CLASS_NAME, __func__);
654 return;
656 for(sal_Int32 i = 0; i < nItems; i++) {
657 [rMenu removeItemAtIndex:i];
660 break;
661 case ControlActions::SET_SELECT_ITEM:
663 sal_Int32 nPos = -1;
664 rValue >>= nPos;
665 OSL_TRACE("Selecting item at position %d", nPos);
666 [pButton selectItemAtIndex:nPos];
668 break;
669 default:
670 OSL_TRACE("undocumented/unimplemented ControlAction for a list");
671 break;
674 layoutControls();
676 DBG_PRINT_EXIT(CLASS_NAME, __func__);
680 uno::Any ControlHelper::HandleGetListValue(const NSControl* pControl, const sal_Int16 nControlAction) const
682 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlAction", nControlAction);
684 uno::Any aAny;
686 if ([pControl class] != [NSPopUpButton class]) {
687 OSL_TRACE("not a popup button");
688 DBG_PRINT_EXIT(CLASS_NAME, __func__);
689 return aAny;
692 NSPopUpButton *pButton = (NSPopUpButton*)pControl;
693 NSMenu *rMenu = [pButton menu];
694 if (nil == rMenu) {
695 OSL_TRACE("button has no menu");
696 DBG_PRINT_EXIT(CLASS_NAME, __func__);
697 return aAny;
700 switch (nControlAction)
702 case ControlActions::GET_ITEMS:
704 OSL_TRACE("GET_ITEMS");
705 uno::Sequence< OUString > aItemList;
707 int nItems = [rMenu numberOfItems];
708 if (nItems > 0) {
709 aItemList.realloc(nItems);
711 for (int i = 0; i < nItems; i++) {
712 NSString* sCFItem = [pButton itemTitleAtIndex:i];
713 if (nil != sCFItem) {
714 aItemList[i] = [sCFItem OUString];
715 OSL_TRACE("Return value[%d]: %s", (i - 1), OUStringToOString(aItemList[i - 1], RTL_TEXTENCODING_UTF8).getStr());
719 aAny <<= aItemList;
721 break;
722 case ControlActions::GET_SELECTED_ITEM:
724 OSL_TRACE("GET_SELECTED_ITEM");
725 NSString* sCFItem = [pButton titleOfSelectedItem];
726 if (nil != sCFItem) {
727 OUString sString = [sCFItem OUString];
728 OSL_TRACE("Return value: %s", OUStringToOString(sString, RTL_TEXTENCODING_UTF8).getStr());
729 aAny <<= sString;
732 break;
733 case ControlActions::GET_SELECTED_ITEM_INDEX:
735 OSL_TRACE("GET_SELECTED_ITEM_INDEX");
736 sal_Int32 nActive = [pButton indexOfSelectedItem];
737 OSL_TRACE("Return value: %d", nActive);
738 aAny <<= nActive;
740 break;
741 default:
742 OSL_TRACE("undocumented/unimplemented ControlAction for a list");
743 break;
746 DBG_PRINT_EXIT(CLASS_NAME, __func__);
748 return aAny;
752 // cf. offapi/com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.idl
753 NSControl* ControlHelper::getControl( const sal_Int16 nControlId ) const
755 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId);
757 NSControl* pWidget = nil;
759 #define MAP_TOGGLE( elem ) \
760 case ExtendedFilePickerElementIds::CHECKBOX_##elem: \
761 pWidget = m_pToggles[elem]; \
762 break
764 #define MAP_BUTTON( elem ) \
765 case ExtendedFilePickerElementIds::PUSHBUTTON_##elem: \
766 pWidget = m_pButtons[elem]; \
767 break
769 #define MAP_LIST( elem ) \
770 case ExtendedFilePickerElementIds::LISTBOX_##elem: \
771 pWidget = m_pListControls[elem]; \
772 break
774 #define MAP_LIST_LABEL( elem ) \
775 case ExtendedFilePickerElementIds::LISTBOX_##elem##_LABEL: \
776 pWidget = m_pListControls[elem]; \
777 break
779 switch( nControlId )
781 MAP_TOGGLE( AUTOEXTENSION );
782 MAP_TOGGLE( PASSWORD );
783 MAP_TOGGLE( FILTEROPTIONS );
784 MAP_TOGGLE( READONLY );
785 MAP_TOGGLE( LINK );
786 MAP_TOGGLE( PREVIEW );
787 MAP_TOGGLE( SELECTION );
788 //MAP_BUTTON( PLAY );
789 MAP_LIST( VERSION );
790 MAP_LIST( TEMPLATE );
791 MAP_LIST( IMAGE_TEMPLATE );
792 MAP_LIST_LABEL( VERSION );
793 MAP_LIST_LABEL( TEMPLATE );
794 MAP_LIST_LABEL( IMAGE_TEMPLATE );
795 default:
796 OSL_TRACE("Handle unknown control %d", nControlId);
797 break;
799 #undef MAP
801 DBG_PRINT_EXIT(CLASS_NAME, __func__);
803 return pWidget;
806 void ControlHelper::layoutControls()
808 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
810 ::vos::OGuard aGuard( Application::GetSolarMutex() );
812 if (nil == m_pUserPane) {
813 OSL_TRACE("no user pane to layout");
814 DBG_PRINT_EXIT(CLASS_NAME, __func__);
815 return;
818 if (m_bIsUserPaneLaidOut == true) {
819 OSL_TRACE("user pane already laid out");
820 DBG_PRINT_EXIT(CLASS_NAME, __func__);
821 return;
824 NSRect userPaneRect = [m_pUserPane frame];
825 OSL_TRACE("userPane frame: {%f, %f, %f, %f}",userPaneRect.origin.x, userPaneRect.origin.y, userPaneRect.size.width, userPaneRect.size.height);
827 int nUsableWidth = userPaneRect.size.width;
829 //NOTE: NSView's coordinate system starts in the lower left hand corner but we start adding controls from the top,
830 // so we subtract from the vertical position as we make our way down the pane.
831 int currenttop = userPaneRect.size.height;
832 int nCheckboxMaxWidth = 0;
833 int nPopupMaxWidth = 0;
834 int nPopupLabelMaxWidth = 0;
836 //first loop to determine max sizes
837 for (::std::list<NSControl*>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) {
838 NSControl* pControl = *child;
840 NSRect controlRect = [pControl frame];
841 int nControlWidth = controlRect.size.width;
843 Class aSubType = [pControl class];
844 if (aSubType == [NSPopUpButton class]) {
845 if (nPopupMaxWidth < nControlWidth) {
846 nPopupMaxWidth = nControlWidth;
848 NSTextField *label = m_aMapListLabelFields[(NSPopUpButton*)pControl];
849 NSRect labelFrame = [label frame];
850 int nLabelWidth = labelFrame.size.width;
851 if (nPopupLabelMaxWidth < nLabelWidth) {
852 nPopupLabelMaxWidth = nLabelWidth;
854 } else {
855 if (nCheckboxMaxWidth < nControlWidth) {
856 nCheckboxMaxWidth = nControlWidth;
861 int nLongestPopupWidth = nPopupMaxWidth + nPopupLabelMaxWidth + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
862 OSL_TRACE("longest popup width: %d", nLongestPopupWidth);
864 NSControl* previousControl = nil;
866 int nDistBetweenControls = 0;
868 for (::std::list<NSControl*>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) {
869 NSControl* pControl = *child;
871 //get the control's bounds
872 NSRect controlRect = [pControl frame];
873 int nControlHeight = controlRect.size.height;
874 int nControlWidth = controlRect.size.width;
876 //subtract the height from the current vertical position, because the control's bounds origin rect will be its lower left hand corner
877 currenttop -= nControlHeight;
879 Class aSubType = [pControl class];
881 //add space between the previous control and this control according to Apple's HIG
882 nDistBetweenControls = getVerticalDistance(previousControl, pControl);
883 OSL_TRACE("vertical distance: %d", nDistBetweenControls);
884 currenttop -= nDistBetweenControls;
886 previousControl = pControl;
888 if (aSubType == [NSPopUpButton class]) {
889 //move vertically up some pixels to space the controls between their real (visual) bounds
890 currenttop += kAquaSpacePopupMenuFrameBoundsDiffTop;//from top
892 //get the corresponding popup label
893 NSTextField *label = m_aMapListLabelFields[(NSPopUpButton*)pControl];
894 NSRect labelFrame = [label frame];
895 int totalWidth = nPopupMaxWidth + labelFrame.size.width + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
896 OSL_TRACE("totalWidth: %d", totalWidth);
897 //let's center popups
898 int left = (nUsableWidth + nLongestPopupWidth) / 2 - totalWidth;
899 OSL_TRACE("left: %d", left);
900 labelFrame.origin.x = left;
901 labelFrame.origin.y = currenttop + kAquaSpaceLabelPopupDiffV;
902 OSL_TRACE("setting label at: {%f, %f, %f, %f}",labelFrame.origin.x, labelFrame.origin.y, labelFrame.size.width, labelFrame.size.height);
903 [label setFrame:labelFrame];
905 controlRect.origin.x = left + labelFrame.size.width + kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft;
906 controlRect.origin.y = currenttop;
907 controlRect.size.width = nPopupMaxWidth;
908 OSL_TRACE("setting popup at: {%f, %f, %f, %f}",controlRect.origin.x, controlRect.origin.y, controlRect.size.width, controlRect.size.height);
909 [pControl setFrame:controlRect];
911 //add some space to place the vertical position right below the popup's visual bounds
912 currenttop += kAquaSpacePopupMenuFrameBoundsDiffBottom;
913 } else {
914 currenttop += kAquaSpaceSwitchButtonFrameBoundsDiff;//from top
916 nControlWidth = nCheckboxMaxWidth;
917 int left = (nUsableWidth - nCheckboxMaxWidth) / 2;
918 controlRect.origin.x = left;
919 controlRect.origin.y = currenttop;
920 controlRect.size.width = nPopupMaxWidth;
921 [pControl setFrame:controlRect];
922 OSL_TRACE("setting checkbox at: {%f, %f, %f, %f}",controlRect.origin.x, controlRect.origin.y, controlRect.size.width, controlRect.size.height);
924 currenttop += kAquaSpaceSwitchButtonFrameBoundsDiff;
928 m_bIsUserPaneLaidOut = true;
930 DBG_PRINT_EXIT(CLASS_NAME, __func__);
933 void ControlHelper::createFilterControl() {
934 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
936 CResourceProvider aResProvider;
937 NSString* sLabel = aResProvider.getResString(CommonFilePickerElementIds::LISTBOX_FILTER_LABEL);
939 m_pFilterControl = [NSPopUpButton new];
941 [m_pFilterControl setAction:@selector(filterSelectedAtIndex:)];
942 [m_pFilterControl setTarget:m_pDelegate];
944 NSMenu *menu = [m_pFilterControl menu];
946 for (NSStringList::iterator iter = m_pFilterHelper->getFilterNames()->begin(); iter != m_pFilterHelper->getFilterNames()->end(); iter++) {
947 NSString *filterName = *iter;
948 OSL_TRACE("adding filter name: %s", [filterName UTF8String]);
949 if ([filterName isEqualToString:@"-"]) {
950 [menu addItem:[NSMenuItem separatorItem]];
952 else {
953 [m_pFilterControl addItemWithTitle:filterName];
957 // always add the filter as first item
958 m_aActiveControls.push_front(m_pFilterControl);
959 m_aMapListLabels[m_pFilterControl] = [sLabel retain];
961 DBG_PRINT_EXIT(CLASS_NAME, __func__);
964 NSTextField* ControlHelper::createLabelWithString(const NSString* labelString) {
965 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "label", labelString);
967 NSTextField *textField = [NSTextField new];
968 [textField setEditable:NO];
969 [textField setSelectable:NO];
970 [textField setDrawsBackground:NO];
971 [textField setBordered:NO];
972 [[textField cell] setTitle:labelString];
974 DBG_PRINT_EXIT(CLASS_NAME, __func__);
975 return textField;
978 int ControlHelper::getVerticalDistance(const NSControl* first, const NSControl* second)
980 if (first == nil) {
981 return kAquaSpaceBoxFrameViewDiffTop;
983 else if (second == nil) {
984 return kAquaSpaceBoxFrameViewDiffBottom;
986 else {
987 Class firstClass = [first class];
988 Class secondClass = [second class];
990 if (firstClass == [NSPopUpButton class]) {
991 if (secondClass == [NSPopUpButton class]) {
992 return kAquaSpaceBetweenPopupMenus;
994 else {
995 return kAquaSpaceAfterPopupButtonsV;
999 return kAquaSpaceBetweenControls;
1003 void ControlHelper::updateFilterUI()
1005 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
1007 if (m_bIsFilterControlNeeded == false || m_pFilterHelper == NULL) {
1008 OSL_TRACE("no filter control needed or no filter helper present");
1009 DBG_PRINT_EXIT(CLASS_NAME, __func__);
1010 return;
1013 int index = m_pFilterHelper->getCurrentFilterIndex();
1015 if (m_pFilterControl == nil) {
1016 createFilterControl();
1019 [m_pFilterControl selectItemAtIndex:index];
1021 DBG_PRINT_EXIT(CLASS_NAME, __func__);