openFunctions.cc 33.9 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
*                                                                            *
*   $Revision$                                                       *
*   $LastChangedBy$                                                *
*   $Date$                     *
*                                                                            *
48
\*===========================================================================*/
Jan Möbius's avatar
 
Jan Möbius committed
49 50 51 52 53 54 55 56





#include "Core.hh"

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

59
#include <OpenFlipper/common/RecentFiles.hh>
Jan Möbius's avatar
 
Jan Möbius committed
60 61 62 63

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

Matthias Möller's avatar
Matthias Möller committed
64 65
#include "OpenFunctionThread.hh"

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

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

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

Jan Möbius's avatar
 
Jan Möbius committed
82
  }
83

Jan Möbius's avatar
 
Jan Möbius committed
84 85 86 87 88 89 90 91
}

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



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

102
void Core::commandLineOpen(const QString& _filename, bool _asPolyMesh ){
103

104
  QString file = _filename;
105

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

Jan Möbius's avatar
Jan Möbius committed
113
  // Add to the open list
114
  commandLineFileNames_.push_back(std::pair< QString , bool >(file, _asPolyMesh));
Jan Möbius's avatar
 
Jan Möbius committed
115 116
}

117
void Core::commandLineScript(const QString& _filename ) {
118

119
  QString file = _filename;
120 121 122 123 124 125 126 127 128
  
  // 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
129
  commandLineScriptNames_.push_back(file);
130 131
}

Jan Möbius's avatar
Jan Möbius committed
132 133
void Core::slotExecuteAfterStartup() {

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

135
  // Update logger
Jan Möbius's avatar
Jan Möbius committed
136 137
  if ( OpenFlipper::Options::gui())
    coreWidget_->updateInSceneLoggerGeometry();
138

Jan Möbius's avatar
Jan Möbius committed
139 140 141 142
  //check if we have scripting support:
  bool scriptingSupport = false;
  slotPluginExists("scripting",scriptingSupport);
  if ( ! scriptingSupport ) {
143
    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
144 145
  }

Jan Möbius's avatar
Jan Möbius committed
146 147 148
  // 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
149 150
  if ( scriptingSupport ) {

Jan Möbius's avatar
Jan Möbius committed
151
    // Get the files in the directory
Jan Möbius's avatar
Jan Möbius committed
152 153 154
    QDir scriptDir = OpenFlipper::Options::scriptDir();
    QStringList scriptFiles = scriptDir.entryList(QDir::Files,QDir::Name);

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

160 161 162
    // Clear scripting window afterexecuting the coresubdir scripts
    bool ok = false;
    slotCall( "scripting" ,"clearEditor()",ok);
Jan Möbius's avatar
Jan Möbius committed
163 164
  }

165
  OpenFlipper::Options::blockSceneGraphUpdates();
166

Jan Möbius's avatar
Jan Möbius committed
167
  // Open all files given at the commandline
168
  for ( uint i = 0 ; i < commandLineFileNames_.size() ; ++i ) {
169 170

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

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

185
  OpenFlipper::Options::unblockSceneGraphUpdates();
186

187 188 189
  // Reset the scenegraph once to make sure everything is fine
  resetScenegraph( true );

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

Jan Möbius's avatar
Jan Möbius committed
196 197
  // 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
198 199
  if ( !OpenFlipper::Options::gui() && !OpenFlipper::Options::remoteControl())
    exitApplication();
Jan Möbius's avatar
 
Jan Möbius committed
200 201
}

Matthias Möller's avatar
Matthias Möller committed
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 234 235 236 237
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 );
  }

}

238

Jan Möbius's avatar
Jan Möbius committed
239 240 241 242 243 244 245
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.
  */
  
246
  if (_filename.endsWith(".ini",Qt::CaseInsensitive)) {
247 248

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

Jan Möbius's avatar
 
Jan Möbius committed
251
    if ( OpenFlipper::Options::gui() )
252
      coreWidget_->addRecent(_filename, DATA_UNKNOWN);
253

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

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

264
      QString filters = supportedTypes()[i].loadFilters;
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281

      // 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;
282
        }
283 284 285 286 287 288 289

        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
290
      }
Dirk Wilden's avatar
Dirk Wilden committed
291

292 293 294 295
      // continue processing only if found
      if ( ! found )
        continue;

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

Matthias Möller's avatar
Matthias Möller committed
302 303 304 305
      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
306

Matthias Möller's avatar
Matthias Möller committed
307 308
      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
309

Matthias Möller's avatar
Matthias Möller committed
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
      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
327 328
      }

Matthias Möller's avatar
Matthias Möller committed
329 330 331
      int objId = thread->getObjId(0);

      return objId;
Dirk Wilden's avatar
Dirk Wilden committed
332 333 334 335
    }
  }

  emit log(LOGERR, tr("Unable to load object (type unknown). No suitable plugin found!") );
Jan Möbius's avatar
 
Jan Möbius committed
336 337 338 339

  return -1;
}

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

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

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

356
      QString filters = supportedTypes()[i].loadFilters;
357 358 359 360 361 362 363 364 365 366 367 368 369

      // 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) ) {
