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
164void 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 )
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}
const DataType DATA_UNKNOWN(0)
None of the other Objects.
DLLEXPORT QString typeName(DataType _id)
Get the name of a type with given id.
Definition: Types.cc:154
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
@ LOGERR
void addRecent(QString _filename, DataType _type)
Add a recent file and update menu.
Definition: CoreWidget.cc:878
bool saveObjectTo(int _id, QString _filename)
void saveSettings()
Save current status to a settings file. Solicit file name through dialog.
Definition: saveSettings.cc:53
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 log(Logtype _type, QString _message)
Logg with OUT,WARN or ERR as type.
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.
CoreWidget * coreWidget_
The main applications widget ( only created in gui mode )
Definition: Core.hh:1652
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
@ READY
Status is ready (green light)
@ BLOCKED
Status is processing and blocked system will not allow interaction (red light)
QStringList IteratorRestriction
Iterable object range.
const QStringList TARGET_OBJECTS("target")
Iterable object range.
ObjectRange objects(IteratorRestriction _restriction, DataType _dataType)
Iterable object range.
const QStringList ALL_OBJECTS
Iterable object range.