Salome HOME
[bos #40644][CEA](2024-T1) Feature search.
authordish <dmitrii.shvydkoi@opencascade.com>
Thu, 11 Apr 2024 14:44:38 +0000 (14:44 +0000)
committerdish <dmitrii.shvydkoi@opencascade.com>
Thu, 11 Apr 2024 14:44:38 +0000 (14:44 +0000)
Break down cyclic linking dependency - Qtx<-SUIT<-Qtx.
The dependency led to build fail if qtwebengine5-dev is installed.

21 files changed:
src/Qtx/CMakeLists.txt
src/Qtx/QtxFindActionDialog.cxx [deleted file]
src/Qtx/QtxFindActionDialog.h [deleted file]
src/Qtx/QtxPagePrefMgr.cxx
src/Qtx/QtxPagePrefMgr.h
src/Qtx/QtxShortcutEdit.cxx [deleted file]
src/Qtx/QtxShortcutEdit.h [deleted file]
src/Qtx/resources/Qtx_msg_fr.ts
src/Qtx/resources/Qtx_msg_ja.ts
src/SUIT/CMakeLists.txt
src/SUIT/SUIT_FindActionDialog.cxx [new file with mode: 0644]
src/SUIT/SUIT_FindActionDialog.h [new file with mode: 0644]
src/SUIT/SUIT_PagePrefShortcutTreeItem.cxx [new file with mode: 0644]
src/SUIT/SUIT_PagePrefShortcutTreeItem.h [new file with mode: 0644]
src/SUIT/SUIT_PreferenceMgr.cxx
src/SUIT/SUIT_ShortcutMgr. ReadMe.md
src/SUIT/SUIT_ShortcutTree.cxx [new file with mode: 0644]
src/SUIT/SUIT_ShortcutTree.h [new file with mode: 0644]
src/SUIT/resources/SUIT_msg_fr.ts
src/SUIT/resources/SUIT_msg_ja.ts
src/SalomeApp/SalomeApp_Application.cxx

index 78b104718bed3af22955d0ca4a86445738cbe964..d62b4e1c2bce7360477067dec105c3f5f1bf6b69 100644 (file)
@@ -22,10 +22,7 @@ INCLUDE(UseQtExt)
 # --- options ---
 
 # additional include directories
-INCLUDE_DIRECTORIES(
-  ${QT_INCLUDES}
-  ${PROJECT_SOURCE_DIR}/src/SUIT
-)
+INCLUDE_DIRECTORIES(${QT_INCLUDES})
 
 # additional preprocessor / compiler flags
 ADD_DEFINITIONS(${QT_DEFINITIONS})
@@ -53,7 +50,6 @@ SET(_moc_HEADERS
   QtxDockWidget.h
   QtxDoubleSpinBox.h
   QtxDoubleSpinSlider.h
-  QtxFindActionDialog.h
   QtxFontEdit.h
   QtxGridBox.h
   QtxGroupBox.h
@@ -74,7 +70,6 @@ SET(_moc_HEADERS
   QtxPopupMgr.h
   QtxRubberBand.h
   QtxSearchTool.h
-  QtxShortcutEdit.h
   QtxSlider.h
   QtxSplash.h
   QtxToolBar.h
@@ -148,7 +143,6 @@ SET(_other_SOURCES
   QtxDoubleSpinBox.cxx
   QtxDoubleSpinSlider.cxx
   QtxEvalExpr.cxx
-  QtxFindActionDialog.cxx
   QtxFontEdit.cxx
   QtxGridBox.cxx
   QtxGroupBox.cxx
@@ -172,7 +166,6 @@ SET(_other_SOURCES
   QtxResourceMgr.cxx
   QtxRubberBand.cxx
   QtxSearchTool.cxx
-  QtxShortcutEdit.cxx
   QtxSlider.cxx
   QtxSplash.cxx
   QtxToolBar.cxx
diff --git a/src/Qtx/QtxFindActionDialog.cxx b/src/Qtx/QtxFindActionDialog.cxx
deleted file mode 100644 (file)
index f631673..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
-//
-
-#include "QtxFindActionDialog.h"
-
-#include <QAction>
-#include <QWidget>
-#include <QLayout>
-#include <QList>
-#include <QMap>
-
-#include <QCollator>
-
-#include <QCheckBox>
-#include <QLineEdit>
-#include <QBrush>
-#include <QColor>
-#include <QHeaderView>
-
-#include <algorithm>
-
-
-QtxFindActionDialog::QtxFindActionDialog(QWidget* theParent)
-: QDialog(theParent)
-{
-  setMinimumWidth(500);
-  setWindowTitle(tr("Find action"));
-  QVBoxLayout* layout = new QVBoxLayout(this);
-
-  myQueryLineEdit = new QLineEdit(this);
-  layout->addWidget(myQueryLineEdit);
-  myQueryLineEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
-  setFocusProxy(myQueryLineEdit);
-
-  QHBoxLayout* searchOptionsLayout = new QHBoxLayout(this);
-  layout->addLayout(searchOptionsLayout);
-  myIncludeUnavailableActionsCB = new QCheckBox(tr("Unavailable actions"), this);
-  myIncludeUnavailableActionsCB->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-  myIncludeUnavailableActionsCB->setCheckState(Qt::CheckState::Checked);
-  myActionSearcher.includeDisabledActions(true);
-  myIncludeInactiveModulesCB = new QCheckBox(tr("Inactive modules"), this);
-  myIncludeInactiveModulesCB->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-  myIncludeInactiveModulesCB->setCheckState(Qt::CheckState::Unchecked);
-  searchOptionsLayout->addWidget(myIncludeUnavailableActionsCB);
-  searchOptionsLayout->addWidget(myIncludeInactiveModulesCB);
-
-  myFoundActionsTree = new QtxFoundActionTree(this);
-  layout->addWidget(myFoundActionsTree);
-
-  connect(myQueryLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(onQueryChanged(const QString&)));
-  connect(myIncludeUnavailableActionsCB, SIGNAL(stateChanged(int)), this, SLOT(onSearchOptionUnavailableActionsChanged(int)));
-  connect(myIncludeInactiveModulesCB, SIGNAL(stateChanged(int)), this, SLOT(onSearchOptionInactiveModulesChanged(int)));
-}
-
-void QtxFindActionDialog::setActiveModuleID(const QString& theModuleID)
-{
-  myActiveModuleID = theModuleID;
-  if(myActionSearcher.setIncludedModuleIDs(std::set<QString>({SUIT_ShortcutMgr::ROOT_MODULE_ID, myActiveModuleID})))
-    updateUI();
-}
-
-void QtxFindActionDialog::onQueryChanged(const QString& theQuery)
-{
-  if (myActionSearcher.setQuery(theQuery))
-    updateUI();
-}
-
-void QtxFindActionDialog::onSearchOptionUnavailableActionsChanged(int theState)
-{
-  if (myActionSearcher.includeDisabledActions(theState == Qt::CheckState::Checked))
-    updateUI();
-}
-
-void QtxFindActionDialog::onSearchOptionInactiveModulesChanged(int theState)
-{
-  bool resultsChanged = false;
-  if (theState == Qt::CheckState::Checked)
-    resultsChanged = myActionSearcher.setIncludedModuleIDs(SUIT_ShortcutMgr::get()->getShortcutContainer().getIDsOfAllModules());
-  else
-    resultsChanged = myActionSearcher.setIncludedModuleIDs(std::set<QString>({SUIT_ShortcutMgr::ROOT_MODULE_ID, myActiveModuleID}));
-
-  if (resultsChanged)
-    updateUI();
-}
-
-void QtxFindActionDialog::updateUI()
-{
-  myFoundActionsTree->updateItems(myActionSearcher.getSearchResults());
-}
-
-
-
-QtxFoundActionTree::QtxFoundActionTree(QtxFindActionDialog* theParent)
-: QTreeWidget(theParent)
-{
-  setColumnCount(2);
-  setSelectionMode(QAbstractItemView::SingleSelection);
-  setSortingEnabled(false); // Items are sorted in the same way, as in ShortcutContainer.
-  header()->setSectionResizeMode(QHeaderView::Interactive);
-  {
-    QMap<int, QString> labelMap;
-    labelMap[QtxFoundActionTree::ElementIdx::Name]    = QtxFindActionDialog::tr("Action");
-    labelMap[QtxFoundActionTree::ElementIdx::ToolTip] = QtxFindActionDialog::tr("Description");
-    setHeaderLabels(labelMap.values());
-  }
-  setExpandsOnDoubleClick(false); // Open shortcut editor on double click instead.
-  setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
-  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
-
-  setColumnWidth(QtxFoundActionTree::ElementIdx::Name, 120);
-  setColumnWidth(QtxFoundActionTree::ElementIdx::Name, 250);
-  setMinimumHeight(300);
-
-  setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
-
-  connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(onItemDoubleClicked(QTreeWidgetItem*, int)));
-}
-
-void QtxFoundActionTree::updateItems(const std::map<QString, std::map<QString, SUIT_ActionSearcher::AssetsAndSearchData>>& theAssets)
-{
-  clear();
-
-  const auto shortcutMgr = SUIT_ShortcutMgr::get();
-  const QString lang = SUIT_ShortcutMgr::getLang();
-
-  for (const auto& moduleIDAndAssets : theAssets) {
-    const QString& moduleID = moduleIDAndAssets.first;
-    const auto& moduleAssets = moduleIDAndAssets.second;
-    if (moduleAssets.empty())
-      continue;
-
-    const auto moduleItem = new QtxFoundActionTreeFolder(moduleID);
-    moduleItem->setAssets(shortcutMgr->getModuleAssets(moduleID), lang);
-    addTopLevelItem(moduleItem);
-    moduleItem->setFlags(Qt::ItemIsEnabled);
-    for (const auto& actionIDAndAssets : moduleAssets) {
-      const QString& inModuleActionID = actionIDAndAssets.first;
-      const SUIT_ActionSearcher::AssetsAndSearchData& assetsAndSearchData = actionIDAndAssets.second;
-
-      auto actionItem = QtxFoundActionTreeAction::create(moduleID, inModuleActionID);
-      if (!actionItem) {
-        ShCutDbg("QtxFoundActionTree can't create child item for action ID = \"" + SUIT_ShortcutMgr::makeActionID(moduleID, inModuleActionID) + "\".");
-        continue;
-      }
-
-      actionItem->setAssets(assetsAndSearchData.myAssets, lang);
-      moduleItem->addChild(actionItem);
-    }
-    moduleItem->setExpanded(true); // Make tree expanded on first show.
-  }
-}
-
-std::pair<QtxFoundActionTreeFolder*, int> QtxFoundActionTree::findModuleFolderItem(const QString& theModuleID) const
-{
-  for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); moduleIdx++) {
-    QtxFoundActionTreeFolder* moduleItem = static_cast<QtxFoundActionTreeFolder*>(topLevelItem(moduleIdx));
-    if (moduleItem->myModuleID == theModuleID)
-      return std::pair<QtxFoundActionTreeFolder*, int>(moduleItem, moduleIdx);
-  }
-  return std::pair<QtxFoundActionTreeFolder*, int>(nullptr, -1);
-}
-
-void QtxFoundActionTree::onItemDoubleClicked(QTreeWidgetItem* theItem, int theColIdx)
-{
-  {
-    QtxFoundActionTreeItem* const item = static_cast<QtxFoundActionTreeItem*>(theItem);
-    // Do not react if folder-item is clicked.
-    if (item->type() != QtxFoundActionTreeItem::Type::Action)
-      return;
-  }
-
-  QtxFoundActionTreeAction* const actionItem = static_cast<QtxFoundActionTreeAction*>(theItem);
-  if (actionItem->trigger())
-    static_cast<QtxFindActionDialog*>(parentWidget())->accept();
-}
-
-
-QtxFoundActionTreeItem::QtxFoundActionTreeItem(const QString& theModuleID)
-: QTreeWidgetItem(), myModuleID(theModuleID)
-{ }
-
-QString QtxFoundActionTreeItem::name() const
-{
-  return text(QtxFoundActionTree::ElementIdx::Name);
-}
-
-QString QtxFoundActionTreeItem::toolTip() const
-{
-  return text(QtxFoundActionTree::ElementIdx::ToolTip);
-}
-
-
-QtxFoundActionTreeFolder::QtxFoundActionTreeFolder(const QString& theModuleID)
-: QtxFoundActionTreeItem(theModuleID)
-{
-  QFont f = font(QtxFoundActionTree::ElementIdx::Name);
-  f.setBold(true);
-  setFont(QtxFoundActionTree::ElementIdx::Name, f);
-  setText(QtxFoundActionTree::ElementIdx::Name, theModuleID);
-}
-
-void QtxFoundActionTreeFolder::setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang)
-{
-  if (!theAssets)
-    return;
-
-  setIcon(QtxFoundActionTree::ElementIdx::Name, theAssets->myIcon);
-
-  const auto& ldaMap = theAssets->myLangDependentAssets;
-  if (ldaMap.empty()) {
-    setText(QtxFoundActionTree::ElementIdx::Name, myModuleID);
-    return;
-  }
-
-  auto itLDA = ldaMap.find(theLang);
-  if (itLDA == ldaMap.end())
-    itLDA = ldaMap.begin();
-
-  const SUIT_ActionAssets::LangDependentAssets& lda = itLDA->second;
-  const QString& name = lda.myName.isEmpty() ? myModuleID : lda.myName;
-  setText(QtxFoundActionTree::ElementIdx::Name, name);
-}
-
-QString QtxFoundActionTreeFolder::getValue(QtxFoundActionTree::SortKey theKey) const
-{
-  switch (theKey) {
-    case QtxFoundActionTree::SortKey::ID:
-      return myModuleID;
-    case QtxFoundActionTree::SortKey::Name:
-      return name();
-    case QtxFoundActionTree::SortKey::ToolTip:
-      return toolTip();
-    default:
-      return QString();
-  }
-}
-
-bool QtxFoundActionTreeFolder::isEnabled() const
-{
-  return true;
-}
-
-
-QtxFoundActionTreeAction::QtxFoundActionTreeAction(const QString& theModuleID, const QString& theInModuleActionID)
-: QtxFoundActionTreeItem(theModuleID), myInModuleActionID(theInModuleActionID)
-{
-  setText(QtxFoundActionTree::ElementIdx::Name, theInModuleActionID);
-}
-
-/*static*/ QtxFoundActionTreeAction* QtxFoundActionTreeAction::create(const QString& theModuleID, const QString& theInModuleActionID)
-{
-  if (theInModuleActionID.isEmpty()) {
-    ShCutDbg("QtxFoundActionTreeItem: attempt to create item with empty action ID.");
-    return nullptr;
-  }
-
-  return new QtxFoundActionTreeAction(theModuleID, theInModuleActionID);
-}
-
-void QtxFoundActionTreeAction::setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang)
-{
-  if (!theAssets)
-    return;
-
-  setIcon(QtxFoundActionTree::ElementIdx::Name, theAssets->myIcon);
-
-  const auto& ldaMap = theAssets->myLangDependentAssets;
-  if (ldaMap.empty()) {
-    setText(QtxFoundActionTree::ElementIdx::Name, myInModuleActionID);
-    return;
-  }
-
-  auto itLDA = ldaMap.find(theLang);
-  if (itLDA == ldaMap.end())
-    itLDA = ldaMap.begin();
-
-  const SUIT_ActionAssets::LangDependentAssets& lda = itLDA->second;
-  const QString& name = lda.myName.isEmpty() ? myInModuleActionID : lda.myName;
-  setText(QtxFoundActionTree::ElementIdx::Name, name);
-
-  setText(QtxFoundActionTree::ElementIdx::ToolTip, lda.myToolTip);
-
-  if (isEnabled()) {
-    setToolTip(
-      QtxFoundActionTree::ElementIdx::Name,
-      QtxFoundActionTree::tr("Double click to start")
-    );
-
-    setToolTip(
-      QtxFoundActionTree::ElementIdx::ToolTip,
-      QtxFoundActionTree::tr("Double click to start")
-    );
-  }
-  else {
-    static const QBrush greyedOutBrush = QBrush(Qt::gray);
-    setForeground(QtxFoundActionTree::ElementIdx::Name,    greyedOutBrush);
-    setForeground(QtxFoundActionTree::ElementIdx::ToolTip, greyedOutBrush);
-  }
-}
-
-QString QtxFoundActionTreeAction::getValue(QtxFoundActionTree::SortKey theKey) const
-{
-  switch (theKey) {
-    case QtxFoundActionTree::SortKey::ID:
-      return myInModuleActionID;
-    case QtxFoundActionTree::SortKey::Name:
-      return name();
-    case QtxFoundActionTree::SortKey::ToolTip:
-      return toolTip();
-    default:
-      return QString();
-  }
-}
-
-bool QtxFoundActionTreeAction::isEnabled() const
-{
-  const auto& actions = SUIT_ShortcutMgr::get()->getActions(myModuleID, myInModuleActionID);
-  return std::find_if(actions.begin(), actions.end(), [](const QAction* const theAction){ return theAction->isEnabled(); }) != actions.end();
-}
-
-bool QtxFoundActionTreeAction::trigger() const
-{
-  bool res = false;
-  const auto& actions = SUIT_ShortcutMgr::get()->getActions(myModuleID, myInModuleActionID);
-  for (const auto& action : actions) {
-    if (action->isEnabled()) {
-      action->trigger();
-      res = true;
-    }
-  }
-  return res;
-}
\ No newline at end of file
diff --git a/src/Qtx/QtxFindActionDialog.h b/src/Qtx/QtxFindActionDialog.h
deleted file mode 100644 (file)
index 7632e2b..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
-//
-
-#ifndef QTXFINDACTIONDIALOG_H
-#define QTXFINDACTIONDIALOG_H
-
-#include "Qtx.h"
-#include <QDialog>
-#include <QFrame>
-#include <QTreeWidget>
-#include "SUIT_ShortcutMgr.h"
-#include <memory>
-#include <map>
-#include <set>
-#include <functional>
-
-
-class QCheckBox;
-class QLineEdit;
-class QLabel;
-class QPushButton;
-class QtxFoundActionTree;
-
-
-class QTX_EXPORT QtxFindActionDialog : public QDialog
-{
-  Q_OBJECT
-
-public:
-  QtxFindActionDialog(QWidget* theParent);
-  QtxFindActionDialog(const QtxFindActionDialog&) = delete;
-  QtxFindActionDialog& operator=(const QtxFindActionDialog&) = delete;
-  virtual ~QtxFindActionDialog() = default;
-
-  void setActiveModuleID(const QString& theModuleID = SUIT_ShortcutMgr::ROOT_MODULE_ID);
-
-private slots:
-  void onQueryChanged(const QString& theKeyword);
-  void onSearchOptionUnavailableActionsChanged(int);
-  void onSearchOptionInactiveModulesChanged(int);
-
-private:
-  void updateUI();
-
-  QLineEdit* myQueryLineEdit;
-  QCheckBox* myIncludeUnavailableActionsCB;
-  QCheckBox* myIncludeInactiveModulesCB;
-  QtxFoundActionTree* myFoundActionsTree;
-
-  QString myActiveModuleID;
-  SUIT_ActionSearcher myActionSearcher;
-};
-
-
-class QtxFoundActionTreeItem;
-class QtxFoundActionTreeFolder;
-class QtxFoundActionTreeAction;;
-
-
-class QTX_EXPORT QtxFoundActionTree : public QTreeWidget
-{
-  Q_OBJECT
-
-public:
-  enum ElementIdx {
-    Name = 0,
-    ToolTip = 1
-  };
-
-  enum class SortKey {
-    ID,
-    Name,
-    ToolTip
-  };
-
-  QtxFoundActionTree(QtxFindActionDialog* theParent);
-  QtxFoundActionTree(const QtxFoundActionTree&) = delete;
-  QtxFoundActionTree& operator=(const QtxFoundActionTree&) = delete;
-  virtual ~QtxFoundActionTree() = default;
-
-  void updateItems(const std::map<QString, std::map<QString, SUIT_ActionSearcher::AssetsAndSearchData>>& theAssets);
-
-private:
-  std::pair<QtxFoundActionTreeFolder*, int> findModuleFolderItem(const QString& theModuleID) const;
-
-private slots:
-  void onItemDoubleClicked(QTreeWidgetItem* theWidgetItem, int theColIdx);
-};
-
-
-class QtxFoundActionTreeItem : public QTreeWidgetItem
-{
-public:
-  enum Type {
-    Folder = 0,
-    Action = 1,
-  };
-
-protected:
-  QtxFoundActionTreeItem(const QString& theModuleID);
-
-public:
-  virtual ~QtxFoundActionTreeItem() = default;
-  virtual QtxFoundActionTreeItem::Type type() const = 0;
-
-  virtual void setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang) = 0;
-  QString name() const;
-  QString toolTip() const;
-
-  virtual QString getValue(QtxFoundActionTree::SortKey theKey) const = 0;
-
-  virtual bool isEnabled() const = 0;
-
-public:
-  const QString myModuleID;
-};
-
-
-class QtxFoundActionTreeFolder : public QtxFoundActionTreeItem
-{
-public:
-  QtxFoundActionTreeFolder(const QString& theModuleID);
-  virtual ~QtxFoundActionTreeFolder() = default;
-  virtual QtxFoundActionTreeItem::Type type() const { return QtxFoundActionTreeItem::Type::Folder; };
-
-  virtual void setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang);
-
-  virtual QString getValue(QtxFoundActionTree::SortKey theKey) const;
-
-  virtual bool isEnabled() const;
-};
-
-
-class QtxFoundActionTreeAction : public QtxFoundActionTreeItem
-{
-private:
-  QtxFoundActionTreeAction(const QString& theModuleID, const QString& theInModuleActionID);
-
-public:
-  static QtxFoundActionTreeAction* create(const QString& theModuleID, const QString& theInModuleActionID);
-  virtual ~QtxFoundActionTreeAction() = default;
-  virtual QtxFoundActionTreeItem::Type type() const { return QtxFoundActionTreeItem::Type::Action; };
-
-  virtual void setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang);
-
-  virtual QString getValue(QtxFoundActionTree::SortKey theKey) const;
-
-  virtual bool isEnabled() const;
-
-  bool trigger() const;
-
-  const QString myInModuleActionID;
-};
-
-#endif // QTXFINDACTIONDIALOG_H
index 8cd626e8665d9764c29a6bd5ed498dc69c6adbc7..7f8222ae54018f730792273dcc44cf1b89e255da 100644 (file)
 #include "QtxColorButton.h"
 #include "QtxBiColorTool.h"
 #include "QtxDoubleSpinBox.h"
