Developer Documentation
saveSettings.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 
43 
44 
45 #include "Core.hh"
46 
47 //#include <ObjectTypes/Light/Light.hh>
48 
50 
51 
54 
55  // ========================================================================================
56  // generate the saveSettings-Dialog
57  // ========================================================================================
58 
59  QFileDialog fileDialog( coreWidget_,
60  tr("Save Settings"),
61  OpenFlipperSettings().value("Core/CurrentDir").toString(),
62  tr("INI files (*.ini);;OBJ files (*.obj )") );
63 
64  fileDialog.setOption (QFileDialog::DontUseNativeDialog, true);
65  fileDialog.setAcceptMode ( QFileDialog::AcceptSave );
66  fileDialog.setFileMode ( QFileDialog::AnyFile );
67 
68  QGridLayout *layout = (QGridLayout*)fileDialog.layout();
69 
70  QGroupBox* optionsBox = new QGroupBox( &fileDialog ) ;
71  optionsBox->setSizePolicy( QSizePolicy ( QSizePolicy::Expanding , QSizePolicy::Preferred ) );
72  optionsBox->setTitle(tr("Options"));
73  layout->addWidget( optionsBox, layout->rowCount() , 0 , 1,layout->columnCount() );
74 
75  QCheckBox *saveProgramSettings = new QCheckBox(optionsBox);
76  saveProgramSettings->setText(tr("Save program settings"));
77  saveProgramSettings->setToolTip(tr("Save all current program settings to the file ( This will include view settings, colors,...) "));
78  saveProgramSettings->setCheckState( Qt::Unchecked );
79 
80  QCheckBox *savePluginSettings = new QCheckBox(optionsBox);
81  savePluginSettings->setText(tr("Save per Plugin Settings"));
82  savePluginSettings->setToolTip(tr("Plugins should add their current global settings to the file"));
83  savePluginSettings->setCheckState( Qt::Checked );
84 
85  QCheckBox *saveObjectInfo = new QCheckBox(optionsBox);
86  saveObjectInfo->setText(tr("Save open object information to the file"));
87  saveObjectInfo->setToolTip(tr("Save all open Objects and add them to the settings file ( they will be loaded if opening the settings file"));
88  saveObjectInfo->setCheckState( Qt::Checked );
89 
90  QCheckBox *saveAllBox = new QCheckBox(optionsBox);
91  saveAllBox->setText(tr("Save everything to same folder"));
92  saveAllBox->setToolTip(tr("Save all open files to the same folder as the ini file"));
93  saveAllBox->setCheckState( Qt::Checked );
94 
95  QCheckBox *askOverwrite = new QCheckBox(optionsBox);
96  askOverwrite->setText(tr("Ask before overwriting files"));
97  askOverwrite->setToolTip(tr("If a file exists you will get asked what to do"));
98  askOverwrite->setCheckState( Qt::Checked );
99 
100  QCheckBox *targetOnly = new QCheckBox(optionsBox);
101  targetOnly->setText(tr("Save only target objects"));
102  targetOnly->setToolTip(tr("Only objects with target flag will be handled"));
103  targetOnly->setCheckState( Qt::Unchecked );
104 
105  QBoxLayout* frameLayout = new QBoxLayout(QBoxLayout::TopToBottom,optionsBox);
106 
107  #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
108  frameLayout->addWidget( saveProgramSettings , 0 , 0);
109  frameLayout->addWidget( savePluginSettings , 1 , 0);
110  frameLayout->addWidget( saveObjectInfo , 2 , 0);
111  frameLayout->addWidget( saveAllBox , 3 , 0);
112  frameLayout->addWidget( askOverwrite , 4 , 0);
113  frameLayout->addWidget( targetOnly , 5 , 0);
114  #else
115  frameLayout->addWidget( saveProgramSettings , 0 , Qt::Alignment());
116  frameLayout->addWidget( savePluginSettings , 1 , Qt::Alignment());
117  frameLayout->addWidget( saveObjectInfo , 2 , Qt::Alignment());
118  frameLayout->addWidget( saveAllBox , 3 , Qt::Alignment());
119  frameLayout->addWidget( askOverwrite , 4 , Qt::Alignment());
120  frameLayout->addWidget( targetOnly , 5 , Qt::Alignment());
121  #endif
122  frameLayout->addStretch();
123 
124  fileDialog.resize(550 ,600);
125 
126  // ========================================================================================
127  // show the saveSettings-Dialog and get the target file
128  // ========================================================================================
129  QStringList fileNames;
130  if (fileDialog.exec()) {
131  fileNames = fileDialog.selectedFiles();
132  } else {
133  return;
134  }
135 
136  if ( fileNames.size() > 1 ) {
137  std::cerr << "Too many save filenames selected" << std::endl;
138  return;
139  }
140 
141  QString complete_name = fileNames[0];
142 
143  //check the extension if its a known one
144  if ( !complete_name.endsWith(".ini", Qt::CaseInsensitive) && !complete_name.endsWith(".obj", Qt::CaseInsensitive) ){
145 
146  // If its unknown, get the type from the currently selected filter and add this extension to the filename
147  if ( fileDialog.selectedNameFilter().contains(tr("INI files (*.ini)")) )
148  complete_name += ".ini";
149  else
150  complete_name += ".obj";
151 
152  }
153 
154  bool is_saveObjectInfo = saveObjectInfo->isChecked();
155  bool is_targetOnly = targetOnly->isChecked();
156  bool is_saveAll = saveAllBox->isChecked();
157  bool is_askOverwrite = askOverwrite->isChecked();
158  bool is_saveProgramSettings = saveProgramSettings->isChecked();
159  bool is_savePluginSettings = savePluginSettings->isChecked();
160 
161  saveSettings(complete_name, is_saveObjectInfo, is_targetOnly, is_saveAll, is_askOverwrite, is_saveProgramSettings, is_savePluginSettings);
162 }
163 
164 void Core::saveSettings(QString complete_name, bool is_saveObjectInfo, bool is_targetOnly, bool is_saveAll,
165  bool is_askOverwrite, bool is_saveProgramSettings, bool is_savePluginSettings){
166  // Get the chosen directory and remember it.
167  QFileInfo fileInfo(complete_name);
168  OpenFlipperSettings().setValue("Core/CurrentDir", fileInfo.absolutePath() );
169 
170  // ========================================================================================
171  // update status information
172  // ========================================================================================
173  OpenFlipper::Options::savingSettings(true);
174 
175  if ( OpenFlipper::Options::gui() ) {
176  coreWidget_->statusMessage( tr("Saving Settings to ") + complete_name + " ...");
178  }
179 
180  // ========================================================================================
181  // Save the objects itself
182  // ========================================================================================
183  // Depending on the checkbox iterate over all objects or only the selected ones.
184 
185  // Memorize saved files new file names
186  std::map<int,QString> savedFiles;
187 
188  if ( is_saveObjectInfo ) {
189 
191  if ( is_targetOnly )
192  restriction = PluginFunctions::TARGET_OBJECTS;
193  else
194  restriction = PluginFunctions::ALL_OBJECTS;
195 
196  // Store saved file's original names (in order to get number of duplicates)
197  std::multiset<QString> originalFiles;
198 
199  // Store default extensions per type
200  std::map<DataType,QString> defaultExtensions;
201  // get the supported extensions for when no extension is given
202  QMultiMap<DataType,QString> allFilters; // type -> supported extension
203  const std::vector<fileTypes>& types = supportedTypes();
204  for (int i=0; i < (int)types.size(); i++) {
205  QString filters = types[i].saveFilters;
206 
207  // only take the actual extensions
208  filters = filters.section("(",1).section(")",0,0);
209  if (filters.trimmed() == "")
210  continue;
211 
212  QStringList separateFilters = filters.split(" ");
213  bool found = false;
214  for ( int filterId = 0 ; filterId < separateFilters.size(); ++filterId ) {
215  if (separateFilters[filterId].trimmed() == "")
216  continue;
217 
218  found = true;
219  allFilters.insert(types[i].type,separateFilters[filterId]);
220  }
221 
222  if (!found)
223  allFilters.insert(types[i].type,filters);
224  }
225 
226  // create a dialog to set extensions if none are given once
227  QDialog extensionDialog(coreWidget_, Qt::Dialog);
228  QGridLayout extensionLayout;
229  const QString extensionCheckBoxPrefixString = "Apply extension to all Objects without preset extensions with DataType: ";
230  QCheckBox extensionCheckBox;
231  QComboBox extensionComboBox;
232  QDialogButtonBox extensionButtons(QDialogButtonBox::Ok);
233  QDialogButtonBox::connect(&extensionButtons, SIGNAL(accepted()), &extensionDialog, SLOT(accept()));
234  //extensionComboBox.addItems(allFilters);
235  extensionLayout.addWidget(&extensionComboBox);
236  extensionLayout.addWidget(&extensionCheckBox);
237  extensionLayout.addWidget(&extensionButtons);
238  extensionDialog.setLayout(&extensionLayout);
239 
240  //Iterate over opened objects and save them
241  for (auto* o_it : PluginFunctions::objects(restriction) ) {
242  QString filename;
243 
244  if ( is_saveAll )
245  {
246  // Use path of settings file for all objects
247  filename = fileInfo.absolutePath() + OpenFlipper::Options::dirSeparator() + o_it->name();
248  }
249  else
250  {
251  // Use objects own path if it has one. Otherwise also use path of settings file
252  filename = o_it->path() + OpenFlipper::Options::dirSeparator() + o_it->name();
253 
254  // handle the case that the object was created in current session and not loaded from disk
255  if (o_it->path() == ".") {
256  filename = fileInfo.absolutePath() + OpenFlipper::Options::dirSeparator() + o_it->name();
257  std::cerr << "newpath : " << fileInfo.absolutePath().toStdString() << std::endl;
258  std::cerr << "name : " << o_it->name().toStdString() << std::endl;
259  }
260  }
261 
262  // enforce that all files end with obj extension if its an obj-settings file
263  if ( complete_name.endsWith("obj") )
264  {
265  if (!filename.endsWith("obj"))
266  {
267  // remove old extension
268  int pos = filename.lastIndexOf(".");
269  filename.remove(pos+1, filename.length() - pos);
270  // add obj extension
271  filename += "obj";
272  }
273  }
274 
275  /* @Todo: This is broken when Light source Object type is not available!
276  // Don't save default light source objects
277  LightObject* light = 0;
278  PluginFunctions::getObject( o_it->id(), light );
279  if(light != 0) {
280  if(light->defaultLight()) continue;
281  }
282 
283  */
284 
285  // Store original file name
286  originalFiles.insert(filename);
287 
288  // If a file with the same name already has been saved,
289  // rename it.
290  size_t c = originalFiles.count(filename);
291  if(c > 1) {
292  QFileInfo finfo(filename);
293  filename = finfo.absolutePath() + OpenFlipper::Options::dirSeparator();
294  filename += finfo.baseName() + QString("_%1").arg(c-1) + ".";
295  filename += finfo.completeSuffix();
296  }
297 
298  // check if the name of the object specifies already the extension
299  bool extInName = false;
300  for (QMultiMap<DataType,QString>::const_iterator e_it = allFilters.begin(); e_it != allFilters.end(); ++e_it)
301  {
302  // suffix is the same as one extension and
303  extInName = e_it.key().contains(o_it->dataType()) && e_it.value() == QString("*.")+QFileInfo(filename).suffix();
304  if (extInName)
305  break;
306  }
307 
308  if (!extInName)
309  {
310  // search for the default data type
311  std::map<DataType,QString>::const_iterator defaultExtIt = defaultExtensions.find(o_it->dataType());
312  bool useDefault = defaultExtIt != defaultExtensions.end();
313  QString extension = (useDefault) ? defaultExtIt->second : "";
314 
315  // if no default extension for the datatype was given, request one
316  if (!useDefault)
317  {
318  // present only those filters, which support the type
319  QStringList supportedFilters;
320  for (QMultiMap<DataType,QString>::const_iterator it = allFilters.begin(); it != allFilters.end() ; ++it)
321  {
322  if (it.key().contains(o_it->dataType()))
323  supportedFilters.append(it.value());
324  }
325 
326  extensionComboBox.clear();
327  extensionComboBox.addItems(supportedFilters);
328  extensionDialog.setWindowTitle("Please specify a file extension for " + o_it->name());
329  extensionCheckBox.setText(extensionCheckBoxPrefixString + typeName(o_it->dataType()));
330  extensionDialog.move(coreWidget_->width()/2 - extensionDialog.width(),
331  coreWidget_->height()/2 - extensionDialog.height());
332 
333  if (extensionDialog.exec() && !supportedFilters.isEmpty())
334  {
335  extension = extensionComboBox.currentText();
336  extension = QFileInfo(extension).suffix();
337  filename += "." + extension;
338  if (extensionCheckBox.isChecked())
339  defaultExtensions[o_it->dataType()] = extension;
340 
341  } else
342  {
343  emit log(LOGERR, tr("Unabel to save %1. No extension specified.").arg(o_it->name()));
344  continue;
345  }
346  } else
347  {
348  filename += "." + extension;
349  }
350  }
351 
352 
353  // decide whether to use saveObject or saveObjectTo
354  if ( !QFile(filename).exists() || !is_askOverwrite )
355  saveObject( o_it->id(), filename);
356  else
357  saveObjectTo(o_it->id(), filename);
358 
359  // Store saved file's name
360  savedFiles.insert(std::pair<int,QString>(o_it->id(),filename));
361 
362  }
363  }
364 
365 
366  // ========================================================================================
367  // Finally save all Settings
368  // ========================================================================================
369  if ( complete_name.endsWith("obj") ) {
370 
371  //write to obj
372  writeObjFile(complete_name, is_saveAll, is_targetOnly, savedFiles);
373 
374  } else {
375  // write to ini
376  writeIniFile( complete_name,
377  is_saveAll,
378  is_targetOnly,
379  is_saveProgramSettings,
380  is_savePluginSettings,
381  is_saveObjectInfo,
382  savedFiles);
383  }
384 
385  // update status
386  OpenFlipper::Options::savingSettings(false);
387 
388  if ( OpenFlipper::Options::gui() ) {
389  coreWidget_->statusMessage( tr("Saving Settings to ") + complete_name + tr(" ... Done"), 4000);
391  }
392 
393  //add to recent files
394  if ( OpenFlipper::Options::gui() )
395  coreWidget_->addRecent( complete_name, DATA_UNKNOWN );
396 
397 }
Status is ready (green light)
void writeIniFile(QString _filename, bool _relativePaths, bool _targetOnly, bool _saveSystemSettings, bool _savePluginSettings, bool _saveObjectInfo, std::map< int, QString > &_fileMapping)
Write current status to ini file (Application and File Options)
Definition: ParseIni.cc:540
const QStringList ALL_OBJECTS
Iterable object range.
void addRecent(QString _filename, DataType _type)
Add a recent file and update menu.
Definition: CoreWidget.cc:860
void saveSettings()
Save current status to a settings file. Solicit file name through dialog.
Definition: saveSettings.cc:53
void log(Logtype _type, QString _message)
Logg with OUT,WARN or ERR as type.
CoreWidget * coreWidget_
The main applications widget ( only created in gui mode )
Definition: Core.hh:1596
bool saveObjectTo(int _id, QString _filename)
QStringList IteratorRestriction
Iterable object range.
DLLEXPORT QString typeName(DataType _id)
Get the name of a type with given id.
Definition: Types.cc:154
const QStringList TARGET_OBJECTS("target")
Iterable object range.
ObjectRange objects(IteratorRestriction _restriction, DataType _dataType)
Iterable object range.
Status is processing and blocked system will not allow interaction (red light)
void writeObjFile(QString _filename, bool _relativePaths, bool _targetOnly, std::map< int, QString > &_fileMapping)
Write current status to obj file (Application and File Options)
Definition: ParseObj.cc:65
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
bool saveObject(int _id, QString _filename)
Save an object.
const DataType DATA_UNKNOWN(0)
None of the other Objects.