How to catch a wxHtmlLinkEvent from wxHtmlHelpController? Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
etxmato
Knows some wx things
Knows some wx things
Posts: 40
Joined: Fri Sep 14, 2007 5:32 pm

How to catch a wxHtmlLinkEvent from wxHtmlHelpController?

Post by etxmato »

Hi there,

Wondering if someone could help me with the following problem:
I'm using wxHtmlHelpController to show the help book for my app, however when clicking on an external link (http://...) in the help book the url won't open. What I would like to do is to get the default browser started and the url gets opened in the browser.

I used to have this working in windows by using the solution suggested here: https://trac.wxwidgets.org/ticket/12037#no1. However this solution needs a change in wxWidget code which isn't really possible on Linux as my installer package requests a wxWidgets dependency, i.e. original code.

So now I'm looking for a solution to 'catch' the link click in the wxHtmlHelpController to my main app, is that even possible?
The same trac ticket above has some suggestion to use Connect or PushEventHandler to hook into the HtmlWindow's event handler and handle EVT_HTML_LINK_CLICKED but I can't get my head around how this would work.

My 'help' code is fairly basic roughly like:

Code: Select all

wxHtmlHelpController *help;

Main:Main()
{
	wxString helpFile = "emma_02.htb";

	help = new wxHtmlHelpController(wxHF_TOOLBAR | wxHF_CONTENTS | wxHF_INDEX | wxHF_SEARCH | wxHF_BOOKMARKS | wxHF_PRINT | wxHF_BOOKMARKS);
	
 	if (!help->AddBook(helpFile))
	{
		(void)wxMessageBox( "Failed adding book " + helpFile + "\n", "Emma 02", wxICON_ERROR | wxOK );
	}
}

Main::~Main()
{
    delete help;
}

void Main::onHelp(wxCommandEvent& WXUNUSED(event))
{
	help->DisplayContents();
}
I tried to add something like this:

Code: Select all

    Connect(wxID_ANY,
            wxEVT_HTML_LINK_CLICKED,
            wxHtmlLinkEventHandler(Main::linkClicked),
            (wxObject*) NULL,
            this);
in the Main code but that (obviously?) doesn't work.

Any help or advice would be much appreciated.

Cheers, Marcel.
OS: Windows 10 / Ubuntu / Mac OS X Sierra
IDE: VC++ Express / Eclipse / xCode
wxWidgets 3.0.3
User avatar
xaviou
Super wx Problem Solver
Super wx Problem Solver
Posts: 437
Joined: Mon Aug 21, 2006 3:18 pm
Location: Annecy - France
Contact:

Re: How to catch a wxHtmlLinkEvent from wxHtmlHelpController?

Post by xaviou »

Hi.
etxmato wrote: I tried to add something like this:

Code: Select all

    Connect(wxID_ANY,
            wxEVT_HTML_LINK_CLICKED,
            wxHtmlLinkEventHandler(Main::linkClicked),
            (wxObject*) NULL,
            this);
in the Main code but that (obviously?) doesn't work.
This is probably due to the fact that then event is proceceed by the wxHtmlHelpControler before the frame can receive it.

You should connect the event of the wxHtmlHelpControler to your event handler, just after creating it :

Code: Select all

Main:Main()
{
   wxString helpFile = "emma_02.htb";

   help = new wxHtmlHelpController(wxHF_TOOLBAR | wxHF_CONTENTS | wxHF_INDEX | wxHF_SEARCH | wxHF_BOOKMARKS | wxHF_PRINT | wxHF_BOOKMARKS);
   
    if (!help->AddBook(helpFile))
   {
      (void)wxMessageBox( "Failed adding book " + helpFile + "\n", "Emma 02", wxICON_ERROR | wxOK );
   }
   else
   {
      help->Connect(wxEVT_HTML_LINK_CLICKED,
            wxHtmlLinkEventHandler(Main::linkClicked),
            (wxObject*) NULL,
            this);
   }
}
Regards
Xav'
My wxWidgets stuff web page : X@v's wxStuff
etxmato
Knows some wx things
Knows some wx things
Posts: 40
Joined: Fri Sep 14, 2007 5:32 pm

Re: How to catch a wxHtmlLinkEvent from wxHtmlHelpController?

Post by etxmato »

Hi Xav,

Thanks for your reply!

I tried your suggestion, I actually did try something similar before as well; but unfortunately I get a compilation error on the 'Connect':
'No member named 'Connect' in wxHtmlHelpController'.

Any other ideas?

My thinking was that I somehow need to connect it to the wxHtmlWindow that is used by the wxHtmlHelpController but how to do that?

Cheers, Marcel.
OS: Windows 10 / Ubuntu / Mac OS X Sierra
IDE: VC++ Express / Eclipse / xCode
wxWidgets 3.0.3
User avatar
xaviou
Super wx Problem Solver
Super wx Problem Solver
Posts: 437
Joined: Mon Aug 21, 2006 3:18 pm
Location: Annecy - France
Contact:

Re: How to catch a wxHtmlLinkEvent from wxHtmlHelpController?

Post by xaviou »

Hi.
etxmato wrote:I tried your suggestion, I actually did try something similar before as well; but unfortunately I get a compilation error on the 'Connect':
'No member named 'Connect' in wxHtmlHelpController'.
You're right : wxHtmlHelpController doesn't derive from wxEvtHandler.

You can try this:

Code: Select all

help->GetHelpWindow()->Connect(wxEVT_HTML_LINK_CLICKED,
            wxHtmlLinkEventHandler(Main::linkClicked),
            (wxObject*) NULL,
            this);
And perhaps you should better use Bind instead of Connect :

Code: Select all

help->GetHelpWindow()->Bind(wxEVT_HTML_LINK_CLICKED,
            &Main::linkClicked,
            this);
Regards
Xav'
My wxWidgets stuff web page : X@v's wxStuff
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to catch a wxHtmlLinkEvent from wxHtmlHelpController?

Post by doublemax »

I think the help window will only be created on demand, i suspect that "help->GetHelpWindow()" will return NULL at this point.

I think there really is no easy way to do this.
Use the source, Luke!
etxmato
Knows some wx things
Knows some wx things
Posts: 40
Joined: Fri Sep 14, 2007 5:32 pm

Re: How to catch a wxHtmlLinkEvent from wxHtmlHelpController?

Post by etxmato »

Hi Xav, doublemax,

Thanks again for your input, I'm afraid doublemax might be right.... at least both last options crashed on the Connect and Bind.
Ah well, will try to think of something else; maybe just remove all urls from the help pages :(.

Cheers, Marcel.
OS: Windows 10 / Ubuntu / Mac OS X Sierra
IDE: VC++ Express / Eclipse / xCode
wxWidgets 3.0.3
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: How to catch a wxHtmlLinkEvent from wxHtmlHelpController?

Post by PB »

I just tried to modify the html/help sample and it seems I was able to get the link event.

I wrote this code in the MyFrame ctor between SetMenuBar(menuBar); and bool ret; (where help is an instance of wxHtmlHelpController)

Code: Select all

    SetMenuBar(menuBar);

    wxHtmlHelpWindow* embeddedHelpWindow = new wxHtmlHelpWindow(this, wxID_ANY, wxDefaultPosition, GetClientSize(),
                                 wxTAB_TRAVERSAL|wxBORDER_NONE, wxHF_DEFAULT_STYLE);    
    help.SetHelpWindow(embeddedHelpWindow);    

    wxHtmlWindow* htmlWindow = embeddedHelpWindow->GetHtmlWindow();
    if ( htmlWindow )    
        htmlWindow->Bind(wxEVT_HTML_LINK_CLICKED, &MyFrame::OnHtmlLinkClicked, this);            
    
    bool ret;
and added the event handler to the MyFrame

Code: Select all

void MyFrame::OnHtmlLinkClicked(wxHtmlLinkEvent& event)
{    
    const wxString href = event.GetLinkInfo().GetHref();

    if ( href.StartsWith("http") ) // change as needed    
        wxLaunchDefaultBrowser(href);            
    else   
        event.Skip(true);
}
Perhaps I missed something important but perhaps you could do something like this in your application...
etxmato
Knows some wx things
Knows some wx things
Posts: 40
Joined: Fri Sep 14, 2007 5:32 pm

Re: How to catch a wxHtmlLinkEvent from wxHtmlHelpController?

Post by etxmato »

Hi PB,

Ok, yes this somewhat works but I'm getting the help window 'instead' of the 'MyFrame' with the menuBar. So I directly see the help books instead of a menubar where I can select 'help'. Both in the html/sample as well as my own app.

Otherwise the event itself indeed works but I need it in a separate help window.
Any idea how I initiate a new window and still use this?

Thanks anyway for you suggestion this got further than I ever got :).

Cheers, Marcel.
OS: Windows 10 / Ubuntu / Mac OS X Sierra
IDE: VC++ Express / Eclipse / xCode
wxWidgets 3.0.3
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: How to catch a wxHtmlLinkEvent from wxHtmlHelpController?

Post by PB »

Sorry, I did not notice that, my bad. The approach below may be better, but I am again shooting from the hip here

Start with unmodified version of the html/help sample.

Add this before MyFrame declaration

Code: Select all

class MyHtmlHelpController : public wxHtmlHelpController
{
public:
    MyHtmlHelpController(int style=wxHF_DEFAULT_STYLE, wxWindow *parentWindow=NULL)
        : wxHtmlHelpController(style, parentWindow) {}
    MyHtmlHelpController(wxWindow *parentWindow, int style=wxHF_DEFAULT_STYLE)
        : wxHtmlHelpController(parentWindow, style) {}
protected:
    virtual wxWindow* CreateHelpWindow() wxOVERRIDE
    {
        wxHtmlHelpController::CreateHelpWindow();
        
        m_helpWindow->Bind(wxEVT_HTML_LINK_CLICKED, &MyHtmlHelpController::OnHtmlLinkClicked);  

        return m_helpWindow;
    }
private:    
    static void OnHtmlLinkClicked(wxHtmlLinkEvent& event)
    {
        const wxString href = event.GetLinkInfo().GetHref();

        if ( href.StartsWith("http") ) // change as needed    
            wxLaunchDefaultBrowser(href);            
        else   
            event.Skip(true);
    }
};
and then in MyFrame declaration replace

Code: Select all

wxHtmlHelpController help;
with

Code: Select all

MyHtmlHelpController help;
etxmato
Knows some wx things
Knows some wx things
Posts: 40
Joined: Fri Sep 14, 2007 5:32 pm

Re: How to catch a wxHtmlLinkEvent from wxHtmlHelpController?

Post by etxmato »

Hi PB,

:) Cool, that worked!

I just removed the wxOVERRIDE as my wx version didn't recognise that.

Thanks a mill,
Cheers, Marcel.
OS: Windows 10 / Ubuntu / Mac OS X Sierra
IDE: VC++ Express / Eclipse / xCode
wxWidgets 3.0.3
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: How to catch a wxHtmlLinkEvent from wxHtmlHelpController?

Post by PB »

You are probably aware of it but just to be sure: the code was just a proof of concept, not a production-level one and there may be some issues.

For starters, wxHtmlHelpController::CreateHelpWindow() is undocumented. The source code of the method also indicates it is possible it can be called more than once, so perhaps the overriden version should take this into account and guard against multiple event binding, e.g.

Code: Select all

wxWindow* MyHtmlHelpController::CreateHelpWindow()
{
    const bool hadHelpWindow = m_helpWindow != NULL;

    wxHtmlHelpController::CreateHelpWindow();
   
    if ( !hadHelpWindow )
        m_helpWindow->Bind(wxEVT_HTML_LINK_CLICKED, &MyHtmlHelpController::OnHtmlLinkClicked); 

    return m_helpWindow;
}
If you are using modern C++, you can replace the two MyHtmlHelpController constructors with using wxHtmlHelpController::wxHtmlHelpController.

Testing for the external URL is also no good, even if one checks only for the http and https protocols. At the very least the check should not be case sensitive and needs to be changed, e.g. to

Code: Select all

href.Lower().StartsWith("http")
but there is still issue of local link (files) names starting with "http" so the check really needs to look at protocols...
etxmato
Knows some wx things
Knows some wx things
Posts: 40
Joined: Fri Sep 14, 2007 5:32 pm

Re: How to catch a wxHtmlLinkEvent from wxHtmlHelpController?

Post by etxmato »

Hi PB,

Ok, noted!
For my useage I do think this is good enough :).

I will try your latest suggestions as well.

I changed the check on http to check for http:// and https://; also good enough for my usage as I know I have no links in my help book that use that. I understand now why it is maybe not good enough to add as a fix in the wxWidget source.

Thanks again,
Marcel
OS: Windows 10 / Ubuntu / Mac OS X Sierra
IDE: VC++ Express / Eclipse / xCode
wxWidgets 3.0.3
Post Reply