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 //------------------------------------------------------------------------------------ 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 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 //------------------------------------------------ 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 163 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 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 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 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 285 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 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 //------------------------------------------------------------------------------------ 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 555 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 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 673 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 746 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 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 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 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 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 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