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 <comphelper/string.hxx>
21 #include <vcl/svapp.hxx>
22 #include <vcl/weld.hxx>
23 #include <svl/eitem.hxx>
24 #include <svl/intitem.hxx>
25 #include <svl/style.hxx>
26 #include <osl/diagnose.h>
28 #include <sfx2/styfitem.hxx>
29 #include <sfx2/styledlg.hxx>
30 #include <sfx2/tabdlg.hxx>
31 #include <sfx2/app.hxx>
32 #include <sfx2/objsh.hxx>
33 #include <sfx2/sfxresid.hxx>
34 #include <sfx2/module.hxx>
35 #include <sfx2/sfxsids.hrc>
37 #include <sfx2/strings.hrc>
39 #include <svl/stritem.hxx>
40 #include <sfx2/dispatch.hxx>
42 #include "mgetempl.hxx"
44 /* SfxManageStyleSheetPage Constructor
46 * initializes the list box with the templates
48 SfxManageStyleSheetPage::SfxManageStyleSheetPage(weld::Container
* pPage
, weld::DialogController
* pController
, const SfxItemSet
& rAttrSet
)
49 : SfxTabPage(pPage
, pController
, "sfx/ui/managestylepage.ui", "ManageStylePage", &rAttrSet
)
50 , pStyle(&static_cast<SfxStyleDialogController
*>(pController
)->GetStyleSheet())
53 , aName(pStyle
->GetName())
54 , aFollow(pStyle
->GetFollow())
55 , aParent(pStyle
->GetParent())
56 , nFlags(pStyle
->GetMask())
57 , m_xName(m_xBuilder
->weld_entry("name"))
58 , m_xAutoCB(m_xBuilder
->weld_check_button("autoupdate"))
59 , m_xFollowFt(m_xBuilder
->weld_label("nextstyleft"))
60 , m_xFollowLb(m_xBuilder
->weld_combo_box("nextstyle"))
61 , m_xEditStyleBtn(m_xBuilder
->weld_button("editstyle"))
62 , m_xBaseFt(m_xBuilder
->weld_label("linkedwithft"))
63 , m_xBaseLb(m_xBuilder
->weld_combo_box("linkedwith"))
64 , m_xEditLinkStyleBtn(m_xBuilder
->weld_button("editlinkstyle"))
65 , m_xFilterFt(m_xBuilder
->weld_label("categoryft"))
66 , m_xFilterLb(m_xBuilder
->weld_combo_box("category"))
67 , m_xDescFt(m_xBuilder
->weld_label("desc"))
68 , m_xNameFt(m_xBuilder
->weld_label("nameft"))
70 m_xFollowLb
->make_sorted();
71 // tdf#120188 like SwCharURLPage limit the width of the style combos
72 const int nMaxWidth(m_xFollowLb
->get_approximate_digit_width() * 50);
73 m_xFollowLb
->set_size_request(nMaxWidth
, -1);
74 m_xBaseLb
->make_sorted();
75 m_xBaseLb
->set_size_request(nMaxWidth
, -1);
76 //note that the code depends on categories not being lexically
77 //sorted, so if it's changed to sorted, the code needs to
78 //be adapted to be position unaware
79 m_xFilterLb
->set_size_request(nMaxWidth
, -1);
81 // this Page needs ExchangeSupport
84 if ( aFollow
.isEmpty() || aFollow
== aName
)
85 m_xEditStyleBtn
->set_sensitive(false);
87 m_xEditStyleBtn
->set_sensitive(true);
89 int linkSelectPos
= m_xBaseLb
->get_active();
90 if ( linkSelectPos
== 0 )
91 m_xEditLinkStyleBtn
->set_sensitive(false);
93 m_xEditLinkStyleBtn
->set_sensitive(true);
95 mxFamilies
= SfxApplication::GetModule_Impl()->CreateStyleFamilies();
97 SfxStyleSheetBasePool
* pPool
= nullptr;
98 SfxObjectShell
* pDocShell
= SfxObjectShell::Current();
101 pPool
= pDocShell
->GetStyleSheetPool();
102 OSL_ENSURE( pPool
, "no Pool or no DocShell" );
106 pPool
->First(pStyle
->GetFamily()); // for SW - update internal list
109 if ( pStyle
->GetName().isEmpty() && pPool
)
111 // NullString as Name -> generate Name
112 OUString
aNoName(SfxStyleDialogController::GenerateUnusedName(*pPool
, pStyle
->GetFamily()));
113 pStyle
->SetName( aNoName
);
115 aFollow
= pStyle
->GetFollow();
116 aParent
= pStyle
->GetParent();
118 m_xName
->set_text(pStyle
->GetName());
120 // Set the field read-only if it is NOT an user-defined style
121 // but allow selecting and copying
122 if (pStyle
->IsUserDefined())
124 m_xName
->set_can_focus(true);
125 m_xName
->set_editable(true);
126 m_xName
->set_sensitive(true);
127 m_xName
->grab_focus(); // tdf#142017 default to focus within the page, not in notebook tab
131 m_xName
->set_sensitive(false);
134 if ( pStyle
->HasFollowSupport() && pPool
)
136 SfxStyleSheetBase
* pPoolStyle
= pPool
->First(pStyle
->GetFamily());
138 m_xFollowLb
->freeze();
142 m_xFollowLb
->append_text(pPoolStyle
->GetName());
143 pPoolStyle
= pPool
->Next();
146 // A new Template is not yet in the Pool
147 if (m_xFollowLb
->find_text(pStyle
->GetName()) == -1)
148 m_xFollowLb
->append_text(pStyle
->GetName());
154 m_xFollowFt
->set_sensitive(false);
156 m_xFollowLb
->set_sensitive(false);
158 m_xEditStyleBtn
->hide();
161 if ( pStyle
->HasParentSupport() && pPool
)
165 if ( pStyle
->HasClearParentSupport() )
166 // the base template can be set to NULL
167 m_xBaseLb
->append_text(SfxResId(STR_NONE
));
169 SfxStyleSheetBase
* pPoolStyle
= pPool
->First(pStyle
->GetFamily());
173 const OUString
aStr( pPoolStyle
->GetName() );
174 // own name as base template
176 m_xBaseLb
->append_text(aStr
);
177 pPoolStyle
= pPool
->Next();
184 m_xBaseFt
->set_sensitive(false);
185 m_xBaseLb
->set_sensitive(false);
188 size_t nCount
= mxFamilies
->size();
190 for ( i
= 0; i
< nCount
; ++i
)
192 pItem
= &(mxFamilies
->at(i
));
194 if ( pItem
->GetFamily() == pStyle
->GetFamily() )
200 sal_uInt16 nStyleFilterIdx
= 0xffff;
202 const SfxStyleFilter
& rList
= pItem
->GetFilterList();
203 nCount
= rList
.size();
205 SfxStyleSearchBits nMask
= pStyle
->GetMask() & ~SfxStyleSearchBits::UserDefined
;
207 if ( nMask
== SfxStyleSearchBits::Auto
) // User Template?
208 nMask
= pStyle
->GetMask();
210 for ( i
= 0; i
< nCount
; ++i
)
212 const SfxFilterTuple
& rTupel
= rList
[ i
];
214 if ( rTupel
.nFlags
!= SfxStyleSearchBits::Auto
&&
215 rTupel
.nFlags
!= SfxStyleSearchBits::Used
&&
216 rTupel
.nFlags
!= SfxStyleSearchBits::AllVisible
&&
217 rTupel
.nFlags
!= SfxStyleSearchBits::All
)
219 OUString
sId(OUString::number(i
));
220 m_xFilterLb
->insert(nIdx
, rTupel
.aName
, &sId
, nullptr, nullptr);
221 if ( ( rTupel
.nFlags
& nMask
) == nMask
)
222 nStyleFilterIdx
= nIdx
;
227 if ( nStyleFilterIdx
!= 0xFFFF )
228 m_xFilterLb
->set_active(nStyleFilterIdx
);
231 if ( !m_xFilterLb
->get_count() || !pStyle
->IsUserDefined() )
234 m_xFilterFt
->set_sensitive(false);
235 m_xFilterLb
->set_sensitive(false);
238 m_xFilterLb
->save_value();
239 SetDescriptionText_Impl();
241 if (m_xFollowLb
->get_sensitive() || m_xBaseLb
->get_sensitive())
243 m_xName
->connect_focus_in(
244 LINK( this, SfxManageStyleSheetPage
, GetFocusHdl
) );
245 m_xName
->connect_focus_out(
246 LINK( this, SfxManageStyleSheetPage
, LoseFocusHdl
) );
248 // It is a style with auto update? (SW only)
249 if(SfxItemState::SET
== rAttrSet
.GetItemState(SID_ATTR_AUTO_STYLE_UPDATE
))
251 m_xFollowLb
->connect_changed(LINK(this, SfxManageStyleSheetPage
, EditStyleSelectHdl_Impl
));
252 m_xBaseLb
->connect_changed(LINK(this, SfxManageStyleSheetPage
, EditLinkStyleSelectHdl_Impl
));
253 m_xEditStyleBtn
->connect_clicked(LINK(this, SfxManageStyleSheetPage
, EditStyleHdl_Impl
));
254 m_xEditLinkStyleBtn
->connect_clicked(LINK(this, SfxManageStyleSheetPage
, EditLinkStyleHdl_Impl
));
257 SfxManageStyleSheetPage::~SfxManageStyleSheetPage()
264 void SfxManageStyleSheetPage::UpdateName_Impl( weld::ComboBox
* pBox
,
265 const OUString
& rNew
)
269 After the change of a template name update the ListBox pBox
273 ListBox* pBox ListBox, whose entries are to be updated
274 const String& rNew the new Name
278 if (pBox
->get_sensitive())
280 // it is the current entry, which name was modified
281 const bool bSelect
= pBox
->get_active_text() == aBuf
;
282 int nOldIndex
= pBox
->find_text(aBuf
);
284 pBox
->remove(nOldIndex
);
285 pBox
->append_text(rNew
);
288 pBox
->set_active_text(rNew
);
292 void SfxManageStyleSheetPage::SetDescriptionText_Impl()
296 Set attribute description. Get the set metric for this.
300 MapUnit eUnit
= MapUnit::MapCM
;
301 FieldUnit
eFieldUnit( FieldUnit::CM
);
302 SfxModule
* pModule
= SfxModule::GetActiveModule();
305 const SfxPoolItem
* pPoolItem
= pModule
->GetItem( SID_ATTR_METRIC
);
307 eFieldUnit
= static_cast<FieldUnit
>(static_cast<const SfxUInt16Item
*>( pPoolItem
)->GetValue());
310 switch ( eFieldUnit
)
312 case FieldUnit::MM
: eUnit
= MapUnit::MapMM
; break;
315 case FieldUnit::KM
: eUnit
= MapUnit::MapCM
; break;
316 case FieldUnit::POINT
:
317 case FieldUnit::PICA
: eUnit
= MapUnit::MapPoint
; break;
318 case FieldUnit::INCH
:
319 case FieldUnit::FOOT
:
320 case FieldUnit::MILE
: eUnit
= MapUnit::MapInch
; break;
323 OSL_FAIL( "non supported field unit" );
325 m_xDescFt
->set_label(pStyle
->GetDescription(eUnit
));
328 IMPL_LINK_NOARG(SfxManageStyleSheetPage
, EditStyleSelectHdl_Impl
, weld::ComboBox
&, void)
330 OUString
aTemplName(m_xFollowLb
->get_active_text());
331 OUString
aEditTemplName(m_xName
->get_text());
332 m_xEditStyleBtn
->set_sensitive(aTemplName
!= aEditTemplName
);
335 IMPL_LINK_NOARG(SfxManageStyleSheetPage
, EditStyleHdl_Impl
, weld::Button
&, void)
337 OUString
aTemplName(m_xFollowLb
->get_active_text());
338 Execute_Impl(SID_STYLE_EDIT
, aTemplName
, static_cast<sal_uInt16
>(pStyle
->GetFamily()));
341 IMPL_LINK_NOARG(SfxManageStyleSheetPage
, EditLinkStyleSelectHdl_Impl
, weld::ComboBox
&, void)
343 int linkSelectPos
= m_xBaseLb
->get_active();
344 if ( linkSelectPos
== 0 )
345 m_xEditLinkStyleBtn
->set_sensitive(false);
347 m_xEditLinkStyleBtn
->set_sensitive(true);
350 IMPL_LINK_NOARG(SfxManageStyleSheetPage
, EditLinkStyleHdl_Impl
, weld::Button
&, void)
352 OUString
aTemplName(m_xBaseLb
->get_active_text());
353 if (aTemplName
!= SfxResId(STR_NONE
))
354 Execute_Impl( SID_STYLE_EDIT
, aTemplName
, static_cast<sal_uInt16
>(pStyle
->GetFamily()) );
357 // Internal: Perform functions through the Dispatcher
358 bool SfxManageStyleSheetPage::Execute_Impl(
359 sal_uInt16 nId
, const OUString
&rStr
, sal_uInt16 nFamily
)
362 SfxDispatcher
&rDispatcher
= *SfxGetpApp()->GetDispatcher_Impl();
363 SfxStringItem
aItem(nId
, rStr
);
364 SfxUInt16Item
aFamily(SID_STYLE_FAMILY
, nFamily
);
365 const SfxPoolItem
* pItems
[ 6 ];
366 sal_uInt16 nCount
= 0;
367 if( !rStr
.isEmpty() )
368 pItems
[ nCount
++ ] = &aItem
;
369 pItems
[ nCount
++ ] = &aFamily
;
371 pItems
[ nCount
++ ] = nullptr;
373 const SfxPoolItem
* pItem
= rDispatcher
.Execute(
374 nId
, SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
,
377 return pItem
!= nullptr;
381 IMPL_LINK(SfxManageStyleSheetPage
, GetFocusHdl
, weld::Widget
&, rControl
, void)
385 StarView Handler; GetFocus-Handler of the Edits with the template name.
389 weld::Entry
& rEdit
= dynamic_cast<weld::Entry
&>(rControl
);
390 aBuf
= comphelper::string::stripStart(rEdit
.get_text(), ' ');
393 IMPL_LINK(SfxManageStyleSheetPage
, LoseFocusHdl
, weld::Widget
&, rControl
, void)
397 StarView Handler; lose-focus-handler of the edits of the template name.
398 This will update the listbox with the subsequent templates. The current
399 template itself is not returned in the listbox of the base templates.
403 weld::Entry
& rEdit
= dynamic_cast<weld::Entry
&>(rControl
);
404 const OUString
aStr(comphelper::string::stripStart(rEdit
.get_text(), ' '));
405 rEdit
.set_text(aStr
);
406 // Update the Listbox of the base template if possible
408 UpdateName_Impl(m_xFollowLb
.get(), aStr
);
411 bool SfxManageStyleSheetPage::FillItemSet( SfxItemSet
* rSet
)
415 Handler for setting the (modified) data. I called from the OK of the
420 SfxItemSet &rAttrSet The set, which receives the data.
424 sal_Bool sal_True: The data had been changed
425 sal_False: The data had not been changed
433 const int nFilterIdx
= m_xFilterLb
->get_active();
437 if ( nFilterIdx
!= -1 &&
438 m_xFilterLb
->get_value_changed_from_saved() &&
439 m_xFilterLb
->get_sensitive() )
442 OSL_ENSURE( pItem
, "No Item" );
443 // is only possibly for user templates
444 SfxStyleSearchBits nMask
= pItem
->GetFilterList()[m_xFilterLb
->get_id(nFilterIdx
).toUInt32()].nFlags
| SfxStyleSearchBits::UserDefined
;
445 pStyle
->SetMask( nMask
);
447 if (m_xAutoCB
->get_visible() && m_xAutoCB
->get_state_changed_from_saved())
449 rSet
->Put(SfxBoolItem(SID_ATTR_AUTO_STYLE_UPDATE
, m_xAutoCB
->get_active()));
456 void SfxManageStyleSheetPage::Reset( const SfxItemSet
* /*rAttrSet*/ )
460 Handler to initialize the page with the initial data.
464 const SfxItemSet &rAttrSet The data set
473 OUString
sCmp( pStyle
->GetName() );
476 pStyle
->SetName( aName
);
477 m_xName
->set_text( aName
);
478 if (m_xName
->get_editable())
479 m_xName
->select_region(0, -1);
481 if ( m_xFollowLb
->get_sensitive() )
483 sCmp
= pStyle
->GetFollow();
485 if ( sCmp
!= aFollow
)
486 pStyle
->SetFollow( aFollow
);
488 if ( aFollow
.isEmpty() )
490 m_xFollowLb
->set_active_text( aName
);
491 m_xEditStyleBtn
->set_sensitive( false );
494 m_xFollowLb
->set_active_text( aFollow
);
497 if (m_xBaseLb
->get_sensitive())
499 sCmp
= pStyle
->GetParent();
501 if ( sCmp
!= aParent
)
502 pStyle
->SetParent( aParent
);
504 if ( aParent
.isEmpty() )
506 m_xBaseLb
->set_active_text( SfxResId(STR_NONE
) );
507 m_xEditLinkStyleBtn
->set_sensitive( false );
510 m_xBaseLb
->set_active_text( aParent
);
512 if ( SfxResId(STR_STANDARD
) == aName
)
514 // the default template can not be linked
515 m_xBaseFt
->set_sensitive(false);
516 m_xBaseLb
->set_sensitive(false);
520 m_xEditLinkStyleBtn
->set_sensitive( false );
522 if (m_xFilterLb
->get_sensitive())
524 SfxStyleSearchBits nCmp
= pStyle
->GetMask();
526 if ( nCmp
!= nFlags
)
527 pStyle
->SetMask( nFlags
);
528 m_xFilterLb
->set_active_text(m_xFilterLb
->get_saved_value());
532 std::unique_ptr
<SfxTabPage
> SfxManageStyleSheetPage::Create( weld::Container
* pPage
, weld::DialogController
* pController
,
533 const SfxItemSet
*rAttrSet
)
535 return std::make_unique
<SfxManageStyleSheetPage
>(pPage
, pController
, *rAttrSet
);
538 void SfxManageStyleSheetPage::ActivatePage( const SfxItemSet
& rSet
)
542 ActivatePage handler of SfxTabDialog, is used for the update of the
543 descriptive text, since this might have changed through changes of data on
548 const SfxItemSet& the set for the exchange of data; is not used here.
552 <SfxTabDialog::ActivatePage(const SfxItemSet &)>
556 SetDescriptionText_Impl();
558 // It is a style with auto update? (SW only)
559 const SfxPoolItem
* pPoolItem
;
561 if ( SfxItemState::SET
==
562 rSet
.GetItemState( SID_ATTR_AUTO_STYLE_UPDATE
, false, &pPoolItem
) )
563 m_xAutoCB
->set_active(static_cast<const SfxBoolItem
*>(pPoolItem
)->GetValue());
564 m_xAutoCB
->save_state();
565 m_xName
->save_value();
568 DeactivateRC
SfxManageStyleSheetPage::DeactivatePage( SfxItemSet
* pItemSet
)
572 DeactivatePage-handler of SfxTabDialog; data is set on the template, so
573 that the correct inheritance on the other pages of the dialog is made.
574 If an error occurs, leaving the page is prevented.
577 SfxItemSet* the set for the exchange of data; is not used here.
581 <SfxTabDialog::DeactivatePage(SfxItemSet*)>
585 DeactivateRC nRet
= DeactivateRC::LeavePage
;
587 if (m_xName
->get_value_changed_from_saved())
589 // By pressing <Enter> LoseFocus() is not triggered through StarView
590 if (m_xName
->has_focus())
591 LoseFocusHdl( *m_xName
);
593 if (!pStyle
->SetName(comphelper::string::stripStart(m_xName
->get_text(), ' ')))
595 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(GetFrameWeld(),
596 VclMessageType::Info
, VclButtonsType::Ok
,
597 SfxResId(STR_TABPAGE_INVALIDNAME
)));
599 m_xName
->grab_focus();
600 m_xName
->select_region(0, -1);
601 return DeactivateRC::KeepPage
;
606 if (pStyle
->HasFollowSupport() && m_xFollowLb
->get_sensitive())
608 const OUString
aFollowEntry( m_xFollowLb
->get_active_text() );
610 if ( pStyle
->GetFollow() != aFollowEntry
)
612 if ( !pStyle
->SetFollow( aFollowEntry
) )
614 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(GetFrameWeld(),
615 VclMessageType::Info
, VclButtonsType::Ok
,
616 SfxResId(STR_TABPAGE_INVALIDSTYLE
)));
618 m_xFollowLb
->grab_focus();
619 return DeactivateRC::KeepPage
;
625 if (m_xBaseLb
->get_sensitive())
627 OUString
aParentEntry( m_xBaseLb
->get_active_text() );
629 if ( SfxResId(STR_NONE
) == aParentEntry
|| aParentEntry
== pStyle
->GetName() )
630 aParentEntry
.clear();
632 if ( pStyle
->GetParent() != aParentEntry
)
634 if ( !pStyle
->SetParent( aParentEntry
) )
636 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(GetFrameWeld(),
637 VclMessageType::Info
, VclButtonsType::Ok
,
638 SfxResId(STR_TABPAGE_INVALIDPARENT
)));
640 m_xBaseLb
->grab_focus();
641 return DeactivateRC::KeepPage
;
644 nRet
= nRet
| DeactivateRC::RefreshSet
;
649 FillItemSet( pItemSet
);
654 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */