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"))
69 m_xFollowLb
->make_sorted();
70 // tdf#120188 like SwCharURLPage limit the width of the style combos
71 const int nMaxWidth(m_xFollowLb
->get_approximate_digit_width() * 50);
72 m_xFollowLb
->set_size_request(nMaxWidth
, -1);
73 m_xBaseLb
->make_sorted();
74 m_xBaseLb
->set_size_request(nMaxWidth
, -1);
75 //note that the code depends on categories not being lexically
76 //sorted, so if it's changed to sorted, the code needs to
77 //be adapted to be position unaware
78 m_xFilterLb
->set_size_request(nMaxWidth
, -1);
80 // this Page needs ExchangeSupport
83 if ( aFollow
.isEmpty() || aFollow
== aName
)
84 m_xEditStyleBtn
->set_sensitive(false);
86 m_xEditStyleBtn
->set_sensitive(true);
88 int linkSelectPos
= m_xBaseLb
->get_active();
89 if ( linkSelectPos
== 0 )
90 m_xEditLinkStyleBtn
->set_sensitive(false);
92 m_xEditLinkStyleBtn
->set_sensitive(true);
94 mxFamilies
= SfxApplication::GetModule_Impl()->CreateStyleFamilies();
96 SfxStyleSheetBasePool
* pPool
= nullptr;
97 SfxObjectShell
* pDocShell
= SfxObjectShell::Current();
100 pPool
= pDocShell
->GetStyleSheetPool();
101 OSL_ENSURE( pPool
, "no Pool or no DocShell" );
105 pPool
->First(pStyle
->GetFamily()); // for SW - update internal list
108 if ( pStyle
->GetName().isEmpty() && pPool
)
110 // NullString as Name -> generate Name
111 OUString
aNoName(SfxStyleDialogController::GenerateUnusedName(*pPool
, pStyle
->GetFamily()));
112 pStyle
->SetName( aNoName
);
114 aFollow
= pStyle
->GetFollow();
115 aParent
= pStyle
->GetParent();
117 m_xName
->set_text(pStyle
->GetName());
119 // Set the field read-only if it is NOT an user-defined style
120 // but allow selecting and copying
121 if (pStyle
->IsUserDefined())
123 m_xName
->set_can_focus(true);
124 m_xName
->set_editable(true);
125 m_xName
->set_sensitive(true);
126 m_xName
->grab_focus(); // tdf#142017 default to focus within the page, not in notebook tab
130 m_xName
->set_sensitive(false);
133 if ( pStyle
->HasFollowSupport() && pPool
)
135 SfxStyleSheetBase
* pPoolStyle
= pPool
->First(pStyle
->GetFamily());
137 m_xFollowLb
->freeze();
141 m_xFollowLb
->append_text(pPoolStyle
->GetName());
142 pPoolStyle
= pPool
->Next();
145 // A new Template is not yet in the Pool
146 if (m_xFollowLb
->find_text(pStyle
->GetName()) == -1)
147 m_xFollowLb
->append_text(pStyle
->GetName());
153 m_xFollowFt
->set_sensitive(false);
155 m_xFollowLb
->set_sensitive(false);
157 m_xEditStyleBtn
->hide();
160 if ( pStyle
->HasParentSupport() && pPool
)
164 if ( pStyle
->HasClearParentSupport() )
165 // the base template can be set to NULL
166 m_xBaseLb
->append_text(SfxResId(STR_NONE
));
168 SfxStyleSheetBase
* pPoolStyle
= pPool
->First(pStyle
->GetFamily());
172 const OUString
aStr( pPoolStyle
->GetName() );
173 // own name as base template
175 m_xBaseLb
->append_text(aStr
);
176 pPoolStyle
= pPool
->Next();
183 m_xBaseFt
->set_sensitive(false);
184 m_xBaseLb
->set_sensitive(false);
187 size_t nCount
= mxFamilies
->size();
189 for ( i
= 0; i
< nCount
; ++i
)
191 pItem
= &(mxFamilies
->at(i
));
193 if ( pItem
->GetFamily() == pStyle
->GetFamily() )
199 sal_uInt16 nStyleFilterIdx
= 0xffff;
201 const SfxStyleFilter
& rList
= pItem
->GetFilterList();
202 nCount
= rList
.size();
204 SfxStyleSearchBits nMask
= pStyle
->GetMask() & ~SfxStyleSearchBits::UserDefined
;
206 if ( nMask
== SfxStyleSearchBits::Auto
) // User Template?
207 nMask
= pStyle
->GetMask();
209 for ( i
= 0; i
< nCount
; ++i
)
211 const SfxFilterTuple
& rTupel
= rList
[ i
];
213 if ( rTupel
.nFlags
!= SfxStyleSearchBits::Auto
&&
214 rTupel
.nFlags
!= SfxStyleSearchBits::Used
&&
215 rTupel
.nFlags
!= SfxStyleSearchBits::AllVisible
&&
216 rTupel
.nFlags
!= SfxStyleSearchBits::All
)
218 OUString
sId(OUString::number(i
));
219 m_xFilterLb
->insert(nIdx
, rTupel
.aName
, &sId
, nullptr, nullptr);
220 if ( ( rTupel
.nFlags
& nMask
) == nMask
)
221 nStyleFilterIdx
= nIdx
;
226 if ( nStyleFilterIdx
!= 0xFFFF )
227 m_xFilterLb
->set_active(nStyleFilterIdx
);
230 if ( !m_xFilterLb
->get_count() || !pStyle
->IsUserDefined() )
233 m_xFilterFt
->set_sensitive(false);
234 m_xFilterLb
->set_sensitive(false);
237 m_xFilterLb
->save_value();
238 SetDescriptionText_Impl();
240 if (m_xFollowLb
->get_sensitive() || m_xBaseLb
->get_sensitive())
242 m_xName
->connect_focus_in(
243 LINK( this, SfxManageStyleSheetPage
, GetFocusHdl
) );
244 m_xName
->connect_focus_out(
245 LINK( this, SfxManageStyleSheetPage
, LoseFocusHdl
) );
247 // It is a style with auto update? (SW only)
248 if(SfxItemState::SET
== rAttrSet
.GetItemState(SID_ATTR_AUTO_STYLE_UPDATE
))
250 m_xFollowLb
->connect_changed(LINK(this, SfxManageStyleSheetPage
, EditStyleSelectHdl_Impl
));
251 m_xBaseLb
->connect_changed(LINK(this, SfxManageStyleSheetPage
, EditLinkStyleSelectHdl_Impl
));
252 m_xEditStyleBtn
->connect_clicked(LINK(this, SfxManageStyleSheetPage
, EditStyleHdl_Impl
));
253 m_xEditLinkStyleBtn
->connect_clicked(LINK(this, SfxManageStyleSheetPage
, EditLinkStyleHdl_Impl
));
256 SfxManageStyleSheetPage::~SfxManageStyleSheetPage()
263 void SfxManageStyleSheetPage::UpdateName_Impl( weld::ComboBox
* pBox
,
264 const OUString
& rNew
)
268 After the change of a template name update the ListBox pBox
272 ListBox* pBox ListBox, whose entries are to be updated
273 const String& rNew the new Name
277 if (pBox
->get_sensitive())
279 // it is the current entry, which name was modified
280 const bool bSelect
= pBox
->get_active_text() == aBuf
;
281 int nOldIndex
= pBox
->find_text(aBuf
);
283 pBox
->remove(nOldIndex
);
284 pBox
->append_text(rNew
);
287 pBox
->set_active_text(rNew
);
291 void SfxManageStyleSheetPage::SetDescriptionText_Impl()
295 Set attribute description. Get the set metric for this.
299 MapUnit eUnit
= MapUnit::MapCM
;
300 FieldUnit
eFieldUnit( FieldUnit::CM
);
301 SfxModule
* pModule
= SfxModule::GetActiveModule();
304 eFieldUnit
= pModule
->GetFieldUnit();
307 switch ( eFieldUnit
)
309 case FieldUnit::MM
: eUnit
= MapUnit::MapMM
; break;
312 case FieldUnit::KM
: eUnit
= MapUnit::MapCM
; break;
313 case FieldUnit::POINT
:
314 case FieldUnit::PICA
: eUnit
= MapUnit::MapPoint
; break;
315 case FieldUnit::INCH
:
316 case FieldUnit::FOOT
:
317 case FieldUnit::MILE
: eUnit
= MapUnit::MapInch
; break;
320 OSL_FAIL( "non supported field unit" );
322 m_xDescFt
->set_label(pStyle
->GetDescription(eUnit
));
325 IMPL_LINK_NOARG(SfxManageStyleSheetPage
, EditStyleSelectHdl_Impl
, weld::ComboBox
&, void)
327 OUString
aTemplName(m_xFollowLb
->get_active_text());
328 OUString
aEditTemplName(m_xName
->get_text());
329 m_xEditStyleBtn
->set_sensitive(aTemplName
!= aEditTemplName
);
332 IMPL_LINK_NOARG(SfxManageStyleSheetPage
, EditStyleHdl_Impl
, weld::Button
&, void)
334 OUString
aTemplName(m_xFollowLb
->get_active_text());
335 Execute_Impl(SID_STYLE_EDIT
, aTemplName
, static_cast<sal_uInt16
>(pStyle
->GetFamily()));
338 IMPL_LINK_NOARG(SfxManageStyleSheetPage
, EditLinkStyleSelectHdl_Impl
, weld::ComboBox
&, void)
340 int linkSelectPos
= m_xBaseLb
->get_active();
341 if ( linkSelectPos
== 0 )
342 m_xEditLinkStyleBtn
->set_sensitive(false);
344 m_xEditLinkStyleBtn
->set_sensitive(true);
347 IMPL_LINK_NOARG(SfxManageStyleSheetPage
, EditLinkStyleHdl_Impl
, weld::Button
&, void)
349 OUString
aTemplName(m_xBaseLb
->get_active_text());
350 if (aTemplName
!= SfxResId(STR_NONE
))
351 Execute_Impl( SID_STYLE_EDIT
, aTemplName
, static_cast<sal_uInt16
>(pStyle
->GetFamily()) );
354 // Internal: Perform functions through the Dispatcher
355 bool SfxManageStyleSheetPage::Execute_Impl(
356 sal_uInt16 nId
, const OUString
&rStr
, sal_uInt16 nFamily
)
359 SfxDispatcher
&rDispatcher
= *SfxGetpApp()->GetDispatcher_Impl();
360 SfxStringItem
aItem(nId
, rStr
);
361 SfxUInt16Item
aFamily(SID_STYLE_FAMILY
, nFamily
);
362 const SfxPoolItem
* pItems
[ 6 ];
363 sal_uInt16 nCount
= 0;
364 if( !rStr
.isEmpty() )
365 pItems
[ nCount
++ ] = &aItem
;
366 pItems
[ nCount
++ ] = &aFamily
;
368 pItems
[ nCount
++ ] = nullptr;
370 const SfxPoolItemHolder
aResult(rDispatcher
.Execute(
371 nId
, SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
,
374 return nullptr != aResult
.getItem();
378 IMPL_LINK(SfxManageStyleSheetPage
, GetFocusHdl
, weld::Widget
&, rControl
, void)
382 StarView Handler; GetFocus-Handler of the Edits with the template name.
386 weld::Entry
& rEdit
= dynamic_cast<weld::Entry
&>(rControl
);
387 aBuf
= comphelper::string::stripStart(rEdit
.get_text(), ' ');
390 IMPL_LINK(SfxManageStyleSheetPage
, LoseFocusHdl
, weld::Widget
&, rControl
, void)
394 StarView Handler; lose-focus-handler of the edits of the template name.
395 This will update the listbox with the subsequent templates. The current
396 template itself is not returned in the listbox of the base templates.
400 weld::Entry
& rEdit
= dynamic_cast<weld::Entry
&>(rControl
);
401 const OUString
aStr(comphelper::string::stripStart(rEdit
.get_text(), ' '));
402 rEdit
.set_text(aStr
);
403 // Update the Listbox of the base template if possible
405 UpdateName_Impl(m_xFollowLb
.get(), aStr
);
408 bool SfxManageStyleSheetPage::FillItemSet( SfxItemSet
* rSet
)
412 Handler for setting the (modified) data. I called from the OK of the
417 SfxItemSet &rAttrSet The set, which receives the data.
421 sal_Bool sal_True: The data had been changed
422 sal_False: The data had not been changed
430 const int nFilterIdx
= m_xFilterLb
->get_active();
434 if ( nFilterIdx
!= -1 &&
435 m_xFilterLb
->get_value_changed_from_saved() &&
436 m_xFilterLb
->get_sensitive() )
439 OSL_ENSURE( pItem
, "No Item" );
440 // is only possibly for user templates
441 SfxStyleSearchBits nMask
= pItem
->GetFilterList()[m_xFilterLb
->get_id(nFilterIdx
).toUInt32()].nFlags
| SfxStyleSearchBits::UserDefined
;
442 pStyle
->SetMask( nMask
);
444 if (m_xAutoCB
->get_visible() && m_xAutoCB
->get_state_changed_from_saved())
446 rSet
->Put(SfxBoolItem(SID_ATTR_AUTO_STYLE_UPDATE
, m_xAutoCB
->get_active()));
453 void SfxManageStyleSheetPage::Reset( const SfxItemSet
* /*rAttrSet*/ )
457 Handler to initialize the page with the initial data.
461 const SfxItemSet &rAttrSet The data set
470 OUString
sCmp( pStyle
->GetName() );
473 pStyle
->SetName( aName
);
474 m_xName
->set_text( aName
);
475 if (m_xName
->get_editable())
476 m_xName
->select_region(0, -1);
478 if ( m_xFollowLb
->get_sensitive() )
480 sCmp
= pStyle
->GetFollow();
482 if ( sCmp
!= aFollow
)
483 pStyle
->SetFollow( aFollow
);
485 if ( aFollow
.isEmpty() )
487 m_xFollowLb
->set_active_text( aName
);
488 m_xEditStyleBtn
->set_sensitive( false );
491 m_xFollowLb
->set_active_text( aFollow
);
494 if (m_xBaseLb
->get_sensitive())
496 sCmp
= pStyle
->GetParent();
498 if ( sCmp
!= aParent
)
499 pStyle
->SetParent( aParent
);
501 if ( aParent
.isEmpty() )
503 m_xBaseLb
->set_active_text( SfxResId(STR_NONE
) );
504 m_xEditLinkStyleBtn
->set_sensitive( false );
507 m_xBaseLb
->set_active_text( aParent
);
509 if ( SfxResId(STR_STANDARD
) == aName
)
511 // the default template can not be linked
512 m_xBaseFt
->set_sensitive(false);
513 m_xBaseLb
->set_sensitive(false);
517 m_xEditLinkStyleBtn
->set_sensitive( false );
519 if (m_xFilterLb
->get_sensitive())
521 SfxStyleSearchBits nCmp
= pStyle
->GetMask();
523 if ( nCmp
!= nFlags
)
524 pStyle
->SetMask( nFlags
);
525 m_xFilterLb
->set_active_text(m_xFilterLb
->get_saved_value());
529 std::unique_ptr
<SfxTabPage
> SfxManageStyleSheetPage::Create( weld::Container
* pPage
, weld::DialogController
* pController
,
530 const SfxItemSet
*rAttrSet
)
532 return std::make_unique
<SfxManageStyleSheetPage
>(pPage
, pController
, *rAttrSet
);
535 void SfxManageStyleSheetPage::ActivatePage( const SfxItemSet
& rSet
)
539 ActivatePage handler of SfxTabDialog, is used for the update of the
540 descriptive text, since this might have changed through changes of data on
545 const SfxItemSet& the set for the exchange of data; is not used here.
549 <SfxTabDialog::ActivatePage(const SfxItemSet &)>
553 SetDescriptionText_Impl();
555 // It is a style with auto update? (SW only)
556 const SfxBoolItem
* pPoolItem
;
558 if ( (pPoolItem
= rSet
.GetItemIfSet( SID_ATTR_AUTO_STYLE_UPDATE
, false )) )
559 m_xAutoCB
->set_active(pPoolItem
->GetValue());
560 m_xAutoCB
->save_state();
561 m_xName
->save_value();
564 DeactivateRC
SfxManageStyleSheetPage::DeactivatePage( SfxItemSet
* pItemSet
)
568 DeactivatePage-handler of SfxTabDialog; data is set on the template, so
569 that the correct inheritance on the other pages of the dialog is made.
570 If an error occurs, leaving the page is prevented.
573 SfxItemSet* the set for the exchange of data; is not used here.
577 <SfxTabDialog::DeactivatePage(SfxItemSet*)>
581 DeactivateRC nRet
= DeactivateRC::LeavePage
;
583 if (m_xName
->get_value_changed_from_saved())
585 // By pressing <Enter> LoseFocus() is not triggered through StarView
586 if (m_xName
->has_focus())
587 LoseFocusHdl( *m_xName
);
589 if (!pStyle
->SetName(comphelper::string::stripStart(m_xName
->get_text(), ' ')))
591 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(GetFrameWeld(),
592 VclMessageType::Info
, VclButtonsType::Ok
,
593 SfxResId(STR_TABPAGE_INVALIDNAME
)));
595 m_xName
->grab_focus();
596 m_xName
->select_region(0, -1);
597 return DeactivateRC::KeepPage
;
602 if (pStyle
->HasFollowSupport() && m_xFollowLb
->get_sensitive())
604 const OUString
aFollowEntry( m_xFollowLb
->get_active_text() );
606 if ( pStyle
->GetFollow() != aFollowEntry
)
608 if ( !pStyle
->SetFollow( aFollowEntry
) )
610 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(GetFrameWeld(),
611 VclMessageType::Info
, VclButtonsType::Ok
,
612 SfxResId(STR_TABPAGE_INVALIDSTYLE
)));
614 m_xFollowLb
->grab_focus();
615 return DeactivateRC::KeepPage
;
621 if (m_xBaseLb
->get_sensitive())
623 OUString
aParentEntry( m_xBaseLb
->get_active_text() );
625 if ( SfxResId(STR_NONE
) == aParentEntry
|| aParentEntry
== pStyle
->GetName() )
626 aParentEntry
.clear();
628 if ( pStyle
->GetParent() != aParentEntry
)
630 if ( !pStyle
->SetParent( aParentEntry
) )
632 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(GetFrameWeld(),
633 VclMessageType::Info
, VclButtonsType::Ok
,
634 SfxResId(STR_TABPAGE_INVALIDPARENT
)));
636 m_xBaseLb
->grab_focus();
637 return DeactivateRC::KeepPage
;
640 nRet
= nRet
| DeactivateRC::RefreshSet
;
645 FillItemSet( pItemSet
);
650 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */