openFunctions.cc 33.4 KB
Newer Older
1
/*===========================================================================*\
Jan Möbius's avatar
Jan Möbius committed
2 3
*                                                                            *
*                              OpenFlipper                                   *
Martin Schultz's avatar
Martin Schultz committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 *           Copyright (c) 2001-2015, RWTH-Aachen University                 *
 *           Department of Computer Graphics and Multimedia                  *
 *                          All rights reserved.                             *
 *                            www.openflipper.org                            *
 *                                                                           *
 *---------------------------------------------------------------------------*
 * This file is part of OpenFlipper.                                         *
 *---------------------------------------------------------------------------*
 *                                                                           *
 * Redistribution and use in source and binary forms, with or without        *
 * modification, are permitted provided that the following conditions        *
 * are met:                                                                  *
 *                                                                           *
 * 1. Redistributions of source code must retain the above copyright notice, *
 *    this list of conditions and the following disclaimer.                  *
 *                                                                           *
 * 2. Redistributions in binary form must reproduce the above copyright      *
 *    notice, this list of conditions and the following disclaimer in the    *
 *    documentation and/or other materials provided with the distribution.   *
 *                                                                           *
 * 3. Neither the name of the copyright holder nor the names of its          *
 *    contributors may be used to endorse or promote products derived from   *
 *    this software without specific prior written permission.               *
 *                                                                           *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       *
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           *
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,       *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR        *
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      *
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        *
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              *
Jan Möbius's avatar
Jan Möbius committed
39
*                                                                            *
40 41
\*===========================================================================*/

42

Jan Möbius's avatar
 
Jan Möbius committed
43 44 45 46 47 48 49 50





#include "Core.hh"

#include <ACG/QtWidgets/QtFileDialog.hh>
Jan Möbius's avatar
Jan Möbius committed
51
#include <ACG/Scenegraph/SceneGraphAnalysis.hh>
Jan Möbius's avatar
 
Jan Möbius committed
52

53
#include <OpenFlipper/common/RecentFiles.hh>
Jan Möbius's avatar
 
Jan Möbius committed
54 55 56 57

#include "OpenFlipper/widgets/loadWidget/loadWidget.hh"
#include "OpenFlipper/widgets/addEmptyWidget/addEmptyWidget.hh"

Matthias Möller's avatar
Matthias Möller committed
58
#include "OpenFunctionThread.hh"
59 60

#include <ACG/Scenegraph/SeparatorNode.hh>
Matthias Möller's avatar
Matthias Möller committed
61

62
void Core::resetScenegraph( bool _resetTrackBall  ) {
Jan Möbius's avatar
Jan Möbius committed
63

64
  if ( OpenFlipper::Options::gui() && !OpenFlipper::Options::sceneGraphUpdatesBlocked() ) {
Jan Möbius's avatar
Jan Möbius committed
65

Jan Möbius's avatar
Jan Möbius committed
66 67 68 69
    unsigned int maxPases = 1;
    ACG::Vec3d bbmin,bbmax;
    ACG::SceneGraph::analyzeSceneGraph(PluginFunctions::getSceneGraphRootNode(),maxPases,bbmin,bbmax);

Jan Möbius's avatar
Jan Möbius committed
70
    for ( unsigned int i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i ) {
71
      // update scene graph (get new bounding box and set projection right, including near and far plane)
72
      PluginFunctions::viewerProperties(i).lockUpdate();
Jan Möbius's avatar
Jan Möbius committed
73
      coreWidget_->examiner_widgets_[i]->sceneGraph(root_node_scenegraph_,maxPases,bbmin,bbmax, _resetTrackBall );
74
      PluginFunctions::viewerProperties(i).unLockUpdate();
Jan Möbius's avatar
Jan Möbius committed
75 76 77
      coreWidget_->examiner_widgets_[i]->updateGL();
    }

Jan Möbius's avatar
 
Jan Möbius committed
78
  }
79

Jan Möbius's avatar
 
Jan Möbius committed
80 81 82 83 84 85 86 87
}

//========================================================================================
// ===            Open/Add-Empty Functions                    ============================
//========================================================================================



88
void Core::slotGetAllFilters ( QStringList& _list){
89
  /// \todo check why the supported Type is used here!
Jan Möbius's avatar
Jan Möbius committed
90
  // Iterate over all types
91 92
  for (int i=0; i < (int)supportedTypes().size(); i++){
    QString f = supportedTypes()[i].plugin->getLoadFilters();
Jan Möbius's avatar
 
Jan Möbius committed
93
    f = f.section(")",0,0).section("(",1,1).trimmed();
94
    _list << f;
Jan Möbius's avatar
 
Jan Möbius committed
95 96 97
  }
}

98
void Core::commandLineOpen(const QString& _filename, bool _asPolyMesh ){
99

100
  QString file = _filename;
101

102
  // Modify filename to contain full paths if they were given as relative paths
Jan Möbius's avatar
Jan Möbius committed
103 104 105 106 107
  if ( !file.startsWith("/") && !file.contains(":") ) {
    file = QDir::currentPath();
    file += OpenFlipper::Options::dirSeparator();
    file += _filename;
  }
108

Jan Möbius's avatar
Jan Möbius committed
109
  // Add to the open list
110
  commandLineFileNames_.push_back(std::pair< QString , bool >(file, _asPolyMesh));
Jan Möbius's avatar
 
Jan Möbius committed
111 112
}

113
void Core::commandLineScript(const QString& _filename ) {
114

115
  QString file = _filename;
116 117 118 119 120 121 122 123 124
  
  // Modify filename to contain full paths if they were given as relative paths
  if ( !file.startsWith("/") && !file.contains(":") ) {
    file = QDir::currentPath();
    file += OpenFlipper::Options::dirSeparator();
    file += _filename;
  }
  
  // Add to the open list
125
  commandLineScriptNames_.push_back(file);
126 127
}

Jan Möbius's avatar
Jan Möbius committed
128 129
void Core::slotExecuteAfterStartup() {

Jan Möbius's avatar
Jan Möbius committed
130

131
  // Update logger
Jan Möbius's avatar
Jan Möbius committed
132 133
  if ( OpenFlipper::Options::gui())
    coreWidget_->updateInSceneLoggerGeometry();
134

Jan Möbius's avatar
Jan Möbius committed
135 136 137 138
  //check if we have scripting support:
  bool scriptingSupport = false;
  slotPluginExists("scripting",scriptingSupport);
  if ( ! scriptingSupport ) {
139
    emit log(LOGERR ,tr("No scripting support available, please check if we load a scripting plugin .. Skipping script execution on startup"));
Jan Möbius's avatar
Jan Möbius committed
140 141
  }

Jan Möbius's avatar
Jan Möbius committed
142 143 144
  // Collect all script files from the scripting subdirectory and execute them if possible.
  // You can use this directory to execute scipts that modify for example modify the ui at
  // every startup.
Jan Möbius's avatar
Jan Möbius committed
145 146
  if ( scriptingSupport ) {

Jan Möbius's avatar
Jan Möbius committed
147
    // Get the files in the directory
Jan Möbius's avatar
Jan Möbius committed
148 149 150
    QDir scriptDir = OpenFlipper::Options::scriptDir();
    QStringList scriptFiles = scriptDir.entryList(QDir::Files,QDir::Name);

Jan Möbius's avatar
Jan Möbius committed
151
    // Execute all files ending with ofs
Jan Möbius's avatar
Jan Möbius committed
152
    for ( int i = 0 ; i  < scriptFiles.size(); ++i )
153
      if ( scriptFiles[i].endsWith("ofs",Qt::CaseInsensitive) )
154
        emit executeFileScript(scriptDir.path() + "/" + scriptFiles[i]);
Jan Möbius's avatar
Jan Möbius committed
155

156 157 158
    // Clear scripting window afterexecuting the coresubdir scripts
    bool ok = false;
    slotCall( "scripting" ,"clearEditor()",ok);
Jan Möbius's avatar
Jan Möbius committed
159 160
  }

161
  OpenFlipper::Options::blockSceneGraphUpdates();
162

Jan Möbius's avatar
Jan Möbius committed
163
  // Open all files given at the commandline
164
  for ( uint i = 0 ; i < commandLineFileNames_.size() ; ++i ) {
165 166

    // Skip scripts here as they will be handled by a different function
167
    QString tmp = commandLineFileNames_[i].first;
168
    if ( tmp.endsWith("ofs",Qt::CaseInsensitive) ) {
169 170 171 172
      commandLineScriptNames_.push_back(commandLineFileNames_[i].first);
      continue;
    }

Jan Möbius's avatar
Jan Möbius committed
173
    // If the file was given with the polymesh option, open them as polymeshes.
174
    if (commandLineFileNames_[i].second)
175
      loadObject(typeId("PolyMesh"), commandLineFileNames_[i].first);
176
    else {
177
      loadObject(commandLineFileNames_[i].first);
178
    }
Jan Möbius's avatar
 
Jan Möbius committed
179 180
  }

181
  OpenFlipper::Options::unblockSceneGraphUpdates();
182

183 184 185
  // Reset the scenegraph once to make sure everything is fine
  resetScenegraph( true );

Jan Möbius's avatar
Jan Möbius committed
186
  // If we have scripting support, execute the scripts given at the commandline.
Jan Möbius's avatar
Jan Möbius committed
187
  if ( scriptingSupport )
188
    for ( uint i = 0 ; i < commandLineScriptNames_.size() ; ++i ) {
189
      emit executeFileScript(commandLineScriptNames_[i]);
190
    }
191

Jan Möbius's avatar
Jan Möbius committed
192 193
  // If we don't have a gui and we are not under remote control,
  // exit the application as there would be no way to execute further commands
Dirk Wilden's avatar
Dirk Wilden committed
194 195
  if ( !OpenFlipper::Options::gui() && !OpenFlipper::Options::remoteControl())
    exitApplication();
Jan Möbius's avatar
 
Jan Möbius committed
196 197
}

Matthias Möller's avatar
Matthias Möller committed
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
void Core::loadObjectFinished(QString _threadId)
{
  if ( OpenFlipper::Options::gui() ) {
    LoadFromPluginThread* thread = dynamic_cast<LoadFromPluginThread*>(sender());
    if (!thread)
      return;

    int id = thread->getObjId(0);
    QString filename = thread->getFilename(0);

    if ( id != -1 ) {
      coreWidget_->statusMessage( tr("Loading %1 ... done").arg(filename), 4000 );

      // Get the object to figure out the data type
      BaseObject* object;
      PluginFunctions::getObject(id,object);

      // Security check, if object really exists
      if ( object != 0 ) {

        // Add to recent files with the given datatype
        if ( OpenFlipper::Options::gui() )
          coreWidget_->addRecent(filename, object->dataType());
      } else {
        emit log(LOGERR, tr("Unable to add recent as object with id %1 could not be found!").arg(id) );
      }

    } else
      coreWidget_->statusMessage( tr("Loading %1 ... failed!").arg(filename), 4000 );

    if ( !OpenFlipper::Options::sceneGraphUpdatesBlocked() )
      coreWidget_->setStatus(ApplicationStatus::READY );
  }

}

234

Jan Möbius's avatar
Jan Möbius committed
235 236 237 238 239 240 241
int Core::loadObject ( QString _filename ) {
  /** \todo Check if this function is ok. It should check all plugins for the given files and do not depend
            on Triangle meshes only! 
            Rewrite function to get the plugin only and then open the file. So iterate over all plugins and find the
            matching ones. open it with this plugin.
  */
  
242
  if (_filename.endsWith(".ini",Qt::CaseInsensitive)) {
243 244

    // Load all information from the given ini file
245
    openIniFile(_filename,true,true,true);
246

Jan Möbius's avatar
 
Jan Möbius committed
247
    if ( OpenFlipper::Options::gui() )
248
      coreWidget_->addRecent(_filename, DATA_UNKNOWN);
249

Jan Möbius's avatar
 
Jan Möbius committed
250
    return -2;
251
  } else if (_filename.endsWith(".ofs",Qt::CaseInsensitive)) {
Jan Möbius's avatar
Jan Möbius committed
252
     emit log(LOGINFO ,tr("Starting script execution of %1.").arg( _filename)) ;
Jan Möbius's avatar
 
Jan Möbius committed
253
     emit executeFileScript(_filename);
Dirk Wilden's avatar
Dirk Wilden committed
254 255 256
  } else {
    
    QFileInfo fi(_filename);
257

258
    for (int i=0; i < (int)supportedTypes().size(); i++){
Dirk Wilden's avatar
Dirk Wilden committed
259

260
      QString filters = supportedTypes()[i].loadFilters;
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277

      // Only take the parts inside the brackets
      filters = filters.section("(",1).section(")",0,0);

      // Split into blocks
      QStringList separateFilters = filters.split(" ");

      bool found = false;

      // for all filters associated with this plugin
      for ( int filterId = 0 ; filterId < separateFilters.size(); ++filterId ) {
        separateFilters[filterId] = separateFilters[filterId].trimmed();

        //check extension
        if ( separateFilters[filterId].endsWith( "*." + fi.completeSuffix() , Qt::CaseInsensitive) ) {
          found = true;
          break;
278
        }
279 280 281 282 283 284 285

        if (  separateFilters[filterId].endsWith( "*." + fi.suffix() , Qt::CaseInsensitive) ) {
          found = true;
          emit log(LOGWARN,"Found supported datatype but only the suffix is matched not the complete suffix!");
          break;
        }

Jan Möbius's avatar
Jan Möbius committed
286
      }
Dirk Wilden's avatar
Dirk Wilden committed
287

288 289 290 291
      // continue processing only if found
      if ( ! found )
        continue;

Dirk Wilden's avatar
Dirk Wilden committed
292 293
      if ( OpenFlipper::Options::gui() ) {
        coreWidget_->statusMessage( tr("Loading %1 ... ").arg(_filename));
294
        if ( !OpenFlipper::Options::sceneGraphUpdatesBlocked() )
Dirk Wilden's avatar
Dirk Wilden committed
295 296 297
          coreWidget_->setStatus(ApplicationStatus::PROCESSING );
      }

Matthias Möller's avatar
Matthias Möller committed
298 299 300 301
      QString jobId = QString("Loading_"+_filename);
      QVector<LoadFromPluginThread::LoadInfos> infos;
      infos.push_back(LoadFromPluginThread::LoadInfos(supportedTypes()[i].plugin, _filename));
      LoadFromPluginThread* thread = new LoadFromPluginThread(infos, jobId);
Dirk Wilden's avatar
Dirk Wilden committed
302

Matthias Möller's avatar
Matthias Möller committed
303 304
      connect(thread, SIGNAL(finished(QString)), this, SLOT(slotFinishJob(QString)));
      connect(thread, SIGNAL(finished(QString)), this, SLOT(loadObjectFinished(QString)));
Dirk Wilden's avatar
Dirk Wilden committed
305

Matthias Möller's avatar
Matthias Möller committed
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
      if ( OpenFlipper::Options::gui() )
      {
        connect(thread, SIGNAL(updateView()), this, SLOT(updateView()), Qt::BlockingQueuedConnection);

        slotStartJob(jobId , QString("Loading %1").arg(_filename) , 0, 0, true);
        thread->start();
        thread->startProcessing();


        while(thread->isRunning())
          QApplication::processEvents();
        // process last events
        QApplication::processEvents();
      }
      else
      {
        thread->loadFromPlugin();
Dirk Wilden's avatar
Dirk Wilden committed
323 324
      }

Matthias Möller's avatar
Matthias Möller committed
325 326 327
      int objId = thread->getObjId(0);

      return objId;
Dirk Wilden's avatar
Dirk Wilden committed
328 329 330 331
    }
  }

  emit log(LOGERR, tr("Unable to load object (type unknown). No suitable plugin found!") );
Jan Möbius's avatar
 
Jan Möbius committed
332 333 334 335

  return -1;
}

Matthias Möller's avatar
Matthias Möller committed
336

Jan Möbius's avatar
 
Jan Möbius committed
337 338
/// Function for loading a given file
int Core::loadObject( DataType _type, QString _filename) {
Jan Möbius's avatar
Jan Möbius committed
339 340 341
  /** \todo this function has to be checked. test for the plugin which can handle 
            the given file and then use it. 
  */
342
  
343
  if (_type == DATA_UNKNOWN)
Jan Möbius's avatar
 
Jan Möbius committed
344 345
    return loadObject(_filename);

Dirk Wilden's avatar
Dirk Wilden committed
346 347
  QFileInfo fi(_filename);
  
348 349
  std::vector<int> typeIds;
  for (int i=0; i < (int)supportedTypes().size(); i++) {
350
    if (supportedTypes()[i].type & _type || supportedTypes()[i].type == _type) {
Jan Möbius's avatar
 
Jan Möbius committed
351

352
      QString filters = supportedTypes()[i].loadFilters;
353 354 355 356 357 358 359 360 361 362 363 364 365

      // Only take the parts inside the brackets
      filters = filters.section("(",1).section(")",0,0);

      // Split into blocks
      QStringList separateFilters = filters.split(" ");

      // for all filters associated with this plugin
      for ( int filterId = 0 ; filterId < separateFilters.size(); ++filterId ) {
        separateFilters[filterId] = separateFilters[filterId].trimmed();

        //check extension
        if ( separateFilters[filterId].endsWith( "*." + fi.completeSuffix() , Qt::CaseInsensitive) ) {
366 367
          typeIds.push_back(i);
          continue;
368 369 370
        }

        if (  separateFilters[filterId].endsWith( "*." + fi.suffix() , Qt::CaseInsensitive) ) {
371
          typeIds.push_back(i);
372
          emit log(LOGWARN,"Found supported datatype but only the suffix is matched not the complete suffix!");
373
          continue;
374 375
        }
      }
376 377
    }
  }
378

379
  // load file with plugins
380
  size_t nPlugins = typeIds.size();
381 382 383 384 385 386 387
  if (nPlugins > 0) {

    int i = -1;

    // several plugins can load this type
    if (nPlugins > 1) {
      // let the user choose the plugin for loading
Jan Möbius's avatar
 
Jan Möbius committed
388
      if ( OpenFlipper::Options::gui() ) {
389
        QStringList items;
390
        for (size_t j = 0; j < nPlugins; ++j) {
391 392 393
          // only add the plugin name if it does not already exist in the itemlist
          if (items.indexOf(supportedTypes()[typeIds[j]].name) == -1)
            items << supportedTypes()[typeIds[j]].name;
394 395 396 397 398 399 400 401 402 403 404 405 406 407
        }

        bool ok;
        QString item = QInputDialog::getItem(coreWidget_, tr("File Plugins"),
                                             tr("Please choose a plugin for loading:"), items, 0, false, &ok);
        if (!ok) {
          emit log(LOGERR, tr("Unable to load object. No suitable plugin found!") );
          return -1; //no plugin found
        } else
          i = typeIds[items.indexOf(item)];
      }
      // if there is no gui just take the first one for now
      else {
        i = 0;
Jan Möbius's avatar
 
Jan Möbius committed
408
      }
409 410
    } else
      i = typeIds[0];
Jan Möbius's avatar
 
Jan Möbius committed
411

412 413 414 415 416
    if ( OpenFlipper::Options::gui() ) {
      coreWidget_->statusMessage( tr("Loading %1 ... ").arg(_filename));
      if ( !OpenFlipper::Options::sceneGraphUpdatesBlocked() )
        coreWidget_->setStatus(ApplicationStatus::PROCESSING );
    }
Dirk Wilden's avatar
Dirk Wilden committed
417

418
    //load file
Matthias Möller's avatar
Matthias Möller committed
419 420 421
    QString jobId = QString("Loading_"+_filename);
    QVector<LoadFromPluginThread::LoadInfos> infos;

422
    if ( checkSlot( supportedTypes()[i].object , "loadObject(QString,DataType)" ) )
Matthias Möller's avatar
Matthias Möller committed
423
      infos.push_back(LoadFromPluginThread::LoadInfos(supportedTypes()[i].plugin, _type,_filename));
424
    else
Matthias Möller's avatar
Matthias Möller committed
425
      infos.push_back(LoadFromPluginThread::LoadInfos(supportedTypes()[i].plugin, _filename));
Jan Möbius's avatar
 
Jan Möbius committed
426

Matthias Möller's avatar
Matthias Möller committed
427
    LoadFromPluginThread* thread = new LoadFromPluginThread(infos, jobId);
Jan Möbius's avatar
 
Jan Möbius committed
428

Matthias Möller's avatar
Matthias Möller committed
429 430
    connect(thread, SIGNAL(finished(QString)), this, SLOT(slotFinishJob(QString)));
    connect(thread, SIGNAL(finished(QString)), this, SLOT(loadObjectFinished(QString)));
431

Matthias Möller's avatar
Matthias Möller committed
432 433 434
    if ( OpenFlipper::Options::gui() )
    {
      connect(thread, SIGNAL(updateView()), this, SLOT(updateView()), Qt::BlockingQueuedConnection);
435

Matthias Möller's avatar
Matthias Möller committed
436 437 438
      slotStartJob(jobId , QString("Loading %1").arg(_filename) , 0, 0, true);
      thread->start();
      thread->startProcessing();
439

Matthias Möller's avatar
Matthias Möller committed
440 441 442 443 444

      while(thread->isRunning())
        QApplication::processEvents();
      // process last events
      QApplication::processEvents();
Jan Möbius's avatar
 
Jan Möbius committed
445
    }
Matthias Möller's avatar
Matthias Möller committed
446 447 448 449 450 451 452 453
    else
    {
      thread->loadFromPlugin();
    }

    int objId = thread->getObjId(0);

    return objId;
454 455 456 457 458 459 460

  } else {

    emit log(LOGERR, tr("Unable to load object. No suitable plugin found!") );

    return -1; //no plugin found
  }
Jan Möbius's avatar
 
Jan Möbius committed
461 462
}

Jan Möbius's avatar
Jan Möbius committed
463

Jan Möbius's avatar
 
Jan Möbius committed
464
int Core::addEmptyObject( DataType _type ) {
465
  // Iterate over all plugins. The first plugin supporting the addEmpty function for the
466 467
  // specified type will be used to create the new object. If adding the object failed,
  // we iterate over the remaining plugins.
468
  
469
  // Iterate over type plugins
470
  for (int i=0; i < (int)supportedDataTypes_.size(); i++)
471 472 473 474
    if ( supportedDataTypes_[i].type & _type ) {
      int retCode = supportedDataTypes_[i].plugin->addEmpty();
      if ( retCode != -1 )
        return retCode;
Jan Möbius's avatar
Jan Möbius committed
475
    }
476
  
477
  return -1; // no plugin found
Jan Möbius's avatar
 
Jan Möbius committed
478 479 480 481 482 483
}

//========================================================================================
// ===             Open/Add-Empty Slots                       ============================
//========================================================================================

484 485 486 487 488
void Core::slotAddEmptyObject( DataType _type, int* _id)
{
  slotAddEmptyObject(_type,*_id);
}

