android: Update app-specific/MIME type icons
[LibreOffice.git] / cui / source / customize / SvxMenuConfigPage.cxx
blob3ec1f2a531e1c09eb3fc0cd73691be3891cc3b43
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <cui/dlgname.hxx>
24 #include <vcl/weld.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/commandevent.hxx>
28 #include <strings.hrc>
29 #include <helpids.h>
31 #include <cfg.hxx>
32 #include <SvxMenuConfigPage.hxx>
33 #include <SvxConfigPageHelper.hxx>
34 #include <dialmgr.hxx>
36 #include <comphelper/processfactory.hxx>
38 SvxMenuConfigPage::SvxMenuConfigPage(weld::Container* pPage, weld::DialogController* pController,
39 const SfxItemSet& rSet, bool bIsMenuBar)
40 : SvxConfigPage(pPage, pController, rSet)
41 , m_bIsMenuBar(bIsMenuBar)
43 m_xGearBtn = m_xBuilder->weld_menu_button("menugearbtn");
44 m_xGearBtn->show();
45 m_xContentsListBox.reset(
46 new SvxMenuEntriesListBox(m_xBuilder->weld_tree_view("menucontents"), this));
47 weld::TreeView& rTreeView = m_xContentsListBox->get_widget();
48 m_xDropTargetHelper.reset(new SvxConfigPageFunctionDropTarget(*this, rTreeView));
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);
55 rTreeView.show();
57 rTreeView.connect_changed(LINK(this, SvxMenuConfigPage, SelectMenuEntry));
58 rTreeView.connect_popup_menu(LINK(this, SvxMenuConfigPage, ContentContextMenuHdl));
60 m_xFunctions->get_widget().connect_popup_menu(
61 LINK(this, SvxMenuConfigPage, FunctionContextMenuHdl));
63 m_xGearBtn->connect_selected(LINK(this, SvxMenuConfigPage, GearHdl));
65 m_xCommandCategoryListBox->connect_changed(LINK(this, SvxMenuConfigPage, SelectCategory));
67 m_xMoveUpButton->connect_clicked(LINK(this, SvxConfigPage, MoveHdl));
68 m_xMoveDownButton->connect_clicked(LINK(this, SvxConfigPage, MoveHdl));
70 m_xAddCommandButton->connect_clicked(LINK(this, SvxMenuConfigPage, AddCommandHdl));
71 m_xRemoveCommandButton->connect_clicked(LINK(this, SvxMenuConfigPage, RemoveCommandHdl));
73 m_xInsertBtn->connect_selected(LINK(this, SvxMenuConfigPage, InsertHdl));
74 m_xModifyBtn->connect_selected(LINK(this, SvxMenuConfigPage, ModifyItemHdl));
75 m_xResetBtn->connect_clicked(LINK(this, SvxMenuConfigPage, ResetMenuHdl));
77 // These operations are not possible on menus/context menus yet
78 m_xModifyBtn->remove_item("changeIcon");
79 m_xModifyBtn->remove_item("resetIcon");
80 m_xModifyBtn->remove_item("restoreItem");
82 if (!bIsMenuBar)
84 //TODO: Remove this when the gear button is implemented for context menus
85 m_xGearBtn->set_sensitive(false);
86 m_xGearBtn->hide();
88 else
90 // TODO: Remove this when it is possible to reset menubar menus individually
91 m_xResetBtn->set_sensitive(false);
95 void SvxMenuConfigPage::ListModified()
97 // regenerate with the current ordering within the list
98 SvxEntries* pEntries = GetTopLevelSelection()->GetEntries();
99 pEntries->clear();
101 for (int i = 0; i < m_xContentsListBox->n_children(); ++i)
102 pEntries->push_back(weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(i)));
104 GetSaveInData()->SetModified();
105 GetTopLevelSelection()->SetModified();
106 UpdateButtonStates();
109 IMPL_LINK(SvxMenuConfigPage, MenuEntriesSizeAllocHdl, const Size&, rSize, void)
111 weld::TreeView& rTreeView = m_xContentsListBox->get_widget();
112 std::vector<int> aWidths;
114 int nStandardImageColWidth = rTreeView.get_checkbox_column_width();
115 int nMargin = 16;
117 aWidths.push_back(rSize.Width() - (nMargin + nStandardImageColWidth));
118 rTreeView.set_column_fixed_widths(aWidths);
121 SvxMenuConfigPage::~SvxMenuConfigPage()
123 for (int i = 0, nCount = m_xSaveInListBox->get_count(); i < nCount; ++i)
124 delete weld::fromId<SaveInData*>(m_xSaveInListBox->get_id(i));
125 m_xSaveInListBox->clear();
128 // Populates the Menu combo box
129 void SvxMenuConfigPage::Init()
131 // ensure that the UI is cleared before populating it
132 m_xTopLevelListBox->clear();
133 m_xContentsListBox->clear();
135 ReloadTopLevelListBox();
137 m_xTopLevelListBox->set_active(m_xTopLevelListBox->get_count() ? 0 : -1);
138 SelectElement();
140 m_xCommandCategoryListBox->Init(comphelper::getProcessComponentContext(), m_xFrame,
141 m_aModuleId);
142 m_xCommandCategoryListBox->categorySelected(m_xFunctions.get(), OUString(), GetSaveInData());
143 SelectFunctionHdl(m_xFunctions->get_widget());
146 IMPL_LINK_NOARG(SvxMenuConfigPage, SelectMenuEntry, weld::TreeView&, void) { UpdateButtonStates(); }
148 void SvxMenuConfigPage::UpdateButtonStates()
150 // Disable Up and Down buttons depending on current selection
151 int selection = m_xContentsListBox->get_selected_index();
153 bool bIsSeparator
154 = selection != -1
155 && weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(selection))->IsSeparator();
156 bool bIsValidSelection = (m_xContentsListBox->n_children() != 0 && selection != -1);
158 m_xMoveUpButton->set_sensitive(bIsValidSelection && selection != 0);
159 m_xMoveDownButton->set_sensitive(bIsValidSelection
160 && selection != m_xContentsListBox->n_children() - 1);
162 m_xRemoveCommandButton->set_sensitive(bIsValidSelection);
164 m_xModifyBtn->set_sensitive(bIsValidSelection && !bIsSeparator);
166 // If there is no top level selection (menu), then everything working on the right box
167 // which contains the functions of the selected menu/toolbar needs to be disabled
168 SvxConfigEntry* pMenuData = GetTopLevelSelection();
170 m_xInsertBtn->set_sensitive(pMenuData != nullptr);
172 SvxConfigEntry* selectedCmd = CreateCommandFromSelection(GetScriptURL());
174 m_xAddCommandButton->set_sensitive(
175 pMenuData != nullptr && !IsCommandInMenuList(selectedCmd, pMenuData->GetEntries()));
177 delete selectedCmd;
179 if (bIsValidSelection)
181 m_xRemoveCommandButton->set_sensitive(pMenuData != nullptr);
184 //Handle the gear button
185 if (pMenuData && m_bIsMenuBar)
187 // Add option (gear_add) will always be enabled
188 m_xGearBtn->set_item_sensitive("menu_gear_delete", pMenuData->IsDeletable());
189 m_xGearBtn->set_item_sensitive("menu_gear_rename", pMenuData->IsRenamable());
190 m_xGearBtn->set_item_sensitive("menu_gear_move", pMenuData->IsMovable());
194 void SvxMenuConfigPage::DeleteSelectedTopLevel()
196 SvxConfigEntry* pMenuData = GetTopLevelSelection();
198 SvxEntries* pParentEntries = FindParentForChild(GetSaveInData()->GetEntries(), pMenuData);
200 SvxConfigPageHelper::RemoveEntry(pParentEntries, pMenuData);
201 delete pMenuData;
203 ReloadTopLevelListBox();
205 GetSaveInData()->SetModified();
208 void SvxMenuConfigPage::DeleteSelectedContent()
210 int nActEntry = m_xContentsListBox->get_selected_index();
212 if (nActEntry == -1)
213 return;
215 // get currently selected menu entry
216 SvxConfigEntry* pMenuEntry
217 = weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nActEntry));
219 // get currently selected menu
220 SvxConfigEntry* pMenu = GetTopLevelSelection();
222 // remove menu entry from the list for this menu
223 SvxConfigPageHelper::RemoveEntry(pMenu->GetEntries(), pMenuEntry);
225 // remove menu entry from UI
226 m_xContentsListBox->remove(nActEntry);
228 // if this is a submenu entry, redraw the menus list box
229 if (pMenuEntry->IsPopup())
231 ReloadTopLevelListBox();
234 // delete data for menu entry
235 delete pMenuEntry;
237 GetSaveInData()->SetModified();
238 pMenu->SetModified();
241 short SvxMenuConfigPage::QueryReset()
243 OUString msg = CuiResId(RID_CUISTR_CONFIRM_MENU_RESET);
245 OUString saveInName = m_xSaveInListBox->get_active_text();
247 OUString label = SvxConfigPageHelper::replaceSaveInName(msg, saveInName);
249 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(
250 GetFrameWeld(), VclMessageType::Question, VclButtonsType::YesNo, label));
251 return xQueryBox->run();
254 void SvxMenuConfigPage::SelectElement()
256 weld::TreeView& rTreeView = m_xContentsListBox->get_widget();
258 SvxConfigEntry* pMenuData = GetTopLevelSelection();
259 if (!pMenuData)
260 rTreeView.clear();
261 else
263 SvxEntries* pEntries = pMenuData->GetEntries();
265 rTreeView.bulk_insert_for_each(
266 pEntries->size(), [this, &rTreeView, pEntries](weld::TreeIter& rIter, int nIdx) {
267 auto const& entry = (*pEntries)[nIdx];
268 OUString sId(weld::toId(entry));
269 rTreeView.set_id(rIter, sId);
270 InsertEntryIntoUI(entry, rTreeView, rIter, true);
274 UpdateButtonStates();
277 IMPL_LINK(SvxMenuConfigPage, GearHdl, const OUString&, rIdent, void)
279 if (rIdent == "menu_gear_add")
281 SvxMainMenuOrganizerDialog aDialog(GetFrameWeld(), GetSaveInData()->GetEntries(), nullptr,
282 true);
284 if (aDialog.run() == RET_OK)
286 GetSaveInData()->SetEntries(aDialog.ReleaseEntries());
287 ReloadTopLevelListBox(aDialog.GetSelectedEntry());
288 GetSaveInData()->SetModified();
291 else if (rIdent == "menu_gear_delete")
293 DeleteSelectedTopLevel();
295 else if (rIdent == "menu_gear_rename")
297 SvxConfigEntry* pMenuData = GetTopLevelSelection();
299 OUString sCurrentName(SvxConfigPageHelper::stripHotKey(pMenuData->GetName()));
300 OUString sDesc = CuiResId(RID_CUISTR_LABEL_NEW_NAME);
302 SvxNameDialog aNameDialog(GetFrameWeld(), sCurrentName, sDesc);
303 aNameDialog.set_help_id(HID_SVX_CONFIG_RENAME_MENU);
304 aNameDialog.set_title(CuiResId(RID_CUISTR_RENAME_MENU));
306 if (aNameDialog.run() == RET_OK)
308 OUString sNewName = aNameDialog.GetName();
310 if (sCurrentName == sNewName)
311 return;
313 pMenuData->SetName(sNewName);
315 ReloadTopLevelListBox();
317 GetSaveInData()->SetModified();
320 else if (rIdent == "menu_gear_move")
322 SvxConfigEntry* pMenuData = GetTopLevelSelection();
324 SvxMainMenuOrganizerDialog aDialog(GetFrameWeld(), GetSaveInData()->GetEntries(), pMenuData,
325 false);
326 if (aDialog.run() == RET_OK)
328 GetSaveInData()->SetEntries(aDialog.ReleaseEntries());
330 ReloadTopLevelListBox();
332 GetSaveInData()->SetModified();
335 else
337 //This block should never be reached
338 SAL_WARN("cui.customize", "Unknown gear menu option: " << rIdent);
339 return;
342 UpdateButtonStates();
345 IMPL_LINK_NOARG(SvxMenuConfigPage, SelectCategory, weld::ComboBox&, void)
347 OUString aSearchTerm(m_xSearchEdit->get_text());
349 m_xCommandCategoryListBox->categorySelected(m_xFunctions.get(), aSearchTerm, GetSaveInData());
351 SelectFunctionHdl(m_xFunctions->get_widget());
354 IMPL_LINK_NOARG(SvxMenuConfigPage, AddCommandHdl, weld::Button&, void)
356 int nPos = AddFunction(-1, /*bAllowDuplicates*/ false);
357 if (nPos == -1)
358 return;
359 weld::TreeView& rTreeView = m_xContentsListBox->get_widget();
360 SvxConfigEntry* pEntry = weld::fromId<SvxConfigEntry*>(rTreeView.get_id(nPos));
361 InsertEntryIntoUI(pEntry, rTreeView, nPos, true);
364 IMPL_LINK_NOARG(SvxMenuConfigPage, RemoveCommandHdl, weld::Button&, void)
366 DeleteSelectedContent();
367 if (GetSaveInData()->IsModified())
369 UpdateButtonStates();
373 IMPL_LINK(SvxMenuConfigPage, InsertHdl, const OUString&, rIdent, void)
375 weld::TreeView& rTreeView = m_xContentsListBox->get_widget();
376 if (rIdent == "insertseparator")
378 SvxConfigEntry* pNewEntryData = new SvxConfigEntry;
379 pNewEntryData->SetUserDefined();
380 int nPos = AppendEntry(pNewEntryData, -1);
381 InsertEntryIntoUI(pNewEntryData, rTreeView, nPos, true);
383 else if (rIdent == "insertsubmenu")
385 OUString aNewName;
386 OUString aDesc = CuiResId(RID_CUISTR_SUBMENU_NAME);
388 SvxNameDialog aNameDialog(GetFrameWeld(), aNewName, aDesc);
389 aNameDialog.set_help_id(HID_SVX_CONFIG_NAME_SUBMENU);
390 aNameDialog.set_title(CuiResId(RID_CUISTR_ADD_SUBMENU));
392 if (aNameDialog.run() == RET_OK)
394 aNewName = aNameDialog.GetName();
396 SvxConfigEntry* pNewEntryData
397 = new SvxConfigEntry(aNewName, aNewName, true, /*bParentData*/ false);
398 pNewEntryData->SetName(aNewName);
399 pNewEntryData->SetUserDefined();
401 int nPos = AppendEntry(pNewEntryData, -1);
402 InsertEntryIntoUI(pNewEntryData, rTreeView, nPos, true);
404 ReloadTopLevelListBox();
406 m_xContentsListBox->scroll_to_row(nPos);
407 m_xContentsListBox->select(nPos);
409 GetSaveInData()->SetModified();
412 else
414 //This block should never be reached
415 SAL_WARN("cui.customize", "Unknown insert option: " << rIdent);
416 return;
419 if (GetSaveInData()->IsModified())
421 UpdateButtonStates();
425 IMPL_LINK(SvxMenuConfigPage, ModifyItemHdl, const OUString&, rIdent, void)
427 if (rIdent == "renameItem")
429 int nActEntry = m_xContentsListBox->get_selected_index();
430 SvxConfigEntry* pEntry
431 = weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nActEntry));
433 OUString aNewName(SvxConfigPageHelper::stripHotKey(pEntry->GetName()));
434 OUString aDesc = CuiResId(RID_CUISTR_LABEL_NEW_NAME);
436 SvxNameDialog aNameDialog(GetFrameWeld(), aNewName, aDesc);
437 aNameDialog.set_help_id(HID_SVX_CONFIG_RENAME_MENU_ITEM);
438 aNameDialog.set_title(CuiResId(RID_CUISTR_RENAME_MENU));
440 if (aNameDialog.run() == RET_OK)
442 aNewName = aNameDialog.GetName();
444 pEntry->SetName(aNewName);
445 m_xContentsListBox->set_text(nActEntry, aNewName, 0);
447 GetSaveInData()->SetModified();
448 GetTopLevelSelection()->SetModified();
451 else
453 //This block should never be reached
454 SAL_WARN("cui.customize", "Unknown insert option: " << rIdent);
455 return;
458 if (GetSaveInData()->IsModified())
460 UpdateButtonStates();
464 IMPL_LINK_NOARG(SvxMenuConfigPage, ResetMenuHdl, weld::Button&, void)
466 SvxConfigEntry* pMenuData = GetTopLevelSelection();
468 if (pMenuData == nullptr)
470 SAL_WARN("cui.customize",
471 "RHB top level selection is null. A menu must be selected to reset!");
472 return;
475 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(
476 GetFrameWeld(), VclMessageType::Question, VclButtonsType::YesNo,
477 CuiResId(RID_CUISTR_CONFIRM_RESTORE_DEFAULT_MENU)));
479 // Resetting individual top-level menus is not possible at the moment.
480 // So we are resetting only if it is a context menu
481 if (m_bIsMenuBar || xQueryBox->run() != RET_YES)
482 return;
484 sal_Int32 nPos = m_xTopLevelListBox->get_active();
485 ContextMenuSaveInData* pSaveInData = static_cast<ContextMenuSaveInData*>(GetSaveInData());
487 pSaveInData->ResetContextMenu(pMenuData);
489 // ensure that the UI is cleared before populating it
490 m_xTopLevelListBox->clear();
491 m_xContentsListBox->clear();
493 ReloadTopLevelListBox();
495 // Reselect the reset menu
496 m_xTopLevelListBox->set_active(nPos);
497 SelectElement();
500 SaveInData* SvxMenuConfigPage::CreateSaveInData(
501 const css::uno::Reference<css::ui::XUIConfigurationManager>& xCfgMgr,
502 const css::uno::Reference<css::ui::XUIConfigurationManager>& xParentCfgMgr,
503 const OUString& aModuleId, bool bDocConfig)
505 if (!m_bIsMenuBar)
506 return static_cast<SaveInData*>(
507 new ContextMenuSaveInData(xCfgMgr, xParentCfgMgr, aModuleId, bDocConfig));
509 return static_cast<SaveInData*>(
510 new MenuSaveInData(xCfgMgr, xParentCfgMgr, aModuleId, bDocConfig));
513 IMPL_LINK(SvxMenuConfigPage, ContentContextMenuHdl, const CommandEvent&, rCEvt, bool)
515 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
516 return false;
518 weld::TreeView& rTreeView = m_xContentsListBox->get_widget();
520 // Select clicked entry
521 std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
522 if (!rTreeView.get_dest_row_at_pos(rCEvt.GetMousePosPixel(), xIter.get(), false))
523 return false;
524 rTreeView.select(*xIter);
525 SelectMenuEntry(rTreeView);
527 int nSelectIndex = m_xContentsListBox->get_selected_index();
529 bool bIsSeparator
530 = nSelectIndex != -1
531 && weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nSelectIndex))->IsSeparator();
532 bool bIsValidSelection = (m_xContentsListBox->n_children() != 0 && nSelectIndex != -1);
534 std::unique_ptr<weld::Builder> xBuilder(
535 Application::CreateBuilder(&rTreeView, "cui/ui/entrycontextmenu.ui"));
536 auto xContextMenu = xBuilder->weld_menu("menu");
537 xContextMenu->set_visible("add", false);
538 xContextMenu->set_visible("remove", bIsValidSelection);
539 xContextMenu->set_visible("rename", bIsValidSelection && !bIsSeparator);
540 xContextMenu->set_visible("changeIcon", false);
541 xContextMenu->set_visible("resetIcon", false);
542 xContextMenu->set_visible("restoreDefault", false);
543 OUString sCommand(xContextMenu->popup_at_rect(
544 &rTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1))));
546 if (sCommand == "remove")
548 RemoveCommandHdl(*m_xRemoveCommandButton);
550 else if (sCommand == "rename")
552 ModifyItemHdl("renameItem");
554 else if (!sCommand.isEmpty())
555 SAL_WARN("cui.customize", "Unknown context menu action: " << sCommand);
556 return true;
559 IMPL_LINK(SvxMenuConfigPage, FunctionContextMenuHdl, const CommandEvent&, rCEvt, bool)
561 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
562 return false;
564 weld::TreeView& rTreeView = m_xFunctions->get_widget();
566 // Select clicked entry
567 std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
568 if (!rTreeView.get_dest_row_at_pos(rCEvt.GetMousePosPixel(), xIter.get(), false))
569 return false;
570 rTreeView.select(*xIter);
571 SelectFunctionHdl(rTreeView);
573 std::unique_ptr<weld::Builder> xBuilder(
574 Application::CreateBuilder(&rTreeView, "cui/ui/entrycontextmenu.ui"));
575 auto xContextMenu = xBuilder->weld_menu("menu");
576 xContextMenu->set_visible("add", true);
577 xContextMenu->set_visible("remove", false);
578 xContextMenu->set_visible("rename", false);
579 xContextMenu->set_visible("changeIcon", false);
580 xContextMenu->set_visible("resetIcon", false);
581 xContextMenu->set_visible("restoreDefault", false);
582 OUString sCommand(xContextMenu->popup_at_rect(
583 &rTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1))));
585 if (sCommand == "add")
587 AddCommandHdl(*m_xAddCommandButton);
589 else if (!sCommand.isEmpty())
590 SAL_WARN("cui.customize", "Unknown context menu action: " << sCommand);
591 return true;
594 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */