ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvPluginUIManager.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "ecvPluginUIManager.h"
9 
10 #include <QAction>
11 #include <QMenu>
12 #include <QToolBar>
13 #include <QWidget>
14 
15 #include "ecvConsole.h"
16 #include "ecvDisplayTools.h"
17 #include "ecvIOPluginInterface.h"
18 #include "ecvMainAppInterface.h"
19 #include "ecvPclPluginInterface.h"
20 #include "ecvPluginInfoDlg.h"
21 #include "ecvPluginManager.h"
22 #include "ecvStdPluginInterface.h"
23 
25  QWidget *parent)
26  : QObject(parent),
27  m_parentWidget(parent),
28  m_appInterface(appInterface),
29  m_pluginMenu(nullptr),
30  m_pclAlgorithmMenu(nullptr),
31  m_actionRemovePCLAlgorithm(nullptr),
32  m_pclAlgorithmActions(this),
33  m_mainPluginToolbar(nullptr),
34  m_showPluginToolbar(nullptr),
35  m_pclAlgorithmsToolbar(nullptr),
36  m_showPCLAlgorithmToolbar(nullptr) {
37  setupActions();
38  setupMenus();
39  setupToolbars();
40 }
41 
43 
45  auto plugins = ccPluginManager::get().pluginList();
46 
47  m_pluginMenu->setEnabled(false);
48  m_pclAlgorithmMenu->setEnabled(false);
49 
50  m_mainPluginToolbar->setVisible(false);
51 
52  QVector<ccStdPluginInterface *> coreStdPlugins;
53  QVector<ccStdPluginInterface *> thirdPartyStdPlugins;
54 
55  QVector<ccPclPluginInterface *> corePCLPlugins;
56  QVector<ccPclPluginInterface *> thirdPartyPCLPlugins;
57 
58  for (ccPluginInterface *plugin : plugins) {
59  if (plugin == nullptr) {
60  Q_ASSERT(false);
61  continue;
62  }
63 
64  if (!ccPluginManager::get().isEnabled(plugin)) {
65  m_plugins.push_back(plugin);
66 
67  continue;
68  }
69 
70  const QString pluginName = plugin->getName();
71 
72  Q_ASSERT(!pluginName.isEmpty());
73 
74  if (pluginName.isEmpty()) {
75  // should be unreachable - we have already checked for this in
76  // ecvPlugins::Find()
77  continue;
78  }
79 
80  switch (plugin->getType()) {
81  case ECV_STD_PLUGIN: // standard plugin
82  {
83  ccStdPluginInterface *stdPlugin =
84  static_cast<ccStdPluginInterface *>(plugin);
85 
86  stdPlugin->setMainAppInterface(m_appInterface);
87 
88  if (stdPlugin->isCore()) {
89  coreStdPlugins.append(stdPlugin);
90  } else {
91  thirdPartyStdPlugins.append(stdPlugin);
92  }
93 
94  m_plugins.push_back(stdPlugin);
95 
96  break;
97  }
98 
99  case ECV_PCL_ALGORITHM_PLUGIN: // pcl algorithm
100  {
101  ccPclPluginInterface *pclPlugin =
102  static_cast<ccPclPluginInterface *>(plugin);
103 
104  pclPlugin->setMainAppInterface(m_appInterface);
105 
106  QAction *action = new QAction(pluginName, this);
107 
108  action->setToolTip(pclPlugin->getDescription());
109  action->setIcon(pclPlugin->getIcon());
110  action->setCheckable(true);
111 
112  // store the plugin's interface pointer in the QAction data so
113  // we can access it in enablePCLAlgorithm()
114  QVariant v;
115 
116  v.setValue(pclPlugin);
117 
118  action->setData(v);
119 
120  connect(action, &QAction::triggered, this,
121  &ccPluginUIManager::enablePCLAlgorithm);
122 
123  m_pclAlgorithmActions.addAction(action);
124 
125  if (pclPlugin->isCore()) {
126  corePCLPlugins.append(pclPlugin);
127  } else {
128  thirdPartyPCLPlugins.append(pclPlugin);
129  }
130 
131  m_plugins.push_back(pclPlugin);
132  break;
133  }
134 
135  case ECV_IO_FILTER_PLUGIN: {
136  ccIOPluginInterface *ioPlugin =
137  static_cast<ccIOPluginInterface *>(plugin);
138 
139  // there are no menus or toolbars for I/O plugins
140  m_plugins.push_back(ioPlugin);
141  break;
142  }
143  }
144  }
145 
146  // add core standard plugins to menu & tool bar
147  for (ccStdPluginInterface *plugin : coreStdPlugins) {
148  QList<QAction *> actions = plugin->getActions();
149 
150  addActionsToMenu(plugin, actions);
151  addActionsToToolBar(plugin, actions);
152 
153  plugin->onNewSelection(m_appInterface->getSelectedEntities());
154  }
155 
156  // add 3rd standard party plugins to menu & tool bar (if any )
157  if (!thirdPartyStdPlugins.isEmpty()) {
158  m_pluginMenu->addSection("3rd std Party");
159 
160  for (ccStdPluginInterface *plugin : thirdPartyStdPlugins) {
161  QList<QAction *> actions = plugin->getActions();
162 
163  addActionsToMenu(plugin, actions);
164  addActionsToToolBar(plugin, actions);
165 
166  plugin->onNewSelection(m_appInterface->getSelectedEntities());
167  }
168  }
169 
170  // add core PCL plugins to menu & tool bar
171  for (ccPclPluginInterface *plugin : corePCLPlugins) {
172  QVector<QList<QAction *>> allModuleActions = plugin->getActions();
173  QVector<QString> moduleNames = plugin->getModuleNames();
174  assert(allModuleActions.size() == moduleNames.size());
175 
176  if (!plugin->getName().isEmpty()) {
177  m_pclAlgorithmMenu->setTitle(plugin->getName());
178  }
179 
180  for (int i = 0; i < moduleNames.size(); ++i) {
181  addActionsToMenu(moduleNames[i], allModuleActions[i]);
182  addActionsToToolBar(moduleNames[i], allModuleActions[i]);
183  }
184  plugin->onNewSelection(m_appInterface->getSelectedEntities());
185  }
186 
187  // add 3rd PCL party plugins to menu & tool bar (if any )
188  if (!thirdPartyPCLPlugins.isEmpty()) {
189  m_pclAlgorithmMenu->addSection("3rd pcl Party");
190 
191  for (ccPclPluginInterface *plugin : thirdPartyPCLPlugins) {
192  QVector<QList<QAction *>> allModuleActions = plugin->getActions();
193  QVector<QString> moduleNames = plugin->getModuleNames();
194  assert(allModuleActions.size() == moduleNames.size());
195 
196  for (int i = 0; i < moduleNames.size(); ++i) {
197  addActionsToMenu(moduleNames[i], allModuleActions[i]);
198  addActionsToToolBar(moduleNames[i], allModuleActions[i]);
199  }
200 
201  plugin->onNewSelection(m_appInterface->getSelectedEntities());
202  }
203  }
204 
205  m_pluginMenu->setEnabled(!m_pluginMenu->isEmpty());
206 
207  if (m_mainPluginToolbar->isEnabled()) {
208  m_showPluginToolbar->setEnabled(true);
209  }
210 
211  m_pclAlgorithmMenu->setEnabled(!m_pclAlgorithmMenu->isEmpty());
212  m_pclAlgorithmsToolbar->setEnabled(
213  !m_pclAlgorithmMenu->isEmpty()); // [sic] we have toolbar actions
214  // if we have them in the menu
215 
216  m_showPluginToolbar->setChecked(m_mainPluginToolbar->isEnabled());
217 
218  if (m_pclAlgorithmsToolbar->isEnabled()) {
219  m_showPCLAlgorithmToolbar->setEnabled(true);
220  }
221 
222  m_showPCLAlgorithmToolbar->setChecked(m_pclAlgorithmsToolbar->isEnabled());
223 }
224 
225 QMenu *ccPluginUIManager::pluginMenu() const { return m_pluginMenu; }
226 
228  return m_pclAlgorithmMenu;
229 }
230 
231 QToolBar *ccPluginUIManager::mainPluginToolbar() { return m_mainPluginToolbar; }
232 
234  return m_additionalPluginToolbars;
235 }
236 
238  return m_showPluginToolbar;
239 }
240 
241 QToolBar *ccPluginUIManager::glPclToolbar() { return m_pclAlgorithmsToolbar; }
242 
244  return m_showPCLAlgorithmToolbar;
245 }
246 
248  if (!toolbar) {
249  return false;
250  }
251  // Python plugin name is "Python Plugin" (from info.json)
252  return toolbar->objectName() == "Python Plugin";
253 }
254 
256  QWidget *active3DView = m_appInterface->getActiveWindow();
257  const bool hasActiveView = (active3DView != nullptr);
258 
259  const QList<QAction *> actionList = m_pclAlgorithmActions.actions();
260 
261  for (QAction *action : actionList) {
262  action->setEnabled(hasActiveView);
263  }
264 }
265 
267  const ccHObject::Container &selectedEntities =
268  m_appInterface->getSelectedEntities();
269 
270  for (ccPluginInterface *plugin : m_plugins) {
271  if (plugin->getType() == ECV_STD_PLUGIN) {
272  ccStdPluginInterface *stdPlugin =
273  static_cast<ccStdPluginInterface *>(plugin);
274 
275  stdPlugin->onNewSelection(selectedEntities);
276  } else if (plugin->getType() == ECV_PCL_ALGORITHM_PLUGIN) {
277  ccPclPluginInterface *pclPlugin =
278  static_cast<ccPclPluginInterface *>(plugin);
279 
280  pclPlugin->onNewSelection(selectedEntities);
281  }
282  }
283 }
284 
286  ccPluginInfoDlg about;
287 
288  about.setPluginPaths(ccPluginManager::get().pluginPaths());
289  about.setPluginList(m_plugins);
290 
291  about.exec();
292 }
293 
294 void ccPluginUIManager::setupActions() {
295  // m_actionRemovePCLAlgorithm = new
296  // QAction(QIcon(":/CC/pluginManager/images/noAlgorithm.png"), tr("Remove
297  // Algorithm"), this); m_actionRemovePCLAlgorithm->setEnabled(false);
298  // connect(m_actionRemovePCLAlgorithm, &QAction::triggered, this,
299  // &ccPluginUIManager::disablePCLAlgorithm);
300 
301  m_showPluginToolbar = new QAction(tr("Plugins"), this);
302  m_showPluginToolbar->setCheckable(true);
303  m_showPluginToolbar->setEnabled(false);
304 
305  m_showPCLAlgorithmToolbar = new QAction(tr("PCL Algorithm"), this);
306  m_showPCLAlgorithmToolbar->setCheckable(true);
307  m_showPCLAlgorithmToolbar->setEnabled(false);
308 }
309 
310 void ccPluginUIManager::setupMenus() {
311  m_pluginMenu = new QMenu(tr("Plugins"), m_parentWidget);
312  m_pclAlgorithmMenu = new QMenu(tr("PCL ALgorithms"), m_parentWidget);
313 }
314 
315 void ccPluginUIManager::addActionsToMenu(ccStdPluginInterface *stdPlugin,
316  const QList<QAction *> &actions) {
317  // If the plugin has more than one action we create its own menu
318  if (actions.size() > 1) {
319  QMenu *menu = new QMenu(stdPlugin->getName(), m_parentWidget);
320 
321  menu->setIcon(stdPlugin->getIcon());
322  menu->setEnabled(true);
323 
324  for (QAction *action : actions) {
325  menu->addAction(action);
326  }
327 
328  m_pluginMenu->addMenu(menu);
329  } else // otherwise we just add it to the main menu
330  {
331  Q_ASSERT(actions.count() == 1);
332 
333  m_pluginMenu->addAction(actions.at(0));
334  }
335 }
336 
337 void ccPluginUIManager::addActionsToToolBar(ccStdPluginInterface *stdPlugin,
338  const QList<QAction *> &actions) {
339  const QString pluginName = stdPlugin->getName();
340 
341  // If the plugin has more than one action we create its own tool bar
342  if (actions.size() > 1) {
343  QToolBar *toolBar = new QToolBar(
344  pluginName + QStringLiteral(" toolbar"), m_parentWidget);
345 
346  if (toolBar != nullptr) {
347  m_additionalPluginToolbars.push_back(toolBar);
348 
349  toolBar->setObjectName(pluginName);
350  toolBar->setEnabled(true);
351 
352  for (QAction *action : actions) {
353  toolBar->addAction(action);
354  }
355  }
356  } else // otherwise we just add it to the main tool bar
357  {
358  Q_ASSERT(actions.count() == 1);
359 
360  m_mainPluginToolbar->addAction(actions.at(0));
361  }
362 }
363 
364 void ccPluginUIManager::addActionsToMenu(const QString &moduleName,
365  const QList<QAction *> &actions) {
366  // If the plugin has more than one action we create its own menu
367  if (actions.size() > 1) {
368  QMenu *menu = new QMenu(moduleName, m_parentWidget);
369  menu->setEnabled(true);
370 
371  for (QAction *action : actions) {
372  menu->addAction(action);
373  }
374 
375  m_pclAlgorithmMenu->addMenu(menu);
376  } else // otherwise we just add it to the main menu
377  {
378  Q_ASSERT(actions.count() == 1);
379 
380  m_pclAlgorithmMenu->addAction(actions.at(0));
381  }
382 }
383 
384 void ccPluginUIManager::addActionsToToolBar(const QString &moduleName,
385  const QList<QAction *> &actions) {
386  // If the plugin has more than one action we create its own tool bar
387  if (actions.size() > 1) {
388  if (m_pclAlgorithmsToolbar != nullptr) {
389  for (QAction *action : actions) {
390  m_pclAlgorithmsToolbar->addAction(action);
391  }
392  }
393  } else // otherwise we just add it to the main tool bar
394  {
395  Q_ASSERT(actions.count() == 1);
396 
397  m_pclAlgorithmsToolbar->addAction(actions.at(0));
398  }
399 }
400 
401 void ccPluginUIManager::setupToolbars() {
402  m_mainPluginToolbar = new QToolBar(tr("Plugins"), m_parentWidget);
403 
404  m_mainPluginToolbar->setObjectName(QStringLiteral("Main Plugin Toolbar"));
405 
406  connect(m_showPluginToolbar, &QAction::toggled, m_mainPluginToolbar,
407  &QToolBar::setVisible);
408 
409  m_pclAlgorithmsToolbar = new QToolBar(tr("PCL ALgorithms"), m_parentWidget);
410 
411  m_pclAlgorithmsToolbar->setObjectName(QStringLiteral("PCL Plugin Toolbar"));
412 
413  connect(m_showPCLAlgorithmToolbar, &QAction::toggled,
414  m_pclAlgorithmsToolbar, &QToolBar::setVisible);
415 }
416 
417 void ccPluginUIManager::enablePCLAlgorithm() {
418  QWidget *win = m_appInterface->getActiveWindow();
419 
420  if (win == nullptr) {
421  CVLog::Warning("[PCL ALGORITHM] No active 3D view");
422  return;
423  }
424 
425  QAction *action = qobject_cast<QAction *>(sender());
426 
427  Q_ASSERT(action != nullptr);
428 
429  ccPclPluginInterface *plugin =
430  action->data().value<ccPclPluginInterface *>();
431 
432  if (plugin == nullptr) {
433  return;
434  }
435 
436  m_actionRemovePCLAlgorithm->setEnabled(true);
437 
439  "Note: go to << PCL ALgorithms >> to disable PCL ALGORITHM");
440 }
441 
442 void ccPluginUIManager::disablePCLAlgorithm() {
443  if (m_appInterface->getActiveWindow() != nullptr) {
444  m_actionRemovePCLAlgorithm->setEnabled(false);
445  m_pclAlgorithmActions.checkedAction()->setChecked(false);
446  }
447 }
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
static bool Print(const char *format,...)
Prints out a formatted message in console.
Definition: CVLog.cpp:113
virtual QString getName() const override
Returns (short) name (for menu entry, etc.)
virtual QString getDescription() const override
Returns long name/description (for tooltip, etc.)
virtual QIcon getIcon() const override
Returns icon.
virtual bool isCore() const override
Is this plugin a core plugin?
std::vector< ccHObject * > Container
Standard instances container (for children, etc.)
Definition: ecvHObject.h:337
I/O filter plugin interface.
Pcl ECV plugin interface.
virtual void onNewSelection(const ccHObject::Container &selectedEntities)
virtual void setMainAppInterface(ecvMainAppInterface *app)
Sets application entry point.
void setPluginPaths(const QStringList &pluginPaths)
void setPluginList(const QList< ccPluginInterface * > &pluginList)
Standard ECV plugin interface.
ccPluginInterfaceList & pluginList()
static ccPluginManager & get()
void showAboutDialog() const
QList< QToolBar * > & additionalPluginToolbars()
QToolBar * mainPluginToolbar()
QMenu * pluginMenu() const
QMenu * pclAlgorithmMenu() const
ccPluginUIManager(ecvMainAppInterface *appInterface, QWidget *parent)
QAction * actionShowPCLAlgorithmToolbar()
static bool isPythonPluginToolbar(QToolBar *toolbar)
QAction * actionShowMainPluginToolbar()
Standard ECV plugin interface.
virtual void setMainAppInterface(ecvMainAppInterface *app)
Sets application entry point.
virtual void onNewSelection(const ccHObject::Container &selectedEntities)
Main application interface (for plugins)
virtual QWidget * getActiveWindow()=0
virtual const ccHObject::Container & getSelectedEntities() const =0
Returns currently selected entities ("read only")
@ ECV_STD_PLUGIN
@ ECV_IO_FILTER_PLUGIN
@ ECV_PCL_ALGORITHM_PLUGIN