/*===========================================================================*\
* *
* OpenFlipper *
* Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen *
* www.openflipper.org *
* *
*--------------------------------------------------------------------------- *
* This file is part of OpenFlipper. *
* *
* OpenFlipper is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of *
* the License, or (at your option) any later version with the *
* following exceptions: *
* *
* If other files instantiate templates or use macros *
* or inline functions from this file, or you compile this file and *
* link it with other files to produce an executable, this file does *
* not by itself cause the resulting executable to be covered by the *
* GNU Lesser General Public License. This exception does not however *
* invalidate any other reasons why the executable file might be *
* covered by the GNU Lesser General Public License. *
* *
* OpenFlipper is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU LesserGeneral Public *
* License along with OpenFlipper. If not, *
* see . *
* *
\*===========================================================================*/
/*===========================================================================*\
* *
* $Revision$ *
* $LastChangedBy$ *
* $Date$ *
* *
\*===========================================================================*/
#include "CoreWidget.hh"
#include
#include
#include
#include
//-----------------------------------------------------------------------------
KeyBinding CoreWidget::getKeyBinding(QObject* _plugin, int _keyIndex ){
if (_plugin == 0)
return coreKeys_[_keyIndex];
for (uint i=0; i < plugins_.size(); i++){
if (plugins_[i].plugin == _plugin)
return plugins_[i].keys[_keyIndex];
}
emit log(LOGERR,tr("ERROR: could not get KeyBinding"));
return KeyBinding();
}
QString CoreWidget::getRPCName(QObject* _plugin ){
if (_plugin == 0)
return "";
for (uint i=0; i < plugins_.size(); i++){
if (plugins_[i].plugin == _plugin)
return plugins_[i].rpcName;
}
emit log(LOGERR,tr("ERROR: could not get rpcname"));
return "";
}
/// passes keyPressEvents to either the Core or a Plugin depending on who has registered the key
void CoreWidget::keyPressEvent(QKeyEvent* _e)
{
std::pair< int,Qt::KeyboardModifiers > key = std::make_pair(_e->key(), _e->modifiers() );
//iterate over all assigned keys
KeyRange range = keys_.equal_range(key);
KeyMap::iterator it;
for (it=range.first; it != range.second; ++it){
QObject* plugin = (*it).second.first;
KeyBinding binding = getKeyBinding( plugin, (*it).second.second );
//check if its a core Key
if (plugin == 0){
//the key belongs to a slot
if (binding.slot){
bool ok;
emit call("core." + binding.description, ok);
return;
}
// =================================================================================
// Map event to the cores key and modifier.
// Call the core key handler with the mapped event.
// =================================================================================
QKeyEvent* mappedEvent = new QKeyEvent(_e->type(),binding.key, binding.modifiers,
_e->text(), _e->isAutoRepeat(), _e->count() );
coreKeyPressEvent(mappedEvent);
delete mappedEvent;
//if the key is multiUse also check other assigned keys
if (binding.multiUse)
continue;
else
return;
}
//it's a plugin key
//the key belongs to a slot
if (binding.slot){
bool ok;
emit call(getRPCName(plugin) +"."+ binding.description, ok);
return;
}
//the key was specified through keyInterface
KeyInterface* keyPlugin = qobject_cast< KeyInterface * >(plugin);
if (keyPlugin){
// =================================================================================
// Map event to the plugins key and modifier.
// Call it with the mapped event.
// =================================================================================
QKeyEvent* mappedEvent = new QKeyEvent(_e->type(),binding.key, binding.modifiers,
_e->text(), _e->isAutoRepeat(), _e->count() );
keyPlugin->slotKeyEvent(mappedEvent);
delete mappedEvent ;
}
//if its not a multiUse key we are ready
if (!binding.multiUse)
return;
}
}
//-----------------------------------------------------------------------------
/// passes keyReleaseEvents to either the Core or a Plugin depending on who has registered the key
void CoreWidget::keyReleaseEvent(QKeyEvent* _e) {
if (_e->isAutoRepeat()) return; //consider only "real" release events
std::pair< int,Qt::KeyboardModifiers > key = std::make_pair(_e->key(), _e->modifiers() );
//iterate over all assigned keys
KeyRange range = keys_.equal_range(key);
KeyMap::iterator it;
for (it=range.first; it != range.second; ++it){
QObject* plugin = (*it).second.first;
KeyBinding binding = getKeyBinding( plugin, (*it).second.second );
if (plugin == 0){
// =================================================================================
// Map event to the cores key and modifier.
// Call the core key handler with the mapped event.
// =================================================================================
QKeyEvent* mappedEvent = new QKeyEvent(_e->type(),binding.key, binding.modifiers,
_e->text(), _e->isAutoRepeat(), _e->count() );
coreKeyReleaseEvent(mappedEvent);
delete mappedEvent;
//if the key is multiUse also check other assigned keys
if (binding.multiUse)
continue;
else
return;
}
//it's a plugin key
KeyInterface* keyPlugin = qobject_cast< KeyInterface * >(plugin);
if (keyPlugin){
// =================================================================================
// Map event to the plugins key and modifier.
// Call the plugin with the mapped event.
// =================================================================================
QKeyEvent* mappedEvent = new QKeyEvent(_e->type(),binding.key, binding.modifiers,
_e->text(), _e->isAutoRepeat(), _e->count() );
keyPlugin->slotKeyReleaseEvent(mappedEvent);
delete mappedEvent;
}
//if its not a multiUse key we are ready
if (!binding.multiUse)
return;
}
}
//-----------------------------------------------------------------------------
/// Register a key to the core or a plugin
void CoreWidget::slotRegisterKey(int _key, Qt::KeyboardModifiers _modifiers, QString _description, bool _multiUse){
//first check if the key is already registered by the coreWidget
bool found = false;
bool multi = false;
QString name;
for (uint i=0; i < coreKeys_.size(); i++)
if (coreKeys_[i].key == _key && coreKeys_[i].modifiers == _modifiers){
found = true;
multi = coreKeys_[i].multiUse;
name = "Core";
break;
}
//then check if the key is already registered by a different plugin
if (!found)
for (uint i=0; i < plugins_.size(); i++)
for (int k=0; k < plugins_[i].keys.count(); k++)
if (plugins_[i].keys[k].key == _key
&& plugins_[i].keys[k].modifiers == _modifiers){
found = true;
multi = plugins_[i].keys[k].multiUse;
name = plugins_[i].name;
break;
}
if (found && !multi)
emit log(LOGERR, tr("Key already registered by '%1'").arg( name ) );
//check if its a key for the core
if (sender() == this){
KeyBinding kb;
kb.key = _key;
kb.modifiers = _modifiers;
kb.description = _description;
kb.multiUse = multi || _multiUse;
kb.slot = false;
if (multi && !_multiUse)
emit log(LOGERR, tr("Key already registered by '%1'. Forced registration as multiUse key.").arg( name ));
coreKeys_.push_back( kb );
keys_.insert( std::make_pair( std::make_pair(_key, _modifiers) , std::make_pair ((QObject*)0, coreKeys_.size()-1 ) )) ;
invKeys_.insert( std::make_pair( std::make_pair ((QObject*)0, coreKeys_.size()-1 ) , std::make_pair(_key, _modifiers) ) );
return;
}
//find plugin
PluginInfo* pluginInfo = 0;
for (uint i=0; i < plugins_.size(); i++)
if (plugins_[i].plugin == sender())
pluginInfo = &plugins_[i];
if (pluginInfo == 0){
emit log(LOGERR, tr("Unable to register key. Plugin not found!"));
return;
}
KeyBinding kb;
kb.key = _key;
kb.modifiers = _modifiers;
kb.description = _description;
kb.multiUse = multi || _multiUse;
kb.slot = false;
if (multi && !_multiUse)
emit log(LOGERR, tr("Key already registered by '%1'. Forced registration as multiUse key.").arg( name ));
pluginInfo->keys.append( kb );
keys_.insert( std::make_pair( std::make_pair(_key, _modifiers) , std::make_pair(pluginInfo->plugin, pluginInfo->keys.size()-1) ) );
invKeys_.insert( std::make_pair( std::make_pair(pluginInfo->plugin, pluginInfo->keys.size()-1) , std::make_pair(_key, _modifiers) ) );
}
///scripting slots will automatically registered to be assigned to an invalid key(-1)
void CoreWidget::slotRegisterSlotKeyBindings(){
//check the core slots
for (int i=0; i < coreSlots_.count(); i++){
//only consider functions without arguments
if ( !coreSlots_.at(i).slotName.contains( "()" ) )
continue;
KeyBinding kb;
kb.key = -1;
kb.modifiers = 0;
kb.description = coreSlots_.at(i).slotName;
kb.multiUse = true;
kb.slot = true;
coreKeys_.push_back( kb );
keys_.insert( std::make_pair( std::make_pair(-1, 0) , std::make_pair ((QObject*)0, coreKeys_.size()-1 ) )) ;
invKeys_.insert( std::make_pair( std::make_pair ((QObject*)0, coreKeys_.size()-1 ) , std::make_pair(-1, 0) ) );
}
//check all plugins
for (uint i=0; i < plugins_.size(); i++)
for (int j=0; j < plugins_[i].rpcFunctions.count(); j++){
//only consider functions without arguments
if ( !plugins_[i].rpcFunctions[j].contains( "()" )
|| plugins_[i].rpcFunctions[j] == "version()")
continue;
KeyBinding kb;
kb.key = -1;
kb.modifiers = 0;
kb.description = plugins_[i].rpcFunctions[j];
kb.multiUse = true;
kb.slot = true;
plugins_[i].keys.append( kb );
keys_.insert( std::make_pair( std::make_pair(-1, 0) , std::make_pair(plugins_[i].plugin, plugins_[i].keys.size()-1) ) );
invKeys_.insert( std::make_pair( std::make_pair(plugins_[i].plugin, plugins_[i].keys.size()-1) , std::make_pair(-1, 0) ) );
}
}
/// add a new keyMapping (keyBindingID is the id of the keyBinding in the pluginInfo of _plugin :)
void CoreWidget::slotAddKeyMapping(int _key, Qt::KeyboardModifiers _modifiers, QObject* _plugin, int _keyBindingID){
std::pair< int,Qt::KeyboardModifiers > keyCombi = std::make_pair(_key, _modifiers );
std::pair< int,Qt::KeyboardModifiers > oldCombi;
std::pair< QObject*, int > oldTarget;
bool replace = false;
//and check if the key is already assigned without multiUse
KeyMap::iterator it;
for (it=keys_.begin(); it != keys_.end(); ++it){
int key = (*it).first.first;
Qt::KeyboardModifiers modifiers = (*it).first.second;
QObject* plugin = (*it).second.first;
int bindingID = (*it).second.second;
KeyBinding binding = getKeyBinding(plugin, bindingID);
//check if its the keyBinding we want to map/replace
if (plugin == _plugin && bindingID == _keyBindingID){
replace = true;
oldCombi = (*it).first;
oldTarget = (*it).second;
continue;
}
//check if the mapping is conflicting with other mappings
if (_key == key && _modifiers == modifiers ){
if (!binding.multiUse){
if (plugin == 0)
emit log(LOGERR, tr("Could not add key mapping. Key already assigned to the core."));
else{
BaseInterface* basePlugin = qobject_cast< BaseInterface * >(plugin);
if (basePlugin)
emit log(LOGERR, tr("Could not add key mapping. Key already assigned to %1").arg( basePlugin->name() ) );
else
emit log(LOGERR, tr("Could not add key mapping. Key already assigned to an unknown plugin."));
}
return;
}
}
}
KeyBinding keyBinding = getKeyBinding(_plugin, _keyBindingID);
//check if new binding doesn't allow multiUse but other assignments for the key exist
if (!keyBinding.multiUse)
if ( (replace && keys_.count(keyCombi) > 1) || (!replace && keys_.count(keyCombi) > 0) ){
emit log(LOGERR, tr("Could not add (single usage) key mapping. Key already assigned."));
return;
}
if (replace){
keys_.erase(oldCombi);
invKeys_.erase(oldTarget);
}
//now we can add the mapping
keys_.insert ( std::make_pair( keyCombi , std::make_pair(_plugin, _keyBindingID) ));
invKeys_.insert( std::make_pair( std::make_pair(_plugin, _keyBindingID), keyCombi ));
}
///Load key assignments from a given INI file
void CoreWidget::loadKeyBindings(INIFile& _ini){
QVector< int > keys;
QVector< int > modifiers;
QStringList pluginNames;
QVector< int > bindingIDs;
//first load everything from INI file
if ( !_ini.section_exists("KeyBindings") )
return;
int keyCount;
if (_ini.get_entry(keyCount,"KeyBindings","KeyCount") ){
int key;
int mod;
QString name;
int binding;
for (int i=0; i < keyCount; i++){
if (!_ini.get_entry(key, "KeyBindings","Key" + QString::number(i) ) ) continue;
if (!_ini.get_entry(mod, "KeyBindings","KeyModifiers" + QString::number(i) ) ) continue;
if (!_ini.get_entry(name, "KeyBindings","KeyTarget" + QString::number(i) ) ) continue;
if (!_ini.get_entry(binding, "KeyBindings","KeyBinding" + QString::number(i) ) ) continue;
keys.push_back( key );
modifiers.push_back( mod );
pluginNames.push_back( name );
bindingIDs.push_back( binding );
}
}
//add the keyMapping
for (int i=0; i < keys.count(); i++){
//first we need the plugin
QObject* plugin = 0;
if (pluginNames[i] != "Core" ){
//search for the plugin
for (uint i=0; i < plugins_.size(); i++)
if (plugins_[i].rpcName == pluginNames[i] ){
plugin = plugins_[i].plugin;
break;
}
if (plugin == 0)
continue; //because plugin was not found
}
slotAddKeyMapping( keys[i], (Qt::KeyboardModifiers) modifiers[i], plugin, bindingIDs[i] );
}
}
///Store current key assignments to a given INI file
void CoreWidget::saveKeyBindings(INIFile& _ini){
QVector< int > keys;
QVector< int > modifiers;
QStringList pluginNames;
QVector< int > bindingIDs;
//first get all keys with custom assignments
KeyMap::iterator it;
for (it=keys_.begin(); it != keys_.end(); ++it){
int key = (*it).first.first;
Qt::KeyboardModifiers mod = (*it).first.second;
QObject* plugin = (*it).second.first;
int bindingID = (*it).second.second;
KeyBinding binding = getKeyBinding(plugin, bindingID);
//check if current key assignment and original assignment differ
if (key != binding.key || mod != binding.modifiers){
//get the pluginName
QString name;
if (plugin == 0)
name = "Core";
else
name = getRPCName(plugin);
//store key assignment
keys.push_back( key );
modifiers.push_back( mod );
pluginNames.push_back( name );
bindingIDs.push_back( bindingID );
}
}
//finally store everything to INI file
if ( !_ini.section_exists("KeyBindings") )
_ini.add_section("KeyBindings");
_ini.add_entry("KeyBindings","KeyCount", keys.count());
for (int i=0; i < keys.count(); i++){
_ini.add_entry("KeyBindings","Key" + QString::number(i) , keys[i] );
_ini.add_entry("KeyBindings","KeyModifiers" + QString::number(i), modifiers[i] );
_ini.add_entry("KeyBindings","KeyTarget" + QString::number(i) , pluginNames[i] );
_ini.add_entry("KeyBindings","KeyBinding" + QString::number(i) , bindingIDs[i] );
}
}
/// if a keyPressEvent belongs to the core this functions is called
void CoreWidget::registerCoreKeys() {
//register keys for coreWidget
connect(this , SIGNAL( registerKey(int, Qt::KeyboardModifiers, QString, bool) ),
this , SLOT(slotRegisterKey(int, Qt::KeyboardModifiers, QString, bool)) );
emit registerKey(Qt::Key_Print , Qt::NoModifier, "Create Snapshot");
emit registerKey(Qt::Key_Escape , Qt::NoModifier, "Switch to last action mode ( Move,Picking,Light or Info Mode)");
emit registerKey(Qt::Key_Space , Qt::NoModifier, "Toggle between multiview and single view");
emit registerKey(Qt::Key_S , Qt::ControlModifier, "Save Object");
emit registerKey(Qt::Key_O , Qt::ControlModifier, "Open Object");
emit registerKey(Qt::Key_L , Qt::ControlModifier, "Show/Hide Logger");
emit registerKey(Qt::Key_T , Qt::ControlModifier, "Show/Hide Toolbox");
emit registerKey(Qt::Key_F , Qt::ControlModifier, "Toggle Fullscreen");
emit registerKey(Qt::Key_B , Qt::ControlModifier, "Show/Hide StatusBar");
if ( OpenFlipper::Options::isLinux() ) {
emit registerKey(Qt::Key_Meta , Qt::MetaModifier, "Use Navigation mode while key is pressed");
emit registerKey(Qt::Key_Meta , Qt::NoModifier, "Use Navigation mode while key is pressed");
} else {
emit registerKey(Qt::Key_Alt , Qt::AltModifier, "Use Navigation mode while key is pressed");
emit registerKey(Qt::Key_Alt , Qt::NoModifier, "Use Navigation mode while key is pressed");
}
emit registerKey(Qt::Key_Shift , Qt::ShiftModifier, "Apply context menu action to all Viewers", true);
emit registerKey(Qt::Key_Shift , Qt::NoModifier, "Apply context menu action to all Viewers", true);
emit registerKey(Qt::Key_A , Qt::NoModifier, "First Person view strafe left");
emit registerKey(Qt::Key_D , Qt::NoModifier, "First Person view strafe right");
emit registerKey(Qt::Key_W , Qt::NoModifier, "First Person view move forward");
emit registerKey(Qt::Key_S , Qt::NoModifier, "First Person view move back");
}
/// if a keyPressEvent belongs to the core this functions is called
void CoreWidget::coreKeyPressEvent (QKeyEvent* _e){
//emit log(LOGERR,"Key Press");
if ( ( _e->key() == Qt::Key_Meta ) && OpenFlipper::Options::isLinux() ) {
if ( _e->type() == QEvent::KeyPress ) {
setActionMode( Viewer::ExamineMode );
}
}
if ( ( _e->key() == Qt::Key_Alt ) && ! OpenFlipper::Options::isLinux() ) {
if ( _e->type() == QEvent::KeyPress ) {
//emit log(LOGERR,"Switch to examine mode");
setActionMode( Viewer::ExamineMode );
}
}
if (_e->modifiers() & Qt::ControlModifier ) {
switch (_e->key()) {
case Qt::Key_B :
toggleStatusBar();
return;
case Qt::Key_F :
toggleFullscreen();
return;
case Qt::Key_L :
toggleLogger();
return;
case Qt::Key_T :
toggleToolbox();
return;
case Qt::Key_O :
loadMenu();
case Qt::Key_S :
saveMenu();
default:
return;
}
}
switch (_e->key()) {
case Qt::Key_Escape:
setActionMode( lastActionMode() );
break;
case Qt::Key_Print:
std::cerr << "Todo : On Print Screen, create a snapshot for all viewers" << std::endl;
break;
case Qt::Key_Space:
nextViewerLayout();
break;
case Qt::Key_A:
strafeLeft();
break;
case Qt::Key_D:
strafeRight();
break;
case Qt::Key_W:
moveForward();
break;
case Qt::Key_S:
moveBack();
break;
case Qt::Key_Shift :
shiftPressed_ = true;
break;
default:
shiftPressed_ = false;
return;
}
}
/// if a keyReleaseEvent belongs to the core this functions is called
void CoreWidget::coreKeyReleaseEvent(QKeyEvent* _e){
if ( ( _e->key() == Qt::Key_Meta ) && OpenFlipper::Options::isLinux() ) {
if ( _e->type() == QEvent::KeyRelease ) {
setActionMode( lastActionMode() );
}
}
//emit log(LOGERR,"Key release");
if ( ( _e->key() == Qt::Key_Alt ) && !OpenFlipper::Options::isLinux() ) {
//emit log(LOGERR,"Key alt release");
if ( _e->type() == QEvent::KeyRelease ) {
//emit log(LOGERR,"Key alt release toggle");
setActionMode( lastActionMode() );
}
}
switch (_e->key()) {
case Qt::Key_Shift :
shiftPressed_ = false;
break;
default:
return;
}
}