370 371
          typeIds.push_back(i);
          continue;
372 373 374
        }

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

383
  // load file with plugins
384
  size_t nPlugins = typeIds.size();
385 386 387 388 389 390 391
  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
392
      if ( OpenFlipper::Options::gui() ) {
393
        QStringList items;
394
        for (size_t j = 0; j < nPlugins; ++j) {
395 396 397
          // 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;
398 399 400 401 402 403 404 405 406 407 408 409 410 411
        }

        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
412
      }
413 414
    } else
      i = typeIds[0];
Jan Möbius's avatar
 
Jan Möbius committed
415

416 417 418 419 420
    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
421

422
    //load file
Matthias Möller's avatar
Matthias Möller committed
423 424 425
    QString jobId = QString("Loading_"+_filename);
    QVector<LoadFromPluginThread::LoadInfos> infos;

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

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

Matthias Möller's avatar
Matthias Möller committed
433 434
    connect(thread, SIGNAL(finished(QString)), this, SLOT(slotFinishJob(QString)));
    connect(thread, SIGNAL(finished(QString)), this, SLOT(loadObjectFinished(QString)));
435

Matthias Möller's avatar
Matthias Möller committed
436 437 438
    if ( OpenFlipper::Options::gui() )
    {
      connect(thread, SIGNAL(updateView()), this, SLOT(updateView()), Qt::BlockingQueuedConnection);
439

Matthias Möller's avatar
Matthias Möller committed
440 441 442
      slotStartJob(jobId , QString("Loading %1").arg(_filename) , 0, 0, true);
      thread->start();
      thread->startProcessing();
443

Matthias Möller's avatar
Matthias Möller committed
444 445 446 447 448

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

    int objId = thread->getObjId(0);

    return objId;
458 459 460 461 462 463 464

  } 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
465 466
}

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

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

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

488 489 490 491 492
void Core::slotAddEmptyObject( DataType _type, int* _id)
{
  slotAddEmptyObject(_type,*_id);
}

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


  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
513 514
      }
  }
Jan Möbius's avatar
 
Jan Möbius committed
515 516
}

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

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

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

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

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

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

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

546
  // return the new id
Jan Möbius's avatar
Jan Möbius committed
547
  _newId = copy->id();
548

549 550 551 552 553 554
  // tell plugins that a new object has been created
  slotEmptyObjectAdded(_newId);

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

555 556
}

Matthias Möller's avatar
Matthias Möller committed
557 558 559 560 561 562 563 564 565 566

/// 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
567 568

  if ( OpenFlipper::Options::gui() ) {
Matthias Möller's avatar
Matthias Möller committed
569
    coreWidget_->statusMessage( filemsg );
570
    if ( !OpenFlipper::Options::sceneGraphUpdatesBlocked() )
Dirk Wilden's avatar
Dirk Wilden committed
571 572 573
      coreWidget_->setStatus(ApplicationStatus::PROCESSING );
  }

Matthias Möller's avatar
Matthias Möller committed
574 575 576 577
  //setup thread
  QString jobId = QString("Loading File");
  if (_filenames.size() > 1)
    jobId += "s";
Dirk Wilden's avatar
Dirk Wilden committed
578

Matthias Möller's avatar
Matthias Möller committed
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
  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
596
    else
Matthias Möller's avatar
Matthias Möller committed
597
      slotStartJob(jobId , QString(filemsg), 0, 0, true);
Dirk Wilden's avatar
Dirk Wilden committed
598

Matthias Möller's avatar
Matthias Möller committed
599 600 601 602 603 604 605 606 607 608 609
    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
610
  }
Matthias Möller's avatar
Matthias Möller committed
611 612 613 614 615
  else
  {
    thread->loadFromPlugin();
  }

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

Matthias Möller's avatar
Matthias Möller committed
619 620 621
  for (int i = 0; i < _filenames.size(); ++i)
  {
    int id = thread->getObjId(i);
622

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

Matthias Möller's avatar
Matthias Möller committed
625 626 627 628
      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
629

Matthias Möller's avatar
Matthias Möller committed
630 631 632
      if ( !OpenFlipper::Options::sceneGraphUpdatesBlocked() )
        coreWidget_->setStatus(ApplicationStatus::READY );
    }
Dirk Wilden's avatar
Dirk Wilden committed
633

Matthias Möller's avatar
Matthias Möller committed
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
    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
659
      }
Matthias Möller's avatar
Matthias Möller committed
660 661 662 663

      // Get the objects type
      if (object)
        type[i] = object->dataType();
664
    }
Dirk Wilden's avatar
Dirk Wilden committed
665
  }
666 667
  
  // If the id was greater than zero, add the file to the recent files.
Matthias Möller's avatar
Matthias Möller committed
668 669 670 671 672
  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
673 674
}

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

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