-#include "QtxShortcutEdit.h"
 #include "QtxBackgroundTool.h"
 #include "QtxResourceMgr.h"
 
-#include "SUIT_ShortcutMgr.h"
-
 #include <QEvent>
 #include <QLayout>
 #include <QToolBox>
@@ -4429,67 +4426,6 @@ void QtxPagePrefDateTimeItem::updateDateTime()
 }
 
 
-/*!
-  \brief Creates preference item for editing of key bindings
-  \param theParent parent preference item. Must not be nullptr.
-*/
-QtxPagePrefShortcutTreeItem::QtxPagePrefShortcutTreeItem(QtxPreferenceItem* theParent)
- : QtxPagePrefItem(QString(), theParent)
-{
-  auto container = std::shared_ptr<SUIT_ShortcutContainer>();
-  const auto itContainers = QtxPagePrefShortcutTreeItem::shortcutContainers.find(rootItem());
-  if (itContainers == QtxPagePrefShortcutTreeItem::shortcutContainers.end()) {
-    container.reset(new SUIT_ShortcutContainer());
-    QtxPagePrefShortcutTreeItem::shortcutContainers.emplace(rootItem(), container);
-  }
-  else {
-    container = itContainers->second.lock();
-    if (!container) {
-      container.reset(new SUIT_ShortcutContainer());
-      itContainers->second = container;
-    }
-  }
-
-  QtxShortcutTree* tree = new QtxShortcutTree(container);
-  tree->myModuleIDs = SUIT_ShortcutMgr::get()->getShortcutModuleIDs();
-  setWidget(tree);
-}
-
-/*!
-  \brief Retrieves shortcut preferences from ShortcutMgr.
-  Updates UI of controlling widget.
-  \sa store()
-*/
-void QtxPagePrefShortcutTreeItem::retrieve()
-{
-  static_cast<QtxShortcutTree*>(widget())->setShortcutsFromManager();
-}
-
-/*!
-  \brief Retrieves shortcut preferences from resource files, ignoring user preferences.
-  Updates UI of controlling widget.
-  \sa store()
-*/
-void QtxPagePrefShortcutTreeItem::retrieveDefault()
-{
-  static_cast<QtxShortcutTree*>(widget())->setDefaultShortcuts();
-}
-
-/*!
-  \brief Applies modified shortcut preferences to ShortcutMgr.
-  Updates UI of controlling widget.
-  And ShortcutMgr, in turn, serilizes shortcut preferences using the resource manager.
-  \sa retrieve()
-*/
-void QtxPagePrefShortcutTreeItem::store()
-{
-  static_cast<QtxShortcutTree*>(widget())->applyChangesToShortcutMgr();
-}
-
-/*static*/ std::map<QtxPreferenceItem*, std::weak_ptr<SUIT_ShortcutContainer>> QtxPagePrefShortcutTreeItem::shortcutContainers =
-std::map<QtxPreferenceItem*, std::weak_ptr<SUIT_ShortcutContainer>>();
-
-
 /*!
   \class QtxPagePrefBackgroundItem
   \brief GUI implementation of the resources item to store background data.
index 24ed21539cebc9244949871396a49931bc539061..26485122a501a0af8699515cb075e960eec0b66a 100644 (file)
@@ -42,7 +42,6 @@ class QtxGroupBox;
 class QtxComboBox;
 class QtxColorButton;
 class QtxBiColorTool;
-class QtxShortcutTree;
 class QtxBackgroundTool;
 
 class QToolBox;
@@ -740,37 +739,6 @@ private:
   QDateTimeEdit*   myDateTime;
 };
 
-
-class SUIT_ShortcutContainer;
-
-
-class QTX_EXPORT QtxPagePrefShortcutTreeItem : public QtxPagePrefItem
-{
-public:
-  QtxPagePrefShortcutTreeItem(QtxPreferenceItem* theParent);
-  virtual ~QtxPagePrefShortcutTreeItem() = default;
-
-  virtual void     retrieve();
-  virtual void     retrieveDefault();
-  virtual void     store();
-
-private:
-  QtxShortcutTree* myShortcutTree;
-
-  // { root item (preference window), shortcut container of synchronized trees (widgets within the same window) }
-  static std::map<QtxPreferenceItem*, std::weak_ptr<SUIT_ShortcutContainer>> shortcutContainers;
-  /** Why is this?
-   * Every QtxPagePrefMgr is eventually a preference window. Each preference window has button "Apply".
-   * When the button is pressed, all descendants of the QtxPagePrefMgr store changes they carry into preferences.
-   * The pitfall with shortcut trees is as follows: made in independent shortcut trees, changes may conflict,
-   * and merge of such changes is ambiguous. And the solution is to keep shortcut trees within the same window
-   * synchronized - all changes being made in a tree of a synchronized bundle are projected to other trees from the bundle
-   * without interacting with SUIT_ShortcutMgr.
-   *
-   * Every time shortcut preferences stored to the ShortcutMgr, all instances of QtxShortcutTree are updated.
-  */
-};
-
 class QTX_EXPORT QtxPagePrefBackgroundItem : public QObject, public QtxPageNamedPrefItem
 {
   Q_OBJECT
diff --git a/src/Qtx/QtxShortcutEdit.cxx b/src/Qtx/QtxShortcutEdit.cxx
deleted file mode 100644 (file)
index fe845b5..0000000
+++ /dev/null
@@ -1,883 +0,0 @@
-// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
-//
-
-#include "QtxShortcutEdit.h"
-
-#include <QWidget>
-#include <QLayout>
-#include <QList>
-#include <QMap>
-
-#include <QToolButton>
-#include <QLineEdit>
-#include <QLabel>
-#include <QTableWidgetItem>
-#include <QTextEdit>
-#include <QMessageBox>
-#include <QPushButton>
-#include <QBrush>
-#include <QColor>
-#include <QHeaderView>
-
-#include <QKeyEvent>
-#include <QKeySequence>
-#include <QCollator>
-
-#include <algorithm>
-
-
-#define COLUMN_SIZE  500
-
-
-QtxKeySequenceEdit::QtxKeySequenceEdit(QWidget* parent)
-: QFrame(parent)
-{
-  initialize();
-  myKeySequenceLineEdit->installEventFilter(this);
-}
-
-/*! \brief Set a key sequence to edit. */
-void QtxKeySequenceEdit::setConfirmedKeySequence(const QKeySequence& theKeySequence)
-{
-  myConfirmedKeySequenceString = theKeySequence.toString();
-  myKeySequenceLineEdit->setText(myConfirmedKeySequenceString);
-  myPrevKeySequenceString = myConfirmedKeySequenceString;
-}
-
-void QtxKeySequenceEdit::setEditedKeySequence(const QKeySequence& theKeySequence)
-{
-  const QString keySequenceString = theKeySequence.toString();
-  myKeySequenceLineEdit->setText(keySequenceString);
-  myPrevKeySequenceString = keySequenceString;
-}
-
-QKeySequence QtxKeySequenceEdit::editedKeySequence() const
-{
-  return QKeySequence::fromString(myKeySequenceLineEdit->text());
-}
-
-/*! \returns true, if the edited key sequence differs from confirmed one. */
-bool QtxKeySequenceEdit::isKeySequenceModified() const
-{
-  return QKeySequence(myConfirmedKeySequenceString) != editedKeySequence();
-}
-
-/*! \brief Set confirmed key sequence to line editor. */
-void QtxKeySequenceEdit::restoreKeySequence()
-{
-  myKeySequenceLineEdit->setText(myConfirmedKeySequenceString);
-  myPrevKeySequenceString = myConfirmedKeySequenceString;
-}
-
-/*!
-  \brief Gets the key sequence from keys that were pressed
-  \param e a key event
-  \returns a string representation of the key sequence
-*/
-/*static*/ QString QtxKeySequenceEdit::parseEvent(QKeyEvent* e)
-{
-  bool isShiftPressed = e->modifiers() & Qt::ShiftModifier;
-  bool isControlPressed = e->modifiers() & Qt::ControlModifier;
-  bool isAltPressed = e->modifiers() & Qt::AltModifier;
-  bool isMetaPressed = e->modifiers() & Qt::MetaModifier;
-  bool isModifiersPressed = isControlPressed || isAltPressed || isMetaPressed; // Do not treat Shift alone as a modifier!
-  int result=0;
-  if(isControlPressed)
-    result += Qt::CTRL;
-  if(isAltPressed)
-    result += Qt::ALT;
-  if(isShiftPressed)
-    result += Qt::SHIFT;
-  if(isMetaPressed)
-    result += Qt::META;
-
-  int aKey = e->key();
-  if ((isValidKey(aKey) && isModifiersPressed) || ((aKey >= Qt::Key_F1) && (aKey <= Qt::Key_F12)))
-    result += aKey;
-
-  return QKeySequence(result).toString();
-}
-
-/*!
-  \brief Check if the key event contains a 'valid' key
-  \param theKey the code of the key
-  \returns \c true if the key is 'valid'
-*/
-/*static*/ bool QtxKeySequenceEdit::isValidKey(int theKey)
-{
-  if ( theKey == Qt::Key_Underscore || theKey == Qt::Key_Escape ||
-     ( theKey >= Qt::Key_Backspace && theKey <= Qt::Key_Delete ) ||
-     ( theKey >= Qt::Key_Home && theKey <= Qt::Key_PageDown ) ||
-     ( theKey >= Qt::Key_F1 && theKey <= Qt::Key_F12 )  ||
-     ( theKey >= Qt::Key_Space && theKey <= Qt::Key_Asterisk ) ||
-     ( theKey >= Qt::Key_Comma && theKey <= Qt::Key_Question ) ||
-     ( theKey >= Qt::Key_A && theKey <= Qt::Key_AsciiTilde ) )
-    return true;
-  return false;
-}
-
-/*! \brief Called when "Clear" button is clicked. */
-void QtxKeySequenceEdit::onClear()
-{
-  myKeySequenceLineEdit->setText("");
-  myPrevKeySequenceString = "";
-  emit editingFinished();
-}
-
-/*! \brief Called when myKeySequenceLineEdit loses focus. */
-void QtxKeySequenceEdit::onEditingFinished()
-{
-  if (myKeySequenceLineEdit->text().endsWith("+"))
-    myKeySequenceLineEdit->setText(myPrevKeySequenceString);
-  else
-    myPrevKeySequenceString = myKeySequenceLineEdit->text();
-    emit editingFinished();
-}
-
-/*!
-  \brief Custom event filter.
-  \param obj event receiver object
-  \param event event
-  \returns \c true if further event processing should be stopped
-*/
-bool QtxKeySequenceEdit::eventFilter(QObject* theObject, QEvent* theEvent)
-{
-  if (theObject == myKeySequenceLineEdit) {
-    if (theEvent->type() == QEvent::KeyPress) {
-      QKeyEvent* keyEvent = static_cast<QKeyEvent*>(theEvent);
-      QString text = parseEvent(keyEvent);
-      if (keyEvent->key() == Qt::Key_Delete || keyEvent->key() == Qt::Key_Backspace)
-        myKeySequenceLineEdit->setText("");
-      if (!text.isEmpty())
-        myKeySequenceLineEdit->setText(text);
-
-      emit editingStarted();
-      return true;
-    }
-    if (theEvent->type() == QEvent::KeyRelease) {
-      onEditingFinished();
-      return true;
-    }
-  }
-  return false;
-}
-
-/*
-  \brief Perform internal intialization.
-*/
-void QtxKeySequenceEdit::initialize()
-{
-  static const int PIXMAP_SIZE = 30;
-
-  QHBoxLayout* base = new QHBoxLayout( this );
-  base->setMargin(0);
-  base->setSpacing(5);
-
-  base->addWidget(myKeySequenceLineEdit = new QLineEdit(this));
-  setFocusProxy(myKeySequenceLineEdit);
-
-  QToolButton* clearBtn = new QToolButton();
-  auto clearPixmap = QPixmap(":/images/shortcut_disable.svg");
-  clearPixmap.scaled(QSize(PIXMAP_SIZE, PIXMAP_SIZE), Qt::KeepAspectRatio, Qt::SmoothTransformation);
-  clearBtn->setIcon(clearPixmap);
-  clearBtn->setToolTip(tr("Disable shortcut."));
-  base->addWidget(clearBtn);
-
-  QToolButton* restoreBtn = new QToolButton();
-  auto restorePixmap = QPixmap(":/images/shortcut_restore.svg");
-  restorePixmap.scaled(QSize(PIXMAP_SIZE, PIXMAP_SIZE), Qt::KeepAspectRatio, Qt::SmoothTransformation);
-  restoreBtn->setIcon(restorePixmap);
-  restoreBtn->setToolTip(tr("Restore the currently applied key sequence."));
-  base->addWidget(restoreBtn);
-
-  myKeySequenceLineEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
-  clearBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-  restoreBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-
-  connect(clearBtn, SIGNAL(clicked()), this, SLOT(onClear()));
-  connect(restoreBtn, SIGNAL(clicked()), this, SIGNAL(restoreFromShortcutMgrClicked()));
-  connect(myKeySequenceLineEdit, SIGNAL(editingFinished()), this, SLOT(onEditingFinished()));
-}
-
-
-/*! \param theParent must not be nullptr. */
-QtxEditKeySequenceDialog::QtxEditKeySequenceDialog(QtxShortcutTree* theParent)
-: QDialog(theParent)
-{
-  setMinimumWidth(500);
-  setWindowTitle(tr("Change key sequence"));
-  QVBoxLayout* layout = new QVBoxLayout(this);
-  myActionName = new QLabel(this);
-  myActionName->setTextFormat(Qt::RichText);
-  myKeySequenceEdit = new QtxKeySequenceEdit(this);
-  myTextEdit = new QTextEdit(this);
-  layout->addWidget(myActionName);
-  layout->addWidget(myKeySequenceEdit);
-  layout->addWidget(myTextEdit);
-  myActionName->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
-  myKeySequenceEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
-  myTextEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
-  myTextEdit->setReadOnly(true);
-  myTextEdit->setAcceptRichText(true);
-  myTextEdit->setPlaceholderText(tr("No conflicts."));
-  setFocusProxy(myKeySequenceEdit);
-
-  QHBoxLayout* buttonLayout = new QHBoxLayout(this);
-  layout->addLayout(buttonLayout);
-  QPushButton* confirmButton = new QPushButton(tr("Confirm"), this);
-  confirmButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-  QPushButton* cancelButton = new QPushButton(tr("Cancel"), this);
-  cancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-  buttonLayout->addStretch();
-  buttonLayout->addWidget(confirmButton);
-  buttonLayout->addWidget(cancelButton);
-
-  connect(myKeySequenceEdit, SIGNAL(editingStarted()), this, SLOT(onEditingStarted()));
-  connect(myKeySequenceEdit, SIGNAL(editingFinished()), this, SLOT(onEditingFinished()));
-  connect(myKeySequenceEdit, SIGNAL(restoreFromShortcutMgrClicked()), this, SLOT(onRestoreFromShortcutMgr()));
-  connect(confirmButton, SIGNAL(clicked()), this, SLOT(onConfirm()));
-  connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
-}
-
-void QtxEditKeySequenceDialog::setModuleAndActionID(const QString& theModuleID, const QString& theInModuleActionID)
-{
-  myModuleID = theModuleID;
-  myInModuleActionID = theInModuleActionID;
-}
-
-const QString& QtxEditKeySequenceDialog::moduleID() const { return myModuleID; }
-const QString& QtxEditKeySequenceDialog::inModuleActionID() const { return myInModuleActionID; }
-
-void QtxEditKeySequenceDialog::setModuleAndActionName(const QString& theModuleName, const QString& theActionName, const QString& theActionToolTip)
-{
-  myActionName->setText("<b>" + theModuleName + "</b>&nbsp;&nbsp;" + theActionName);
-  myActionName->setToolTip(theActionToolTip);
-}
-
-void QtxEditKeySequenceDialog::setConfirmedKeySequence(const QKeySequence& theSequence)
-{
-  myKeySequenceEdit->setConfirmedKeySequence(theSequence);
-}
-
-QKeySequence QtxEditKeySequenceDialog::editedKeySequence() const
-{
-  return myKeySequenceEdit->editedKeySequence();
-}
-
-int QtxEditKeySequenceDialog::exec()
-{
-  myKeySequenceEdit->setFocus(Qt::ActiveWindowFocusReason);
-  return QDialog::exec();
-}
-
-void QtxEditKeySequenceDialog::onEditingStarted()
-{
-  myTextEdit->setEnabled(false);
-}
-
-void QtxEditKeySequenceDialog::onEditingFinished()
-{
-  updateConflictsMessage();
-}
-
-void QtxEditKeySequenceDialog::onRestoreFromShortcutMgr()
-{
-  const auto shortcutMgr = SUIT_ShortcutMgr::get();
-  myKeySequenceEdit->setEditedKeySequence(shortcutMgr->getKeySequence(myModuleID, myInModuleActionID));
-  updateConflictsMessage();
-}
-
-/*! Updates message with list of actions, whose shortcuts will be disabled on Confirm. */
-void QtxEditKeySequenceDialog::updateConflictsMessage()
-{
-  myTextEdit->setEnabled(true);
-  QTextDocument* doc = myTextEdit->document();
-  if (!doc) {
-    doc = new QTextDocument(myTextEdit);
-    myTextEdit->setDocument(doc);
-  }
-
-  if (!myKeySequenceEdit->isKeySequenceModified()) {
-    doc->clear();
-    return;
-  }
-
-  const QKeySequence newKeySequence = editedKeySequence();
-
-  const auto shortcutTree = static_cast<QtxShortcutTree*>(parentWidget());
-  /** {moduleID, inModuleActionID}[] */
-  std::set<std::pair<QString, QString>> conflicts = shortcutTree->shortcutContainer()->getConflicts(myModuleID, myInModuleActionID, newKeySequence);
-  if (!conflicts.empty()) {
-    const auto shortcutMgr = SUIT_ShortcutMgr::get();
-
-    QString report = "<b>" + tr("These shortcuts will be disabled on confirm:") + "</b>";
-    {
-      report += "<ul>";
-      for (const auto& conflict : conflicts) {
-        const QString conflictingModuleName = shortcutMgr->getModuleName(conflict.first);
-        const QString conflictingActionName = shortcutMgr->getActionName(conflict.first, conflict.second);
-        report += "<li><b>" + conflictingModuleName + "</b>&nbsp;&nbsp;" + conflictingActionName + "</li>";
-      }
-      report += "</ul>";
-    }
-    doc->setHtml(report);
-  }
-  else /* if no conflicts */ {
-    doc->clear();
-  }
-}
-
-void QtxEditKeySequenceDialog::onConfirm()
-{
-  if (myKeySequenceEdit->isKeySequenceModified())
-    accept();
-  else
-    reject();
-}
-
-
-/*! \brief Compensates lack of std::distance(), which is introduced in C++17.
-\returns -1, if theIt does not belong to the  */
-template <class Container>
-size_t indexOf(
-  const Container& theContainer,
-  const typename Container::iterator& theIt
-) {
-  auto it = theContainer.begin();
-  size_t distance = 0;
-  while (it != theContainer.end()) {
-    if (it == theIt)
-      return distance;
-
-    it++;
-    distance++;
-  }
-  return -1;
-}
-
-
-/*! \param theContainer Share the same container between several trees,
-to edit them synchronously even without exchange of changes with SUIT_ShortcutMgr.
-Pass nullptr to create non-synchronized tree. */
-QtxShortcutTree::QtxShortcutTree(
-  std::shared_ptr<SUIT_ShortcutContainer> theContainer,
-  QWidget* theParent
-) : QTreeWidget(theParent),
-myShortcutContainer(theContainer ? theContainer : std::shared_ptr<SUIT_ShortcutContainer>(new SUIT_ShortcutContainer())),
-mySortKey(QtxShortcutTree::SortKey::Name), mySortOrder(QtxShortcutTree::SortOrder::Ascending)
-{
-  setColumnCount(2);
-  setSelectionMode(QAbstractItemView::SingleSelection);
-  setColumnWidth(0, COLUMN_SIZE);
-  setSortingEnabled(false); // Items are sorted in the same way, as in ShortcutContainer.
-  header()->setSectionResizeMode(QHeaderView::Interactive);
-  {
-    QMap<int, QString> labelMap;
-    labelMap[QtxShortcutTree::ElementIdx::Name]        = tr("Action");
-    labelMap[QtxShortcutTree::ElementIdx::KeySequence] = tr("Key sequence");
-    setHeaderLabels(labelMap.values());
-  }
-  setExpandsOnDoubleClick(false); // Open shortcut editor on double click instead.
-  setSortingEnabled(false);
-  setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
-  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
-  myEditDialog = new QtxEditKeySequenceDialog(this);
-
-  this->installEventFilter(this);
-  connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(onItemDoubleClicked(QTreeWidgetItem*, int)));
-
-  QtxShortcutTree::instances[myShortcutContainer.get()].emplace(this);
-}
-
-QtxShortcutTree::~QtxShortcutTree()
-{
-  QtxShortcutTree::instances[myShortcutContainer.get()].erase(this);
-  if (QtxShortcutTree::instances[myShortcutContainer.get()].empty())
-    QtxShortcutTree::instances.erase(myShortcutContainer.get());
-}
-
-/*! \brief Copies shortcuts from ShortcutMgr. (Re)displays shortcuts of myModuleIDs. */
-void QtxShortcutTree::setShortcutsFromManager()
-{
-  const auto shortcutMgr = SUIT_ShortcutMgr::get();
-  *myShortcutContainer = shortcutMgr->getShortcutContainer();
-  // nb! ShortcutMgr never removes shortcuts from its container, only disables.
-
-  updateItems(false /*theHighlightModified*/, true /*theUpdateSyncTrees*/);
-}
-
-/*! \brief Copies shortcuts from resources, user files are not accounted. (Re)displays shortcuts of myModuleIDs. */
-void QtxShortcutTree::setDefaultShortcuts()
-{
-  SUIT_ShortcutContainer defaultShortcuts;
-  SUIT_ShortcutMgr::fillContainerFromPreferences(defaultShortcuts, true /*theDefaultOnly*/);
-
-  myShortcutContainer->merge(defaultShortcuts, true /*theOverride*/, true /*theTreatAbsentIncomingAsDisabled*/);
-  // nb! SUIT_ShortcutContainer never erases shortcuts, only disables.
-
-  updateItems(true /*theHighlightModified*/, true /*theUpdateSyncTrees*/);
-}
-
-/*! \brief Applies pending changes to ShortcutMgr. Updates other instances of QtxShortcutTree. */
-void QtxShortcutTree::applyChangesToShortcutMgr()
-{
-  const auto mgr = SUIT_ShortcutMgr::get();
-  mgr->mergeShortcutContainer(*myShortcutContainer);
-
-  // Update non-synchronized with this instances.
-  for (const auto& containerAndSyncTrees : QtxShortcutTree::instances) {
-    if (containerAndSyncTrees.first == myShortcutContainer.get())
-      continue;
-
-    const std::set<QtxShortcutTree*>& syncTrees = containerAndSyncTrees.second;
-    const auto itFirstSyncTree = syncTrees.begin();
-    if (itFirstSyncTree == syncTrees.end())
-      continue;
-
-    (*itFirstSyncTree)->setShortcutsFromManager();
-    const auto editDialog = (*itFirstSyncTree)->myEditDialog;
-    editDialog->setConfirmedKeySequence(mgr->getShortcutContainer().getKeySequence(editDialog->moduleID(), editDialog->inModuleActionID()));
-    editDialog->updateConflictsMessage();
-  }
-}
-
-std::shared_ptr<const SUIT_ShortcutContainer> QtxShortcutTree::shortcutContainer() const
-{
-  return myShortcutContainer;
-}
-
-/*! \brief Does not sort modules. */
-void QtxShortcutTree::sort(QtxShortcutTree::SortKey theKey, QtxShortcutTree::SortOrder theOrder)
-{
-  if (theKey == mySortKey && theOrder == mySortOrder)
-    return;
-
-  mySortKey == theKey;
-  mySortOrder = theOrder;
-
-  for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); moduleIdx++) {
-    const auto moduleItem = static_cast<QtxShortcutTreeFolder*>(topLevelItem(moduleIdx));
-    const auto sortedChildren = getSortedChildren(moduleItem);
-    moduleItem->takeChildren();
-
-    for (const auto childItem : sortedChildren) {
-      moduleItem->addChild(childItem);
-    }
-  }
-}
-
-/*! \param If theUpdateSyncTrees, trees sharing the same shortcut container are updated. */
-void QtxShortcutTree::updateItems(bool theHighlightModified, bool theUpdateSyncTrees)
-{
-  const auto shortcutMgr = SUIT_ShortcutMgr::get();
-  const QString lang = SUIT_ShortcutMgr::getLang();
-
-  for (const QString& moduleID : myModuleIDs) {
-    const auto& moduleShortcuts = myShortcutContainer->getModuleShortcutsInversed(moduleID);
-    if (moduleShortcuts.empty()) {
-      // Do not display empty module.
-      const auto moduleItemAndIdx = findModuleFolderItem(moduleID);
-      if (moduleItemAndIdx.second >= 0)
-        delete takeTopLevelItem(moduleItemAndIdx.second);
-
-      continue;
-    }
-
-    const auto moduleItemAndIdx = findModuleFolderItem(moduleID);
-    QtxShortcutTreeFolder* moduleItem = moduleItemAndIdx.first;
-    if (!moduleItem) {
-      moduleItem = new QtxShortcutTreeFolder(moduleID);
-      moduleItem->setAssets(shortcutMgr->getModuleAssets(moduleID), lang);
-      addTopLevelItem(moduleItem);
-      moduleItem->setFlags(Qt::ItemIsEnabled);
-
-      auto sortedChildren = getSortedChildren(moduleItem);
-      for (const auto& shortcut : moduleShortcuts) {
-        const QString& inModuleActionID = shortcut.first;
-        const QKeySequence& keySequence = shortcut.second;
-        const QString keySequenceString = keySequence.toString();
-
-        auto actionItem = QtxShortcutTreeAction::create(moduleID, inModuleActionID);
-        if (!actionItem) {
-          ShCutDbg("QtxShortcutTree can't create child item for action ID = \"" + SUIT_ShortcutMgr::makeActionID(moduleID, inModuleActionID) + "\".");
-          continue;
-        }
-
-        actionItem->setAssets(shortcutMgr->getActionAssets(moduleID, inModuleActionID), lang);
-        actionItem->setKeySequence(keySequenceString);
-
-        if (theHighlightModified) {
-          const QKeySequence& appliedKeySequence = SUIT_ShortcutMgr::get()->getKeySequence(moduleID, inModuleActionID);
-          actionItem->highlightKeySequenceAsModified(keySequence != appliedKeySequence);
-        }
-
-        insertChild(moduleItem, sortedChildren, actionItem);
-      }
-
-      moduleItem->setExpanded(true); // Make tree expanded on first show.
-    }
-    else /* if the tree has the module-item */ {
-      for (int childIdx = 0; childIdx < moduleItem->childCount(); childIdx++) {
-        // Update exisiting items of a module.
-        QtxShortcutTreeAction* const childItem = static_cast<QtxShortcutTreeAction*>(moduleItem->child(childIdx));
-        const auto itShortcut = moduleShortcuts.find(childItem->myInModuleActionID);
-        if (itShortcut == moduleShortcuts.end()) {
-          // Shortcut of the item has been removed from myShortcutContainer - impossible.
-          continue;
-        }
-        const QKeySequence& newKeySequence = itShortcut->second;
-        const QString newKeySequenceString = newKeySequence.toString();
-        if (childItem->keySequence() != newKeySequenceString)
-          childItem->setKeySequence(newKeySequenceString);
-
-        if (theHighlightModified) {
-          const QKeySequence& appliedKeySequence = SUIT_ShortcutMgr::get()->getKeySequence(moduleID, childItem->myInModuleActionID);
-          childItem->highlightKeySequenceAsModified(newKeySequence != appliedKeySequence);
-        }
-        else
-          childItem->highlightKeySequenceAsModified(false);
-      }
-
-      // Add new items if myShortcutContainer acquired new shortcuts, which may happen if a developer forgot
-      // to add shortcuts for registered actions to resource files.
-      if (moduleItem->childCount() < moduleShortcuts.size()) {
-        auto sortedChildren = getSortedChildren(moduleItem);
-        for (const auto& shortcut : moduleShortcuts) {
-          const QString& inModuleActionID = shortcut.first;
-          const auto predicate = [&inModuleActionID](const QtxShortcutTreeItem* const theItem) -> bool {
-            return static_cast<const QtxShortcutTreeAction* const>(theItem)->myInModuleActionID == inModuleActionID;
-          };
-
-          if (std::find_if(sortedChildren.begin(), sortedChildren.end(), predicate) == sortedChildren.end()) {
-            const auto actionItem = QtxShortcutTreeAction::create(moduleID, inModuleActionID);
-            if (!actionItem) {
-              ShCutDbg("QtxShortcutTree can't create child item for action ID = \"" + SUIT_ShortcutMgr::makeActionID(moduleID, inModuleActionID) + "\".");
-              continue;
-            }
-
-            const QKeySequence& keySequence = shortcut.second;
-            actionItem->setAssets(shortcutMgr->getActionAssets(moduleID, inModuleActionID), lang);
-            actionItem->setKeySequence(keySequence.toString());
-
-            if (theHighlightModified) {
-              const QKeySequence& appliedKeySequence = SUIT_ShortcutMgr::get()->getKeySequence(moduleID, inModuleActionID);
-              actionItem->highlightKeySequenceAsModified(keySequence != appliedKeySequence);
-            }
-
-            insertChild(moduleItem, sortedChildren, actionItem);
-          }
-        }
-      }
-    }
-  }
-
-  if (theUpdateSyncTrees) {
-    const std::set<QtxShortcutTree*>& syncTrees = QtxShortcutTree::instances[myShortcutContainer.get()];
-    for (const auto syncTree: syncTrees) {
-      if (syncTree == this)
-        continue;
-
-      syncTree->updateItems(theHighlightModified, false /*theUpdateSyncTrees*/);
-      const auto editDialog = syncTree->myEditDialog;
-      editDialog->setConfirmedKeySequence(myShortcutContainer->getKeySequence(editDialog->moduleID(), editDialog->inModuleActionID()));
-      editDialog->updateConflictsMessage();
-    }
-  }
-}
-
-/*! \returns Pointer and index of top-level item.
-If the tree does not contain an item with theModuleID, returns {nullptr, -1}. */
-std::pair<QtxShortcutTreeFolder*, int> QtxShortcutTree::findModuleFolderItem(const QString& theModuleID) const
-{
-  for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); moduleIdx++) {
-    QtxShortcutTreeFolder* moduleItem = static_cast<QtxShortcutTreeFolder*>(topLevelItem(moduleIdx));
-    if (moduleItem->myModuleID == theModuleID)
-      return std::pair<QtxShortcutTreeFolder*, int>(moduleItem, moduleIdx);
-  }
-  return std::pair<QtxShortcutTreeFolder*, int>(nullptr, -1);
-}
-
-/*! \returns Children of theParentItem being sorted according to current sort mode and order. */
-std::set<QtxShortcutTreeItem*, std::function<bool(QtxShortcutTreeItem*, QtxShortcutTreeItem*)>> QtxShortcutTree::getSortedChildren(QtxShortcutTreeFolder* theParentItem)
-{
-  QList<std::pair<QtxShortcutTree::SortKey, QtxShortcutTree::SortOrder>> sortSchema = QtxShortcutTree::DEFAULT_SORT_SCHEMA;
-  {
-    for (auto itSameKey = sortSchema.begin(); itSameKey != sortSchema.end(); itSameKey++) {
-      if (itSameKey->first == mySortKey) {
-        sortSchema.erase(itSameKey);
-        break;
-      }
-    }
-    sortSchema.push_front(std::pair<QtxShortcutTree::SortKey, QtxShortcutTree::SortOrder>(mySortKey, mySortOrder));
-  }
-
-  static const QCollator collator;
-  const std::function<bool(QtxShortcutTreeItem*, QtxShortcutTreeItem*)> comparator =
-  [this, sortSchema, &collator](const QtxShortcutTreeItem* theItemA, const QtxShortcutTreeItem* theItemB) {
-    int res = 0;
-    for (const auto& keyAndOrder : sortSchema) {
-      int res = 0;
-      res = collator.compare(theItemA->getValue(keyAndOrder.first), theItemB->getValue(keyAndOrder.first));
-      if (res != 0)
-        return keyAndOrder.second == QtxShortcutTree::SortOrder::Ascending ? res < 0 : res > 0;
-    }
-    return false;
-  };
-
-  std::set<QtxShortcutTreeItem*, std::function<bool(QtxShortcutTreeItem*, QtxShortcutTreeItem*)>> sortedChildren(comparator);
-  for (int childIdx = 0; childIdx < theParentItem->childCount(); childIdx++) {
-    QtxShortcutTreeAction* const childItem = static_cast<QtxShortcutTreeAction*>(theParentItem->child(childIdx));
-    sortedChildren.emplace(childItem);
-  }
-  return sortedChildren;
-}
-
-/*! \brief Inserts theChildItem to theParentItem and theSortedChildren.
-Does not check whether theSortedChildren are actually child items of theParentItem.
-Does not check whether current item sort schema is same as one of theSortedChildren. */
-void QtxShortcutTree::insertChild(
-  QtxShortcutTreeFolder* theParentItem,
-  std::set<QtxShortcutTreeItem*, std::function<bool(QtxShortcutTreeItem*, QtxShortcutTreeItem*)>>& theSortedChildren,
-  QtxShortcutTreeItem* theChildItem
-) {
-  auto emplaceRes = theSortedChildren.emplace(theChildItem);
-  theParentItem->insertChild(indexOf(theSortedChildren, emplaceRes.first), theChildItem);
-}
-
-void QtxShortcutTree::onItemDoubleClicked(QTreeWidgetItem* theItem, int theColIdx)
-{
-  {
-    QtxShortcutTreeItem* const item = static_cast<QtxShortcutTreeItem*>(theItem);
-    // Do not react if folder-item is clicked.
-    if (item->type() != QtxShortcutTreeItem::Type::Action)
-      return;
-  }
-
-  QtxShortcutTreeAction* const actionItem = static_cast<QtxShortcutTreeAction*>(theItem);
-
-  myEditDialog->setModuleAndActionID(actionItem->myModuleID, actionItem->myInModuleActionID);
-  QString actionToolTip = actionItem->toolTip(QtxShortcutTree::ElementIdx::Name);
-  actionToolTip.truncate(actionToolTip.lastIndexOf('\n') + 1);
-  myEditDialog->setModuleAndActionName(
-    static_cast<QtxShortcutTreeItem*>(actionItem->parent())->name(),
-    actionItem->name(),
-    actionToolTip
-  );
-  myEditDialog->setConfirmedKeySequence(QKeySequence::fromString(actionItem->keySequence()));
-  myEditDialog->updateConflictsMessage();
-  const bool somethingChanged = myEditDialog->exec() == QDialog::Accepted;
-
-  if (!somethingChanged)
-    return;
-
-  const QKeySequence newKeySequence = myEditDialog->editedKeySequence();
-
-  /** { moduleID, inModuleActionID }[] */
-  std::set<std::pair<QString, QString>> disabledActionIDs = myShortcutContainer->setShortcut(actionItem->myModuleID, actionItem->myInModuleActionID, newKeySequence, true /*override*/);
-
-  /** { moduleID, {inModuleActionID, keySequence}[] }[] */
-  std::map<QString, std::map<QString, QString>> changes;
-  changes[actionItem->myModuleID][actionItem->myInModuleActionID] = newKeySequence.toString();
-  for (const auto moduleAndActionID : disabledActionIDs) {
-    changes[moduleAndActionID.first][moduleAndActionID.second] = QString();
-  }
-
-  // Set new key sequences to shortcut items.
-  for (const auto& moduleIDAndChanges : changes) {
-    const QString& moduleID = moduleIDAndChanges.first;
-
-    const auto moduleItemAndIdx = findModuleFolderItem(moduleID);
-    const auto moduleItem = moduleItemAndIdx.first;
-    if (!moduleItem)
-      continue;
-
-    /** {inModuleActionID, newKeySequence}[] */
-    const std::map<QString, QString>& moduleChanges = moduleIDAndChanges.second;
-
-    // Go through module' shortcut items, and highlight those, whose key sequences differ from applied key sequences.
-    for (int childIdx = 0; childIdx < moduleItem->childCount(); childIdx++) {
-      QtxShortcutTreeAction* const childItem = static_cast<QtxShortcutTreeAction*>(moduleItem->child(childIdx));
-      const auto itChange = moduleChanges.find(childItem->myInModuleActionID);
-      if (itChange == moduleChanges.end()) {
-        // The shortcut has not been changed.
-        continue;
-      }
-
-      childItem->setKeySequence(itChange->second);
-
-      const QKeySequence& appliedKeySequence = SUIT_ShortcutMgr::get()->getKeySequence(moduleID, childItem->myInModuleActionID);
-      childItem->highlightKeySequenceAsModified(QKeySequence::fromString(itChange->second) != appliedKeySequence);
-    }
-  }
-}
-
-/*static*/ const QList<std::pair<QtxShortcutTree::SortKey, QtxShortcutTree::SortOrder>> QtxShortcutTree::DEFAULT_SORT_SCHEMA =
-{
-  {QtxShortcutTree::SortKey::Name, QtxShortcutTree::SortOrder::Ascending},
-  {QtxShortcutTree::SortKey::ToolTip, QtxShortcutTree::SortOrder::Ascending},
-  {QtxShortcutTree::SortKey::KeySequence, QtxShortcutTree::SortOrder::Ascending},
-  {QtxShortcutTree::SortKey::ID, QtxShortcutTree::SortOrder::Ascending}
-};
-
-/*static*/ std::map<SUIT_ShortcutContainer*, std::set<QtxShortcutTree*>> QtxShortcutTree::instances =
-std::map<SUIT_ShortcutContainer*, std::set<QtxShortcutTree*>>();
-
-
-
-QtxShortcutTreeItem::QtxShortcutTreeItem(const QString& theModuleID)
-: QTreeWidgetItem(), myModuleID(theModuleID)
-{ }
-
-QString QtxShortcutTreeItem::name() const
-{
-  return text(QtxShortcutTree::ElementIdx::Name);
-}
-
-
-QtxShortcutTreeFolder::QtxShortcutTreeFolder(const QString& theModuleID)
-: QtxShortcutTreeItem(theModuleID)
-{
-  QFont f = font(QtxShortcutTree::ElementIdx::Name);
-  f.setBold(true);
-  setFont(QtxShortcutTree::ElementIdx::Name, f);
-  setText(QtxShortcutTree::ElementIdx::Name, theModuleID);
-}
-
-void QtxShortcutTreeFolder::setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang)
-{
-  if (!theAssets)
-    return;
-
-  setIcon(QtxShortcutTree::ElementIdx::Name, theAssets->myIcon);
-
-  const auto& ldaMap = theAssets->myLangDependentAssets;
-  if (ldaMap.empty()) {
-    setText(QtxShortcutTree::ElementIdx::Name, myModuleID);
-    return;
-  }
-
-  auto itLDA = ldaMap.find(theLang);
-  if (itLDA == ldaMap.end())
-    itLDA = ldaMap.begin();
-
-  const SUIT_ActionAssets::LangDependentAssets& lda = itLDA->second;
-  const QString& name = lda.myName.isEmpty() ? myModuleID : lda.myName;
-  setText(QtxShortcutTree::ElementIdx::Name, name);
-}
-
-QString QtxShortcutTreeFolder::getValue(QtxShortcutTree::SortKey theKey) const
-{
-  switch (theKey) {
-    case QtxShortcutTree::SortKey::ID:
-      return myModuleID;
-    case QtxShortcutTree::SortKey::Name:
-      return name();
-    case QtxShortcutTree::SortKey::ToolTip:
-      return name();
-    default:
-      return QString();
-  }
-}
-
-
-QtxShortcutTreeAction::QtxShortcutTreeAction(const QString& theModuleID, const QString& theInModuleActionID)
-: QtxShortcutTreeItem(theModuleID), myInModuleActionID(theInModuleActionID)
-{
-  setText(QtxShortcutTree::ElementIdx::Name, theInModuleActionID);
-  setToolTip(
-    QtxShortcutTree::ElementIdx::Name,
-    theInModuleActionID + (theInModuleActionID.at(theInModuleActionID.length()-1) == "." ? "\n" : ".\n") + QtxShortcutTree::tr("Double click to edit key sequence.")
-  );
-  setToolTip(QtxShortcutTree::ElementIdx::KeySequence, QtxShortcutTree::tr("Double click to edit key sequence."));
-}
-
-/*static*/ QtxShortcutTreeAction* QtxShortcutTreeAction::create(const QString& theModuleID, const QString& theInModuleActionID)
-{
-  if (theInModuleActionID.isEmpty()) {
-    ShCutDbg("QtxShortcutTreeItem: attempt to create item with empty action ID.");
-    return nullptr;
-  }
-
-  return new QtxShortcutTreeAction(theModuleID, theInModuleActionID);
-}
-
-void QtxShortcutTreeAction::setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang)
-{
-  if (!theAssets)
-    return;
-
-  setIcon(QtxShortcutTree::ElementIdx::Name, theAssets->myIcon);
-
-  const auto& ldaMap = theAssets->myLangDependentAssets;
-  if (ldaMap.empty()) {
-    setText(QtxShortcutTree::ElementIdx::Name, myInModuleActionID);
-    return;
-  }
-
-  auto itLDA = ldaMap.find(theLang);
-  if (itLDA == ldaMap.end())
-    itLDA = ldaMap.begin();
-
-  const SUIT_ActionAssets::LangDependentAssets& lda = itLDA->second;
-  const QString& name = lda.myName.isEmpty() ? myInModuleActionID : lda.myName;
-  setText(QtxShortcutTree::ElementIdx::Name, name);
-
-  const QString& actionToolTip = lda.myToolTip.isEmpty() ? name : lda.myToolTip;
-  setToolTip(
-    QtxShortcutTree::ElementIdx::Name,
-    actionToolTip + (actionToolTip.at(actionToolTip.length()-1) == "." ? "\n" : ".\n") + QtxShortcutTree::tr("Double click to edit key sequence.")
-  );
-}
-
-QString QtxShortcutTreeAction::getValue(QtxShortcutTree::SortKey theKey) const
-{
-  switch (theKey) {
-    case QtxShortcutTree::SortKey::ID:
-      return myInModuleActionID;
-    case QtxShortcutTree::SortKey::Name:
-      return name();
-    case QtxShortcutTree::SortKey::ToolTip:
-      return toolTip(QtxShortcutTree::ElementIdx::Name);
-    case QtxShortcutTree::SortKey::KeySequence:
-      return keySequence();
-    default:
-      return QString();
-  }
-}
-
-void QtxShortcutTreeAction::setKeySequence(const QString& theKeySequence)
-{
-  setText(QtxShortcutTree::ElementIdx::KeySequence, theKeySequence);
-}
-
-QString QtxShortcutTreeAction::keySequence() const
-{
-  return text(QtxShortcutTree::ElementIdx::KeySequence);
-}
-
-/*! \brief Highlights text at ElementIdx::KeySequence. */
-void QtxShortcutTreeAction::highlightKeySequenceAsModified(bool theHighlight)
-{
-  static const QBrush bgHighlitingBrush = QBrush(Qt::darkGreen);
-  static const QBrush fgHighlitingBrush = QBrush(Qt::white);
-  static const QBrush noBrush = QBrush();
-
-  setBackground(QtxShortcutTree::ElementIdx::KeySequence, theHighlight ? bgHighlitingBrush : noBrush);
-  setForeground(QtxShortcutTree::ElementIdx::KeySequence, theHighlight ? fgHighlitingBrush : noBrush);
-}
\ No newline at end of file
diff --git a/src/Qtx/QtxShortcutEdit.h b/src/Qtx/QtxShortcutEdit.h
deleted file mode 100644 (file)
index 862c80d..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
-//
-
-#ifndef QTXSHORTCUTTREE_H
-#define QTXSHORTCUTTREE_H
-
-#include "Qtx.h"
-#include <QDialog>
-#include <QFrame>
-#include <QTreeWidget>
-#include "SUIT_ShortcutMgr.h"
-#include <memory>
-#include <map>
-#include <set>
-#include <functional>
-
-
-class QLineEdit;
-class QLabel;
-class QPushButton;
-class QTreeWidgetItem;
-
-class QTX_EXPORT QtxKeySequenceEdit : public QFrame
-{
-  Q_OBJECT
-
-public:
-  QtxKeySequenceEdit(QWidget* = nullptr);
-  virtual ~QtxKeySequenceEdit() = default;
-
-  void           setConfirmedKeySequence(const QKeySequence&);
-  void           setEditedKeySequence(const QKeySequence&);
-  QKeySequence   editedKeySequence() const;
-  bool           isKeySequenceModified() const;
-  void           restoreKeySequence();
-
-  static QString parseEvent(QKeyEvent*);
-  static bool    isValidKey(int);
-
-signals:
-  void           editingStarted();
-  void           editingFinished();
-  void           restoreFromShortcutMgrClicked();
-
-private slots:
-  void           onClear();
-  void           onEditingFinished();
-
-protected:
-  virtual bool   eventFilter(QObject*, QEvent*);
-
-private:
-  void           initialize();
-
-private:
-  QLineEdit*     myKeySequenceLineEdit;
-  QString        myConfirmedKeySequenceString;
-
-  // Last valid key sequence string from myKeySequenceLineEdit.
-  QString        myPrevKeySequenceString;
-};
-
-
-class QtxShortcutTree;
-class QtxShortcutTreeItem;
-class QtxShortcutTreeFolder;
-class QtxShortcutTreeAction;
-class QTextEdit;
-
-
-class QTX_EXPORT QtxEditKeySequenceDialog : public QDialog
-{
-  Q_OBJECT
-
-public:
-  QtxEditKeySequenceDialog(QtxShortcutTree* theParent);
-  QtxEditKeySequenceDialog(const QtxEditKeySequenceDialog&) = delete;
-  QtxEditKeySequenceDialog& operator=(const QtxEditKeySequenceDialog&) = delete;
-  virtual ~QtxEditKeySequenceDialog() = default;
-
-  void setModuleAndActionID(const QString& theModuleID, const QString& theInModuleActionID);
-  const QString& moduleID() const;
-  const QString& inModuleActionID() const;
-
-  void setModuleAndActionName(const QString& theModuleName, const QString& theActionName, const QString& theActionToolTip = "");
-
-  void setConfirmedKeySequence(const QKeySequence& theSequence);
-  QKeySequence editedKeySequence() const;
-
-  void updateConflictsMessage();
-
-  int exec();
-
-private slots:
-  void onEditingStarted();
-  void onEditingFinished();
-  void onRestoreFromShortcutMgr();
-  void onConfirm();
-
-private:
-  QString myModuleID;
-  QString myInModuleActionID;
-  QLabel* myActionName;
-  QtxKeySequenceEdit* myKeySequenceEdit;
-  QTextEdit* myTextEdit;
-};
-
-
-class QTX_EXPORT QtxShortcutTree : public QTreeWidget
-{
-  Q_OBJECT
-
-public:
-  enum ElementIdx {
-    Name = 0,
-    KeySequence = 1, // Empty, if item is folder item.
-  };
-
-  enum class SortKey {
-    ID,
-    Name,
-    ToolTip,
-    KeySequence,
-  };
-
-  enum class SortOrder {
-    Ascending,
-    Descending
-  };
-
-  QtxShortcutTree(
-    std::shared_ptr<SUIT_ShortcutContainer> theContainer = std::shared_ptr<SUIT_ShortcutContainer>(),
-    QWidget* theParent = nullptr
-  );
-  QtxShortcutTree(const QtxShortcutTree&) = delete;
-  QtxShortcutTree& operator=(const QtxShortcutTree&) = delete;
-  virtual ~QtxShortcutTree();
-
-  void setShortcutsFromManager();
-  void setDefaultShortcuts();
-  void applyChangesToShortcutMgr();
-
-  std::shared_ptr<const SUIT_ShortcutContainer> shortcutContainer() const;
-
-  void sort(QtxShortcutTree::SortKey theKey, QtxShortcutTree::SortOrder theOrder);
-
-private:
-  void updateItems(bool theHighlightModified, bool theUpdateSyncTrees);
-  std::pair<QtxShortcutTreeFolder*, int> findModuleFolderItem(const QString& theModuleID) const;
-
-  std::set<QtxShortcutTreeItem*, std::function<bool(QtxShortcutTreeItem*, QtxShortcutTreeItem*)>> getSortedChildren(QtxShortcutTreeFolder* theParentItem);
-
-  void insertChild(
-    QtxShortcutTreeFolder* theParentItem,
-    std::set<QtxShortcutTreeItem*, std::function<bool(QtxShortcutTreeItem*, QtxShortcutTreeItem*)>>& theSortedChildren,
-    QtxShortcutTreeItem* theChildItem
-  );
-
-private slots:
-  void onItemDoubleClicked(QTreeWidgetItem* theWidgetItem, int theColIdx);
-
-public:
-  /** Keeps IDs of modules, which will are shown on setShortcutsFromManager(). */
-  std::set<QString> myModuleIDs;
-
-  static const QList<std::pair<QtxShortcutTree::SortKey, QtxShortcutTree::SortOrder>> DEFAULT_SORT_SCHEMA;
-
-private:
-  /** Allows to modify plenty of shortcuts and then apply them to SUIT_ShortcutMgr as a batch. */
-  const std::shared_ptr<SUIT_ShortcutContainer> myShortcutContainer;
-
-  QtxEditKeySequenceDialog* myEditDialog;
-
-  QtxShortcutTree::SortKey mySortKey;
-  QtxShortcutTree::SortOrder mySortOrder;
-
-  /**
-   * Ensures that, if several QtxShortcutTree instances coexist,
-   * all of them are updated when one of them applies pending changes to SUIT_ShortcutMgr.
-   *
-   * Sharing of SUIT_ShortcutContainer allows to keep some trees synchronized even without
-   * applying changes to SUIT_ShortcutMgr. Why? See QtxPagePrefShortcutTreeItem.
-   *
-   * Access is not synchronized in assumption, that all instances live in the same thread.
-  */
-  static std::map<SUIT_ShortcutContainer*, std::set<QtxShortcutTree*>> instances;
-};
-
-
-class QtxShortcutTreeItem : public QTreeWidgetItem
-{
-public:
-  enum Type {
-    Folder = 0,
-    Action = 1,
-  };
-
-protected:
-  QtxShortcutTreeItem(const QString& theModuleID);
-
-public:
-  virtual ~QtxShortcutTreeItem() = default;
-  virtual QtxShortcutTreeItem::Type type() const = 0;
-
-  virtual void setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang) = 0;
-  QString name() const;
-
-  virtual QString getValue(QtxShortcutTree::SortKey theKey) const = 0;
-
-public:
-  const QString myModuleID;
-};
-
-
-class QtxShortcutTreeFolder : public QtxShortcutTreeItem
-{
-public:
-  QtxShortcutTreeFolder(const QString& theModuleID);
-  virtual ~QtxShortcutTreeFolder() = default;
-  virtual QtxShortcutTreeItem::Type type() const { return QtxShortcutTreeItem::Type::Folder; };
-
-  virtual void setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang);
-
-  virtual QString getValue(QtxShortcutTree::SortKey theKey) const;
-};
-
-
-class QtxShortcutTreeAction : public QtxShortcutTreeItem
-{
-private:
-  QtxShortcutTreeAction(const QString& theModuleID, const QString& theInModuleActionID);
-
-public:
-  static QtxShortcutTreeAction* create(const QString& theModuleID, const QString& theInModuleActionID);
-  virtual ~QtxShortcutTreeAction() = default;
-  virtual QtxShortcutTreeItem::Type type() const { return QtxShortcutTreeItem::Type::Action; };
-
-  virtual void setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang);
-
-  virtual QString getValue(QtxShortcutTree::SortKey theKey) const;
-
-  void setKeySequence(const QString& theKeySequence);
-  QString keySequence() const;
-  void highlightKeySequenceAsModified(bool theHighlight);
-
-  const QString myInModuleActionID;
-};
-
-#endif // QTXSHORTCUTTREE_H
index a0b359e49b5319802962e0a367020afc16976bf2..d61dfe7fb74c7b1b483a029ea7046f7b342c851a 100644 (file)
         <translation>Echelle de couleurs</translation>
     </message>
 </context>
-<context>
-    <name>QtxFindActionDialog</name>
-    <message>
-        <source>Find action</source>
-        <translation>Trouver une action</translation>
-    </message>
-    <message>
-        <source>Unavailable actions</source>
-        <translation>Actions indisponibles</translation>
-    </message>
-    <message>
-        <source>Inactive modules</source>
-        <translation>Modules inactifs</translation>
-    </message>
-    <message>
-        <source>Action</source>
-        <translation>Action</translation>
-    </message>
-    <message>
-        <source>Description</source>
-        <translation>Description</translation>
-    </message>
-</context>
 <context>
     <name>QtxBackgroundTool</name>
     <message>
         <translation>%1 a été développé en utilisant %2</translation>
     </message>
 </context>
-<context>
-    <name>QtxKeySequenceEdit</name>
-    <message>
-        <source>Disable shortcut.</source>
-        <translation>Désactivez le raccourci.</translation>
-    </message>
-    <message>
-        <source>Restore the currently applied key sequence.</source>
-        <translation>Restaurez la séquence de touches actuellement appliquée.</translation>
-    </message>
-</context>
-<context>
-    <name>QtxEditKeySequenceDialog</name>
-    <message>
-        <source>Change key sequence</source>
-        <translation>Modifier la séquence de touches</translation>
-    </message>
-    <message>
-        <source>No conflicts.</source>
-        <translation>Aucun conflit.</translation>
-    </message>
-    <message>
-        <source>Confirm</source>
-        <translation>Confirmer</translation>
-    </message>
-    <message>
-        <source>Cancel</source>
-        <translation>Annuler</translation>
-    </message>
-    <message>
-        <source>These shortcuts will be disabled on confirm:</source>
-        <translation>Ces raccourcis seront désactivés lors de la confirmation :</translation>
-    </message>
-</context>
-<context>
-    <name>QtxShortcutTree</name>
-    <message>
-        <source>Action</source>
-        <translation>Action</translation>
-    </message>
-    <message>
-        <source>Key sequence</source>
-        <translation>Séquence de touches</translation>
-    </message>
-    <message>
-        <source>Double click to edit key sequence.</source>
-        <translation>Double-cliquez pour modifier la séquence de touches.</translation>
-    </message>
-</context>
 </TS>
index e7e67a371a84af4b3815bbdaf4cf74988bf03987..173c8128288fe8d0517d008310985163c6a522a8 100644 (file)
       <translation>カラースケール</translation>
     </message>
   </context>
-  <context>
-    <name>QtxFindActionDialog</name>
-    <message>
-        <source>Find action</source>
-        <translation>検索アクション</translation>
-    </message>
-    <message>
-        <source>Unavailable actions</source>
-        <translation>利用できないアクション</translation>
-    </message>
-    <message>
-        <source>Inactive modules</source>
-        <translation>非アクティブなモジュール</translation>
-    </message>
-    <message>
-        <source>Action</source>
-        <translation>アクション</translation>
-    </message>
-    <message>
-        <source>Description</source>
-        <translation>説明</translation>
-    </message>
-  </context>
   <context>
     <name>QtxBackgroundTool</name>
     <message>
       <translation>%1 は %2 を使用して開発されています。</translation>
     </message>
   </context>
-  <context>
-    <name>QtxKeySequenceEdit</name>
-    <message>
-        <source>Disable shortcut.</source>
-        <translation>ショートカットを無効にします。</translation>
-    </message>
-    <message>
-        <source>Restore the currently applied key sequence.</source>
-        <translation>現在適用されているキー シーケンスを復元します。</translation>
-    </message>
-  </context>
-  <context>
-      <name>QtxEditKeySequenceDialog</name>
-      <message>
-          <source>Change key sequence</source>
-          <translation>キーシーケンスを変更する</translation>
-      </message>
-      <message>
-          <source>No conflicts.</source>
-          <translation>競合はありません。</translation>
-      </message>
-      <message>
-          <source>Confirm</source>
-          <translation>確認する</translation>
-      </message>
-      <message>
-          <source>Cancel</source>
-          <translation>キャンセル</translation>
-      </message>
-      <message>
-          <source>These shortcuts will be disabled on confirm:</source>
-          <translation>これらのショートカットは確認時に無効になります。</translation>
-      </message>
-  </context>
-  <context>
-      <name>QtxShortcutTree</name>
-      <message>
-        <source>Action</source>
-        <translation>アクション</translation>
-      </message>
-      <message>
-          <source>Key sequence</source>
-          <translation>キーシーケンス</translation>
-      </message>
-      <message>
-          <source>Double click to edit key sequence.</source>
-          <translation>ダブルクリックしてキー シーケンスを編集します。</translation>
-      </message>
-  </context>
 </TS>
index 6c7c3f6af0a215c70d008c62d050b781df445c5c..95015a57c70e7b1657312321c908670cac4a6984 100644 (file)
@@ -46,14 +46,17 @@ SET(_moc_HEADERS
   SUIT_DataObject.h
   SUIT_Desktop.h
   SUIT_FileDlg.h
+  SUIT_FindActionDialog.h
   SUIT_LicenseDlg.h
   SUIT_MessageBox.h
   SUIT_Operation.h
+  SUIT_PagePrefShortcutTreeItem.h
   SUIT_PopupClient.h
   SUIT_PreferenceMgr.h
   SUIT_SelectionMgr.h
   SUIT_Session.h
   SUIT_ShortcutMgr.h
+  SUIT_ShortcutTree.h
   SUIT_Study.h
   SUIT_TreeModel.h
   SUIT_ViewManager.h
@@ -121,10 +124,12 @@ SET(_other_SOURCES
   SUIT_ExceptionHandler.cxx
   SUIT_FileDlg.cxx
   SUIT_FileValidator.cxx
+  SUIT_FindActionDialog.cxx
   SUIT_LicenseDlg.cxx
   SUIT_MessageBox.cxx
   SUIT_Operation.cxx
   SUIT_OverrideCursor.cxx
+  SUIT_PagePrefShortcutTreeItem.cxx
   SUIT_PopupClient.cxx
   SUIT_PreferenceMgr.cxx
   SUIT_ResourceMgr.cxx
@@ -133,6 +138,7 @@ SET(_other_SOURCES
   SUIT_Selector.cxx
   SUIT_Session.cxx
   SUIT_ShortcutMgr.cxx
+  SUIT_ShortcutTree.cxx
   SUIT_Study.cxx
   SUIT_Tools.cxx
   SUIT_TreeModel.cxx
diff --git a/src/SUIT/SUIT_FindActionDialog.cxx b/src/SUIT/SUIT_FindActionDialog.cxx
new file mode 100644 (file)
index 0000000..4136513
--- /dev/null
@@ -0,0 +1,348 @@
+// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "SUIT_FindActionDialog.h"
+
+#include <QAction>
+#include <QWidget>
+#include <QLayout>
+#include <QList>
+#include <QMap>
+
+#include <QCollator>
+
+#include <QCheckBox>
+#include <QLineEdit>
+#include <QBrush>
+#include <QColor>
+#include <QHeaderView>
+
+#include <algorithm>
+
+
+SUIT_FindActionDialog::SUIT_FindActionDialog(QWidget* theParent)
+: QDialog(theParent)
+{
+  setMinimumWidth(500);
+  setWindowTitle(tr("Find action"));
+  QVBoxLayout* layout = new QVBoxLayout(this);
+
+  myQueryLineEdit = new QLineEdit(this);
+  layout->addWidget(myQueryLineEdit);
+  myQueryLineEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+  setFocusProxy(myQueryLineEdit);
+
+  QHBoxLayout* searchOptionsLayout = new QHBoxLayout(this);
+  layout->addLayout(searchOptionsLayout);
+  myIncludeUnavailableActionsCB = new QCheckBox(tr("Unavailable actions"), this);
+  myIncludeUnavailableActionsCB->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+  myIncludeUnavailableActionsCB->setCheckState(Qt::CheckState::Checked);
+  myActionSearcher.includeDisabledActions(true);
+  myIncludeInactiveModulesCB = new QCheckBox(tr("Inactive modules"), this);
+  myIncludeInactiveModulesCB->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+  myIncludeInactiveModulesCB->setCheckState(Qt::CheckState::Unchecked);
+  searchOptionsLayout->addWidget(myIncludeUnavailableActionsCB);
+  searchOptionsLayout->addWidget(myIncludeInactiveModulesCB);
+
+  myFoundActionsTree = new SUIT_FoundActionTree(this);
+  layout->addWidget(myFoundActionsTree);
+
+  connect(myQueryLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(onQueryChanged(const QString&)));
+  connect(myIncludeUnavailableActionsCB, SIGNAL(stateChanged(int)), this, SLOT(onSearchOptionUnavailableActionsChanged(int)));
+  connect(myIncludeInactiveModulesCB, SIGNAL(stateChanged(int)), this, SLOT(onSearchOptionInactiveModulesChanged(int)));
+}
+
+void SUIT_FindActionDialog::setActiveModuleID(const QString& theModuleID)
+{
+  myActiveModuleID = theModuleID;
+  if(myActionSearcher.setIncludedModuleIDs(std::set<QString>({SUIT_ShortcutMgr::ROOT_MODULE_ID, myActiveModuleID})))
+    updateUI();
+}
+
+void SUIT_FindActionDialog::onQueryChanged(const QString& theQuery)
+{
+  if (myActionSearcher.setQuery(theQuery))
+    updateUI();
+}
+
+void SUIT_FindActionDialog::onSearchOptionUnavailableActionsChanged(int theState)
+{
+  if (myActionSearcher.includeDisabledActions(theState == Qt::CheckState::Checked))
+    updateUI();
+}
+
+void SUIT_FindActionDialog::onSearchOptionInactiveModulesChanged(int theState)
+{
+  bool resultsChanged = false;
+  if (theState == Qt::CheckState::Checked)
+    resultsChanged = myActionSearcher.setIncludedModuleIDs(SUIT_ShortcutMgr::get()->getShortcutContainer().getIDsOfAllModules());
+  else
+    resultsChanged = myActionSearcher.setIncludedModuleIDs(std::set<QString>({SUIT_ShortcutMgr::ROOT_MODULE_ID, myActiveModuleID}));
+
+  if (resultsChanged)
+    updateUI();
+}
+
+void SUIT_FindActionDialog::updateUI()
+{
+  myFoundActionsTree->updateItems(myActionSearcher.getSearchResults());
+}
+
+
+
+SUIT_FoundActionTree::SUIT_FoundActionTree(SUIT_FindActionDialog* theParent)
+: QTreeWidget(theParent)
+{
+  setColumnCount(2);
+  setSelectionMode(QAbstractItemView::SingleSelection);
+  setSortingEnabled(false); // Items are sorted in the same way, as in ShortcutContainer.
+  header()->setSectionResizeMode(QHeaderView::Interactive);
+  {
+    QMap<int, QString> labelMap;
+    labelMap[SUIT_FoundActionTree::ElementIdx::Name]    = SUIT_FindActionDialog::tr("Action");
+    labelMap[SUIT_FoundActionTree::ElementIdx::ToolTip] = SUIT_FindActionDialog::tr("Description");
+    setHeaderLabels(labelMap.values());
+  }
+  setExpandsOnDoubleClick(false); // Open shortcut editor on double click instead.
+  setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
+  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+  setColumnWidth(SUIT_FoundActionTree::ElementIdx::Name, 120);
+  setColumnWidth(SUIT_FoundActionTree::ElementIdx::Name, 250);
+  setMinimumHeight(300);
+
+  setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
+
+  connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(onItemDoubleClicked(QTreeWidgetItem*, int)));
+}
+
+void SUIT_FoundActionTree::updateItems(const std::map<QString, std::map<QString, SUIT_ActionSearcher::AssetsAndSearchData>>& theAssets)
+{
+  clear();
+
+  const auto shortcutMgr = SUIT_ShortcutMgr::get();
+  const QString lang = SUIT_ShortcutMgr::getLang();
+
+  for (const auto& moduleIDAndAssets : theAssets) {
+    const QString& moduleID = moduleIDAndAssets.first;
+    const auto& moduleAssets = moduleIDAndAssets.second;
+    if (moduleAssets.empty())
+      continue;
+
+    const auto moduleItem = new SUIT_FoundActionTreeFolder(moduleID);
+    moduleItem->setAssets(shortcutMgr->getModuleAssets(moduleID), lang);
+    addTopLevelItem(moduleItem);
+    moduleItem->setFlags(Qt::ItemIsEnabled);
+    for (const auto& actionIDAndAssets : moduleAssets) {
+      const QString& inModuleActionID = actionIDAndAssets.first;
+      const SUIT_ActionSearcher::AssetsAndSearchData& assetsAndSearchData = actionIDAndAssets.second;
+
+      auto actionItem = SUIT_FoundActionTreeAction::create(moduleID, inModuleActionID);
+      if (!actionItem) {
+        ShCutDbg("SUIT_FoundActionTree can't create child item for action ID = \"" + SUIT_ShortcutMgr::makeActionID(moduleID, inModuleActionID) + "\".");
+        continue;
+      }
+
+      actionItem->setAssets(assetsAndSearchData.myAssets, lang);
+      moduleItem->addChild(actionItem);
+    }
+    moduleItem->setExpanded(true); // Make tree expanded on first show.
+  }
+}
+
+std::pair<SUIT_FoundActionTreeFolder*, int> SUIT_FoundActionTree::findModuleFolderItem(const QString& theModuleID) const
+{
+  for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); moduleIdx++) {
+    SUIT_FoundActionTreeFolder* moduleItem = static_cast<SUIT_FoundActionTreeFolder*>(topLevelItem(moduleIdx));
+    if (moduleItem->myModuleID == theModuleID)
+      return std::pair<SUIT_FoundActionTreeFolder*, int>(moduleItem, moduleIdx);
+  }
+  return std::pair<SUIT_FoundActionTreeFolder*, int>(nullptr, -1);
+}
+
+void SUIT_FoundActionTree::onItemDoubleClicked(QTreeWidgetItem* theItem, int theColIdx)
+{
+  {
+    SUIT_FoundActionTreeItem* const item = static_cast<SUIT_FoundActionTreeItem*>(theItem);
+    // Do not react if folder-item is clicked.
+    if (item->type() != SUIT_FoundActionTreeItem::Type::Action)
+      return;
+  }
+
+  SUIT_FoundActionTreeAction* const actionItem = static_cast<SUIT_FoundActionTreeAction*>(theItem);
+  if (actionItem->trigger())
+    static_cast<SUIT_FindActionDialog*>(parentWidget())->accept();
+}
+
+
+SUIT_FoundActionTreeItem::SUIT_FoundActionTreeItem(const QString& theModuleID)
+: QTreeWidgetItem(), myModuleID(theModuleID)
+{ }
+
+QString SUIT_FoundActionTreeItem::name() const
+{
+  return text(SUIT_FoundActionTree::ElementIdx::Name);
+}
+
+QString SUIT_FoundActionTreeItem::toolTip() const
+{
+  return text(SUIT_FoundActionTree::ElementIdx::ToolTip);
+}
+
+
+SUIT_FoundActionTreeFolder::SUIT_FoundActionTreeFolder(const QString& theModuleID)
+: SUIT_FoundActionTreeItem(theModuleID)
+{
+  QFont f = font(SUIT_FoundActionTree::ElementIdx::Name);
+  f.setBold(true);
+  setFont(SUIT_FoundActionTree::ElementIdx::Name, f);
+  setText(SUIT_FoundActionTree::ElementIdx::Name, theModuleID);
+}
+
+void SUIT_FoundActionTreeFolder::setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang)
+{
+  if (!theAssets)
+    return;
+
+  setIcon(SUIT_FoundActionTree::ElementIdx::Name, theAssets->myIcon);
+
+  const auto& ldaMap = theAssets->myLangDependentAssets;
+  if (ldaMap.empty()) {
+    setText(SUIT_FoundActionTree::ElementIdx::Name, myModuleID);
+    return;
+  }
+
+  auto itLDA = ldaMap.find(theLang);
+  if (itLDA == ldaMap.end())
+    itLDA = ldaMap.begin();
+
+  const SUIT_ActionAssets::LangDependentAssets& lda = itLDA->second;
+  const QString& name = lda.myName.isEmpty() ? myModuleID : lda.myName;
+  setText(SUIT_FoundActionTree::ElementIdx::Name, name);
+}
+
+QString SUIT_FoundActionTreeFolder::getValue(SUIT_FoundActionTree::SortKey theKey) const
+{
+  switch (theKey) {
+    case SUIT_FoundActionTree::SortKey::ID:
+      return myModuleID;
+    case SUIT_FoundActionTree::SortKey::Name:
+      return name();
+    case SUIT_FoundActionTree::SortKey::ToolTip:
+      return toolTip();
+    default:
+      return QString();
+  }
+}
+
+bool SUIT_FoundActionTreeFolder::isEnabled() const
+{
+  return true;
+}
+
+
+SUIT_FoundActionTreeAction::SUIT_FoundActionTreeAction(const QString& theModuleID, const QString& theInModuleActionID)
+: SUIT_FoundActionTreeItem(theModuleID), myInModuleActionID(theInModuleActionID)
+{
+  setText(SUIT_FoundActionTree::ElementIdx::Name, theInModuleActionID);
+}
+
+/*static*/ SUIT_FoundActionTreeAction* SUIT_FoundActionTreeAction::create(const QString& theModuleID, const QString& theInModuleActionID)
+{
+  if (theInModuleActionID.isEmpty()) {
+    ShCutDbg("SUIT_FoundActionTreeItem: attempt to create item with empty action ID.");
+    return nullptr;
+  }
+
+  return new SUIT_FoundActionTreeAction(theModuleID, theInModuleActionID);
+}
+
+void SUIT_FoundActionTreeAction::setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang)
+{
+  if (!theAssets)
+    return;
+
+  setIcon(SUIT_FoundActionTree::ElementIdx::Name, theAssets->myIcon);
+
+  const auto& ldaMap = theAssets->myLangDependentAssets;
+  if (ldaMap.empty()) {
+    setText(SUIT_FoundActionTree::ElementIdx::Name, myInModuleActionID);
+    return;
+  }
+
+  auto itLDA = ldaMap.find(theLang);
+  if (itLDA == ldaMap.end())
+    itLDA = ldaMap.begin();
+
+  const SUIT_ActionAssets::LangDependentAssets& lda = itLDA->second;
+  const QString& name = lda.myName.isEmpty() ? myInModuleActionID : lda.myName;
+  setText(SUIT_FoundActionTree::ElementIdx::Name, name);
+
+  setText(SUIT_FoundActionTree::ElementIdx::ToolTip, lda.myToolTip);
+
+  if (isEnabled()) {
+    setToolTip(
+      SUIT_FoundActionTree::ElementIdx::Name,
+      SUIT_FoundActionTree::tr("Double click to start")
+    );
+
+    setToolTip(
+      SUIT_FoundActionTree::ElementIdx::ToolTip,
+      SUIT_FoundActionTree::tr("Double click to start")
+    );
+  }
+  else {
+    static const QBrush greyedOutBrush = QBrush(Qt::gray);
+    setForeground(SUIT_FoundActionTree::ElementIdx::Name,    greyedOutBrush);
+    setForeground(SUIT_FoundActionTree::ElementIdx::ToolTip, greyedOutBrush);
+  }
+}
+
+QString SUIT_FoundActionTreeAction::getValue(SUIT_FoundActionTree::SortKey theKey) const
+{
+  switch (theKey) {
+    case SUIT_FoundActionTree::SortKey::ID:
+      return myInModuleActionID;
+    case SUIT_FoundActionTree::SortKey::Name:
+      return name();
+    case SUIT_FoundActionTree::SortKey::ToolTip:
+      return toolTip();
+    default:
+      return QString();
+  }
+}
+
+bool SUIT_FoundActionTreeAction::isEnabled() const
+{
+  const auto& actions = SUIT_ShortcutMgr::get()->getActions(myModuleID, myInModuleActionID);
+  return std::find_if(actions.begin(), actions.end(), [](const QAction* const theAction){ return theAction->isEnabled(); }) != actions.end();
+}
+
+bool SUIT_FoundActionTreeAction::trigger() const
+{
+  bool res = false;
+  const auto& actions = SUIT_ShortcutMgr::get()->getActions(myModuleID, myInModuleActionID);
+  for (const auto& action : actions) {
+    if (action->isEnabled()) {
+      action->trigger();
+      res = true;
+    }
+  }
+  return res;
+}
\ No newline at end of file
diff --git a/src/SUIT/SUIT_FindActionDialog.h b/src/SUIT/SUIT_FindActionDialog.h
new file mode 100644 (file)
index 0000000..1682721
--- /dev/null
@@ -0,0 +1,174 @@
+// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef SUIT_FINDACTIONDIALOG_H
+#define SUIT_FINDACTIONDIALOG_H
+
+#include "SUIT.h"
+#include <QDialog>
+#include <QFrame>
+#include <QTreeWidget>
+#include "SUIT_ShortcutMgr.h"
+#include <memory>
+#include <map>
+#include <set>
+#include <functional>
+
+
+class QCheckBox;
+class QLineEdit;
+class QLabel;
+class QPushButton;
+class SUIT_FoundActionTree;
+
+
+class SUIT_EXPORT SUIT_FindActionDialog : public QDialog
+{
+  Q_OBJECT
+
+public:
+  SUIT_FindActionDialog(QWidget* theParent);
+  SUIT_FindActionDialog(const SUIT_FindActionDialog&) = delete;
+  SUIT_FindActionDialog& operator=(const SUIT_FindActionDialog&) = delete;
+  virtual ~SUIT_FindActionDialog() = default;
+
+  void setActiveModuleID(const QString& theModuleID = SUIT_ShortcutMgr::ROOT_MODULE_ID);
+
+private slots:
+  void onQueryChanged(const QString& theKeyword);
+  void onSearchOptionUnavailableActionsChanged(int);
+  void onSearchOptionInactiveModulesChanged(int);
+
+private:
+  void updateUI();
+
+  QLineEdit* myQueryLineEdit;
+  QCheckBox* myIncludeUnavailableActionsCB;
+  QCheckBox* myIncludeInactiveModulesCB;
+  SUIT_FoundActionTree* myFoundActionsTree;
+
+  QString myActiveModuleID;
+  SUIT_ActionSearcher myActionSearcher;
+};
+
+
+class SUIT_FoundActionTreeItem;
+class SUIT_FoundActionTreeFolder;
+class SUIT_FoundActionTreeAction;
+
+
+class SUIT_EXPORT SUIT_FoundActionTree : public QTreeWidget
+{
+  Q_OBJECT
+
+public:
+  enum ElementIdx {
+    Name = 0,
+    ToolTip = 1
+  };
+
+  enum class SortKey {
+    ID,
+    Name,
+    ToolTip
+  };
+
+  SUIT_FoundActionTree(SUIT_FindActionDialog* theParent);
+  SUIT_FoundActionTree(const SUIT_FoundActionTree&) = delete;
+  SUIT_FoundActionTree& operator=(const SUIT_FoundActionTree&) = delete;
+  virtual ~SUIT_FoundActionTree() = default;
+
+  void updateItems(const std::map<QString, std::map<QString, SUIT_ActionSearcher::AssetsAndSearchData>>& theAssets);
+
+private:
+  std::pair<SUIT_FoundActionTreeFolder*, int> findModuleFolderItem(const QString& theModuleID) const;
+
+private slots:
+  void onItemDoubleClicked(QTreeWidgetItem* theWidgetItem, int theColIdx);
+};
+
+
+class SUIT_FoundActionTreeItem : public QTreeWidgetItem
+{
+public:
+  enum Type {
+    Folder = 0,
+    Action = 1,
+  };
+
+protected:
+  SUIT_FoundActionTreeItem(const QString& theModuleID);
+
+public:
+  virtual ~SUIT_FoundActionTreeItem() = default;
+  virtual SUIT_FoundActionTreeItem::Type type() const = 0;
+
+  virtual void setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang) = 0;
+  QString name() const;
+  QString toolTip() const;
+
+  virtual QString getValue(SUIT_FoundActionTree::SortKey theKey) const = 0;
+
+  virtual bool isEnabled() const = 0;
+
+public:
+  const QString myModuleID;
+};
+
+
+class SUIT_FoundActionTreeFolder : public SUIT_FoundActionTreeItem
+{
+public:
+  SUIT_FoundActionTreeFolder(const QString& theModuleID);
+  virtual ~SUIT_FoundActionTreeFolder() = default;
+  virtual SUIT_FoundActionTreeItem::Type type() const { return SUIT_FoundActionTreeItem::Type::Folder; };
+
+  virtual void setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang);
+
+  virtual QString getValue(SUIT_FoundActionTree::SortKey theKey) const;
+
+  virtual bool isEnabled() const;
+};
+
+
+class SUIT_FoundActionTreeAction : public SUIT_FoundActionTreeItem
+{
+private:
+  SUIT_FoundActionTreeAction(const QString& theModuleID, const QString& theInModuleActionID);
+
+public:
+  static SUIT_FoundActionTreeAction* create(const QString& theModuleID, const QString& theInModuleActionID);
+  virtual ~SUIT_FoundActionTreeAction() = default;
+  virtual SUIT_FoundActionTreeItem::Type type() const { return SUIT_FoundActionTreeItem::Type::Action; };
+
+  virtual void setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang);
+
+  virtual QString getValue(SUIT_FoundActionTree::SortKey theKey) const;
+
+  virtual bool isEnabled() const;
+
+  bool trigger() const;
+
+  const QString myInModuleActionID;
+};
+
+#endif // SUIT_FINDACTIONDIALOG_H
diff --git a/src/SUIT/SUIT_PagePrefShortcutTreeItem.cxx b/src/SUIT/SUIT_PagePrefShortcutTreeItem.cxx
new file mode 100644 (file)
index 0000000..d05d511
--- /dev/null
@@ -0,0 +1,65 @@
+#include "SUIT_PagePrefShortcutTreeItem.h"
+
+#include "SUIT_ShortcutTree.h"
+#include "SUIT_ShortcutMgr.h"
+
+
+/*!
+  \brief Creates preference item for editing of key bindings
+  \param theParent parent preference item. Must not be nullptr.
+*/
+SUIT_PagePrefShortcutTreeItem::SUIT_PagePrefShortcutTreeItem(QtxPreferenceItem* theParent)
+ : QtxPagePrefItem(QString(), theParent)
+{
+  auto container = std::shared_ptr<SUIT_ShortcutContainer>();
+  const auto itContainers = SUIT_PagePrefShortcutTreeItem::shortcutContainers.find(rootItem());
+  if (itContainers == SUIT_PagePrefShortcutTreeItem::shortcutContainers.end()) {
+    container.reset(new SUIT_ShortcutContainer());
+    SUIT_PagePrefShortcutTreeItem::shortcutContainers.emplace(rootItem(), container);
+  }
+  else {
+    container = itContainers->second.lock();
+    if (!container) {
+      container.reset(new SUIT_ShortcutContainer());
+      itContainers->second = container;
+    }
+  }
+
+  SUIT_ShortcutTree* tree = new SUIT_ShortcutTree(container);
+  tree->myModuleIDs = SUIT_ShortcutMgr::get()->getShortcutModuleIDs();
+  setWidget(tree);
+}
+
+/*!
+  \brief Retrieves shortcut preferences from ShortcutMgr.
+  Updates UI of controlling widget.
+  \sa store()
+*/
+void SUIT_PagePrefShortcutTreeItem::retrieve()
+{
+  static_cast<SUIT_ShortcutTree*>(widget())->setShortcutsFromManager();
+}
+
+/*!
+  \brief Retrieves shortcut preferences from resource files, ignoring user preferences.
+  Updates UI of controlling widget.
+  \sa store()
+*/
+void SUIT_PagePrefShortcutTreeItem::retrieveDefault()
+{
+  static_cast<SUIT_ShortcutTree*>(widget())->setDefaultShortcuts();
+}
+
+/*!
+  \brief Applies modified shortcut preferences to ShortcutMgr.
+  Updates UI of controlling widget.
+  And ShortcutMgr, in turn, serilizes shortcut preferences using the resource manager.
+  \sa retrieve()
+*/
+void SUIT_PagePrefShortcutTreeItem::store()
+{
+  static_cast<SUIT_ShortcutTree*>(widget())->applyChangesToShortcutMgr();
+}
+
+/*static*/ std::map<QtxPreferenceItem*, std::weak_ptr<SUIT_ShortcutContainer>> SUIT_PagePrefShortcutTreeItem::shortcutContainers =
+std::map<QtxPreferenceItem*, std::weak_ptr<SUIT_ShortcutContainer>>();
\ No newline at end of file
diff --git a/src/SUIT/SUIT_PagePrefShortcutTreeItem.h b/src/SUIT/SUIT_PagePrefShortcutTreeItem.h
new file mode 100644 (file)
index 0000000..653a1e0
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef SUIT_PAGEPREFSHORTCUTTREEITEM_H
+#define SUIT_PAGEPREFSHORTCUTTREEITEM_H
+
+#include "SUIT.h"
+#include <QtxPagePrefMgr.h>
+
+#include <map>
+#include <memory>
+
+
+class SUIT_ShortcutTree;
+class SUIT_ShortcutContainer;
+
+
+class SUIT_EXPORT SUIT_PagePrefShortcutTreeItem : public QtxPagePrefItem
+{
+public:
+  SUIT_PagePrefShortcutTreeItem(QtxPreferenceItem* theParent);
+  virtual ~SUIT_PagePrefShortcutTreeItem() = default;
+
+  virtual void     retrieve();
+  virtual void     retrieveDefault();
+  virtual void     store();
+
+private:
+  SUIT_ShortcutTree* myShortcutTree;
+
+  // { root item (preference window), shortcut container of synchronized trees (widgets within the same window) }
+  static std::map<QtxPreferenceItem*, std::weak_ptr<SUIT_ShortcutContainer>> shortcutContainers;
+  /** Why is this?
+   * Every QtxPagePrefMgr is eventually a preference window. Each preference window has button "Apply".
+   * When the button is pressed, all descendants of the QtxPagePrefMgr store changes they carry into preferences.
+   * The pitfall with shortcut trees is as follows: made in independent shortcut trees, changes may conflict,
+   * and merge of such changes is ambiguous. And the solution is to keep shortcut trees within the same window
+   * synchronized - all changes being made in a tree of a synchronized bundle are projected to other trees from the bundle
+   * without interacting with SUIT_ShortcutMgr.
+   *
+   * Every time shortcut preferences stored to the ShortcutMgr, all instances of SUIT_ShortcutTree are updated.
+  */
+};
+
+#endif // SUIT_PAGEPREFSHORTCUTTREEITEM_H
\ No newline at end of file
index a45449d3674e9b94a8c6278a82659d030fca106f..f78b70952135ec631fd9624a9b45358c9fc6220b 100644 (file)
@@ -21,6 +21,7 @@
 // Author:    Sergey TELKOV
 //
 #include "SUIT_PreferenceMgr.h"
+#include "SUIT_PagePrefShortcutTreeItem.h"
 
 SUIT_PreferenceMgr::SUIT_PreferenceMgr( QtxResourceMgr* resMgr, QWidget* parent )
 : QtxPagePrefMgr( resMgr, parent ),
@@ -155,7 +156,7 @@ int SUIT_PreferenceMgr::addItem( const QString& title, const int pId,
     item = new QtxPagePrefPathListItem( Qtx::PT_Directory, title, parent, sect, param );
     break;
   case ShortcutTree:
-    item = new QtxPagePrefShortcutTreeItem( parent );
+    item = new SUIT_PagePrefShortcutTreeItem( parent );
     break;
   case BiColor:
     item = new QtxPagePrefBiColorItem( title, parent, sect, param );
index d0cc5adc8c796e0685f9f80d6633a012be80c753..9ce349bf04f3c73d0252a5c4fb8419b848f8726f 100644 (file)
@@ -2,11 +2,11 @@
 
 Hot keys must be considered as resources, being shared between all components of an application. E.g. it is unacceptable to have 'Close file' and 'Redo' actions being assigned to the same key sequence. When the SHAPER module is active, the application desktop is active too. The desktop has own hot keys, and they must not interfere with ones of SHAPER. Since the task implies granting users a right to assign shortcuts on their will, the application must track all assigned shortcuts of all modules, prevent intolerable user shortcut modifications and govern actual binding of QActions with key sequences.
 
-`SUIT_ShortcutMgr` handles shortcuts of SALOME desktop and all modules. It is solely responsible and capable to dynamically bind actions with key sequences and (de)serialize shortcut preferences using `SUIT_ResourceMgr`. `SUIT_ShortcutContainer` encapsulates logics of conflict detecting and resolving. `QtxShortcutTree` widget provides GUI to change shortcut preferences conveniently: it allows to remap plenty of shortcuts without applying, displays conflict-resolving dialog, highlights modifications until they are applied (saved into preference files).
+`SUIT_ShortcutMgr` handles shortcuts of SALOME desktop and all modules. It is solely responsible and capable to dynamically bind actions with key sequences and (de)serialize shortcut preferences using `SUIT_ResourceMgr`. `SUIT_ShortcutContainer` encapsulates logics of conflict detecting and resolving. `SUIT_ShortcutTree` widget provides GUI to change shortcut preferences conveniently: it allows to remap plenty of shortcuts without applying, displays conflict-resolving dialog, highlights modifications until they are applied (saved into preference files).
 
 To (de)serialize shortcut preferences without dependence on language environment, shortcuts must be stored as pairs {action ID, key sequence}, where action IDs must be application-unique.
 
-Since desktop shortcuts may also be changed and interfere with shortcuts of modules, `QtxShortcutTree` should always display desktop shortcuts and shortcuts of all modules altogether, even if some modules are inactive. It means, that `QtxShortcutTree` must be fed not only with shortcut data {action ID, key sequence}[], but also with dictionaries {action ID, action name}[]. `QtxShortcutTree` also requires other action assets - tool tip and icon path.
+Since desktop shortcuts may also be changed and interfere with shortcuts of modules, `SUIT_ShortcutTree` should always display desktop shortcuts and shortcuts of all modules altogether, even if some modules are inactive. It means, that `SUIT_ShortcutTree` must be fed not only with shortcut data {action ID, key sequence}[], but also with dictionaries {action ID, action name}[]. `SUIT_ShortcutTree` also requires other action assets - tool tip and icon path.
 
 Assets of actions may be retrieved from instances of actions, but there is a pitfall: if a module has not been activated yet, its actions have not been initialized either.
 Qt Linguist is no help in this case too. To retrieve an action name using `QObject::tr(actionID)`, the `tr(const char*)` method must be called with instance of the class, which is designated as a context for the actionID in *.ts files. And contexts are usually descendants of SUIT_Application and CAM_Module. Again, until a module instance is created, there is no way for `SUIT_ShortcutMgr` to get even a name of a context-class, which an action with an ID belongs to, without any additional data. Straightforward mechanism for loading of action assets in advance has been devised: for all actions, which are bound by default or may be bound by user to hotkeys, assets must be placed into asset files. People who do/refine localizations should keep this in mind and also process JSON files, which are referred in resource files in sections `<section name="action_assets">`.
@@ -77,6 +77,6 @@ Thus, ampersand-shortcuts will appear and be treated in shortcut editor as regul
 If the second option is preferable, should different ampersand-shortcuts for every target language be placed in resource files?
 
 ## Minor issues
-1. `QtxShortcutTree` widget does not take the whole available height of preference window, it only takes as mush as its items require.
-2. Selection of `QtxShortcutTree`' item shadows "modified" highlighter. Can be fixed by replacing base `QTreeWidget` of `QtxShortcutTree` with `QTreeView`, or may be by applying some style sheet.
+1. `SUIT_ShortcutTree` widget does not take the whole available height of preference window, it only takes as mush as its items require.
+2. Selection of `SUIT_ShortcutTree`' item shadows "modified" highlighter. Can be fixed by replacing base `QTreeWidget` of `SUIT_ShortcutTree` with `QTreeView`, or may be by applying some style sheet.
 3. `SUIT_ShortcutMgr` introduces concept of module, but the first module class is `CAM_Module` is introduced along with `CAM_Application`, which is descendant of `SUIT_Application`.
diff --git a/src/SUIT/SUIT_ShortcutTree.cxx b/src/SUIT/SUIT_ShortcutTree.cxx
new file mode 100644 (file)
index 0000000..d6ae071
--- /dev/null
@@ -0,0 +1,883 @@
+// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "SUIT_ShortcutTree.h"
+
+#include <QWidget>
+#include <QLayout>
+#include <QList>
+#include <QMap>
+
+#include <QToolButton>
+#include <QLineEdit>
+#include <QLabel>
+#include <QTableWidgetItem>
+#include <QTextEdit>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QBrush>
+#include <QColor>
+#include <QHeaderView>
+
+#include <QKeyEvent>
+#include <QKeySequence>
+#include <QCollator>
+
+#include <algorithm>
+
+
+#define COLUMN_SIZE  500
+
+
+SUIT_KeySequenceEdit::SUIT_KeySequenceEdit(QWidget* parent)
+: QFrame(parent)
+{
+  initialize();
+  myKeySequenceLineEdit->installEventFilter(this);
+}
+
+/*! \brief Set a key sequence to edit. */
+void SUIT_KeySequenceEdit::setConfirmedKeySequence(const QKeySequence& theKeySequence)
+{
+  myConfirmedKeySequenceString = theKeySequence.toString();
+  myKeySequenceLineEdit->setText(myConfirmedKeySequenceString);
+  myPrevKeySequenceString = myConfirmedKeySequenceString;
+}
+
+void SUIT_KeySequenceEdit::setEditedKeySequence(const QKeySequence& theKeySequence)
+{
+  const QString keySequenceString = theKeySequence.toString();
+  myKeySequenceLineEdit->setText(keySequenceString);
+  myPrevKeySequenceString = keySequenceString;
+}
+
+QKeySequence SUIT_KeySequenceEdit::editedKeySequence() const
+{
+  return QKeySequence::fromString(myKeySequenceLineEdit->text());
+}
+
+/*! \returns true, if the edited key sequence differs from confirmed one. */
+bool SUIT_KeySequenceEdit::isKeySequenceModified() const
+{
+  return QKeySequence(myConfirmedKeySequenceString) != editedKeySequence();
+}
+
+/*! \brief Set confirmed key sequence to line editor. */
+void SUIT_KeySequenceEdit::restoreKeySequence()
+{
+  myKeySequenceLineEdit->setText(myConfirmedKeySequenceString);
+  myPrevKeySequenceString = myConfirmedKeySequenceString;
+}
+
+/*!
+  \brief Gets the key sequence from keys that were pressed
+  \param e a key event
+  \returns a string representation of the key sequence
+*/
+/*static*/ QString SUIT_KeySequenceEdit::parseEvent(QKeyEvent* e)
+{
+  bool isShiftPressed = e->modifiers() & Qt::ShiftModifier;
+  bool isControlPressed = e->modifiers() & Qt::ControlModifier;
+  bool isAltPressed = e->modifiers() & Qt::AltModifier;
+  bool isMetaPressed = e->modifiers() & Qt::MetaModifier;
+  bool isModifiersPressed = isControlPressed || isAltPressed || isMetaPressed; // Do not treat Shift alone as a modifier!
+  int result=0;
+  if(isControlPressed)
+    result += Qt::CTRL;
+  if(isAltPressed)
+    result += Qt::ALT;
+  if(isShiftPressed)
+    result += Qt::SHIFT;
+  if(isMetaPressed)
+    result += Qt::META;
+
+  int aKey = e->key();
+  if ((isValidKey(aKey) && isModifiersPressed) || ((aKey >= Qt::Key_F1) && (aKey <= Qt::Key_F12)))
+    result += aKey;
+
+  return QKeySequence(result).toString();
+}
+
+/*!
+  \brief Check if the key event contains a 'valid' key
+  \param theKey the code of the key
+  \returns \c true if the key is 'valid'
+*/
+/*static*/ bool SUIT_KeySequenceEdit::isValidKey(int theKey)
+{
+  if ( theKey == Qt::Key_Underscore || theKey == Qt::Key_Escape ||
+     ( theKey >= Qt::Key_Backspace && theKey <= Qt::Key_Delete ) ||
+     ( theKey >= Qt::Key_Home && theKey <= Qt::Key_PageDown ) ||
+     ( theKey >= Qt::Key_F1 && theKey <= Qt::Key_F12 )  ||
+     ( theKey >= Qt::Key_Space && theKey <= Qt::Key_Asterisk ) ||
+     ( theKey >= Qt::Key_Comma && theKey <= Qt::Key_Question ) ||
+     ( theKey >= Qt::Key_A && theKey <= Qt::Key_AsciiTilde ) )
+    return true;
+  return false;
+}
+
+/*! \brief Called when "Clear" button is clicked. */
+void SUIT_KeySequenceEdit::onClear()
+{
+  myKeySequenceLineEdit->setText("");
+  myPrevKeySequenceString = "";
+  emit editingFinished();
+}
+
+/*! \brief Called when myKeySequenceLineEdit loses focus. */
+void SUIT_KeySequenceEdit::onEditingFinished()
+{
+  if (myKeySequenceLineEdit->text().endsWith("+"))
+    myKeySequenceLineEdit->setText(myPrevKeySequenceString);
+  else
+    myPrevKeySequenceString = myKeySequenceLineEdit->text();
+    emit editingFinished();
+}
+
+/*!
+  \brief Custom event filter.
+  \param obj event receiver object
+  \param event event
+  \returns \c true if further event processing should be stopped
+*/
+bool SUIT_KeySequenceEdit::eventFilter(QObject* theObject, QEvent* theEvent)
+{
+  if (theObject == myKeySequenceLineEdit) {
+    if (theEvent->type() == QEvent::KeyPress) {
+      QKeyEvent* keyEvent = static_cast<QKeyEvent*>(theEvent);
+      QString text = parseEvent(keyEvent);
+      if (keyEvent->key() == Qt::Key_Delete || keyEvent->key() == Qt::Key_Backspace)
+        myKeySequenceLineEdit->setText("");
+      if (!text.isEmpty())
+        myKeySequenceLineEdit->setText(text);
+
+      emit editingStarted();
+      return true;
+    }
+    if (theEvent->type() == QEvent::KeyRelease) {
+      onEditingFinished();
+      return true;
+    }
+  }
+  return false;
+}
+
+/*
+  \brief Perform internal intialization.
+*/
+void SUIT_KeySequenceEdit::initialize()
+{
+  static const int PIXMAP_SIZE = 30;
+
+  QHBoxLayout* base = new QHBoxLayout( this );
+  base->setMargin(0);
+  base->setSpacing(5);
+
+  base->addWidget(myKeySequenceLineEdit = new QLineEdit(this));
+  setFocusProxy(myKeySequenceLineEdit);
+
+  QToolButton* clearBtn = new QToolButton();
+  auto clearPixmap = QPixmap(":/images/shortcut_disable.svg");
+  clearPixmap.scaled(QSize(PIXMAP_SIZE, PIXMAP_SIZE), Qt::KeepAspectRatio, Qt::SmoothTransformation);
+  clearBtn->setIcon(clearPixmap);
+  clearBtn->setToolTip(tr("Disable shortcut."));
+  base->addWidget(clearBtn);
+
+  QToolButton* restoreBtn = new QToolButton();
+  auto restorePixmap = QPixmap(":/images/shortcut_restore.svg");
+  restorePixmap.scaled(QSize(PIXMAP_SIZE, PIXMAP_SIZE), Qt::KeepAspectRatio, Qt::SmoothTransformation);
+  restoreBtn->setIcon(restorePixmap);
+  restoreBtn->setToolTip(tr("Restore the currently applied key sequence."));
+  base->addWidget(restoreBtn);
+
+  myKeySequenceLineEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+  clearBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+  restoreBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+  connect(clearBtn, SIGNAL(clicked()), this, SLOT(onClear()));
+  connect(restoreBtn, SIGNAL(clicked()), this, SIGNAL(restoreFromShortcutMgrClicked()));
+  connect(myKeySequenceLineEdit, SIGNAL(editingFinished()), this, SLOT(onEditingFinished()));
+}
+
+
+/*! \param theParent must not be nullptr. */
+SUIT_EditKeySequenceDialog::SUIT_EditKeySequenceDialog(SUIT_ShortcutTree* theParent)
+: QDialog(theParent)
+{
+  setMinimumWidth(500);
+  setWindowTitle(tr("Change key sequence"));
+  QVBoxLayout* layout = new QVBoxLayout(this);
+  myActionName = new QLabel(this);
+  myActionName->setTextFormat(Qt::RichText);
+  myKeySequenceEdit = new SUIT_KeySequenceEdit(this);
+  myTextEdit = new QTextEdit(this);
+  layout->addWidget(myActionName);
+  layout->addWidget(myKeySequenceEdit);
+  layout->addWidget(myTextEdit);
+  myActionName->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+  myKeySequenceEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+  myTextEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+  myTextEdit->setReadOnly(true);
+  myTextEdit->setAcceptRichText(true);
+  myTextEdit->setPlaceholderText(tr("No conflicts."));
+  setFocusProxy(myKeySequenceEdit);
+
+  QHBoxLayout* buttonLayout = new QHBoxLayout(this);
+  layout->addLayout(buttonLayout);
+  QPushButton* confirmButton = new QPushButton(tr("Confirm"), this);
+  confirmButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+  QPushButton* cancelButton = new QPushButton(tr("Cancel"), this);
+  cancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+  buttonLayout->addStretch();
+  buttonLayout->addWidget(confirmButton);
+  buttonLayout->addWidget(cancelButton);
+
+  connect(myKeySequenceEdit, SIGNAL(editingStarted()), this, SLOT(onEditingStarted()));
+  connect(myKeySequenceEdit, SIGNAL(editingFinished()), this, SLOT(onEditingFinished()));
+  connect(myKeySequenceEdit, SIGNAL(restoreFromShortcutMgrClicked()), this, SLOT(onRestoreFromShortcutMgr()));
+  connect(confirmButton, SIGNAL(clicked()), this, SLOT(onConfirm()));
+  connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+}
+
+void SUIT_EditKeySequenceDialog::setModuleAndActionID(const QString& theModuleID, const QString& theInModuleActionID)
+{
+  myModuleID = theModuleID;
+  myInModuleActionID = theInModuleActionID;
+}
+
+const QString& SUIT_EditKeySequenceDialog::moduleID() const { return myModuleID; }
+const QString& SUIT_EditKeySequenceDialog::inModuleActionID() const { return myInModuleActionID; }
+
+void SUIT_EditKeySequenceDialog::setModuleAndActionName(const QString& theModuleName, const QString& theActionName, const QString& theActionToolTip)
+{
+  myActionName->setText("<b>" + theModuleName + "</b>&nbsp;&nbsp;" + theActionName);
+  myActionName->setToolTip(theActionToolTip);
+}
+
+void SUIT_EditKeySequenceDialog::setConfirmedKeySequence(const QKeySequence& theSequence)
+{
+  myKeySequenceEdit->setConfirmedKeySequence(theSequence);
+}
+
+QKeySequence SUIT_EditKeySequenceDialog::editedKeySequence() const
+{
+  return myKeySequenceEdit->editedKeySequence();
+}
+
+int SUIT_EditKeySequenceDialog::exec()
+{
+  myKeySequenceEdit->setFocus(Qt::ActiveWindowFocusReason);
+  return QDialog::exec();
+}
+
+void SUIT_EditKeySequenceDialog::onEditingStarted()
+{
+  myTextEdit->setEnabled(false);
+}
+
+void SUIT_EditKeySequenceDialog::onEditingFinished()
+{
+  updateConflictsMessage();
+}
+
+void SUIT_EditKeySequenceDialog::onRestoreFromShortcutMgr()
+{
+  const auto shortcutMgr = SUIT_ShortcutMgr::get();
+  myKeySequenceEdit->setEditedKeySequence(shortcutMgr->getKeySequence(myModuleID, myInModuleActionID));
+  updateConflictsMessage();
+}
+
+/*! Updates message with list of actions, whose shortcuts will be disabled on Confirm. */
+void SUIT_EditKeySequenceDialog::updateConflictsMessage()
+{
+  myTextEdit->setEnabled(true);
+  QTextDocument* doc = myTextEdit->document();
+  if (!doc) {
+    doc = new QTextDocument(myTextEdit);
+    myTextEdit->setDocument(doc);
+  }
+
+  if (!myKeySequenceEdit->isKeySequenceModified()) {
+    doc->clear();
+    return;
+  }
+
+  const QKeySequence newKeySequence = editedKeySequence();
+
+  const auto shortcutTree = static_cast<SUIT_ShortcutTree*>(parentWidget());
+  /** {moduleID, inModuleActionID}[] */
+  std::set<std::pair<QString, QString>> conflicts = shortcutTree->shortcutContainer()->getConflicts(myModuleID, myInModuleActionID, newKeySequence);
+  if (!conflicts.empty()) {
+    const auto shortcutMgr = SUIT_ShortcutMgr::get();
+
+    QString report = "<b>" + tr("These shortcuts will be disabled on confirm:") + "</b>";
+    {
+      report += "<ul>";
+      for (const auto& conflict : conflicts) {
+        const QString conflictingModuleName = shortcutMgr->getModuleName(conflict.first);
+        const QString conflictingActionName = shortcutMgr->getActionName(conflict.first, conflict.second);
+        report += "<li><b>" + conflictingModuleName + "</b>&nbsp;&nbsp;" + conflictingActionName + "</li>";
+      }
+      report += "</ul>";
+    }
+    doc->setHtml(report);
+  }
+  else /* if no conflicts */ {
+    doc->clear();
+  }
+}
+
+void SUIT_EditKeySequenceDialog::onConfirm()
+{
+  if (myKeySequenceEdit->isKeySequenceModified())
+    accept();
+  else
+    reject();
+}
+
+
+/*! \brief Compensates lack of std::distance(), which is introduced in C++17.
+\returns -1, if theIt does not belong to the  */
+template <class Container>
+size_t indexOf(
+  const Container& theContainer,
+  const typename Container::iterator& theIt
+) {
+  auto it = theContainer.begin();
+  size_t distance = 0;
+  while (it != theContainer.end()) {
+    if (it == theIt)
+      return distance;
+
+    it++;
+    distance++;
+  }
+  return -1;
+}
+
+
+/*! \param theContainer Share the same container between several trees,
+to edit them synchronously even without exchange of changes with SUIT_ShortcutMgr.
+Pass nullptr to create non-synchronized tree. */
+SUIT_ShortcutTree::SUIT_ShortcutTree(
+  std::shared_ptr<SUIT_ShortcutContainer> theContainer,
+  QWidget* theParent
+) : QTreeWidget(theParent),
+myShortcutContainer(theContainer ? theContainer : std::shared_ptr<SUIT_ShortcutContainer>(new SUIT_ShortcutContainer())),
+mySortKey(SUIT_ShortcutTree::SortKey::Name), mySortOrder(SUIT_ShortcutTree::SortOrder::Ascending)
+{
+  setColumnCount(2);
+  setSelectionMode(QAbstractItemView::SingleSelection);
+  setColumnWidth(0, COLUMN_SIZE);
+  setSortingEnabled(false); // Items are sorted in the same way, as in ShortcutContainer.
+  header()->setSectionResizeMode(QHeaderView::Interactive);
+  {
+    QMap<int, QString> labelMap;
+    labelMap[SUIT_ShortcutTree::ElementIdx::Name]        = tr("Action");
+    labelMap[SUIT_ShortcutTree::ElementIdx::KeySequence] = tr("Key sequence");
+    setHeaderLabels(labelMap.values());
+  }
+  setExpandsOnDoubleClick(false); // Open shortcut editor on double click instead.
+  setSortingEnabled(false);
+  setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
+  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+  myEditDialog = new SUIT_EditKeySequenceDialog(this);
+
+  this->installEventFilter(this);
+  connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(onItemDoubleClicked(QTreeWidgetItem*, int)));
+
+  SUIT_ShortcutTree::instances[myShortcutContainer.get()].emplace(this);
+}
+
+SUIT_ShortcutTree::~SUIT_ShortcutTree()
+{
+  SUIT_ShortcutTree::instances[myShortcutContainer.get()].erase(this);
+  if (SUIT_ShortcutTree::instances[myShortcutContainer.get()].empty())
+    SUIT_ShortcutTree::instances.erase(myShortcutContainer.get());
+}
+
+/*! \brief Copies shortcuts from ShortcutMgr. (Re)displays shortcuts of myModuleIDs. */
+void SUIT_ShortcutTree::setShortcutsFromManager()
+{
+  const auto shortcutMgr = SUIT_ShortcutMgr::get();
+  *myShortcutContainer = shortcutMgr->getShortcutContainer();
+  // nb! ShortcutMgr never removes shortcuts from its container, only disables.
+
+  updateItems(false /*theHighlightModified*/, true /*theUpdateSyncTrees*/);
+}
+
+/*! \brief Copies shortcuts from resources, user files are not accounted. (Re)displays shortcuts of myModuleIDs. */
+void SUIT_ShortcutTree::setDefaultShortcuts()
+{
+  SUIT_ShortcutContainer defaultShortcuts;
+  SUIT_ShortcutMgr::fillContainerFromPreferences(defaultShortcuts, true /*theDefaultOnly*/);
+
+  myShortcutContainer->merge(defaultShortcuts, true /*theOverride*/, true /*theTreatAbsentIncomingAsDisabled*/);
+  // nb! SUIT_ShortcutContainer never erases shortcuts, only disables.
+
+  updateItems(true /*theHighlightModified*/, true /*theUpdateSyncTrees*/);
+}
+
+/*! \brief Applies pending changes to ShortcutMgr. Updates other instances of SUIT_ShortcutTree. */
+void SUIT_ShortcutTree::applyChangesToShortcutMgr()
+{
+  const auto mgr = SUIT_ShortcutMgr::get();
+  mgr->mergeShortcutContainer(*myShortcutContainer);
+
+  // Update non-synchronized with this instances.
+  for (const auto& containerAndSyncTrees : SUIT_ShortcutTree::instances) {
+    if (containerAndSyncTrees.first == myShortcutContainer.get())
+      continue;
+
+    const std::set<SUIT_ShortcutTree*>& syncTrees = containerAndSyncTrees.second;
+    const auto itFirstSyncTree = syncTrees.begin();
+    if (itFirstSyncTree == syncTrees.end())
+      continue;
+
+    (*itFirstSyncTree)->setShortcutsFromManager();
+    const auto editDialog = (*itFirstSyncTree)->myEditDialog;
+    editDialog->setConfirmedKeySequence(mgr->getShortcutContainer().getKeySequence(editDialog->moduleID(), editDialog->inModuleActionID()));
+    editDialog->updateConflictsMessage();
+  }
+}
+
+std::shared_ptr<const SUIT_ShortcutContainer> SUIT_ShortcutTree::shortcutContainer() const
+{
+  return myShortcutContainer;
+}
+
+/*! \brief Does not sort modules. */
+void SUIT_ShortcutTree::sort(SUIT_ShortcutTree::SortKey theKey, SUIT_ShortcutTree::SortOrder theOrder)
+{
+  if (theKey == mySortKey && theOrder == mySortOrder)
+    return;
+
+  mySortKey == theKey;
+  mySortOrder = theOrder;
+
+  for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); moduleIdx++) {
+    const auto moduleItem = static_cast<SUIT_ShortcutTreeFolder*>(topLevelItem(moduleIdx));
+    const auto sortedChildren = getSortedChildren(moduleItem);
+    moduleItem->takeChildren();
+
+    for (const auto childItem : sortedChildren) {
+      moduleItem->addChild(childItem);
+    }
+  }
+}
+
+/*! \param If theUpdateSyncTrees, trees sharing the same shortcut container are updated. */
+void SUIT_ShortcutTree::updateItems(bool theHighlightModified, bool theUpdateSyncTrees)
+{
+  const auto shortcutMgr = SUIT_ShortcutMgr::get();
+  const QString lang = SUIT_ShortcutMgr::getLang();
+
+  for (const QString& moduleID : myModuleIDs) {
+    const auto& moduleShortcuts = myShortcutContainer->getModuleShortcutsInversed(moduleID);
+    if (moduleShortcuts.empty()) {
+      // Do not display empty module.
+      const auto moduleItemAndIdx = findModuleFolderItem(moduleID);
+      if (moduleItemAndIdx.second >= 0)
+        delete takeTopLevelItem(moduleItemAndIdx.second);
+
+      continue;
+    }
+
+    const auto moduleItemAndIdx = findModuleFolderItem(moduleID);
+    SUIT_ShortcutTreeFolder* moduleItem = moduleItemAndIdx.first;
+    if (!moduleItem) {
+      moduleItem = new SUIT_ShortcutTreeFolder(moduleID);
+      moduleItem->setAssets(shortcutMgr->getModuleAssets(moduleID), lang);
+      addTopLevelItem(moduleItem);
+      moduleItem->setFlags(Qt::ItemIsEnabled);
+
+      auto sortedChildren = getSortedChildren(moduleItem);
+      for (const auto& shortcut : moduleShortcuts) {
+        const QString& inModuleActionID = shortcut.first;
+        const QKeySequence& keySequence = shortcut.second;
+        const QString keySequenceString = keySequence.toString();
+
+        auto actionItem = SUIT_ShortcutTreeAction::create(moduleID, inModuleActionID);
+        if (!actionItem) {
+          ShCutDbg("SUIT_ShortcutTree can't create child item for action ID = \"" + SUIT_ShortcutMgr::makeActionID(moduleID, inModuleActionID) + "\".");
+          continue;
+        }
+
+        actionItem->setAssets(shortcutMgr->getActionAssets(moduleID, inModuleActionID), lang);
+        actionItem->setKeySequence(keySequenceString);
+
+        if (theHighlightModified) {
+          const QKeySequence& appliedKeySequence = SUIT_ShortcutMgr::get()->getKeySequence(moduleID, inModuleActionID);
+          actionItem->highlightKeySequenceAsModified(keySequence != appliedKeySequence);
+        }
+
+        insertChild(moduleItem, sortedChildren, actionItem);
+      }
+
+      moduleItem->setExpanded(true); // Make tree expanded on first show.
+    }
+    else /* if the tree has the module-item */ {
+      for (int childIdx = 0; childIdx < moduleItem->childCount(); childIdx++) {
+        // Update exisiting items of a module.
+        SUIT_ShortcutTreeAction* const childItem = static_cast<SUIT_ShortcutTreeAction*>(moduleItem->child(childIdx));
+        const auto itShortcut = moduleShortcuts.find(childItem->myInModuleActionID);
+        if (itShortcut == moduleShortcuts.end()) {
+          // Shortcut of the item has been removed from myShortcutContainer - impossible.
+          continue;
+        }
+        const QKeySequence& newKeySequence = itShortcut->second;
+        const QString newKeySequenceString = newKeySequence.toString();
+        if (childItem->keySequence() != newKeySequenceString)
+          childItem->setKeySequence(newKeySequenceString);
+
+        if (theHighlightModified) {
+          const QKeySequence& appliedKeySequence = SUIT_ShortcutMgr::get()->getKeySequence(moduleID, childItem->myInModuleActionID);
+          childItem->highlightKeySequenceAsModified(newKeySequence != appliedKeySequence);
+        }
+        else
+          childItem->highlightKeySequenceAsModified(false);
+      }
+
+      // Add new items if myShortcutContainer acquired new shortcuts, which may happen if a developer forgot
+      // to add shortcuts for registered actions to resource files.
+      if (moduleItem->childCount() < moduleShortcuts.size()) {
+        auto sortedChildren = getSortedChildren(moduleItem);
+        for (const auto& shortcut : moduleShortcuts) {
+          const QString& inModuleActionID = shortcut.first;
+          const auto predicate = [&inModuleActionID](const SUIT_ShortcutTreeItem* const theItem) -> bool {
+            return static_cast<const SUIT_ShortcutTreeAction* const>(theItem)->myInModuleActionID == inModuleActionID;
+          };
+
+          if (std::find_if(sortedChildren.begin(), sortedChildren.end(), predicate) == sortedChildren.end()) {
+            const auto actionItem = SUIT_ShortcutTreeAction::create(moduleID, inModuleActionID);
+            if (!actionItem) {
+              ShCutDbg("SUIT_ShortcutTree can't create child item for action ID = \"" + SUIT_ShortcutMgr::makeActionID(moduleID, inModuleActionID) + "\".");
+              continue;
+            }
+
+            const QKeySequence& keySequence = shortcut.second;
+            actionItem->setAssets(shortcutMgr->getActionAssets(moduleID, inModuleActionID), lang);
+            actionItem->setKeySequence(keySequence.toString());
+
+            if (theHighlightModified) {
+              const QKeySequence& appliedKeySequence = SUIT_ShortcutMgr::get()->getKeySequence(moduleID, inModuleActionID);
+              actionItem->highlightKeySequenceAsModified(keySequence != appliedKeySequence);
+            }
+
+            insertChild(moduleItem, sortedChildren, actionItem);
+          }
+        }
+      }
+    }
+  }
+
+  if (theUpdateSyncTrees) {
+    const std::set<SUIT_ShortcutTree*>& syncTrees = SUIT_ShortcutTree::instances[myShortcutContainer.get()];
+    for (const auto syncTree: syncTrees) {
+      if (syncTree == this)
+        continue;
+
+      syncTree->updateItems(theHighlightModified, false /*theUpdateSyncTrees*/);
+      const auto editDialog = syncTree->myEditDialog;
+      editDialog->setConfirmedKeySequence(myShortcutContainer->getKeySequence(editDialog->moduleID(), editDialog->inModuleActionID()));
+      editDialog->updateConflictsMessage();
+    }
+  }
+}
+
+/*! \returns Pointer and index of top-level item.
+If the tree does not contain an item with theModuleID, returns {nullptr, -1}. */
+std::pair<SUIT_ShortcutTreeFolder*, int> SUIT_ShortcutTree::findModuleFolderItem(const QString& theModuleID) const
+{
+  for (int moduleIdx = 0; moduleIdx < topLevelItemCount(); moduleIdx++) {
+    SUIT_ShortcutTreeFolder* moduleItem = static_cast<SUIT_ShortcutTreeFolder*>(topLevelItem(moduleIdx));
+    if (moduleItem->myModuleID == theModuleID)
+      return std::pair<SUIT_ShortcutTreeFolder*, int>(moduleItem, moduleIdx);
+  }
+  return std::pair<SUIT_ShortcutTreeFolder*, int>(nullptr, -1);
+}
+
+/*! \returns Children of theParentItem being sorted according to current sort mode and order. */
+std::set<SUIT_ShortcutTreeItem*, std::function<bool(SUIT_ShortcutTreeItem*, SUIT_ShortcutTreeItem*)>> SUIT_ShortcutTree::getSortedChildren(SUIT_ShortcutTreeFolder* theParentItem)
+{
+  QList<std::pair<SUIT_ShortcutTree::SortKey, SUIT_ShortcutTree::SortOrder>> sortSchema = SUIT_ShortcutTree::DEFAULT_SORT_SCHEMA;
+  {
+    for (auto itSameKey = sortSchema.begin(); itSameKey != sortSchema.end(); itSameKey++) {
+      if (itSameKey->first == mySortKey) {
+        sortSchema.erase(itSameKey);
+        break;
+      }
+    }
+    sortSchema.push_front(std::pair<SUIT_ShortcutTree::SortKey, SUIT_ShortcutTree::SortOrder>(mySortKey, mySortOrder));
+  }
+
+  static const QCollator collator;
+  const std::function<bool(SUIT_ShortcutTreeItem*, SUIT_ShortcutTreeItem*)> comparator =
+  [this, sortSchema, &collator](const SUIT_ShortcutTreeItem* theItemA, const SUIT_ShortcutTreeItem* theItemB) {
+    int res = 0;
+    for (const auto& keyAndOrder : sortSchema) {
+      int res = 0;
+      res = collator.compare(theItemA->getValue(keyAndOrder.first), theItemB->getValue(keyAndOrder.first));
+      if (res != 0)
+        return keyAndOrder.second == SUIT_ShortcutTree::SortOrder::Ascending ? res < 0 : res > 0;
+    }
+    return false;
+  };
+
+  std::set<SUIT_ShortcutTreeItem*, std::function<bool(SUIT_ShortcutTreeItem*, SUIT_ShortcutTreeItem*)>> sortedChildren(comparator);
+  for (int childIdx = 0; childIdx < theParentItem->childCount(); childIdx++) {
+    SUIT_ShortcutTreeAction* const childItem = static_cast<SUIT_ShortcutTreeAction*>(theParentItem->child(childIdx));
+    sortedChildren.emplace(childItem);
+  }
+  return sortedChildren;
+}
+
+/*! \brief Inserts theChildItem to theParentItem and theSortedChildren.
+Does not check whether theSortedChildren are actually child items of theParentItem.
+Does not check whether current item sort schema is same as one of theSortedChildren. */
+void SUIT_ShortcutTree::insertChild(
+  SUIT_ShortcutTreeFolder* theParentItem,
+  std::set<SUIT_ShortcutTreeItem*, std::function<bool(SUIT_ShortcutTreeItem*, SUIT_ShortcutTreeItem*)>>& theSortedChildren,
+  SUIT_ShortcutTreeItem* theChildItem
+) {
+  auto emplaceRes = theSortedChildren.emplace(theChildItem);
+  theParentItem->insertChild(indexOf(theSortedChildren, emplaceRes.first), theChildItem);
+}
+
+void SUIT_ShortcutTree::onItemDoubleClicked(QTreeWidgetItem* theItem, int theColIdx)
+{
+  {
+    SUIT_ShortcutTreeItem* const item = static_cast<SUIT_ShortcutTreeItem*>(theItem);
+    // Do not react if folder-item is clicked.
+    if (item->type() != SUIT_ShortcutTreeItem::Type::Action)
+      return;
+  }
+
+  SUIT_ShortcutTreeAction* const actionItem = static_cast<SUIT_ShortcutTreeAction*>(theItem);
+
+  myEditDialog->setModuleAndActionID(actionItem->myModuleID, actionItem->myInModuleActionID);
+  QString actionToolTip = actionItem->toolTip(SUIT_ShortcutTree::ElementIdx::Name);
+  actionToolTip.truncate(actionToolTip.lastIndexOf('\n') + 1);
+  myEditDialog->setModuleAndActionName(
+    static_cast<SUIT_ShortcutTreeItem*>(actionItem->parent())->name(),
+    actionItem->name(),
+    actionToolTip
+  );
+  myEditDialog->setConfirmedKeySequence(QKeySequence::fromString(actionItem->keySequence()));
+  myEditDialog->updateConflictsMessage();
+  const bool somethingChanged = myEditDialog->exec() == QDialog::Accepted;
+
+  if (!somethingChanged)
+    return;
+
+  const QKeySequence newKeySequence = myEditDialog->editedKeySequence();
+
+  /** { moduleID, inModuleActionID }[] */
+  std::set<std::pair<QString, QString>> disabledActionIDs = myShortcutContainer->setShortcut(actionItem->myModuleID, actionItem->myInModuleActionID, newKeySequence, true /*override*/);
+
+  /** { moduleID, {inModuleActionID, keySequence}[] }[] */
+  std::map<QString, std::map<QString, QString>> changes;
+  changes[actionItem->myModuleID][actionItem->myInModuleActionID] = newKeySequence.toString();
+  for (const auto moduleAndActionID : disabledActionIDs) {
+    changes[moduleAndActionID.first][moduleAndActionID.second] = QString();
+  }
+
+  // Set new key sequences to shortcut items.
+  for (const auto& moduleIDAndChanges : changes) {
+    const QString& moduleID = moduleIDAndChanges.first;
+
+    const auto moduleItemAndIdx = findModuleFolderItem(moduleID);
+    const auto moduleItem = moduleItemAndIdx.first;
+    if (!moduleItem)
+      continue;
+
+    /** {inModuleActionID, newKeySequence}[] */
+    const std::map<QString, QString>& moduleChanges = moduleIDAndChanges.second;
+
+    // Go through module' shortcut items, and highlight those, whose key sequences differ from applied key sequences.
+    for (int childIdx = 0; childIdx < moduleItem->childCount(); childIdx++) {
+      SUIT_ShortcutTreeAction* const childItem = static_cast<SUIT_ShortcutTreeAction*>(moduleItem->child(childIdx));
+      const auto itChange = moduleChanges.find(childItem->myInModuleActionID);
+      if (itChange == moduleChanges.end()) {
+        // The shortcut has not been changed.
+        continue;
+      }
+
+      childItem->setKeySequence(itChange->second);
+
+      const QKeySequence& appliedKeySequence = SUIT_ShortcutMgr::get()->getKeySequence(moduleID, childItem->myInModuleActionID);
+      childItem->highlightKeySequenceAsModified(QKeySequence::fromString(itChange->second) != appliedKeySequence);
+    }
+  }
+}
+
+/*static*/ const QList<std::pair<SUIT_ShortcutTree::SortKey, SUIT_ShortcutTree::SortOrder>> SUIT_ShortcutTree::DEFAULT_SORT_SCHEMA =
+{
+  {SUIT_ShortcutTree::SortKey::Name, SUIT_ShortcutTree::SortOrder::Ascending},
+  {SUIT_ShortcutTree::SortKey::ToolTip, SUIT_ShortcutTree::SortOrder::Ascending},
+  {SUIT_ShortcutTree::SortKey::KeySequence, SUIT_ShortcutTree::SortOrder::Ascending},
+  {SUIT_ShortcutTree::SortKey::ID, SUIT_ShortcutTree::SortOrder::Ascending}
+};
+
+/*static*/ std::map<SUIT_ShortcutContainer*, std::set<SUIT_ShortcutTree*>> SUIT_ShortcutTree::instances =
+std::map<SUIT_ShortcutContainer*, std::set<SUIT_ShortcutTree*>>();
+
+
+
+SUIT_ShortcutTreeItem::SUIT_ShortcutTreeItem(const QString& theModuleID)
+: QTreeWidgetItem(), myModuleID(theModuleID)
+{ }
+
+QString SUIT_ShortcutTreeItem::name() const
+{
+  return text(SUIT_ShortcutTree::ElementIdx::Name);
+}
+
+
+SUIT_ShortcutTreeFolder::SUIT_ShortcutTreeFolder(const QString& theModuleID)
+: SUIT_ShortcutTreeItem(theModuleID)
+{
+  QFont f = font(SUIT_ShortcutTree::ElementIdx::Name);
+  f.setBold(true);
+  setFont(SUIT_ShortcutTree::ElementIdx::Name, f);
+  setText(SUIT_ShortcutTree::ElementIdx::Name, theModuleID);
+}
+
+void SUIT_ShortcutTreeFolder::setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang)
+{
+  if (!theAssets)
+    return;
+
+  setIcon(SUIT_ShortcutTree::ElementIdx::Name, theAssets->myIcon);
+
+  const auto& ldaMap = theAssets->myLangDependentAssets;
+  if (ldaMap.empty()) {
+    setText(SUIT_ShortcutTree::ElementIdx::Name, myModuleID);
+    return;
+  }
+
+  auto itLDA = ldaMap.find(theLang);
+  if (itLDA == ldaMap.end())
+    itLDA = ldaMap.begin();
+
+  const SUIT_ActionAssets::LangDependentAssets& lda = itLDA->second;
+  const QString& name = lda.myName.isEmpty() ? myModuleID : lda.myName;
+  setText(SUIT_ShortcutTree::ElementIdx::Name, name);
+}
+
+QString SUIT_ShortcutTreeFolder::getValue(SUIT_ShortcutTree::SortKey theKey) const
+{
+  switch (theKey) {
+    case SUIT_ShortcutTree::SortKey::ID:
+      return myModuleID;
+    case SUIT_ShortcutTree::SortKey::Name:
+      return name();
+    case SUIT_ShortcutTree::SortKey::ToolTip:
+      return name();
+    default:
+      return QString();
+  }
+}
+
+
+SUIT_ShortcutTreeAction::SUIT_ShortcutTreeAction(const QString& theModuleID, const QString& theInModuleActionID)
+: SUIT_ShortcutTreeItem(theModuleID), myInModuleActionID(theInModuleActionID)
+{
+  setText(SUIT_ShortcutTree::ElementIdx::Name, theInModuleActionID);
+  setToolTip(
+    SUIT_ShortcutTree::ElementIdx::Name,
+    theInModuleActionID + (theInModuleActionID.at(theInModuleActionID.length()-1) == "." ? "\n" : ".\n") + SUIT_ShortcutTree::tr("Double click to edit key sequence.")
+  );
+  setToolTip(SUIT_ShortcutTree::ElementIdx::KeySequence, SUIT_ShortcutTree::tr("Double click to edit key sequence."));
+}
+
+/*static*/ SUIT_ShortcutTreeAction* SUIT_ShortcutTreeAction::create(const QString& theModuleID, const QString& theInModuleActionID)
+{
+  if (theInModuleActionID.isEmpty()) {
+    ShCutDbg("SUIT_ShortcutTreeItem: attempt to create item with empty action ID.");
+    return nullptr;
+  }
+
+  return new SUIT_ShortcutTreeAction(theModuleID, theInModuleActionID);
+}
+
+void SUIT_ShortcutTreeAction::setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang)
+{
+  if (!theAssets)
+    return;
+
+  setIcon(SUIT_ShortcutTree::ElementIdx::Name, theAssets->myIcon);
+
+  const auto& ldaMap = theAssets->myLangDependentAssets;
+  if (ldaMap.empty()) {
+    setText(SUIT_ShortcutTree::ElementIdx::Name, myInModuleActionID);
+    return;
+  }
+
+  auto itLDA = ldaMap.find(theLang);
+  if (itLDA == ldaMap.end())
+    itLDA = ldaMap.begin();
+
+  const SUIT_ActionAssets::LangDependentAssets& lda = itLDA->second;
+  const QString& name = lda.myName.isEmpty() ? myInModuleActionID : lda.myName;
+  setText(SUIT_ShortcutTree::ElementIdx::Name, name);
+
+  const QString& actionToolTip = lda.myToolTip.isEmpty() ? name : lda.myToolTip;
+  setToolTip(
+    SUIT_ShortcutTree::ElementIdx::Name,
+    actionToolTip + (actionToolTip.at(actionToolTip.length()-1) == "." ? "\n" : ".\n") + SUIT_ShortcutTree::tr("Double click to edit key sequence.")
+  );
+}
+
+QString SUIT_ShortcutTreeAction::getValue(SUIT_ShortcutTree::SortKey theKey) const
+{
+  switch (theKey) {
+    case SUIT_ShortcutTree::SortKey::ID:
+      return myInModuleActionID;
+    case SUIT_ShortcutTree::SortKey::Name:
+      return name();
+    case SUIT_ShortcutTree::SortKey::ToolTip:
+      return toolTip(SUIT_ShortcutTree::ElementIdx::Name);
+    case SUIT_ShortcutTree::SortKey::KeySequence:
+      return keySequence();
+    default:
+      return QString();
+  }
+}
+
+void SUIT_ShortcutTreeAction::setKeySequence(const QString& theKeySequence)
+{
+  setText(SUIT_ShortcutTree::ElementIdx::KeySequence, theKeySequence);
+}
+
+QString SUIT_ShortcutTreeAction::keySequence() const
+{
+  return text(SUIT_ShortcutTree::ElementIdx::KeySequence);
+}
+
+/*! \brief Highlights text at ElementIdx::KeySequence. */
+void SUIT_ShortcutTreeAction::highlightKeySequenceAsModified(bool theHighlight)
+{
+  static const QBrush bgHighlitingBrush = QBrush(Qt::darkGreen);
+  static const QBrush fgHighlitingBrush = QBrush(Qt::white);
+  static const QBrush noBrush = QBrush();
+
+  setBackground(SUIT_ShortcutTree::ElementIdx::KeySequence, theHighlight ? bgHighlitingBrush : noBrush);
+  setForeground(SUIT_ShortcutTree::ElementIdx::KeySequence, theHighlight ? fgHighlitingBrush : noBrush);
+}
\ No newline at end of file
diff --git a/src/SUIT/SUIT_ShortcutTree.h b/src/SUIT/SUIT_ShortcutTree.h
new file mode 100644 (file)
index 0000000..7d2df22
--- /dev/null
@@ -0,0 +1,265 @@
+// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef SUIT_SHORTCUTTREE_H
+#define SUIT_SHORTCUTTREE_H
+
+#include "SUIT.h"
+#include <QDialog>
+#include <QFrame>
+#include <QTreeWidget>
+#include "SUIT_ShortcutMgr.h"
+#include <memory>
+#include <map>
+#include <set>
+#include <functional>
+
+
+class QLineEdit;
+class QLabel;
+class QPushButton;
+class QTreeWidgetItem;
+
+class SUIT_EXPORT SUIT_KeySequenceEdit : public QFrame
+{
+  Q_OBJECT
+
+public:
+  SUIT_KeySequenceEdit(QWidget* = nullptr);
+  virtual ~SUIT_KeySequenceEdit() = default;
+
+  void           setConfirmedKeySequence(const QKeySequence&);
+  void           setEditedKeySequence(const QKeySequence&);
+  QKeySequence   editedKeySequence() const;
+  bool           isKeySequenceModified() const;
+  void           restoreKeySequence();
+
+  static QString parseEvent(QKeyEvent*);
+  static bool    isValidKey(int);
+
+signals:
+  void           editingStarted();
+  void           editingFinished();
+  void           restoreFromShortcutMgrClicked();
+
+private slots:
+  void           onClear();
+  void           onEditingFinished();
+
+protected:
+  virtual bool   eventFilter(QObject*, QEvent*);
+
+private:
+  void           initialize();
+
+private:
+  QLineEdit*     myKeySequenceLineEdit;
+  QString        myConfirmedKeySequenceString;
+
+  // Last valid key sequence string from myKeySequenceLineEdit.
+  QString        myPrevKeySequenceString;
+};
+
+
+class SUIT_ShortcutTree;
+class SUIT_ShortcutTreeItem;
+class SUIT_ShortcutTreeFolder;
+class SUIT_ShortcutTreeAction;
+class QTextEdit;
+
+
+class SUIT_EXPORT SUIT_EditKeySequenceDialog : public QDialog
+{
+  Q_OBJECT
+
+public:
+  SUIT_EditKeySequenceDialog(SUIT_ShortcutTree* theParent);
+  SUIT_EditKeySequenceDialog(const SUIT_EditKeySequenceDialog&) = delete;
+  SUIT_EditKeySequenceDialog& operator=(const SUIT_EditKeySequenceDialog&) = delete;
+  virtual ~SUIT_EditKeySequenceDialog() = default;
+
+  void setModuleAndActionID(const QString& theModuleID, const QString& theInModuleActionID);
+  const QString& moduleID() const;
+  const QString& inModuleActionID() const;
+
+  void setModuleAndActionName(const QString& theModuleName, const QString& theActionName, const QString& theActionToolTip = "");
+
+  void setConfirmedKeySequence(const QKeySequence& theSequence);
+  QKeySequence editedKeySequence() const;
+
+  void updateConflictsMessage();
+
+  int exec();
+
+private slots:
+  void onEditingStarted();
+  void onEditingFinished();
+  void onRestoreFromShortcutMgr();
+  void onConfirm();
+
+private:
+  QString myModuleID;
+  QString myInModuleActionID;
+  QLabel* myActionName;
+  SUIT_KeySequenceEdit* myKeySequenceEdit;
+  QTextEdit* myTextEdit;
+};
+
+
+class SUIT_EXPORT SUIT_ShortcutTree : public QTreeWidget
+{
+  Q_OBJECT
+
+public:
+  enum ElementIdx {
+    Name = 0,
+    KeySequence = 1, // Empty, if item is folder item.
+  };
+
+  enum class SortKey {
+    ID,
+    Name,
+    ToolTip,
+    KeySequence,
+  };
+
+  enum class SortOrder {
+    Ascending,
+    Descending
+  };
+
+  SUIT_ShortcutTree(
+    std::shared_ptr<SUIT_ShortcutContainer> theContainer = std::shared_ptr<SUIT_ShortcutContainer>(),
+    QWidget* theParent = nullptr
+  );
+  SUIT_ShortcutTree(const SUIT_ShortcutTree&) = delete;
+  SUIT_ShortcutTree& operator=(const SUIT_ShortcutTree&) = delete;
+  virtual ~SUIT_ShortcutTree();
+
+  void setShortcutsFromManager();
+  void setDefaultShortcuts();
+  void applyChangesToShortcutMgr();
+
+  std::shared_ptr<const SUIT_ShortcutContainer> shortcutContainer() const;
+
+  void sort(SUIT_ShortcutTree::SortKey theKey, SUIT_ShortcutTree::SortOrder theOrder);
+
+private:
+  void updateItems(bool theHighlightModified, bool theUpdateSyncTrees);
+  std::pair<SUIT_ShortcutTreeFolder*, int> findModuleFolderItem(const QString& theModuleID) const;
+
+  std::set<SUIT_ShortcutTreeItem*, std::function<bool(SUIT_ShortcutTreeItem*, SUIT_ShortcutTreeItem*)>> getSortedChildren(SUIT_ShortcutTreeFolder* theParentItem);
+
+  void insertChild(
+    SUIT_ShortcutTreeFolder* theParentItem,
+    std::set<SUIT_ShortcutTreeItem*, std::function<bool(SUIT_ShortcutTreeItem*, SUIT_ShortcutTreeItem*)>>& theSortedChildren,
+    SUIT_ShortcutTreeItem* theChildItem
+  );
+
+private slots:
+  void onItemDoubleClicked(QTreeWidgetItem* theWidgetItem, int theColIdx);
+
+public:
+  /** Keeps IDs of modules, which will are shown on setShortcutsFromManager(). */
+  std::set<QString> myModuleIDs;
+
+  static const QList<std::pair<SUIT_ShortcutTree::SortKey, SUIT_ShortcutTree::SortOrder>> DEFAULT_SORT_SCHEMA;
+
+private:
+  /** Allows to modify plenty of shortcuts and then apply them to SUIT_ShortcutMgr as a batch. */
+  const std::shared_ptr<SUIT_ShortcutContainer> myShortcutContainer;
+
+  SUIT_EditKeySequenceDialog* myEditDialog;
+
+  SUIT_ShortcutTree::SortKey mySortKey;
+  SUIT_ShortcutTree::SortOrder mySortOrder;
+
+  /**
+   * Ensures that, if several SUIT_ShortcutTree instances coexist,
+   * all of them are updated when one of them applies pending changes to SUIT_ShortcutMgr.
+   *
+   * Sharing of SUIT_ShortcutContainer allows to keep some trees synchronized even without
+   * applying changes to SUIT_ShortcutMgr. Why? See SUIT_PagePrefShortcutTreeItem.
+   *
+   * Access is not synchronized in assumption, that all instances live in the same thread.
+  */
+  static std::map<SUIT_ShortcutContainer*, std::set<SUIT_ShortcutTree*>> instances;
+};
+
+
+class SUIT_ShortcutTreeItem : public QTreeWidgetItem
+{
+public:
+  enum Type {
+    Folder = 0,
+    Action = 1,
+  };
+
+protected:
+  SUIT_ShortcutTreeItem(const QString& theModuleID);
+
+public:
+  virtual ~SUIT_ShortcutTreeItem() = default;
+  virtual SUIT_ShortcutTreeItem::Type type() const = 0;
+
+  virtual void setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang) = 0;
+  QString name() const;
+
+  virtual QString getValue(SUIT_ShortcutTree::SortKey theKey) const = 0;
+
+public:
+  const QString myModuleID;
+};
+
+
+class SUIT_ShortcutTreeFolder : public SUIT_ShortcutTreeItem
+{
+public:
+  SUIT_ShortcutTreeFolder(const QString& theModuleID);
+  virtual ~SUIT_ShortcutTreeFolder() = default;
+  virtual SUIT_ShortcutTreeItem::Type type() const { return SUIT_ShortcutTreeItem::Type::Folder; };
+
+  virtual void setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang);
+
+  virtual QString getValue(SUIT_ShortcutTree::SortKey theKey) const;
+};
+
+
+class SUIT_ShortcutTreeAction : public SUIT_ShortcutTreeItem
+{
+private:
+  SUIT_ShortcutTreeAction(const QString& theModuleID, const QString& theInModuleActionID);
+
+public:
+  static SUIT_ShortcutTreeAction* create(const QString& theModuleID, const QString& theInModuleActionID);
+  virtual ~SUIT_ShortcutTreeAction() = default;
+  virtual SUIT_ShortcutTreeItem::Type type() const { return SUIT_ShortcutTreeItem::Type::Action; };
+
+  virtual void setAssets(std::shared_ptr<const SUIT_ActionAssets> theAssets, const QString& theLang);
+
+  virtual QString getValue(SUIT_ShortcutTree::SortKey theKey) const;
+
+  void setKeySequence(const QString& theKeySequence);
+  QString keySequence() const;
+  void highlightKeySequenceAsModified(bool theHighlight);
+
+  const QString myInModuleActionID;
+};
+
+#endif // SUIT_SHORTCUTTREE_H
index bdbbb196e3f99171ab9b0e145805c9b94e6b2ff5..9b8a319063d6d453eb9c4d4d7d3e55076097c154 100644 (file)
@@ -160,6 +160,29 @@ Voulez-vous l&apos;écraser ?</translation>
         <translation>Tous les fichiers (*)</translation>
     </message>
 </context>
