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>
28 #include <vcl/commandinfoprovider.hxx>
29 #include <vcl/help.hxx>
30 #include <vcl/weld.hxx>
31 #include <vcl/decoview.hxx>
32 #include <vcl/virdev.hxx>
33 #include <vcl/settings.hxx>
34 #include <vcl/svapp.hxx>
36 #include <sfx2/app.hxx>
37 #include <sfx2/sfxdlg.hxx>
38 #include <sfx2/viewfrm.hxx>
39 #include <sfx2/viewsh.hxx>
40 #include <sfx2/msg.hxx>
41 #include <sfx2/msgpool.hxx>
42 #include <sfx2/minfitem.hxx>
43 #include <sfx2/objsh.hxx>
44 #include <sfx2/request.hxx>
45 #include <sfx2/filedlghelper.hxx>
46 #include <svl/stritem.hxx>
47 #include <svtools/miscopt.hxx>
48 #include <tools/diagnose_ex.h>
51 #include <strings.hrc>
56 #include <SvxMenuConfigPage.hxx>
57 #include <SvxConfigPageHelper.hxx>
58 #include <dialmgr.hxx>
60 #include <comphelper/processfactory.hxx>
61 #include <unotools/configmgr.hxx>
62 #include <com/sun/star/embed/ElementModes.hpp>
63 #include <com/sun/star/embed/FileSystemStorageFactory.hpp>
64 #include <com/sun/star/frame/UnknownModuleException.hpp>
65 #include <com/sun/star/frame/XFrames.hpp>
66 #include <com/sun/star/frame/XLayoutManager.hpp>
67 #include <com/sun/star/frame/FrameSearchFlag.hpp>
68 #include <com/sun/star/frame/ModuleManager.hpp>
69 #include <com/sun/star/frame/XController.hpp>
70 #include <com/sun/star/frame/Desktop.hpp>
71 #include <com/sun/star/graphic/GraphicProvider.hpp>
72 #include <com/sun/star/io/IOException.hpp>
73 #include <com/sun/star/lang/IllegalAccessException.hpp>
74 #include <com/sun/star/ui/ItemType.hpp>
75 #include <com/sun/star/ui/ItemStyle.hpp>
76 #include <com/sun/star/ui/ImageManager.hpp>
77 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
78 #include <com/sun/star/ui/XUIConfiguration.hpp>
79 #include <com/sun/star/ui/XUIConfigurationListener.hpp>
80 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
81 #include <com/sun/star/ui/XUIConfigurationPersistence.hpp>
82 #include <com/sun/star/ui/XUIConfigurationStorage.hpp>
83 #include <com/sun/star/ui/XModuleUIConfigurationManager.hpp>
84 #include <com/sun/star/ui/XUIElement.hpp>
85 #include <com/sun/star/ui/UIElementType.hpp>
86 #include <com/sun/star/ui/ImageType.hpp>
87 #include <com/sun/star/ui/theWindowStateConfiguration.hpp>
88 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
89 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
90 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
91 #include <com/sun/star/util/thePathSettings.hpp>
93 #include <dlgname.hxx>
95 SvxMenuConfigPage::SvxMenuConfigPage(TabPageParent pParent
, const SfxItemSet
& rSet
, bool bIsMenuBar
)
96 : SvxConfigPage(pParent
, rSet
)
97 , m_bIsMenuBar(bIsMenuBar
)
99 m_xGearBtn
= m_xBuilder
->weld_menu_button("menugearbtn");
101 m_xContentsListBox
.reset(new SvxMenuEntriesListBox(m_xBuilder
->weld_tree_view("menucontents"), this));
102 weld::TreeView
& rTreeView
= m_xContentsListBox
->get_widget();
103 rTreeView
.connect_size_allocate(LINK(this, SvxMenuConfigPage
, MenuEntriesSizeAllocHdl
));
104 Size
aSize(m_xFunctions
->get_size_request());
105 rTreeView
.set_size_request(aSize
.Width(), aSize
.Height());
106 MenuEntriesSizeAllocHdl(aSize
);
107 rTreeView
.set_hexpand(true);
108 rTreeView
.set_vexpand(true);
111 rTreeView
.connect_changed(
112 LINK( this, SvxMenuConfigPage
, SelectMenuEntry
) );
114 rTreeView
.connect_model_changed(LINK(this, SvxMenuConfigPage
, ListModifiedHdl
));
116 m_xGearBtn
->connect_selected(LINK(this, SvxMenuConfigPage
, GearHdl
));
118 m_xCommandCategoryListBox
->connect_changed(LINK(this, SvxMenuConfigPage
, SelectCategory
));
120 m_xMoveUpButton
->connect_clicked( LINK( this, SvxConfigPage
, MoveHdl
) );
121 m_xMoveDownButton
->connect_clicked( LINK( this, SvxConfigPage
, MoveHdl
) );
123 m_xAddCommandButton
->connect_clicked( LINK( this, SvxMenuConfigPage
, AddCommandHdl
) );
124 m_xRemoveCommandButton
->connect_clicked( LINK( this, SvxMenuConfigPage
, RemoveCommandHdl
) );
126 m_xInsertBtn
->connect_selected(
127 LINK( this, SvxMenuConfigPage
, InsertHdl
) );
128 m_xModifyBtn
->connect_selected(
129 LINK( this, SvxMenuConfigPage
, ModifyItemHdl
) );
130 m_xResetBtn
->connect_clicked(
131 LINK( this, SvxMenuConfigPage
, ResetMenuHdl
) );
133 // These operations are not possible on menus/context menus yet
134 m_xModifyBtn
->remove_item("changeIcon");
135 m_xModifyBtn
->remove_item("resetIcon");
136 m_xModifyBtn
->remove_item("restoreItem");
140 //TODO: Remove this when the gear button is implemented for context menus
141 m_xGearBtn
->set_sensitive(false);
146 // TODO: Remove this when it is possible to reset menubar menus individually
147 m_xResetBtn
->set_sensitive(false);
151 IMPL_LINK_NOARG(SvxMenuConfigPage
, ListModifiedHdl
, weld::TreeView
&, void)
153 // regenerate with the current ordering within the list
154 SvxEntries
* pEntries
= GetTopLevelSelection()->GetEntries();
157 for (int i
= 0; i
< m_xContentsListBox
->n_children(); ++i
)
158 pEntries
->push_back(reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(i
).toInt64()));
160 GetSaveInData()->SetModified();
161 GetTopLevelSelection()->SetModified();
162 UpdateButtonStates();
165 IMPL_LINK(SvxMenuConfigPage
, MenuEntriesSizeAllocHdl
, const Size
&, rSize
, void)
167 weld::TreeView
& rTreeView
= m_xContentsListBox
->get_widget();
168 std::vector
<int> aWidths
;
170 int nExpectedSize
= 16;
172 int nStandardImageColWidth
= rTreeView
.get_checkbox_column_width();
173 int nMargin
= nStandardImageColWidth
- nExpectedSize
;
177 if (SvxConfigPageHelper::GetImageType() & css::ui::ImageType::SIZE_LARGE
)
179 else if (SvxConfigPageHelper::GetImageType() & css::ui::ImageType::SIZE_32
)
182 int nImageColWidth
= nExpectedSize
+ nMargin
;
184 aWidths
.push_back(nImageColWidth
);
185 aWidths
.push_back(rSize
.Width() - (nImageColWidth
+ nStandardImageColWidth
));
186 rTreeView
.set_column_fixed_widths(aWidths
);
189 SvxMenuConfigPage::~SvxMenuConfigPage()
194 // Populates the Menu combo box
195 void SvxMenuConfigPage::Init()
197 // ensure that the UI is cleared before populating it
198 m_xTopLevelListBox
->clear();
199 m_xContentsListBox
->clear();
201 ReloadTopLevelListBox();
203 m_xTopLevelListBox
->set_active(0);
206 m_xCommandCategoryListBox
->Init(
207 comphelper::getProcessComponentContext(),
209 vcl::CommandInfoProvider::GetModuleIdentifier(m_xFrame
));
210 m_xCommandCategoryListBox
->categorySelected(m_xFunctions
.get(), OUString(), GetSaveInData());
213 void SvxMenuConfigPage::dispose()
215 for (int i
= 0, nCount
= m_xSaveInListBox
->get_count(); i
< nCount
; ++i
)
216 delete reinterpret_cast<SaveInData
*>(m_xSaveInListBox
->get_id(i
).toInt64());
217 m_xSaveInListBox
->clear();
219 SvxConfigPage::dispose();
222 IMPL_LINK_NOARG(SvxMenuConfigPage
, SelectMenuEntry
, weld::TreeView
&, void)
224 UpdateButtonStates();
227 void SvxMenuConfigPage::UpdateButtonStates()
229 // Disable Up and Down buttons depending on current selection
230 int selection
= m_xContentsListBox
->get_selected_index();
233 selection
!= -1 && reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(selection
).toInt64())->IsSeparator();
234 bool bIsValidSelection
=
235 !(m_xContentsListBox
->n_children() == 0 || selection
== -1);
237 m_xMoveUpButton
->set_sensitive(
238 bIsValidSelection
&& selection
!= 0 );
239 m_xMoveDownButton
->set_sensitive(
240 bIsValidSelection
&& selection
!= m_xContentsListBox
->n_children() - 1);
242 m_xRemoveCommandButton
->set_sensitive( bIsValidSelection
);
244 m_xModifyBtn
->set_sensitive( bIsValidSelection
&& !bIsSeparator
);
246 //Handle the gear button
249 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
250 // Add option (gear_add) will always be enabled
251 m_xGearBtn
->set_item_sensitive( "menu_gear_delete", pMenuData
->IsDeletable() );
252 m_xGearBtn
->set_item_sensitive( "menu_gear_rename", pMenuData
->IsRenamable() );
253 m_xGearBtn
->set_item_sensitive( "menu_gear_move", pMenuData
->IsMovable() );
257 void SvxMenuConfigPage::DeleteSelectedTopLevel()
259 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
261 SvxEntries
* pParentEntries
=
262 FindParentForChild( GetSaveInData()->GetEntries(), pMenuData
);
264 SvxConfigPageHelper::RemoveEntry( pParentEntries
, pMenuData
);
267 ReloadTopLevelListBox();
269 GetSaveInData()->SetModified( );
272 void SvxMenuConfigPage::DeleteSelectedContent()
274 int nActEntry
= m_xContentsListBox
->get_selected_index();
278 // get currently selected menu entry
279 SvxConfigEntry
* pMenuEntry
=
280 reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(nActEntry
).toInt64());
282 // get currently selected menu
283 SvxConfigEntry
* pMenu
= GetTopLevelSelection();
285 // remove menu entry from the list for this menu
286 SvxConfigPageHelper::RemoveEntry( pMenu
->GetEntries(), pMenuEntry
);
288 // remove menu entry from UI
289 m_xContentsListBox
->remove(nActEntry
);
291 // if this is a submenu entry, redraw the menus list box
292 if ( pMenuEntry
->IsPopup() )
294 ReloadTopLevelListBox();
297 // delete data for menu entry
300 GetSaveInData()->SetModified();
301 pMenu
->SetModified();
305 short SvxMenuConfigPage::QueryReset()
307 OUString msg
= CuiResId( RID_SVXSTR_CONFIRM_MENU_RESET
);
309 OUString saveInName
= m_xSaveInListBox
->get_active_text();
311 OUString label
= SvxConfigPageHelper::replaceSaveInName( msg
, saveInName
);
313 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(GetDialogFrameWeld(),
314 VclMessageType::Question
, VclButtonsType::YesNo
,
316 return xQueryBox
->run();
319 void SvxMenuConfigPage::SelectElement()
321 m_xContentsListBox
->clear();
323 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
327 SvxEntries
* pEntries
= pMenuData
->GetEntries();
330 for (auto const& entry
: *pEntries
)
332 OUString
sId(OUString::number(reinterpret_cast<sal_Int64
>(entry
)));
333 m_xContentsListBox
->insert(i
, sId
);
334 InsertEntryIntoUI(entry
, i
, 0);
339 UpdateButtonStates();
342 IMPL_LINK(SvxMenuConfigPage
, GearHdl
, const OString
&, rIdent
, void)
344 if (rIdent
== "menu_gear_add")
346 SvxMainMenuOrganizerDialog
aDialog(GetDialogFrameWeld(),
347 GetSaveInData()->GetEntries(), nullptr, true );
349 if (aDialog
.run() == RET_OK
)
351 GetSaveInData()->SetEntries(aDialog
.ReleaseEntries());
352 ReloadTopLevelListBox(aDialog
.GetSelectedEntry());
353 GetSaveInData()->SetModified();
356 else if (rIdent
== "menu_gear_delete")
358 DeleteSelectedTopLevel();
360 else if (rIdent
== "menu_gear_rename")
362 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
364 OUString
sCurrentName( SvxConfigPageHelper::stripHotKey( pMenuData
->GetName() ) );
365 OUString sDesc
= CuiResId( RID_SVXSTR_LABEL_NEW_NAME
);
367 SvxNameDialog
aNameDialog(GetDialogFrameWeld(), sCurrentName
, sDesc
);
368 aNameDialog
.set_help_id(HID_SVX_CONFIG_RENAME_MENU
);
369 aNameDialog
.set_title(CuiResId(RID_SVXSTR_RENAME_MENU
));
371 if ( aNameDialog
.run() == RET_OK
)
373 OUString sNewName
= aNameDialog
.GetName();
375 if ( sCurrentName
== sNewName
)
378 pMenuData
->SetName( sNewName
);
380 ReloadTopLevelListBox();
382 GetSaveInData()->SetModified();
385 else if (rIdent
== "menu_gear_move")
387 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
389 SvxMainMenuOrganizerDialog
aDialog(GetDialogFrameWeld(), GetSaveInData()->GetEntries(),
391 if (aDialog
.run() == RET_OK
)
393 GetSaveInData()->SetEntries(aDialog
.ReleaseEntries());
395 ReloadTopLevelListBox();
397 GetSaveInData()->SetModified();
402 //This block should never be reached
403 SAL_WARN("cui.customize", "Unknown gear menu option: " << rIdent
);
407 UpdateButtonStates();
410 IMPL_LINK_NOARG(SvxMenuConfigPage
, SelectCategory
, weld::ComboBox
&, void)
412 OUString
aSearchTerm( m_xSearchEdit
->get_text() );
414 m_xCommandCategoryListBox
->categorySelected(m_xFunctions
.get(), aSearchTerm
, GetSaveInData());
417 IMPL_LINK_NOARG( SvxMenuConfigPage
, AddCommandHdl
, weld::Button
&, void )
419 int nPos
= AddFunction();
422 SvxConfigEntry
* pEntry
=
423 reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(nPos
).toInt64());
424 InsertEntryIntoUI(pEntry
, nPos
, 0);
427 IMPL_LINK_NOARG( SvxMenuConfigPage
, RemoveCommandHdl
, weld::Button
&, void )
429 DeleteSelectedContent();
430 if ( GetSaveInData()->IsModified() )
432 UpdateButtonStates();
436 IMPL_LINK(SvxMenuConfigPage
, InsertHdl
, const OString
&, rIdent
, void)
438 if (rIdent
== "insertseparator")
440 SvxConfigEntry
* pNewEntryData
= new SvxConfigEntry
;
441 pNewEntryData
->SetUserDefined();
442 int nPos
= InsertEntry(pNewEntryData
, -1);
443 InsertEntryIntoUI(pNewEntryData
, nPos
, 0);
445 else if (rIdent
== "insertsubmenu")
448 OUString aDesc
= CuiResId( RID_SVXSTR_SUBMENU_NAME
);
450 SvxNameDialog
aNameDialog(GetDialogFrameWeld(), aNewName
, aDesc
);
451 aNameDialog
.set_help_id(HID_SVX_CONFIG_NAME_SUBMENU
);
452 aNameDialog
.set_title(CuiResId( RID_SVXSTR_ADD_SUBMENU
));
454 if (aNameDialog
.run() == RET_OK
)
456 aNewName
= aNameDialog
.GetName();
458 SvxConfigEntry
* pNewEntryData
=
459 new SvxConfigEntry( aNewName
, aNewName
, true, /*bParentData*/false );
460 pNewEntryData
->SetName( aNewName
);
461 pNewEntryData
->SetUserDefined();
463 int nPos
= InsertEntry(pNewEntryData
, -1);
464 InsertEntryIntoUI(pNewEntryData
, nPos
, 0);
466 ReloadTopLevelListBox();
468 m_xContentsListBox
->scroll_to_row(nPos
);
469 m_xContentsListBox
->select(nPos
);
471 GetSaveInData()->SetModified();
477 //This block should never be reached
478 SAL_WARN("cui.customize", "Unknown insert option: " << rIdent
);
482 if ( GetSaveInData()->IsModified() )
484 UpdateButtonStates();
488 IMPL_LINK(SvxMenuConfigPage
, ModifyItemHdl
, const OString
&, rIdent
, void)
490 if (rIdent
== "renameItem")
492 int nActEntry
= m_xContentsListBox
->get_selected_index();
493 SvxConfigEntry
* pEntry
=
494 reinterpret_cast<SvxConfigEntry
*>(m_xContentsListBox
->get_id(nActEntry
).toInt64());
496 OUString
aNewName( SvxConfigPageHelper::stripHotKey( pEntry
->GetName() ) );
497 OUString aDesc
= CuiResId( RID_SVXSTR_LABEL_NEW_NAME
);
499 SvxNameDialog
aNameDialog(GetDialogFrameWeld(), aNewName
, aDesc
);
500 aNameDialog
.set_help_id(HID_SVX_CONFIG_RENAME_MENU_ITEM
);
501 aNameDialog
.set_title(CuiResId(RID_SVXSTR_RENAME_MENU
));
503 if (aNameDialog
.run() == RET_OK
)
505 aNewName
= aNameDialog
.GetName();
507 pEntry
->SetName( aNewName
);
508 m_xContentsListBox
->set_text(nActEntry
, aNewName
, 1);
510 GetSaveInData()->SetModified();
511 GetTopLevelSelection()->SetModified();
516 //This block should never be reached
517 SAL_WARN("cui.customize", "Unknown insert option: " << rIdent
);
521 if ( GetSaveInData()->IsModified() )
523 UpdateButtonStates();
527 IMPL_LINK_NOARG(SvxMenuConfigPage
, ResetMenuHdl
, weld::Button
&, void)
529 SvxConfigEntry
* pMenuData
= GetTopLevelSelection();
531 if (pMenuData
== nullptr)
533 SAL_WARN("cui.customize", "RHB top level selection is null. A menu must be selected to reset!");
537 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(GetDialogFrameWeld(),
538 VclMessageType::Question
, VclButtonsType::YesNo
,
539 CuiResId(RID_SVXSTR_CONFIRM_RESTORE_DEFAULT_MENU
)));
541 // Resetting individual top-level menus is not possible at the moment.
542 // So we are resetting only if it is a context menu
543 if (!m_bIsMenuBar
&& xQueryBox
->run() == RET_YES
)
545 sal_Int32 nPos
= m_xTopLevelListBox
->get_active();
546 ContextMenuSaveInData
* pSaveInData
= static_cast< ContextMenuSaveInData
* >(GetSaveInData());
548 pSaveInData
->ResetContextMenu(pMenuData
);
550 // ensure that the UI is cleared before populating it
551 m_xTopLevelListBox
->clear();
552 m_xContentsListBox
->clear();
554 ReloadTopLevelListBox();
556 // Reselect the reset menu
557 m_xTopLevelListBox
->set_active(nPos
);
562 SaveInData
* SvxMenuConfigPage::CreateSaveInData(
563 const css::uno::Reference
< css::ui::XUIConfigurationManager
>& xCfgMgr
,
564 const css::uno::Reference
< css::ui::XUIConfigurationManager
>& xParentCfgMgr
,
565 const OUString
& aModuleId
,
569 return static_cast< SaveInData
* >( new ContextMenuSaveInData( xCfgMgr
, xParentCfgMgr
, aModuleId
, bDocConfig
) );
571 return static_cast< SaveInData
* >( new MenuSaveInData( xCfgMgr
, xParentCfgMgr
, aModuleId
, bDocConfig
) );
574 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */