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 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49 
50 
51 #include "Core.hh"
52 
54 
57 
58  // ========================================================================================
59  // generate the saveSettings-Dialog
60  // ========================================================================================
61 
62  QFileDialog fileDialog( coreWidget_,
63  tr("Save Settings"),
64  OpenFlipperSettings().value("Core/CurrentDir").toString(),
65  tr("INI files (*.ini);;OBJ files (*.obj )") );
66 
67  fileDialog.setOption (QFileDialog::DontUseNativeDialog, true);
68  fileDialog.setAcceptMode ( QFileDialog::AcceptSave );
69  fileDialog.setFileMode ( QFileDialog::AnyFile );
70 
71  QGridLayout *layout = (QGridLayout*)fileDialog.layout();
72 
73  QGroupBox* optionsBox = new QGroupBox( &fileDialog ) ;
74  optionsBox->setSizePolicy( QSizePolicy ( QSizePolicy::Expanding , QSizePolicy::Preferred ) );
75  optionsBox->setTitle(tr("Options"));
76  layout->addWidget( optionsBox, layout->rowCount() , 0 , 1,layout->columnCount() );
77 
78  QCheckBox *saveProgramSettings = new QCheckBox(optionsBox);
79  saveProgramSettings->setText(tr("Save program settings"));
80  saveProgramSettings->setToolTip(tr("Save all current program settings to the file ( This will include view settings, colors,...) "));
81  saveProgramSettings->setCheckState( Qt::Unchecked );
82 
83  QCheckBox *savePluginSettings = new QCheckBox(optionsBox);
84  savePluginSettings->setText(tr("Save per Plugin Settings"));
85  savePluginSettings->setToolTip(tr("Plugins should add their current global settings to the file"));
86  savePluginSettings->setCheckState( Qt::Checked );
87 
88  QCheckBox *saveObjectInfo = new QCheckBox(optionsBox);
89  saveObjectInfo->setText(tr("Save open object information to the file"));
90  saveObjectInfo->setToolTip(tr("Save all open Objects and add them to the settings file ( they will be loaded if opening the settings file"));
91  saveObjectInfo->setCheckState( Qt::Checked );
92 
93  QCheckBox *saveAllBox = new QCheckBox(optionsBox);
94  saveAllBox->setText(tr("Save everything to same folder"));
95  saveAllBox->setToolTip(tr("Save all open files to the same folder as the ini file"));
96  saveAllBox->setCheckState( Qt::Checked );
97 
98  QCheckBox *askOverwrite = new QCheckBox(optionsBox);
99  askOverwrite->setText(tr("Ask before overwriting files"));
100  askOverwrite->setToolTip(tr("If a file exists you will get asked what to do"));
101  askOverwrite->setCheckState( Qt::Checked );
102 
103  QCheckBox *targetOnly = new QCheckBox(optionsBox);
104  targetOnly->setText(tr("Save only target objects"));
105  targetOnly->setToolTip(tr("Only objects with target flag will be handled"));
106  targetOnly->setCheckState( Qt::Unchecked );
107 
108  QBoxLayout* frameLayout = new QBoxLayout(QBoxLayout::TopToBottom,optionsBox);
109  frameLayout->addWidget( saveProgramSettings , 0 , 0);
110  frameLayout->addWidget( savePluginSettings , 1 , 0);
111  frameLayout->addWidget( saveObjectInfo , 2 , 0);
112  frameLayout->addWidget( saveAllBox , 3 , 0);
113  frameLayout->addWidget( askOverwrite , 4 , 0);
114  frameLayout->addWidget( targetOnly , 5 , 0);
115  frameLayout->addStretch();
116 
117  fileDialog.resize(550 ,600);
118 
119  // ========================================================================================
120  // show the saveSettings-Dialog and get the target file
121  // ========================================================================================
122  QStringList fileNames;
123  if (fileDialog.exec()) {
124  fileNames = fileDialog.selectedFiles();
125  } else {
126  return;
127  }
128 
129  if ( fileNames.size() > 1 ) {
130  std::cerr << "Too many save filenames selected" << std::endl;
131  return;
132  }
133 
134  QString complete_name = fileNames[0];
135 
136  //check the extension if its a known one
137  if ( !complete_name.endsWith(".ini", Qt::CaseInsensitive) && !complete_name.endsWith(".obj", Qt::CaseInsensitive) ){
138 
139  // If its unknown, get the type from the currently selected filter and add this extension to the filename
140  if ( fileDialog.selectedNameFilter().contains(tr("INI files (*.ini)")) )
141  complete_name += ".ini";
142  else
143  complete_name += ".obj";
144 
145  }
146 
147  bool is_saveObjectInfo = saveObjectInfo->isChecked();
148  bool is_targetOnly = targetOnly->isChecked();
149  bool is_saveAll = saveAllBox->isChecked();
150  bool is_askOverwrite = askOverwrite->isChecked();
151  bool is_saveProgramSettings = saveProgramSettings->isChecked();
152  bool is_savePluginSettings = savePluginSettings->isChecked();
153 
154  saveSettings(complete_name, is_saveObjectInfo, is_targetOnly, is_saveAll, is_askOverwrite, is_saveProgramSettings, is_savePluginSettings);
155 }
156 
157 void Core::saveSettings(QString complete_name, bool is_saveObjectInfo, bool is_targetOnly, bool is_saveAll,
158  bool is_askOverwrite, bool is_saveProgramSettings, bool is_savePluginSettings){
159  // Get the chosen directory and remember it.
160  QFileInfo fileInfo(complete_name);
161  OpenFlipperSettings().setValue("Core/CurrentDir", fileInfo.absolutePath() );
162 
163  // ========================================================================================
164  // update status information
165  // ========================================================================================
166  OpenFlipper::Options::savingSettings(true);
167 
168  if ( OpenFlipper::Options::gui() ) {
169  coreWidget_->statusMessage( tr("Saving Settings to ") + complete_name + " ...");
171  }
172 
173  // ========================================================================================
174  // Save the objects itself
175  // ========================================================================================
176  // Depending on the checkbox iterate over all objects or only the selected ones.
177 
178  // Memorize saved files new file names
179  std::map<int,QString> savedFiles;
180 
181  if ( is_saveObjectInfo ) {
182 
184  if ( is_targetOnly )
185  restriction = PluginFunctions::TARGET_OBJECTS;
186  else
187  restriction = PluginFunctions::ALL_OBJECTS;
188 
189  // Store saved file's original names (in order to get number of duplicates)
190  std::multiset<QString> originalFiles;
191 
192  // Store default extensions per type
193  std::map<DataType,QString> defaultExtensions;
194  // get the supported extensions for when no extension is given
195  QMultiMap<DataType,QString> allFilters; // type -> supported extension
196  const std::vector<fileTypes>& types = supportedTypes();
197  for (int i=0; i < (int)types.size(); i++) {
198  QString filters = types[i].saveFilters;
199 
200  // only take the actual extensions
201  filters = filters.section("(",1).section(")",0,0);
202  if (filters.trimmed() == "")
203  continue;
204 
205  QStringList separateFilters = filters.split(" ");
206  bool found = false;
207  for ( int filterId = 0 ; filterId < separateFilters.size(); ++filterId ) {
208  if (separateFilters[filterId].trimmed() == "")
209  continue;
210 
211  found = true;
212  allFilters.insert(types[i].type,separateFilters[filterId]);
213  }
214 
215  if (!found)
216  allFilters.insert(types[i].type,filters);
217  }
218 
219  // create a dialog to set extensions if none are given once
220  QDialog extensionDialog(coreWidget_, Qt::Dialog);
221  QGridLayout extensionLayout;
222  const QString extensionCheckBoxPrefixString = "Apply extension to all Objects without preset extensions with DataType: ";
223  QCheckBox extensionCheckBox;
224  QComboBox extensionComboBox;
225  QDialogButtonBox extensionButtons(QDialogButtonBox::Ok);
226  QDialogButtonBox::connect(&extensionButtons, SIGNAL(accepted()), &extensionDialog, SLOT(accept()));
227  //extensionComboBox.addItems(allFilters);
228  extensionLayout.addWidget(&extensionComboBox);
229  extensionLayout.addWidget(&extensionCheckBox);
230  extensionLayout.addWidget(&extensionButtons);
231  extensionDialog.setLayout(&extensionLayout);
232 
233  //Iterate over opened objects and save them
234  for ( PluginFunctions::ObjectIterator o_it(restriction);
235  o_it != PluginFunctions::objectsEnd(); ++o_it)
236  {
237  QString filename;
238 
239  if ( is_saveAll )
240  {
241  // Use path of settings file for all objects
242  filename = fileInfo.absolutePath() + OpenFlipper::Options::dirSeparator() + o_it->name();
243  }
244  else
245  {
246  // Use objects own path if it has one. Otherwise also use path of settings file
247  filename = o_it->path() + OpenFlipper::Options::dirSeparator() + o_it->name();
248 
249  // handle the case that the object was created in current session and not loaded from disk
250  if (o_it->path() == ".") {
251  filename = fileInfo.absolutePath() + OpenFlipper::Options::dirSeparator() + o_it->name();
252  std::cerr << "newpath : " << fileInfo.absolutePath().toStdString() << std::endl;
253  std::cerr << "name : " << o_it->name().toStdString() << std::endl;
254  }
255  }
256 
257  // enforce that all files end with obj extension if its an obj-settings file
258  if ( complete_name.endsWith("obj") )
259  {
260  if (!filename.endsWith("obj"))
261  {
262  // remove old extension
263  int pos = filename.lastIndexOf(".");
264  filename.remove(pos+1, filename.length() - pos);
265  // add obj extension
266  filename += "obj";
267  }
268  }
269 
270  // Don't save default light source objects
271  LightObject* light = 0;
272  PluginFunctions::getObject( o_it->id(), light );
273  if(light != 0) {
274  if(light->defaultLight()) continue;
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 }
bool defaultLight() const
Is light default light source?
Definition: LightObject.hh:130
QStringList IteratorRestriction
Iterable object range.
void addRecent(QString _filename, DataType _type)
Add a recent file and update menu.
Definition: CoreWidget.cc:893
CoreWidget * coreWidget_
The main applications widget ( only created in gui mode )
Definition: Core.hh:1553
bool getObject(int _identifier, BSplineCurveObject *&_object)
bool saveObject(int _id, QString _filename)
Save an object.
const QStringList TARGET_OBJECTS("target")
Iterable object range.
Status is ready (green light)
bool saveObjectTo(int _id, QString _filename)
const DataType DATA_UNKNOWN(0)
None of the other Objects.
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:56
const QStringList ALL_OBJECTS
Iterable object range.
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:71
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
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:546
Status is processing and blocked system will not allow interaction (red light)
void log(Logtype _type, QString _message)
Logg with OUT,WARN or ERR as type.
DLLEXPORT QString typeName(DataType _id)
Get the name of a type with given id.
Definition: Types.cc:165
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.