Jan Möbius's avatar
 
Jan Möbius committed
489
void Core::slotAddEmptyObject( DataType _type , int& _id ) {
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508


  if (QThread::currentThread() != QApplication::instance()->thread())
  {
    //execute method in main thread
    QMetaObject::invokeMethod(this,"slotAddEmptyObject",Qt::BlockingQueuedConnection, Q_ARG(DataType, _type), Q_ARG(int*, &_id));
  }
  else
  {
    _id = addEmptyObject( _type );
    if ( OpenFlipper::Options::doSlotDebugging() ) {
        if ( sender() != 0 ) {
          if ( sender()->metaObject() != 0 ) {
            emit log(LOGINFO,"slotAddEmptyObject( " + _type.name() + "," + QString::number(_id) +  tr(" ) called by ") +
            QString( sender()->metaObject()->className() ) );
          }
        } else {
          emit log(LOGINFO,"slotAddEmptyObject( " + _type.name() + ","  + QString::number(_id) +  tr(" ) called by Core") );
        }
Jan Möbius's avatar
Jan Möbius committed
509 510
      }
  }
Jan Möbius's avatar
 
Jan Möbius committed
511 512
}

513
/// Slot creating a copy of an existing object
Jan Möbius's avatar
Jan Möbius committed
514
void Core::slotCopyObject( int _oldId , int& _newId ) {
515

Jan Möbius's avatar
Jan Möbius committed
516
  if ( _oldId == -1 ) {
Jan Möbius's avatar
Jan Möbius committed
517
    emit log(LOGERR,tr("Requested copy for illegal Object id: %1").arg(_oldId) );
Jan Möbius's avatar
Jan Möbius committed
518 519 520 521 522 523 524 525
    _newId = -1;
    return;
  }

  // get the node
  BaseObject* object = objectRoot_->childExists(_oldId);

  if ( !object ) {
Jan Möbius's avatar
Jan Möbius committed
526
    emit log(LOGERR,tr("Requested copy for unknown Object id: %1 ").arg(_oldId) );
Jan Möbius's avatar
Jan Möbius committed
527 528 529 530 531 532 533 534
    _newId = -1;
    return ;
  }

  // Copy the item
  BaseObject* copy = object->copy();

  if ( copy == 0 ) {
535
    emit log(LOGERR,tr("Unable to create a copy of the object."));
Jan Möbius's avatar
Jan Möbius committed
536 537 538 539 540 541
    return;
  }

  // Integrate into object tree
  copy->setParent( object->parent() );

542
  // return the new id
Jan Möbius's avatar
Jan Möbius committed
543
  _newId = copy->id();
544

545 546 547 548 549 550
  // tell plugins that a new object has been created
  slotEmptyObjectAdded(_newId);

  // tell plugins that the object has been updated
  slotObjectUpdated(_newId);

551 552
}

Matthias Möller's avatar
Matthias Möller committed
553 554 555 556 557 558 559 560 561 562

/// Function for loading multiple files
void Core::slotLoad(QStringList _filenames, IdList _pluginIDs) {


  QString filemsg = "";
  if (_filenames.size() > 1)
    filemsg = QString( tr("Loading Files ...") );
  else
    filemsg = QString( tr("Loading %1 ...").arg(_filenames[0]) );
Dirk Wilden's avatar
Dirk Wilden committed
563 564

  if ( OpenFlipper::Options::gui() ) {
Matthias Möller's avatar
Matthias Möller committed
565
    coreWidget_->statusMessage( filemsg );
566
    if ( !OpenFlipper::Options::sceneGraphUpdatesBlocked() )
Dirk Wilden's avatar
Dirk Wilden committed
567 568 569
      coreWidget_->setStatus(ApplicationStatus::PROCESSING );
  }

Matthias Möller's avatar
Matthias Möller committed
570 571 572 573
  //setup thread
  QString jobId = QString("Loading File");
  if (_filenames.size() > 1)
    jobId += "s";
Dirk Wilden's avatar
Dirk Wilden committed
574

Matthias Möller's avatar
Matthias Möller committed
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
  QVector<LoadFromPluginThread::LoadInfos> loadInfos;
  for (int i = 0; i < _filenames.size(); ++i)
    loadInfos.push_back(LoadFromPluginThread::LoadInfos(supportedTypes()[_pluginIDs[i]].plugin, _filenames[i]));
  LoadFromPluginThread* thread = new LoadFromPluginThread(loadInfos, jobId);

  connect(thread, SIGNAL(finished(QString)), this, SLOT(slotFinishJob(QString)));
  connect(thread, SIGNAL(state(QString , int )), this, SLOT(slotSetJobState(QString , int)));

  if ( OpenFlipper::Options::gui() )
  {
    connect(thread, SIGNAL(updateView()), this, SLOT(updateView()), Qt::BlockingQueuedConnection);
    //block log (decrease performance when loading multiple files)
    coreWidget_->logWidget_->setUpdatesEnabled(false);

    // start thread
    if (_filenames.size() > 1)
      slotStartJob(jobId , QString(filemsg), 0, _filenames.size(), true);
Dirk Wilden's avatar
Dirk Wilden committed
592
    else
Matthias Möller's avatar
Matthias Möller committed
593
      slotStartJob(jobId , QString(filemsg), 0, 0, true);
Dirk Wilden's avatar
Dirk Wilden committed
594

Matthias Möller's avatar
Matthias Möller committed
595 596 597 598 599 600 601 602 603 604 605
    thread->start();
    thread->startProcessing();

    //wait thread
    while(thread->isRunning())
      QApplication::processEvents();
    //process last occuring events
    QApplication::processEvents();

    //unblock and update log
    coreWidget_->logWidget_->setUpdatesEnabled(true);
Dirk Wilden's avatar
Dirk Wilden committed
606
  }
Matthias Möller's avatar
Matthias Möller committed
607 608 609 610 611
  else
  {
    thread->loadFromPlugin();
  }

612
  // Initialize as unknown type
Matthias Möller's avatar
Matthias Möller committed
613
  QVector<DataType> type = QVector<DataType>(_filenames.size(), DATA_UNKNOWN);
614

Matthias Möller's avatar
Matthias Möller committed
615 616 617
  for (int i = 0; i < _filenames.size(); ++i)
  {
    int id = thread->getObjId(i);
618

Matthias Möller's avatar
Matthias Möller committed
619
    if ( OpenFlipper::Options::gui() ) {
Dirk Wilden's avatar
Dirk Wilden committed
620

Matthias Möller's avatar
Matthias Möller committed
621 622 623 624
      if ( id != -1 )
        coreWidget_->statusMessage( tr("Loading %1 done").arg(_filenames[i]), 4000 );
      else
        coreWidget_->statusMessage( tr("Loading %1 failed").arg(_filenames[i]), 4000 );
Dirk Wilden's avatar
Dirk Wilden committed
625

Matthias Möller's avatar
Matthias Möller committed
626 627 628
      if ( !OpenFlipper::Options::sceneGraphUpdatesBlocked() )
        coreWidget_->setStatus(ApplicationStatus::READY );
    }
Dirk Wilden's avatar
Dirk Wilden committed
629

Matthias Möller's avatar
Matthias Möller committed
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
    if ( id > 0 ) {

      BaseObjectData* object;
      PluginFunctions::getObject(id,object);

      if ( !object ) {

        BaseObject* baseObj = 0;
        GroupObject* group = 0;

        PluginFunctions::getObject(id,baseObj);

        if (baseObj){

          group = dynamic_cast< GroupObject* > (baseObj);

          if (group)
            type[i] = DATA_GROUP;

        }

        if ( group == 0 ){
          emit log(LOGERR,tr("Object id returned but no object with this id has been found! Error in one of the file plugins!"));
          return;
        }
Dirk Wilden's avatar
Dirk Wilden committed
655
      }
Matthias Möller's avatar
Matthias Möller committed
656 657 658 659

      // Get the objects type
      if (object)
        type[i] = object->dataType();
660
    }
Dirk Wilden's avatar
Dirk Wilden committed
661
  }
662 663
  
  // If the id was greater than zero, add the file to the recent files.
Matthias Möller's avatar
Matthias Möller committed
664 665 666 667 668
  if ( OpenFlipper::Options::gui() )
    for (int i = 0; i < _filenames.size(); ++i)
      if ( thread->getObjId(i) >= 0 )
        coreWidget_->addRecent(_filenames[i], type[i]);

Dirk Wilden's avatar
Dirk Wilden committed
669 670
}

Jan Möbius's avatar
 
Jan Möbius committed
671 672 673
/// Slot for loading a given file
void Core::slotLoad(QString _filename, DataType _type, int& _id) {
  _id = loadObject(_type,_filename);
674

Jan Möbius's avatar
 
Jan Möbius committed
675 676 677
  if ( _id < 0 )
    _id = -1;
  else
678
    if ( OpenFlipper::Options::gui() )
Jan Möbius's avatar
 
Jan Möbius committed
679 680 681 682
      coreWidget_->addRecent(_filename,_type);
}

/// Slot gets called after a file-plugin has opened an object
683
void Core::slotFileOpened ( int _id ) {
684 685 686 687 688 689 690

  if (QThread::currentThread() != QApplication::instance()->thread())
  {
    QMetaObject::invokeMethod(this,"slotFileOpened",Qt::QueuedConnection, Q_ARG(int, _id));
    return;
  }

691 692 693
  if ( OpenFlipper::Options::doSlotDebugging() ) {
    if ( sender() != 0 ) {
      if ( sender()->metaObject() != 0 ) {
694
        emit log(LOGINFO,tr("slotObjectOpened( ") + QString::number(_id) + tr(" ) called by ") +
695 696 697
                  QString( sender()->metaObject()->className() ) );
      }
    } else {
698
      emit log(LOGINFO,tr("slotObjectOpened( ") + QString::number(_id) + tr(" ) called by Core") );
699 700
    }
  }
701 702

  // get the opened object
703 704
  BaseObjectData* object;
  PluginFunctions::getObject(_id,object);
705

Jan Möbius's avatar
Jan Möbius committed
706 707
  // ================================================================================
  // Recompute bounding box and scenegraph info
708
  // Reset scene center here to include new object
Jan Möbius's avatar
Jan Möbius committed
709
  // ================================================================================
710
  resetScenegraph(true);
Jan Möbius's avatar
 
Jan Möbius committed
711

Jan Möbius's avatar
Jan Möbius committed
712 713 714
  // ================================================================================
  // Tell plugins, that a file has been opened
  // ================================================================================
715
  emit openedFile( _id );
716 717 718 719 720
  
  // ================================================================================
  // Print Info to logger
  // ================================================================================
  emit log( LOGINFO ,object->getObjectinfo() );
Jan Möbius's avatar
 
Jan Möbius committed
721

Jan Möbius's avatar
Jan Möbius committed
722 723 724
  // ================================================================================
  // Tell plugins, that the Object is updated and the active object has changed
  // ================================================================================
Jan Möbius's avatar
Jan Möbius committed
725 726
  emit signalObjectUpdated(_id );
  emit signalObjectUpdated(_id, UPDATE_ALL);
Jan Möbius's avatar
 
Jan Möbius committed
727

Jan Möbius's avatar
Jan Möbius committed
728 729 730
  // ================================================================================
  // Create initial backup
  // ================================================================================
731
  emit createBackup(_id,"Original Object");
Jan Möbius's avatar
 
Jan Möbius committed
732

733 734 735
  // ================================================================================
  // Add the file to the recent files menu
  // ================================================================================
736 737 738
  QString filename = object->path() + OpenFlipper::Options::dirSeparator() + object->name();
  BaseObject* object2;
  PluginFunctions::getObject(_id,object2);
Jan Möbius's avatar
 
Jan Möbius committed
739

Jan Möbius's avatar
Jan Möbius committed
740
  // ================================================================================
741
  // show all files
Jan Möbius's avatar
Jan Möbius committed
742
  // ================================================================================
743
  PluginFunctions::viewAll();
744

Jan Möbius's avatar
 
Jan Möbius committed
745
  // objectRoot_->dumpTree();
746
}
Jan Möbius's avatar
 
Jan Möbius committed
747 748

 /// Slot gets called after a file-plugin has opened an object
749
void Core::slotEmptyObjectAdded ( int _id ) {
750

751 752 753
  if ( OpenFlipper::Options::doSlotDebugging() ) {
    if ( sender() != 0 ) {
      if ( sender()->metaObject() != 0 ) {
754
        emit log(LOGINFO,tr("slotEmptyObjectAdded( ") + QString::number(_id) + tr(" ) called by ") +
755 756 757
                  QString( sender()->metaObject()->className() ) );
      }
    } else {
758
      emit log(LOGINFO,tr("slotEmptyObjectAdded( ") + QString::number(_id) + tr(" ) called by Core") );
759 760 761
    }
  }

762 763 764 765
  // get the opened object
  BaseObjectData* object;
  PluginFunctions::getObject(_id,object);

766
  
767
  emit emptyObjectAdded( _id );
768

Jan Möbius's avatar
 
Jan Möbius committed
769
  // Tell the Plugins that the Object List and the active object have changed
770
  emit signalObjectUpdated(_id);
Jan Möbius's avatar
Jan Möbius committed
771
  emit signalObjectUpdated(_id,UPDATE_ALL);
Jan Möbius's avatar
 
Jan Möbius committed
772

773 774
  resetScenegraph(false);

775
  ///@todo : set a default path for new objects
Jan Möbius's avatar
 
Jan Möbius committed
776 777 778
//    QString filename = object->path() + OpenFlipper::Options::dirSeparator() + object->name();

//    addRecent(filename);
779
}
Jan Möbius's avatar
 
Jan Möbius committed
780 781 782 783 784 785 786

//========================================================================================
// ===             Menu Slots                                 ============================
//========================================================================================

/// Opens AddEmpty-Object widget
void Core::slotAddEmptyObjectMenu() {
787 788 789 790 791 792 793 794 795 796 797 798 799
  std::vector< DataType > types;
  QStringList             typeNames;
  
  DataType currentType = 2;
  
  // Iterate over all Types known to the core
  // Start at 2:
  // 0 type is defined as DATA_UNKNOWN
  // 1 type is defined as DATA_GROUP
  // Therefore we have two types less then reported
  // 
  for ( uint i = 0 ; i < typeCount() - 2  ; ++i) {
    
800
    // Iterate over all supported types (created from plugins on load)
801 802
    // Check if a plugin supports addEmpty for the current type.
    // Only if the type is supported, add it to the addEmpty Dialog
803 804 805
    
    // typePlugin
    for ( uint j = 0 ; j < supportedDataTypes_.size(); j++) {
806
      
807 808
      // Check if a plugin supports the current type
      if ( supportedDataTypes_[j].type & currentType ) {
809 810 811 812 813
        types.push_back(currentType);
        typeNames.push_back( typeName( currentType ) );
        
        // Stop here as we need only one plugin supporting addEmpty for a given type
        break;
Jan Möbius's avatar
 
Jan Möbius committed
814
      }
815 816
    }
    
817
    // filePlugin
818
    for ( uint j = 0 ; j < supportedTypes().size(); j++) {
819 820
      
      // Check if a plugin supports the current Type
821
      if ( supportedTypes()[j].type & currentType ) {
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
	
	// Avoid duplicates
	bool duplicate = false;
	for(std::vector< DataType >::iterator it = types.begin(); it != types.end(); ++it) {
	  if(*it == currentType) {
	    duplicate = true;
	    break;
	  }
	}
	  
	if(!duplicate) {
	  types.push_back(currentType);
	  typeNames.push_back( typeName( currentType ) );
        
	  // Stop here as we need only one plugin supporting addEmpty for a given type
	  break;
	}
      }
    }
    
842 843
    // Advance to next type ( Indices are bits so multiply by two to get next bit)
    ++currentType;
844 845 846
  }
  
  
Jan Möbius's avatar
Jan Möbius committed
847

848
  if (supportedTypes().size() != 0) {
849
    
Jan Möbius's avatar
Jan Möbius committed
850 851
    static addEmptyWidget* widget = 0;

852
    if ( !widget ){
Jan Möbius's avatar
 
Jan Möbius committed
853
      widget = new addEmptyWidget(types,typeNames);
854
      widget->setWindowIcon( OpenFlipper::Options::OpenFlipperIcon() );
Jan Möbius's avatar
 
Jan Möbius committed
855 856
      connect(widget,SIGNAL(chosen(DataType, int&)),this,SLOT(slotAddEmptyObject(DataType, int&)));
    }
857
    
Jan Möbius's avatar
 
Jan Möbius committed
858
    widget->show();
859 860 861 862
    
  } else
    emit log(LOGERR,tr("Could not show 'add Empty' dialog. Missing file-plugins ?"));
  
Jan Möbius's avatar
 
Jan Möbius committed
863 864
}

865 866 867 868
//========================================================================================
// ===             Public Slots                                 ============================
//========================================================================================

Jan Möbius's avatar
 
Jan Möbius committed
869
/// Open Load-Object Widget
870 871 872 873
void Core::loadObject() {

  if ( OpenFlipper::Options::gui() ){

874 875
    if (supportedTypes().size() != 0){
      LoadWidget* widget = new LoadWidget(supportedTypes());
Matthias Möller's avatar
Matthias Möller committed
876
      connect(widget,SIGNAL(loadFiles(QStringList, IdList)),this,SLOT(slotLoad(QStringList, IdList)));
Dirk Wilden's avatar
Dirk Wilden committed
877
      connect(widget,SIGNAL(save(int, QString, int)),this,SLOT(saveObject(int, QString, int)));
Jan Möbius's avatar
Jan Möbius committed
878

879 880
      widget->setWindowIcon( OpenFlipper::Options::OpenFlipperIcon() );

881
      widget->showLoad();
882 883 884 885

      widget->disconnect();
      delete widget;

886
    }else
887
      emit log(LOGERR,tr("Could not show 'load objects' dialog. Missing file-plugins."));
Jan Möbius's avatar
 
Jan Möbius committed
888

889
  }
Jan Möbius's avatar
 
Jan Möbius committed
890 891
}

892 893 894 895 896 897
/// Load settings from file
void Core::loadSettings(){

  if ( OpenFlipper::Options::gui() ){

    QString complete_name;
Jan Möbius's avatar
Jan Möbius committed
898

899 900 901

    QFileDialog fileDialog( coreWidget_,
                            tr("Load Settings"),
902
                            OpenFlipperSettings().value("Core/CurrentDir").toString(),
903
                            tr("INI files (*.ini)") );
904

905
    fileDialog.setOption (QFileDialog::DontUseNativeDialog, true);
906 907 908 909 910 911 912
    fileDialog.setAcceptMode ( QFileDialog::AcceptOpen );
    fileDialog.setFileMode ( QFileDialog::AnyFile );

    QGridLayout *layout = (QGridLayout*)fileDialog.layout();

    QGroupBox* optionsBox = new QGroupBox( &fileDialog ) ;
    optionsBox->setSizePolicy( QSizePolicy ( QSizePolicy::Expanding , QSizePolicy::Preferred ) );
913
    optionsBox->setTitle(tr("Options"));
914 915 916
    layout->addWidget( optionsBox, layout->rowCount() , 0 , 1,layout->columnCount() );

    QCheckBox *loadProgramSettings = new QCheckBox(optionsBox);
917 918
    loadProgramSettings->setText(tr("Load program settings"));
    loadProgramSettings->setToolTip(tr("Load all current program settings from the file ( This will include view settings, colors,...) "));
919 920 921
    loadProgramSettings->setCheckState( Qt::Unchecked );

    QCheckBox *loadPluginSettings = new QCheckBox(optionsBox);
922 923
    loadPluginSettings->setText(tr("Load per Plugin Settings"));
    loadPluginSettings->setToolTip(tr("Plugins should load their current global settings from the file"));
924 925 926
    loadPluginSettings->setCheckState( Qt::Checked );

    QCheckBox *loadObjectInfo = new QCheckBox(optionsBox);
927 928
    loadObjectInfo->setText(tr("Load all objects defined in the file"));
    loadObjectInfo->setToolTip(tr("Load all objects which are defined in the file"));
929 930 931 932 933 934 935 936
    loadObjectInfo->setCheckState( Qt::Checked );

    QBoxLayout* frameLayout = new QBoxLayout(QBoxLayout::TopToBottom,optionsBox);
    frameLayout->addWidget( loadProgramSettings , 0 , 0);
    frameLayout->addWidget( loadPluginSettings  , 1 , 0);
    frameLayout->addWidget( loadObjectInfo      , 2 , 0);
    frameLayout->addStretch();

Jan Möbius's avatar
Jan Möbius committed
937 938
    fileDialog.resize(550 ,500);

939 940 941 942 943 944 945 946 947 948 949 950
    // ========================================================================================
    // show the saveSettings-Dialog and get the target file
    // ========================================================================================
    QStringList fileNames;
    if (fileDialog.exec()) {
      fileNames = fileDialog.selectedFiles();
    } else {
      return;
    }

    if ( fileNames.size() > 1 ) {
      std::cerr << "Too many save filenames selected" << std::endl;
951
      return;
952 953 954 955
    }

    complete_name = fileNames[0];

Jan Möbius's avatar
Jan Möbius committed
956

957
    QString newpath = complete_name.section(OpenFlipper::Options::dirSeparator(),0,-2);
958
    OpenFlipperSettings().setValue("Core/CurrentDir", newpath);
Jan Möbius's avatar
Jan Möbius committed
959

960
    if ( complete_name.endsWith("ini",Qt::CaseInsensitive) ) {
961 962 963 964
      openIniFile( complete_name,
                   loadProgramSettings->isChecked(),
                   loadPluginSettings->isChecked(),
                   loadObjectInfo->isChecked());
965 966
      if ( loadProgramSettings->isChecked() )
        applyOptions();
967 968
    } 
    
969
    coreWidget_->addRecent(complete_name, DATA_UNKNOWN);
970 971
  }
}
Jan Möbius's avatar
 
Jan Möbius committed
972

973 974
/// Load settings from file
void Core::loadSettings(QString _filename){
Jan Möbius's avatar
Jan Möbius committed
975

976
  if ( !QFile(_filename).exists() )
Jan Möbius's avatar
 
Jan Möbius committed
977 978
    return;

979
  QString newpath = _filename.section(OpenFlipper::Options::dirSeparator(),0,-2);
980
  OpenFlipperSettings().setValue("Core/CurrentDir", newpath);
Jan Möbius's avatar
 
Jan Möbius committed
981

982 983 984 985
  if ( _filename.endsWith("obj",Qt::CaseInsensitive) ) {
    loadObject(_filename);
    applyOptions();
  } else {
986
    // Loaded function for recent files. Load everything.
987
    openIniFile(_filename,true,true,true);
Jan Möbius's avatar
 
Jan Möbius committed
988 989 990
    applyOptions();
  }
}