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 <sal/config.h>
21 #include <sal/log.hxx>
23 #include <vcl/commandinfoprovider.hxx>
24 #include <vcl/weld.hxx>
25 #include <vcl/svapp.hxx>
28 #include <strings.hrc>
32 #include <SvxMenuConfigPage.hxx>
33 #include <SvxConfigPageHelper.hxx>
34 #include <dialmgr.hxx>
36 #include <comphelper/processfactory.hxx>
37 #include <com/sun/star/ui/ImageType.hpp>
39 #include <dlgname.hxx>
41 SvxMenuConfigPage::SvxMenuConfigPage(weld::Container
* pPage
, weld::DialogController
* pController
, const SfxItemSet
& rSet
, bool bIsMenuBar
)
42 : SvxConfigPage(pPage
, pController
, rSet
)
43 , m_bIsMenuBar(bIsMenuBar
)
45 m_xGearBtn
= m_xBuilder
->weld_menu_button("menugearbtn");
47 m_xContentsListBox
.reset(new SvxMenuEntriesListBox(m_xBuilder
->weld_tree_view("menucontents"), this));
48 weld::TreeView
& rTreeView
= m_xContentsListBox
->get_widget();
49 rTreeView
.connect_size_allocate(LINK(this, SvxMenuConfigPage
, MenuEntriesSizeAllocHdl
));
50 Size
aSize(m_xFunctions
->get_size_request());
51 rTreeView
.set_size_request(aSize
.Width(), aSize
.Height());
52 MenuEntriesSizeAllocHdl(aSize
);
53 rTreeView
.set_hexpand(true);
54 rTreeView
.set_vexpand(true);
57 rTreeView
.connect_changed(
58 LINK( this, SvxMenuConfigPage
, SelectMenuEntry
) );
60 rTreeView
.connect_model_changed(LINK(this, SvxMenuConfigPage
, ListModifiedHdl
));
62 m_xGearBtn
->connect_selected(LINK(this, SvxMenuConfigPage
, GearHdl
));
64 m_xCommandCategoryListBox
->connect_changed(LINK(this, SvxMenuConfigPage
, SelectCategory
));
66 m_xMoveUpButton
->connect_clicked( LINK( this, SvxConfigPage
, MoveHdl
) );
67 m_xMoveDownButton
->connect_clicked( LINK( this, SvxConfigPage
, MoveHdl
) );
69 m_xAddCommandButton
->connect_clicked( LINK( this, SvxMenuConfigPage
, AddCommandHdl
) );
70 m_xRemoveCommandButton
->connect_clicked( LINK( this, SvxMenuConfigPage
, RemoveCommandHdl
) );
72 m_xInsertBtn
->connect_selected(
73 LINK( this, SvxMenuConfigPage
, InsertHdl
) );
74 m_xModifyBtn
->connect_selected(
75 LINK( this, SvxMenuConfigPage
, ModifyItemHdl
) );
76 m_xResetBtn
->connect_clicked(
77 LINK( this, SvxMenuConfigPage
, ResetMenuHdl
) );
79 // These operations are not possible on menus/context menus yet
80 m_xModifyBtn
->remove_item("changeIcon");
81 m_xModifyBtn
->remove_item("resetIcon");
82 m_xModifyBtn
->remove_item("restoreItem");
86 //TODO: Remove this when the gear button is implemented for context menus
87 m_xGearBtn
->set_sensitive(false);
92 // TODO: Remove this when it is possible to reset menubar menus individually
93 m_xResetBtn
->set_sensitive(false);
97 IMPL_LINK_NOARG(SvxMenuConfigPage
, ListModifiedHdl
, weld::TreeView
&, void)
99 // regenerate with the current ordering within the list
100 SvxEntries
* pEntries
= GetTopLevelSelection()->GetEntries();
103 for (int i
= 0; i
< m_xContentsListBox
->n_children(); ++i
)
104 pEntries
->push_back(reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(i
).toInt64()));
106 GetSaveInData()->SetModified();
107 GetTopLevelSelection()->SetModified();
108 UpdateButtonStates();
111 IMPL_LINK(SvxMenuConfigPage
, MenuEntriesSizeAllocHdl
, const Size
&, rSize
, void)
113 weld::TreeView
& rTreeView
= m_xContentsListBox
->get_widget();
114 std::vector
<int> aWidths
;
116 int nExpectedSize
= 16;
118 int nStandardImageColWidth
= rTreeView
.get_checkbox_column_width();
119 int nMargin
= nStandardImageColWidth
- nExpectedSize
;
123 if (SvxConfigPageHelper::GetImageType() & css::ui::ImageType::SIZE_LARGE
)
125 else if (SvxConfigPageHelper::GetImageType() & css::ui::ImageType::SIZE_32
)
128 int nImageColWidth
= nExpectedSize
+ nMargin
;
130 aWidths
.push_back(nImageColWidth
);
131 aWidths
.push_back(rSize
.Width() - (nImageColWidth
+ nStandardImageColWidth
));
132 rTreeView
.set_column_fixed_widths(aWidths
);
135 SvxMenuConfigPage::~SvxMenuConfigPage()
137 for (int i
= 0, nCount
= m_xSaveInListBox
->get_count(); i
< nCount
; ++i
)
138 delete reinterpret_cast<SaveInData
*>(m_xSaveInListBox
->get_id(i
).toInt64());
139 m_xSaveInListBox
->clear();
142 // Populates the Menu combo box
143 void SvxMenuConfigPage::Init()
145 // ensure that the UI is cleared before populating it
146 m_xTopLevelListBox
->clear();
147 m_xContentsListBox
->clear();
149 ReloadTopLevelListBox();
151 m_xTopLevelListBox
->set_active(0);
154 m_xCommandCategoryListBox
->Init(
155 comphelper::getProcessComponentContext(),
157 vcl::CommandInfoProvider::GetModuleIdentifier(m_xFrame
));
158 m_xCommandCategoryListBox
->categorySelected(m_xFunctions
.get(), OUString(), GetSaveInData());
161 IMPL_LINK_NOARG(SvxMenuConfigPage
, SelectMenuEntry
, weld::TreeView
&, void)
163 UpdateButtonStates();
166 void SvxMenuConfigPage::UpdateButtonStates()
168 // Disable Up and Down buttons depending on current selection
169 int selection
= m_xContentsListBox
->get_selected_index();
172 selection
!= -1 && reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(selection
).toInt64())->IsSeparator();
173 bool bIsValidSelection
=
174 !(m_xContentsListBox
->n_children() == 0 || selection
== -1);
176 m_xMoveUpButton
->set_sensitive(
177 bIsValidSelection
&& selection
!= 0 );
178 m_xMoveDownButton
->set_sensitive(
179 bIsValidSelection
&& selection
!= m_xContentsListBox
->n_children() - 1);
181 m_xRemoveCommandButton
->set_sensitive( bIsValidSelection
);
183 m_xModifyBtn
->set_sensitive( bIsValidSelection
&& !bIsSeparator
);
185 // If there is no top level selection (menu), then everything working on the right box
186 // which contains the functions of the selected menu/toolbar needs to be disabled
187 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
189 m_xInsertBtn
->set_sensitive(pMenuData
!= nullptr);
191 m_xAddCommandButton
->set_sensitive(pMenuData
!= nullptr);
192 m_xRemoveCommandButton
->set_sensitive(pMenuData
!= nullptr);
194 //Handle the gear button
195 if (pMenuData
&& m_bIsMenuBar
)
197 // Add option (gear_add) will always be enabled
198 m_xGearBtn
->set_item_sensitive( "menu_gear_delete", pMenuData
->IsDeletable() );
199 m_xGearBtn
->set_item_sensitive( "menu_gear_rename", pMenuData
->IsRenamable() );
200 m_xGearBtn
->set_item_sensitive( "menu_gear_move", pMenuData
->IsMovable() );
204 void SvxMenuConfigPage::DeleteSelectedTopLevel()
206 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
208 SvxEntries
* pParentEntries
=
209 FindParentForChild( GetSaveInData()->GetEntries(), pMenuData
);
211 SvxConfigPageHelper::RemoveEntry( pParentEntries
, pMenuData
);
214 ReloadTopLevelListBox();
216 GetSaveInData()->SetModified( );
219 void SvxMenuConfigPage::DeleteSelectedContent()
221 int nActEntry
= m_xContentsListBox
->get_selected_index();
225 // get currently selected menu entry
226 SvxConfigEntry
* pMenuEntry
=
227 reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(nActEntry
).toInt64());
229 // get currently selected menu
230 SvxConfigEntry
* pMenu
= GetTopLevelSelection();
232 // remove menu entry from the list for this menu
233 SvxConfigPageHelper::RemoveEntry( pMenu
->GetEntries(), pMenuEntry
);
235 // remove menu entry from UI
236 m_xContentsListBox
->remove(nActEntry
);
238 // if this is a submenu entry, redraw the menus list box
239 if ( pMenuEntry
->IsPopup() )
241 ReloadTopLevelListBox();
244 // delete data for menu entry
247 GetSaveInData()->SetModified();
248 pMenu
->SetModified();
252 short SvxMenuConfigPage::QueryReset()
254 OUString msg
= CuiResId( RID_SVXSTR_CONFIRM_MENU_RESET
);
256 OUString saveInName
= m_xSaveInListBox
->get_active_text();
258 OUString label
= SvxConfigPageHelper::replaceSaveInName( msg
, saveInName
);
260 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
261 VclMessageType::Question
, VclButtonsType::YesNo
,
263 return xQueryBox
->run();
266 void SvxMenuConfigPage::SelectElement()
268 m_xContentsListBox
->clear();
270 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
274 SvxEntries
* pEntries
= pMenuData
->GetEntries();
277 for (auto const& entry
: *pEntries
)
279 OUString
sId(OUString::number(reinterpret_cast<sal_Int64
>(entry
)));
280 m_xContentsListBox
->insert(i
, sId
);
281 InsertEntryIntoUI(entry
, i
, 0);
286 UpdateButtonStates();
289 IMPL_LINK(SvxMenuConfigPage
, GearHdl
, const OString
&, rIdent
, void)
291 if (rIdent
== "menu_gear_add")
293 SvxMainMenuOrganizerDialog
aDialog(GetFrameWeld(),
294 GetSaveInData()->GetEntries(), nullptr, true );
296 if (aDialog
.run() == RET_OK
)
298 GetSaveInData()->SetEntries(aDialog
.ReleaseEntries());
299 ReloadTopLevelListBox(aDialog
.GetSelectedEntry());
300 GetSaveInData()->SetModified();
303 else if (rIdent
== "menu_gear_delete")
305 DeleteSelectedTopLevel();
307 else if (rIdent
== "menu_gear_rename")
309 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
311 OUString
sCurrentName( SvxConfigPageHelper::stripHotKey( pMenuData
->GetName() ) );
312 OUString sDesc
= CuiResId( RID_SVXSTR_LABEL_NEW_NAME
);
314 SvxNameDialog
aNameDialog(GetFrameWeld(), sCurrentName
, sDesc
);
315 aNameDialog
.set_help_id(HID_SVX_CONFIG_RENAME_MENU
);
316 aNameDialog
.set_title(CuiResId(RID_SVXSTR_RENAME_MENU
));
318 if ( aNameDialog
.run() == RET_OK
)
320 OUString sNewName
= aNameDialog
.GetName();
322 if ( sCurrentName
== sNewName
)
325 pMenuData
->SetName( sNewName
);
327 ReloadTopLevelListBox();
329 GetSaveInData()->SetModified();
332 else if (rIdent
== "menu_gear_move")
334 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
336 SvxMainMenuOrganizerDialog
aDialog(GetFrameWeld(), GetSaveInData()->GetEntries(),
338 if (aDialog
.run() == RET_OK
)
340 GetSaveInData()->SetEntries(aDialog
.ReleaseEntries());
342 ReloadTopLevelListBox();
344 GetSaveInData()->SetModified();
349 //This block should never be reached
350 SAL_WARN("cui.customize", "Unknown gear menu option: " << rIdent
);
354 UpdateButtonStates();
357 IMPL_LINK_NOARG(SvxMenuConfigPage
, SelectCategory
, weld::ComboBox
&, void)
359 OUString
aSearchTerm( m_xSearchEdit
->get_text() );
361 m_xCommandCategoryListBox
->categorySelected(m_xFunctions
.get(), aSearchTerm
, GetSaveInData());
364 IMPL_LINK_NOARG( SvxMenuConfigPage
, AddCommandHdl
, weld::Button
&, void )
366 int nPos
= AddFunction(-1, /*bAllowDuplicates*/false);
369 SvxConfigEntry
* pEntry
=
370 reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(nPos
).toInt64());
371 InsertEntryIntoUI(pEntry
, nPos
, 0);
374 IMPL_LINK_NOARG( SvxMenuConfigPage
, RemoveCommandHdl
, weld::Button
&, void )
376 DeleteSelectedContent();
377 if ( GetSaveInData()->IsModified() )
379 UpdateButtonStates();
383 IMPL_LINK(SvxMenuConfigPage
, InsertHdl
, const OString
&, rIdent
, void)
385 if (rIdent
== "insertseparator")
387 SvxConfigEntry
* pNewEntryData
= new SvxConfigEntry
;
388 pNewEntryData
->SetUserDefined();
389 int nPos
= AppendEntry(pNewEntryData
, -1);
390 InsertEntryIntoUI(pNewEntryData
, nPos
, 0);
392 else if (rIdent
== "insertsubmenu")
395 OUString aDesc
= CuiResId( RID_SVXSTR_SUBMENU_NAME
);
397 SvxNameDialog
aNameDialog(GetFrameWeld(), aNewName
, aDesc
);
398 aNameDialog
.set_help_id(HID_SVX_CONFIG_NAME_SUBMENU
);
399 aNameDialog
.set_title(CuiResId( RID_SVXSTR_ADD_SUBMENU
));
401 if (aNameDialog
.run() == RET_OK
)
403 aNewName
= aNameDialog
.GetName();
405 SvxConfigEntry
* pNewEntryData
=
406 new SvxConfigEntry( aNewName
, aNewName
, true, /*bParentData*/false );
407 pNewEntryData
->SetName( aNewName
);
408 pNewEntryData
->SetUserDefined();
410 int nPos
= AppendEntry(pNewEntryData
, -1);
411 InsertEntryIntoUI(pNewEntryData
, nPos
, 0);
413 ReloadTopLevelListBox();
415 m_xContentsListBox
->scroll_to_row(nPos
);
416 m_xContentsListBox
->select(nPos
);
418 GetSaveInData()->SetModified();
424 //This block should never be reached
425 SAL_WARN("cui.customize", "Unknown insert option: " << rIdent
);
429 if ( GetSaveInData()->IsModified() )
431 UpdateButtonStates();
435 IMPL_LINK(SvxMenuConfigPage
, ModifyItemHdl
, const OString
&, rIdent
, void)
437 if (rIdent
== "renameItem")
439 int nActEntry
= m_xContentsListBox
->get_selected_index();
440 SvxConfigEntry
* pEntry
=
441 reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(nActEntry
).toInt64());
443 OUString
aNewName( SvxConfigPageHelper::stripHotKey( pEntry
->GetName() ) );
444 OUString aDesc
= CuiResId( RID_SVXSTR_LABEL_NEW_NAME
);
446 SvxNameDialog
aNameDialog(GetFrameWeld(), aNewName
, aDesc
);
447 aNameDialog
.set_help_id(HID_SVX_CONFIG_RENAME_MENU_ITEM
);
448 aNameDialog
.set_title(CuiResId(RID_SVXSTR_RENAME_MENU
));
450 if (aNameDialog
.run() == RET_OK
)
452 aNewName
= aNameDialog
.GetName();
454 pEntry
->SetName( aNewName
);
455 m_xContentsListBox
->set_text(nActEntry
, aNewName
, 1);
457 GetSaveInData()->SetModified();
458 GetTopLevelSelection()->SetModified();
463 //This block should never be reached
464 SAL_WARN("cui.customize", "Unknown insert option: " << rIdent
);
468 if ( GetSaveInData()->IsModified() )
470 UpdateButtonStates();
474 IMPL_LINK_NOARG(SvxMenuConfigPage
, ResetMenuHdl
, weld::Button
&, void)
476 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
478 if (pMenuData
== nullptr)
480 SAL_WARN("cui.customize", "RHB top level selection is null. A menu must be selected to reset!");
484 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
485 VclMessageType::Question
, VclButtonsType::YesNo
,
486 CuiResId(RID_SVXSTR_CONFIRM_RESTORE_DEFAULT_MENU
)));
488 // Resetting individual top-level menus is not possible at the moment.
489 // So we are resetting only if it is a context menu
490 if (!m_bIsMenuBar
&& xQueryBox
->run() == RET_YES
)
492 sal_Int32 nPos
= m_xTopLevelListBox
->get_active();
493 ContextMenuSaveInData
* pSaveInData
= static_cast< ContextMenuSaveInData
* >(GetSaveInData());
495 pSaveInData
->ResetContextMenu(pMenuData
);
497 // ensure that the UI is cleared before populating it
498 m_xTopLevelListBox
->clear();
499 m_xContentsListBox
->clear();
501 ReloadTopLevelListBox();
503 // Reselect the reset menu
504 m_xTopLevelListBox
->set_active(nPos
);
509 SaveInData
* SvxMenuConfigPage::CreateSaveInData(
510 const css::uno::Reference
< css::ui::XUIConfigurationManager
>& xCfgMgr
,
511 const css::uno::Reference
< css::ui::XUIConfigurationManager
>& xParentCfgMgr
,
512 const OUString
& aModuleId
,
516 return static_cast< SaveInData
* >( new ContextMenuSaveInData( xCfgMgr
, xParentCfgMgr
, aModuleId
, bDocConfig
) );
518 return static_cast< SaveInData
* >( new MenuSaveInData( xCfgMgr
, xParentCfgMgr
, aModuleId
, bDocConfig
) );
521 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */