window.cpp 14.1 KB
Newer Older
Pierre Kraemer's avatar
Pierre Kraemer committed
1
#include "window.h"
2

Pierre Kraemer's avatar
Pierre Kraemer committed
3
4
#include <QVBoxLayout>
#include <QSplitter>
5
6
7
8
#include <QMessageBox>
#include <QDockWidget>
#include <QPluginLoader>
#include <QFileInfo>
9
10
11
#include <QKeyEvent>
#include <QMouseEvent>
#include <QWheelEvent>
12

Pierre Kraemer's avatar
Pierre Kraemer committed
13
14
#include "plugin.h"
#include "view.h"
15
#include "texture.h"
16
17
#include "camera.h"
#include "mapHandler.h"
18

Pierre Kraemer's avatar
Pierre Kraemer committed
19
20
21
22
23
24
25
26
27
#include "dialogs/camerasDialog.h"
#include "dialogs/pluginsDialog.h"
#include "dialogs/mapsDialog.h"

namespace CGoGN
{

namespace SCHNApps
{
Pierre Kraemer's avatar
Pierre Kraemer committed
28

Pierre Kraemer's avatar
Pierre Kraemer committed
29
Window::Window(const QString& appPath, PythonQtObjectPtr& pythonContext) :
Pierre Kraemer's avatar
Pierre Kraemer committed
30
	QMainWindow(),
Pierre Kraemer's avatar
Pierre Kraemer committed
31
32
	m_appPath(appPath),
	m_pythonContext(pythonContext),
33
	m_firstView(NULL),
34
	m_currentView(NULL)
35
{
Pierre Kraemer's avatar
Pierre Kraemer committed
36
	// program in its initialization phase
37
38
	m_initialization = true;

Pierre Kraemer's avatar
Pierre Kraemer committed
39
40
41
	m_camerasDialog = new CamerasDialog(this);
	m_pluginsDialog = new PluginsDialog(this);
	m_mapsDialog = new MapsDialog(this);
42

43
	this->setupUi(this);
44

45
46
47
48
	m_dock = new QDockWidget(tr("Control"), this);
	m_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
	m_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable);
	addDockWidget(Qt::RightDockWidgetArea, m_dock);
Pierre Kraemer's avatar
Pierre Kraemer committed
49
	m_dock->setVisible(false);
50
51
52

	m_dockTabWidget = new QTabWidget(m_dock);
	m_dockTabWidget->setObjectName("DockTabWidget");
53
	m_dockTabWidget->setLayoutDirection(Qt::LeftToRight);
54
55
56
	m_dockTabWidget->setTabPosition(QTabWidget::East);
	m_dock->setWidget(m_dockTabWidget);

57
58
	connect(actionShowHideDock, SIGNAL(triggered()), this, SLOT(cb_showHideDock()));

Pierre Kraemer's avatar
Pierre Kraemer committed
59
60
61
62
63
	m_centralLayout = new QVBoxLayout(centralwidget);

	m_rootSplitter = new QSplitter(centralwidget);
	b_rootSplitterInitialized = false;
	m_centralLayout->addWidget(m_rootSplitter);
64

65
66
	// add first view
	m_firstView = addView();
67
	m_currentView = m_firstView;
Pierre Kraemer's avatar
Pierre Kraemer committed
68
	m_rootSplitter->addWidget(m_firstView);
69

70
71
	glewInit();

Pierre Kraemer's avatar
Pierre Kraemer committed
72
	// connect the basic actions
73
74
	connect(actionAboutSCHNApps, SIGNAL(triggered()), this, SLOT(cb_aboutSCHNApps()));
	connect(actionAboutCGoGN, SIGNAL(triggered()), this, SLOT(cb_aboutCGoGN()));
75

Pierre Kraemer's avatar
Pierre Kraemer committed
76
	connect(actionManageCameras, SIGNAL(triggered()), this, SLOT(cb_manageCameras()));
77
	connect(actionManagePlugins, SIGNAL(triggered()), this, SLOT(cb_managePlugins()));
78
	connect(actionManageMaps, SIGNAL(triggered()), this, SLOT(cb_manageMaps()));
79

80
//	System::StateHandler::loadState(this, &h_plugin, &h_scene, m_splitArea);
81

Pierre Kraemer's avatar
Pierre Kraemer committed
82
	// program in its initialization phase
83
84
	m_initialization = false;

Pierre Kraemer's avatar
Pierre Kraemer committed
85
	m_pythonContext.addObject("dock", m_dock);
Pierre Kraemer's avatar
Pierre Kraemer committed
86
87
}

88
89
Window::~Window()
{
90
//	System::StateHandler::saveState(this, h_plugins);
91
92
}

Pierre Kraemer's avatar
Pierre Kraemer committed
93
94
95
96
/*********************************************************
 * MANAGE DOCK
 *********************************************************/

97
void Window::addTabInDock(QWidget* tabWidget, const QString& tabText, bool enable)
Pierre Kraemer's avatar
Pierre Kraemer committed
98
{
99
	if(tabWidget)
100
	{
101
102
		int currentTab = m_dockTabWidget->currentIndex();

103
		int idx = m_dockTabWidget->addTab(tabWidget, tabText);
Pierre Kraemer's avatar
Pierre Kraemer committed
104
		m_dock->setVisible(true);
105
		m_dockTabWidget->setTabEnabled(idx, enable);
106
107
108

		if(currentTab != -1)
			m_dockTabWidget->setCurrentIndex(currentTab);
109
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
110
111
112
113
}

void Window::removeTabInDock(QWidget *tabWidget)
{
114
	if(tabWidget)
Pierre Kraemer's avatar
Pierre Kraemer committed
115
116
117
		m_dockTabWidget->removeTab(m_dockTabWidget->indexOf(tabWidget));
}

118
119
void Window::enablePluginTabWidgets(Plugin* plugin)
{
120
121
	int currentTab = m_dockTabWidget->currentIndex();

122
123
	const QList<QWidget*> tabWidgets = plugin->getTabWidgets();
	foreach(QWidget* w, tabWidgets)
124
125
126
		m_dockTabWidget->setTabEnabled(m_dockTabWidget->indexOf(w), true);

	m_dockTabWidget->setCurrentIndex(currentTab);
127
128
129
130
}

void Window::disablePluginTabWidgets(Plugin* plugin)
{
131
132
	int currentTab = m_dockTabWidget->currentIndex();

133
134
	const QList<QWidget*> tabWidgets = plugin->getTabWidgets();
	foreach(QWidget* w, tabWidgets)
135
136
137
		m_dockTabWidget->setTabEnabled(m_dockTabWidget->indexOf(w), false);

	m_dockTabWidget->setCurrentIndex(currentTab);
138
139
}

Pierre Kraemer's avatar
Pierre Kraemer committed
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*********************************************************
 * MANAGE MENU ACTIONS
 *********************************************************/

bool Window::addMenuAction(const QString& menuPath, QAction* action)
{
	// if menu path = empty string: set error + failure
	if (menuPath.isEmpty())
		return false;

	if (!action)
		return false;

	// extracting all the substring separated by ';'
	QStringList stepNames = menuPath.split(";");
	stepNames.removeAll("");
	unsigned int nbStep = stepNames.count();

	// if only one substring: error + failure
	// No action directly in the menu bar
	if (nbStep < 1)
		return false;

	unsigned int i = 0;
164
	QMenu* lastMenu = NULL;
Pierre Kraemer's avatar
Pierre Kraemer committed
165
166
167
	foreach(QString step, stepNames)
	{
		++i;
168
		if (i < nbStep) // if not last substring (= menu)
Pierre Kraemer's avatar
Pierre Kraemer committed
169
		{
170
171
172
173
174
175
			// try to find an existing submenu with step name
			bool found = false;
			QList<QAction*> actions;
			if(i == 1) actions = menubar->actions();
			else actions = lastMenu->actions();
			foreach(QAction* action, actions)
Pierre Kraemer's avatar
Pierre Kraemer committed
176
			{
177
178
				QMenu* submenu = action->menu();
				if (submenu && submenu->title() == step)
Pierre Kraemer's avatar
Pierre Kraemer committed
179
				{
180
181
182
					lastMenu = submenu;
					found = true;
					break;
Pierre Kraemer's avatar
Pierre Kraemer committed
183
184
				}
			}
185
			if (!found)
Pierre Kraemer's avatar
Pierre Kraemer committed
186
			{
187
				QMenu* newMenu;
188
189
190
191
192
193
194
195
196
197
				if(i == 1)
				{
					newMenu = menubar->addMenu(step);
					newMenu->setParent(menubar);
				}
				else
				{
					newMenu = lastMenu->addMenu(step);
					newMenu->setParent(lastMenu);
				}
198
				lastMenu = newMenu;
Pierre Kraemer's avatar
Pierre Kraemer committed
199
200
			}
		}
201
		else // if last substring (= action name)
Pierre Kraemer's avatar
Pierre Kraemer committed
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
		{
			lastMenu->addAction(action);
			action->setText(step);
			action->setParent(lastMenu);
		}
	}

	return true;
}

void Window::removeMenuAction(QAction *action)
{
	if(action)
	{
		action->setEnabled(false);
		// parent of the action
		// which is an instance of QMenu if the action was created
		// using the addMenuActionMethod()
		QObject* parent = action->parent();
		delete action;

223
		while(parent != NULL)
Pierre Kraemer's avatar
Pierre Kraemer committed
224
		{
225
226
			QMenu* parentMenu = dynamic_cast<QMenu*>(parent);
			if(parentMenu && parentMenu->actions().empty())
Pierre Kraemer's avatar
Pierre Kraemer committed
227
228
			{
				parent = parent->parent();
229
				delete parentMenu;
Pierre Kraemer's avatar
Pierre Kraemer committed
230
			}
231
232
			else
				parent = NULL;
Pierre Kraemer's avatar
Pierre Kraemer committed
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
		}
	}
}

/*********************************************************
 * MANAGE TOOLBAR ACTIONS
 *********************************************************/

bool Window::addToolbarAction(QAction* action)
{
	if (action)
	{
		toolBar->addAction(action);
		return true;
	}
	return false;
}

void Window::removeToolbarAction(QAction* action)
{
	if (action)
		toolBar->removeAction(action);
}

/*********************************************************
258
 * MANAGE CAMERAS
Pierre Kraemer's avatar
Pierre Kraemer committed
259
260
 *********************************************************/

261
Camera* Window::addCamera(const QString& name)
Pierre Kraemer's avatar
Pierre Kraemer committed
262
{
263
	if (h_cameras.contains(name))
264
265
		return NULL;

266
267
	Camera* camera = new Camera(name, this);
	h_cameras.insert(name, camera);
Pierre Kraemer's avatar
Pierre Kraemer committed
268

269
	emit(cameraAdded(camera));
Pierre Kraemer's avatar
Pierre Kraemer committed
270

271
272
	return camera;
}
Pierre Kraemer's avatar
Pierre Kraemer committed
273

274
275
276
Camera* Window::addCamera()
{
	return addCamera(QString("camera_") + QString::number(Camera::cameraCount));
Pierre Kraemer's avatar
Pierre Kraemer committed
277
278
}

279
void Window::removeCamera(const QString& name)
Pierre Kraemer's avatar
Pierre Kraemer committed
280
{
281
	if (h_cameras.contains(name))
Pierre Kraemer's avatar
Pierre Kraemer committed
282
	{
283
284
		Camera* camera = h_cameras[name];
		h_cameras.remove(name);
Pierre Kraemer's avatar
Pierre Kraemer committed
285

286
		emit(cameraRemoved(camera));
Pierre Kraemer's avatar
Pierre Kraemer committed
287

288
		delete camera;
289
290
	}
}
Pierre Kraemer's avatar
Pierre Kraemer committed
291

292
Camera* Window::getCamera(const QString& name) const
Pierre Kraemer's avatar
Pierre Kraemer committed
293
{
294
295
	if (h_cameras.contains(name))
		return h_cameras[name];
Pierre Kraemer's avatar
Pierre Kraemer committed
296
297
298
299
	else
		return NULL;
}

300
301
302
/*********************************************************
 * MANAGE VIEWS
 *********************************************************/
Pierre Kraemer's avatar
Pierre Kraemer committed
303

304
View* Window::addView(const QString& name)
305
{
306
307
	if (h_views.contains(name))
		return NULL;
308

309
310
	View* view = NULL;
	if(m_firstView == NULL)
Pierre Kraemer's avatar
Pierre Kraemer committed
311
		view = new View(name, this);
312
	else
Pierre Kraemer's avatar
Pierre Kraemer committed
313
		view = new View(name, this, m_firstView);
314
	h_views.insert(name, view);
Pierre Kraemer's avatar
Pierre Kraemer committed
315

316
317
	emit(viewAdded(view));

318
	return view;
319
320
}

321
322
323
324
325
View* Window::addView()
{
	return addView(QString("view_") + QString::number(View::viewCount));
}

326
void Window::removeView(const QString& name)
327
{
328
	if (h_views.contains(name))
329
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
330
331
332
		if(h_views.count() > 1)
		{
			View* view = h_views[name];
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
			if(view == m_firstView)
			{
				ViewHash::const_iterator i = h_views.constBegin();
				while (i != h_views.constEnd())
				{
					if(i.value() != view)
					{
						m_firstView = i.value();
						i = h_views.constEnd();
					}
					else
						++i;
				}
			}
//			if(view == m_currentView)
			setCurrentView(m_firstView);
Pierre Kraemer's avatar
Pierre Kraemer committed
349
			h_views.remove(name);
350
351
352

			emit(viewRemoved(view));

Pierre Kraemer's avatar
Pierre Kraemer committed
353
354
			delete view;
		}
355
356
357
	}
}

358
View* Window::getView(const QString& name) const
359
{
360
361
	if (h_views.contains(name))
		return h_views[name];
362
	else
363
		return NULL;
364
365
}

366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
void Window::setCurrentView(View* view)
{
	const QList<Plugin*>& oldPlugins = m_currentView->getLinkedPlugins();
	foreach(Plugin* p, oldPlugins)
		disablePluginTabWidgets(p);

	View* oldCurrent = m_currentView;
	m_currentView = view;

	const QList<Plugin*>& newPlugins = m_currentView->getLinkedPlugins();
	foreach(Plugin* p, newPlugins)
	{
		enablePluginTabWidgets(p);
		p->currentViewChanged(m_currentView);
	}

	oldCurrent->updateGL();
	m_currentView->updateGL();
}

Pierre Kraemer's avatar
Pierre Kraemer committed
386
void Window::splitView(const QString& name, Qt::Orientation orientation)
387
{
Pierre Kraemer's avatar
Pierre Kraemer committed
388
	View* newView = addView();
389

Pierre Kraemer's avatar
Pierre Kraemer committed
390
//	std::cout << "splitView" << std::endl;
391

Pierre Kraemer's avatar
Pierre Kraemer committed
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
	View* view = h_views[name];
	QSplitter* parent = (QSplitter*)(view->parentWidget());
	if(parent == m_rootSplitter && !b_rootSplitterInitialized)
	{
//		std::cout << "init root splitter" << std::endl;
		m_rootSplitter->setOrientation(orientation);
		b_rootSplitterInitialized = true;
	}
	if(parent->orientation() == orientation)
	{
//		std::cout << "same orientation" << std::endl;
		parent->insertWidget(parent->indexOf(view)+1, newView);
	}
	else
	{
//		std::cout << "new orientation" << std::endl;
		int idx = parent->indexOf(view);
		view->setParent(NULL);
		QSplitter* spl = new QSplitter(orientation);
		spl->addWidget(view);
		spl->addWidget(newView);
		parent->insertWidget(idx, spl);
414
415
416
	}
}

417
/*********************************************************
418
 * MANAGE PLUGINS
419
420
 *********************************************************/

421
Plugin* Window::loadPlugin(const QString& pluginFilePath)
422
{
423
424
425
	QString pluginName = QFileInfo(pluginFilePath).baseName().remove(0, 3);

	if (h_plugins.contains(pluginName))
426
		return NULL;
427

428
	QPluginLoader loader(pluginFilePath);
Pierre Kraemer's avatar
Pierre Kraemer committed
429

430
431
432
433
	// if the loader loads a plugin instance
	if (QObject* pluginObject = loader.instance())
	{
		Plugin* plugin = qobject_cast<Plugin*>(pluginObject);
Pierre Kraemer's avatar
Pierre Kraemer committed
434

435
436
437
438
439
440
441
442
443
444
445
		// we set the plugin with correct parameters (name, filepath, window)
		plugin->setName(pluginName);
		plugin->setFilePath(pluginFilePath);
		plugin->setWindow(this);

		// then we call its enable() methods
		if (plugin->enable())
		{
			// if it succeeded we reference this plugin
			h_plugins.insert(pluginName, plugin);

446
			statusbar->showMessage(pluginName + QString(" successfully loaded."), 2000);
447
448
			emit(pluginAdded(plugin));

449
450
			m_pythonContext.addObject(pluginName, plugin);

451
452
453
454
455
			// method success
			return plugin;
		}
		else
		{
Pierre Kraemer's avatar
Pierre Kraemer committed
456
			std::cout << "plugin enable failed" << std::endl;
457
458
459
460
461
462
			delete plugin;
			return NULL;
		}
	}
	// if loading fails
	else
Pierre Kraemer's avatar
Pierre Kraemer committed
463
464
	{
		std::cout << "loader.instance failed" << std::endl << loader.errorString().toUtf8().constData() << std::endl;
465
		return NULL;
Pierre Kraemer's avatar
Pierre Kraemer committed
466
467
468
	}
}

469
void Window::unloadPlugin(const QString& pluginName)
470
{
471
472
473
474
475
476
477
478
	if (h_plugins.contains(pluginName))
	{
		Plugin* plugin = h_plugins[pluginName];

		// calling its disable() method and dereferencing it
		plugin->disable();
		h_plugins.remove(pluginName);

479
480
481
482
		QPluginLoader loader(plugin->getFilePath());
		loader.unload();

		statusbar->showMessage(pluginName + QString(" successfully unloaded."), 2000);
483
484
485
486
487
		emit(pluginRemoved(plugin));

		// delete plugin
		delete plugin;
	}
488
489
}

490
Plugin* Window::getPlugin(const QString& name) const
491
{
492
493
494
495
	if (h_plugins.contains(name))
		return h_plugins[name];
	else
		return NULL;
496
}
497
498
/*
Plugin* Window::checkPluginDependencie(QString name, Plugin* dependantPlugin)
499
{
500
501
502
503
504
505
506
507
508
509
	// if the plugin is referenced and found
	PluginHash::iterator it;

	if ((it = h_plugin.find(name)) != h_plugin.end())
	{
		// the plugin calling for the depencie is added to the found plugin's list of dependant plugins
		(*it)->addDependantPlugin(dependantPlugin);
		return (*it);
	}
	//if not found: set error message + failure
510
	else
511
		return NULL;
512
}
513
*/
514

515
516
517
/*********************************************************
 * MANAGE MAPS
 *********************************************************/
518

519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
GenericMap* Window::createMap(unsigned int dim)
{
	GenericMap* map = NULL;
	switch(dim)
	{
		case 2 :
			map = new PFP2::MAP();
			break;
		case 3 :
			map = new PFP3::MAP();
			break;
	}
	return map;
}

534
bool Window::addMap(MapHandlerGen* map)
535
{
536
	if (h_maps.contains(map->getName()))
537
		return false;
538

539
	h_maps.insert(map->getName(), map);
540
541
542

	emit(mapAdded(map));

543
	return true;
544
545
}

546
void Window::removeMap(const QString& name)
547
{
548
	if (h_maps.contains(name))
549
	{
550
		MapHandlerGen* map = h_maps[name];
551
		h_maps.remove(name);
552
553
554

		emit(mapRemoved(map));

555
		delete map;
556
	}
557
558
}

559
MapHandlerGen* Window::getMap(const QString& name) const
560
561
562
{
	if (h_maps.contains(name))
		return h_maps[name];
563
564
565
566
	else
		return NULL;
}

567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
/*********************************************************
 * MANAGE TEXTURES
 *********************************************************/

Texture* Window::getTexture(const QString& image)
{
	if(h_textures.contains(image))
	{
		Texture* t = h_textures[image];
		t->ref++;
		return t;
	}
	else
	{
		Texture* t = NULL;
		QImage img(image);
		if(!img.isNull())
		{
			GLuint texID = m_firstView->bindTexture(img);
			t = new Texture(texID, img.size(), 1);
			h_textures.insert(image, t);
		}
		return t;
	}
}

void Window::releaseTexture(const QString& image)
{
	if(h_textures.contains(image))
	{
		Texture* t = h_textures[image];
		t->ref--;
		if(t->ref == 0)
		{
			m_firstView->deleteTexture(h_textures[image]->texID);
			h_textures.remove(image);
			delete t;
		}
	}
}

608
609
610
611
612
613
614
615
616
617
618


void Window::cb_aboutSCHNApps()
{
	QString str("SCHNApps:\nS... CGoGN Holder for Nice Applications\n"
	            "Web site: http://cgogn.unistra.fr \n"
	            "Contact information: cgogn@unistra.fr");
	QMessageBox::about(this, tr("About SCHNApps"), str);
}

void Window::cb_aboutCGoGN()
619
620
621
622
623
624
625
626
{
	QString str("CGoGN:\nCombinatorial and Geometric modeling\n"
	            "with Generic N-dimensional Maps\n"
	            "Web site: http://cgogn.unistra.fr \n"
	            "Contact information: cgogn@unistra.fr");
	QMessageBox::about(this, tr("About CGoGN"), str);
}

627
628
629
630
631
void Window::cb_showHideDock()
{
	m_dock->setVisible(m_dock->isHidden());
}

632
void Window::cb_manageCameras()
633
{
Pierre Kraemer's avatar
Pierre Kraemer committed
634
	m_camerasDialog->show();
635
636
}

637
void Window::cb_managePlugins()
638
{
Pierre Kraemer's avatar
Pierre Kraemer committed
639
	m_pluginsDialog->show();
640
641
}

642
void Window::cb_manageMaps()
643
{
Pierre Kraemer's avatar
Pierre Kraemer committed
644
	m_mapsDialog->show();
645
}
Pierre Kraemer's avatar
Pierre Kraemer committed
646
647
648
649

} // namespace SCHNApps

} // namespace CGoGN