1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
25 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
26 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
27 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
28 #include <vos/mutex.hxx>
29 #include <vcl/svapp.hxx>
30 #include "CFStringUtilities.hxx"
31 #include "resourceprovider.hxx"
32 #include "NSString_OOoAdditions.hxx"
33
34 #include "ControlHelper.hxx"
35
36 #pragma mark DEFINES
37 #define CLASS_NAME "ControlHelper"
38 #define POPUP_WIDTH_MIN 200
39 #define POPUP_WIDTH_MAX 350
40
41 using namespace ::com::sun::star::ui::dialogs;
42 using namespace ::com::sun::star::ui::dialogs::TemplateDescription;
43 using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds;
44 using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds;
45 using namespace ::rtl;
46
47 #pragma mark Constructor / Destructor
48 //------------------------------------------------------------------------------------
49 // Constructor / Destructor
50 //------------------------------------------------------------------------------------
ControlHelper()51 ControlHelper::ControlHelper()
52 : m_pUserPane(NULL)
53 , m_pFilterControl(nil)
54 , m_bUserPaneNeeded( false )
55 , m_bIsUserPaneLaidOut(false)
56 , m_bIsFilterControlNeeded(false)
57 , m_pFilterHelper(NULL)
58 {
59 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
60
61 int i;
62
63 for( i = 0; i < TOGGLE_LAST; i++ ) {
64 m_bToggleVisibility[i] = false;
65 }
66
67 for( i = 0; i < LIST_LAST; i++ ) {
68 m_bListVisibility[i] = false;
69 }
70
71 DBG_PRINT_EXIT(CLASS_NAME, __func__);
72 }
73
~ControlHelper()74 ControlHelper::~ControlHelper()
75 {
76 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
77
78 NSAutoreleasePool *pool = [NSAutoreleasePool new];
79
80 if (NULL != m_pUserPane) {
81 [m_pUserPane release];
82 }
83
84 for(std::list<NSControl *>::iterator control = m_aActiveControls.begin(); control != m_aActiveControls.end(); control++) {
85 NSControl* pControl = (*control);
86 NSString* sLabelName = m_aMapListLabels[pControl];
87 if (sLabelName != nil) {
88 [sLabelName release];
89 }
90 if ([pControl class] == [NSPopUpButton class]) {
91 NSTextField* pField = m_aMapListLabelFields[(NSPopUpButton*)pControl];
92 if (pField != nil) {
93 [pField release];
94 }
95 }
96 [pControl release];
97 }
98
99 if (m_pFilterControl != NULL) {
100 [m_pFilterControl setTarget:nil];
101 }
102
103 [pool release];
104
105 DBG_PRINT_EXIT(CLASS_NAME, __func__);
106 }
107
108 #pragma mark XInitialization delegate
109 //------------------------------------------------
110 // XInitialization delegate
111 //------------------------------------------------
initialize(sal_Int16 nTemplateId)112 void ControlHelper::initialize( sal_Int16 nTemplateId )
113 {
114 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "templateId", nTemplateId);
115
116 switch( nTemplateId )
117 {
118 case FILESAVE_AUTOEXTENSION_PASSWORD:
119 m_bToggleVisibility[AUTOEXTENSION] = true;
120 m_bToggleVisibility[PASSWORD] = true;
121 break;
122 case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
123 m_bToggleVisibility[AUTOEXTENSION] = true;
124 m_bToggleVisibility[PASSWORD] = true;
125 m_bToggleVisibility[FILTEROPTIONS] = true;
126 break;
127 case FILESAVE_AUTOEXTENSION_SELECTION:
128 m_bToggleVisibility[AUTOEXTENSION] = true;
129 m_bToggleVisibility[SELECTION] = true;
130 break;
131 case FILESAVE_AUTOEXTENSION_TEMPLATE:
132 m_bToggleVisibility[AUTOEXTENSION] = true;
133 m_bListVisibility[TEMPLATE] = true;
134 break;
135 case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
136 m_bToggleVisibility[LINK] = true;
137 m_bToggleVisibility[PREVIEW] = true;
138 m_bListVisibility[IMAGE_TEMPLATE] = true;
139 break;
140 case FILEOPEN_READONLY_VERSION:
141 m_bToggleVisibility[READONLY] = true;
142 m_bListVisibility[VERSION] = true;
143 break;
144 case FILEOPEN_LINK_PREVIEW:
145 m_bToggleVisibility[LINK] = true;
146 m_bToggleVisibility[PREVIEW] = true;
147 break;
148 case FILESAVE_AUTOEXTENSION:
149 m_bToggleVisibility[AUTOEXTENSION] = true;
150 break;
151 }
152
153 createControls();
154
155 DBG_PRINT_EXIT(CLASS_NAME, __func__);
156 }
157
158 #pragma mark XFilePickerControlAccess delegates
159 //------------------------------------------------------------------------------------
160 // XFilePickerControlAccess functions
161 //------------------------------------------------------------------------------------
162
enableControl(const sal_Int16 nControlId,const sal_Bool bEnable) const163 void ControlHelper::enableControl( const sal_Int16 nControlId, const sal_Bool bEnable ) const
164 {
165 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "enable", bEnable);
166
167 ::vos::OGuard aGuard( Application::GetSolarMutex() );
168
169 if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_PREVIEW) {
170 OSL_TRACE(" preview checkbox cannot be changed");
171 DBG_PRINT_EXIT(CLASS_NAME, __func__);
172 return;
173 }
174
175 NSControl* pControl = getControl(nControlId);
176
177 if( pControl != nil ) {
178 if( bEnable ) {
179 OSL_TRACE( "enable" );
180 } else {
181 OSL_TRACE( "disable" );
182 }
183 [pControl setEnabled:bEnable];
184 } else {
185 OSL_TRACE("enable unknown control %d", nControlId );
186 }
187
188 DBG_PRINT_EXIT(CLASS_NAME, __func__);
189 }
190
getLabel(sal_Int16 nControlId)191 OUString ControlHelper::getLabel( sal_Int16 nControlId )
192 {
193 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId);
194
195 ::vos::OGuard aGuard( Application::GetSolarMutex() );
196
197 NSControl* pControl = getControl( nControlId );
198
199 if( pControl == nil ) {
200 OSL_TRACE("Get label for unknown control %d", nControlId);
201 return OUString();
202 }
203
204 rtl::OUString retVal;
205 if ([pControl class] == [NSPopUpButton class]) {
206 NSString *temp = m_aMapListLabels[pControl];
207 if (temp != nil)
208 retVal = [temp OUString];
209 }
210 else {
211 NSString* sLabel = [[pControl cell] title];
212 retVal = [sLabel OUString];
213 }
214
215 DBG_PRINT_EXIT(CLASS_NAME, __func__, retVal);
216
217 return retVal;
218 }
219
setLabel(sal_Int16 nControlId,NSString * aLabel)220 void ControlHelper::setLabel( sal_Int16 nControlId, NSString* aLabel )
221 {
222 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "label", aLabel);
223
224 ::vos::OGuard aGuard( Application::GetSolarMutex() );
225
226 NSAutoreleasePool *pool = [NSAutoreleasePool new];
227
228 NSControl* pControl = getControl(nControlId);
229
230 if (nil != pControl) {
231 if ([pControl class] == [NSPopUpButton class]) {
232 NSString *sOldName = m_aMapListLabels[pControl];
233 if (sOldName != NULL && sOldName != aLabel) {
234 [sOldName release];
235 }
236
237 m_aMapListLabels[pControl] = [aLabel retain];
238 } else if ([pControl class] == [NSButton class]) {
239 [[pControl cell] setTitle:aLabel];
240 }
241 } else {
242 OSL_TRACE("Control not found to set label for");
243 }
244
245 layoutControls();
246
247 [pool release];
248
249 DBG_PRINT_EXIT(CLASS_NAME, __func__);
250 }
251
setValue(sal_Int16 nControlId,sal_Int16 nControlAction,const uno::Any & rValue)252 void ControlHelper::setValue( sal_Int16 nControlId, sal_Int16 nControlAction, const uno::Any& rValue )
253 {
254 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "controlAction", nControlAction);
255
256 ::vos::OGuard aGuard( Application::GetSolarMutex() );
257
258 if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_PREVIEW) {
259 OSL_TRACE(" value for preview is unchangeable");
260 }
261 else {
262 NSControl* pControl = getControl( nControlId );
263
264 if( pControl == nil ) {
265 OSL_TRACE("enable unknown control %d", nControlId);
266 } else {
267 if( [pControl class] == [NSPopUpButton class] ) {
268 HandleSetListValue(pControl, nControlAction, rValue);
269 } else if( [pControl class] == [NSButton class] ) {
270 sal_Bool bChecked = false;
271 rValue >>= bChecked;
272 OSL_TRACE(" value is a bool: %d", bChecked);
273 [(NSButton*)pControl setState:(bChecked ? NSOnState : NSOffState)];
274 } else
275 {
276 OSL_TRACE("Can't set value on button / list %d %d",
277 nControlId, nControlAction);
278 }
279 }
280 }
281
282 DBG_PRINT_EXIT(CLASS_NAME, __func__);
283 }
284
getValue(sal_Int16 nControlId,sal_Int16 nControlAction) const285 uno::Any ControlHelper::getValue( sal_Int16 nControlId, sal_Int16 nControlAction ) const
286 {
287 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId, "controlAction", nControlAction);
288
289 ::vos::OGuard aGuard( Application::GetSolarMutex() );
290 uno::Any aRetval;
291
292 NSControl* pControl = getControl( nControlId );
293
294 if( pControl == nil ) {
295 OSL_TRACE("get value for unknown control %d", nControlId);
296 aRetval <<= sal_True;
297 } else {
298 if( [pControl class] == [NSPopUpButton class] ) {
299 aRetval = HandleGetListValue(pControl, nControlAction);
300 } else if( [pControl class] == [NSButton class] ) {
301 //NSLog(@"control: %@", [[pControl cell] title]);
302 sal_Bool bValue = [(NSButton*)pControl state] == NSOnState ? sal_True : sal_False;
303 aRetval <<= bValue;
304 OSL_TRACE("value is a bool (checkbox): %d", bValue);
305 }
306 }
307
308 DBG_PRINT_EXIT(CLASS_NAME, __func__);
309
310 return aRetval;
311 }
312
createUserPane()313 void ControlHelper::createUserPane()
314 {
315 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
316
317 if (m_bUserPaneNeeded == false) {
318 OSL_TRACE("no user pane needed");
319 DBG_PRINT_EXIT(CLASS_NAME, __func__);
320 return;
321 }
322
323 if (nil != m_pUserPane) {
324 OSL_TRACE("user pane already exists");
325 DBG_PRINT_EXIT(CLASS_NAME, __func__);
326 return;
327 }
328
329 if (m_bIsFilterControlNeeded == true && m_pFilterControl == nil) {
330 createFilterControl();
331 }
332
333 NSRect minRect = NSMakeRect(0,0,300,33);
334 m_pUserPane = [[NSView alloc] initWithFrame:minRect];
335
336 int currentHeight = kAquaSpaceBoxFrameViewDiffTop + kAquaSpaceBoxFrameViewDiffBottom;
337 int currentWidth = 300;
338
339 sal_Bool bPopupControlPresent = NO;
340 sal_Bool bButtonControlPresent = NO;
341
342 int nCheckboxMaxWidth = 0;
343 int nPopupMaxWidth = 0;
344 int nPopupLabelMaxWidth = 0;
345
346 for (::std::list<NSControl*>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) {
347 OSL_TRACE("currentHeight: %d", currentHeight);
348
349 NSControl* pControl = *child;
350
351 //let the control calculate its size
352 [pControl sizeToFit];
353
354 NSRect frame = [pControl frame];
355 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);
356
357 int nControlHeight = frame.size.height;
358 int nControlWidth = frame.size.width;
359
360 // Note: controls are grouped by kind, first all popup menus, then checkboxes
361 if ([pControl class] == [NSPopUpButton class]) {
362 if (bPopupControlPresent == YES) {
363 //this is not the first popup
364 currentHeight += kAquaSpaceBetweenPopupMenus;
365 }
366 else if (child != m_aActiveControls.begin()){
367 currentHeight += kAquaSpaceBetweenControls;
368 }
369
370 bPopupControlPresent = YES;
371
372 // we have to add the label text width
373 NSString *label = m_aMapListLabels[pControl];
374
375 NSTextField *textField = createLabelWithString(label);
376 [textField sizeToFit];
377 m_aMapListLabelFields[(NSPopUpButton*)pControl] = textField;
378 [m_pUserPane addSubview:textField];
379
380 NSRect tfRect = [textField frame];
381 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);
382
383 int tfWidth = tfRect.size.width;
384
385 if (nPopupLabelMaxWidth < tfWidth) {
386 nPopupLabelMaxWidth = tfWidth;
387 }
388
389 frame.origin.x += (kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft) + tfWidth;
390
391 if (nControlWidth < POPUP_WIDTH_MIN) {
392 nControlWidth = POPUP_WIDTH_MIN;
393 frame.size.width = nControlWidth;
394 [pControl setFrame:frame];
395 }
396
397 if (nControlWidth > POPUP_WIDTH_MAX) {
398 nControlWidth = POPUP_WIDTH_MAX;
399 frame.size.width = nControlWidth;
400 [pControl setFrame:frame];
401 }
402
403 //set the max size
404 if (nPopupMaxWidth < nControlWidth) {
405 nPopupMaxWidth = nControlWidth;
406 }
407
408 nControlWidth += tfWidth + kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft;
409 if (nControlHeight < kAquaPopupButtonDefaultHeight) {
410 //maybe the popup has no menu item yet, so set a default height
411 nControlHeight = kAquaPopupButtonDefaultHeight;
412 }
413
414 nControlHeight -= kAquaSpacePopupMenuFrameBoundsDiffV;
415 }
416 else if ([pControl class] == [NSButton class]) {
417 if (child != m_aActiveControls.begin()){
418 currentHeight += kAquaSpaceBetweenControls;
419 }
420
421 if (nCheckboxMaxWidth < nControlWidth) {
422 nCheckboxMaxWidth = nControlWidth;
423 }
424
425 bButtonControlPresent = YES;
426 nControlWidth -= 2 * kAquaSpaceSwitchButtonFrameBoundsDiff;
427 nControlHeight -= 2 * kAquaSpaceSwitchButtonFrameBoundsDiff;
428 }
429
430 // if ((nControlWidth + 2 * kAquaSpaceInsideGroupH) > currentWidth) {
431 // currentWidth = nControlWidth + 2 * kAquaSpaceInsideGroupH;
432 // }
433
434 currentHeight += nControlHeight;
435
436 [m_pUserPane addSubview:pControl];
437 }
438
439 OSL_TRACE("height after adding all controls: %d", currentHeight);
440
441 if (bPopupControlPresent && bButtonControlPresent)
442 {
443 //after a popup button (array) and before a different kind of control we need some extra space instead of the standard
444 currentHeight -= kAquaSpaceBetweenControls;
445 currentHeight += kAquaSpaceAfterPopupButtonsV;
446 OSL_TRACE("popup extra space added, currentHeight: %d", currentHeight);
447 }
448
449 int nLongestPopupWidth = nPopupMaxWidth + nPopupLabelMaxWidth + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
450
451 currentWidth = nLongestPopupWidth > nCheckboxMaxWidth ? nLongestPopupWidth : nCheckboxMaxWidth;
452 OSL_TRACE("longest control width: %d", currentWidth);
453
454 currentWidth += 2* kAquaSpaceInsideGroupH;
455
456 if (currentWidth < minRect.size.width)
457 currentWidth = minRect.size.width;
458
459 if (currentHeight < minRect.size.height)
460 currentHeight = minRect.size.height;
461
462 NSRect upRect = NSMakeRect(0, 0, currentWidth, currentHeight );
463 OSL_TRACE("setting user pane rect to {%f, %f, %f, %f}",upRect.origin.x, upRect.origin.y, upRect.size.width, upRect.size.height);
464
465 [m_pUserPane setFrame:upRect];
466
467 layoutControls();
468
469 DBG_PRINT_EXIT(CLASS_NAME, __func__);
470 }
471
472 #pragma mark Private / Misc
473 //------------------------------------------------------------------------------------
474 // Private / Misc
475 //------------------------------------------------------------------------------------
createControls()476 void ControlHelper::createControls()
477 {
478 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
479
480 CResourceProvider aResProvider;
481 for (int i = 0; i < LIST_LAST; i++) {
482 if (true == m_bListVisibility[i]) {
483 m_bUserPaneNeeded = true;
484
485 int elementName = getControlElementName([NSPopUpButton class], i);
486 NSString* sLabel = aResProvider.getResString(elementName);
487
488 m_pListControls[i] = [NSPopUpButton new];
489
490 #define MAP_LIST_( elem ) \
491 case elem: \
492 setLabel(ExtendedFilePickerElementIds::LISTBOX_##elem, sLabel); \
493 break
494
495 switch(i) {
496 MAP_LIST_(VERSION);
497 MAP_LIST_(TEMPLATE);
498 MAP_LIST_(IMAGE_TEMPLATE);
499 }
500
501 m_aActiveControls.push_back(m_pListControls[i]);
502 } else {
503 m_pListControls[i] = nil;
504 }
505 }
506
507 for (int i = 0/*#i102102*/; i < TOGGLE_LAST; i++) {
508 if (true == m_bToggleVisibility[i]) {
509 m_bUserPaneNeeded = true;
510
511 int elementName = getControlElementName([NSButton class], i);
512 NSString* sLabel = aResProvider.getResString(elementName);
513
514 NSButton *button = [NSButton new];
515 [button setTitle:sLabel];
516
517 [button setButtonType:NSSwitchButton];
518
519 [button setState:NSOffState];
520
521 if (i == AUTOEXTENSION) {
522 [button setTarget:m_pDelegate];
523 [button setAction:@selector(autoextensionChanged:)];
524 }
525
526 m_pToggles[i] = button;
527
528 m_aActiveControls.push_back(m_pToggles[i]);
529 } else {
530 m_pToggles[i] = nil;
531 }
532 }
533
534 //preview is always on with Mac OS X
535 NSControl *pPreviewBox = m_pToggles[PREVIEW];
536 if (pPreviewBox != nil) {
537 [pPreviewBox setEnabled:NO];
538 [(NSButton*)pPreviewBox setState:NSOnState];
539 }
540
541 DBG_PRINT_EXIT(CLASS_NAME, __func__);
542 }
543
544 #define TOGGLE_ELEMENT( elem ) \
545 case elem: \
546 nReturn = CHECKBOX_##elem; \
547 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn); \
548 return nReturn
549 #define LIST_ELEMENT( elem ) \
550 case elem: \
551 nReturn = LISTBOX_##elem##_LABEL; \
552 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn); \
553 return nReturn
554
getControlElementName(const Class aClazz,const int nControlId) const555 int ControlHelper::getControlElementName(const Class aClazz, const int nControlId) const
556 {
557 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "aClazz", [[aClazz description] UTF8String], "controlId", nControlId);
558
559 int nReturn = -1;
560 if (aClazz == [NSButton class])
561 {
562 switch (nControlId) {
563 TOGGLE_ELEMENT( AUTOEXTENSION );
564 TOGGLE_ELEMENT( PASSWORD );
565 TOGGLE_ELEMENT( FILTEROPTIONS );
566 TOGGLE_ELEMENT( READONLY );
567 TOGGLE_ELEMENT( LINK );
568 TOGGLE_ELEMENT( PREVIEW );
569 TOGGLE_ELEMENT( SELECTION );
570 }
571 }
572 else if (aClazz == [NSPopUpButton class])
573 {
574 switch (nControlId) {
575 LIST_ELEMENT( VERSION );
576 LIST_ELEMENT( TEMPLATE );
577 LIST_ELEMENT( IMAGE_TEMPLATE );
578 }
579 }
580
581 DBG_PRINT_EXIT(CLASS_NAME, __func__, nReturn);
582
583 return nReturn;
584 }
585
HandleSetListValue(const NSControl * pControl,const sal_Int16 nControlAction,const uno::Any & rValue)586 void ControlHelper::HandleSetListValue(const NSControl* pControl, const sal_Int16 nControlAction, const uno::Any& rValue)
587 {
588 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlAction", nControlAction);
589
590 if ([pControl class] != [NSPopUpButton class]) {
591 OSL_TRACE("not a popup menu");
592 DBG_PRINT_EXIT(CLASS_NAME, __func__);
593 return;
594 }
595
596 NSPopUpButton *pButton = (NSPopUpButton*)pControl;
597 NSMenu *rMenu = [pButton menu];
598 if (nil == rMenu) {
599 OSL_TRACE("button has no menu");
600 DBG_PRINT_EXIT(CLASS_NAME, __func__);
601 return;
602 }
603
604 switch (nControlAction)
605 {
606 case ControlActions::ADD_ITEM:
607 {
608 OSL_TRACE("ADD_ITEMS");
609 OUString sItem;
610 rValue >>= sItem;
611
612 NSString* sCFItem = [NSString stringWithOUString:sItem];
613 OSL_TRACE("Adding menu item: %s", OUStringToOString(sItem, RTL_TEXTENCODING_UTF8).getStr());
614 [pButton addItemWithTitle:sCFItem];
615 }
616 break;
617 case ControlActions::ADD_ITEMS:
618 {
619 OSL_TRACE("ADD_ITEMS");
620 uno::Sequence< OUString > aStringList;
621 rValue >>= aStringList;
622 sal_Int32 nItemCount = aStringList.getLength();
623 for (sal_Int32 i = 0; i < nItemCount; ++i)
624 {
625 NSString* sCFItem = [NSString stringWithOUString:aStringList[i]];
626 OSL_TRACE("Adding menu item: %s", OUStringToOString(aStringList[i], RTL_TEXTENCODING_UTF8).getStr());
627 [pButton addItemWithTitle:sCFItem];
628 }
629 }
630 break;
631 case ControlActions::DELETE_ITEM:
632 {
633 OSL_TRACE("DELETE_ITEM");
634 sal_Int32 nPos = -1;
635 rValue >>= nPos;
636 OSL_TRACE("Deleting item at position %d", (nPos));
637 [rMenu removeItemAtIndex:nPos];
638 }
639 break;
640 case ControlActions::DELETE_ITEMS:
641 {
642 OSL_TRACE("DELETE_ITEMS");
643 int nItems = [rMenu numberOfItems];
644 if (nItems == 0) {
645 OSL_TRACE("no menu items to delete");
646 DBG_PRINT_EXIT(CLASS_NAME, __func__);
647 return;
648 }
649 for(sal_Int32 i = 0; i < nItems; i++) {
650 [rMenu removeItemAtIndex:i];
651 }
652 }
653 break;
654 case ControlActions::SET_SELECT_ITEM:
655 {
656 sal_Int32 nPos = -1;
657 rValue >>= nPos;
658 OSL_TRACE("Selecting item at position %d", nPos);
659 [pButton selectItemAtIndex:nPos];
660 }
661 break;
662 default:
663 OSL_TRACE("undocumented/unimplemented ControlAction for a list");
664 break;
665 }
666
667 layoutControls();
668
669 DBG_PRINT_EXIT(CLASS_NAME, __func__);
670 }
671
672
HandleGetListValue(const NSControl * pControl,const sal_Int16 nControlAction) const673 uno::Any ControlHelper::HandleGetListValue(const NSControl* pControl, const sal_Int16 nControlAction) const
674 {
675 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlAction", nControlAction);
676
677 uno::Any aAny;
678
679 if ([pControl class] != [NSPopUpButton class]) {
680 OSL_TRACE("not a popup button");
681 DBG_PRINT_EXIT(CLASS_NAME, __func__);
682 return aAny;
683 }
684
685 NSPopUpButton *pButton = (NSPopUpButton*)pControl;
686 NSMenu *rMenu = [pButton menu];
687 if (nil == rMenu) {
688 OSL_TRACE("button has no menu");
689 DBG_PRINT_EXIT(CLASS_NAME, __func__);
690 return aAny;
691 }
692
693 switch (nControlAction)
694 {
695 case ControlActions::GET_ITEMS:
696 {
697 OSL_TRACE("GET_ITEMS");
698 uno::Sequence< OUString > aItemList;
699
700 int nItems = [rMenu numberOfItems];
701 if (nItems > 0) {
702 aItemList.realloc(nItems);
703 }
704 for (int i = 0; i < nItems; i++) {
705 NSString* sCFItem = [pButton itemTitleAtIndex:i];
706 if (nil != sCFItem) {
707 aItemList[i] = [sCFItem OUString];
708 OSL_TRACE("Return value[%d]: %s", (i - 1), OUStringToOString(aItemList[i - 1], RTL_TEXTENCODING_UTF8).getStr());
709 }
710 }
711
712 aAny <<= aItemList;
713 }
714 break;
715 case ControlActions::GET_SELECTED_ITEM:
716 {
717 OSL_TRACE("GET_SELECTED_ITEM");
718 NSString* sCFItem = [pButton titleOfSelectedItem];
719 if (nil != sCFItem) {
720 OUString sString = [sCFItem OUString];
721 OSL_TRACE("Return value: %s", OUStringToOString(sString, RTL_TEXTENCODING_UTF8).getStr());
722 aAny <<= sString;
723 }
724 }
725 break;
726 case ControlActions::GET_SELECTED_ITEM_INDEX:
727 {
728 OSL_TRACE("GET_SELECTED_ITEM_INDEX");
729 sal_Int32 nActive = [pButton indexOfSelectedItem];
730 OSL_TRACE("Return value: %d", nActive);
731 aAny <<= nActive;
732 }
733 break;
734 default:
735 OSL_TRACE("undocumented/unimplemented ControlAction for a list");
736 break;
737 }
738
739 DBG_PRINT_EXIT(CLASS_NAME, __func__);
740
741 return aAny;
742 }
743
744
745 // cf. offapi/com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.idl
getControl(const sal_Int16 nControlId) const746 NSControl* ControlHelper::getControl( const sal_Int16 nControlId ) const
747 {
748 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "controlId", nControlId);
749
750 NSControl* pWidget = nil;
751
752 #define MAP_TOGGLE( elem ) \
753 case ExtendedFilePickerElementIds::CHECKBOX_##elem: \
754 pWidget = m_pToggles[elem]; \
755 break
756
757 #define MAP_BUTTON( elem ) \
758 case ExtendedFilePickerElementIds::PUSHBUTTON_##elem: \
759 pWidget = m_pButtons[elem]; \
760 break
761
762 #define MAP_LIST( elem ) \
763 case ExtendedFilePickerElementIds::LISTBOX_##elem: \
764 pWidget = m_pListControls[elem]; \
765 break
766
767 #define MAP_LIST_LABEL( elem ) \
768 case ExtendedFilePickerElementIds::LISTBOX_##elem##_LABEL: \
769 pWidget = m_pListControls[elem]; \
770 break
771
772 switch( nControlId )
773 {
774 MAP_TOGGLE( AUTOEXTENSION );
775 MAP_TOGGLE( PASSWORD );
776 MAP_TOGGLE( FILTEROPTIONS );
777 MAP_TOGGLE( READONLY );
778 MAP_TOGGLE( LINK );
779 MAP_TOGGLE( PREVIEW );
780 MAP_TOGGLE( SELECTION );
781 //MAP_BUTTON( PLAY );
782 MAP_LIST( VERSION );
783 MAP_LIST( TEMPLATE );
784 MAP_LIST( IMAGE_TEMPLATE );
785 MAP_LIST_LABEL( VERSION );
786 MAP_LIST_LABEL( TEMPLATE );
787 MAP_LIST_LABEL( IMAGE_TEMPLATE );
788 default:
789 OSL_TRACE("Handle unknown control %d", nControlId);
790 break;
791 }
792 #undef MAP
793
794 DBG_PRINT_EXIT(CLASS_NAME, __func__);
795
796 return pWidget;
797 }
798
layoutControls()799 void ControlHelper::layoutControls()
800 {
801 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
802
803 ::vos::OGuard aGuard( Application::GetSolarMutex() );
804
805 if (nil == m_pUserPane) {
806 OSL_TRACE("no user pane to layout");
807 DBG_PRINT_EXIT(CLASS_NAME, __func__);
808 return;
809 }
810
811 if (m_bIsUserPaneLaidOut == true) {
812 OSL_TRACE("user pane already laid out");
813 DBG_PRINT_EXIT(CLASS_NAME, __func__);
814 return;
815 }
816
817 NSRect userPaneRect = [m_pUserPane frame];
818 OSL_TRACE("userPane frame: {%f, %f, %f, %f}",userPaneRect.origin.x, userPaneRect.origin.y, userPaneRect.size.width, userPaneRect.size.height);
819
820 int nUsableWidth = userPaneRect.size.width;
821
822 //NOTE: NSView's coordinate system starts in the lower left hand corner but we start adding controls from the top,
823 // so we subtract from the vertical position as we make our way down the pane.
824 int currenttop = userPaneRect.size.height;
825 int nCheckboxMaxWidth = 0;
826 int nPopupMaxWidth = 0;
827 int nPopupLabelMaxWidth = 0;
828
829 //first loop to determine max sizes
830 for (::std::list<NSControl*>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) {
831 NSControl* pControl = *child;
832
833 NSRect controlRect = [pControl frame];
834 int nControlWidth = controlRect.size.width;
835
836 Class aSubType = [pControl class];
837 if (aSubType == [NSPopUpButton class]) {
838 if (nPopupMaxWidth < nControlWidth) {
839 nPopupMaxWidth = nControlWidth;
840 }
841 NSTextField *label = m_aMapListLabelFields[(NSPopUpButton*)pControl];
842 NSRect labelFrame = [label frame];
843 int nLabelWidth = labelFrame.size.width;
844 if (nPopupLabelMaxWidth < nLabelWidth) {
845 nPopupLabelMaxWidth = nLabelWidth;
846 }
847 } else {
848 if (nCheckboxMaxWidth < nControlWidth) {
849 nCheckboxMaxWidth = nControlWidth;
850 }
851 }
852 }
853
854 int nLongestPopupWidth = nPopupMaxWidth + nPopupLabelMaxWidth + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
855 OSL_TRACE("longest popup width: %d", nLongestPopupWidth);
856
857 NSControl* previousControl = nil;
858
859 int nDistBetweenControls = 0;
860
861 for (::std::list<NSControl*>::iterator child = m_aActiveControls.begin(); child != m_aActiveControls.end(); child++) {
862 NSControl* pControl = *child;
863
864 //get the control's bounds
865 NSRect controlRect = [pControl frame];
866 int nControlHeight = controlRect.size.height;
867 int nControlWidth = controlRect.size.width;
868
869 //subtract the height from the current vertical position, because the control's bounds origin rect will be its lower left hand corner
870 currenttop -= nControlHeight;
871
872 Class aSubType = [pControl class];
873
874 //add space between the previous control and this control according to Apple's HIG
875 nDistBetweenControls = getVerticalDistance(previousControl, pControl);
876 OSL_TRACE("vertical distance: %d", nDistBetweenControls);
877 currenttop -= nDistBetweenControls;
878
879 previousControl = pControl;
880
881 if (aSubType == [NSPopUpButton class]) {
882 //move vertically up some pixels to space the controls between their real (visual) bounds
883 currenttop += kAquaSpacePopupMenuFrameBoundsDiffTop;//from top
884
885 //get the corresponding popup label
886 NSTextField *label = m_aMapListLabelFields[(NSPopUpButton*)pControl];
887 NSRect labelFrame = [label frame];
888 int totalWidth = nPopupMaxWidth + labelFrame.size.width + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
889 OSL_TRACE("totalWidth: %d", totalWidth);
890 //let's center popups
891 int left = (nUsableWidth + nLongestPopupWidth) / 2 - totalWidth;
892 OSL_TRACE("left: %d", left);
893 labelFrame.origin.x = left;
894 labelFrame.origin.y = currenttop + kAquaSpaceLabelPopupDiffV;
895 OSL_TRACE("setting label at: {%f, %f, %f, %f}",labelFrame.origin.x, labelFrame.origin.y, labelFrame.size.width, labelFrame.size.height);
896 [label setFrame:labelFrame];
897
898 controlRect.origin.x = left + labelFrame.size.width + kAquaSpaceBetweenControls - kAquaSpaceLabelFrameBoundsDiffH - kAquaSpacePopupMenuFrameBoundsDiffLeft;
899 controlRect.origin.y = currenttop;
900 controlRect.size.width = nPopupMaxWidth;
901 OSL_TRACE("setting popup at: {%f, %f, %f, %f}",controlRect.origin.x, controlRect.origin.y, controlRect.size.width, controlRect.size.height);
902 [pControl setFrame:controlRect];
903
904 //add some space to place the vertical position right below the popup's visual bounds
905 currenttop += kAquaSpacePopupMenuFrameBoundsDiffBottom;
906 } else {
907 currenttop += kAquaSpaceSwitchButtonFrameBoundsDiff;//from top
908
909 nControlWidth = nCheckboxMaxWidth;
910 int left = (nUsableWidth - nCheckboxMaxWidth) / 2;
911 controlRect.origin.x = left;
912 controlRect.origin.y = currenttop;
913 controlRect.size.width = nPopupMaxWidth;
914 [pControl setFrame:controlRect];
915 OSL_TRACE("setting checkbox at: {%f, %f, %f, %f}",controlRect.origin.x, controlRect.origin.y, controlRect.size.width, controlRect.size.height);
916
917 currenttop += kAquaSpaceSwitchButtonFrameBoundsDiff;
918 }
919 }
920
921 m_bIsUserPaneLaidOut = true;
922
923 DBG_PRINT_EXIT(CLASS_NAME, __func__);
924 }
925
createFilterControl()926 void ControlHelper::createFilterControl() {
927 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
928
929 CResourceProvider aResProvider;
930 NSString* sLabel = aResProvider.getResString(CommonFilePickerElementIds::LISTBOX_FILTER_LABEL);
931
932 m_pFilterControl = [NSPopUpButton new];
933
934 [m_pFilterControl setAction:@selector(filterSelectedAtIndex:)];
935 [m_pFilterControl setTarget:m_pDelegate];
936
937 NSMenu *menu = [m_pFilterControl menu];
938
939 for (NSStringList::iterator iter = m_pFilterHelper->getFilterNames()->begin(); iter != m_pFilterHelper->getFilterNames()->end(); iter++) {
940 NSString *filterName = *iter;
941 OSL_TRACE("adding filter name: %s", [filterName UTF8String]);
942 if ([filterName isEqualToString:@"-"]) {
943 [menu addItem:[NSMenuItem separatorItem]];
944 }
945 else {
946 [m_pFilterControl addItemWithTitle:filterName];
947 }
948 }
949
950 // always add the filter as first item
951 m_aActiveControls.push_front(m_pFilterControl);
952 m_aMapListLabels[m_pFilterControl] = [sLabel retain];
953
954 DBG_PRINT_EXIT(CLASS_NAME, __func__);
955 }
956
createLabelWithString(NSString * labelString)957 NSTextField* ControlHelper::createLabelWithString(NSString* labelString) {
958 DBG_PRINT_ENTRY(CLASS_NAME, __func__, "label", labelString);
959
960 NSTextField *textField = [NSTextField new];
961 [textField setEditable:NO];
962 [textField setSelectable:NO];
963 [textField setDrawsBackground:NO];
964 [textField setBordered:NO];
965 [[textField cell] setTitle:labelString];
966
967 DBG_PRINT_EXIT(CLASS_NAME, __func__);
968 return textField;
969 }
970
getVerticalDistance(const NSControl * first,const NSControl * second)971 int ControlHelper::getVerticalDistance(const NSControl* first, const NSControl* second)
972 {
973 if (first == nil) {
974 return kAquaSpaceBoxFrameViewDiffTop;
975 }
976 else if (second == nil) {
977 return kAquaSpaceBoxFrameViewDiffBottom;
978 }
979 else {
980 Class firstClass = [first class];
981 Class secondClass = [second class];
982
983 if (firstClass == [NSPopUpButton class]) {
984 if (secondClass == [NSPopUpButton class]) {
985 return kAquaSpaceBetweenPopupMenus;
986 }
987 else {
988 return kAquaSpaceAfterPopupButtonsV;
989 }
990 }
991
992 return kAquaSpaceBetweenControls;
993 }
994 }
995
updateFilterUI()996 void ControlHelper::updateFilterUI()
997 {
998 DBG_PRINT_ENTRY(CLASS_NAME, __func__);
999
1000 if (m_bIsFilterControlNeeded == false || m_pFilterHelper == NULL) {
1001 OSL_TRACE("no filter control needed or no filter helper present");
1002 DBG_PRINT_EXIT(CLASS_NAME, __func__);
1003 return;
1004 }
1005
1006 int index = m_pFilterHelper->getCurrentFilterIndex();
1007
1008 if (m_pFilterControl == nil) {
1009 createFilterControl();
1010 }
1011
1012 [m_pFilterControl selectItemAtIndex:index];
1013
1014 DBG_PRINT_EXIT(CLASS_NAME, __func__);
1015 }
1016