Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
Home » Developing U++ » U++ Developers corner » Question: Simple plugin implementation
Question: Simple plugin implementation [message #30804] Sun, 23 January 2011 22:20 Go to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
Hello all

I will ask you the question with an example based in OfficeAutomation:

There is an API of functions to handle spreadsheets. As they can be handled using OpenOffice, LibreOffice, Excel or other programs, the same API can be set for all programs. In run time it is possible to choose which program to use.

To do it, I have prepared something similar to the enclosed code. However, I think it is ugly and something much better could be done in U++ using C++.

Do you have any idea?

#include <Core/Core.h>

using namespace Upp;


class SpreadsheetPlugin {
public:
	virtual bool Open(char *filename) 			{return false;};
	virtual bool SetData(int row, int col, Value val) 	{return false;};
};


class OpenSpreadsheet : public SpreadsheetPlugin {
	virtual bool Open(char *filename);
	virtual bool SetData(int row, int col, Value val); 	
};

bool OpenSpreadsheet::Open(char *filename) {
	// Do stuff
}

bool OpenSpreadsheet::SetData(int row, int col, Value val) {
	// Do stuff
}

class ExcelSpreadsheet : public SpreadsheetPlugin {
	virtual bool Open(char *filename);
	virtual bool SetData(int row, int col, Value val);
};

bool ExcelSpreadsheet::Open(char *filename) {
	// Do stuff
}

bool ExcelSpreadsheet::SetData(int row, int col, Value val) {
	// Do stuff
}


class Spreadsheet : public SpreadsheetPlugin {
private:
	SpreadsheetPlugin *data;
	
public:
	Spreadsheet() {data = 0;};
	~Spreadsheet() {
		if (data)
			delete data;
	}
	void Init(String type) {
		if (type == "Open" || type == "Libre")
			data = new OpenSpreadsheet();
		else
			data = new ExcelSpreadsheet();
	}
	
	virtual bool Open(char *filename) 			{return data->Open(filename);}
	virtual bool SetData(int row, int col, Value val)	{return data->SetData(row, col, val);}
};


CONSOLE_APP_MAIN
{
	Spreadsheet spreadsheet;
	
	spreadsheet.Init("Libre");
	spreadsheet.Open("c:\\myfile.xls");
	spreadsheet.SetData(4, 6, "Hello world");
}


Best regards
Iñaki
Re: Question: Simple plugin implementation [message #30808 is a reply to message #30804] Sun, 23 January 2011 23:53 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Well, this is pretty standard aprroach in fact. And we are using something quite similar e.g. in image format support.

You can make it a little bit nicer using

class Spreadsheet : public SpreadsheetPlugin {
private:
	One<SpreadsheetPlugin> data;


or perhaps you can avoid Spreadsheet and provide

CreateSpreadsheet(One<Spreadsheet>& x, String type);


but it is hard to say what is better... Smile

Mirek

[Updated on: Sun, 23 January 2011 23:54]

Report message to a moderator

Re: Question: Simple plugin implementation [message #30815 is a reply to message #30808] Mon, 24 January 2011 09:44 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
Oooh, I thought it was possible to do it smarter with templates. Smile

Best regards
Iñaki
Re: Question: Simple plugin implementation [message #30861 is a reply to message #30815] Tue, 25 January 2011 14:50 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
Hello

This is other focus. It permits adding plugins just by adding files without touching base class. It is based on Painter example.

For example to add Excel support, it would be:

#include <Core/Core.h>

using namespace Upp;

#include "Spreadsheet.h"

class ExcelSpreadsheet : public SpreadsheetPlugin {
	Spreadsheet_METHOD_LIST
};

ExcelSpreadsheet excelSpreadsheet;

INITBLOCK {
	RegisterPlugin("Excel", dynamic_cast<SpreadsheetPlugin *>(&excelSpreadsheet));
}

bool ExcelSpreadsheet::Open(const char *filename) {
	puts("ExcelSpreadsheet::Open");
	return false; 
}

bool ExcelSpreadsheet::SetData(int row, int col, Value val) {
	puts("ExcelSpreadsheet::SetData");
	return false;
}





Best regards
Iñaki
Re: Question: Simple plugin implementation [message #30862 is a reply to message #30861] Tue, 25 January 2011 15:34 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
koldo wrote on Tue, 25 January 2011 08:50

Hello

This is other focus. It permits adding plugins just by adding files without touching base class. It is based on Painter example.

For example to add Excel support, it would be:

#include <Core/Core.h>

using namespace Upp;

#include "Spreadsheet.h"

class ExcelSpreadsheet : public SpreadsheetPlugin {
	Spreadsheet_METHOD_LIST
};

ExcelSpreadsheet excelSpreadsheet;

INITBLOCK {
	RegisterPlugin("Excel", dynamic_cast<SpreadsheetPlugin *>(&excelSpreadsheet));
}

bool ExcelSpreadsheet::Open(const char *filename) {
	puts("ExcelSpreadsheet::Open");
	return false; 
}

bool ExcelSpreadsheet::SetData(int row, int col, Value val) {
	puts("ExcelSpreadsheet::SetData");
	return false;
}






I guess even better pattern can be found with RasterImage...
Re: Question: Simple plugin implementation [message #30873 is a reply to message #30862] Thu, 27 January 2011 10:34 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
Hello Mirek

A little bit better (not as rich as StreamRaster, but clearer for me Smile). Added "new" instead of ugly global var:

#include <Core/Core.h>

using namespace Upp;

#include "Spreadsheet.h"

class ExcelSpreadsheet : public SpreadsheetPlugin {
	Spreadsheet_METHOD_LIST
};


INITBLOCK {
	RegisterPlugin<ExcelSpreadsheet>("Excel");
}

bool ExcelSpreadsheet::Open(const char *filename) {
	puts("ExcelSpreadsheet::Open");
	return false; 
}

bool ExcelSpreadsheet::SetData(int row, int col, Value val) {
	puts("ExcelSpreadsheet::SetData");
	return false;
}


However all possible plugins are initialized, not just the one to be used.

It is the same in class StreamRaster (file Raster.h):

template <class T> static StreamRaster *FactoryFn() { return new T; }


Every registered class has to be initialized.

[Edit: Simplified INITBLOCK with templates]


Best regards
Iñaki

[Updated on: Thu, 27 January 2011 13:07]

Report message to a moderator

Re: Question: Simple plugin implementation [message #30875 is a reply to message #30873] Thu, 27 January 2011 13:58 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
Hello Mirek

One question. Following with StreamRaster, it seems registered classes are never deleted:

Here PNGRaster is registered
StreamRaster::Register<PNGRaster>();


So
static void Register()              { AddFormat(&StreamRaster::FactoryFn<T>); }


FactoryFn creates a new T
template <class T> static StreamRaster *FactoryFn() { return new T; }


Added here:
void StreamRaster::AddFormat(RasterFactory factory)
{
	INTERLOCKED_(sAnyRaster)
		Map().Add((void *)factory);
}

Vector<void *>& StreamRaster::Map()
{
	static Vector<void *> x;
	return x;
}


So it is assigned to a void *


Best regards
Iñaki
Re: Question: Simple plugin implementation [message #30885 is a reply to message #30875] Thu, 27 January 2011 17:34 Go to previous messageGo to next message
fudadmin is currently offline  fudadmin
Messages: 1321
Registered: November 2005
Location: Kaunas, Lithuania
Ultimate Contributor
Administrator
Can these things to be made as universal plugins implementation for upp?
Re: Question: Simple plugin implementation [message #30889 is a reply to message #30875] Thu, 27 January 2011 20:53 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
koldo wrote on Thu, 27 January 2011 07:58

Hello Mirek

One question. Following with StreamRaster, it seems registered classes are never deleted:



What you register is the "factory function". What would you want to delete? Smile

Mirek
Re: Question: Simple plugin implementation [message #30890 is a reply to message #30885] Thu, 27 January 2011 20:54 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
fudadmin wrote on Thu, 27 January 2011 11:34

Can these things to be made as universal plugins implementation for upp?


If you have in mind something like .dll, then the answer is NO.

Mirek
Re: Question: Simple plugin implementation [message #30893 is a reply to message #30889] Thu, 27 January 2011 21:47 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
mirek wrote on Thu, 27 January 2011 20:53

koldo wrote on Thu, 27 January 2011 07:58

Hello Mirek

One question. Following with StreamRaster, it seems registered classes are never deleted:



What you register is the "factory function". What would you want to delete? Smile

Mirek


Hello Mirek

If to register a new class FactoryFn does a new T that is added to Map() to a static Vector<void *> x, I have not seen how it is deleted.


Best regards
Iñaki
Re: Question: Simple plugin implementation [message #30912 is a reply to message #30893] Fri, 28 January 2011 10:33 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
koldo wrote on Thu, 27 January 2011 15:47

mirek wrote on Thu, 27 January 2011 20:53

koldo wrote on Thu, 27 January 2011 07:58

Hello Mirek

One question. Following with StreamRaster, it seems registered classes are never deleted:



What you register is the "factory function". What would you want to delete? Smile

Mirek


Hello Mirek

If to register a new class FactoryFn does a new T that is added to Map() to a static Vector<void *> x, I have not seen how it is deleted.


That 'void *' is a pointer to a function. What do you want to delete?

If Vector itself, it gets deleted with all other static objects.

Mirek
Re: Question: Simple plugin implementation [message #30913 is a reply to message #30912] Fri, 28 January 2011 10:34 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
To be more specific:

void Fn() {
   ....
}

void (*fn)() = &Fn;

delete fn; //WTF?


Smile
Re: Question: Simple plugin implementation [message #30945 is a reply to message #30913] Sat, 29 January 2011 01:08 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
Hello Mirek

After a couple of hours looking like an stupid Raster.h and Raster.cpp... Confused , you are right: Registering a new bitmap class in U++ is including a pointer to a function that will create an object of that class when necessary ... Shocked

As the bitmap class is always assigned to a One<StreamRaster>, deletion is assured Smile


Best regards
Iñaki
Re: Question: Simple plugin implementation [message #31131 is a reply to message #30945] Mon, 07 February 2011 11:16 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
He he Smile

Following with it here it is something perhaps better than StreamRaster plugin system.

In StreamRaster it is done a "new" any time a function is called. But is is possible to do it only once:

class StaticPlugin {
public:
	StaticPlugin();
	~StaticPlugin();
	bool Init(const char *name);

	template <class T>
	static void Register(const char *name) {
		PluginData& x = Plugins().Add();
		x.name = name;
		x.New = New<T>;
		x.Delete = Delete<T>;
	}

protected:
	void *data;
	
private:	
	String name;
	
	template <class T> static void *New() 		{return new T;};
	template <class T> static void Delete(void *p) 	{delete static_cast<T *>(p);};
	
	struct PluginData {
		String name;
		void *(*New)();
		void (*Delete)(void *);
	};
	
	static Array<PluginData>& Plugins();
};

The plugin class is stored in a void *data, with its "new" and "delete", in Register() (thanks to templates Smile).

This way, if a plugin is used, StaticPlugin uses the right "new". And in ~StaticPlugin it is used the right "delete" Smile Smile.




Best regards
Iñaki
Re: Question: Simple plugin implementation [message #31175 is a reply to message #31131] Fri, 11 February 2011 16:50 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Well, but then you keep all plugins in memory, including all data in memory they needed for the last operation or you need to implement some sort of 'free' for them.

Allocating/deallocating memory is actually quite fast operation in U++.
Re: Question: Simple plugin implementation [message #31186 is a reply to message #31175] Fri, 11 February 2011 22:47 Go to previous message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
mirek wrote on Fri, 11 February 2011 16:50

Well, but then you keep all plugins in memory, including all data in memory they needed for the last operation or you need to implement some sort of 'free' for them.

Allocating/deallocating memory is actually quite fast operation in U++.

Hello Mirek

It is only necessary to allocate the used plugin. It is done in
INITBLOCK {
	RegisterPlugin<ExcelSpreadsheet>("Excel");
}


In fact it is interesting to have it allocated while the plugin is used as it can keep some variables.

For example for an spreadsheet, the Open() method load some variables that will be used by other methods like SetData(Value v, int row, int col).


Best regards
Iñaki
Previous Topic: Q: howto incorporate a native console window in GUI
Next Topic: BackgroundTask
Goto Forum:
  


Current Time: Wed Apr 24 04:38:06 CEST 2024

Total time taken to generate the page: 0.02472 seconds