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 m_xDropTargetHelper
.reset(new SvxConfigPageFunctionDropTarget(*this, rTreeView
));
50 rTreeView
.connect_size_allocate(LINK(this, SvxMenuConfigPage
, MenuEntriesSizeAllocHdl
));
51 Size
aSize(m_xFunctions
->get_size_request());
52 rTreeView
.set_size_request(aSize
.Width(), aSize
.Height());
53 MenuEntriesSizeAllocHdl(aSize
);
54 rTreeView
.set_hexpand(true);
55 rTreeView
.set_vexpand(true);
58 rTreeView
.connect_changed(
59 LINK( this, SvxMenuConfigPage
, SelectMenuEntry
) );
61 m_xGearBtn
->connect_selected(LINK(this, SvxMenuConfigPage
, GearHdl
));
63 m_xCommandCategoryListBox
->connect_changed(LINK(this, SvxMenuConfigPage
, SelectCategory
));
65 m_xMoveUpButton
->connect_clicked( LINK( this, SvxConfigPage
, MoveHdl
) );
66 m_xMoveDownButton
->connect_clicked( LINK( this, SvxConfigPage
, MoveHdl
) );
68 m_xAddCommandButton
->connect_clicked( LINK( this, SvxMenuConfigPage
, AddCommandHdl
) );
69 m_xRemoveCommandButton
->connect_clicked( LINK( this, SvxMenuConfigPage
, RemoveCommandHdl
) );
71 m_xInsertBtn
->connect_selected(
72 LINK( this, SvxMenuConfigPage
, InsertHdl
) );
73 m_xModifyBtn
->connect_selected(
74 LINK( this, SvxMenuConfigPage
, ModifyItemHdl
) );
75 m_xResetBtn
->connect_clicked(
76 LINK( this, SvxMenuConfigPage
, ResetMenuHdl
) );
78 // These operations are not possible on menus/context menus yet
79 m_xModifyBtn
->remove_item("changeIcon");
80 m_xModifyBtn
->remove_item("resetIcon");
81 m_xModifyBtn
->remove_item("restoreItem");
85 //TODO: Remove this when the gear button is implemented for context menus
86 m_xGearBtn
->set_sensitive(false);
91 // TODO: Remove this when it is possible to reset menubar menus individually
92 m_xResetBtn
->set_sensitive(false);
96 void SvxMenuConfigPage::ListModified()
98 // regenerate with the current ordering within the list
99 SvxEntries
* pEntries
= GetTopLevelSelection()->GetEntries();
102 for (int i
= 0; i
< m_xContentsListBox
->n_children(); ++i
)
103 pEntries
->push_back(reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(i
).toInt64()));
105 GetSaveInData()->SetModified();
106 GetTopLevelSelection()->SetModified();
107 UpdateButtonStates();
110 IMPL_LINK(SvxMenuConfigPage
, MenuEntriesSizeAllocHdl
, const Size
&, rSize
, void)
112 weld::TreeView
& rTreeView
= m_xContentsListBox
->get_widget();
113 std::vector
<int> aWidths
;
115 int nExpectedSize
= 16;
117 int nStandardImageColWidth
= rTreeView
.get_checkbox_column_width();
118 int nMargin
= nStandardImageColWidth
- nExpectedSize
;
122 if (SvxConfigPageHelper::GetImageType() & css::ui::ImageType::SIZE_LARGE
)
124 else if (SvxConfigPageHelper::GetImageType() & css::ui::ImageType::SIZE_32
)
127 int nImageColWidth
= nExpectedSize
+ nMargin
;
129 aWidths
.push_back(nImageColWidth
);
130 aWidths
.push_back(rSize
.Width() - (nImageColWidth
+ nStandardImageColWidth
));
131 rTreeView
.set_column_fixed_widths(aWidths
);
134 SvxMenuConfigPage::~SvxMenuConfigPage()
136 for (int i
= 0, nCount
= m_xSaveInListBox
->get_count(); i
< nCount
; ++i
)
137 delete reinterpret_cast<SaveInData
*>(m_xSaveInListBox
->get_id(i
).toInt64());
138 m_xSaveInListBox
->clear();
141 // Populates the Menu combo box
142 void SvxMenuConfigPage::Init()
144 // ensure that the UI is cleared before populating it
145 m_xTopLevelListBox
->clear();
146 m_xContentsListBox
->clear();
148 ReloadTopLevelListBox();
150 m_xTopLevelListBox
->set_active(0);
153 m_xCommandCategoryListBox
->Init(
154 comphelper::getProcessComponentContext(),
155 m_xFrame
, m_aModuleId
);
156 m_xCommandCategoryListBox
->categorySelected(m_xFunctions
.get(), OUString(), GetSaveInData());
159 IMPL_LINK_NOARG(SvxMenuConfigPage
, SelectMenuEntry
, weld::TreeView
&, void)
161 UpdateButtonStates();
164 void SvxMenuConfigPage::UpdateButtonStates()
166 // Disable Up and Down buttons depending on current selection
167 int selection
= m_xContentsListBox
->get_selected_index();
170 selection
!= -1 && reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(selection
).toInt64())->IsSeparator();
171 bool bIsValidSelection
=
172 !(m_xContentsListBox
->n_children() == 0 || selection
== -1);
174 m_xMoveUpButton
->set_sensitive(
175 bIsValidSelection
&& selection
!= 0 );
176 m_xMoveDownButton
->set_sensitive(
177 bIsValidSelection
&& selection
!= m_xContentsListBox
->n_children() - 1);
179 m_xRemoveCommandButton
->set_sensitive( bIsValidSelection
);
181 m_xModifyBtn
->set_sensitive( bIsValidSelection
&& !bIsSeparator
);
183 // If there is no top level selection (menu), then everything working on the right box
184 // which contains the functions of the selected menu/toolbar needs to be disabled
185 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
187 m_xInsertBtn
->set_sensitive(pMenuData
!= nullptr);
189 m_xAddCommandButton
->set_sensitive(pMenuData
!= nullptr);
190 m_xRemoveCommandButton
->set_sensitive(pMenuData
!= nullptr);
192 //Handle the gear button
193 if (pMenuData
&& m_bIsMenuBar
)
195 // Add option (gear_add) will always be enabled
196 m_xGearBtn
->set_item_sensitive( "menu_gear_delete", pMenuData
->IsDeletable() );
197 m_xGearBtn
->set_item_sensitive( "menu_gear_rename", pMenuData
->IsRenamable() );
198 m_xGearBtn
->set_item_sensitive( "menu_gear_move", pMenuData
->IsMovable() );
202 void SvxMenuConfigPage::DeleteSelectedTopLevel()
204 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
206 SvxEntries
* pParentEntries
=
207 FindParentForChild( GetSaveInData()->GetEntries(), pMenuData
);
209 SvxConfigPageHelper::RemoveEntry( pParentEntries
, pMenuData
);
212 ReloadTopLevelListBox();
214 GetSaveInData()->SetModified( );
217 void SvxMenuConfigPage::DeleteSelectedContent()
219 int nActEntry
= m_xContentsListBox
->get_selected_index();
223 // get currently selected menu entry
224 SvxConfigEntry
* pMenuEntry
=
225 reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(nActEntry
).toInt64());
227 // get currently selected menu
228 SvxConfigEntry
* pMenu
= GetTopLevelSelection();
230 // remove menu entry from the list for this menu
231 SvxConfigPageHelper::RemoveEntry( pMenu
->GetEntries(), pMenuEntry
);
233 // remove menu entry from UI
234 m_xContentsListBox
->remove(nActEntry
);
236 // if this is a submenu entry, redraw the menus list box
237 if ( pMenuEntry
->IsPopup() )
239 ReloadTopLevelListBox();
242 // delete data for menu entry
245 GetSaveInData()->SetModified();
246 pMenu
->SetModified();
250 short SvxMenuConfigPage::QueryReset()
252 OUString msg
= CuiResId( RID_SVXSTR_CONFIRM_MENU_RESET
);
254 OUString saveInName
= m_xSaveInListBox
->get_active_text();
256 OUString label
= SvxConfigPageHelper::replaceSaveInName( msg
, saveInName
);
258 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
259 VclMessageType::Question
, VclButtonsType::YesNo
,
261 return xQueryBox
->run();
264 void SvxMenuConfigPage::SelectElement()
266 weld::TreeView
& rTreeView
= m_xContentsListBox
->get_widget();
268 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
273 SvxEntries
* pEntries
= pMenuData
->GetEntries();
275 rTreeView
.bulk_insert_for_each(pEntries
->size(), [this, &rTreeView
, pEntries
](weld::TreeIter
& rIter
, int nIdx
) {
276 auto const& entry
= (*pEntries
)[nIdx
];
277 OUString
sId(OUString::number(reinterpret_cast<sal_Int64
>(entry
)));
278 rTreeView
.set_id(rIter
, sId
);
279 InsertEntryIntoUI(entry
, rTreeView
, rIter
, 0);
283 UpdateButtonStates();
286 IMPL_LINK(SvxMenuConfigPage
, GearHdl
, const OString
&, rIdent
, void)
288 if (rIdent
== "menu_gear_add")
290 SvxMainMenuOrganizerDialog
aDialog(GetFrameWeld(),
291 GetSaveInData()->GetEntries(), nullptr, true );
293 if (aDialog
.run() == RET_OK
)
295 GetSaveInData()->SetEntries(aDialog
.ReleaseEntries());
296 ReloadTopLevelListBox(aDialog
.GetSelectedEntry());
297 GetSaveInData()->SetModified();
300 else if (rIdent
== "menu_gear_delete")
302 DeleteSelectedTopLevel();
304 else if (rIdent
== "menu_gear_rename")
306 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
308 OUString
sCurrentName( SvxConfigPageHelper::stripHotKey( pMenuData
->GetName() ) );
309 OUString sDesc
= CuiResId( RID_SVXSTR_LABEL_NEW_NAME
);
311 SvxNameDialog
aNameDialog(GetFrameWeld(), sCurrentName
, sDesc
);
312 aNameDialog
.set_help_id(HID_SVX_CONFIG_RENAME_MENU
);
313 aNameDialog
.set_title(CuiResId(RID_SVXSTR_RENAME_MENU
));
315 if ( aNameDialog
.run() == RET_OK
)
317 OUString sNewName
= aNameDialog
.GetName();
319 if ( sCurrentName
== sNewName
)
322 pMenuData
->SetName( sNewName
);
324 ReloadTopLevelListBox();
326 GetSaveInData()->SetModified();
329 else if (rIdent
== "menu_gear_move")
331 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
333 SvxMainMenuOrganizerDialog
aDialog(GetFrameWeld(), GetSaveInData()->GetEntries(),
335 if (aDialog
.run() == RET_OK
)
337 GetSaveInData()->SetEntries(aDialog
.ReleaseEntries());
339 ReloadTopLevelListBox();
341 GetSaveInData()->SetModified();
346 //This block should never be reached
347 SAL_WARN("cui.customize", "Unknown gear menu option: " << rIdent
);
351 UpdateButtonStates();
354 IMPL_LINK_NOARG(SvxMenuConfigPage
, SelectCategory
, weld::ComboBox
&, void)
356 OUString
aSearchTerm( m_xSearchEdit
->get_text() );
358 m_xCommandCategoryListBox
->categorySelected(m_xFunctions
.get(), aSearchTerm
, GetSaveInData());
361 IMPL_LINK_NOARG( SvxMenuConfigPage
, AddCommandHdl
, weld::Button
&, void )
363 int nPos
= AddFunction(-1, /*bAllowDuplicates*/false);
366 weld::TreeView
& rTreeView
= m_xContentsListBox
->get_widget();
367 SvxConfigEntry
* pEntry
=
368 reinterpret_cast<SvxConfigEntry
*>(rTreeView
.get_id(nPos
).toInt64());
369 InsertEntryIntoUI(pEntry
, rTreeView
, nPos
, 0);
372 IMPL_LINK_NOARG( SvxMenuConfigPage
, RemoveCommandHdl
, weld::Button
&, void )
374 DeleteSelectedContent();
375 if ( GetSaveInData()->IsModified() )
377 UpdateButtonStates();
381 IMPL_LINK(SvxMenuConfigPage
, InsertHdl
, const OString
&, rIdent
, void)
383 weld::TreeView
& rTreeView
= m_xContentsListBox
->get_widget();
384 if (rIdent
== "insertseparator")
386 SvxConfigEntry
* pNewEntryData
= new SvxConfigEntry
;
387 pNewEntryData
->SetUserDefined();
388 int nPos
= AppendEntry(pNewEntryData
, -1);
389 InsertEntryIntoUI(pNewEntryData
, rTreeView
, nPos
, 0);
391 else if (rIdent
== "insertsubmenu")
394 OUString aDesc
= CuiResId( RID_SVXSTR_SUBMENU_NAME
);
396 SvxNameDialog
aNameDialog(GetFrameWeld(), aNewName
, aDesc
);
397 aNameDialog
.set_help_id(HID_SVX_CONFIG_NAME_SUBMENU
);
398 aNameDialog
.set_title(CuiResId( RID_SVXSTR_ADD_SUBMENU
));
400 if (aNameDialog
.run() == RET_OK
)
402 aNewName
= aNameDialog
.GetName();
404 SvxConfigEntry
* pNewEntryData
=
405 new SvxConfigEntry( aNewName
, aNewName
, true, /*bParentData*/false );
406 pNewEntryData
->SetName( aNewName
);
407 pNewEntryData
->SetUserDefined();
409 int nPos
= AppendEntry(pNewEntryData
, -1);
410 InsertEntryIntoUI(pNewEntryData
, rTreeView
, nPos
, 0);
412 ReloadTopLevelListBox();
414 m_xContentsListBox
->scroll_to_row(nPos
);
415 m_xContentsListBox
->select(nPos
);
417 GetSaveInData()->SetModified();
423 //This block should never be reached
424 SAL_WARN("cui.customize", "Unknown insert option: " << rIdent
);
428 if ( GetSaveInData()->IsModified() )
430 UpdateButtonStates();
434 IMPL_LINK(SvxMenuConfigPage
, ModifyItemHdl
, const OString
&, rIdent
, void)
436 if (rIdent
== "renameItem")
438 int nActEntry
= m_xContentsListBox
->get_selected_index();
439 SvxConfigEntry
* pEntry
=
440 reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(nActEntry
).toInt64());
442 OUString
aNewName( SvxConfigPageHelper::stripHotKey( pEntry
->GetName() ) );
443 OUString aDesc
= CuiResId( RID_SVXSTR_LABEL_NEW_NAME
);
445 SvxNameDialog
aNameDialog(GetFrameWeld(), aNewName
, aDesc
);
446 aNameDialog
.set_help_id(HID_SVX_CONFIG_RENAME_MENU_ITEM
);
447 aNameDialog
.set_title(CuiResId(RID_SVXSTR_RENAME_MENU
));
449 if (aNameDialog
.run() == RET_OK
)
451 aNewName
= aNameDialog
.GetName();
453 pEntry
->SetName( aNewName
);
454 m_xContentsListBox
->set_text(nActEntry
, aNewName
, 1);
456 GetSaveInData()->SetModified();
457 GetTopLevelSelection()->SetModified();
462 //This block should never be reached
463 SAL_WARN("cui.customize", "Unknown insert option: " << rIdent
);
467 if ( GetSaveInData()->IsModified() )
469 UpdateButtonStates();
473 IMPL_LINK_NOARG(SvxMenuConfigPage
, ResetMenuHdl
, weld::Button
&, void)
475 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
477 if (pMenuData
== nullptr)
479 SAL_WARN("cui.customize", "RHB top level selection is null. A menu must be selected to reset!");
483 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
484 VclMessageType::Question
, VclButtonsType::YesNo
,
485 CuiResId(RID_SVXSTR_CONFIRM_RESTORE_DEFAULT_MENU
)));
487 // Resetting individual top-level menus is not possible at the moment.
488 // So we are resetting only if it is a context menu
489 if (!m_bIsMenuBar
&& xQueryBox
->run() == RET_YES
)
491 sal_Int32 nPos
= m_xTopLevelListBox
->get_active();
492 ContextMenuSaveInData
* pSaveInData
= static_cast< ContextMenuSaveInData
* >(GetSaveInData());
494 pSaveInData
->ResetContextMenu(pMenuData
);
496 // ensure that the UI is cleared before populating it
497 m_xTopLevelListBox
->clear();
498 m_xContentsListBox
->clear();
500 ReloadTopLevelListBox();
502 // Reselect the reset menu
503 m_xTopLevelListBox
->set_active(nPos
);
508 SaveInData
* SvxMenuConfigPage::CreateSaveInData(
509 const css::uno::Reference
< css::ui::XUIConfigurationManager
>& xCfgMgr
,
510 const css::uno::Reference
< css::ui::XUIConfigurationManager
>& xParentCfgMgr
,
511 const OUString
& aModuleId
,
515 return static_cast< SaveInData
* >( new ContextMenuSaveInData( xCfgMgr
, xParentCfgMgr
, aModuleId
, bDocConfig
) );
517 return static_cast< SaveInData
* >( new MenuSaveInData( xCfgMgr
, xParentCfgMgr
, aModuleId
, bDocConfig
) );
520 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */