summaryrefslogtreecommitdiffstats
path: root/src/extension/output.cpp
blob: 750d80bd4fd3b7b1c9edbda02620cd78da218d9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Authors:
 *   Ted Gould <ted@gould.cx>
 *
 * Copyright (C) 2006 Johan Engelen <johan@shouraizou.nl>
 * Copyright (C) 2002-2004 Authors
 *
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#include "output.h"

#include "document.h"

#include "io/sys.h"
#include "implementation/implementation.h"

#include "prefdialog/prefdialog.h"

#include "xml/repr.h"


/* Inkscape::Extension::Output */

namespace Inkscape {
namespace Extension {

/**
    \return   None
    \brief    Builds a SPModuleOutput object from a XML description
    \param    module  The module to be initialized
    \param    repr    The XML description in a Inkscape::XML::Node tree

    Okay, so you want to build a SPModuleOutput object.

    This function first takes and does the build of the parent class,
    which is SPModule.  Then, it looks for the <output> section of the
    XML description.  Under there should be several fields which
    describe the output module to excruciating detail.  Those are parsed,
    copied, and put into the structure that is passed in as module.
    Overall, there are many levels of indentation, just to handle the
    levels of indentation in the XML file.
*/
Output::Output (Inkscape::XML::Node *in_repr, Implementation::Implementation *in_imp, std::string *base_directory)
    : Extension(in_repr, in_imp, base_directory)
{
    mimetype = nullptr;
    extension = nullptr;
    filetypename = nullptr;
    filetypetooltip = nullptr;
    dataloss = true;
    savecopyonly = false;
    exported = false;
    raster = false;

    if (repr != nullptr) {
        Inkscape::XML::Node * child_repr;

        child_repr = repr->firstChild();

        while (child_repr != nullptr) {
            if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "output")) {

                if (child_repr->attribute("raster") && !strcmp(child_repr->attribute("raster"), "true")) {
                     raster = true;
                }
                if (child_repr->attribute("is_exported") && !strcmp(child_repr->attribute("is_exported"), "true")) {
                     exported = true;
                }

                child_repr = child_repr->firstChild();
                while (child_repr != nullptr) {
                    char const * chname = child_repr->name();
					if (!strncmp(chname, INKSCAPE_EXTENSION_NS_NC, strlen(INKSCAPE_EXTENSION_NS_NC))) {
						chname += strlen(INKSCAPE_EXTENSION_NS);
					}
                    if (chname[0] == '_') /* Allow _ for translation of tags */
                        chname++;
                    if (!strcmp(chname, "extension")) {
                        g_free (extension);
                        extension = g_strdup(child_repr->firstChild()->content());
                    }
                    if (!strcmp(chname, "mimetype")) {
                        g_free (mimetype);
                        mimetype = g_strdup(child_repr->firstChild()->content());
                    }
                    if (!strcmp(chname, "filetypename")) {
                        g_free (filetypename);
                        filetypename = g_strdup(child_repr->firstChild()->content());
                    }
                    if (!strcmp(chname, "filetypetooltip")) {
                        g_free (filetypetooltip);
                        filetypetooltip = g_strdup(child_repr->firstChild()->content());
                    }
                    if (!strcmp(chname, "dataloss")) {
                        dataloss = strcmp(child_repr->firstChild()->content(), "false");
                    }
                    if (!strcmp(chname, "savecopyonly")) {
                        savecopyonly = !strcmp(child_repr->firstChild()->content(), "true");
                    }

                    child_repr = child_repr->next();
                }

                break;
            }

            child_repr = child_repr->next();
        }

    }
}

/**
    \brief  Destroy an output extension
*/
Output::~Output ()
{
    g_free(mimetype);
    g_free(extension);
    g_free(filetypename);
    g_free(filetypetooltip);
    return;
}

/**
    \return  Whether this extension checks out
	\brief   Validate this extension

	This function checks to make sure that the output extension has
	a filename extension and a MIME type.  Then it calls the parent
	class' check function which also checks out the implementation.
*/
bool
Output::check ()
{
	if (extension == nullptr)
		return FALSE;
	if (mimetype == nullptr)
		return FALSE;

	return Extension::check();
}

/**
    \return  IETF mime-type for the extension
	\brief   Get the mime-type that describes this extension
*/
gchar *
Output::get_mimetype()
{
    return mimetype;
}

/**
    \return  Filename extension for the extension
	\brief   Get the filename extension for this extension
*/
gchar *
Output::get_extension()
{
    return extension;
}

/**
    \return  The name of the filetype supported
	\brief   Get the name of the filetype supported
*/
const char *
Output::get_filetypename(bool translated)
{
    const char *name;

    if (filetypename)
        name = filetypename;
    else
        name = get_name();

    if (name && translated && filetypename) {
        return get_translation(name);
    } else {
        return name;
    }
}

/**
    \return  Tooltip giving more information on the filetype
	\brief   Get the tooltip for more information on the filetype
*/
const char *
Output::get_filetypetooltip(bool translated)
{
    if (filetypetooltip && translated) {
        return get_translation(filetypetooltip);
    } else {
        return filetypetooltip;
    }
}

/**
    \return  A dialog to get settings for this extension
	\brief   Create a dialog for preference for this extension

	Calls the implementation to get the preferences.
*/
bool
Output::prefs ()
{
    if (!loaded())
        set_state(Extension::STATE_LOADED);
    if (!loaded()) return false;

    Gtk::Widget * controls;
    controls = imp->prefs_output(this);
    if (controls == nullptr) {
        // std::cout << "No preferences for Output" << std::endl;
        return true;
    }

    Glib::ustring title = this->get_name();
    PrefDialog *dialog = new PrefDialog(title, controls);
    int response = dialog->run();
    dialog->hide();

    delete dialog;

    return (response == Gtk::RESPONSE_OK);
}

/**
    \return  None
	\brief   Save a document as a file
	\param   doc  Document to save
	\param   filename  File to save the document as

	This function does a little of the dirty work involved in saving
	a document so that the implementation only has to worry about getting
	bits on the disk.

	The big thing that it does is remove and read the fields that are
	only used at runtime and shouldn't be saved.  One that may surprise
	people is the output extension.  This is not saved so that the IDs
	could be changed, and old files will still work properly.
*/
void
Output::save(SPDocument *doc, gchar const *filename, bool detachbase)
{
    if (!loaded())
        set_state(Extension::STATE_LOADED);

    if (loaded()) {
        imp->setDetachBase(detachbase);
        auto new_doc = doc->copy();
        imp->save(this, new_doc.get(), filename);
        // This shouldn't be needed, but the unique_ptr is not destroying this SPDocument.
        delete new_doc.release();
    }
}

/**
    \return  None
    \brief   Save a rendered png as a raster output
    \param   png_filename source png file.
    \param   filename  File to save the raster as

*/
void
Output::export_raster(const SPDocument *doc, std::string png_filename, gchar const *filename, bool detachbase)
{
    if (!loaded())
        set_state(Extension::STATE_LOADED);

    if (loaded()) {
        imp->setDetachBase(detachbase);
        imp->export_raster(this, doc, png_filename, filename);
    }
}

/**
 * Adds a valid extension to the filename if it's missing.
 */
void
Output::add_extension(Glib::ustring &filename)
{
    auto current_ext = Inkscape::IO::get_file_extension(filename);
    if (extension && current_ext != extension) {
        filename = filename + extension;
    }
}

} }  /* namespace Inkscape, Extension */

/*
  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 :