diff options
Diffstat (limited to '')
-rw-r--r-- | cui/source/customize/SvxMenuConfigPage.cxx | 595 |
1 files changed, 595 insertions, 0 deletions
diff --git a/cui/source/customize/SvxMenuConfigPage.cxx b/cui/source/customize/SvxMenuConfigPage.cxx new file mode 100644 index 000000000..5793825b5 --- /dev/null +++ b/cui/source/customize/SvxMenuConfigPage.cxx @@ -0,0 +1,595 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> +#include <sal/log.hxx> + +#include <vcl/weld.hxx> +#include <vcl/svapp.hxx> +#include <vcl/commandevent.hxx> + +#include <strings.hrc> +#include <helpids.h> + +#include <cfg.hxx> +#include <SvxMenuConfigPage.hxx> +#include <SvxConfigPageHelper.hxx> +#include <dialmgr.hxx> + +#include <comphelper/processfactory.hxx> + +#include <dlgname.hxx> + +SvxMenuConfigPage::SvxMenuConfigPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet, bool bIsMenuBar) + : SvxConfigPage(pPage, pController, rSet) + , m_bIsMenuBar(bIsMenuBar) +{ + m_xGearBtn = m_xBuilder->weld_menu_button("menugearbtn"); + m_xGearBtn->show(); + m_xContentsListBox.reset( + new SvxMenuEntriesListBox(m_xBuilder->weld_tree_view("menucontents"), this)); + weld::TreeView& rTreeView = m_xContentsListBox->get_widget(); + m_xDropTargetHelper.reset(new SvxConfigPageFunctionDropTarget(*this, rTreeView)); + rTreeView.connect_size_allocate(LINK(this, SvxMenuConfigPage, MenuEntriesSizeAllocHdl)); + Size aSize(m_xFunctions->get_size_request()); + rTreeView.set_size_request(aSize.Width(), aSize.Height()); + MenuEntriesSizeAllocHdl(aSize); + rTreeView.set_hexpand(true); + rTreeView.set_vexpand(true); + rTreeView.show(); + + rTreeView.connect_changed(LINK(this, SvxMenuConfigPage, SelectMenuEntry)); + rTreeView.connect_popup_menu(LINK(this, SvxMenuConfigPage, ContentContextMenuHdl)); + + m_xFunctions->get_widget().connect_popup_menu( + LINK(this, SvxMenuConfigPage, FunctionContextMenuHdl)); + + m_xGearBtn->connect_selected(LINK(this, SvxMenuConfigPage, GearHdl)); + + m_xCommandCategoryListBox->connect_changed(LINK(this, SvxMenuConfigPage, SelectCategory)); + + m_xMoveUpButton->connect_clicked(LINK(this, SvxConfigPage, MoveHdl)); + m_xMoveDownButton->connect_clicked(LINK(this, SvxConfigPage, MoveHdl)); + + m_xAddCommandButton->connect_clicked(LINK(this, SvxMenuConfigPage, AddCommandHdl)); + m_xRemoveCommandButton->connect_clicked(LINK(this, SvxMenuConfigPage, RemoveCommandHdl)); + + m_xInsertBtn->connect_selected(LINK(this, SvxMenuConfigPage, InsertHdl)); + m_xModifyBtn->connect_selected(LINK(this, SvxMenuConfigPage, ModifyItemHdl)); + m_xResetBtn->connect_clicked(LINK(this, SvxMenuConfigPage, ResetMenuHdl)); + + // These operations are not possible on menus/context menus yet + m_xModifyBtn->remove_item("changeIcon"); + m_xModifyBtn->remove_item("resetIcon"); + m_xModifyBtn->remove_item("restoreItem"); + + if (!bIsMenuBar) + { + //TODO: Remove this when the gear button is implemented for context menus + m_xGearBtn->set_sensitive(false); + m_xGearBtn->hide(); + } + else + { + // TODO: Remove this when it is possible to reset menubar menus individually + m_xResetBtn->set_sensitive(false); + } +} + +void SvxMenuConfigPage::ListModified() +{ + // regenerate with the current ordering within the list + SvxEntries* pEntries = GetTopLevelSelection()->GetEntries(); + pEntries->clear(); + + for (int i = 0; i < m_xContentsListBox->n_children(); ++i) + pEntries->push_back(weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(i))); + + GetSaveInData()->SetModified(); + GetTopLevelSelection()->SetModified(); + UpdateButtonStates(); +} + +IMPL_LINK(SvxMenuConfigPage, MenuEntriesSizeAllocHdl, const Size&, rSize, void) +{ + weld::TreeView& rTreeView = m_xContentsListBox->get_widget(); + std::vector<int> aWidths; + + int nStandardImageColWidth = rTreeView.get_checkbox_column_width(); + int nMargin = 16; + + aWidths.push_back(rSize.Width() - (nMargin + nStandardImageColWidth)); + rTreeView.set_column_fixed_widths(aWidths); +} + +SvxMenuConfigPage::~SvxMenuConfigPage() +{ + for (int i = 0, nCount = m_xSaveInListBox->get_count(); i < nCount; ++i) + delete weld::fromId<SaveInData*>(m_xSaveInListBox->get_id(i)); + m_xSaveInListBox->clear(); +} + +// Populates the Menu combo box +void SvxMenuConfigPage::Init() +{ + // ensure that the UI is cleared before populating it + m_xTopLevelListBox->clear(); + m_xContentsListBox->clear(); + + ReloadTopLevelListBox(); + + m_xTopLevelListBox->set_active(m_xTopLevelListBox->get_count() ? 0 : -1); + SelectElement(); + + m_xCommandCategoryListBox->Init(comphelper::getProcessComponentContext(), m_xFrame, + m_aModuleId); + m_xCommandCategoryListBox->categorySelected(m_xFunctions.get(), OUString(), GetSaveInData()); + SelectFunctionHdl(m_xFunctions->get_widget()); +} + +IMPL_LINK_NOARG(SvxMenuConfigPage, SelectMenuEntry, weld::TreeView&, void) { UpdateButtonStates(); } + +void SvxMenuConfigPage::UpdateButtonStates() +{ + // Disable Up and Down buttons depending on current selection + int selection = m_xContentsListBox->get_selected_index(); + + bool bIsSeparator + = selection != -1 + && weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(selection))->IsSeparator(); + bool bIsValidSelection = (m_xContentsListBox->n_children() != 0 && selection != -1); + + m_xMoveUpButton->set_sensitive(bIsValidSelection && selection != 0); + m_xMoveDownButton->set_sensitive(bIsValidSelection + && selection != m_xContentsListBox->n_children() - 1); + + m_xRemoveCommandButton->set_sensitive(bIsValidSelection); + + m_xModifyBtn->set_sensitive(bIsValidSelection && !bIsSeparator); + + // If there is no top level selection (menu), then everything working on the right box + // which contains the functions of the selected menu/toolbar needs to be disabled + SvxConfigEntry* pMenuData = GetTopLevelSelection(); + + m_xInsertBtn->set_sensitive(pMenuData != nullptr); + + SvxConfigEntry* selectedCmd = CreateCommandFromSelection(GetScriptURL()); + + m_xAddCommandButton->set_sensitive( + pMenuData != nullptr && !IsCommandInMenuList(selectedCmd, pMenuData->GetEntries())); + + delete selectedCmd; + + if (bIsValidSelection) + { + m_xRemoveCommandButton->set_sensitive(pMenuData != nullptr); + } + + //Handle the gear button + if (pMenuData && m_bIsMenuBar) + { + // Add option (gear_add) will always be enabled + m_xGearBtn->set_item_sensitive("menu_gear_delete", pMenuData->IsDeletable()); + m_xGearBtn->set_item_sensitive("menu_gear_rename", pMenuData->IsRenamable()); + m_xGearBtn->set_item_sensitive("menu_gear_move", pMenuData->IsMovable()); + } +} + +void SvxMenuConfigPage::DeleteSelectedTopLevel() +{ + SvxConfigEntry* pMenuData = GetTopLevelSelection(); + + SvxEntries* pParentEntries = FindParentForChild(GetSaveInData()->GetEntries(), pMenuData); + + SvxConfigPageHelper::RemoveEntry(pParentEntries, pMenuData); + delete pMenuData; + + ReloadTopLevelListBox(); + + GetSaveInData()->SetModified(); +} + +void SvxMenuConfigPage::DeleteSelectedContent() +{ + int nActEntry = m_xContentsListBox->get_selected_index(); + + if (nActEntry == -1) + return; + + // get currently selected menu entry + SvxConfigEntry* pMenuEntry + = weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nActEntry)); + + // get currently selected menu + SvxConfigEntry* pMenu = GetTopLevelSelection(); + + // remove menu entry from the list for this menu + SvxConfigPageHelper::RemoveEntry(pMenu->GetEntries(), pMenuEntry); + + // remove menu entry from UI + m_xContentsListBox->remove(nActEntry); + + // if this is a submenu entry, redraw the menus list box + if (pMenuEntry->IsPopup()) + { + ReloadTopLevelListBox(); + } + + // delete data for menu entry + delete pMenuEntry; + + GetSaveInData()->SetModified(); + pMenu->SetModified(); +} + +short SvxMenuConfigPage::QueryReset() +{ + OUString msg = CuiResId(RID_CUISTR_CONFIRM_MENU_RESET); + + OUString saveInName = m_xSaveInListBox->get_active_text(); + + OUString label = SvxConfigPageHelper::replaceSaveInName(msg, saveInName); + + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog( + GetFrameWeld(), VclMessageType::Question, VclButtonsType::YesNo, label)); + return xQueryBox->run(); +} + +void SvxMenuConfigPage::SelectElement() +{ + weld::TreeView& rTreeView = m_xContentsListBox->get_widget(); + + SvxConfigEntry* pMenuData = GetTopLevelSelection(); + if (!pMenuData) + rTreeView.clear(); + else + { + SvxEntries* pEntries = pMenuData->GetEntries(); + + rTreeView.bulk_insert_for_each( + pEntries->size(), [this, &rTreeView, pEntries](weld::TreeIter& rIter, int nIdx) { + auto const& entry = (*pEntries)[nIdx]; + OUString sId(weld::toId(entry)); + rTreeView.set_id(rIter, sId); + InsertEntryIntoUI(entry, rTreeView, rIter, true); + }); + } + + UpdateButtonStates(); +} + +IMPL_LINK(SvxMenuConfigPage, GearHdl, const OString&, rIdent, void) +{ + if (rIdent == "menu_gear_add") + { + SvxMainMenuOrganizerDialog aDialog(GetFrameWeld(), GetSaveInData()->GetEntries(), nullptr, + true); + + if (aDialog.run() == RET_OK) + { + GetSaveInData()->SetEntries(aDialog.ReleaseEntries()); + ReloadTopLevelListBox(aDialog.GetSelectedEntry()); + GetSaveInData()->SetModified(); + } + } + else if (rIdent == "menu_gear_delete") + { + DeleteSelectedTopLevel(); + } + else if (rIdent == "menu_gear_rename") + { + SvxConfigEntry* pMenuData = GetTopLevelSelection(); + + OUString sCurrentName(SvxConfigPageHelper::stripHotKey(pMenuData->GetName())); + OUString sDesc = CuiResId(RID_CUISTR_LABEL_NEW_NAME); + + SvxNameDialog aNameDialog(GetFrameWeld(), sCurrentName, sDesc); + aNameDialog.set_help_id(HID_SVX_CONFIG_RENAME_MENU); + aNameDialog.set_title(CuiResId(RID_CUISTR_RENAME_MENU)); + + if (aNameDialog.run() == RET_OK) + { + OUString sNewName = aNameDialog.GetName(); + + if (sCurrentName == sNewName) + return; + + pMenuData->SetName(sNewName); + + ReloadTopLevelListBox(); + + GetSaveInData()->SetModified(); + } + } + else if (rIdent == "menu_gear_move") + { + SvxConfigEntry* pMenuData = GetTopLevelSelection(); + + SvxMainMenuOrganizerDialog aDialog(GetFrameWeld(), GetSaveInData()->GetEntries(), pMenuData, + false); + if (aDialog.run() == RET_OK) + { + GetSaveInData()->SetEntries(aDialog.ReleaseEntries()); + + ReloadTopLevelListBox(); + + GetSaveInData()->SetModified(); + } + } + else + { + //This block should never be reached + SAL_WARN("cui.customize", "Unknown gear menu option: " << rIdent); + return; + } + + UpdateButtonStates(); +} + +IMPL_LINK_NOARG(SvxMenuConfigPage, SelectCategory, weld::ComboBox&, void) +{ + OUString aSearchTerm(m_xSearchEdit->get_text()); + + m_xCommandCategoryListBox->categorySelected(m_xFunctions.get(), aSearchTerm, GetSaveInData()); + + SelectFunctionHdl(m_xFunctions->get_widget()); +} + +IMPL_LINK_NOARG(SvxMenuConfigPage, AddCommandHdl, weld::Button&, void) +{ + int nPos = AddFunction(-1, /*bAllowDuplicates*/ false); + if (nPos == -1) + return; + weld::TreeView& rTreeView = m_xContentsListBox->get_widget(); + SvxConfigEntry* pEntry = weld::fromId<SvxConfigEntry*>(rTreeView.get_id(nPos)); + InsertEntryIntoUI(pEntry, rTreeView, nPos, true); +} + +IMPL_LINK_NOARG(SvxMenuConfigPage, RemoveCommandHdl, weld::Button&, void) +{ + DeleteSelectedContent(); + if (GetSaveInData()->IsModified()) + { + UpdateButtonStates(); + } +} + +IMPL_LINK(SvxMenuConfigPage, InsertHdl, const OString&, rIdent, void) +{ + weld::TreeView& rTreeView = m_xContentsListBox->get_widget(); + if (rIdent == "insertseparator") + { + SvxConfigEntry* pNewEntryData = new SvxConfigEntry; + pNewEntryData->SetUserDefined(); + int nPos = AppendEntry(pNewEntryData, -1); + InsertEntryIntoUI(pNewEntryData, rTreeView, nPos, true); + } + else if (rIdent == "insertsubmenu") + { + OUString aNewName; + OUString aDesc = CuiResId(RID_CUISTR_SUBMENU_NAME); + + SvxNameDialog aNameDialog(GetFrameWeld(), aNewName, aDesc); + aNameDialog.set_help_id(HID_SVX_CONFIG_NAME_SUBMENU); + aNameDialog.set_title(CuiResId(RID_CUISTR_ADD_SUBMENU)); + + if (aNameDialog.run() == RET_OK) + { + aNewName = aNameDialog.GetName(); + + SvxConfigEntry* pNewEntryData + = new SvxConfigEntry(aNewName, aNewName, true, /*bParentData*/ false); + pNewEntryData->SetName(aNewName); + pNewEntryData->SetUserDefined(); + + int nPos = AppendEntry(pNewEntryData, -1); + InsertEntryIntoUI(pNewEntryData, rTreeView, nPos, true); + + ReloadTopLevelListBox(); + + m_xContentsListBox->scroll_to_row(nPos); + m_xContentsListBox->select(nPos); + + GetSaveInData()->SetModified(); + } + } + else + { + //This block should never be reached + SAL_WARN("cui.customize", "Unknown insert option: " << rIdent); + return; + } + + if (GetSaveInData()->IsModified()) + { + UpdateButtonStates(); + } +} + +IMPL_LINK(SvxMenuConfigPage, ModifyItemHdl, const OString&, rIdent, void) +{ + if (rIdent == "renameItem") + { + int nActEntry = m_xContentsListBox->get_selected_index(); + SvxConfigEntry* pEntry + = weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nActEntry)); + + OUString aNewName(SvxConfigPageHelper::stripHotKey(pEntry->GetName())); + OUString aDesc = CuiResId(RID_CUISTR_LABEL_NEW_NAME); + + SvxNameDialog aNameDialog(GetFrameWeld(), aNewName, aDesc); + aNameDialog.set_help_id(HID_SVX_CONFIG_RENAME_MENU_ITEM); + aNameDialog.set_title(CuiResId(RID_CUISTR_RENAME_MENU)); + + if (aNameDialog.run() == RET_OK) + { + aNewName = aNameDialog.GetName(); + + pEntry->SetName(aNewName); + m_xContentsListBox->set_text(nActEntry, aNewName, 0); + + GetSaveInData()->SetModified(); + GetTopLevelSelection()->SetModified(); + } + } + else + { + //This block should never be reached + SAL_WARN("cui.customize", "Unknown insert option: " << rIdent); + return; + } + + if (GetSaveInData()->IsModified()) + { + UpdateButtonStates(); + } +} + +IMPL_LINK_NOARG(SvxMenuConfigPage, ResetMenuHdl, weld::Button&, void) +{ + SvxConfigEntry* pMenuData = GetTopLevelSelection(); + + if (pMenuData == nullptr) + { + SAL_WARN("cui.customize", + "RHB top level selection is null. A menu must be selected to reset!"); + return; + } + + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog( + GetFrameWeld(), VclMessageType::Question, VclButtonsType::YesNo, + CuiResId(RID_CUISTR_CONFIRM_RESTORE_DEFAULT_MENU))); + + // Resetting individual top-level menus is not possible at the moment. + // So we are resetting only if it is a context menu + if (m_bIsMenuBar || xQueryBox->run() != RET_YES) + return; + + sal_Int32 nPos = m_xTopLevelListBox->get_active(); + ContextMenuSaveInData* pSaveInData = static_cast<ContextMenuSaveInData*>(GetSaveInData()); + + pSaveInData->ResetContextMenu(pMenuData); + + // ensure that the UI is cleared before populating it + m_xTopLevelListBox->clear(); + m_xContentsListBox->clear(); + + ReloadTopLevelListBox(); + + // Reselect the reset menu + m_xTopLevelListBox->set_active(nPos); + SelectElement(); +} + +SaveInData* SvxMenuConfigPage::CreateSaveInData( + const css::uno::Reference<css::ui::XUIConfigurationManager>& xCfgMgr, + const css::uno::Reference<css::ui::XUIConfigurationManager>& xParentCfgMgr, + const OUString& aModuleId, bool bDocConfig) +{ + if (!m_bIsMenuBar) + return static_cast<SaveInData*>( + new ContextMenuSaveInData(xCfgMgr, xParentCfgMgr, aModuleId, bDocConfig)); + + return static_cast<SaveInData*>( + new MenuSaveInData(xCfgMgr, xParentCfgMgr, aModuleId, bDocConfig)); +} + +IMPL_LINK(SvxMenuConfigPage, ContentContextMenuHdl, const CommandEvent&, rCEvt, bool) +{ + if (rCEvt.GetCommand() != CommandEventId::ContextMenu) + return false; + + weld::TreeView& rTreeView = m_xContentsListBox->get_widget(); + + // Select clicked entry + std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator()); + if (!rTreeView.get_dest_row_at_pos(rCEvt.GetMousePosPixel(), xIter.get(), false)) + return false; + rTreeView.select(*xIter); + SelectMenuEntry(rTreeView); + + int nSelectIndex = m_xContentsListBox->get_selected_index(); + + bool bIsSeparator + = nSelectIndex != -1 + && weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nSelectIndex))->IsSeparator(); + bool bIsValidSelection = (m_xContentsListBox->n_children() != 0 && nSelectIndex != -1); + + std::unique_ptr<weld::Builder> xBuilder( + Application::CreateBuilder(&rTreeView, "cui/ui/entrycontextmenu.ui")); + auto xContextMenu = xBuilder->weld_menu("menu"); + xContextMenu->set_visible("add", false); + xContextMenu->set_visible("remove", bIsValidSelection); + xContextMenu->set_visible("rename", bIsValidSelection && !bIsSeparator); + xContextMenu->set_visible("changeIcon", false); + xContextMenu->set_visible("resetIcon", false); + xContextMenu->set_visible("restoreDefault", false); + OString sCommand(xContextMenu->popup_at_rect( + &rTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1)))); + + if (sCommand == "remove") + { + RemoveCommandHdl(*m_xRemoveCommandButton); + } + else if (sCommand == "rename") + { + ModifyItemHdl("renameItem"); + } + else if (!sCommand.isEmpty()) + SAL_WARN("cui.customize", "Unknown context menu action: " << sCommand); + return true; +} + +IMPL_LINK(SvxMenuConfigPage, FunctionContextMenuHdl, const CommandEvent&, rCEvt, bool) +{ + if (rCEvt.GetCommand() != CommandEventId::ContextMenu) + return false; + + weld::TreeView& rTreeView = m_xFunctions->get_widget(); + + // Select clicked entry + std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator()); + if (!rTreeView.get_dest_row_at_pos(rCEvt.GetMousePosPixel(), xIter.get(), false)) + return false; + rTreeView.select(*xIter); + SelectFunctionHdl(rTreeView); + + std::unique_ptr<weld::Builder> xBuilder( + Application::CreateBuilder(&rTreeView, "cui/ui/entrycontextmenu.ui")); + auto xContextMenu = xBuilder->weld_menu("menu"); + xContextMenu->set_visible("add", true); + xContextMenu->set_visible("remove", false); + xContextMenu->set_visible("rename", false); + xContextMenu->set_visible("changeIcon", false); + xContextMenu->set_visible("resetIcon", false); + xContextMenu->set_visible("restoreDefault", false); + OString sCommand(xContextMenu->popup_at_rect( + &rTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1)))); + + if (sCommand == "add") + { + AddCommandHdl(*m_xAddCommandButton); + } + else if (!sCommand.isEmpty()) + SAL_WARN("cui.customize", "Unknown context menu action: " << sCommand); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |