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;
45 uno::Any HandleGetListValue(const NSControl* pControl, const sal_Int16 nControlAction)
47 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlAction", nControlAction);
51 if ([pControl class] != [NSPopUpButton class]) {
52 SAL_INFO("fpicker.aqua","not a popup button");
53 DBG_PRINT_EXIT(CLASS_NAME, __func__);
57 NSPopUpButton *pButton = (NSPopUpButton*)pControl;
58 NSMenu *rMenu = [pButton menu];
60 SAL_INFO("fpicker.aqua","button has no menu");
61 DBG_PRINT_EXIT(CLASS_NAME, __func__);
65 switch (nControlAction)
67 case ControlActions::GET_ITEMS:
69 SAL_INFO("fpicker.aqua","GET_ITEMS");
70 uno::Sequence< OUString > aItemList;
72 int nItems = [rMenu numberOfItems];
74 aItemList.realloc(nItems);
76 for (int i = 0; i < nItems; i++) {
77 NSString* sCFItem = [pButton itemTitleAtIndex:i];
79 aItemList[i] = [sCFItem OUString];
80 SAL_INFO("fpicker.aqua","Return value[" << (i - 1) << "]: " << OUStringToOString(aItemList[i - 1], RTL_TEXTENCODING_UTF8).getStr());
87 case ControlActions::GET_SELECTED_ITEM:
89 SAL_INFO("fpicker.aqua","GET_SELECTED_ITEM");
90 NSString* sCFItem = [pButton titleOfSelectedItem];
92 OUString sString = [sCFItem OUString];
93 SAL_INFO("fpicker.aqua","Return value: " << OUStringToOString(sString, RTL_TEXTENCODING_UTF8).getStr());
98 case ControlActions::GET_SELECTED_ITEM_INDEX:
100 SAL_INFO("fpicker.aqua","GET_SELECTED_ITEM_INDEX");
101 sal_Int32 nActive = [pButton indexOfSelectedItem];
102 SAL_INFO("fpicker.aqua","Return value: " << nActive);
107 SAL_INFO("fpicker.aqua","undocumented/unimplemented ControlAction for a list");
111 DBG_PRINT_EXIT(CLASS_NAME, __func__);
116 NSTextField* createLabelWithString(NSString* labelString) {
117 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "label", labelString);
119 NSTextField *textField = [NSTextField new];
120 [textField setEditable:NO];
121 [textField setSelectable:NO];
122 [textField setDrawsBackground:NO];
123 [textField setBordered:NO];
124 SAL_WNODEPRECATED_DECLARATIONS_PUSH //TODO: 10.9 setTitle
125 [[textField cell] setTitle:labelString];
126 SAL_WNODEPRECATED_DECLARATIONS_POP
128 DBG_PRINT_EXIT(CLASS_NAME, __func__);
134 #pragma mark Constructor / Destructor
136 // Constructor / Destructor
138 ControlHelper::ControlHelper()
140 , m_pFilterControl(nil)
141 , m_bUserPaneNeeded( false )
142 , m_bIsUserPaneLaidOut(false)
143 , m_bIsFilterControlNeeded(false)
144 , m_pFilterHelper(NULL)
146 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
150 for( i = 0; i < TOGGLE_LAST; i++ ) {
151 m_bToggleVisibility[i] = false;
154 for( i = 0; i < LIST_LAST; i++ ) {
155 m_bListVisibility[i] = false;
158 DBG_PRINT_EXIT(CLASS_NAME, __func__);
161 ControlHelper::~ControlHelper()
163 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
165 NSAutoreleasePool *pool = [NSAutoreleasePool new];
167 if (NULL != m_pUserPane) {
168 [m_pUserPane release];
171 if (m_pFilterControl != NULL) {
172 [m_pFilterControl setTarget:nil];
175 for(std::list<NSControl *>::iterator control = m_aActiveControls.begin(); control != m_aActiveControls.end(); ++control) {
176 NSControl* pControl = (*control);
177 NSString* sLabelName = m_aMapListLabels[pControl];
178 if (sLabelName != nil) {
179 [sLabelName release];
181 if ([pControl class] == [NSPopUpButton class]) {
182 NSTextField* pField = m_aMapListLabelFields[(NSPopUpButton*)pControl];
192 DBG_PRINT_EXIT(CLASS_NAME, __func__);
195 #pragma mark XInitialization delegate
197 // XInitialization delegate
199 void ControlHelper::initialize( sal_Int16 nTemplateId )
201 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "templateId", nTemplateId);
203 switch( nTemplateId )
205 case FILESAVE_AUTOEXTENSION_PASSWORD:
206 m_bToggleVisibility[AUTOEXTENSION] = true;
207 m_bToggleVisibility[PASSWORD] = true;
209 case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
210 m_bToggleVisibility[AUTOEXTENSION] = true;
211 m_bToggleVisibility[PASSWORD] = true;
212 m_bToggleVisibility[FILTEROPTIONS] = true;
214 case FILESAVE_AUTOEXTENSION_SELECTION:
215 m_bToggleVisibility[AUTOEXTENSION] = true;
216 m_bToggleVisibility[SELECTION] = true;
218 case FILESAVE_AUTOEXTENSION_TEMPLATE:
219 m_bToggleVisibility[AUTOEXTENSION] = true;
220 m_bListVisibility[TEMPLATE] = true;
222 case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
223 m_bToggleVisibility[LINK] = true;
224 m_bToggleVisibility[PREVIEW] = true;
225 m_bListVisibility[IMAGE_TEMPLATE] = true;
227 case FILEOPEN_READONLY_VERSION:
228 m_bToggleVisibility[READONLY] = true;
229 m_bListVisibility[VERSION] = true;
231 case FILEOPEN_LINK_PREVIEW:
232 m_bToggleVisibility[LINK] = true;
233 m_bToggleVisibility[PREVIEW] = true;
235 case FILESAVE_AUTOEXTENSION:
236 m_bToggleVisibility[AUTOEXTENSION] = true;
242 DBG_PRINT_EXIT(CLASS_NAME, __func__);
245 #pragma mark XFilePickerControlAccess delegates
247 // XFilePickerControlAccess functions
250 void ControlHelper::enableControl( const sal_Int16 nControlId, const bool bEnable ) const
252 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "enable", int(bEnable));
254 SolarMutexGuard aGuard;
256 if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_PREVIEW) {
257 SAL_INFO("fpicker.aqua"," preview checkbox cannot be changed");
258 DBG_PRINT_EXIT(CLASS_NAME, __func__);
262 NSControl* pControl = getControl(nControlId);
264 if( pControl != nil ) {
266 SAL_INFO("fpicker.aqua", "enable" );
268 SAL_INFO("fpicker.aqua", "disable" );
270 [pControl setEnabled:bEnable];
272 SAL_INFO("fpicker.aqua","enable unknown control " << nControlId );
275 DBG_PRINT_EXIT(CLASS_NAME, __func__);
278 OUString ControlHelper::getLabel( sal_Int16 nControlId )
280 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId);
282 SolarMutexGuard aGuard;
284 NSControl* pControl = getControl( nControlId );
286 if( pControl == nil ) {
287 SAL_INFO("fpicker.aqua","Get label for unknown control " << nControlId);
291 rtl::OUString retVal;
292 if ([pControl class] == [NSPopUpButton class]) {
293 NSString *temp = m_aMapListLabels[pControl];
295 retVal = [temp OUString];
298 SAL_WNODEPRECATED_DECLARATIONS_PUSH //TODO: 10.9 title
299 NSString* sLabel = [[pControl cell] title];
300 SAL_WNODEPRECATED_DECLARATIONS_POP
301 retVal = [sLabel OUString];
304 DBG_PRINT_EXIT(CLASS_NAME, __func__, retVal);
309 void ControlHelper::setLabel( sal_Int16 nControlId, NSString* aLabel )
311 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "label", aLabel);
313 SolarMutexGuard aGuard;
315 NSAutoreleasePool *pool = [NSAutoreleasePool new];
317 NSControl* pControl = getControl(nControlId);
319 if (nil != pControl) {
320 if ([pControl class] == [NSPopUpButton class]) {
321 NSString *sOldName = m_aMapListLabels[pControl];
322 if (sOldName != NULL && sOldName != aLabel) {
326 m_aMapListLabels[pControl] = [aLabel retain];
327 } else if ([pControl class] == [NSButton class]) {
328 SAL_WNODEPRECATED_DECLARATIONS_PUSH //TODO: 10.9 setTitle
329 [[pControl cell] setTitle:aLabel];
330 SAL_WNODEPRECATED_DECLARATIONS_POP
333 SAL_INFO("fpicker.aqua","Control not found to set label for");
340 DBG_PRINT_EXIT(CLASS_NAME, __func__);
343 void ControlHelper::setValue( sal_Int16 nControlId, sal_Int16 nControlAction, const uno::Any& rValue )
345 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "controlAction", nControlAction);
347 SolarMutexGuard aGuard;
349 if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_PREVIEW) {
350 SAL_INFO("fpicker.aqua"," value for preview is unchangeable");
353 NSControl* pControl = getControl( nControlId );
355 if( pControl == nil ) {
356 SAL_INFO("fpicker.aqua","enable unknown control " << nControlId);
358 if( [pControl class] == [NSPopUpButton class] ) {
359 HandleSetListValue(pControl, nControlAction, rValue);
360 } else if( [pControl class] == [NSButton class] ) {
361 bool bChecked = false;
363 SAL_INFO("fpicker.aqua"," value is a bool: " << bChecked);
364 [(NSButton*)pControl setState:(bChecked ? NSOnState : NSOffState)];
367 SAL_INFO("fpicker.aqua","Can't set value on button / list " << nControlId << " " << nControlAction);
372 DBG_PRINT_EXIT(CLASS_NAME, __func__);
375 uno::Any ControlHelper::getValue( sal_Int16 nControlId, sal_Int16 nControlAction ) const
377 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "controlAction", nControlAction);
379 SolarMutexGuard aGuard;
382 NSControl* pControl = getControl( nControlId );
384 if( pControl == nil ) {
385 SAL_INFO("fpicker.aqua","get value for unknown control " << nControlId);
388 if( [pControl class] == [NSPopUpButton class] ) {
389 aRetval = HandleGetListValue(pControl, nControlAction);
390 } else if( [pControl class] == [NSButton class] ) {
391 //NSLog(@"control: %@", [[pControl cell] title]);
392 bool bValue = [(NSButton*)pControl state] == NSOnState;
394 SAL_INFO("fpicker.aqua","value is a bool (checkbox): " << bValue);
398 DBG_PRINT_EXIT(CLASS_NAME, __func__);
403 void ControlHelper::createUserPane()
405 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
407 if (!m_bUserPaneNeeded) {
408 SAL_INFO("fpicker.aqua","no user pane needed");
409 DBG_PRINT_EXIT(CLASS_NAME, __func__);
413 if (nil != m_pUserPane) {
414 SAL_INFO("fpicker.aqua","user pane already exists");
415 DBG_PRINT_EXIT(CLASS_NAME, __func__);
419 if (m_bIsFilterControlNeeded && m_pFilterControl == nil) {
420 createFilterControl();
423 NSRect minRect = NSMakeRect(0,0,300,33);
424 m_pUserPane = [[NSView alloc] initWithFrame:minRect];
426 int currentHeight = kAquaSpaceBoxFrameViewDiffTop + kAquaSpaceBoxFrameViewDiffBottom;
427 int currentWidth = 300;
429 bool bPopupControlPresent = false;
430 bool bButtonControlPresent = false;
432 int nCheckboxMaxWidth = 0;
433 int nPopupMaxWidth = 0;
434 int nPopupLabelMaxWidth = 0;
436 for (::std::list<NSControl*>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) {
437 SAL_INFO("fpicker.aqua","currentHeight: " << currentHeight);
439 NSControl* pControl = *child;
441 //let the control calculate its size
442 [pControl sizeToFit];
444 NSRect frame = [pControl frame];
445 SAL_INFO("fpicker.aqua","frame for control " << [[pControl description] UTF8String] << " is {" << frame.origin.x << ", " << frame.origin.y << ", " << frame.size.width << ", " << frame.size.height << "}");
447 int nControlHeight = frame.size.height;
448 int nControlWidth = frame.size.width;
450 // Note: controls are grouped by kind, first all popup menus, then checkboxes
451 if ([pControl class] == [NSPopUpButton class]) {
452 if (bPopupControlPresent) {
453 //this is not the first popup
454 currentHeight += kAquaSpaceBetweenPopupMenus;
456 else if (child != m_aActiveControls.begin()){
457 currentHeight += kAquaSpaceBetweenControls;
460 bPopupControlPresent = true;
462 // we have to add the label text width
463 NSString *label = m_aMapListLabels[pControl];
465 NSTextField *textField = createLabelWithString(label);
466 [textField sizeToFit];
467 m_aMapListLabelFields[(NSPopUpButton*)pControl] = textField;
468 [m_pUserPane addSubview:textField];
470 NSRect tfRect = [textField frame];
471 SAL_INFO("fpicker.aqua","frame for textfield " << [[textField description] UTF8String] << " is {" << tfRect.origin.x << ", " << tfRect.origin.y << ", " << tfRect.size.width << ", " << tfRect.size.height << "}");
473 int tfWidth = tfRect.size.width;
475 if (nPopupLabelMaxWidth < tfWidth) {
476 nPopupLabelMaxWidth = tfWidth;
479 frame.origin.x += (kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft) + tfWidth;
481 if (nControlWidth < POPUP_WIDTH_MIN) {
482 nControlWidth = POPUP_WIDTH_MIN;
483 frame.size.width = nControlWidth;
484 [pControl setFrame:frame];
487 if (nControlWidth > POPUP_WIDTH_MAX) {
488 nControlWidth = POPUP_WIDTH_MAX;
489 frame.size.width = nControlWidth;
490 [pControl setFrame:frame];
494 if (nPopupMaxWidth < nControlWidth) {
495 nPopupMaxWidth = nControlWidth;
498 nControlWidth += tfWidth + kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft;
499 if (nControlHeight < kAquaPopupButtonDefaultHeight) {
500 //maybe the popup has no menu item yet, so set a default height
501 nControlHeight = kAquaPopupButtonDefaultHeight;
504 nControlHeight -= kAquaSpacePopupMenuFrameBoundsDiffV;
506 else if ([pControl class] == [NSButton class]) {
507 if (child != m_aActiveControls.begin()){
508 currentHeight += kAquaSpaceBetweenControls;
511 if (nCheckboxMaxWidth < nControlWidth) {
512 nCheckboxMaxWidth = nControlWidth;
515 bButtonControlPresent = YES;
516 nControlWidth -= 2 * kAquaSpaceSwitchButtonFrameBoundsDiff;
517 nControlHeight -= 2 * kAquaSpaceSwitchButtonFrameBoundsDiff;
520 // if ((nControlWidth + 2 * kAquaSpaceInsideGroupH) > currentWidth) {
521 // currentWidth = nControlWidth + 2 * kAquaSpaceInsideGroupH;
524 currentHeight += nControlHeight;
526 [m_pUserPane addSubview:pControl];
529 SAL_INFO("fpicker.aqua","height after adding all controls: " << currentHeight);
531 if (bPopupControlPresent && bButtonControlPresent)
533 //after a popup button (array) and before a different kind of control we need some extra space instead of the standard
534 currentHeight -= kAquaSpaceBetweenControls;
535 currentHeight += kAquaSpaceAfterPopupButtonsV;
536 SAL_INFO("fpicker.aqua","popup extra space added, currentHeight: " << currentHeight);
539 int nLongestPopupWidth = nPopupMaxWidth + nPopupLabelMaxWidth + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
541 currentWidth = nLongestPopupWidth > nCheckboxMaxWidth ? nLongestPopupWidth : nCheckboxMaxWidth;
542 SAL_INFO("fpicker.aqua","longest control width: " << currentWidth);
544 currentWidth += 2* kAquaSpaceInsideGroupH;
546 if (currentWidth < minRect.size.width)
547 currentWidth = minRect.size.width;
549 if (currentHeight < minRect.size.height)
550 currentHeight = minRect.size.height;
552 NSRect upRect = NSMakeRect(0, 0, currentWidth, currentHeight );
553 SAL_INFO("fpicker.aqua","setting user pane rect to {" << upRect.origin.x << ", " << upRect.origin.y << ", " << upRect.size.width << ", " << upRect.size.height << "}");
555 [m_pUserPane setFrame:upRect];
559 DBG_PRINT_EXIT(CLASS_NAME, __func__);
562 #pragma mark Private / Misc
566 void ControlHelper::createControls()
568 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
570 CResourceProvider aResProvider;
571 for (int i = 0; i < LIST_LAST; i++) {
572 if (m_bListVisibility[i]) {
573 m_bUserPaneNeeded = true;
575 int elementName = getControlElementName([NSPopUpButton class], i);
576 NSString* sLabel = aResProvider.getResString(elementName);
578 m_pListControls[i] = [NSPopUpButton new];
580 #define MAP_LIST_( elem ) \
582 setLabel(ExtendedFilePickerElementIds::LISTBOX_##elem, sLabel); \
588 MAP_LIST_(IMAGE_TEMPLATE);
591 m_aActiveControls.push_back(m_pListControls[i]);
593 m_pListControls[i] = nil;
597 for (int i = 0/*#i102102*/; i < TOGGLE_LAST; i++) {
598 if (m_bToggleVisibility[i]) {
599 m_bUserPaneNeeded = true;
601 int elementName = getControlElementName([NSButton class], i);
602 NSString* sLabel = aResProvider.getResString(elementName);
604 NSButton *button = [NSButton new];
605 [button setTitle:sLabel];
607 [button setButtonType:NSSwitchButton];
609 [button setState:NSOffState];
611 if (i == AUTOEXTENSION) {
612 [button setTarget:m_pDelegate];
613 [button setAction:@selector(autoextensionChanged:)];
616 m_pToggles[i] = button;
618 m_aActiveControls.push_back(m_pToggles[i]);
624 //preview is always on with Mac OS X
625 NSControl *pPreviewBox = m_pToggles[PREVIEW];
626 if (pPreviewBox != nil) {
627 [pPreviewBox setEnabled:NO];
628 [(NSButton*)pPreviewBox setState:NSOnState];
631 DBG_PRINT_EXIT(CLASS_NAME, __func__);
634 #define TOGGLE_ELEMENT( elem ) \
636 nReturn = CHECKBOX_##elem; \
637 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn); \
639 #define LIST_ELEMENT( elem ) \
641 nReturn = LISTBOX_##elem##_LABEL; \
642 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn); \
645 int ControlHelper::getControlElementName(const Class aClazz, const int nControlId)
647 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aClazz", [[aClazz description] UTF8String], "controlId", nControlId);
650 if (aClazz == [NSButton class])
652 switch (nControlId) {
653 TOGGLE_ELEMENT( AUTOEXTENSION );
654 TOGGLE_ELEMENT( PASSWORD );
655 TOGGLE_ELEMENT( FILTEROPTIONS );
656 TOGGLE_ELEMENT( READONLY );
657 TOGGLE_ELEMENT( LINK );
658 TOGGLE_ELEMENT( PREVIEW );
659 TOGGLE_ELEMENT( SELECTION );
662 else if (aClazz == [NSPopUpButton class])
664 switch (nControlId) {
665 LIST_ELEMENT( VERSION );
666 LIST_ELEMENT( TEMPLATE );
667 LIST_ELEMENT( IMAGE_TEMPLATE );
671 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn);
676 void ControlHelper::HandleSetListValue(const NSControl* pControl, const sal_Int16 nControlAction, const uno::Any& rValue)
678 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlAction", nControlAction);
680 if ([pControl class] != [NSPopUpButton class]) {
681 SAL_INFO("fpicker.aqua","not a popup menu");
682 DBG_PRINT_EXIT(CLASS_NAME, __func__);
686 NSPopUpButton *pButton = (NSPopUpButton*)pControl;
687 NSMenu *rMenu = [pButton menu];
689 SAL_INFO("fpicker.aqua","button has no menu");
690 DBG_PRINT_EXIT(CLASS_NAME, __func__);
694 switch (nControlAction)
696 case ControlActions::ADD_ITEM:
698 SAL_INFO("fpicker.aqua","ADD_ITEMS");
702 NSString* sCFItem = [NSString stringWithOUString:sItem];
703 SAL_INFO("fpicker.aqua","Adding menu item: " << OUStringToOString(sItem, RTL_TEXTENCODING_UTF8).getStr());
704 [pButton addItemWithTitle:sCFItem];
707 case ControlActions::ADD_ITEMS:
709 SAL_INFO("fpicker.aqua","ADD_ITEMS");
710 uno::Sequence< OUString > aStringList;
711 rValue >>= aStringList;
712 sal_Int32 nItemCount = aStringList.getLength();
713 for (sal_Int32 i = 0; i < nItemCount; ++i)
715 NSString* sCFItem = [NSString stringWithOUString:aStringList[i]];
716 SAL_INFO("fpicker.aqua","Adding menu item: " << OUStringToOString(aStringList[i], RTL_TEXTENCODING_UTF8).getStr());
717 [pButton addItemWithTitle:sCFItem];
721 case ControlActions::DELETE_ITEM:
723 SAL_INFO("fpicker.aqua","DELETE_ITEM");
726 SAL_INFO("fpicker.aqua","Deleting item at position " << (nPos));
727 [rMenu removeItemAtIndex:nPos];
730 case ControlActions::DELETE_ITEMS:
732 SAL_INFO("fpicker.aqua","DELETE_ITEMS");
733 int nItems = [rMenu numberOfItems];
735 SAL_INFO("fpicker.aqua","no menu items to delete");
736 DBG_PRINT_EXIT(CLASS_NAME, __func__);
739 for(sal_Int32 i = 0; i < nItems; i++) {
740 [rMenu removeItemAtIndex:i];
744 case ControlActions::SET_SELECT_ITEM:
748 SAL_INFO("fpicker.aqua","Selecting item at position " << nPos);
749 [pButton selectItemAtIndex:nPos];
753 SAL_INFO("fpicker.aqua","undocumented/unimplemented ControlAction for a list");
759 DBG_PRINT_EXIT(CLASS_NAME, __func__);
762 // cf. offapi/com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.idl
763 NSControl* ControlHelper::getControl( const sal_Int16 nControlId ) const
765 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId);
767 NSControl* pWidget = nil;
769 #define MAP_TOGGLE( elem ) \
770 case ExtendedFilePickerElementIds::CHECKBOX_##elem: \
771 pWidget = m_pToggles[elem]; \
774 #define MAP_LIST( elem ) \
775 case ExtendedFilePickerElementIds::LISTBOX_##elem: \
776 pWidget = m_pListControls[elem]; \
779 #define MAP_LIST_LABEL( elem ) \
780 case ExtendedFilePickerElementIds::LISTBOX_##elem##_LABEL: \
781 pWidget = m_pListControls[elem]; \
786 MAP_TOGGLE( AUTOEXTENSION );
787 MAP_TOGGLE( PASSWORD );
788 MAP_TOGGLE( FILTEROPTIONS );
789 MAP_TOGGLE( READONLY );
791 MAP_TOGGLE( PREVIEW );
792 MAP_TOGGLE( SELECTION );
793 //MAP_BUTTON( PLAY );
795 MAP_LIST( TEMPLATE );
796 MAP_LIST( IMAGE_TEMPLATE );
797 MAP_LIST_LABEL( VERSION );
798 MAP_LIST_LABEL( TEMPLATE );
799 MAP_LIST_LABEL( IMAGE_TEMPLATE );
801 SAL_INFO("fpicker.aqua","Handle unknown control " << nControlId);
806 DBG_PRINT_EXIT(CLASS_NAME, __func__);
811 void ControlHelper::layoutControls()
813 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
815 SolarMutexGuard aGuard;
817 if (nil == m_pUserPane) {
818 SAL_INFO("fpicker.aqua","no user pane to layout");
819 DBG_PRINT_EXIT(CLASS_NAME, __func__);
823 if (m_bIsUserPaneLaidOut) {
824 SAL_INFO("fpicker.aqua","user pane already laid out");
825 DBG_PRINT_EXIT(CLASS_NAME, __func__);
829 NSRect userPaneRect = [m_pUserPane frame];
830 SAL_INFO("fpicker.aqua","userPane frame: {" << userPaneRect.origin.x << ", " << userPaneRect.origin.y << ", " << userPaneRect.size.width << ", " << userPaneRect.size.height << "}");
832 int nUsableWidth = userPaneRect.size.width;
834 //NOTE: NSView's coordinate system starts in the lower left hand corner but we start adding controls from the top,
835 // so we subtract from the vertical position as we make our way down the pane.
836 int currenttop = userPaneRect.size.height;
837 int nCheckboxMaxWidth = 0;
838 int nPopupMaxWidth = 0;
839 int nPopupLabelMaxWidth = 0;
841 //first loop to determine max sizes
842 for (::std::list<NSControl*>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) {
843 NSControl* pControl = *child;
845 NSRect controlRect = [pControl frame];
846 int nControlWidth = controlRect.size.width;
848 Class aSubType = [pControl class];
849 if (aSubType == [NSPopUpButton class]) {
850 if (nPopupMaxWidth < nControlWidth) {
851 nPopupMaxWidth = nControlWidth;
853 NSTextField *label = m_aMapListLabelFields[(NSPopUpButton*)pControl];
854 NSRect labelFrame = [label frame];
855 int nLabelWidth = labelFrame.size.width;
856 if (nPopupLabelMaxWidth < nLabelWidth) {
857 nPopupLabelMaxWidth = nLabelWidth;
860 if (nCheckboxMaxWidth < nControlWidth) {
861 nCheckboxMaxWidth = nControlWidth;
866 int nLongestPopupWidth = nPopupMaxWidth + nPopupLabelMaxWidth + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
867 SAL_INFO("fpicker.aqua","longest popup width: " << nLongestPopupWidth);
869 NSControl* previousControl = nil;
871 int nDistBetweenControls = 0;
873 for (::std::list<NSControl*>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) {
874 NSControl* pControl = *child;
876 //get the control's bounds
877 NSRect controlRect = [pControl frame];
878 int nControlHeight = controlRect.size.height;
879 int nControlWidth = controlRect.size.width;
881 //subtract the height from the current vertical position, because the control's bounds origin rect will be its lower left hand corner
882 currenttop -= nControlHeight;
884 Class aSubType = [pControl class];
886 //add space between the previous control and this control according to Apple's HIG
887 nDistBetweenControls = getVerticalDistance(previousControl, pControl);
888 SAL_INFO("fpicker.aqua","vertical distance: " << nDistBetweenControls);
889 currenttop -= nDistBetweenControls;
891 previousControl = pControl;
893 if (aSubType == [NSPopUpButton class]) {
894 //move vertically up some pixels to space the controls between their real (visual) bounds
895 currenttop += kAquaSpacePopupMenuFrameBoundsDiffTop;//from top
897 //get the corresponding popup label
898 NSTextField *label = m_aMapListLabelFields[(NSPopUpButton*)pControl];
899 NSRect labelFrame = [label frame];
900 int totalWidth = nPopupMaxWidth + labelFrame.size.width + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
901 SAL_INFO("fpicker.aqua","totalWidth: " << totalWidth);
902 //let's center popups
903 int left = (nUsableWidth + nLongestPopupWidth) / 2 - totalWidth;
904 SAL_INFO("fpicker.aqua","left: " << left);
905 labelFrame.origin.x = left;
906 labelFrame.origin.y = currenttop + kAquaSpaceLabelPopupDiffV;
907 SAL_INFO("fpicker.aqua","setting label at: {" << labelFrame.origin.x << ", " << labelFrame.origin.y << ", " << labelFrame.size.width << ", " << labelFrame.size.height << "}");
908 [label setFrame:labelFrame];
910 controlRect.origin.x = left + labelFrame.size.width + kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft;
911 controlRect.origin.y = currenttop;
912 controlRect.size.width = nPopupMaxWidth;
913 SAL_INFO("fpicker.aqua","setting popup at: {" << controlRect.origin.x << ", " << controlRect.origin.y << ", " << controlRect.size.width << ", " << controlRect.size.height << "}");
914 [pControl setFrame:controlRect];
916 //add some space to place the vertical position right below the popup's visual bounds
917 currenttop += kAquaSpacePopupMenuFrameBoundsDiffBottom;
919 currenttop += kAquaSpaceSwitchButtonFrameBoundsDiff;//from top
921 nControlWidth = nCheckboxMaxWidth;
922 int left = (nUsableWidth - nCheckboxMaxWidth) / 2;
923 controlRect.origin.x = left;
924 controlRect.origin.y = currenttop;
925 controlRect.size.width = nPopupMaxWidth;
926 [pControl setFrame:controlRect];
927 SAL_INFO("fpicker.aqua","setting checkbox at: {" << controlRect.origin.x << ", " << controlRect.origin.y << ", " << controlRect.size.width << ", " << controlRect.size.height << "}");
929 currenttop += kAquaSpaceSwitchButtonFrameBoundsDiff;
933 m_bIsUserPaneLaidOut = true;
935 DBG_PRINT_EXIT(CLASS_NAME, __func__);
938 void ControlHelper::createFilterControl() {
939 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
941 CResourceProvider aResProvider;
942 NSString* sLabel = aResProvider.getResString(CommonFilePickerElementIds::LISTBOX_FILTER_LABEL);
944 m_pFilterControl = [NSPopUpButton new];
946 [m_pFilterControl setAction:@selector(filterSelectedAtIndex:)];
947 [m_pFilterControl setTarget:m_pDelegate];
949 NSMenu *menu = [m_pFilterControl menu];
951 for (NSStringList::iterator iter = m_pFilterHelper->getFilterNames()->begin(); iter != m_pFilterHelper->getFilterNames()->end(); iter++) {
952 NSString *filterName = *iter;
953 SAL_INFO("fpicker.aqua","adding filter name: " << [filterName UTF8String]);
954 if ([filterName isEqualToString:@"-"]) {
955 [menu addItem:[NSMenuItem separatorItem]];
958 [m_pFilterControl addItemWithTitle:filterName];
962 // always add the filter as first item
963 m_aActiveControls.push_front(m_pFilterControl);
964 m_aMapListLabels[m_pFilterControl] = [sLabel retain];
966 DBG_PRINT_EXIT(CLASS_NAME, __func__);
969 int ControlHelper::getVerticalDistance(const NSControl* first, const NSControl* second)
972 return kAquaSpaceBoxFrameViewDiffTop;
974 else if (second == nil) {
975 return kAquaSpaceBoxFrameViewDiffBottom;
978 Class firstClass = [first class];
979 Class secondClass = [second class];
981 if (firstClass == [NSPopUpButton class]) {
982 if (secondClass == [NSPopUpButton class]) {
983 return kAquaSpaceBetweenPopupMenus;
986 return kAquaSpaceAfterPopupButtonsV;
990 return kAquaSpaceBetweenControls;
994 void ControlHelper::updateFilterUI()
996 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
998 if (!m_bIsFilterControlNeeded || m_pFilterHelper == NULL) {
999 SAL_INFO("fpicker.aqua","no filter control needed or no filter helper present");
1000 DBG_PRINT_EXIT(CLASS_NAME, __func__);
1004 int index = m_pFilterHelper->getCurrentFilterIndex();
1006 if (m_pFilterControl == nil) {
1007 createFilterControl();
1010 [m_pFilterControl selectItemAtIndex:index];
1012 DBG_PRINT_EXIT(CLASS_NAME, __func__);
1015 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */