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