Wednesday, February 09, 2005

Using MFC and threads, dazzled and amazed!?

As always Im amazed on how much worse it is by developing applications in MFC than using Swing. MFC has a complete different view of how a dialog and threads should cooperate. In short words, MFC wont let any threads to change any control in a dialog. WTF? If you have a task that takes hours, and you want to have a GUI that displays the progress of it; what do you do? The thread is not allowed to use any of the GUI controls at all, and if you do, then suddenly the whole application will lock up because you try to change a control. In Swing you dont have this problem, because you have true VMC modelling.


So what do you do when you want to update a GUI from a thread. There are two ways in MFC: you can either change the GUI control youself, but this will result in deadlocks 100% guarantee; you can either change the value (string/dword) behind the control and then call the UpdateData() method. But something that they forgot to say is that you cant call UpdateData() from a thread outside the GUI loop, doing that will result in deadlock 100% guarantee. MS only response is "threads are not allowed to touch GUI, you must send a message to the dialog that you want to update". Fair enough, but MS has failed to give such a functionality and if I want to update a tabbed dialog with data from the thread, there is no way but to implement a WM_USER message listener for every dialog that you want to update from the thread. Sheeeesh, I dont want to put more stuff into each one of the dialogs, for just make it "thread-safe" for the MFC GUI.


My solution to this problem is jsut to create a base CDialog class that will handle this problem, and is safe to update all values in a dialog. It took med 5 minutes to create it and test it. Whoah, that was easy, but that main point is IF IT WAS SO EASY, WHY HASNT MS DONE THIS IN THE FIRST PLACE? Why do I have to live with crap design eons after the MFC was "designed", why can't they extend the dialog class with such functionality so you dont have to sit and wonder why the application has locked. "Is it me or MFC?"


Im still amazed that MFC is still not thread safe, it was earlier one of the most commonly used application tools/API for creating applications. How could it survive for such a long time??


My solution, is as easy as pie. Here it is:

#include

#include



class CRefreshDialog : public CDialog

{

public:

CRefreshDialog(UINT nIDTemplate,CWnd* pParentWnd = NULL );

virtual ~CRefreshDialog();

virtual BOOL OnWndMsg( UINT message,WPARAM wParam, LPARAM lParam, LRESULT* pResult );



void RefreshDialog();

private:

CCriticalSection refreshMutex;

};





#define WM_REFRESH WM_USER + 0x9283



CRefreshDialog::CRefreshDialog(UINT nIDTemplate, CWnd* pParentWnd ) : CDialog(nIDTemplate, pParentWnd)

{

}



CRefreshDialog::~CRefreshDialog()

{

}



BOOL CRefreshDialog::OnWndMsg( UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult )

{

BOOL wasHandled = FALSE;

if (message == WM_REFRESH)

{

UpdateData(FALSE);

} else

{

wasHandled = CDialog::OnWndMsg(message, wParam, lParam, pResult);

}

return wasHandled;

}



void CRefreshDialog::RefreshDialog()

{

CSingleLock lock(&refreshMutex);

lock.Lock();

::PostMessage(m_hWnd, WM_REFRESH, 0, 0);

lock.Unlock();

}

Thursday, November 11, 2004

Java Desktop Search tool

I find that the Google Desktop Search tool, is an extremly usefull tool. But one that has many disadvantages, it is very MS orientated. It can only read emails from MS apps, can only read web history from IE, it can only read Word document (by default). As many people goes about and try to figure on how to add the FireFox web history into GDS, perhaps there is another way.


Since Ive used Lucene before and find this an extremly good search tool/API for java, which is very lean and quick; I came up with an idea, Why not make this in Java? This would be a blast for all Linux users as well, since there is no GDS for linux (right?). Of course it will probably be hard to pair up with the searching techniques done by Google, since they've done this for years. But I still think there is an opportunity here for an open-source project that can work in all platforms.


By making it in java, it would be very simpel to add other searches, such as:

  • MP3 files ID3 tags
  • Thunderbirds emails
  • Columba emails (Java based email program)
  • Open office documents
  • Miranda chat logs
  • ICQ chat logs, etc...
For presentating the stuff, the Velocity engine could be used for seperating the logic and presentation. Velocity is a very nice tool for simpel web based applications.

But I wonder if there are already any very light weight web servers that can be used for this?


One problem is that google is going to fill this void, so its either now or never!

Friday, September 10, 2004

Localization problems

Localizing software is a very tedious effort, and most times its up to the translators language knowledge on how good the result will be. Most applications shares also a bunch of menu entries that must be the same in all localized applications. (You can't replace a "Save" button with a button named "Store"). There are other definitions that you can find several synonyms for but where only one is applicable.

How do you know that one word is more appriopiate than another one? This must happen to every open-source project that is undergoing localizations. How much time isnt spent on getting the right words for some actions or menu entries?

Im looking for a common source for localizing softwares, a place where you can get the simplest menu entries translated just by looking at some documents. This common place could be a community with a forum for placing questions, language defintions, basic help on getting a localization working. Each language would have their own section of it, this would of course help open-source projects to become accepted quicker among ordinary users. There must be loads of info/data already available in different linux builds, (debian comes to mind) why cant we put this knowledge where it is easier to get?

Is there such a place, Ive done some googling but havent found any. Perhaps SF or any other open-source site would be suitable for this... (Or am I just dreaming?)

Tuesday, April 20, 2004

Workarounds for Swings DnD problems!


After digging around, googling and receiving tons of help; I've built two workarounds for some of the problems with Swings Drag and Drop (DnD) problems. The first problem with the DnD is the lack of the ability to dynamically create files dynamically when exporting files from a Java program. The second problem with the DnD is that you have to redo already implemented data handling.




I've already described the two problems in these blogs: Extending the.. and Shortcoming of...




These problems comes from design decisions in Swing, and cannot be fixed without tampering with the APIs of the DnD in Swing. Actually the first problem is the one that will have the largest impact on the handling of DnD to the native system. The second can be changed within the current API.




The problem was that all files that are to be DnD from a Java application to the native system, must exist before the action. And there are several areas where this isn't possible. Example the Columba email client, it was not wanted to extract attachments from an email until the user has selected so. FTP applications could just have one file list for the remote server, and then the user could DnD files from the file list to the desktop to start a transfer.


My solution was to create the files during the DnD action, before the actual drop of the file has been initiated. Therefore I came up with the class DynamicFileTransferHandler. This class could be used for any JComponent that wants to export files from Java dynamically. All it needs is a File factory that creates the files during the DnD process. The files can either be created at the start of the DnD or at the very end of it. Well not really the very end, it is actually when the DnD moves over a native application, that is the last known place for the DnD of files.. Check out the webstart demo of the frappucino package. Unfortunately this feature will not be a part of the Swing's DND API for a very long time, and I doubt that it will even go into the SDK 1.6 release. Please note that this solution is good enough but Sun should get their act together and make better support for this type of DnD. I solved the problem for the email application, but for FTP applications this is still unsolvable.




The second problem was that often the developer only wants to add one DnD data flavor to a JComponent. This was not possible with the current API. Some of the methods in the API has protected access, and the DnD API "cheated" by being in the same package. I've now developed a solution that enables a JComponent to have multiple TransferHandlers for importing data. Now you can easily add DnD support of files into a Textarea, and not lose the default DnD implementation. I wonder why nobody has done anything about this problem, because it makes it even more tedious to add DnD import for Swing components. Anyhow my solution is to have a set of transfer handlers that uses the Chain of responsibility design pattern. The class MultipleTransferHandler can have one or more transfer handlers, and will go through the set until it can find one handler that accepts a certain data flavor. Due to the fact that the export methods for TransferHandler are protected and it is impossible to call those without extending the handler or being in the same package, I had to use the reflection API to access those two methods. Due to this "cheat" there are some security issues when using this class, but as long as it is used in one trusted application, this wont be any problem. Now the class will work with one or more transfer handler for importing data flavor, and it still can export flavors from ONE of the transfer handler. Restricting it to one export transfer handler, solved the problem when you have several handlers that export the same data flavor. This may change in the future.. With this bug, I have little faith in that they are going to fix this. The bug/feature request has been around for over one year, with no real answers. Check out the Frappucino demo, it has a demo for this component as well.


BTW, thanks for all the replies from the Java desktop forum and bug lists, I hope that I can help somebody with these Swing objects.

Friday, March 26, 2004

Extending the DnD in Swing = reinventing the wheel


The Swing's DnD functionality looks very extendable at a first glance, but as more as I dig deeper into this part of the SDK I understand that it is not 100% true. Adding new DnD functionality to a component, forces the developer to reinvent the wheel every time. Why do the developer have to redo already implemented functionality to extend a components DnD actions?




Many of the JComponents in the swing package supports drag and drop actions. Those components already have a nice feature rich implementation that handles the dragging and dropping of objects to/from the component. The problem arises when the developer wants to add a new flavor to the components DnD functionality, ie extend so the component can import new types of objects. Each JComponent can only have one TransferHandler, and this is the one used during a DnD action.




Once again I'm in the middle of adding DnD to the email client (see my previous blog). This time I would like to add drag and drop of files into a new email, ie. add them as attachments. Other native email clients lets the user drag files onto the text area and the attachment bar. When the user drops the files in either of the target components, they are added to the emails attachment list. Now this was no problem adding the DnD of files to a attachment component but when I wanted to add this feature to the editor panes DnD support, I stumbled upon this problem. The editor pane already has a TransferHandler that supports strings/texts/Unicode data flavors. I would only like to add the fileList data flavor so it would also accept files.




The problem starts with that the TransferHandlers that are used by the JEditorPane components is package private, and therefore I cant extend them to get the functionality I want. I don't want to re-implement all those features in my own version, since that would be a waste of time and bloat the code. Then I thought of using the chain of responsibility design pattern to merge the two transfer handlers into one. Ie use one as the primary transfer handler, and then if the primary doesn't support a certain flavor it will try the other handler(s) if they can import a certain flavor. This to me looked like a fine idea, and I developed a nice class to work as one TransferHandler, but actually handling several. Everything went fine until the user tries to drag and drop from a component that has this object.




During that drag and drop action, it wants to create a transferable object through the protected method createTransferable(). BUT the method is called by at javax.swing.TransferHandler$DragHandler.dragGestureRecognized(TransferHandler.java:710) method, (outside the TransferHandler class) and it uses the fact that they are in the same package, ie they can break the protected access modifier. Now I have no clue on how to create the real transferable object, since in my implementation (see below) tries to do this on the primary transfer handler, but its createTransferable() method is protected and therefore I cant reach it, I'm not in the same package so I can "cheat" as the DragHandler does.




Once again, there is a problem in the design of the Swings DnD, but at least for this problem I have a workaround. I get around the problem by calling the needed protected methods using the reflection API, and making them public. But this to me is not the correct way of doing it, I should be able to call those methods in TransferHandler without relying on using reflection. There is already a feature request at Suns bug report system, and all I can do is hope that they change it in coming releases, but for now I at least got a solution. If you would like to use it, it is part of the Frappucino module in the Columba project. Frappucino is a collection of widgets that eases the development of Swing UIs. Check the link section for the class.