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  frameLayout->addWidget( saveProgramSettings , 0 , 0);
107  frameLayout->addWidget( savePluginSettings , 1 , 0);
108  frameLayout->addWidget( saveObjectInfo , 2 , 0);
109  frameLayout->addWidget( saveAllBox , 3 , 0);
110  frameLayout->addWidget( askOverwrite , 4 , 0);
111  frameLayout->addWidget( targetOnly , 5 , 0);
112  frameLayout->addStretch();
113 
114  fileDialog.resize(550 ,600);
115 
116  // ========================================================================================
117  // show the saveSettings-Dialog and get the target file
118  // ========================================================================================
119  QStringList fileNames;
120  if (fileDialog.exec()) {
121  fileNames = fileDialog.selectedFiles();
122  } else {
123  return;
124  }
125 
126  if ( fileNames.size() > 1 ) {
127  std::cerr << "Too many save filenames selected" << std::endl;
128  return;
129  }
130 
131  QString complete_name = fileNames[0];
132 
133  //check the extension if its a known one
134  if ( !complete_name.endsWith(".ini", Qt::CaseInsensitive) && !complete_name.endsWith(".obj", Qt::CaseInsensitive) ){
135 
136  // If its unknown, get the type from the currently selected filter and add this extension to the filename
137  if ( fileDialog.selectedNameFilter().contains(tr("INI files (*.ini)")) )
138  complete_name += ".ini";
139  else
140  complete_name += ".obj";
141 
142  }
143 
144  bool is_saveObjectInfo = saveObjectInfo->isChecked();
145  bool is_targetOnly = targetOnly->isChecked();
146  bool is_saveAll = saveAllBox->isChecked();
147  bool is_askOverwrite = askOverwrite->isChecked();
148  bool is_saveProgramSettings = saveProgramSettings->isChecked();
149  bool is_savePluginSettings = savePluginSettings->isChecked();
150 
151  saveSettings(complete_name, is_saveObjectInfo, is_targetOnly, is_saveAll, is_askOverwrite, is_saveProgramSettings, is_savePluginSettings);
152 }
153 
154 void Core::saveSettings(QString complete_name, bool is_saveObjectInfo, bool is_targetOnly, bool is_saveAll,
155  bool is_askOverwrite, bool is_saveProgramSettings, bool is_savePluginSettings){
156  // Get the chosen directory and remember it.
157  QFileInfo fileInfo(complete_name);
158  OpenFlipperSettings().setValue("Core/CurrentDir", fileInfo.absolutePath() );
159 
160  // ========================================================================================
161  // update status information
162  // ========================================================================================
163  OpenFlipper::Options::savingSettings(true);
164 
165  if ( OpenFlipper::Options::gui() ) {
166  coreWidget_->statusMessage( tr("Saving Settings to ") + complete_name + " ...");
168  }
169 
170  // ========================================================================================
171  // Save the objects itself
172  // ========================================================================================
173  // Depending on the checkbox iterate over all objects or only the selected ones.
174 
175  // Memorize saved files new file names
176  std::map<int,QString> savedFiles;
177 
178  if ( is_saveObjectInfo ) {
179 
181  if ( is_targetOnly )
182  restriction = PluginFunctions::TARGET_OBJECTS;
183  else
184  restriction = PluginFunctions::ALL_OBJECTS;
185 
186  // Store saved file's original names (in order to get number of duplicates)
187  std::multiset<QString> originalFiles;
188 
189  // Store default extensions per type
190  std::map<DataType,QString> defaultExtensions;
191  // get the supported extensions for when no extension is given
192  QMultiMap<DataType,QString> allFilters; // type -> supported extension
193  const std::vector<fileTypes>& types = supportedTypes();
194  for (int i=0; i < (int)types.size(); i++) {
195  QString filters = types[i].saveFilters;
196 
197  // only take the actual extensions
198  filters = filters.section("(",1).section(")",0,0);
199  if (filters.trimmed() == "")
200  continue;
201 
202  QStringList separateFilters = filters.split(" ");
203  bool found = false;
204  for ( int filterId = 0 ; filterId < separateFilters.size(); ++filterId ) {
205  if (separateFilters[filterId].trimmed() == "")
206  continue;
207 
208  found = true;
209  allFilters.insert(types[i].type,separateFilters[filterId]);
210  }
211 
212  if (!found)
213  allFilters.insert(types[i].type,filters);
214  }
215 
216  // create a dialog to set extensions if none are given once
217  QDialog extensionDialog(coreWidget_, Qt::Dialog);
218  QGridLayout extensionLayout;
219  const QString extensionCheckBoxPrefixString = "Apply extension to all Objects without preset extensions with DataType: ";
220  QCheckBox extensionCheckBox;
221  QComboBox extensionComboBox;
222  QDialogButtonBox extensionButtons(QDialogButtonBox::Ok);
223  QDialogButtonBox::connect(&extensionButtons, SIGNAL(accepted()), &extensionDialog, SLOT(accept()));
224  //extensionComboBox.addItems(allFilters);
225  extensionLayout.addWidget(&extensionComboBox);
226  extensionLayout.addWidget(&extensionCheckBox);
227  extensionLayout.addWidget(&extensionButtons);
228  extensionDialog.setLayout(&extensionLayout);
229 
230  //Iterate over opened objects and save them
231  for ( PluginFunctions::ObjectIterator o_it(restriction);
232  o_it != PluginFunctions::objectsEnd(); ++o_it)
233  {
234  QString filename;
235 
236  if ( is_saveAll )
237  {
238  // Use path of settings file for all objects
239  filename = fileInfo.absolutePath() + OpenFlipper::Options::dirSeparator() + o_it->name();
240  }
241  else
242  {
243  // Use objects own path if it has one. Otherwise also use path of settings file
244  filename = o_it->path() + OpenFlipper::Options::dirSeparator() + o_it->name();
245 
246  // handle the case that the object was created in current session and not loaded from disk
247  if (o_it->path() == ".") {
248  filename = fileInfo.absolutePath() + OpenFlipper::Options::dirSeparator() + o_it->name();
249  std::cerr << "newpath : " << fileInfo.absolutePath().toStdString() << std::endl;
250  std::cerr << "name : " << o_it->name().toStdString() << std::endl;
251  }
252  }
253 
254  // enforce that all files end with obj extension if its an obj-settings file
255  if ( complete_name.endsWith("obj") )
256  {
257  if (!filename.endsWith("obj"))
258  {
259  // remove old extension
260  int pos = filename.lastIndexOf(".");
261  filename.remove(pos+1, filename.length() - pos);
262  // add obj extension
263  filename += "obj";
264  }
265  }
266 
267  /* @Todo: This is broken when Light source Object type is not available!
268  // Don't save default light source objects
269  LightObject* light = 0;
270  PluginFunctions::getObject( o_it->id(), light );
271  if(light != 0) {
272  if(light->defaultLight()) continue;
273  }
274 
275  */
276 
277  // Store original file name
278  originalFiles.insert(filename);
279 
280  // If a file with the same name already has been saved,
281  // rename it.
282  size_t c = originalFiles.count(filename);
283  if(c > 1) {
284  QFileInfo finfo(filename);
285  filename = finfo.absolutePath() + OpenFlipper::Options::dirSeparator();
286  filename += finfo.baseName() + QString("_%1").arg(c-1) + ".";
287  filename += finfo.completeSuffix();
288  }
289 
290  // check if the name of the object specifies already the extension
291  bool extInName = false;
292  for (QMultiMap<DataType,QString>::const_iterator e_it = allFilters.begin(); e_it != allFilters.end(); ++e_it)
293  {
294  // suffix is the same as one extension and
295  extInName = e_it.key().contains(o_it->dataType()) && e_it.value() == QString("*.")+QFileInfo(filename).suffix();
296  if (extInName)
297  break;
298  }
299 
300  if (!extInName)
301  {
302  // search for the default data type
303  std::map<DataType,QString>::const_iterator defaultExtIt = defaultExtensions.find(o_it->dataType());
304  bool useDefault = defaultExtIt != defaultExtensions.end();
305  QString extension = (useDefault) ? defaultExtIt->second : "";
306 
307  // if no default extension for the datatype was given, request one
308  if (!useDefault)
309  {
310  // present only those filters, which support the type
311  QStringList supportedFilters;
312  for (QMultiMap<DataType,QString>::const_iterator it = allFilters.begin(); it != allFilters.end() ; ++it)
313  {
314  if (it.key().contains(o_it->dataType()))
315  supportedFilters.append(it.value());
316  }
317 
318  extensionComboBox.clear();
319  extensionComboBox.addItems(supportedFilters);
320  extensionDialog.setWindowTitle("Please specify a file extension for " + o_it->name());
321  extensionCheckBox.setText(extensionCheckBoxPrefixString + typeName(o_it->dataType()));
322  extensionDialog.move(coreWidget_->width()/2 - extensionDialog.width(),
323  coreWidget_->height()/2 - extensionDialog.height());
324 
325  if (extensionDialog.exec() && !supportedFilters.isEmpty())
326  {
327  extension = extensionComboBox.currentText();
328  extension = QFileInfo(extension).suffix();
329  filename += "." + extension;
330  if (extensionCheckBox.isChecked())
331  defaultExtensions[o_it->dataType()] = extension;
332 
333  } else
334  {
335  emit log(LOGERR, tr("Unabel to save %1. No extension specified.").arg(o_it->name()));
336  continue;
337  }
338  } else
339  {
340  filename += "." + extension;
341  }
342  }
343 
344 
345  // decide whether to use saveObject or saveObjectTo
346  if ( !QFile(filename).exists() || !is_askOverwrite )
347  saveObject( o_it->id(), filename);
348  else
349  saveObjectTo(o_it->id(), filename);
350 
351  // Store saved file's name
352  savedFiles.insert(std::pair<int,QString>(o_it->id(),filename));
353 
354  }
355  }
356 
357 
358  // ========================================================================================
359  // Finally save all Settings
360  // ========================================================================================
361  if ( complete_name.endsWith("obj") ) {
362 
363  //write to obj
364  writeObjFile(complete_name, is_saveAll, is_targetOnly, savedFiles);
365 
366  } else {
367  // write to ini
368  writeIniFile( complete_name,
369  is_saveAll,
370  is_targetOnly,
371  is_saveProgramSettings,
372  is_savePluginSettings,
373  is_saveObjectInfo,
374  savedFiles);
375  }
376 
377  // update status
378  OpenFlipper::Options::savingSettings(false);
379 
380  if ( OpenFlipper::Options::gui() ) {
381  coreWidget_->statusMessage( tr("Saving Settings to ") + complete_name + tr(" ... Done"), 4000);
383  }
384 
385  //add to recent files
386  if ( OpenFlipper::Options::gui() )
387  coreWidget_->addRecent( complete_name, DATA_UNKNOWN );
388 
389 }
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
void saveSettings()
Save current status to a settings file. Solicit file name through dialog.
Definition: saveSettings.cc:53
Status is ready (green light)
Status is processing and blocked system will not allow interaction (red light)
DLLEXPORT QString typeName(DataType _id)
Get the name of a type with given id.
Definition: Types.cc:154
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
void addRecent(QString _filename, DataType _type)
Add a recent file and update menu.
Definition: CoreWidget.cc:860
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
const QStringList TARGET_OBJECTS("target")
Iterable object range.
QStringList IteratorRestriction
Iterable object range.
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
const QStringList ALL_OBJECTS
Iterable object range.
bool saveObjectTo(int _id, QString _filename)
const DataType DATA_UNKNOWN(0)
None of the other Objects.
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
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
bool saveObject(int _id, QString _filename)
Save an object.