/** * \return None * \brief This is a generic function to use the save function of * a module (including Autodetect) * \param key Identifier of which module to use * \param doc The document to be saved * \param filename The file that the document should be saved to * \param official (optional) whether to set :output_module and :modified in the * document; is true for normal save, false for temporary saves * * First things first, are we looking at an autodetection? Well if that's the case then the module * needs to be found, and that is done with a database lookup through the module DB. The foreach * function is called, with the parameter being a gpointer array. It contains both the filename * (to find its extension) and where to write the module when it is found. * * If there is no autodetection the module database is queried with the key given. * * If everything is cool at this point, the module is loaded, and there is possibility for * preferences. If there is a function, then it is executed to get the dialog to be displayed. * After it is finished the function continues. * * Lastly, the save function is called in the module itself. */ void save(Extension *key, SPDocument *doc, gchar const *filename, bool setextension, bool check_overwrite, bool official, Inkscape::Extension::FileSaveMethod save_method) { Output *omod; if (key == NULL) { gpointer parray[2]; parray[0] = (gpointer)filename; parray[1] = (gpointer)&omod; omod = NULL; db.foreach(save_internal, (gpointer)&parray); /* This is a nasty hack, but it is required to ensure that autodetect will always save with the Inkscape extensions if they are available. */ if (omod != NULL && !strcmp(omod->get_id(), SP_MODULE_KEY_OUTPUT_SVG)) { omod = dynamic_cast<Output *>(db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE)); } /* If autodetect fails, save as Inkscape SVG */ if (omod == NULL) { // omod = dynamic_cast<Output *>(db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE)); use exception and let user choose } } else { omod = dynamic_cast<Output *>(key); } if (!dynamic_cast<Output *>(omod)) { g_warning("Unable to find output module to handle file: %s\n", filename); throw Output::no_extension_found(); } omod->set_state(Extension::STATE_LOADED); if (!omod->loaded()) { throw Output::save_failed(); } if (!omod->prefs()) { throw Output::save_cancelled(); } gchar *fileName = NULL; if (setextension) { gchar *lowerfile = g_utf8_strdown(filename, -1); gchar *lowerext = g_utf8_strdown(omod->get_extension(), -1); if (!g_str_has_suffix(lowerfile, lowerext)) { fileName = g_strdup_printf("%s%s", filename, omod->get_extension()); } g_free(lowerfile); g_free(lowerext); } if (fileName == NULL) { fileName = g_strdup(filename); } if (check_overwrite && !sp_ui_overwrite_file(fileName)) { g_free(fileName); throw Output::no_overwrite(); } // test if the file exists and is writable // the test only checks the file attributes and might pass where ACL does not allow to write if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS) && !Inkscape::IO::file_is_writable(filename)) { g_free(fileName); throw Output::file_read_only(); } Inkscape::XML::Node *repr = doc->getReprRoot(); // remember attributes in case this is an unofficial save and/or overwrite fails gchar *saved_uri = g_strdup(doc->getURI()); gchar *saved_output_extension = NULL; gchar *saved_dataloss = NULL; bool saved_modified = doc->isModifiedSinceSave(); saved_output_extension = g_strdup(get_file_save_extension(save_method).c_str()); saved_dataloss = g_strdup(repr->attribute("inkscape:dataloss")); if (official) { // The document is changing name/uri. doc->changeUriAndHrefs(fileName); } // Update attributes: { bool const saved = DocumentUndo::getUndoSensitive(doc); DocumentUndo::setUndoSensitive(doc, false); { // also save the extension for next use store_file_extension_in_prefs (omod->get_id(), save_method); // set the "dataloss" attribute if the chosen extension is lossy repr->setAttribute("inkscape:dataloss", NULL); if (omod->causes_dataloss()) { repr->setAttribute("inkscape:dataloss", "true"); } } DocumentUndo::setUndoSensitive(doc, saved); doc->setModifiedSinceSave(false); } try { omod->save(doc, fileName); } catch(...) { // revert attributes in case of official and overwrite if(check_overwrite && official) { bool const saved = DocumentUndo::getUndoSensitive(doc); DocumentUndo::setUndoSensitive(doc, false); { store_file_extension_in_prefs (saved_output_extension, save_method); repr->setAttribute("inkscape:dataloss", saved_dataloss); } DocumentUndo::setUndoSensitive(doc, saved); doc->changeUriAndHrefs(saved_uri); } doc->setModifiedSinceSave(saved_modified); // free used ressources g_free(saved_output_extension); g_free(saved_dataloss); g_free(saved_uri); g_free(fileName); throw Inkscape::Extension::Output::save_failed(); } // If it is an unofficial save, set the modified attributes back to what they were. if ( !official) { bool const saved = DocumentUndo::getUndoSensitive(doc); DocumentUndo::setUndoSensitive(doc, false); { store_file_extension_in_prefs (saved_output_extension, save_method); repr->setAttribute("inkscape:dataloss", saved_dataloss); } DocumentUndo::setUndoSensitive(doc, saved); doc->setModifiedSinceSave(saved_modified); g_free(saved_output_extension); g_free(saved_dataloss); } g_free(fileName); return; }
/** * \return None * \brief This is a generic function to use the save function of * a module (including Autodetect) * \param key Identifier of which module to use * \param doc The document to be saved * \param filename The file that the document should be saved to * \param official (optional) whether to set :output_module and :modified in the * document; is true for normal save, false for temporary saves * * First things first, are we looking at an autodetection? Well if that's the case then the module * needs to be found, and that is done with a database lookup through the module DB. The foreach * function is called, with the parameter being a gpointer array. It contains both the filename * (to find its extension) and where to write the module when it is found. * * If there is no autodetection the module database is queried with the key given. * * If everything is cool at this point, the module is loaded, and there is possibility for * preferences. If there is a function, then it is executed to get the dialog to be displayed. * After it is finished the function continues. * * Lastly, the save function is called in the module itself. */ void save(Extension *key, SPDocument *doc, gchar const *filename, bool setextension, bool check_overwrite, bool official) { Output *omod; if (key == NULL) { gpointer parray[2]; parray[0] = (gpointer)filename; parray[1] = (gpointer)&omod; omod = NULL; db.foreach(save_internal, (gpointer)&parray); /* This is a nasty hack, but it is required to ensure that autodetect will always save with the Inkscape extensions if they are available. */ if (omod != NULL && !strcmp(omod->get_id(), SP_MODULE_KEY_OUTPUT_SVG)) { omod = dynamic_cast<Output *>(db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE)); } /* If autodetect fails, save as Inkscape SVG */ if (omod == NULL) { omod = dynamic_cast<Output *>(db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE)); } } else { omod = dynamic_cast<Output *>(key); } if (!dynamic_cast<Output *>(omod)) { g_warning("Unable to find output module to handle file: %s\n", filename); throw Output::no_extension_found(); return; } omod->set_state(Extension::STATE_LOADED); if (!omod->loaded()) { throw Output::save_failed(); } if (!omod->prefs()) { throw Output::save_cancelled(); } gchar *fileName = NULL; if (setextension) { gchar *lowerfile = g_utf8_strdown(filename, -1); gchar *lowerext = g_utf8_strdown(omod->get_extension(), -1); if (!g_str_has_suffix(lowerfile, lowerext)) { fileName = g_strdup_printf("%s%s", filename, omod->get_extension()); } g_free(lowerfile); g_free(lowerext); } if (fileName == NULL) { fileName = g_strdup(filename); } if (check_overwrite && !sp_ui_overwrite_file(fileName)) { g_free(fileName); throw Output::no_overwrite(); } Inkscape::XML::Node *repr = sp_document_repr_root(doc); // remember attributes in case this is an unofficial save bool saved_modified = false; gchar *saved_output_extension = NULL; gchar *saved_dataloss = NULL; gchar *saved_uri = NULL; if (!official) { saved_modified = doc->isModifiedSinceSave(); if (repr->attribute("inkscape:output_extension")) { saved_output_extension = g_strdup(repr->attribute("inkscape:output_extension")); } if (repr->attribute("inkscape:dataloss")) { saved_dataloss = g_strdup(repr->attribute("inkscape:dataloss")); } if (doc->uri) { saved_uri = g_strdup(doc->uri); } } // update attributes: bool saved = sp_document_get_undo_sensitive(doc); sp_document_set_undo_sensitive (doc, false); // save the filename for next use sp_document_set_uri(doc, fileName); // also save the extension for next use repr->setAttribute("inkscape:output_extension", omod->get_id()); // set the "dataloss" attribute if the chosen extension is lossy repr->setAttribute("inkscape:dataloss", NULL); if ( omod->causes_dataloss() ) { repr->setAttribute("inkscape:dataloss", "true"); } sp_document_set_undo_sensitive (doc, saved); doc->setModifiedSinceSave(false); omod->save(doc, fileName); // if it is an unofficial save, set the modified attributes back to what they were if ( !official) { saved = sp_document_get_undo_sensitive(doc); sp_document_set_undo_sensitive (doc, false); repr->setAttribute("inkscape:output_extension", saved_output_extension); repr->setAttribute("inkscape:dataloss", saved_dataloss); sp_document_set_uri(doc, saved_uri); sp_document_set_undo_sensitive (doc, saved); doc->setModifiedSinceSave(saved_modified); } if (saved_output_extension) g_free(saved_output_extension); if (saved_dataloss) g_free(saved_dataloss); if (saved_uri) g_free(saved_uri); g_free(fileName); return; }