Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
rvng-import-dialog.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <glibmm/i18n.h>
5
6#include "inkscape.h"
7#include "extension/input.h"
8#include "object/sp-root.h"
9#include "ui/controller.h"
10#include "ui/dialog-events.h"
11#include "ui/dialog-run.h"
12#include "ui/pack.h"
13#include "util/units.h"
14
15using namespace librevenge;
16
18
19RvngImportDialog::RvngImportDialog(std::vector<RVNGString> const &pages)
20 : _pages{pages}
21{
22 int num_pages = _pages.size();
23
24 // Dialog settings
25 set_title(_("Page Selector"));
26 set_modal();
27 sp_transientize(*this);
28 set_resizable();
29 property_destroy_with_parent().set_value(false);
30
31 // Preview area
32 vbox1 = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 4);
33 vbox1->set_margin(4);
34 UI::pack_start(*get_content_area(), *vbox1);
35
36 // CONTROLS
37 _page_selector_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 4);
38
39 // "Select page:" label
40 _labelSelect = Gtk::make_managed<Gtk::Label>(_("Select page:"));
41 _labelTotalPages = Gtk::make_managed<Gtk::Label>();
42 _labelSelect->set_wrap(false);
43 _labelSelect->set_use_markup(false);
44 _labelSelect->set_selectable(false);
46
47 // Adjustment + spinner
48 auto pageNumberSpin_adj = Gtk::Adjustment::create(1, 1, _pages.size(), 1, 10, 0);
49 _pageNumberSpin = Gtk::make_managed<Gtk::SpinButton>(pageNumberSpin_adj, 1, 0);
50 _pageNumberSpin->set_focusable();
51 _pageNumberSpin->set_numeric(true);
52 _pageNumberSpin->set_wrap(false);
54
55 _labelTotalPages->set_wrap(false);
56 _labelTotalPages->set_use_markup(false);
57 _labelTotalPages->set_selectable(false);
58 _labelTotalPages->set_label(Glib::ustring::compose(_("out of %1"), num_pages));
60
62 _preview.setResize(400, 400);
63
65
66 // Buttons
67 cancelbutton = Gtk::make_managed<Gtk::Button>(_("_Cancel"), true);
68 okbutton = Gtk::make_managed<Gtk::Button>(_("_OK"), true);
69 add_action_widget(*cancelbutton, Gtk::ResponseType::CANCEL);
70 add_action_widget(*okbutton, Gtk::ResponseType::OK);
71
72 // Connect signals
73 _pageNumberSpin->signal_value_changed().connect(sigc::mem_fun(*this, &RvngImportDialog::_onPageNumberChanged));
74
75 auto const click = Gtk::GestureClick::create();
76 click->set_button(0); // any
77 click->set_propagation_phase(Gtk::PropagationPhase::TARGET);
78 click->signal_pressed().connect(sigc::mem_fun(*this, &RvngImportDialog::_onSpinButtonClickPressed));
79 click->signal_released().connect(sigc::mem_fun(*this, &RvngImportDialog::_onSpinButtonClickReleased));
80 _pageNumberSpin->add_controller(click);
81
83}
84
86{
87 auto ret = UI::dialog_run(*this);
88 return ret == Gtk::ResponseType::OK || ret == Gtk::ResponseType::ACCEPT;
89}
90
92{
93 auto page = _pageNumberSpin->get_value_as_int();
94 _current_page = std::clamp<int>(page, 1, _pages.size());
96}
97
99{
100 _spinning = false;
102}
103
105{
106 _spinning = true;
107}
108
113{
114 if (_spinning) {
115 return;
116 }
117
118 _preview.setDocument(nullptr);
119
121 if (!_doc) {
122 g_warning("CDR import: Could not create preview for page %d", _current_page);
123 auto no_preview_template = R"A(
124 <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>
125 <path d='M 82,10 18,74 m 0,-64 64,64' style='fill:none;stroke:#ff0000;stroke-width:2px;'/>
126 <rect x='18' y='10' width='64' height='64' style='fill:none;stroke:#000000;stroke-width:1.5px;'/>
127 <text x='50' y='92' style='font-size:10px;text-anchor:middle;font-family:sans-serif;'>%1</text>
128 </svg>
129 )A";
130 auto no_preview = Glib::ustring::compose(no_preview_template, _("No preview"));
131 _doc = SPDocument::createNewDocFromMem(no_preview.raw(), false);
132 }
133
134 if (!_doc) {
135 std::cerr << "RvngImportDialog::_setPreviewPage: No document!" << std::endl;
136 return;
137 }
138
140}
141
142std::unique_ptr<SPDocument> rvng_open(
143 char const *uri,
144 bool (*is_supported)(RVNGInputStream *),
145 bool (*parse)(RVNGInputStream *, RVNGDrawingInterface *))
146{
147#ifdef _WIN32
148 // RVNGFileStream uses fopen() internally which unfortunately only uses ANSI encoding on Windows
149 // therefore attempt to convert uri to the system codepage
150 // even if this is not possible the alternate short (8.3) file name will be used if available
151 auto converted_uri = g_win32_locale_filename_from_utf8(uri);
152 auto input = RVNGFileStream(converted_uri);
153 g_free(converted_uri);
154#else
155 auto input = RVNGFileStream(uri);
156#endif
157
158 if (!is_supported(&input)) {
159 return nullptr;
160 }
161
162 RVNGStringVector output;
163 RVNGSVGDrawingGenerator generator(output, "svg");
164
165 if (!parse(&input, &generator)) {
166 return nullptr;
167 }
168
169 if (output.empty()) {
170 return nullptr;
171 }
172
173 std::vector<RVNGString> tmpSVGOutput;
174 for (unsigned i=0; i<output.size(); ++i) {
175 RVNGString tmpString("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
176 tmpString.append(output[i]);
177 tmpSVGOutput.push_back(tmpString);
178 }
179
180 unsigned page_num = 1;
181
182 // If only one page is present, import that one without bothering user
183 if (tmpSVGOutput.size() > 1 && INKSCAPE.use_gui()) {
184 auto dlg = RvngImportDialog(tmpSVGOutput);
185 if (!dlg.showDialog()) {
186 throw Input::open_cancelled();
187 }
188
189 // Get needed page
190 page_num = std::clamp<int>(dlg.getSelectedPage(), 1, tmpSVGOutput.size());
191 }
192
193 auto doc = SPDocument::createNewDocFromMem(as_span(tmpSVGOutput[page_num - 1]), true);
194
195 if (doc && !doc->getRoot()->viewBox_set) {
196 // Scales the document to account for 72dpi scaling in librevenge(<=0.0.4)
197 doc->setWidth(Inkscape::Util::Quantity(doc->getWidth().quantity, "pt"), false);
198 doc->setHeight(Inkscape::Util::Quantity(doc->getHeight().quantity, "pt"), false);
199 doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value("pt"), doc->getHeight().value("pt")));
200 }
201
202 return doc;
203}
204
205} // namespace Inkscape::Extension::Internal
uint64_t page
Definition canvas.cpp:171
static CRect from_xywh(Coord x, Coord y, Coord w, Coord h)
Create rectangle from origin and dimensions.
RvngImportDialog(std::vector< librevenge::RVNGString > const &pages)
std::vector< librevenge::RVNGString > const & _pages
void _onSpinButtonClickPressed(int n_press, double x, double y)
void _onSpinButtonClickReleased(int n_press, double x, double y)
void _setPreviewPage()
Renders the given page's thumbnail.
void setDocument(SPDocument *document)
void setResize(int width, int height)
static std::unique_ptr< SPDocument > createNewDocFromMem(std::span< char const > buffer, bool keepalive, std::string const &filename="")
Definition document.cpp:708
Utilities to more easily use Gtk::EventController & subclasses like Gesture.
void sp_transientize(Gtk::Window &window)
Make the argument dialog transient to the currently active document window.
Event handler for dialog windows.
std::span< char const > as_span(librevenge::RVNGString const &str)
std::unique_ptr< SPDocument > rvng_open(char const *uri, bool(*is_supported)(RVNGInputStream *), bool(*parse)(RVNGInputStream *, RVNGDrawingInterface *))
void pack_end(Gtk::Box &box, Gtk::Widget &child, bool const expand, bool const fill, unsigned const padding)
Adds child to box, packed with reference to the end of box.
Definition pack.cpp:153
void pack_start(Gtk::Box &box, Gtk::Widget &child, bool const expand, bool const fill, unsigned const padding)
Adds child to box, packed with reference to the start of box.
Definition pack.cpp:141
int dialog_run(Gtk::Dialog &dialog)
This is a GTK4 porting aid meant to replace the removal of the Gtk::Dialog synchronous API.
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
Common import dialog for .cdr and .vss files.
SPRoot: SVG <svg> implementation.