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