summaryrefslogtreecommitdiffstats
path: root/src/ui/dialog/export-batch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/dialog/export-batch.cpp')
-rw-r--r--src/ui/dialog/export-batch.cpp768
1 files changed, 768 insertions, 0 deletions
diff --git a/src/ui/dialog/export-batch.cpp b/src/ui/dialog/export-batch.cpp
new file mode 100644
index 0000000..ae92f9e
--- /dev/null
+++ b/src/ui/dialog/export-batch.cpp
@@ -0,0 +1,768 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * bulia byak <buliabyak@users.sf.net>
+ * Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
+ * Anshudhar Kumar Singh <anshudhar2001@gmail.com>
+ *
+ * Copyright (C) 1999-2007, 2021 Authors
+ * Copyright (C) 2001-2002 Ximian, Inc.
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "export-batch.h"
+
+#include <glibmm/convert.h>
+#include <glibmm/i18n.h>
+#include <glibmm/miscutils.h>
+#include <gtkmm.h>
+#include <png.h>
+#include <regex>
+
+#include "desktop.h"
+#include "document-undo.h"
+#include "document.h"
+#include "extension/db.h"
+#include "extension/output.h"
+#include "file.h"
+#include "helper/png-write.h"
+#include "inkscape-window.h"
+#include "inkscape.h"
+#include "io/resource.h"
+#include "io/sys.h"
+#include "layer-manager.h"
+#include "message-stack.h"
+#include "object/object-set.h"
+#include "object/sp-namedview.h"
+#include "object/sp-page.h"
+#include "object/sp-root.h"
+#include "page-manager.h"
+#include "preferences.h"
+#include "selection-chemistry.h"
+#include "ui/dialog-events.h"
+#include "ui/dialog/export.h"
+#include "ui/dialog/dialog-notebook.h"
+#include "ui/dialog/filedialog.h"
+#include "ui/interface.h"
+#include "ui/widget/export-lists.h"
+#include "ui/widget/export-preview.h"
+#include "ui/widget/scrollprotected.h"
+#include "ui/widget/unit-menu.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+class BatchItem : public Gtk::FlowBoxChild
+{
+public:
+ BatchItem(SPItem *item);
+ BatchItem(SPPage *page);
+ ~BatchItem() override = default;
+
+ Glib::ustring getLabel() { return _label_str; }
+ SPItem *getItem() { return _item; }
+ SPPage *getPage() { return _page; }
+ bool isActive() { return _selector.get_active(); }
+ void refresh(bool hide = false);
+ void refreshHide(const std::vector<SPItem *> &list) { _preview.refreshHide(list); }
+ void setDocument(SPDocument *doc) { _preview.setDocument(doc); }
+
+private:
+ void init(SPDocument *doc, Glib::ustring label);
+
+ Glib::ustring _label_str;
+ Gtk::Grid _grid;
+ Gtk::Label _label;
+ Gtk::CheckButton _selector;
+ ExportPreview _preview;
+ SPItem *_item = nullptr;
+ SPPage *_page = nullptr;
+ bool is_hide = false;
+};
+
+BatchItem::BatchItem(SPItem *item)
+{
+ _item = item;
+
+ Glib::ustring id = _item->defaultLabel();
+ if (id.empty()) {
+ if (auto _id = _item->getId()) {
+ id = _id;
+ } else {
+ id = "no-id";
+ }
+ }
+ init(_item->document, id);
+}
+
+BatchItem::BatchItem(SPPage *page)
+{
+ _page = page;
+
+ Glib::ustring label = _page->getDefaultLabel();
+ if (auto id = _page->label()) {
+ label = id;
+ }
+ init(_page->document, label);
+}
+
+void BatchItem::init(SPDocument *doc, Glib::ustring label) {
+ _label_str = label;
+
+ _grid.set_row_spacing(5);
+ _grid.set_column_spacing(5);
+ _grid.set_valign(Gtk::Align::ALIGN_CENTER);
+
+ _selector.set_active(true);
+ _selector.set_can_focus(false);
+ _selector.set_margin_start(2);
+ _selector.set_margin_bottom(2);
+
+ _preview.set_name("export_preview_batch");
+ _preview.setItem(_item);
+ _preview.setDocument(doc);
+ _preview.setSize(64);
+ _preview.set_halign(Gtk::ALIGN_CENTER);
+ _preview.set_valign(Gtk::ALIGN_CENTER);
+
+ _label.set_width_chars(10);
+ _label.set_ellipsize(Pango::ELLIPSIZE_END);
+ _label.set_halign(Gtk::Align::ALIGN_CENTER);
+ _label.set_text(label);
+
+ set_valign(Gtk::Align::ALIGN_START);
+ set_halign(Gtk::Align::ALIGN_START);
+ add(_grid);
+ show();
+ this->set_can_focus(false);
+ this->set_tooltip_text(label);
+
+ // This initially packs the widgets with a hidden preview.
+ refresh(!is_hide);
+}
+
+void BatchItem::refresh(bool hide)
+{
+ if (_page) {
+ auto b = _page->getDesktopRect();
+ _preview.setDbox(b.left(), b.right(), b.top(), b.bottom());
+ }
+
+ // When hiding the preview, we show the items as a checklist
+ // So all items must be packed differently on refresh.
+ if (hide != is_hide) {
+ is_hide = hide;
+ _grid.remove(_selector);
+ _grid.remove(_label);
+ _grid.remove(_preview);
+
+ if (hide) {
+ _selector.set_valign(Gtk::Align::ALIGN_BASELINE);
+ _label.set_xalign(0.0);
+ _grid.attach(_selector, 0, 1, 1, 1);
+ _grid.attach(_label, 1, 1, 1, 1);
+ } else {
+ _selector.set_valign(Gtk::Align::ALIGN_END);
+ _label.set_xalign(0.5);
+ _grid.attach(_selector, 0, 1, 1, 1);
+ _grid.attach(_label, 0, 2, 2, 1);
+ _grid.attach(_preview, 0, 0, 2, 2);
+ }
+ show_all_children();
+ }
+
+ if (!hide) {
+ _preview.queueRefresh();
+ }
+}
+
+
+void BatchExport::initialise(const Glib::RefPtr<Gtk::Builder> &builder)
+{
+ builder->get_widget("b_s_selection", selection_buttons[SELECTION_SELECTION]);
+ selection_names[SELECTION_SELECTION] = "selection";
+ builder->get_widget("b_s_layers", selection_buttons[SELECTION_LAYER]);
+ selection_names[SELECTION_LAYER] = "layer";
+ builder->get_widget("b_s_pages", selection_buttons[SELECTION_PAGE]);
+ selection_names[SELECTION_PAGE] = "page";
+
+ builder->get_widget("b_preview_box", preview_container);
+ builder->get_widget("b_show_preview", show_preview);
+ builder->get_widget("b_num_elements", num_elements);
+ builder->get_widget("b_hide_all", hide_all);
+ builder->get_widget("b_filename", filename_entry);
+ builder->get_widget("b_export", export_btn);
+ builder->get_widget("b_progress_bar", _prog);
+ builder->get_widget_derived("b_export_list", export_list);
+
+ Inkscape::UI::Widget::ScrollTransfer<Gtk::ScrolledWindow> *temp = nullptr;
+ builder->get_widget_derived("b_pbox_scroll", temp);
+ builder->get_widget_derived("b_scroll", temp);
+}
+
+void BatchExport::selectionModified(Inkscape::Selection *selection, guint flags)
+{
+ if (!_desktop || _desktop->getSelection() != selection) {
+ return;
+ }
+ if (!(flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
+ return;
+ }
+ refreshItems();
+}
+
+void BatchExport::selectionChanged(Inkscape::Selection *selection)
+{
+ if (!_desktop || _desktop->getSelection() != selection) {
+ return;
+ }
+ selection_buttons[SELECTION_SELECTION]->set_sensitive(!selection->isEmpty());
+ if (selection->isEmpty()) {
+ if (current_key == SELECTION_SELECTION) {
+ selection_buttons[SELECTION_LAYER]->set_active(true); // This causes refresh area
+ // return otherwise refreshArea will be called again
+ // even though we are at default key, selection is the one which was original key.
+ prefs->setString("/dialogs/export/batchexportarea/value", selection_names[SELECTION_SELECTION]);
+ return;
+ }
+ } else {
+ Glib::ustring pref_key_name = prefs->getString("/dialogs/export/batchexportarea/value");
+ if (selection_names[SELECTION_SELECTION] == pref_key_name && current_key != SELECTION_SELECTION) {
+ selection_buttons[SELECTION_SELECTION]->set_active();
+ return;
+ }
+ }
+ refreshItems();
+ loadExportHints();
+}
+
+void BatchExport::pagesChanged()
+{
+ if (!_desktop || !_document) return;
+
+ bool has_pages = _document->getPageManager().hasPages();
+ selection_buttons[SELECTION_PAGE]->set_sensitive(has_pages);
+
+ if (current_key == SELECTION_PAGE && !has_pages) {
+ current_key = SELECTION_LAYER;
+ selection_buttons[SELECTION_LAYER]->set_active();
+ }
+
+ refreshItems();
+ loadExportHints();
+}
+
+// Setup Single Export.Called by export on realize
+void BatchExport::setup()
+{
+ if (setupDone) {
+ return;
+ }
+ setupDone = true;
+ prefs = Inkscape::Preferences::get();
+
+ export_list->setup();
+
+ // set them before connecting to signals
+ setDefaultSelectionMode();
+ loadExportHints();
+
+ refreshItems();
+
+ // Connect Signals
+ for (auto [key, button] : selection_buttons) {
+ button->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &BatchExport::onAreaTypeToggle), key));
+ }
+ show_preview->signal_toggled().connect(sigc::mem_fun(*this, &BatchExport::refreshPreview));
+ filenameConn = filename_entry->signal_changed().connect(sigc::mem_fun(*this, &BatchExport::onFilenameModified));
+ exportConn = export_btn->signal_clicked().connect(sigc::mem_fun(*this, &BatchExport::onExport));
+ browseConn = filename_entry->signal_icon_release().connect(sigc::mem_fun(*this, &BatchExport::onBrowse));
+ hide_all->signal_toggled().connect(sigc::mem_fun(*this, &BatchExport::refreshPreview));
+}
+
+void BatchExport::refreshItems()
+{
+ if (!_desktop || !_document) return;
+
+ // Create New List of Items
+ std::set<SPItem *> itemsList;
+ std::set<SPPage *> pageList;
+
+ char *num_str = nullptr;
+ switch (current_key) {
+ case SELECTION_SELECTION: {
+ auto items = _desktop->getSelection()->items();
+ for (auto i = items.begin(); i != items.end(); ++i) {
+ if (SPItem *item = *i) {
+ // Ignore empty items (empty groups, other bad items)
+ if (item->visualBounds()) {
+ itemsList.insert(item);
+ }
+ }
+ }
+ num_str = g_strdup_printf(ngettext("%d Item", "%d Items", itemsList.size()), (int)itemsList.size());
+ break;
+ }
+ case SELECTION_LAYER: {
+ for (auto layer : _desktop->layerManager().getAllLayers()) {
+ // Ignore empty layers, they have no size.
+ if (layer->geometricBounds()) {
+ itemsList.insert(layer);
+ }
+ }
+ num_str = g_strdup_printf(ngettext("%d Layer", "%d Layers", itemsList.size()), (int)itemsList.size());
+ break;
+ }
+ case SELECTION_PAGE: {
+ for (auto page : _desktop->getDocument()->getPageManager().getPages()) {
+ pageList.insert(page);
+ }
+ num_str = g_strdup_printf(ngettext("%d Page", "%d Pages", pageList.size()), (int)pageList.size());
+ break;
+ }
+ default:
+ break;
+ }
+ if (num_str) {
+ num_elements->set_text(num_str);
+ g_free(num_str);
+ }
+
+ // Create a list of items which are already present but will be removed as they are not present anymore
+ std::vector<std::string> toRemove;
+ for (auto &[key, val] : current_items) {
+ if (SPItem *item = val->getItem()) {
+ // if item is not present in itemList add it to remove list so that we can remove it
+ auto itemItr = itemsList.find(item);
+ if (itemItr == itemsList.end() || !(*itemItr)->getId() || (*itemItr)->getId() != key) {
+ toRemove.push_back(key);
+ }
+ }
+ if (SPPage *page = val->getPage()) {
+ auto pageItr = pageList.find(page);
+ if (pageItr == pageList.end() || !(*pageItr)->getId() || (*pageItr)->getId() != key) {
+ toRemove.push_back(key);
+ }
+ }
+ }
+
+ // now remove all the items
+ for (auto key : toRemove) {
+ if (current_items[key]) {
+ // Preview Boxes are GTK managed so simply removing from container will handle delete
+ preview_container->remove(*current_items[key]);
+ current_items.erase(key);
+ }
+ }
+
+ // now add which were are new
+ for (auto &item : itemsList) {
+ if (auto id = item->getId()) {
+ // If an Item with same Id is already present, Skip
+ if (current_items[id] && current_items[id]->getItem() == item) {
+ continue;
+ }
+ // Add new item to the end of list
+ current_items[id] = Gtk::manage(new BatchItem(item));
+ preview_container->insert(*current_items[id], -1);
+ }
+ }
+ for (auto &page : pageList) {
+ if (auto id = page->getId()) {
+ if (current_items[id] && current_items[id]->getPage() == page) {
+ continue;
+ }
+ current_items[id] = Gtk::manage(new BatchItem(page));
+ preview_container->insert(*current_items[id], -1);
+ }
+ }
+
+ refreshPreview();
+}
+
+void BatchExport::refreshPreview()
+{
+ if (!_desktop) return;
+
+ // For Batch Export we are now hiding all object except current object
+ bool hide = hide_all->get_active();
+ bool preview = show_preview->get_active();
+ preview_container->set_orientation(preview ? Gtk::ORIENTATION_HORIZONTAL : Gtk::ORIENTATION_VERTICAL);
+
+ for (auto &[key, val] : current_items) {
+ if (preview) {
+ std::vector<SPItem *> selected;
+ if (hide) {
+ if (auto item = val->getItem()) {
+ selected = std::vector<SPItem *>({item});
+ } else if (val->getPage()) {
+ auto sels = _desktop->getSelection()->items();
+ selected = std::vector<SPItem *>(sels.begin(), sels.end());
+ }
+ }
+ val->refreshHide(selected);
+ }
+ val->refresh(!preview);
+ }
+}
+
+void BatchExport::loadExportHints()
+{
+ SPDocument *doc = _desktop->getDocument();
+ auto old_filename = filename_entry->get_text();
+ if (old_filename.empty()) {
+ Glib::ustring filename = doc->getRoot()->getExportFilename();
+ if (filename.empty()) {
+ Glib::ustring filename_entry_text = filename_entry->get_text();
+ Glib::ustring extension = ".png";
+ filename = Export::defaultFilename(doc, original_name, extension);
+ }
+ filename_entry->set_text(filename);
+ filename_entry->set_position(filename.length());
+ doc_export_name = filename;
+ }
+}
+
+// Signals CallBack
+
+void BatchExport::onAreaTypeToggle(selection_mode key)
+{
+ // Prevent executing function twice
+ if (!selection_buttons[key]->get_active()) {
+ return;
+ }
+ // If you have reached here means the current key is active one ( not sure if multiple transitions happen but
+ // last call will change values)
+ current_key = key;
+ prefs->setString("/dialogs/export/batchexportarea/value", selection_names[current_key]);
+
+ refreshItems();
+ loadExportHints();
+}
+
+void BatchExport::onFilenameModified()
+{
+ ;
+}
+
+void BatchExport::onExport()
+{
+ interrupted = false;
+ if (!_desktop)
+ return;
+ export_btn->set_sensitive(false);
+
+ // If there are no selected button, simply flash message in status bar
+ int num = current_items.size();
+ if (current_items.size() == 0) {
+ _desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("No items selected."));
+ export_btn->set_sensitive(true);
+ return;
+ }
+
+ // Find and remove any extension from filename so that we can add suffix to it.
+ Glib::ustring filename = filename_entry->get_text();
+ export_list->removeExtension(filename);
+
+ // create vector of exports
+ int num_rows = export_list->get_rows();
+ std::vector<Glib::ustring> suffixs;
+ std::vector<Inkscape::Extension::Output *> extensions;
+ std::vector<double> dpis;
+ for (int i = 0; i < num_rows; i++) {
+ suffixs.push_back(export_list->get_suffix(i));
+ extensions.push_back(export_list->getExtension(i));
+ dpis.push_back(export_list->get_dpi(i));
+ }
+
+ // We are exporting standalone items only for now
+ // std::vector<SPItem *> selected(_desktop->getSelection()->items().begin(),
+ // _desktop->getSelection()->items().end());
+ bool hide = hide_all->get_active();
+
+ auto sels = _desktop->getSelection()->items();
+ std::vector<SPItem *> selected_items(sels.begin(), sels.end());
+
+ // Start Exporting Each Item
+ for (int i = 0; i < num_rows; i++) {
+ auto suffix = suffixs[i];
+ auto omod = extensions[i];
+ float dpi = dpis[i];
+
+ if (!omod || omod->deactivated() || !omod->prefs()) {
+ continue;
+ }
+
+ int count = 0;
+ for (auto i = current_items.begin(); i != current_items.end() && !interrupted; ++i) {
+ count++;
+
+ BatchItem *batchItem = i->second;
+ if (!batchItem->isActive()) {
+ continue;
+ }
+
+ SPItem *item = batchItem->getItem();
+ SPPage *page = batchItem->getPage();
+
+ std::vector<SPItem *> show_only;
+ Geom::Rect area;
+ if (item) {
+ if (auto bounds = item->documentVisualBounds()) {
+ area = *bounds;
+ } else {
+ continue;
+ }
+ show_only.emplace_back(item);
+ } else if (page) {
+ area = page->getDesktopRect();
+ show_only = selected_items; // Maybe stuff here
+ } else {
+ continue;
+ }
+
+ Glib::ustring id = batchItem->getLabel();
+ if (id.empty()) {
+ continue;
+ }
+
+ Glib::ustring item_filename = filename + "_" + id;
+ if (!suffix.empty()) {
+ if (omod->is_raster()) {
+ // Put the dpi in at the user's requested location.
+ suffix = std::regex_replace(suffix.c_str(), std::regex("\\{dpi\\}"), std::to_string((int)dpi));
+ }
+ item_filename = item_filename + "_" + suffix;
+ }
+
+ bool found = Export::unConflictFilename(_document, item_filename, omod->get_extension());
+ if (!found) {
+ continue;
+ }
+
+ delete prog_dlg;
+ prog_dlg = create_progress_dialog(Glib::ustring::compose(_("Exporting %1 files"), num));
+ prog_dlg->set_export_panel(this);
+ setExporting(true, Glib::ustring::compose(_("Exporting %1 files"), num));
+ prog_dlg->set_current(count);
+ prog_dlg->set_total(num);
+
+ onProgressCallback(0.0, prog_dlg);
+
+ if (omod->is_raster()) {
+ unsigned long int width = (int)(area.width() * dpi / DPI_BASE + 0.5);
+ unsigned long int height = (int)(area.height() * dpi / DPI_BASE + 0.5);
+
+ Export::exportRaster(
+ area, width, height, dpi, item_filename, true, onProgressCallback,
+ prog_dlg, omod, hide ? &show_only : nullptr);
+ } else {
+ setExporting(true, Glib::ustring::compose(_("Exporting %1"), filename));
+ auto copy_doc = _document->copy();
+ Export::exportVector(omod, copy_doc.get(), item_filename, true, &show_only, page);
+ }
+
+ if (prog_dlg) {
+ delete prog_dlg;
+ prog_dlg = nullptr;
+ }
+ }
+ }
+ // Do this right at the end to finish up
+ setExporting(false);
+}
+
+void BatchExport::onBrowse(Gtk::EntryIconPosition pos, const GdkEventButton *ev)
+{
+ if (!_app || !_app->get_active_window()) {
+ return;
+ }
+ Gtk::Window *window = _app->get_active_window();
+ browseConn.block();
+ Glib::ustring filename = Glib::filename_from_utf8(filename_entry->get_text());
+
+ if (filename.empty()) {
+ filename = Export::defaultFilename(_document, filename, ".png");
+ }
+
+ Inkscape::UI::Dialog::FileSaveDialog *dialog = Inkscape::UI::Dialog::FileSaveDialog::create(
+ *window, filename, Inkscape::UI::Dialog::RASTER_TYPES, _("Select a filename for exporting"), "", "",
+ Inkscape::Extension::FILE_SAVE_METHOD_EXPORT);
+
+ if (dialog->show()) {
+ filename = dialog->getFilename();
+ // Remove extension and don't add a new one, for obvious reasons.
+ export_list->removeExtension(filename);
+
+ filename_entry->set_text(filename);
+ filename_entry->set_position(filename.length());
+
+ // deleting dialog before exporting is important
+ // proper delete function should be made for dialog IMO
+ delete dialog;
+ onExport();
+ } else {
+ delete dialog;
+ }
+ browseConn.unblock();
+}
+
+void BatchExport::setDefaultSelectionMode()
+{
+ current_key = (selection_mode)0; // default key
+ bool found = false;
+ Glib::ustring pref_key_name = prefs->getString("/dialogs/export/batchexportarea/value");
+ for (auto [key, name] : selection_names) {
+ if (pref_key_name == name) {
+ current_key = key;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ pref_key_name = selection_names[current_key];
+ }
+ if (_desktop) {
+ if (auto _sel = _desktop->getSelection()) {
+ selection_buttons[SELECTION_SELECTION]->set_sensitive(!_sel->isEmpty());
+ }
+ selection_buttons[SELECTION_PAGE]->set_sensitive(_document->getPageManager().hasPages());
+ }
+ if (!selection_buttons[current_key]->get_sensitive()) {
+ current_key = SELECTION_LAYER;
+ }
+ selection_buttons[current_key]->set_active(true);
+
+ // we need to set pref key because signals above will set set pref == current key but we sometimes change
+ // current key like selection key
+ prefs->setString("/dialogs/export/batchexportarea/value", pref_key_name);
+}
+
+void BatchExport::setExporting(bool exporting, Glib::ustring const &text)
+{
+ if (exporting) {
+ _prog->set_text(text);
+ _prog->set_fraction(0.0);
+ _prog->set_sensitive(true);
+ export_btn->set_sensitive(false);
+ } else {
+ _prog->set_text("");
+ _prog->set_fraction(0.0);
+ _prog->set_sensitive(false);
+ export_btn->set_sensitive(true);
+ }
+}
+
+ExportProgressDialog *BatchExport::create_progress_dialog(Glib::ustring progress_text)
+{
+ // dont forget to delete it later
+ auto dlg = new ExportProgressDialog(_("Export in progress"), true);
+ dlg->set_transient_for(*(INKSCAPE.active_desktop()->getToplevel()));
+
+ Gtk::ProgressBar *prg = Gtk::manage(new Gtk::ProgressBar());
+ prg->set_text(progress_text);
+ dlg->set_progress(prg);
+ auto CA = dlg->get_content_area();
+ CA->pack_start(*prg, FALSE, FALSE, 4);
+
+ Gtk::Button *btn = dlg->add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
+
+ btn->signal_clicked().connect(sigc::mem_fun(*this, &BatchExport::onProgressCancel));
+ dlg->signal_delete_event().connect(sigc::mem_fun(*this, &BatchExport::onProgressDelete));
+
+ dlg->show_all();
+ return dlg;
+}
+
+/// Called when dialog is deleted
+bool BatchExport::onProgressDelete(GdkEventAny * /*event*/)
+{
+ interrupted = true;
+ prog_dlg->set_stopped();
+ return TRUE;
+}
+
+/// Called when progress is cancelled
+void BatchExport::onProgressCancel()
+{
+ interrupted = true;
+ prog_dlg->set_stopped();
+}
+
+/// Called for every progress iteration
+unsigned int BatchExport::onProgressCallback(float value, void *dlg)
+{
+ auto dlg2 = reinterpret_cast<ExportProgressDialog *>(dlg);
+
+ auto self = dynamic_cast<BatchExport *>(dlg2->get_export_panel());
+
+ if (!self || self->interrupted)
+ return FALSE;
+
+ auto current = dlg2->get_current();
+ auto total = dlg2->get_total();
+ if (total > 0) {
+ double completed = current;
+ completed /= static_cast<double>(total);
+
+ value = completed + (value / static_cast<double>(total));
+ }
+
+ auto prg = dlg2->get_progress();
+ prg->set_fraction(value);
+
+ if (self) {
+ self->_prog->set_fraction(value);
+ }
+
+ int evtcount = 0;
+ while ((evtcount < 16) && gdk_events_pending()) {
+ Gtk::Main::iteration(false);
+ evtcount += 1;
+ }
+
+ Gtk::Main::iteration(false);
+ return TRUE;
+}
+
+void BatchExport::setDesktop(SPDesktop *desktop)
+{
+ if (desktop != _desktop) {
+ _pages_changed_connection.disconnect();
+ _desktop = desktop;
+ }
+}
+
+void BatchExport::setDocument(SPDocument *document)
+{
+ if (!_desktop) {
+ document = nullptr;
+ }
+
+ _document = document;
+ _pages_changed_connection.disconnect();
+ if (document) {
+ // when the page selected is changes, update the export area
+ _pages_changed_connection = document->getPageManager().connectPagesChanged([=]() { pagesChanged(); });
+ }
+ for (auto &[key, val] : current_items) {
+ val->setDocument(document);
+ }
+}
+
+} // namespace Dialog
+} // namespace UI
+} // namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :