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 <vcl/toolkit/button.hxx>
21 #include <vcl/stdtext.hxx>
22 #include <helper/btndlg.hxx>
23 #include <sal/log.hxx>
24 #include <map>
25 #include <memory>
26 
27 struct ImplBtnDlgItem
28 {
29     sal_uInt16              mnId;
30     bool                    mbOwnButton;
31     tools::Long                    mnSepSize;
32     VclPtr<PushButton>      mpPushButton;
33 
ImplBtnDlgItemImplBtnDlgItem34     ImplBtnDlgItem() : mnId(0), mbOwnButton(false), mnSepSize(0) {}
35 };
36 
ImplInitButtonDialogData()37 void ButtonDialog::ImplInitButtonDialogData()
38 {
39     mnButtonSize            = 0;
40     mnCurButtonId           = 0;
41     mnFocusButtonId         = BUTTONDIALOG_BUTTON_NOTFOUND;
42     mbFormat                = true;
43 }
44 
ButtonDialog(WindowType nType)45 ButtonDialog::ButtonDialog( WindowType nType ) :
46     Dialog( nType )
47 {
48     ImplInitButtonDialogData();
49 }
50 
~ButtonDialog()51 ButtonDialog::~ButtonDialog()
52 {
53     disposeOnce();
54 }
55 
dispose()56 void ButtonDialog::dispose()
57 {
58     for (auto & it : m_ItemList)
59     {
60         if ( it->mbOwnButton )
61             it->mpPushButton.disposeAndClear();
62     }
63     m_ItemList.clear();
64     Dialog::dispose();
65 }
66 
ImplCreatePushButton(ButtonDialogFlags nBtnFlags)67 VclPtr<PushButton> ButtonDialog::ImplCreatePushButton( ButtonDialogFlags nBtnFlags )
68 {
69     VclPtr<PushButton> pBtn;
70     WinBits     nStyle = 0;
71 
72     if ( nBtnFlags & ButtonDialogFlags::Default )
73         nStyle |= WB_DEFBUTTON;
74     if ( nBtnFlags & ButtonDialogFlags::Cancel )
75         pBtn = VclPtr<CancelButton>::Create( this, nStyle );
76     else if ( nBtnFlags & ButtonDialogFlags::OK )
77         pBtn = VclPtr<OKButton>::Create( this, nStyle );
78     else if ( nBtnFlags & ButtonDialogFlags::Help )
79         pBtn = VclPtr<HelpButton>::Create( this, nStyle );
80     else
81         pBtn = VclPtr<PushButton>::Create( this, nStyle );
82 
83     if ( !(nBtnFlags & ButtonDialogFlags::Help) )
84         pBtn->SetClickHdl( LINK( this, ButtonDialog, ImplClickHdl ) );
85 
86     return pBtn;
87 }
88 
ImplGetButtonSize()89 tools::Long ButtonDialog::ImplGetButtonSize()
90 {
91     if ( !mbFormat )
92         return mnButtonSize;
93 
94     // Calculate ButtonSize
95     tools::Long nLastSepSize = 0;
96     tools::Long nSepSize = 0;
97     maCtrlSize = Size( IMPL_MINSIZE_BUTTON_WIDTH, IMPL_MINSIZE_BUTTON_HEIGHT );
98 
99     for (const auto & it : m_ItemList)
100     {
101         nSepSize += nLastSepSize;
102 
103         tools::Long nTxtWidth = it->mpPushButton->GetOutDev()->GetCtrlTextWidth(it->mpPushButton->GetText());
104         nTxtWidth += IMPL_EXTRA_BUTTON_WIDTH;
105 
106         if ( nTxtWidth > maCtrlSize.Width() )
107             maCtrlSize.setWidth( nTxtWidth );
108 
109         tools::Long nTxtHeight = it->mpPushButton->GetTextHeight();
110         nTxtHeight += IMPL_EXTRA_BUTTON_HEIGHT;
111 
112         if ( nTxtHeight > maCtrlSize.Height() )
113             maCtrlSize.setHeight( nTxtHeight );
114 
115         nSepSize += it->mnSepSize;
116 
117         if ( GetStyle() & WB_HORZ )
118             nLastSepSize = IMPL_SEP_BUTTON_X;
119         else
120             nLastSepSize = IMPL_SEP_BUTTON_Y;
121     }
122 
123     size_t const nButtonCount = m_ItemList.size();
124 
125     if ( GetStyle() & WB_HORZ )
126         mnButtonSize  = nSepSize + (nButtonCount*maCtrlSize.Width());
127     else
128         mnButtonSize = nSepSize + (nButtonCount*maCtrlSize.Height());
129 
130     return mnButtonSize;
131 }
132 
ImplPosControls()133 void ButtonDialog::ImplPosControls()
134 {
135     if ( !mbFormat )
136         return;
137 
138     // Create PushButtons and determine Sizes
139     ImplGetButtonSize();
140 
141     // determine dialog size
142     Size            aDlgSize = maPageSize;
143     tools::Long            nX;
144     tools::Long            nY;
145     if ( GetStyle() & WB_HORZ )
146     {
147         if ( mnButtonSize+(IMPL_DIALOG_OFFSET*2) > aDlgSize.Width() )
148             aDlgSize.setWidth( mnButtonSize+(IMPL_DIALOG_OFFSET*2) );
149         if ( GetStyle() & WB_LEFT )
150             nX = IMPL_DIALOG_OFFSET;
151         else if ( GetStyle() & WB_RIGHT )
152             nX = aDlgSize.Width()-mnButtonSize-IMPL_DIALOG_OFFSET;
153         else
154             nX = (aDlgSize.Width()-mnButtonSize)/2;
155 
156         aDlgSize.AdjustHeight(IMPL_DIALOG_OFFSET+maCtrlSize.Height() );
157         nY = aDlgSize.Height()-maCtrlSize.Height()-IMPL_DIALOG_OFFSET;
158     }
159     else
160     {
161         if ( mnButtonSize+(IMPL_DIALOG_OFFSET*2) > aDlgSize.Height() )
162             aDlgSize.setHeight( mnButtonSize+(IMPL_DIALOG_OFFSET*2) );
163         if ( GetStyle() & WB_BOTTOM )
164             nY = aDlgSize.Height()-mnButtonSize-IMPL_DIALOG_OFFSET;
165         else if ( GetStyle() & WB_VCENTER )
166             nY = (aDlgSize.Height()-mnButtonSize)/2;
167         else
168             nY = IMPL_DIALOG_OFFSET;
169 
170         aDlgSize.AdjustWidth(IMPL_DIALOG_OFFSET+maCtrlSize.Width() );
171         nX = aDlgSize.Width()-maCtrlSize.Width()-IMPL_DIALOG_OFFSET;
172     }
173 
174     // Arrange PushButtons
175     for (auto & it : m_ItemList)
176     {
177         if ( GetStyle() & WB_HORZ )
178             nX += it->mnSepSize;
179         else
180             nY += it->mnSepSize;
181 
182         it->mpPushButton->SetPosSizePixel( Point( nX, nY ), maCtrlSize );
183         it->mpPushButton->Show();
184 
185         if ( GetStyle() & WB_HORZ )
186             nX += maCtrlSize.Width()+IMPL_SEP_BUTTON_X;
187         else
188             nY += maCtrlSize.Height()+IMPL_SEP_BUTTON_Y;
189     }
190 
191     SetOutputSizePixel(aDlgSize);
192     SetMinOutputSizePixel(aDlgSize);
193 
194     mbFormat = false;
195 }
196 
IMPL_LINK(ButtonDialog,ImplClickHdl,Button *,pBtn,void)197 IMPL_LINK( ButtonDialog, ImplClickHdl, Button*, pBtn, void )
198 {
199     for (const auto & it : m_ItemList)
200     {
201         if ( it->mpPushButton == pBtn )
202         {
203             mnCurButtonId = it->mnId;
204             if ( IsInExecute() )
205                 EndDialog( mnCurButtonId );
206             break;
207         }
208     }
209 }
210 
Resize()211 void ButtonDialog::Resize()
212 {
213 }
214 
StateChanged(StateChangedType nType)215 void ButtonDialog::StateChanged( StateChangedType nType )
216 {
217     if ( nType == StateChangedType::InitShow )
218     {
219         ImplPosControls();
220         for (auto & it : m_ItemList)
221         {
222             if ( it->mpPushButton && it->mbOwnButton )
223                 it->mpPushButton->SetZOrder(nullptr, ZOrderFlags::Last);
224         }
225 
226         // Set focus on default button.
227         if ( mnFocusButtonId != BUTTONDIALOG_BUTTON_NOTFOUND )
228         {
229             for (auto & it : m_ItemList)
230             {
231                 if (it->mnId == mnFocusButtonId )
232                 {
233                     if (it->mpPushButton->IsVisible())
234                         it->mpPushButton->GrabFocus();
235 
236                     break;
237                 }
238             }
239         }
240     }
241 
242     Dialog::StateChanged( nType );
243 }
244 
AddButton(StandardButtonType eType,sal_uInt16 nId,ButtonDialogFlags nBtnFlags,tools::Long nSepPixel)245 void ButtonDialog::AddButton( StandardButtonType eType, sal_uInt16 nId,
246                               ButtonDialogFlags nBtnFlags, tools::Long nSepPixel )
247 {
248     // PageItem anlegen
249     std::unique_ptr<ImplBtnDlgItem> pItem(new ImplBtnDlgItem);
250     pItem->mnId             = nId;
251     pItem->mbOwnButton      = true;
252     pItem->mnSepSize        = nSepPixel;
253 
254     if ( eType == StandardButtonType::OK )
255         nBtnFlags |= ButtonDialogFlags::OK;
256     else if ( eType == StandardButtonType::Help )
257         nBtnFlags |= ButtonDialogFlags::Help;
258     else if ( (eType == StandardButtonType::Cancel) || (eType == StandardButtonType::Close) )
259         nBtnFlags |= ButtonDialogFlags::Cancel;
260     pItem->mpPushButton = ImplCreatePushButton( nBtnFlags );
261 
262     // Standard-Buttons have the right text already
263     if ( !((eType == StandardButtonType::OK     && pItem->mpPushButton->GetType() == WindowType::OKBUTTON) ||
264            (eType == StandardButtonType::Cancel && pItem->mpPushButton->GetType() == WindowType::CANCELBUTTON) ||
265            (eType == StandardButtonType::Help   && pItem->mpPushButton->GetType() == WindowType::HELPBUTTON)) )
266     {
267         std::map<StandardButtonType, OUString> mapButtonTypeToID = {{StandardButtonType::Yes, "yes"},
268             {StandardButtonType::No, "no"}, {StandardButtonType::Retry, "retry"},
269             {StandardButtonType::Close, "close"}, {StandardButtonType::More, "more"},
270             {StandardButtonType::Ignore, "ignore"}, {StandardButtonType::Abort, "abort"},
271             {StandardButtonType::Less, "less"}, {StandardButtonType::Count, "count"}};
272         auto itr = mapButtonTypeToID.find(eType);
273         if (itr != mapButtonTypeToID.end())
274             pItem->mpPushButton->set_id(itr->second);
275         pItem->mpPushButton->SetText( GetStandardText( eType ) );
276     }
277 
278     if ( nBtnFlags & ButtonDialogFlags::Focus )
279         mnFocusButtonId = nId;
280 
281     m_ItemList.push_back(std::move(pItem));
282 
283     mbFormat = true;
284 }
285 
RemoveButton(sal_uInt16 nId)286 void ButtonDialog::RemoveButton( sal_uInt16 nId )
287 {
288     auto it = std::find_if(m_ItemList.begin(), m_ItemList.end(),
289         [&nId](const std::unique_ptr<ImplBtnDlgItem>& rItem) { return rItem->mnId == nId; });
290     if (it != m_ItemList.end())
291     {
292         (*it)->mpPushButton->Hide();
293         if ((*it)->mbOwnButton)
294             (*it)->mpPushButton.disposeAndClear();
295         else
296             (*it)->mpPushButton.clear();
297         m_ItemList.erase(it);
298         return;
299     }
300 
301     SAL_WARN( "vcl.window", "ButtonDialog::RemoveButton(): ButtonId invalid" );
302 }
303 
304 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
305