LibreOffice Module fpicker (master) 1
ControlHelper.mm
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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 "resourceprovider.hxx"
28#include <sal/log.hxx>
29
30#include "ControlHelper.hxx"
31
32#pragma mark DEFINES
33#define POPUP_WIDTH_MIN 200
34#define POPUP_WIDTH_MAX 350
35
36using namespace ::com::sun::star::ui::dialogs;
37using namespace ::com::sun::star::ui::dialogs::TemplateDescription;
38using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds;
39using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds;
40
41namespace {
42
43uno::Any HandleGetListValue(const NSControl* pControl, const sal_Int16 nControlAction)
44{
45 uno::Any aAny;
46
47 if ([pControl class] != [NSPopUpButton class]) {
48 SAL_INFO("fpicker.aqua","not a popup button");
49 return aAny;
50 }
51
52 NSPopUpButton *pButton = static_cast<NSPopUpButton*>(pControl);
53 NSMenu *rMenu = [pButton menu];
54 if (nil == rMenu) {
55 SAL_INFO("fpicker.aqua","button has no menu");
56 return aAny;
57 }
58
59 switch (nControlAction)
60 {
61 case ControlActions::GET_ITEMS:
62 {
63 SAL_INFO("fpicker.aqua","GET_ITEMS");
64 uno::Sequence< OUString > aItemList;
65
66 int nItems = [rMenu numberOfItems];
67 if (nItems > 0) {
68 aItemList.realloc(nItems);
69 OUString* pItemList = aItemList.getArray();
70 for (int i = 0; i < nItems; i++) {
71 NSString* sCFItem = [pButton itemTitleAtIndex:i];
72 if (nil != sCFItem) {
73 pItemList[i] = [sCFItem OUString];
74 SAL_INFO("fpicker.aqua","Return value[" << (i - 1) << "]: " << aItemList[i - 1]);
75 }
76 }
77 }
78
79 aAny <<= aItemList;
80 }
81 break;
82 case ControlActions::GET_SELECTED_ITEM:
83 {
84 SAL_INFO("fpicker.aqua","GET_SELECTED_ITEM");
85 NSString* sCFItem = [pButton titleOfSelectedItem];
86 if (nil != sCFItem) {
87 OUString sString = [sCFItem OUString];
88 SAL_INFO("fpicker.aqua","Return value: " << sString);
89 aAny <<= sString;
90 }
91 }
92 break;
93 case ControlActions::GET_SELECTED_ITEM_INDEX:
94 {
95 SAL_INFO("fpicker.aqua","GET_SELECTED_ITEM_INDEX");
96 sal_Int32 nActive = [pButton indexOfSelectedItem];
97 SAL_INFO("fpicker.aqua","Return value: " << nActive);
98 aAny <<= nActive;
99 }
100 break;
101 default:
102 SAL_INFO("fpicker.aqua","undocumented/unimplemented ControlAction for a list");
103 break;
104 }
105
106 return aAny;
107}
108
109NSTextField* createLabelWithString(NSString* labelString)
110{
111 NSTextField *textField = [NSTextField new];
112 [textField setEditable:NO];
113 [textField setSelectable:NO];
114 [textField setDrawsBackground:NO];
115 [textField setBordered:NO];
116 [[textField cell] setTitle:labelString];
117
118 return textField;
119}
120
121}
122
123#pragma mark Constructor / Destructor
124
125// Constructor / Destructor
126
128: m_pUserPane(nullptr)
129, m_pFilterControl(nil)
130, m_bUserPaneNeeded( false )
131, m_bIsUserPaneLaidOut(false)
132, m_bIsFilterControlNeeded(false)
133, m_pFilterHelper(nullptr)
134{
135 int i;
136
137 for( i = 0; i < TOGGLE_LAST; i++ ) {
138 m_bToggleVisibility[i] = false;
139 }
140
141 for( i = 0; i < LIST_LAST; i++ ) {
142 m_bListVisibility[i] = false;
143 }
144}
145
147{
148 NSAutoreleasePool *pool = [NSAutoreleasePool new];
149
150 if (nullptr != m_pUserPane) {
151 [m_pUserPane release];
152 }
153
154 if (m_pFilterControl != nullptr) {
155 [m_pFilterControl setTarget:nil];
156 }
157
158 for (auto const& activeControl : m_aActiveControls)
159 {
160 NSString* sLabelName = m_aMapListLabels[activeControl];
161 if (sLabelName != nil) {
162 [sLabelName release];
163 }
164 if ([activeControl class] == [NSPopUpButton class]) {
165 NSTextField* pField = m_aMapListLabelFields[static_cast<NSPopUpButton*>(activeControl)];
166 if (pField != nil) {
167 [pField release];
168 }
169 }
170 [activeControl release];
171 }
172
173 [pool release];
174}
175
176#pragma mark XInitialization delegate
177
178// XInitialization delegate
179
180void ControlHelper::initialize( sal_Int16 nTemplateId )
181{
182 switch( nTemplateId )
183 {
184 case FILESAVE_AUTOEXTENSION_PASSWORD:
188 break;
189 case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
194 break;
195 case FILESAVE_AUTOEXTENSION_SELECTION:
198 break;
199 case FILESAVE_AUTOEXTENSION_TEMPLATE:
202 break;
203 case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
207 break;
208 case FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR:
212 break;
213 case FILEOPEN_READONLY_VERSION:
216 break;
217 case FILEOPEN_LINK_PREVIEW:
220 break;
221 case FILESAVE_AUTOEXTENSION:
223 break;
224 case FILEOPEN_PREVIEW:
226 break;
227 case FILEOPEN_LINK_PLAY:
229 }
230
232}
233
234#pragma mark XFilePickerControlAccess delegates
235
236// XFilePickerControlAccess functions
237
238
239void ControlHelper::enableControl( const sal_Int16 nControlId, const bool bEnable ) const
240{
241 SolarMutexGuard aGuard;
242
243 if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_PREVIEW) {
244 SAL_INFO("fpicker.aqua"," preview checkbox cannot be changed");
245 return;
246 }
247
248 NSControl* pControl = getControl(nControlId);
249
250 if( pControl != nil ) {
251 if( bEnable ) {
252 SAL_INFO("fpicker.aqua", "enable" );
253 } else {
254 SAL_INFO("fpicker.aqua", "disable" );
255 }
256 [pControl setEnabled:bEnable];
257 } else {
258 SAL_INFO("fpicker.aqua","enable unknown control " << nControlId );
259 }
260}
261
263{
264 SolarMutexGuard aGuard;
265
266 NSControl* pControl = getControl( nControlId );
267
268 if( pControl == nil ) {
269 SAL_INFO("fpicker.aqua","Get label for unknown control " << nControlId);
270 return OUString();
271 }
272
273 OUString retVal;
274 if ([pControl class] == [NSPopUpButton class]) {
275 NSString *temp = m_aMapListLabels[pControl];
276 if (temp != nil)
277 retVal = [temp OUString];
278 }
279 else {
280 NSString* sLabel = [[pControl cell] title];
281 retVal = [sLabel OUString];
282 }
283
284 return retVal;
285}
286
287void ControlHelper::setLabel( sal_Int16 nControlId, NSString* aLabel )
288{
289 SolarMutexGuard aGuard;
290
291 NSAutoreleasePool *pool = [NSAutoreleasePool new];
292
293 NSControl* pControl = getControl(nControlId);
294
295 if (nil != pControl) {
296 if ([pControl class] == [NSPopUpButton class]) {
297 NSString *sOldName = m_aMapListLabels[pControl];
298 if (sOldName != nullptr && sOldName != aLabel) {
299 [sOldName release];
300 }
301
302 m_aMapListLabels[pControl] = [aLabel retain];
303 } else if ([pControl class] == [NSButton class]) {
304 [[pControl cell] setTitle:aLabel];
305 }
306 } else {
307 SAL_INFO("fpicker.aqua","Control not found to set label for");
308 }
309
311
312 [pool release];
313}
314
315void ControlHelper::setValue( sal_Int16 nControlId, sal_Int16 nControlAction, const uno::Any& rValue )
316{
317 SolarMutexGuard aGuard;
318
319 if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_PREVIEW) {
320 SAL_INFO("fpicker.aqua"," value for preview is unchangeable");
321 }
322 else {
323 NSControl* pControl = getControl( nControlId );
324
325 if( pControl == nil ) {
326 SAL_INFO("fpicker.aqua","enable unknown control " << nControlId);
327 } else {
328 if( [pControl class] == [NSPopUpButton class] ) {
329 HandleSetListValue(pControl, nControlAction, rValue);
330 } else if( [pControl class] == [NSButton class] ) {
331 bool bChecked = false;
332 rValue >>= bChecked;
333 SAL_INFO("fpicker.aqua"," value is a bool: " << bChecked);
334 [static_cast<NSButton*>(pControl) setState:(bChecked ? NSControlStateValueOn : NSControlStateValueOff)];
335 } else
336 {
337 SAL_INFO("fpicker.aqua","Can't set value on button / list " << nControlId << " " << nControlAction);
338 }
339 }
340 }
341}
342
343uno::Any ControlHelper::getValue( sal_Int16 nControlId, sal_Int16 nControlAction ) const
344{
345 SolarMutexGuard aGuard;
346 uno::Any aRetval;
347
348 NSControl* pControl = getControl( nControlId );
349
350 if( pControl == nil ) {
351 SAL_INFO("fpicker.aqua","get value for unknown control " << nControlId);
352 } else {
353 if( [pControl class] == [NSPopUpButton class] ) {
354 aRetval = HandleGetListValue(pControl, nControlAction);
355 } else if( [pControl class] == [NSButton class] ) {
356 //NSLog(@"control: %@", [[pControl cell] title]);
357 bool bValue = [static_cast<NSButton*>(pControl) state] == NSControlStateValueOn;
358 aRetval <<= bValue;
359 SAL_INFO("fpicker.aqua","value is a bool (checkbox): " << bValue);
360 }
361 }
362
363 return aRetval;
364}
365
367{
368 if (!m_bUserPaneNeeded) {
369 SAL_INFO("fpicker.aqua","no user pane needed");
370 return;
371 }
372
373 if (nil != m_pUserPane) {
374 SAL_INFO("fpicker.aqua","user pane already exists");
375 return;
376 }
377
380 }
381
382 NSRect minRect = NSMakeRect(0,0,300,33);
383 m_pUserPane = [[NSView alloc] initWithFrame:minRect];
384
386 int currentWidth = 300;
387
388 bool bPopupControlPresent = false;
389 bool bButtonControlPresent = false;
390
391 int nCheckboxMaxWidth = 0;
392 int nPopupMaxWidth = 0;
393 int nPopupLabelMaxWidth = 0;
394
395 size_t nLoop = 0;
396 for (auto const& activeControl : m_aActiveControls)
397 {
398 SAL_INFO("fpicker.aqua","currentHeight: " << currentHeight);
399
400 //let the control calculate its size
401 [activeControl sizeToFit];
402
403 NSRect frame = [activeControl frame];
404 SAL_INFO("fpicker.aqua","frame for control " << [[activeControl description] UTF8String] << " is {" << frame.origin.x << ", " << frame.origin.y << ", " << frame.size.width << ", " << frame.size.height << "}");
405
406 int nControlHeight = frame.size.height;
407 int nControlWidth = frame.size.width;
408
409 // Note: controls are grouped by kind, first all popup menus, then checkboxes
410 if ([activeControl class] == [NSPopUpButton class]) {
411 if (bPopupControlPresent) {
412 //this is not the first popup
413 currentHeight += kAquaSpaceBetweenPopupMenus;
414 }
415 else if (nLoop)
416 {
417 currentHeight += kAquaSpaceBetweenControls;
418 }
419
420 bPopupControlPresent = true;
421
422 // we have to add the label text width
423 NSString *label = m_aMapListLabels[activeControl];
424
425 NSTextField *textField = createLabelWithString(label);
426 [textField sizeToFit];
427 m_aMapListLabelFields[static_cast<NSPopUpButton*>(activeControl)] = textField;
428 [m_pUserPane addSubview:textField];
429
430 NSRect tfRect = [textField frame];
431 SAL_INFO("fpicker.aqua","frame for textfield " << [[textField description] UTF8String] << " is {" << tfRect.origin.x << ", " << tfRect.origin.y << ", " << tfRect.size.width << ", " << tfRect.size.height << "}");
432
433 int tfWidth = tfRect.size.width;
434
435 if (nPopupLabelMaxWidth < tfWidth) {
436 nPopupLabelMaxWidth = tfWidth;
437 }
438
440
441 if (nControlWidth < POPUP_WIDTH_MIN) {
442 nControlWidth = POPUP_WIDTH_MIN;
443 frame.size.width = nControlWidth;
444 [activeControl setFrame:frame];
445 }
446
447 if (nControlWidth > POPUP_WIDTH_MAX) {
448 nControlWidth = POPUP_WIDTH_MAX;
449 frame.size.width = nControlWidth;
450 [activeControl setFrame:frame];
451 }
452
453 //set the max size
454 if (nPopupMaxWidth < nControlWidth) {
455 nPopupMaxWidth = nControlWidth;
456 }
457
459 if (nControlHeight < kAquaPopupButtonDefaultHeight) {
460 //maybe the popup has no menu item yet, so set a default height
461 nControlHeight = kAquaPopupButtonDefaultHeight;
462 }
463
464 nControlHeight -= kAquaSpacePopupMenuFrameBoundsDiffV;
465 }
466 else if ([activeControl class] == [NSButton class]) {
467 if (nLoop)
468 {
469 currentHeight += kAquaSpaceBetweenControls;
470 }
471
472 if (nCheckboxMaxWidth < nControlWidth) {
473 nCheckboxMaxWidth = nControlWidth;
474 }
475
476 bButtonControlPresent = true;
477 nControlWidth -= 2 * kAquaSpaceSwitchButtonFrameBoundsDiff;
478 nControlHeight -= 2 * kAquaSpaceSwitchButtonFrameBoundsDiff;
479 }
480
481 // if ((nControlWidth + 2 * kAquaSpaceInsideGroupH) > currentWidth) {
482 // currentWidth = nControlWidth + 2 * kAquaSpaceInsideGroupH;
483 // }
484
485 currentHeight += nControlHeight;
486
487 [m_pUserPane addSubview:activeControl];
488 ++nLoop;
489 }
490
491 SAL_INFO("fpicker.aqua","height after adding all controls: " << currentHeight);
492
493 if (bPopupControlPresent && bButtonControlPresent)
494 {
495 //after a popup button (array) and before a different kind of control we need some extra space instead of the standard
496 currentHeight -= kAquaSpaceBetweenControls;
497 currentHeight += kAquaSpaceAfterPopupButtonsV;
498 SAL_INFO("fpicker.aqua","popup extra space added, currentHeight: " << currentHeight);
499 }
500
501 int nLongestPopupWidth = nPopupMaxWidth + nPopupLabelMaxWidth + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
502
503 currentWidth = nLongestPopupWidth > nCheckboxMaxWidth ? nLongestPopupWidth : nCheckboxMaxWidth;
504 SAL_INFO("fpicker.aqua","longest control width: " << currentWidth);
505
506 currentWidth += 2* kAquaSpaceInsideGroupH;
507
508 if (currentWidth < minRect.size.width)
509 currentWidth = minRect.size.width;
510
511 if (currentHeight < minRect.size.height)
512 currentHeight = minRect.size.height;
513
514 NSRect upRect = NSMakeRect(0, 0, currentWidth, currentHeight );
515 SAL_INFO("fpicker.aqua","setting user pane rect to {" << upRect.origin.x << ", " << upRect.origin.y << ", " << upRect.size.width << ", " << upRect.size.height << "}");
516
517 [m_pUserPane setFrame:upRect];
518
520}
521
522#pragma mark Private / Misc
523
524// Private / Misc
525
527{
528 for (int i = 0; i < LIST_LAST; i++) {
529 if (m_bListVisibility[i]) {
530 m_bUserPaneNeeded = true;
531
532 int elementName = getControlElementName([NSPopUpButton class], i);
533 NSString* sLabel = CResourceProvider::getResString(elementName);
534
535 m_pListControls[i] = [NSPopUpButton new];
536
537#define MAP_LIST_( elem ) \
538 case elem: \
539 setLabel(ExtendedFilePickerElementIds::LISTBOX_##elem, sLabel); \
540 break
541
542 switch(i) {
547 }
548
550 } else {
551 m_pListControls[i] = nil;
552 }
553 }
554
555 for (int i = 0/*#i102102*/; i < TOGGLE_LAST; i++) {
556 if (m_bToggleVisibility[i]) {
557 m_bUserPaneNeeded = true;
558
559 int elementName = getControlElementName([NSButton class], i);
560 NSString* sLabel = CResourceProvider::getResString(elementName);
561
562 NSButton *button = [NSButton new];
563 [button setTitle:sLabel];
564
565 [button setButtonType:NSButtonTypeSwitch];
566
567 [button setState:NSControlStateValueOff];
568
569 if (i == AUTOEXTENSION) {
570 [button setTarget:m_pDelegate];
571 [button setAction:@selector(autoextensionChanged:)];
572 }
573
574 m_pToggles[i] = button;
575
576 m_aActiveControls.push_back(m_pToggles[i]);
577 } else {
578 m_pToggles[i] = nil;
579 }
580 }
581
582 //preview is always on with macOS
583 NSControl *pPreviewBox = m_pToggles[PREVIEW];
584 if (pPreviewBox != nil) {
585 [pPreviewBox setEnabled:NO];
586 [static_cast<NSButton*>(pPreviewBox) setState:NSControlStateValueOn];
587 }
588}
589
590#define TOGGLE_ELEMENT( elem ) \
591case elem: \
592 nReturn = CHECKBOX_##elem; \
593 return nReturn
594#define LIST_ELEMENT( elem ) \
595case elem: \
596 nReturn = LISTBOX_##elem##_LABEL; \
597 return nReturn
598
599int ControlHelper::getControlElementName(const Class aClazz, const int nControlId)
600{
601 int nReturn = -1;
602 if (aClazz == [NSButton class])
603 {
604 switch (nControlId) {
613 }
614 }
615 else if (aClazz == [NSPopUpButton class])
616 {
617 switch (nControlId) {
622 }
623 }
624
625 return nReturn;
626}
627
628void ControlHelper::HandleSetListValue(const NSControl* pControl, const sal_Int16 nControlAction, const uno::Any& rValue)
629{
630 if ([pControl class] != [NSPopUpButton class]) {
631 SAL_INFO("fpicker.aqua","not a popup menu");
632 return;
633 }
634
635 NSPopUpButton *pButton = static_cast<NSPopUpButton*>(pControl);
636 NSMenu *rMenu = [pButton menu];
637 if (nil == rMenu) {
638 SAL_INFO("fpicker.aqua","button has no menu");
639 return;
640 }
641
642 switch (nControlAction)
643 {
644 case ControlActions::ADD_ITEM:
645 {
646 SAL_INFO("fpicker.aqua","ADD_ITEMS");
647 OUString sItem;
648 rValue >>= sItem;
649
650 NSString* sCFItem = [NSString stringWithOUString:sItem];
651 SAL_INFO("fpicker.aqua","Adding menu item: " << sItem);
652 [pButton addItemWithTitle:sCFItem];
653 }
654 break;
655 case ControlActions::ADD_ITEMS:
656 {
657 SAL_INFO("fpicker.aqua","ADD_ITEMS");
658 uno::Sequence< OUString > aStringList;
659 rValue >>= aStringList;
660 sal_Int32 nItemCount = aStringList.getLength();
661 for (sal_Int32 i = 0; i < nItemCount; ++i)
662 {
663 NSString* sCFItem = [NSString stringWithOUString:aStringList[i]];
664 SAL_INFO("fpicker.aqua","Adding menu item: " << aStringList[i]);
665 [pButton addItemWithTitle:sCFItem];
666 }
667 }
668 break;
669 case ControlActions::DELETE_ITEM:
670 {
671 SAL_INFO("fpicker.aqua","DELETE_ITEM");
672 sal_Int32 nPos = -1;
673 rValue >>= nPos;
674 SAL_INFO("fpicker.aqua","Deleting item at position " << (nPos));
675 [rMenu removeItemAtIndex:nPos];
676 }
677 break;
678 case ControlActions::DELETE_ITEMS:
679 {
680 SAL_INFO("fpicker.aqua","DELETE_ITEMS");
681 int nItems = [rMenu numberOfItems];
682 if (nItems == 0) {
683 SAL_INFO("fpicker.aqua","no menu items to delete");
684 return;
685 }
686 for(sal_Int32 i = 0; i < nItems; i++) {
687 [rMenu removeItemAtIndex:i];
688 }
689 }
690 break;
691 case ControlActions::SET_SELECT_ITEM:
692 {
693 sal_Int32 nPos = -1;
694 rValue >>= nPos;
695 SAL_INFO("fpicker.aqua","Selecting item at position " << nPos);
696 [pButton selectItemAtIndex:nPos];
697 }
698 break;
699 default:
700 SAL_INFO("fpicker.aqua","undocumented/unimplemented ControlAction for a list");
701 break;
702 }
703
705}
706
707// cf. offapi/com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.idl
708NSControl* ControlHelper::getControl( const sal_Int16 nControlId ) const
709{
710 NSControl* pWidget = nil;
711
712#define MAP_TOGGLE( elem ) \
713case ExtendedFilePickerElementIds::CHECKBOX_##elem: \
714 pWidget = m_pToggles[elem]; \
715 break
716
717#define MAP_LIST( elem ) \
718case ExtendedFilePickerElementIds::LISTBOX_##elem: \
719 pWidget = m_pListControls[elem]; \
720 break
721
722#define MAP_LIST_LABEL( elem ) \
723case ExtendedFilePickerElementIds::LISTBOX_##elem##_LABEL: \
724 pWidget = m_pListControls[elem]; \
725 break
726
727 switch( nControlId )
728 {
734 MAP_TOGGLE( LINK );
737 //MAP_BUTTON( PLAY );
738 MAP_LIST( VERSION );
746 default:
747 SAL_INFO("fpicker.aqua","Handle unknown control " << nControlId);
748 break;
749 }
750#undef MAP
751
752 return pWidget;
753}
754
756{
757 SolarMutexGuard aGuard;
758
759 if (nil == m_pUserPane) {
760 SAL_INFO("fpicker.aqua","no user pane to layout");
761 return;
762 }
763
765 SAL_INFO("fpicker.aqua","user pane already laid out");
766 return;
767 }
768
769 NSRect userPaneRect = [m_pUserPane frame];
770 SAL_INFO("fpicker.aqua","userPane frame: {" << userPaneRect.origin.x << ", " << userPaneRect.origin.y << ", " << userPaneRect.size.width << ", " << userPaneRect.size.height << "}");
771
772 int nUsableWidth = userPaneRect.size.width;
773
774 //NOTE: NSView's coordinate system starts in the lower left hand corner but we start adding controls from the top,
775 // so we subtract from the vertical position as we make our way down the pane.
776 int currenttop = userPaneRect.size.height;
777 int nCheckboxMaxWidth = 0;
778 int nPopupMaxWidth = 0;
779 int nPopupLabelMaxWidth = 0;
780
781 //first loop to determine max sizes
782 for (auto const& activeControl : m_aActiveControls)
783 {
784
785 NSRect controlRect = [activeControl frame];
786 int nControlWidth = controlRect.size.width;
787
788 Class aSubType = [activeControl class];
789 if (aSubType == [NSPopUpButton class]) {
790 if (nPopupMaxWidth < nControlWidth) {
791 nPopupMaxWidth = nControlWidth;
792 }
793 NSTextField *label = m_aMapListLabelFields[static_cast<NSPopUpButton*>(activeControl)];
794 NSRect labelFrame = [label frame];
795 int nLabelWidth = labelFrame.size.width;
796 if (nPopupLabelMaxWidth < nLabelWidth) {
797 nPopupLabelMaxWidth = nLabelWidth;
798 }
799 } else {
800 if (nCheckboxMaxWidth < nControlWidth) {
801 nCheckboxMaxWidth = nControlWidth;
802 }
803 }
804 }
805
806 int nLongestPopupWidth = nPopupMaxWidth + nPopupLabelMaxWidth + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
807 SAL_INFO("fpicker.aqua","longest popup width: " << nLongestPopupWidth);
808
809 NSControl* previousControl = nil;
810
811 int nDistBetweenControls = 0;
812
813 for (auto const& activeControl : m_aActiveControls)
814 {
815 //get the control's bounds
816 NSRect controlRect = [activeControl frame];
817 int nControlHeight = controlRect.size.height;
818
819 //subtract the height from the current vertical position, because the control's bounds origin rect will be its lower left hand corner
820 currenttop -= nControlHeight;
821
822 Class aSubType = [activeControl class];
823
824 //add space between the previous control and this control according to Apple's HIG
825 nDistBetweenControls = getVerticalDistance(previousControl, activeControl);
826 SAL_INFO("fpicker.aqua","vertical distance: " << nDistBetweenControls);
827 currenttop -= nDistBetweenControls;
828
829 previousControl = activeControl;
830
831 if (aSubType == [NSPopUpButton class]) {
832 //move vertically up some pixels to space the controls between their real (visual) bounds
833 currenttop += kAquaSpacePopupMenuFrameBoundsDiffTop;//from top
834
835 //get the corresponding popup label
836 NSTextField *label = m_aMapListLabelFields[static_cast<NSPopUpButton*>(activeControl)];
837 NSRect labelFrame = [label frame];
838 int totalWidth = nPopupMaxWidth + labelFrame.size.width + kAquaSpaceBetweenControls - kAquaSpacePopupMenuFrameBoundsDiffLeft - kAquaSpaceLabelFrameBoundsDiffH;
839 SAL_INFO("fpicker.aqua","totalWidth: " << totalWidth);
840 //let's center popups
841 int left = (nUsableWidth + nLongestPopupWidth) / 2 - totalWidth;
842 SAL_INFO("fpicker.aqua","left: " << left);
843 labelFrame.origin.x = left;
844 labelFrame.origin.y = currenttop + kAquaSpaceLabelPopupDiffV;
845 SAL_INFO("fpicker.aqua","setting label at: {" << labelFrame.origin.x << ", " << labelFrame.origin.y << ", " << labelFrame.size.width << ", " << labelFrame.size.height << "}");
846 [label setFrame:labelFrame];
847
849 controlRect.origin.y = currenttop;
850 controlRect.size.width = nPopupMaxWidth;
851 SAL_INFO("fpicker.aqua","setting popup at: {" << controlRect.origin.x << ", " << controlRect.origin.y << ", " << controlRect.size.width << ", " << controlRect.size.height << "}");
852 [activeControl setFrame:controlRect];
853
854 //add some space to place the vertical position right below the popup's visual bounds
856 } else {
857 currenttop += kAquaSpaceSwitchButtonFrameBoundsDiff;//from top
858
859 int left = (nUsableWidth - nCheckboxMaxWidth) / 2;
860 controlRect.origin.x = left;
861 controlRect.origin.y = currenttop;
862 controlRect.size.width = nPopupMaxWidth;
863 [activeControl setFrame:controlRect];
864 SAL_INFO("fpicker.aqua","setting checkbox at: {" << controlRect.origin.x << ", " << controlRect.origin.y << ", " << controlRect.size.width << ", " << controlRect.size.height << "}");
865
867 }
868 }
869
871}
872
874{
875 NSString* sLabel = CResourceProvider::getResString(CommonFilePickerElementIds::LISTBOX_FILTER_LABEL);
876
877 m_pFilterControl = [NSPopUpButton new];
878
879 [m_pFilterControl setAction:@selector(filterSelectedAtIndex:)];
880 [m_pFilterControl setTarget:m_pDelegate];
881
882 NSMenu *menu = [m_pFilterControl menu];
883
884 for (auto const& filterName : *m_pFilterHelper->getFilterNames())
885 {
886 SAL_INFO("fpicker.aqua","adding filter name: " << [filterName UTF8String]);
887 if ([filterName isEqualToString:@"-"]) {
888 [menu addItem:[NSMenuItem separatorItem]];
889 }
890 else {
891 [m_pFilterControl addItemWithTitle:filterName];
892 }
893 }
894
895 // always add the filter as first item
897 m_aMapListLabels[m_pFilterControl] = [sLabel retain];
898}
899
900int ControlHelper::getVerticalDistance(const NSControl* first, const NSControl* second)
901{
902 if (first == nil) {
904 }
905 else if (second == nil) {
907 }
908 else {
909 Class firstClass = [first class];
910 Class secondClass = [second class];
911
912 if (firstClass == [NSPopUpButton class]) {
913 if (secondClass == [NSPopUpButton class]) {
915 }
916 else {
918 }
919 }
920
922 }
923}
924
926{
927 if (!m_bIsFilterControlNeeded || m_pFilterHelper == nullptr) {
928 SAL_INFO("fpicker.aqua","no filter control needed or no filter helper present");
929 return;
930 }
931
933
934 if (m_pFilterControl == nil) {
936 }
937
938 [m_pFilterControl selectItemAtIndex:index];
939}
940
941/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define LIST_ELEMENT(elem)
#define MAP_LIST_LABEL(elem)
#define TOGGLE_ELEMENT(elem)
#define MAP_LIST_(elem)
#define MAP_TOGGLE(elem)
#define MAP_LIST(elem)
#define POPUP_WIDTH_MAX
#define POPUP_WIDTH_MIN
sal_Int16 nControlId
#define kAquaSpaceSwitchButtonFrameBoundsDiff
#define kAquaSpacePopupMenuFrameBoundsDiffTop
#define kAquaSpacePopupMenuFrameBoundsDiffBottom
#define kAquaSpaceBetweenPopupMenus
#define kAquaSpacePopupMenuFrameBoundsDiffLeft
#define kAquaSpaceInsideGroupH
#define kAquaPopupButtonDefaultHeight
#define kAquaSpaceAfterPopupButtonsV
#define kAquaSpaceBoxFrameViewDiffBottom
#define kAquaSpaceLabelFrameBoundsDiffH
#define kAquaSpaceBoxFrameViewDiffTop
#define kAquaSpaceBetweenControls
#define kAquaSpacePopupMenuFrameBoundsDiffV
#define kAquaSpaceLabelPopupDiffV
void createControls()
FilterHelper * m_pFilterHelper
the filter helper
uno::Any getValue(sal_Int16 nControlId, sal_Int16 nControlAction) const
NSView * m_pUserPane
the native view object
::std::list< NSControl * > m_aActiveControls
a list with all actively used controls
bool m_bToggleVisibility[TOGGLE_LAST]
the visibility flags for the checkboxes
NSControl * m_pListControls[LIST_LAST]
the popup menu controls (except for the filter control)
bool m_bUserPaneNeeded
indicates if a user pane is needed
void createFilterControl()
bool m_bIsUserPaneLaidOut
indicates if the user pane was laid out already
void initialize(sal_Int16 templateId)
NSControl * getControl(const sal_Int16 nControlId) const
void setLabel(sal_Int16 nControlId, NSString *aLabel)
OUString getLabel(sal_Int16 nControlId)
void updateFilterUI()
AquaFilePickerDelegate * m_pDelegate
the save or open panel's delegate
static int getControlElementName(const Class clazz, const int nControlId)
NSControl * m_pToggles[TOGGLE_LAST]
the checkbox controls
static int getVerticalDistance(const NSControl *first, const NSControl *second)
void layoutControls()
void enableControl(sal_Int16 nControlId, bool bEnable) const
void HandleSetListValue(const NSControl *pControl, const sal_Int16 nControlAction, const uno::Any &rValue)
NSPopUpButton * m_pFilterControl
the special filter control
void createUserPane()
::std::map< NSPopUpButton *, NSTextField * > m_aMapListLabelFields
a map to store a popup menu's label text field
bool m_bListVisibility[LIST_LAST]
the visibility flags for the popup menus
bool m_bIsFilterControlNeeded
indicates if a filter control is needed
virtual ~ControlHelper()
void setValue(sal_Int16 nControlId, sal_Int16 nControlAction, const uno::Any &rValue)
::std::map< NSControl *, NSString * > m_aMapListLabels
a map to store a control's label text
int getCurrentFilterIndex()
NSStringList * getFilterNames()
sal_uInt16 nPos
#define SAL_INFO(area, stream)
NSString * getResString(sal_Int32 aId)
def label(st)
int i
constexpr OUStringLiteral first
index
OUString aLabel
const std::u16string_view aStringList[]
sal_uInt64 left