dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
modemanager.cpp
Go to the documentation of this file.
1 
13 /*
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  * for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, see <http://www.gnu.org/licenses/>
26  */
27 
28 #include "modemanager.h"
29 
30 #include "utils/mytabwidget.h"
31 #include "icore.h"
32 #include "mainwindow.h"
33 
34 #include <aggregation/aggregate.h>
35 
39 #include <coreplugin/imode.h>
41 
43 
44 #include <utils/qtcassert.h>
45 
46 #include <QtCore/QObject>
47 #include <QtCore/QDebug>
48 #include <QtCore/QSignalMapper>
49 #include <QShortcut>
50 
51 #include <QAction>
52 #include <QTabWidget>
53 #include <QVBoxLayout>
54 
55 using namespace Core;
56 using namespace Core::Internal;
57 
58 ModeManager *ModeManager::m_instance = nullptr;
59 
61  : m_mainWindow(mainWindow)
62  , m_modeStack(modeStack)
63  , m_signalMapper(new QSignalMapper(this))
64  , m_isReprioritizing(false)
65 {
66  m_instance = this;
67 
68  // connect((m_modeStack), SIGNAL(currentAboutToShow(int)),
69  // SLOT(currentTabAboutToChange(int)));
70  connect(m_modeStack, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged(int)));
71  connect(m_modeStack, SIGNAL(tabMoved(int, int)), this, SLOT(tabMoved(int, int)));
72  connect(m_signalMapper, SIGNAL(mapped(QString)), this, SLOT(activateMode(QString)));
73 }
74 
76 {
77  QObject::connect(ExtensionSystem::PluginManager::instance(), SIGNAL(objectAdded(QObject *)),
78  this, SLOT(objectAdded(QObject *)));
79  QObject::connect(ExtensionSystem::PluginManager::instance(),
80  SIGNAL(aboutToRemoveObject(QObject *)), this,
81  SLOT(aboutToRemoveObject(QObject *)));
82 }
83 
84 void ModeManager::addWidget(QWidget *widget)
85 {
86  Q_UNUSED(widget);
87 
88  // We want the actionbar to stay on the bottom
89  // so m_modeStack->cornerWidgetCount() -1 inserts it at the position immediately above
90  // the actionbar
91  // m_modeStack->insertCornerWidget(m_modeStack->cornerWidgetCount() -1, widget);
92 }
93 
95 {
96  if (m_modes.count() > m_modeStack->currentIndex())
97  return m_modes.at(m_modeStack->currentIndex());
98  else
99  m_modeStack->setCurrentIndex(0); // Fix illegal Index.
100  return nullptr;
101 }
102 
103 int ModeManager::indexOf(const QString &id) const
104 {
105  for (int i = 0; i < m_modes.count(); ++i) {
106  if (m_modes.at(i)->uniqueModeName() == id)
107  return i;
108  }
109  // qDebug() << "Warning, no such mode:" << id;
110  return -1;
111 }
112 
113 IMode *ModeManager::mode(const QString &id) const
114 {
115  const int index = indexOf(id);
116  if (index >= 0)
117  return m_modes.at(index);
118  return nullptr;
119 }
120 
121 void ModeManager::activateMode(const QString &id)
122 {
123  const int index = indexOf(id);
124  if (index >= 0)
125  m_modeStack->setCurrentIndex(index);
126 }
127 
129 {
130  for (int i = 0; i < m_modes.count(); ++i) {
131  if (m_modes.at(i)->name() == id) {
132  m_modeStack->setCurrentIndex(i);
133  return;
134  }
135  }
136 }
137 
138 void ModeManager::objectAdded(QObject *obj)
139 {
140  IMode *mode = Aggregation::query<IMode>(obj);
141  if (!mode)
142  return;
143 
144  m_mainWindow->addContextObject(mode);
145 
146  // Count the number of modes with a higher priority
147  int index = 0;
148  foreach (const IMode *m, m_modes)
149  if (m->priority() > mode->priority())
150  ++index;
151 
152  m_modes.insert(index, mode);
153  m_modeStack->insertTab(index, mode->widget(), mode->icon(), mode->name());
154 
155  // Register mode shortcut
156  ActionManager *am = m_mainWindow->actionManager();
157  const QString shortcutId = QLatin1String("GCS.Mode.") + mode->uniqueModeName();
158  QShortcut *shortcut = new QShortcut(m_mainWindow);
159  shortcut->setWhatsThis(tr("Switch to %1 mode").arg(mode->name()));
160  Command *cmd =
161  am->registerShortcut(shortcut, shortcutId, QList<int>() << Constants::C_GLOBAL_ID);
162 
163  m_modeShortcuts.insert(index, cmd);
164  connect(cmd, SIGNAL(keySequenceChanged()), this, SLOT(updateModeToolTip()));
165 
166  setDefaultKeyshortcuts();
167 
168  m_signalMapper->setMapping(shortcut, mode->uniqueModeName());
169  connect(shortcut, SIGNAL(activated()), m_signalMapper, SLOT(map()));
170 
171  emit modesChanged();
172 }
173 
174 void ModeManager::setDefaultKeyshortcuts()
175 {
176  for (int i = 0; i < m_modeShortcuts.size(); ++i) {
177  Command *currentCmd = m_modeShortcuts.at(i);
178  bool currentlyHasDefaultSequence =
179  (currentCmd->keySequence() == currentCmd->defaultKeySequence());
180 #ifdef Q_OS_MAC
181  currentCmd->setDefaultKeySequence(QKeySequence(QString("Meta+%1").arg(i + 1)));
182 #else
183  currentCmd->setDefaultKeySequence(QKeySequence(QString("Ctrl+%1").arg(i + 1)));
184 #endif
185  if (currentlyHasDefaultSequence)
186  currentCmd->setKeySequence(currentCmd->defaultKeySequence());
187  }
188 }
189 
190 void ModeManager::updateModeToolTip()
191 {
192  Command *cmd = qobject_cast<Command *>(sender());
193  if (cmd) {
194  int index = m_modeShortcuts.indexOf(cmd);
195  if (index != -1)
196  m_modeStack->setTabToolTip(
197  index, cmd->stringWithAppendedShortcut(cmd->shortcut()->whatsThis()));
198  }
199 }
200 
201 void ModeManager::updateModeNameIcon(IMode *mode, const QIcon &icon, const QString &label)
202 {
203  int index = indexOf(mode->uniqueModeName());
204  if (index < 0)
205  return;
206  m_modeStack->setTabIcon(index, icon);
207  m_modeStack->setTabText(index, label);
208 }
209 
210 void ModeManager::aboutToRemoveObject(QObject *obj)
211 {
212  IMode *mode = Aggregation::query<IMode>(obj);
213  if (!mode)
214  return;
215 
216  const int index = m_modes.indexOf(mode);
217  m_modes.remove(index);
218  m_modeShortcuts.remove(index);
219  disconnect(m_modeStack, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged(int)));
220  m_modeStack->removeTab(index);
221  connect(m_modeStack, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged(int)));
222 
223  m_mainWindow->removeContextObject(mode);
224 
225  emit modesChanged();
226 }
227 
228 void ModeManager::addAction(Command *command, int priority, QMenu *menu)
229 {
230  Q_UNUSED(menu);
231 
232  m_actions.insert(command, priority);
233 
234  // Count the number of commands with a higher priority
235  int index = 0;
236  foreach (int p, m_actions.values())
237  if (p > priority)
238  ++index;
239 
240  // m_actionBar->insertAction(index, command->action(), menu);
241 }
242 
243 void ModeManager::currentTabAboutToChange(int index)
244 {
245  if (index >= 0) {
246  IMode *mode = m_modes.at(index);
247  if (mode)
248  emit currentModeAboutToChange(mode);
249  }
250 }
251 
252 void ModeManager::currentTabChanged(int index)
253 {
254  // qDebug() << "Current tab changed " << index;
255  // Tab index changes to -1 when there is no tab left.
256  if (index >= 0) {
257  IMode *mode = m_modes.at(index);
258 
259  // FIXME: This hardcoded context update is required for the Debug and Edit modes, since
260  // they use the editor widget, which is already a context widget so the main window won't
261  // go further up the parent tree to find the mode context.
262  ICore *core = ICore::instance();
263  foreach (const int context, m_addedContexts)
264  core->removeAdditionalContext(context);
265 
266  m_addedContexts = mode->context();
267  foreach (const int context, m_addedContexts)
268  core->addAdditionalContext(context);
269  emit currentModeChanged(mode);
270  core->updateContext();
271  }
272 }
273 
274 void ModeManager::tabMoved(int from, int to)
275 {
276  IMode *mode = m_modes.at(from);
277  m_modes.remove(from);
278  m_modes.insert(to, mode);
279  Command *cmd = m_modeShortcuts.at(from);
280  m_modeShortcuts.remove(from);
281  m_modeShortcuts.insert(to, cmd);
282  setDefaultKeyshortcuts();
283  // Reprioritize, high priority means show to the left
284  if (!m_isReprioritizing) {
285  for (int i = 0; i < m_modes.count(); ++i) {
286  m_modes.at(i)->setPriority(100 - i);
287  }
288  emit newModeOrder(m_modes);
289  }
290 }
291 
292 void ModeManager::reorderModes(QMap<QString, int> priorities)
293 {
294  foreach (IMode *mode, m_modes)
295  mode->setPriority(
296  priorities.value(QString(QLatin1String(mode->uniqueModeName())), mode->priority()));
297 
298  m_isReprioritizing = true;
299  IMode *current = currentMode();
300  // Bubble sort
301  bool swapped = false;
302  do {
303  swapped = false;
304  for (int i = 0; i < m_modes.count() - 1; ++i) {
305  IMode *mode1 = m_modes.at(i);
306  IMode *mode2 = m_modes.at(i + 1);
307  // qDebug() << "Comparing " << i << " to " << i+1 << " p1 " <<
308  // mode1->priority() << " p2 " << mode2->priority();
309  if (mode2->priority() > mode1->priority()) {
310  m_modeStack->moveTab(i, i + 1);
311  // qDebug() << "Tab moved from " << i << " to " << i+1;
312  swapped = true;
313  }
314  }
315  } while (swapped);
316  m_isReprioritizing = false;
317  m_modeStack->setCurrentIndex(0);
318  activateMode(current->uniqueModeName());
319  emit newModeOrder(m_modes);
320 }
321 
323 {
324  IMode *mode = currentMode();
325  QTC_ASSERT(mode, return );
326  QWidget *widget = mode->widget();
327  if (widget) {
328  QWidget *focusWidget = widget->focusWidget();
329  if (focusWidget)
330  focusWidget->setFocus();
331  else
332  widget->setFocus();
333  }
334 }
335 
336 void ModeManager::triggerAction(const QString &actionId)
337 {
338  foreach (Command *command, m_actions.keys()) {
339  if (command->action()->objectName() == actionId) {
340  command->action()->trigger();
341  break;
342  }
343  }
344 }
void setFocusToCurrentMode()
virtual QString stringWithAppendedShortcut(const QString &str) const =0
virtual QIcon icon() const =0
ModeManager(Internal::MainWindow *mainWindow, MyTabWidget *modeStack)
Definition: modemanager.cpp:60
virtual int priority() const =0
virtual QAction * action() const =0
void currentModeAboutToChange(Core::IMode *mode)
The ICore class allows access to the different part that make up the basic functionality of the GCS...
Definition: icore.h:58
for i
Definition: OPPlots.m:140
IMode * mode(const QString &id) const
virtual QKeySequence keySequence() const =0
IMode * currentMode() const
Definition: modemanager.cpp:94
void addAction(Command *command, int priority, QMenu *menu=nullptr)
virtual QString name() const =0
void addWidget(QWidget *widget)
Definition: modemanager.cpp:84
virtual const char * uniqueModeName() const =0
const int C_GLOBAL_ID
Definition: coreconstants.h:90
virtual void setPriority(int priority)=0
void activateModeByWorkspaceName(const QString &id)
void moveTab(int from, int to)
Definition: mytabwidget.cpp:37
static ICore * instance()
Definition: coreimpl.cpp:46
void updateModeNameIcon(IMode *mode, const QIcon &icon, const QString &label)
virtual void addAdditionalContext(int context)=0
Register additional context to be currently active.
virtual void updateContext()=0
Update the list of active contexts after adding or removing additional ones.
virtual QShortcut * shortcut() const =0
virtual void setKeySequence(const QKeySequence &key)=0
virtual void setDefaultKeySequence(const QKeySequence &key)=0
The action manager is responsible for registration of menus and menu items and keyboard shortcuts...
Definition: actionmanager.h:47
virtual QList< int > context() const =0
virtual Command * registerShortcut(QShortcut *shortcut, const QString &id, const QList< int > &context)=0
Makes a shortcut known to the system under the specified string id.
virtual QKeySequence defaultKeySequence() const =0
virtual void removeAdditionalContext(int context)=0
Removes the given context from the list of currently active contexts.
virtual QWidget * widget()=0
void activateMode(const QString &id)
void currentModeChanged(Core::IMode *mode)
void newModeOrder(QVector< IMode * > modes)
void reorderModes(QMap< QString, int > priorities)
void addContextObject(IContext *contex)
Definition: mainwindow.cpp:985
void removeContextObject(IContext *contex)
Definition: mainwindow.cpp:996
The class Command represents an action like a menu item, tool button, or shortcut. You don't create Command objects directly, instead use {ActionManager::registerAction()} to register an action and retrieve a Command. The Command object represents the user visible action and its properties. If multiple actions are registered with the same ID (but different contexts) the returned Command is the shared one between these actions.
Definition: command.h:43
void triggerAction(const QString &actionId)
Core::ActionManager * actionManager() const
Definition: mainwindow.cpp:927