/// Slot gets called after a file-plugin has opened an object
687
void Core::slotFileOpened ( int _id ) {
688 689 690 691 692 693 694

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

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

  // get the opened object
707 708
  BaseObjectData* object;
  PluginFunctions::getObject(_id,object);
709

Jan Möbius's avatar
Jan Möbius committed
710 711
  // ================================================================================
  // Recompute bounding box and scenegraph info
712
  // Reset scene center here to include new object
Jan Möbius's avatar
Jan Möbius committed
713
  // ================================================================================
714
  resetScenegraph(true);
Jan Möbius's avatar
 
Jan Möbius committed
715

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

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

Jan Möbius's avatar
Jan Möbius committed
732 733 734
  // ================================================================================
  // Create initial backup
  // ================================================================================
735
  emit createBackup(_id,"Original Object");
Jan Möbius's avatar
 
Jan Möbius committed
736

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

Jan Möbius's avatar
Jan Möbius committed
744
  // ================================================================================
745
  // show all files
Jan Möbius's avatar
Jan Möbius committed
746
  // ================================================================================
747
  PluginFunctions::viewAll();
748

Jan Möbius's avatar
 
Jan Möbius committed
749
  // objectRoot_->dumpTree();
750
}
Jan Möbius's avatar
 
Jan Möbius committed
751 752

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

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

766 767 768 769
  // get the opened object
  BaseObjectData* object;
  PluginFunctions::getObject(_id,object);

770
  
771
  emit emptyObjectAdded( _id );
772

Jan Möbius's avatar
 
Jan Möbius committed
773
  // Tell the Plugins that the Object List and the active object have changed
774
  emit signalObjectUpdated(_id);
Jan Möbius's avatar
Jan Möbius committed
775
  emit signalObjectUpdated(_id,UPDATE_ALL);
Jan Möbius's avatar
 
Jan Möbius committed
776

777 778
  resetScenegraph(false);

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

//    addRecent(filename);
783
}
Jan Möbius's avatar
 
Jan Möbius committed
784 785 786 787 788 789 790

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

/// Opens AddEmpty-Object widget
void Core::slotAddEmptyObjectMenu() {
791 792 793 794 795 796 797 798 799 800 801 802 803
  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) {
    
804
    // Iterate over all supported types (created from plugins on load)
805 806
    // Check if a plugin supports addEmpty for the current type.
    // Only if the type is supported, add it to the addEmpty Dialog
807 808 809
    
    // typePlugin
    for ( uint j = 0 ; j < supportedDataTypes_.size(); j++) {
810
      
811 812
      // Check if a plugin supports the current type
      if ( supportedDataTypes_[j].type & currentType ) {
813 814 815 816 817
        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
818
      }
819 820
    }
    
821
    // filePlugin
822
    for ( uint j = 0 ; j < supportedTypes().size(); j++) {
823 824
      
      // Check if a plugin supports the current Type
825
      if ( supportedTypes()[j].type & currentType ) {
826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845
	
	// 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;
	}
      }
    }
    
846 847
    // Advance to next type ( Indices are bits so multiply by two to get next bit)
    ++currentType;
848 849 850
  }
  
  
Jan Möbius's avatar
Jan Möbius committed
851

852
  if (supportedTypes().size() != 0) {
853
    
Jan Möbius's avatar
Jan Möbius committed
854 855
    static addEmptyWidget* widget = 0;

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

869 870 871 872
//========================================================================================
// ===             Public Slots                                 ============================
//========================================================================================

Jan Möbius's avatar
 
Jan Möbius committed
873
/// Open Load-Object Widget
874 875 876 877
void Core::loadObject() {

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

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

883 884
      widget->setWindowIcon( OpenFlipper::Options::OpenFlipperIcon() );

885
      widget->showLoad();
886 887 888 889

      widget->disconnect();
      delete widget;

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

893
  }
Jan Möbius's avatar
 
Jan Möbius committed
894 895
}

896 897 898 899 900 901
/// Load settings from file
void Core::loadSettings(){

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

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

903 904 905

    QFileDialog fileDialog( coreWidget_,
                            tr("Load Settings"),
906
                            OpenFlipperSettings().value("Core/CurrentDir").toString(),
907
                            tr("INI files (*.ini)") );
908

909
    fileDialog.setOption (QFileDialog::DontUseNativeDialog, true);
910 911 912 913 914 915 916
    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 ) );
917
    optionsBox->setTitle(tr("Options"));
918 919 920
    layout->addWidget( optionsBox, layout->rowCount() , 0 , 1,layout->columnCount() );

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

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

    QCheckBox *loadObjectInfo = new QCheckBox(optionsBox);
931 932
    loadObjectInfo->setText(tr("Load all objects defined in the file"));
    loadObjectInfo->setToolTip(tr("Load all objects which are defined in the file"));
933 934 935 936 937 938 939 940
    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
941 942
    fileDialog.resize(550 ,500);

943 944 945 946 947 948 949 950 951 952 953 954
    // ========================================================================================
    // 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;
955
      return;
956 957 958 959
    }

    complete_name = fileNames[0];

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

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

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

977 978
/// Load settings from file
void Core::loadSettings(QString _filename){
Jan Möbius's avatar
Jan Möbius committed
979

980
  if ( !QFile(_filename).exists() )
Jan Möbius's avatar
 
Jan Möbius committed
981 982
    return;

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

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