1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
21 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
22 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
23 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
24 #include <osl/mutex.hxx>
25 #include <vcl/svapp.hxx>
26 #include "CFStringUtilities.hxx"
27 #include "resourceprovider.hxx"
28 #include "NSString_OOoAdditions.hxx"
29 #include "sal/log.hxx"
31 #include "ControlHelper.hxx"
34 #define CLASS_NAME "ControlHelper"
35 #define POPUP_WIDTH_MIN 200
36 #define POPUP_WIDTH_MAX 350
38 using namespace ::com::sun::star::ui::dialogs;
39 using namespace ::com::sun::star::ui::dialogs::TemplateDescription;
40 using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds;
41 using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds;
42 using namespace ::rtl;
44 #pragma mark Constructor / Destructor
46 // Constructor / Destructor
48 ControlHelper::ControlHelper()
50 , m_pFilterControl(nil)
51 , m_bUserPaneNeeded( false )
52 , m_bIsUserPaneLaidOut(false)
53 , m_bIsFilterControlNeeded(false)
54 , m_pFilterHelper(NULL)
56 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
60 for( i = 0; i < TOGGLE_LAST; i++ ) {
61 m_bToggleVisibility[i] = false;
64 for( i = 0; i < LIST_LAST; i++ ) {
65 m_bListVisibility[i] = false;
68 DBG_PRINT_EXIT(CLASS_NAME, __func__);
71 ControlHelper::~ControlHelper()
73 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
75 NSAutoreleasePool *pool = [NSAutoreleasePool new];
77 if (NULL != m_pUserPane) {
78 [m_pUserPane release];
81 if (m_pFilterControl != NULL) {
82 [m_pFilterControl setTarget:nil];
85 for(std::list<NSControl *>::iterator control = m_aActiveControls.begin(); control != m_aActiveControls.end(); ++control) {
86 NSControl* pControl = (*control);
87 NSString* sLabelName = m_aMapListLabels[pControl];
88 if (sLabelName != nil) {
91 if ([pControl class] == [NSPopUpButton class]) {
92 NSTextField* pField = m_aMapListLabelFields[(NSPopUpButton*)pControl];
102 DBG_PRINT_EXIT(CLASS_NAME, __func__);
105 #pragma mark XInitialization delegate
107 // XInitialization delegate
109 void ControlHelper::initialize( sal_Int16 nTemplateId )
111 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "templateId", nTemplateId);
113 switch( nTemplateId )
115 case FILESAVE_AUTOEXTENSION_PASSWORD:
116 m_bToggleVisibility[AUTOEXTENSION] = true;
117 m_bToggleVisibility[PASSWORD] = true;
119 case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
120 m_bToggleVisibility[AUTOEXTENSION] = true;
121 m_bToggleVisibility[PASSWORD] = true;
122 m_bToggleVisibility[FILTEROPTIONS] = true;
124 case FILESAVE_AUTOEXTENSION_SELECTION:
125 m_bToggleVisibility[AUTOEXTENSION] = true;
126 m_bToggleVisibility[SELECTION] = true;
128 case FILESAVE_AUTOEXTENSION_TEMPLATE:
129 m_bToggleVisibility[AUTOEXTENSION] = true;
130 m_bListVisibility[TEMPLATE] = true;
132 case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
133 m_bToggleVisibility[LINK] = true;
134 m_bToggleVisibility[PREVIEW] = true;
135 m_bListVisibility[IMAGE_TEMPLATE] = true;
137 case FILEOPEN_READONLY_VERSION:
138 m_bToggleVisibility[READONLY] = true;
139 m_bListVisibility[VERSION] = true;
141 case FILEOPEN_LINK_PREVIEW:
142 m_bToggleVisibility[LINK] = true;
143 m_bToggleVisibility[PREVIEW] = true;
145 case FILESAVE_AUTOEXTENSION:
146 m_bToggleVisibility[AUTOEXTENSION] = true;
152 DBG_PRINT_EXIT(CLASS_NAME, __func__);
155 #pragma mark XFilePickerControlAccess delegates
157 // XFilePickerControlAccess functions
160 void ControlHelper::enableControl( const sal_Int16 nControlId, const sal_Bool bEnable ) const
162 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "enable", bEnable);
164 SolarMutexGuard aGuard;
166 if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_PREVIEW) {
167 SAL_INFO("fpicker.aqua"," preview checkbox cannot be changed");
168 DBG_PRINT_EXIT(CLASS_NAME, __func__);
172 NSControl* pControl = getControl(nControlId);
174 if( pControl != nil ) {
176 SAL_INFO("fpicker.aqua", "enable" );
178 SAL_INFO("fpicker.aqua", "disable" );
180 [pControl setEnabled:bEnable];
182 SAL_INFO("fpicker.aqua","enable unknown control " << nControlId );
185 DBG_PRINT_EXIT(CLASS_NAME, __func__);
188 OUString ControlHelper::getLabel( sal_Int16 nControlId )
190 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId);
192 SolarMutexGuard aGuard;
194 NSControl* pControl = getControl( nControlId );
196 if( pControl == nil ) {
197 SAL_INFO("fpicker.aqua","Get label for unknown control " << nControlId);
201 rtl::OUString retVal;
202 if ([pControl class] == [NSPopUpButton class]) {
203 NSString *temp = m_aMapListLabels[pControl];
205 retVal = [temp OUString];
208 NSString* sLabel = [[pControl cell] title];
209 retVal = [sLabel OUString];
212 DBG_PRINT_EXIT(CLASS_NAME, __func__, retVal);
217 void ControlHelper::setLabel( sal_Int16 nControlId, NSString* aLabel )
219 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "label", aLabel);
221 SolarMutexGuard aGuard;
223 NSAutoreleasePool *pool = [NSAutoreleasePool new];
225 NSControl* pControl = getControl(nControlId);
227 if (nil != pControl) {
228 if ([pControl class] == [NSPopUpButton class]) {
229 NSString *sOldName = m_aMapListLabels[pControl];
230 if (sOldName != NULL && sOldName != aLabel) {
234 m_aMapListLabels[pControl] = [aLabel retain];
235 } else if ([pControl class] == [NSButton class]) {
236 [[pControl cell] setTitle:aLabel];
239 SAL_INFO("fpicker.aqua","Control not found to set label for");
246 DBG_PRINT_EXIT(CLASS_NAME, __func__);
249 void ControlHelper::setValue( sal_Int16 nControlId, sal_Int16 nControlAction, const uno::Any& rValue )
251 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "controlAction", nControlAction);
253 SolarMutexGuard aGuard;
255 if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_PREVIEW) {
256 SAL_INFO("fpicker.aqua"," value for preview is unchangeable");
259 NSControl* pControl = getControl( nControlId );
261 if( pControl == nil ) {
262 SAL_INFO("fpicker.aqua","enable unknown control " << nControlId);
264 if( [pControl class] == [NSPopUpButton class] ) {
265 HandleSetListValue(pControl, nControlAction, rValue);
266 } else if( [pControl class] == [NSButton class] ) {
267 sal_Bool bChecked = false;
269 SAL_INFO("fpicker.aqua"," value is a bool: " << bChecked);
270 [(NSButton*)pControl setState:(bChecked ? NSOnState : NSOffState)];
273 SAL_INFO("fpicker.aqua","Can't set value on button / list " << nControlId << " " << nControlAction);
278 DBG_PRINT_EXIT(CLASS_NAME, __func__);
281 uno::Any ControlHelper::getValue( sal_Int16 nControlId, sal_Int16 nControlAction ) const
283 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "controlAction", nControlAction);
285 SolarMutexGuard aGuard;
288 NSControl* pControl = getControl( nControlId );
290 if( pControl == nil ) {
291 SAL_INFO("fpicker.aqua","get value for unknown control " << nControlId);
292 aRetval <<= sal_True;
294 if( [pControl class] == [NSPopUpButton class] ) {
295 aRetval = HandleGetListValue(pControl, nControlAction);
296 } else if( [pControl class] == [NSButton class] ) {
297 //NSLog(@"control: %@", [[pControl cell] title]);
298 sal_Bool bValue = [(NSButton*)pControl state] == NSOnState ? sal_True : sal_False;
300 SAL_INFO("fpicker.aqua","value is a bool (checkbox): " << bValue);
304 DBG_PRINT_EXIT(CLASS_NAME, __func__);
309 void ControlHelper::createUserPane()
311 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
313 if (m_bUserPaneNeeded == false) {
314 SAL_INFO("fpicker.aqua","no user pane needed");
315 DBG_PRINT_EXIT(CLASS_NAME, __func__);
319 if (nil != m_pUserPane) {
320 SAL_INFO("fpicker.aqua","user pane already exists");
321 DBG_PRINT_EXIT(CLASS_NAME, __func__);
325 if (m_bIsFilterControlNeeded == true && m_pFilterControl == nil) {
326 createFilterControl();
329 NSRect minRect = NSMakeRect(0,0,300,33);
330 m_pUserPane = [[NSView alloc] initWithFrame:minRect];
332 int currentHeight = kAquaSpaceBoxFrameViewDiffTop + kAquaSpaceBoxFrameViewDiffBottom;
333 int currentWidth = 300;
335 sal_Bool bPopupControlPresent = NO;
336 sal_Bool bButtonControlPresent = NO;
338 int nCheckboxMaxWidth = 0;
339 int nPopupMaxWidth = 0;
340 int nPopupLabelMaxWidth = 0;
342 for (::std::list<NSControl*>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) {
343 SAL_INFO("fpicker.aqua","currentHeight: " << currentHeight);
345 NSControl* pControl = *child;
347 //let the control calculate its size
348 [pControl sizeToFit];
350 NSRect frame = [pControl frame];
351 SAL_INFO("fpicker.aqua","frame for control " << [[pControl description] UTF8String] << " is {" << frame.origin.x << ", " << frame.origin.y << ", " << frame.size.width << ", " << frame.size.height << "}");
353 int nControlHeight = frame.size.height;
354 int nControlWidth = frame.size.width;
356 // Note: controls are grouped by kind, first all popup menus, then checkboxes
357 if ([pControl class] == [NSPopUpButton class]) {
358 if (bPopupControlPresent == YES) {
359 //this is not the first popup
360 currentHeight += kAquaSpaceBetweenPopupMenus;
362 else if (child != m_aActiveControls.begin()){
363 currentHeight += kAquaSpaceBetweenControls;
366 bPopupControlPresent = YES;
368 // we have to add the label text width
369 NSString *label = m_aMapListLabels[pControl];
371 NSTextField *textField = createLabelWithString(label);
372 [textField sizeToFit];
373 m_aMapListLabelFields[(NSPopUpButton*)pControl] = textField;
374 [m_pUserPane addSubview:textField];
376 NSRect tfRect = [textField frame];
377 SAL_INFO("fpicker.aqua","frame for textfield " << [[textField description] UTF8String] << " is {" << tfRect.origin.x << ", " << tfRect.origin.y << ", " << tfRect.size.width << ", " << tfRect.size.height << "}");
379 int tfWidth = tfRect.size.width;
381 if (nPopupLabelMaxWidth < tfWidth) {
382 nPopupLabelMaxWidth = tfWidth;
385 frame.origin.x += (kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft) + tfWidth;
387 if (nControlWidth < POPUP_WIDTH_MIN) {
388 nControlWidth = POPUP_WIDTH_MIN;
389 frame.size.width = nControlWidth;
390 [pControl setFrame:frame];
393 if (nControlWidth > POPUP_WIDTH_MAX) {
394 nControlWidth = POPUP_WIDTH_MAX;
395 frame.size.width = nControlWidth;
396 [pControl setFrame:frame];
400 if (nPopupMaxWidth < nControlWidth) {
401 nPopupMaxWidth = nControlWidth;
404 nControlWidth += tfWidth + kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft;
405 if (nControlHeight < kAquaPopupButtonDefaultHeight) {
406 //maybe the popup has no menu item yet, so set a default height
407 nControlHeight = kAquaPopupButtonDefaultHeight;
410 nControlHeight -= kAquaSpacePopupMenuFrameBoundsDiffV;
412 else if ([pControl class] == [NSButton class]) {
413 if (child != m_aActiveControls.begin()){
414 currentHeight += kAquaSpaceBetweenControls;
417 if (nCheckboxMaxWidth < nControlWidth) {
418 nCheckboxMaxWidth = nControlWidth;
421 bButtonControlPresent = YES;
422 nControlWidth -= 2 * kAquaSpaceSwitchButtonFrameBoundsDiff;
423 nControlHeight -= 2 * kAquaSpaceSwitchButtonFrameBoundsDiff;
426 // if ((nControlWidth + 2 * kAquaSpaceInsideGroupH) > currentWidth) {
427 // currentWidth = nControlWidth + 2 * kAquaSpaceInsideGroupH;
430 currentHeight += nControlHeight;
432 [m_pUserPane addSubview:pControl];
435 SAL_INFO("fpicker.aqua","height after adding all controls: " << currentHeight);
437 if (bPopupControlPresent && bButtonControlPresent)
439 //after a popup button (array) and before a different kind of control we need some extra space instead of the standard
440 currentHeight -= kAquaSpaceBetweenControls;
441 currentHeight += kAquaSpaceAfterPopupButtonsV;
442 SAL_INFO("fpicker.aqua","popup extra space added, currentHeight: " << currentHeight);
445 int nLongestPopupWidth = nPopupMaxWidth + nPopupLabelMaxWidth + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
447 currentWidth = nLongestPopupWidth > nCheckboxMaxWidth ? nLongestPopupWidth : nCheckboxMaxWidth;
448 SAL_INFO("fpicker.aqua","longest control width: " << currentWidth);
450 currentWidth += 2* kAquaSpaceInsideGroupH;
452 if (currentWidth < minRect.size.width)
453 currentWidth = minRect.size.width;
455 if (currentHeight < minRect.size.height)
456 currentHeight = minRect.size.height;
458 NSRect upRect = NSMakeRect(0, 0, currentWidth, currentHeight );
459 SAL_INFO("fpicker.aqua","setting user pane rect to {" << upRect.origin.x << ", " << upRect.origin.y << ", " << upRect.size.width << ", " << upRect.size.height << "}");
461 [m_pUserPane setFrame:upRect];
465 DBG_PRINT_EXIT(CLASS_NAME, __func__);
468 #pragma mark Private / Misc
472 void ControlHelper::createControls()
474 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
476 CResourceProvider aResProvider;
477 for (int i = 0; i < LIST_LAST; i++) {
478 if (true == m_bListVisibility[i]) {
479 m_bUserPaneNeeded = true;
481 int elementName = getControlElementName([NSPopUpButton class], i);
482 NSString* sLabel = aResProvider.getResString(elementName);
484 m_pListControls[i] = [NSPopUpButton new];
486 #define MAP_LIST_( elem ) \
488 setLabel(ExtendedFilePickerElementIds::LISTBOX_##elem, sLabel); \
494 MAP_LIST_(IMAGE_TEMPLATE);
497 m_aActiveControls.push_back(m_pListControls[i]);
499 m_pListControls[i] = nil;
503 for (int i = 0/*#i102102*/; i < TOGGLE_LAST; i++) {
504 if (true == m_bToggleVisibility[i]) {
505 m_bUserPaneNeeded = true;
507 int elementName = getControlElementName([NSButton class], i);
508 NSString* sLabel = aResProvider.getResString(elementName);
510 NSButton *button = [NSButton new];
511 [button setTitle:sLabel];
513 [button setButtonType:NSSwitchButton];
515 [button setState:NSOffState];
517 if (i == AUTOEXTENSION) {
518 [button setTarget:m_pDelegate];
519 [button setAction:@selector(autoextensionChanged:)];
522 m_pToggles[i] = button;
524 m_aActiveControls.push_back(m_pToggles[i]);
530 //preview is always on with Mac OS X
531 NSControl *pPreviewBox = m_pToggles[PREVIEW];
532 if (pPreviewBox != nil) {
533 [pPreviewBox setEnabled:NO];
534 [(NSButton*)pPreviewBox setState:NSOnState];
537 DBG_PRINT_EXIT(CLASS_NAME, __func__);
540 #define TOGGLE_ELEMENT( elem ) \
542 nReturn = CHECKBOX_##elem; \
543 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn); \
545 #define LIST_ELEMENT( elem ) \
547 nReturn = LISTBOX_##elem##_LABEL; \
548 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn); \
551 int ControlHelper::getControlElementName(const Class aClazz, const int nControlId) const
553 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aClazz", [[aClazz description] UTF8String], "controlId", nControlId);
556 if (aClazz == [NSButton class])
558 switch (nControlId) {
559 TOGGLE_ELEMENT( AUTOEXTENSION );
560 TOGGLE_ELEMENT( PASSWORD );
561 TOGGLE_ELEMENT( FILTEROPTIONS );
562 TOGGLE_ELEMENT( READONLY );
563 TOGGLE_ELEMENT( LINK );
564 TOGGLE_ELEMENT( PREVIEW );
565 TOGGLE_ELEMENT( SELECTION );
568 else if (aClazz == [NSPopUpButton class])
570 switch (nControlId) {
571 LIST_ELEMENT( VERSION );
572 LIST_ELEMENT( TEMPLATE );
573 LIST_ELEMENT( IMAGE_TEMPLATE );
577 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn);
582 void ControlHelper::HandleSetListValue(const NSControl* pControl, const sal_Int16 nControlAction, const uno::Any& rValue)
584 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlAction", nControlAction);
586 if ([pControl class] != [NSPopUpButton class]) {
587 SAL_INFO("fpicker.aqua","not a popup menu");
588 DBG_PRINT_EXIT(CLASS_NAME, __func__);
592 NSPopUpButton *pButton = (NSPopUpButton*)pControl;
593 NSMenu *rMenu = [pButton menu];
595 SAL_INFO("fpicker.aqua","button has no menu");
596 DBG_PRINT_EXIT(CLASS_NAME, __func__);
600 switch (nControlAction)
602 case ControlActions::ADD_ITEM:
604 SAL_INFO("fpicker.aqua","ADD_ITEMS");
608 NSString* sCFItem = [NSString stringWithOUString:sItem];
609 SAL_INFO("fpicker.aqua","Adding menu item: " << OUStringToOString(sItem, RTL_TEXTENCODING_UTF8).getStr());
610 [pButton addItemWithTitle:sCFItem];
613 case ControlActions::ADD_ITEMS:
615 SAL_INFO("fpicker.aqua","ADD_ITEMS");
616 uno::Sequence< OUString > aStringList;
617 rValue >>= aStringList;
618 sal_Int32 nItemCount = aStringList.getLength();
619 for (sal_Int32 i = 0; i < nItemCount; ++i)
621 NSString* sCFItem = [NSString stringWithOUString:aStringList[i]];
622 SAL_INFO("fpicker.aqua","Adding menu item: " << OUStringToOString(aStringList[i], RTL_TEXTENCODING_UTF8).getStr());
623 [pButton addItemWithTitle:sCFItem];
627 case ControlActions::DELETE_ITEM:
629 SAL_INFO("fpicker.aqua","DELETE_ITEM");
632 SAL_INFO("fpicker.aqua","Deleting item at position " << (nPos));
633 [rMenu removeItemAtIndex:nPos];
636 case ControlActions::DELETE_ITEMS:
638 SAL_INFO("fpicker.aqua","DELETE_ITEMS");
639 int nItems = [rMenu numberOfItems];
641 SAL_INFO("fpicker.aqua","no menu items to delete");
642 DBG_PRINT_EXIT(CLASS_NAME, __func__);
645 for(sal_Int32 i = 0; i < nItems; i++) {
646 [rMenu removeItemAtIndex:i];
650 case ControlActions::SET_SELECT_ITEM:
654 SAL_INFO("fpicker.aqua","Selecting item at position " << nPos);
655 [pButton selectItemAtIndex:nPos];
659 SAL_INFO("fpicker.aqua","undocumented/unimplemented ControlAction for a list");
665 DBG_PRINT_EXIT(CLASS_NAME, __func__);
669 uno::Any ControlHelper::HandleGetListValue(const NSControl* pControl, const sal_Int16 nControlAction) const
671 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlAction", nControlAction);
675 if ([pControl class] != [NSPopUpButton class]) {
676 SAL_INFO("fpicker.aqua","not a popup button");
677 DBG_PRINT_EXIT(CLASS_NAME, __func__);
681 NSPopUpButton *pButton = (NSPopUpButton*)pControl;
682 NSMenu *rMenu = [pButton menu];
684 SAL_INFO("fpicker.aqua","button has no menu");
685 DBG_PRINT_EXIT(CLASS_NAME, __func__);
689 switch (nControlAction)
691 case ControlActions::GET_ITEMS:
693 SAL_INFO("fpicker.aqua","GET_ITEMS");
694 uno::Sequence< OUString > aItemList;
696 int nItems = [rMenu numberOfItems];
698 aItemList.realloc(nItems);
700 for (int i = 0; i < nItems; i++) {
701 NSString* sCFItem = [pButton itemTitleAtIndex:i];
702 if (nil != sCFItem) {
703 aItemList[i] = [sCFItem OUString];
704 SAL_INFO("fpicker.aqua","Return value[" << (i - 1) << "]: " << OUStringToOString(aItemList[i - 1], RTL_TEXTENCODING_UTF8).getStr());
711 case ControlActions::GET_SELECTED_ITEM:
713 SAL_INFO("fpicker.aqua","GET_SELECTED_ITEM");
714 NSString* sCFItem = [pButton titleOfSelectedItem];
715 if (nil != sCFItem) {
716 OUString sString = [sCFItem OUString];
717 SAL_INFO("fpicker.aqua","Return value: " << OUStringToOString(sString, RTL_TEXTENCODING_UTF8).getStr());
722 case ControlActions::GET_SELECTED_ITEM_INDEX:
724 SAL_INFO("fpicker.aqua","GET_SELECTED_ITEM_INDEX");
725 sal_Int32 nActive = [pButton indexOfSelectedItem];
726 SAL_INFO("fpicker.aqua","Return value: " << nActive);
731 SAL_INFO("fpicker.aqua","undocumented/unimplemented ControlAction for a list");
735 DBG_PRINT_EXIT(CLASS_NAME, __func__);
741 // cf. offapi/com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.idl
742 NSControl* ControlHelper::getControl( const sal_Int16 nControlId ) const
744 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId);
746 NSControl* pWidget = nil;
748 #define MAP_TOGGLE( elem ) \
749 case ExtendedFilePickerElementIds::CHECKBOX_##elem: \
750 pWidget = m_pToggles[elem]; \
753 #define MAP_LIST( elem ) \
754 case ExtendedFilePickerElementIds::LISTBOX_##elem: \
755 pWidget = m_pListControls[elem]; \
758 #define MAP_LIST_LABEL( elem ) \
759 case ExtendedFilePickerElementIds::LISTBOX_##elem##_LABEL: \
760 pWidget = m_pListControls[elem]; \
765 MAP_TOGGLE( AUTOEXTENSION );
766 MAP_TOGGLE( PASSWORD );
767 MAP_TOGGLE( FILTEROPTIONS );
768 MAP_TOGGLE( READONLY );
770 MAP_TOGGLE( PREVIEW );
771 MAP_TOGGLE( SELECTION );
772 //MAP_BUTTON( PLAY );
774 MAP_LIST( TEMPLATE );
775 MAP_LIST( IMAGE_TEMPLATE );
776 MAP_LIST_LABEL( VERSION );
777 MAP_LIST_LABEL( TEMPLATE );
778 MAP_LIST_LABEL( IMAGE_TEMPLATE );
780 SAL_INFO("fpicker.aqua","Handle unknown control " << nControlId);
785 DBG_PRINT_EXIT(CLASS_NAME, __func__);
790 void ControlHelper::layoutControls()
792 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
794 SolarMutexGuard aGuard;
796 if (nil == m_pUserPane) {
797 SAL_INFO("fpicker.aqua","no user pane to layout");
798 DBG_PRINT_EXIT(CLASS_NAME, __func__);
802 if (m_bIsUserPaneLaidOut == true) {
803 SAL_INFO("fpicker.aqua","user pane already laid out");
804 DBG_PRINT_EXIT(CLASS_NAME, __func__);
808 NSRect userPaneRect = [m_pUserPane frame];
809 SAL_INFO("fpicker.aqua","userPane frame: {" << userPaneRect.origin.x << ", " << userPaneRect.origin.y << ", " << userPaneRect.size.width << ", " << userPaneRect.size.height << "}");
811 int nUsableWidth = userPaneRect.size.width;
813 //NOTE: NSView's coordinate system starts in the lower left hand corner but we start adding controls from the top,
814 // so we subtract from the vertical position as we make our way down the pane.
815 int currenttop = userPaneRect.size.height;
816 int nCheckboxMaxWidth = 0;
817 int nPopupMaxWidth = 0;
818 int nPopupLabelMaxWidth = 0;
820 //first loop to determine max sizes
821 for (::std::list<NSControl*>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) {
822 NSControl* pControl = *child;
824 NSRect controlRect = [pControl frame];
825 int nControlWidth = controlRect.size.width;
827 Class aSubType = [pControl class];
828 if (aSubType == [NSPopUpButton class]) {
829 if (nPopupMaxWidth < nControlWidth) {
830 nPopupMaxWidth = nControlWidth;
832 NSTextField *label = m_aMapListLabelFields[(NSPopUpButton*)pControl];
833 NSRect labelFrame = [label frame];
834 int nLabelWidth = labelFrame.size.width;
835 if (nPopupLabelMaxWidth < nLabelWidth) {
836 nPopupLabelMaxWidth = nLabelWidth;
839 if (nCheckboxMaxWidth < nControlWidth) {
840 nCheckboxMaxWidth = nControlWidth;
845 int nLongestPopupWidth = nPopupMaxWidth + nPopupLabelMaxWidth + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
846 SAL_INFO("fpicker.aqua","longest popup width: " << nLongestPopupWidth);
848 NSControl* previousControl = nil;
850 int nDistBetweenControls = 0;
852 for (::std::list<NSControl*>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) {
853 NSControl* pControl = *child;
855 //get the control's bounds
856 NSRect controlRect = [pControl frame];
857 int nControlHeight = controlRect.size.height;
858 int nControlWidth = controlRect.size.width;
860 //subtract the height from the current vertical position, because the control's bounds origin rect will be its lower left hand corner
861 currenttop -= nControlHeight;
863 Class aSubType = [pControl class];
865 //add space between the previous control and this control according to Apple's HIG
866 nDistBetweenControls = getVerticalDistance(previousControl, pControl);
867 SAL_INFO("fpicker.aqua","vertical distance: " << nDistBetweenControls);
868 currenttop -= nDistBetweenControls;
870 previousControl = pControl;
872 if (aSubType == [NSPopUpButton class]) {
873 //move vertically up some pixels to space the controls between their real (visual) bounds
874 currenttop += kAquaSpacePopupMenuFrameBoundsDiffTop;//from top
876 //get the corresponding popup label
877 NSTextField *label = m_aMapListLabelFields[(NSPopUpButton*)pControl];
878 NSRect labelFrame = [label frame];
879 int totalWidth = nPopupMaxWidth + labelFrame.size.width + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
880 SAL_INFO("fpicker.aqua","totalWidth: " << totalWidth);
881 //let's center popups
882 int left = (nUsableWidth + nLongestPopupWidth) / 2 - totalWidth;
883 SAL_INFO("fpicker.aqua","left: " << left);
884 labelFrame.origin.x = left;
885 labelFrame.origin.y = currenttop + kAquaSpaceLabelPopupDiffV;
886 SAL_INFO("fpicker.aqua","setting label at: {" << labelFrame.origin.x << ", " << labelFrame.origin.y << ", " << labelFrame.size.width << ", " << labelFrame.size.height << "}");
887 [label setFrame:labelFrame];
889 controlRect.origin.x = left + labelFrame.size.width + kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft;
890 controlRect.origin.y = currenttop;
891 controlRect.size.width = nPopupMaxWidth;
892 SAL_INFO("fpicker.aqua","setting popup at: {" << controlRect.origin.x << ", " << controlRect.origin.y << ", " << controlRect.size.width << ", " << controlRect.size.height << "}");
893 [pControl setFrame:controlRect];
895 //add some space to place the vertical position right below the popup's visual bounds
896 currenttop += kAquaSpacePopupMenuFrameBoundsDiffBottom;
898 currenttop += kAquaSpaceSwitchButtonFrameBoundsDiff;//from top
900 nControlWidth = nCheckboxMaxWidth;
901 int left = (nUsableWidth - nCheckboxMaxWidth) / 2;
902 controlRect.origin.x = left;
903 controlRect.origin.y = currenttop;
904 controlRect.size.width = nPopupMaxWidth;
905 [pControl setFrame:controlRect];
906 SAL_INFO("fpicker.aqua","setting checkbox at: {" << controlRect.origin.x << ", " << controlRect.origin.y << ", " << controlRect.size.width << ", " << controlRect.size.height << "}");
908 currenttop += kAquaSpaceSwitchButtonFrameBoundsDiff;
912 m_bIsUserPaneLaidOut = true;
914 DBG_PRINT_EXIT(CLASS_NAME, __func__);
917 void ControlHelper::createFilterControl() {
918 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
920 CResourceProvider aResProvider;
921 NSString* sLabel = aResProvider.getResString(CommonFilePickerElementIds::LISTBOX_FILTER_LABEL);
923 m_pFilterControl = [NSPopUpButton new];
925 [m_pFilterControl setAction:@selector(filterSelectedAtIndex:)];
926 [m_pFilterControl setTarget:m_pDelegate];
928 NSMenu *menu = [m_pFilterControl menu];
930 for (NSStringList::iterator iter = m_pFilterHelper->getFilterNames()->begin(); iter != m_pFilterHelper->getFilterNames()->end(); iter++) {
931 NSString *filterName = *iter;
932 SAL_INFO("fpicker.aqua","adding filter name: " << [filterName UTF8String]);
933 if ([filterName isEqualToString:@"-"]) {
934 [menu addItem:[NSMenuItem separatorItem]];
937 [m_pFilterControl addItemWithTitle:filterName];
941 // always add the filter as first item
942 m_aActiveControls.push_front(m_pFilterControl);
943 m_aMapListLabels[m_pFilterControl] = [sLabel retain];
945 DBG_PRINT_EXIT(CLASS_NAME, __func__);
948 NSTextField* ControlHelper::createLabelWithString(NSString* labelString) {
949 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "label", labelString);
951 NSTextField *textField = [NSTextField new];
952 [textField setEditable:NO];
953 [textField setSelectable:NO];
954 [textField setDrawsBackground:NO];
955 [textField setBordered:NO];
956 [[textField cell] setTitle:labelString];
958 DBG_PRINT_EXIT(CLASS_NAME, __func__);
962 int ControlHelper::getVerticalDistance(const NSControl* first, const NSControl* second)
965 return kAquaSpaceBoxFrameViewDiffTop;
967 else if (second == nil) {
968 return kAquaSpaceBoxFrameViewDiffBottom;
971 Class firstClass = [first class];
972 Class secondClass = [second class];
974 if (firstClass == [NSPopUpButton class]) {
975 if (secondClass == [NSPopUpButton class]) {
976 return kAquaSpaceBetweenPopupMenus;
979 return kAquaSpaceAfterPopupButtonsV;
983 return kAquaSpaceBetweenControls;
987 void ControlHelper::updateFilterUI()
989 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
991 if (m_bIsFilterControlNeeded == false || m_pFilterHelper == NULL) {
992 SAL_INFO("fpicker.aqua","no filter control needed or no filter helper present");
993 DBG_PRINT_EXIT(CLASS_NAME, __func__);
997 int index = m_pFilterHelper->getCurrentFilterIndex();
999 if (m_pFilterControl == nil) {
1000 createFilterControl();
1003 [m_pFilterControl selectItemAtIndex:index];
1005 DBG_PRINT_EXIT(CLASS_NAME, __func__);
1008 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */