1/*
2 * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17#include "environmentshortcutwidget.h"
18#include "ui_environmentshortcutwidget.h"
19#include "../mainwindow.h"
20#include "../widgets/shortcutinputedit.h"
21#include <QMenuBar>
22#include <QMenu>
23#include <QMessageBox>
24
25EnvironmentShortcutWidget::EnvironmentShortcutWidget(const QString& name, const QString& group, QWidget *parent) :
26 SettingsWidget(name,group,parent),
27 ui(new Ui::EnvironmentShortcutWidget)
28{
29 ui->setupUi(this);
30 mDelegate =new EnvironmentShortcutDelegate(this);
31 ui->tblShortcut->setModel(&mModel);
32 ui->tblShortcut->setItemDelegate(mDelegate);
33 connect(&mModel, &EnvironmentShortcutModel::shortcutChanged,
34 this, &SettingsWidget::setSettingsChanged);
35 mDelegate =new EnvironmentShortcutDelegate(this);
36}
37
38EnvironmentShortcutWidget::~EnvironmentShortcutWidget()
39{
40 delete ui;
41}
42
43void EnvironmentShortcutWidget::doLoad()
44{
45 mModel.reload();
46}
47
48void EnvironmentShortcutWidget::doSave()
49{
50 ShortcutManager manager;
51 manager.setShortcuts(mModel.shortcuts());
52 manager.save();
53 pMainWindow->updateShortcuts();
54 mModel.reload();
55}
56
57EnvironmentShortcutModel::EnvironmentShortcutModel(QObject *parent):QAbstractTableModel(parent)
58{
59
60}
61
62void EnvironmentShortcutModel::reload()
63{
64 beginResetModel();
65 mShortcuts.clear();
66 QList<QMenu*> menus = pMainWindow->menuBar()->findChildren<QMenu*>();
67 QList<QAction*> actions = pMainWindow->listShortCutableActions();
68 foreach( const QMenu* menu, menus) {
69 if (menu->title().isEmpty())
70 continue;
71 loadShortCutsOfMenu(menu, actions);
72 }
73 foreach (QAction* action,actions) {
74 if (!action->text().isEmpty()) {
75 PEnvironmentShortcut item = std::make_shared<EnvironmentShortcut>();
76 item->name = action->objectName();
77 item->fullPath = QString("%1 : %2").arg(tr("action"),action->text());
78 item->action = action;
79 item->shortcut = action->shortcut().toString().trimmed();
80 item->isAction = true;
81 mShortcuts.append(item);
82 }
83 }
84 endResetModel();
85}
86
87int EnvironmentShortcutModel::rowCount(const QModelIndex &) const
88{
89 return mShortcuts.count();
90}
91
92int EnvironmentShortcutModel::columnCount(const QModelIndex &) const
93{
94 return 2;
95}
96
97QVariant EnvironmentShortcutModel::data(const QModelIndex &index, int role) const
98{
99 if (!index.isValid()) {
100 return QVariant();
101 }
102 if (role==Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole) {
103 PEnvironmentShortcut item = mShortcuts[index.row()];
104 switch( index.column()) {
105 case 0:
106 return item->fullPath;
107 case 1:
108 return item->shortcut;
109 }
110 }
111 return QVariant();
112}
113
114bool EnvironmentShortcutModel::setData(const QModelIndex &index, const QVariant &value, int role)
115{
116 if (!index.isValid()) {
117 return false;
118 }
119 if (role == Qt::EditRole) {
120 if (index.column()!=1)
121 return false;
122 PEnvironmentShortcut item = mShortcuts[index.row()];
123 QString s = value.toString().trimmed();
124 if (s!=item->shortcut) {
125 if (s.isEmpty()) {
126 item->shortcut="";
127 } else {
128 for (int i=0;i<mShortcuts.length();i++) {
129 if (i==index.row())
130 continue;
131 if (s==mShortcuts[i]->shortcut) {
132 QMessageBox::critical(nullptr,
133 tr("Error"),
134 tr("Shortcut \"%1\" is used by \"%2\".")
135 .arg(s,mShortcuts[i]->fullPath));
136 return false;
137 }
138 }
139 item->shortcut = value.toString();
140 }
141 emit shortcutChanged();
142 }
143 return true;
144 }
145 return false;
146}
147
148QVariant EnvironmentShortcutModel::headerData(int section, Qt::Orientation orientation, int role) const
149{
150 if (orientation == Qt::Horizontal) {
151 if (role == Qt::DisplayRole) {
152 switch(section) {
153 case 0:
154 return tr("Function");
155 case 1:
156 return tr("Shortcut");
157 }
158 }
159 }
160 return QVariant();
161}
162
163Qt::ItemFlags EnvironmentShortcutModel::flags(const QModelIndex &index) const
164{
165 Qt::ItemFlags flags = Qt::ItemIsEnabled;
166 if (index.isValid() && index.column()==1) {
167 flags.setFlag(Qt::ItemIsEditable);
168 }
169 return flags;
170}
171
172const QList<PEnvironmentShortcut> &EnvironmentShortcutModel::shortcuts() const
173{
174 return mShortcuts;
175}
176
177void EnvironmentShortcutModel::shortcutsUpdated()
178{
179 beginResetModel();
180 endResetModel();
181}
182
183void EnvironmentShortcutModel::loadShortCutsOfMenu(const QMenu *menu, QList<QAction *> &globalActions)
184{
185 QList<QAction*> actions = menu->actions();
186 foreach (QAction* action,actions) {
187 if (!action->text().isEmpty() && action->menu()==nullptr) {
188 PEnvironmentShortcut item = std::make_shared<EnvironmentShortcut>();
189 item->name = action->objectName();
190 item->fullPath = QString("%1 > %2").arg(menu->title(),action->text());
191 item->action = action;
192 item->shortcut = action->shortcut().toString().trimmed();
193 item->isAction = true;
194 mShortcuts.append(item);
195 }
196 globalActions.removeAll(action);
197 }
198}
199
200EnvironmentShortcutDelegate::EnvironmentShortcutDelegate(
201 QObject *parent) : QStyledItemDelegate(parent)
202{
203}
204
205QWidget *EnvironmentShortcutDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
206{
207 if (index.isValid() && index.column()==1) {
208 ShortcutInputEdit *editor=new ShortcutInputEdit(dynamic_cast<QWidget*>(parent));
209 connect(editor,&ShortcutInputEdit::inputFinished,
210 this, &EnvironmentShortcutDelegate::onEditingFinished);
211 return editor;
212 }
213 return QStyledItemDelegate::createEditor(parent,option,index);
214}
215
216void EnvironmentShortcutDelegate::onEditingFinished(QWidget* editor)
217{
218 emit commitData(editor);
219 emit closeEditor(editor, QAbstractItemDelegate::SubmitModelCache);
220}
221