1 // For license of this file, see <project-root-folder>/LICENSE.md.
2 
3 #include "gui/toolbars/toolbareditor.h"
4 
5 #include "gui/dialogs/formmain.h"
6 #include "gui/toolbars/basetoolbar.h"
7 
8 #include <QKeyEvent>
9 
ToolBarEditor(QWidget * parent)10 ToolBarEditor::ToolBarEditor(QWidget* parent)
11   : QWidget(parent), m_ui(new Ui::ToolBarEditor), m_toolBar(nullptr) {
12   m_ui->setupUi(this);
13 
14   // Create connections.
15   connect(m_ui->m_btnInsertSeparator, &QToolButton::clicked, this, &ToolBarEditor::insertSeparator);
16   connect(m_ui->m_btnInsertSpacer, &QToolButton::clicked, this, &ToolBarEditor::insertSpacer);
17   connect(m_ui->m_btnAddSelectedAction, &QToolButton::clicked, this, &ToolBarEditor::addSelectedAction);
18   connect(m_ui->m_btnDeleteAllActions, &QToolButton::clicked, this, &ToolBarEditor::deleteAllActions);
19   connect(m_ui->m_btnDeleteSelectedAction, &QToolButton::clicked, this, &ToolBarEditor::deleteSelectedAction);
20   connect(m_ui->m_btnMoveActionUp, &QToolButton::clicked, this, &ToolBarEditor::moveActionUp);
21   connect(m_ui->m_btnMoveActionDown, &QToolButton::clicked, this, &ToolBarEditor::moveActionDown);
22   connect(m_ui->m_btnReset, &QToolButton::clicked, this, &ToolBarEditor::resetToolBar);
23   connect(m_ui->m_listAvailableActions, &QListWidget::itemSelectionChanged, this, &ToolBarEditor::updateActionsAvailability);
24   connect(m_ui->m_listActivatedActions, &QListWidget::itemSelectionChanged, this, &ToolBarEditor::updateActionsAvailability);
25   connect(m_ui->m_listActivatedActions, &QListWidget::itemDoubleClicked, this, &ToolBarEditor::deleteSelectedAction);
26   connect(m_ui->m_listAvailableActions, &QListWidget::itemDoubleClicked, this, &ToolBarEditor::addSelectedAction);
27   m_ui->m_listActivatedActions->installEventFilter(this);
28   m_ui->m_btnInsertSeparator->setIcon(qApp->icons()->fromTheme(QSL("insert-object")));
29   m_ui->m_btnInsertSpacer->setIcon(qApp->icons()->fromTheme(QSL("go-jump")));
30   m_ui->m_btnAddSelectedAction->setIcon(qApp->icons()->fromTheme(QSL("go-previous")));
31   m_ui->m_btnDeleteAllActions->setIcon(qApp->icons()->fromTheme(QSL("application-exit")));
32   m_ui->m_btnDeleteSelectedAction->setIcon(qApp->icons()->fromTheme(QSL("go-next")));
33   m_ui->m_btnMoveActionDown->setIcon(qApp->icons()->fromTheme(QSL("down")));
34   m_ui->m_btnMoveActionUp->setIcon(qApp->icons()->fromTheme(QSL("up")));
35   m_ui->m_btnReset->setIcon(qApp->icons()->fromTheme(QSL("reload")));
36 }
37 
loadFromToolBar(BaseBar * tool_bar)38 void ToolBarEditor::loadFromToolBar(BaseBar* tool_bar) {
39   m_toolBar = tool_bar;
40 
41   QList<QAction*> activated_actions = m_toolBar->activatedActions();
42   QList<QAction*> available_actions = m_toolBar->availableActions();
43 
44   loadEditor(activated_actions, available_actions);
45 }
46 
saveToolBar()47 void ToolBarEditor::saveToolBar() {
48   QStringList action_names;
49 
50   for (int i = 0; i < m_ui->m_listActivatedActions->count(); i++) {
51     action_names.append(m_ui->m_listActivatedActions->item(i)->data(Qt::UserRole).toString());
52   }
53 
54   m_toolBar->saveAndSetActions(action_names);
55 }
56 
resetToolBar()57 void ToolBarEditor::resetToolBar() {
58   if (m_toolBar != nullptr) {
59     loadEditor(m_toolBar->convertActions(m_toolBar->defaultActions()), m_toolBar->availableActions());
60     emit setupChanged();
61   }
62 }
63 
loadEditor(const QList<QAction * > & activated_actions,const QList<QAction * > & available_actions)64 void ToolBarEditor::loadEditor(const QList<QAction*>& activated_actions, const QList<QAction*>& available_actions) {
65   m_ui->m_listActivatedActions->clear();
66   m_ui->m_listAvailableActions->clear();
67 
68   for (const QAction* action : activated_actions) {
69     QListWidgetItem* action_item = new QListWidgetItem(action->icon(),
70                                                        action->text().replace('&', QL1S("")),
71                                                        m_ui->m_listActivatedActions);
72 
73     if (action->isSeparator()) {
74       action_item->setData(Qt::ItemDataRole::UserRole, SEPARATOR_ACTION_NAME);
75       action_item->setIcon(qApp->icons()->fromTheme(QSL("insert-object")));
76       action_item->setText(tr("Separator"));
77       action_item->setToolTip(tr("Separator"));
78     }
79     else if (action->property("type").isValid()) {
80       action_item->setData(Qt::ItemDataRole::UserRole, action->property("type").toString());
81       action_item->setText(action->property("name").toString());
82       action_item->setToolTip(action_item->text());
83     }
84     else {
85       action_item->setData(Qt::ItemDataRole::UserRole, action->objectName());
86       action_item->setToolTip(action->toolTip());
87     }
88   }
89 
90   for (QAction* action : available_actions) {
91     if (!activated_actions.contains(action)) {
92       QListWidgetItem* action_item = new QListWidgetItem(action->icon(),
93                                                          action->text().replace('&', QL1S("")),
94                                                          m_ui->m_listAvailableActions);
95 
96       if (action->isSeparator()) {
97         action_item->setData(Qt::ItemDataRole::UserRole, QSL(SEPARATOR_ACTION_NAME));
98         action_item->setText(tr("Separator"));
99         action_item->setToolTip(tr("Separator"));
100         action_item->setIcon(qApp->icons()->fromTheme(QSL("insert-object")));
101       }
102       else if (action->property("type").isValid()) {
103         action_item->setData(Qt::ItemDataRole::UserRole, action->property("type").toString());
104         action_item->setText(action->property("name").toString());
105         action_item->setToolTip(action_item->text());
106       }
107       else {
108         action_item->setData(Qt::ItemDataRole::UserRole, action->objectName());
109         action_item->setToolTip(action->toolTip());
110       }
111     }
112   }
113 
114   m_ui->m_listAvailableActions->sortItems(Qt::SortOrder::AscendingOrder);
115   m_ui->m_listAvailableActions->setCurrentRow(m_ui->m_listAvailableActions->count() >= 0 ? 0 : -1);
116   m_ui->m_listActivatedActions->setCurrentRow(m_ui->m_listActivatedActions->count() >= 0 ? 0 : -1);
117 }
118 
eventFilter(QObject * object,QEvent * event)119 bool ToolBarEditor::eventFilter(QObject* object, QEvent* event) {
120   if (object == m_ui->m_listActivatedActions) {
121     if (event->type() == QEvent::Type::KeyPress) {
122       const auto* key_event = static_cast<QKeyEvent*>(event);
123 
124       if (key_event->key() == Qt::Key::Key_Delete) {
125         deleteSelectedAction();
126         return true;
127       }
128       else if (key_event->key() == Qt::Key::Key_Down &&
129                (key_event->modifiers() & Qt::KeyboardModifier::ControlModifier) == Qt::KeyboardModifier::ControlModifier) {
130         moveActionDown();
131         return true;
132       }
133       else if (key_event->key() == Qt::Key::Key_Up &&
134                (key_event->modifiers() & Qt::KeyboardModifier::ControlModifier) == Qt::KeyboardModifier::ControlModifier) {
135         moveActionUp();
136         return true;
137       }
138     }
139   }
140 
141   return false;
142 }
143 
updateActionsAvailability()144 void ToolBarEditor::updateActionsAvailability() {
145   m_ui->m_btnDeleteAllActions->setEnabled(m_ui->m_listActivatedActions->count() > 0);
146   m_ui->m_btnDeleteSelectedAction->setEnabled(m_ui->m_listActivatedActions->selectedItems().size() == 1);
147   m_ui->m_btnMoveActionUp->setEnabled(m_ui->m_listActivatedActions->selectedItems().size() == 1 &&
148                                       m_ui->m_listActivatedActions->currentRow() > 0);
149   m_ui->m_btnMoveActionDown->setEnabled(m_ui->m_listActivatedActions->selectedItems().size() == 1 &&
150                                         m_ui->m_listActivatedActions->currentRow() < m_ui->m_listActivatedActions->count() - 1);
151   m_ui->m_btnAddSelectedAction->setEnabled(m_ui->m_listAvailableActions->selectedItems().size() > 0);
152 }
153 
insertSpacer()154 void ToolBarEditor::insertSpacer() {
155   const int current_row = m_ui->m_listActivatedActions->currentRow();
156   auto* item = new QListWidgetItem(tr("Toolbar spacer"));
157 
158   item->setIcon(qApp->icons()->fromTheme(QSL("go-jump")));
159   item->setData(Qt::ItemDataRole::UserRole, SPACER_ACTION_NAME);
160   m_ui->m_listActivatedActions->insertItem(current_row + 1, item);
161   m_ui->m_listActivatedActions->setCurrentRow(current_row + 1);
162   emit setupChanged();
163 }
164 
insertSeparator()165 void ToolBarEditor::insertSeparator() {
166   const int current_row = m_ui->m_listActivatedActions->currentRow();
167   QListWidgetItem* item = new QListWidgetItem(tr("Separator"));
168 
169   item->setData(Qt::ItemDataRole::UserRole, SEPARATOR_ACTION_NAME);
170   item->setToolTip(tr("Separator"));
171   item->setIcon(qApp->icons()->fromTheme(QSL("insert-object")));
172   m_ui->m_listActivatedActions->insertItem(current_row + 1, item);
173   m_ui->m_listActivatedActions->setCurrentRow(current_row + 1);
174   emit setupChanged();
175 }
176 
moveActionDown()177 void ToolBarEditor::moveActionDown() {
178   QList<QListWidgetItem*> items = m_ui->m_listActivatedActions->selectedItems();
179 
180   if (items.size() == 1 && m_ui->m_listActivatedActions->currentRow() < m_ui->m_listActivatedActions->count() - 1) {
181     QListWidgetItem* selected_item = items.at(0);
182     int row = m_ui->m_listActivatedActions->row(selected_item);
183 
184     m_ui->m_listActivatedActions->takeItem(row++);
185     m_ui->m_listActivatedActions->insertItem(row, selected_item);
186     m_ui->m_listActivatedActions->setCurrentRow(row);
187     emit setupChanged();
188   }
189 }
190 
moveActionUp()191 void ToolBarEditor::moveActionUp() {
192   QList<QListWidgetItem*> items = m_ui->m_listActivatedActions->selectedItems();
193 
194   if (items.size() == 1 && m_ui->m_listActivatedActions->currentRow() > 0) {
195     QListWidgetItem* selected_item = items.at(0);
196     int row = m_ui->m_listActivatedActions->row(selected_item);
197 
198     m_ui->m_listActivatedActions->takeItem(row--);
199     m_ui->m_listActivatedActions->insertItem(row, selected_item);
200     m_ui->m_listActivatedActions->setCurrentRow(row);
201     emit setupChanged();
202   }
203 }
204 
addSelectedAction()205 void ToolBarEditor::addSelectedAction() {
206   QList<QListWidgetItem*> items = m_ui->m_listAvailableActions->selectedItems();
207 
208   if (items.size() == 1) {
209     QListWidgetItem* selected_item = items.at(0);
210 
211     m_ui->m_listActivatedActions->insertItem(
212       m_ui->m_listActivatedActions->currentRow() + 1,
213       m_ui->m_listAvailableActions->takeItem(m_ui->m_listAvailableActions->row(selected_item)));
214     m_ui->m_listActivatedActions->setCurrentRow(m_ui->m_listActivatedActions->currentRow() + 1);
215     emit setupChanged();
216   }
217 }
218 
deleteSelectedAction()219 void ToolBarEditor::deleteSelectedAction() {
220   QList<QListWidgetItem*> items = m_ui->m_listActivatedActions->selectedItems();
221 
222   if (items.size() == 1) {
223     QListWidgetItem* selected_item = items.at(0);
224     const QString data_item = selected_item->data(Qt::ItemDataRole::UserRole).toString();
225 
226     if (data_item == QSL(SEPARATOR_ACTION_NAME) || data_item == QSL(SPACER_ACTION_NAME)) {
227       m_ui->m_listActivatedActions->takeItem(m_ui->m_listActivatedActions->row(selected_item));
228       updateActionsAvailability();
229     }
230     else {
231       m_ui->m_listAvailableActions->insertItem(
232         m_ui->m_listAvailableActions->currentRow() + 1,
233         m_ui->m_listActivatedActions->takeItem(m_ui->m_listActivatedActions->row(selected_item)));
234       m_ui->m_listAvailableActions->sortItems(Qt::SortOrder::AscendingOrder);
235       m_ui->m_listAvailableActions->setCurrentRow(m_ui->m_listAvailableActions->currentRow() + 1);
236     }
237 
238     emit setupChanged();
239   }
240 }
241 
deleteAllActions()242 void ToolBarEditor::deleteAllActions() {
243   QListWidgetItem* taken_item;
244   QString data_item;
245 
246   while ((taken_item = m_ui->m_listActivatedActions->takeItem(0)) != nullptr) {
247     data_item = taken_item->data(Qt::ItemDataRole::UserRole).toString();
248 
249     if (data_item != QSL(SEPARATOR_ACTION_NAME) && data_item != QSL(SPACER_ACTION_NAME)) {
250       m_ui->m_listAvailableActions->insertItem(m_ui->m_listAvailableActions->currentRow() + 1, taken_item);
251     }
252   }
253 
254   m_ui->m_listAvailableActions->sortItems(Qt::SortOrder::AscendingOrder);
255   updateActionsAvailability();
256   emit setupChanged();
257 }
258