summaryrefslogtreecommitdiffstats
path: root/scribus/scplugin.h
blob: bc9b942536eb659feddfed76dedfd13ab53d3444 (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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
/*
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/
#ifndef _SCPLUGIN_H
#define _SCPLUGIN_H

#include <QObject>
#include <QWidget>
#include <QString>
#include <QPixmap>
#include <QDateTime>
#include <QIcon>
#include "scribusapi.h"

class ScribusDoc;
class ScribusMainWindow;
class DeferredTask;
class PrefsPanel;

/**
 * \brief Abstract super class for all Scribus plug-ins
 *
 * ScPlugin is a class that provides information about a plug-in, and a gateway
 * into any plugin-specific functionality.  It should not generally be
 * inherited directly by actual plugin implementations - use one of the
 * provided base classes instead. See below for info on the creation of
 * new types of plugin.
 *
 * Plugins create and return a instance of a subclass of ScPlugin when asked
 * for it by the plugin manager. The plugin manager is responsible for tracking
 * these instances. The ScPlugin instance is used by the plugin manager for
 * tasks such as hooking the plugin up to the UI where appropriate. It's also
 * used by other code that talks to plugins, usually by dynamic_cast<>ing it to
 * a more specific subclass and working with that. The file loader system will
 * provide an example of this.
 *
 * A given plugin implementation's ScPlugin subclass is *not* the best place
 * to implement the bulk of the plugin's functionality. It must be lightweight
 * and maintain as little state as possible. Most functionality should be
 * implemented in a private subclass that is not exposed in the header of the
 * scplugin subclass defined by the plugin. That helps keep the plugin's
 * implementation separate from its inteface to Scribus.
 *
 * Note that the two subclases ScActionPlugin and ScPersistentPlugin, defined
 * below, create two quite different kinds of plugins. One is for import/export
 * of data and for single function actions (like providing a particular dialog
 * or function) which generally do nothing when not in active use. A second for
 * persistent plugins that are loaded (generally when the app starts) and
 * remain resident, possibly active in the background or hooked into many
 * parts of the user interface.
 *
 * More plugin classes - such as plugins for text import and document import
 * - may be added in future.
 *
 * New types of plugin can be created by subclassing ScPlugin or one of its
 * subclasses and adding the additional interfaces required. The two existing
 * subclasses provide examples of how this can work. Of course, once you have
 * the plugin interface, you still need to actually use the plugins. You'll need
 * to extend pluginmanager.cpp a little to handle any low-level init required by
 * the new plugin type (please keep this minimal!). You'll then need to extend
 * the appropriate classes to make use of the new plugin type where required.
 * The new file loader mechanism will provide a good example of this.
 *
 * In addition to the API described here, a plugin is expected to implement
 * the following "extern C" functions, where 'pluginname' is the base name
 * of the plug-in (where the filename is libpluginname.so on UNIX):
 *
 * int pluginname_getPluginAPIVersion();
 *    Return an integer indicating the plug-in API version implemented.
 *    If the version does not exactly match the running plugin API version,
 *    the plugin will not be initialised.
 *
 * ScPlugin* pluginname_getPlugin();
 *    Create and return an instance of the plug-ins ScPlugin subclass.
 *    Nothing should be done here that's overly slow or uses much memory,
 *    and the plugin should not initialize its self here beyond what is
 *    required to return a ScPlugin instance.
 *
 * void pluginname_freePlugin(ScPlugin* plugin);
 *    Free the scplugin instance returned earlier.
 *
 * TODO: better discovery of what plug-ins can import / export what formats, file exts, names, etc.
 *
 */

class SCRIBUS_API ScPlugin : public QObject
{
	Q_OBJECT

	/**
	 * @brief ScPlugin provides an interface to ask plugins for information
	 * about themselves.
	 *
	 */
	public:

		/*! \brief A struct providing the information returned by getAboutData(), for
		the "About Plug-ins" menu item. */
		struct AboutData
		{
			//! Author name(s) and email address(es)
			QString authors;
			//! One-liner description of the function of the plugin
			QString shortDescription;
			//! Longer description of the plugin
			QString description;
			//! Text plug-in version string
			QString version;
			//! Date of the release of this version
			QDateTime releaseDate;
			//! Copyright string
			QString copyright;
			//! License text / name / URL / whatever. Please don't include
			//! the GPL here, just reference it. Remember that Scribus is
			//! licensed under the GPL, so plug-in authors must take that
			//! into account.
			QString license;
		};

		/**
		 * @brief ctor, returns a new ScPlugin instance
		 *
		 * Only pluginname_getPlugin(...) may call this. Calls by other code
		 * will have undefined results.
		 */
		ScPlugin();

		/** @brief Destroy the ScPlugin instance
		 *
		 * Pure virtual destructor - this is an abstract class.
		 *
		 * Only pluginname_freePlugin(...) may call this. Calls by other code
		 * will have undefined results.
		 */
		virtual ~ScPlugin() = 0;

		/** @brief Plug-in's human-readable, translated name.
		 *
		 * Please don't use this for anything except display to the user.
		 * The results of testing the value of this can not be guaranteed,
		 * as its value may change depending on locale and change at runtime.
		 */
		virtual const QString fullTrName() const = 0;

		/**
		 * \brief Create and return a prefs UI panel for the plugin.
		 *
		 * Override this method if you want to provide a panel for the
		 * preferences dialog.
		 *
		 * The caller takes ownership of the panel. Qt is responsible for
		 * deleting it when it's parent is deleted. `parent' must be the dialog
		 * the widget will be added to or a child of it, otherwise the panel
		 * won't be deleted correctly when the dialog is.
		 *
		 * See prefspanel.h for info on implementing the panel.
		 *
		 * This method must return false (the default) if the plugin does
		 * not provide a prefs panel. If true is returned, caption, panel,
		 * and icon MUST have been assigned.
		 *
		 * \param parent Parent widget, to be passed to panel ctor
		 * \param panel (out) the panel created
		 * \param caption (out) caption for icon in panel list
		 * \param icon (out) icon for use in panel list
		 * \return true if panel was created, false if not.
		 *
		 * By default, returns 0 to indicate no prefs UI.
		*/
		virtual bool newPrefsPanelWidget(QWidget* parent, PrefsPanel*& panel,
										 QString& caption, QPixmap& icon);

		/*! @brief Return descriptive information about the plug-in
		 *
		 * Returns a structure containing descriptive information about the
		 * plug-in. This information is used in places like the Help->About
		 * Plug-ins menu item. The stucture MUST be deleted using
		 * deleteAboutData(AboutData* about) when finished with.
		 *
		 * Every plugin MUST reimplement getAboutData(...) and deleteAboutData(...).
		 *
		 * @sa ScPlugin::deleteAboutData
		 */
		virtual const AboutData* getAboutData() const = 0;
		virtual void deleteAboutData(const AboutData* about) const = 0;

		/*! @brief Text summary of last error encountered
		 *
		 * Return the human readable, translated text of last error to be
		 * encountered by this plugin. DO NOT ATTEMPT TO USE THIS VALUE TO MAKE
		 * DECISIONS IN PROGRAM CODE. The value returned for a given error
		 * may change depending on locale, and may change at runtime.
		 */
		const QString & lastError() const;

		//! \brief Returns if lastError message is not empty
		bool hasLastError() const;

		//! \brief Clear last error message
		void clearLastError();

		/*! @brief Update all user-visible text to reflect current UI language
		 *
		 * Updates the text on all widgets on the plug-in to reflect the new
		 * language. You should generally use this method to set all the widget
		 * text during construction. That ensures that text is not duplicated,
		 * and that when this method is called the text of all persistent
		 * widgets is correctly changed.
		 *
		 * This method only needs to affect text in widgets that currently
		 * exists (displayed or otherwise).
		 */
		virtual void languageChange() = 0;

		//! \brief Returns human readable plugin type from plug-in's pluginType
		const QString pluginTypeName() const;

		//! \brief Allow plugins to add to a main menu
		virtual void addToMainWindowMenu(ScribusMainWindow *) = 0;

		//! \brief hooks that plugins can use to detect if the current document was closed etc..
		virtual void setDoc(ScribusDoc* doc);
		virtual void unsetDoc();
		virtual void changedDoc(ScribusDoc* doc);
	protected:
		//! \brief Human readable, translated version of last error to occur.
		QString m_lastError;
};


/*!
 * @brief A plug-in that performs a single action
 *
 * ScActionPlugin describes a plug-in that is used to perform a single well
 * defined action. Uses include data import/export, displaying a dialog, or
 * doing a single batch task. It is automatically connected to the user
 * interface and has simple methods to trigger the plug-in's supported action.
 *
 * If you need more complex user interface integration, persistent operation,
 * etc, you may be better off with ScPersistentPlugin.
 */
class SCRIBUS_API ScActionPlugin : public ScPlugin
{
	Q_OBJECT

	public:

		/** @brief ctor
		 *
		 * @sa ScPlugin::ScPlugin()
		 */
		ScActionPlugin();

		//! \brief Pure virtual dtor - abstract class
		virtual ~ScActionPlugin() = 0;

		// Information about actions, to be returned by actionInfo()
		struct ActionInfo {
			QString name;  // name of action
			QString text;  // text to display to user
			QString keySequence;
			QString menu;
			QString menuAfterName;
			QString parentMenu;
			QString subMenuName;
			QString toolbar;			// Name of the ToolBar the action is to be inserted, if that toolbar doesn't exits it will be created
			QString toolBarName;		// translateable ToolBar title
			QPixmap icon1;
			QPixmap icon2;
			QList<int> notSuitableFor;		// a list of PageItem type values which the plugin can *not* handle
			QList<int> forAppMode;			// a list of AppMode values for which the plugin will be active, an empty list indicates that the plugin is always active
			int needsNumObjects;			// plugin needs this number of selected Objects. -1 = needs no Object, num > 2 any number of Objects is allowed
			QList<int> firstObjectType;		// when needsNumObjects is 2 this list contains the Object Types of the first object on the selection
			QList<int> secondObjectType;	// when needsNumObjects is 2 this list contains the Object Types of the second object on the selection
											// -1 indicates that any kind of object is possible. Otherwise the selection must contain the 2 Object Types
											// for the Plugin Action to be enabled
			bool enabledOnStartup;
			bool enabledForStoryEditor;
			QString seMenu;
			QString seParentMenu;
			QString seKeySequence;
		};

		// Return an ActionInfo instance to the caller
		const ActionInfo & actionInfo() const;
		/**
		* @brief handle the documents selection.
		*
		* This function is dedicated for handling the documents selection
		* By default this uses the notSuitableFor, forAppMode, needsNumObjects,
		* firstObjectType and secondObjectType variables.
		* If you need more control over the selection reimplement this function.
		*
		* @returns bool true when the Action should be enabled.
		*
		*/
		virtual bool handleSelection(ScribusDoc* doc, int SelectedType = -1);

	public slots:
		/**
		 * @brief Run the plug-in's main action.
		 *
		 * Run the plug-in's default action synchronously, blocking the rest of
		 * the application until this method returns.
		 *
		 * This method should generally call run(..., QIODevice* target) or
		 * run(..., QString target) to do the work. This is done by default,
		 * with the assumption that the target is a file. The argument is
		 * opened as QFile with IO_ReadOnly or IO_WriteOnly mode, depending on
		 * plugin type, and passed to run(..., QIODevice*). Override this if
		 * you need more flexibility.
		 *
		 * The optional target argument is a plugin-defined string indicating
		 * what the plugin should operate on. It will typically be a filename
		 * to import from / export to. Nothing stops a plugin doing funky
		 * things like accepting a WebDAV URI, etc, however.
		 *
		 * Plug-in authors might want to consider implementing this using the
		 * DeferredTask subclass used in runAsync, if the plug-in supports it.
		 *
		 * @param target Optional target to operate on (see
		 *                above)
		 * @returns bool True for success.
		 *
		 */
		virtual bool run(ScribusDoc* doc, QString target = QString::null) = 0;

		/**
		 * @brief Run the plug-in's main action.
		 *
		 * This method behaves as the previous one. Except there is
		 * a parent widget reference. It's useful e.g. when you need to
		 * open a dialog on a specific parent one.
		 */
		virtual bool run(QWidget* parent, ScribusDoc* doc, QString target = QString::null);

		/**
		 * @brief Run the plugin on a QIODevice
		 *
		 * This method is essentially the same as the above, except that it
		 * accepts a QIODevice* to work with. This will generally be used for
		 * file I/O without the plugin having to know or care where from.
		 *
		 * A plug-in MUST return false if it cannot support this method or upon
		 * failure. A plug-in MUST supply a working version of this method if
		 * it accepts runWith(..., QString) on a local file, and should
		 * generally implement the former using this method.
		 *
		 * Remember that not all QIODevice*s are seekable, and try to write
		 * your code to handle a non-seekable stream.
		 */
		virtual bool run(ScribusDoc* doc, QIODevice* target);

		/**
		 * @brief Run the plugin asynchronously
		 *
		 * This call is similar to the one above, but instead of doing all the
		 * work in one big batch, it creates an instance of a DeferredTask
		 * subclass to keep track of the job, does some setup, and returns
		 * immediately. The DeferredTask, a pointer to which is returned, has
		 * already been started when this method returns.
		 *
		 * The caller of this method is responsible for handling the aborted()
		 * and finished() signals from the DeferredTask, and (if necessary) for
		 * cleaning it up using deleteLater(...) once it has finished. Remember
		 * that a DeferredTask is automatically deleted when its parent is, if
		 * it hasn't already been deleted. This approach is preferred where
		 * possible.
		 *
		 * See the DeferredTask documentation for details on how it works.
		 *
		 * If your plugin implementation does not support asynchronous
		 * operation, you must return null. This is the default implementation,
		 * so simply ignore this method unless you wish to support it. It is
		 * recommended that all new plugins support this interface where
		 * possible, even if they can only do part of their work progressively.
		 *
		 * If you implement this, you may want to implement run(...) using the
		 * same deferred operation and a modal dialog. That'll permit the event
		 * loop to continue running for redraws, permit you to update the
		 * progress bar, etc.
		 *
		 * NOTE: In current Scribus code (August 2005), callers of this method
		 * will generally create a modal dialog - possibly with progress meter
		 * - then attach signals from the DeferredTask, and exec() the dialog.
		 *   A caller is not required to do this, but with the current (August
		 *   2005) core code it's the only way to operate safely. This is
		 *   likely to change in future and you should avoid relying on it if
		 *   at all posssible.
		 *
		 * If this method is used, the plugin must not be unloaded until all
		 * DeferredTask instances have been deleted.
		 */
		virtual DeferredTask* runAsync(QString target = QString::null);

		/**
		 * @brief Run the plugin asynchronously
		 *
		 * This method is much the same as the above, but takes a QIODevice* as
		 * the target. Please see the documentation for run(..., QIODevice*
		 * target) and runAsync(..., QString target) for details.
		 */
		virtual DeferredTask* runAsync(QIODevice* target);

		// Compat kludge ... we store a QString result from any successful
		// run(...) call in m_runResult and let callers retrive it here.
		// DO NOT USE THIS INTERFACE FOR NEW PLUG-INS; you should
		// dynamic_cast<> to the plugin type then call a plug-in specific
		// method instead.
		///! Obsolete method - do not use this or rely on it in new code.
		const QString & runResult() const;

	protected:
		// Action info. To be set up by ctor.
		ActionInfo m_actionInfo;
		// Obsolete - see runResult()
		QString m_runResult;
		ScribusDoc* m_Doc;
};

/**
 * @brief A plug-in that is resident for the lifetime of the app
 *
 * ScPersistentPlugin describes a plugin that is to be kept resident for the
 * lifetime of the app (or until unloaded by a request to the plug-in manager).
 * Persistent plugins are useful where the plugin author needs to retain state,
 * needs more control of how they integrate with the Scribus user interface,
 * and/or wants to perform tasks in the background.
 *
 * Such plug-ins have an init method and a cleanup method; they have
 * no "run" method as such. It is up to the plugin to determine how
 * best to interfact with the user.
 */
class SCRIBUS_API ScPersistentPlugin : public ScPlugin
{
	Q_OBJECT

	public:

		/** @brief ctor
		 *
		 * @sa ScPlugin::ScPlugin()
		 */
		ScPersistentPlugin();

		//! \brief Pure virtual dtor for abstract class
		virtual ~ScPersistentPlugin() = 0;

		/**
		 * @brief Initialize the plugin
		 *
		 * This method must initialize the plugin. It is called at plug-in load
		 * time. This method will never be called twice without an intervening
		 * cleanupPlugin call, but there is no guarantee the plugin will actually
		 * be unloaded between initPlugin() and cleanupPlugin().
		 *
		 * It will usually instantiate a class and store a pointer to the
		 * instance in a static variable of the plugin or a member of its
		 * ScPersistentPlugin subclass, letting that class do the work of setup
		 * and integration into the app.
		 *
		 * Note that this is NOT the same as the init function of the plugin. That
		 * is always simple and lightweight, intended to just get an instance of this
		 * class back to the core app. This function is where any time-consuming or
		 * memory expensive init should be triggered, generally by the instantiation
		 * of the class that does the real work for the plugin.
		 *
		 * If this method returns failure, the plugin will be treated as dead and
		 * cleanupPlug() will not be called.
		 *
		 * @returns bool True for success.
		 */
		virtual bool initPlugin() = 0;

		/**
		 * @brief Deactivates the plugin for unloading / program quit
		 *
		 * This method will be called when the plug-in is about to be unloaded,
		 * or if the plug-in manager has been asked to disable the plug-in.
		 * This method will never be called unless initPlugin has been called
		 * first, but there is no guarantee the plugin will actually be
		 * unloaded after this is called, or before initPlugin is called again.
		 *
		 * @returns bool True for success.
		 */
		virtual bool cleanupPlugin() = 0;
};

// Plug-in API version used to check if we can load the plug-in. This
// does *NOT* ensure that the plug-in will be compatible with the internal
// Scribus APIs, only that the ScPlugin class and its standard subclasses
// will be compatible with what we expect, and that "extern C" functions
// we need will be present and work as expected. It's a preprocessor directive
// to make sure that it's compiled into each plugin rather than referenced
// from the main code.
//
// The API version is currently simply incremented with each incompatible
// change. Future versions may introduce a minor/major scheme if necessary.
#define PLUGIN_API_VERSION 0x00000010


#endif