+<context>
+    <name>SUIT_FindActionDialog</name>
+    <message>
+        <source>Find action</source>
+        <translation>Trouver une action</translation>
+    </message>
+    <message>
+        <source>Unavailable actions</source>
+        <translation>Actions indisponibles</translation>
+    </message>
+    <message>
+        <source>Inactive modules</source>
+        <translation>Modules inactifs</translation>
+    </message>
+    <message>
+        <source>Action</source>
+        <translation>Action</translation>
+    </message>
+    <message>
+        <source>Description</source>
+        <translation>Description</translation>
+    </message>
+</context>
 <context>
     <name>SUIT_ViewWindow</name>
     <message>
@@ -198,4 +221,53 @@ Voulez-vous l&apos;écraser ?</translation>
         <translation>Corrigez manuellement les entrées suivantes dans les fichiers de préférences</translation>
     </message>
 </context>
+<context>
+    <name>SUIT_KeySequenceEdit</name>
+    <message>
+        <source>Disable shortcut.</source>
+        <translation>Désactivez le raccourci.</translation>
+    </message>
+    <message>
+        <source>Restore the currently applied key sequence.</source>
+        <translation>Restaurez la séquence de touches actuellement appliquée.</translation>
+    </message>
+</context>
+<context>
+    <name>SUIT_EditKeySequenceDialog</name>
+    <message>
+        <source>Change key sequence</source>
+        <translation>Modifier la séquence de touches</translation>
+    </message>
+    <message>
+        <source>No conflicts.</source>
+        <translation>Aucun conflit.</translation>
+    </message>
+    <message>
+        <source>Confirm</source>
+        <translation>Confirmer</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Annuler</translation>
+    </message>
+    <message>
+        <source>These shortcuts will be disabled on confirm:</source>
+        <translation>Ces raccourcis seront désactivés lors de la confirmation :</translation>
+    </message>
+</context>
+<context>
+    <name>SUIT_ShortcutTree</name>
+    <message>
+        <source>Action</source>
+        <translation>Action</translation>
+    </message>
+    <message>
+        <source>Key sequence</source>
+        <translation>Séquence de touches</translation>
+    </message>
+    <message>
+        <source>Double click to edit key sequence.</source>
+        <translation>Double-cliquez pour modifier la séquence de touches.</translation>
+    </message>
+</context>
 </TS>
index 2fb333637a5b516eef5477ce4619f3f1d7ad3add..ad3f28ddbad97d5632ad88d8da8e0871757e452e 100644 (file)
       <translation>すべてのファイル (*)</translation>
     </message>
   </context>
+  <context>
+    <name>SUIT_FindActionDialog</name>
+    <message>
+        <source>Find action</source>
+        <translation>検索アクション</translation>
+    </message>
+    <message>
+        <source>Unavailable actions</source>
+        <translation>利用できないアクション</translation>
+    </message>
+    <message>
+        <source>Inactive modules</source>
+        <translation>非アクティブなモジュール</translation>
+    </message>
+    <message>
+        <source>Action</source>
+        <translation>アクション</translation>
+    </message>
+    <message>
+        <source>Description</source>
+        <translation>説明</translation>
+    </message>
+  </context>
 <context>
     <name>SUIT_ViewWindow</name>
     <message>
         <translation>設定ファイル内の次のエントリを手動で修正します</translation>
     </message>
 </context>
+  <context>
+    <name>SUIT_KeySequenceEdit</name>
+    <message>
+        <source>Disable shortcut.</source>
+        <translation>ショートカットを無効にします。</translation>
+    </message>
+    <message>
+        <source>Restore the currently applied key sequence.</source>
+        <translation>現在適用されているキー シーケンスを復元します。</translation>
+    </message>
+  </context>
+  <context>
+      <name>SUIT_EditKeySequenceDialog</name>
+      <message>
+          <source>Change key sequence</source>
+          <translation>キーシーケンスを変更する</translation>
+      </message>
+      <message>
+          <source>No conflicts.</source>
+          <translation>競合はありません。</translation>
+      </message>
+      <message>
+          <source>Confirm</source>
+          <translation>確認する</translation>
+      </message>
+      <message>
+          <source>Cancel</source>
+          <translation>キャンセル</translation>
+      </message>
+      <message>
+          <source>These shortcuts will be disabled on confirm:</source>
+          <translation>これらのショートカットは確認時に無効になります。</translation>
+      </message>
+  </context>
+  <context>
+      <name>SUIT_ShortcutTree</name>
+      <message>
+        <source>Action</source>
+        <translation>アクション</translation>
+      </message>
+      <message>
+          <source>Key sequence</source>
+          <translation>キーシーケンス</translation>
+      </message>
+      <message>
+          <source>Double click to edit key sequence.</source>
+          <translation>ダブルクリックしてキー シーケンスを編集します。</translation>
+      </message>
+  </context>
 </TS>
index 64a379301a2d3a201bef945a4a425abf76da54a6..e522b64db8362107e38ab3042a2208ebdb227bd8 100644 (file)
@@ -73,7 +73,7 @@
 #include <SUIT_OverrideCursor.h>
 
 #include <QtxTreeView.h>
-#include <QtxFindActionDialog.h>
+#include <SUIT_FindActionDialog.h>
 
 #include <SALOME_EventFilter.h>
 
@@ -1592,7 +1592,7 @@ void SalomeApp_Application::onFindAction()
     // Keep this conditional block until ParaViS's actions are not added to ShortcutMgr resource and asset files.
   }
 
-  QtxFindActionDialog aDlg( desktop() );
+  SUIT_FindActionDialog aDlg( desktop() );
   if (pActiveModule)
     aDlg.setActiveModuleID(pActiveModule->name());
   else