1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <vcl/fixed.hxx>
21 #include <vcl/layout.hxx>
22 #include <vcl/tabctrl.hxx>
23 #include <vcl/tabdlg.hxx>
24 #include <vcl/tabpage.hxx>
27 void TabDialog::ImplInitTabDialogData()
29 mpFixedLine
= nullptr;
30 mpViewWindow
= nullptr;
31 meViewAlign
= WindowAlign::Left
;
35 void TabDialog::ImplPosControls()
37 if (isLayoutEnabled())
40 Size
aCtrlSize( IMPL_MINSIZE_BUTTON_WIDTH
, IMPL_MINSIZE_BUTTON_HEIGHT
);
43 vcl::Window
* pTabControl
= nullptr;
45 vcl::Window
* pChild
= GetWindow( GetWindowType::FirstChild
);
48 if ( pChild
->IsVisible() && (pChild
!= mpViewWindow
) )
50 if (pChild
->GetType() == WINDOW_TABCONTROL
|| isContainerWindow(*pChild
))
52 else if ( pTabControl
)
54 Size
aOptimalSize(pChild
->get_preferred_size());
55 long nTxtWidth
= aOptimalSize
.Width();
56 if ( nTxtWidth
> aCtrlSize
.Width() )
57 aCtrlSize
.Width() = nTxtWidth
;
58 long nTxtHeight
= aOptimalSize
.Height();
59 if ( nTxtHeight
> aCtrlSize
.Height() )
60 aCtrlSize
.Height() = nTxtHeight
;
65 long nHeight
= pChild
->GetSizePixel().Height();
66 if ( nHeight
> nOffY
)
71 pChild
= pChild
->GetWindow( GetWindowType::Next
);
74 // do we have a TabControl ?
77 // adapt offset for other controls by an extra distance
79 nOffY
+= IMPL_DIALOG_BAR_OFFSET
*2 + 2;
81 Point
aTabOffset( IMPL_DIALOG_OFFSET
, IMPL_DIALOG_OFFSET
+nOffY
);
83 if (isContainerWindow(*pTabControl
))
84 pTabControl
->SetSizePixel(pTabControl
->get_preferred_size());
86 Size aTabSize
= pTabControl
->GetSizePixel();
88 Size
aDlgSize( aTabSize
.Width() + IMPL_DIALOG_OFFSET
*2,
89 aTabSize
.Height() + IMPL_DIALOG_OFFSET
*2 + nOffY
);
92 // consider preview window and adapt the sizes/offsets
93 if ( mpViewWindow
&& mpViewWindow
->IsVisible() )
99 PosSizeFlags nViewPosFlags
= PosSizeFlags::Pos
;
100 Size aViewSize
= mpViewWindow
->GetSizePixel();
101 if ( meViewAlign
== WindowAlign::Top
)
103 nViewOffX
= aTabOffset
.X();
104 nViewOffY
= nOffY
+IMPL_DIALOG_OFFSET
;
105 nViewWidth
= aTabSize
.Width();
106 nViewPosFlags
|= PosSizeFlags::Width
;
107 aTabOffset
.Y() += aViewSize
.Height()+IMPL_DIALOG_OFFSET
;
108 aDlgSize
.Height() += aViewSize
.Height()+IMPL_DIALOG_OFFSET
;
110 else if ( meViewAlign
== WindowAlign::Bottom
)
112 nViewOffX
= aTabOffset
.X();
113 nViewOffY
= aTabOffset
.Y()+aTabSize
.Height()+IMPL_DIALOG_OFFSET
;
114 nViewWidth
= aTabSize
.Width();
115 nViewPosFlags
|= PosSizeFlags::Width
;
116 aDlgSize
.Height() += aViewSize
.Height()+IMPL_DIALOG_OFFSET
;
118 else if ( meViewAlign
== WindowAlign::Right
)
120 nViewOffX
= aTabOffset
.X()+aTabSize
.Width()+IMPL_DIALOG_OFFSET
;
121 nViewOffY
= aTabOffset
.Y();
122 nViewHeight
= aTabSize
.Height();
123 nViewPosFlags
|= PosSizeFlags::Height
;
124 aDlgSize
.Width() += aViewSize
.Width()+IMPL_DIALOG_OFFSET
;
125 nBtnEx
= aViewSize
.Width()+IMPL_DIALOG_OFFSET
;
127 else // meViewAlign == WindowAlign::Left
129 nViewOffX
= IMPL_DIALOG_OFFSET
;
130 nViewOffY
= aTabOffset
.Y();
131 nViewHeight
= aTabSize
.Height();
132 nViewPosFlags
|= PosSizeFlags::Height
;
133 aTabOffset
.X() += aViewSize
.Width()+IMPL_DIALOG_OFFSET
;
134 aDlgSize
.Width() += aViewSize
.Width()+IMPL_DIALOG_OFFSET
;
135 nBtnEx
= aViewSize
.Width()+IMPL_DIALOG_OFFSET
;
138 mpViewWindow
->setPosSizePixel( nViewOffX
, nViewOffY
,
139 nViewWidth
, nViewHeight
,
144 pTabControl
->SetPosPixel( aTabOffset
);
146 // position all other Children
147 bool bTabCtrl
= false;
150 long nY
= aDlgSize
.Height();
151 long nTopX
= IMPL_DIALOG_OFFSET
;
153 // all buttons are right aligned under Windows 95
154 nX
= IMPL_DIALOG_OFFSET
;
155 long nCtrlBarWidth
= ((aCtrlSize
.Width()+IMPL_DIALOG_OFFSET
)*nDownCtrl
)-IMPL_DIALOG_OFFSET
;
156 if ( nCtrlBarWidth
<= (aTabSize
.Width()+nBtnEx
) )
157 nX
= (aTabSize
.Width()+nBtnEx
) - nCtrlBarWidth
+ IMPL_DIALOG_OFFSET
;
159 vcl::Window
* pChild2
= GetWindow( GetWindowType::FirstChild
);
162 if ( pChild2
->IsVisible() && (pChild2
!= mpViewWindow
) )
164 if ( pChild2
== pTabControl
)
171 if ( nX
+aCtrlSize
.Width()-IMPL_DIALOG_OFFSET
> (aTabSize
.Width()+nBtnEx
) )
173 nY
+= aCtrlSize
.Height()+IMPL_DIALOG_OFFSET
;
174 nX
= IMPL_DIALOG_OFFSET
;
178 pChild2
->SetPosSizePixel( Point( nX
, nY
), aCtrlSize
);
179 nX
+= aCtrlSize
.Width()+IMPL_DIALOG_OFFSET
;
183 Size aChildSize
= pChild2
->GetSizePixel();
184 pChild2
->SetPosPixel( Point( nTopX
, (nOffY
-aChildSize
.Height())/2 ) );
185 nTopX
+= aChildSize
.Width()+2;
189 pChild2
= pChild2
->GetWindow( GetWindowType::Next
);
192 aDlgSize
.Height() += nLines
* (aCtrlSize
.Height()+IMPL_DIALOG_OFFSET
);
193 SetOutputSizePixel( aDlgSize
);
199 Size aDlgSize
= GetOutputSizePixel();
201 mpFixedLine
= VclPtr
<FixedLine
>::Create( this );
202 mpFixedLine
->SetPosSizePixel( Point( 0, nOffY
),
203 Size( aDlgSize
.Width(), 2 ) );
207 mbPosControls
= false;
210 TabDialog::TabDialog( vcl::Window
* pParent
, WinBits nStyle
) :
211 Dialog( WINDOW_TABDIALOG
)
213 ImplInitTabDialogData();
214 ImplInit( pParent
, nStyle
);
217 TabDialog::TabDialog( vcl::Window
* pParent
, const OUString
& rID
, const OUString
& rUIXMLDescription
) :
218 Dialog(pParent
, rID
, rUIXMLDescription
, WINDOW_TABDIALOG
)
220 ImplInitTabDialogData();
223 TabDialog::~TabDialog()
228 void TabDialog::dispose()
230 mpFixedLine
.disposeAndClear();
231 mpViewWindow
.clear();
235 void TabDialog::StateChanged( StateChangedType nType
)
237 if ( nType
== StateChangedType::InitShow
)
239 // Calculate the Layout only for the initialized state
243 Dialog::StateChanged( nType
);
246 vcl::Window
* findTabControl(vcl::Window
* pCurrent
)
253 if (pCurrent
->GetType() == WINDOW_TABCONTROL
)
258 vcl::Window
* pChild
= pCurrent
->GetWindow(GetWindowType::FirstChild
);
263 vcl::Window
* pInorderChild
= findTabControl(pChild
);
267 return pInorderChild
;
270 pChild
= pChild
->GetWindow(GetWindowType::Next
);
276 std::vector
<OString
> TabDialog::getAllPageUIXMLDescriptions() const
278 std::vector
<OString
> aRetval
;
280 const TabControl
* pTabCtrl
= dynamic_cast<TabControl
*>(findTabControl(const_cast<TabDialog
*>(this)));
284 for (sal_uInt16
a(0); a
< pTabCtrl
->GetPageCount(); a
++)
286 const sal_uInt16
nPageId(pTabCtrl
->GetPageId(a
));
288 if (TAB_PAGE_NOTFOUND
!= nPageId
)
290 TabPage
* pCandidate
= pTabCtrl
->GetTabPage(nPageId
);
294 OString
aNewName(pCandidate
->getUIFile());
296 if (!aNewName
.isEmpty())
298 // we have to check for double entries, this may happen e.g.
299 // in the HeaderFooterDialog which has two times the same
300 // tabPage added. Add the PageID as hint to the name, separated
301 // by a token (using "|" here). Do not do this for 1st ocurrence,
302 // that is used for detection and is not necessary.
303 // Use the UIXMLDescription without trailing '.ui', with one trailing '/'
304 bool bAlreadyAdded(false);
306 for (auto i
= aRetval
.begin(); !bAlreadyAdded
&& i
!= aRetval
.end(); i
++)
308 bAlreadyAdded
= (*i
== aNewName
);
313 // add the PageId to be able to detect the correct tabPage in
314 // selectPageByUIXMLDescription below
315 aNewName
= aNewName
+ "|" + OString::number(nPageId
);
318 aRetval
.push_back(aNewName
);
328 bool TabDialog::selectPageByUIXMLDescription(const OString
& rUIXMLDescription
)
330 TabControl
* pTabCtrl
= dynamic_cast<TabControl
*>(findTabControl(this));
334 sal_uInt32
nTargetPageId(0);
335 OString
aTargetName(rUIXMLDescription
);
336 const sal_Int32
nIndexOfSeparator(rUIXMLDescription
.indexOf("|"));
338 if (-1 != nIndexOfSeparator
)
340 // more than one tabPage with that UXMLDescription is added to this dialog,
341 // see getAllPageUIXMLDescriptions() above. Extract target PageId and
342 // strip the UXMLDescription name for comparison
343 nTargetPageId
= rUIXMLDescription
.copy(nIndexOfSeparator
+ 1).toUInt32();
344 aTargetName
= rUIXMLDescription
.copy(0, nIndexOfSeparator
);
347 for (sal_uInt16
a(0); a
< pTabCtrl
->GetPageCount(); a
++)
349 const sal_uInt16
nPageId(pTabCtrl
->GetPageId(a
));
351 if (TAB_PAGE_NOTFOUND
!= nPageId
)
353 TabPage
* pCandidate
= pTabCtrl
->GetTabPage(nPageId
);
357 if (pCandidate
->getUIFile() == aTargetName
)
361 // when multiple versions may exist, name is not sufficient. Also
362 // check for the given PageId to select the correct tabPage
363 // for cases where the same TabPage is used more than once
364 // in a tabDialog (e.g. HeaderFooterDialog)
365 if (nTargetPageId
== nPageId
)
367 pTabCtrl
->SelectTabPage(nPageId
);
373 // select that tabPage
374 pTabCtrl
->SelectTabPage(nPageId
);
386 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */